Validate that a file path is within the allowed directory. In server mode, the file must be within the current user's private storage directory (checks both new-style and old-style naming). Shared storage (config.SHARED_STORAGE) is intentionally excluded: API keys are per-user
(file_path)
| 68 | |
| 69 | |
| 70 | def validate_api_key_path(file_path): |
| 71 | """ |
| 72 | Validate that a file path is within the allowed directory. |
| 73 | |
| 74 | In server mode, the file must be within the current user's private |
| 75 | storage directory (checks both new-style and old-style naming). |
| 76 | Shared storage (config.SHARED_STORAGE) is intentionally excluded: |
| 77 | API keys are per-user secrets and must not live in directories |
| 78 | visible to other users. |
| 79 | |
| 80 | In desktop mode, the file must be within the user's home directory. |
| 81 | |
| 82 | Returns the resolved canonical path if valid, None otherwise. |
| 83 | """ |
| 84 | if not file_path: |
| 85 | return None |
| 86 | |
| 87 | try: |
| 88 | expanded = os.path.realpath(os.path.expanduser(file_path)) |
| 89 | except (ValueError, TypeError): |
| 90 | # Reject paths with embedded null bytes or non-string types |
| 91 | return None |
| 92 | |
| 93 | if config.SERVER_MODE: |
| 94 | for storage_dir in _get_user_storage_dirs(): |
| 95 | if _is_within(expanded, os.path.realpath(storage_dir)): |
| 96 | return expanded |
| 97 | return None |
| 98 | |
| 99 | # Desktop mode: home directory |
| 100 | allowed = os.path.realpath(os.path.expanduser('~')) |
| 101 | if _is_within(expanded, allowed): |
| 102 | return expanded |
| 103 | return None |
| 104 | |
| 105 | |
| 106 | def _parse_allowlist_entry(entry): |