Read an API key from a file. Args: file_path: Path to the file containing the API key. _trusted: If True, skip path validation. Use ONLY for admin-configured paths from config.py, never for user-supplied input. Returns: The API key strin
(file_path, _trusted=False)
| 204 | |
| 205 | |
| 206 | def _read_api_key_from_file(file_path, _trusted=False): |
| 207 | """ |
| 208 | Read an API key from a file. |
| 209 | |
| 210 | Args: |
| 211 | file_path: Path to the file containing the API key. |
| 212 | _trusted: If True, skip path validation. Use ONLY for |
| 213 | admin-configured paths from config.py, never for |
| 214 | user-supplied input. |
| 215 | |
| 216 | Returns: |
| 217 | The API key string, or None if the file doesn't exist, is empty, |
| 218 | or doesn't look like a valid API key file. |
| 219 | """ |
| 220 | if not file_path: |
| 221 | return None |
| 222 | |
| 223 | if _trusted: |
| 224 | # Admin-configured path: resolve but skip directory check |
| 225 | try: |
| 226 | expanded_path = os.path.realpath( |
| 227 | os.path.expanduser(file_path) |
| 228 | ) |
| 229 | except (ValueError, TypeError): |
| 230 | return None |
| 231 | else: |
| 232 | # User-supplied path: reject paths outside allowed directory. |
| 233 | # validate_api_key_path resolves symlinks and relative |
| 234 | # components via realpath, so use its result directly. |
| 235 | expanded_path = validate_api_key_path(file_path) |
| 236 | if expanded_path is None: |
| 237 | return None |
| 238 | |
| 239 | if not os.path.isfile(expanded_path): |
| 240 | return None |
| 241 | |
| 242 | try: |
| 243 | with open(expanded_path, 'r') as f: |
| 244 | raw = f.read(1025) |
| 245 | if len(raw) > 1024: |
| 246 | return None |
| 247 | key = raw.strip() |
| 248 | if not key: |
| 249 | return None |
| 250 | # An API key should be printable ASCII with no |
| 251 | # whitespace. Reject anything else to prevent misuse |
| 252 | # as an arbitrary file reader. |
| 253 | if not all(c.isascii() and c.isprintable() and |
| 254 | not c.isspace() for c in key): |
| 255 | return None |
| 256 | return key |
| 257 | except (IOError, OSError): |
| 258 | return None |
| 259 | |
| 260 | |
| 261 | # Public alias for use by refresh endpoints |