Encrypted at rest unless it ca... Note

Encrypted at rest unless it cannot be, and the file itself says which

Notifio's auto-reply feature records user replies to create future automated responses, storing this data locally without uploading it anywhere. The entire security boundary for this sensitive data is the local file on the user's disk. Electron’s safeStorage provides encryption, but its availability is not guaranteed across all Linux environments, leading to a need for graceful fallback.To manage this, every file written by Notifio includes an "enc" field in its "Envelope" structure, explicitly stating whether it was encrypted or saved as plaintext. This prevents ambiguity between encrypted and corrupt data, which would otherwise both appear as parsing failures. The "writeEnvelope" function uses safeStorage when available, encrypting the data; otherwise, it saves it as a plaintext JSON string.This design makes a conscious decision to prioritize availability over confidentiality in scenarios where encryption is not possible, such as on a Linux machine without a running keyring. In such cases, the data is saved as plaintext within the user's home directory, ensuring the feature remains functional. The "readEnvelope" function explicitly checks the "enc" field, refusing to guess the file's format and throwing an error if encrypted data cannot be decrypted.The "Envelope" itself has a version number, separate from the content's version, acknowledging that container format and content shape change independently. The "canEncrypt" function handles safeStorage's potential non-availability gracefully, returning false instead of throwing errors outside Electron environments. This approach ensures that modules can be loaded and tested reliably without platform API dependencies.Crucially, the read path explicitly refuses to guess the file format. If a file claims to be encrypted but safeStorage is unavailable, it throws a specific error, preventing attempts to parse ciphertext as content. This clear error reporting is vital for support and debugging, distinguishing between encryption failures and general corruption.While reading a corrupted file will return a fallback, potentially leading to overwrites, this risk is mitigated by the specific nature of the data (e.g., a single boolean, or recordings only written when new content is added). The same envelope format is used for both settings and recordings files, streamlining the encryption path and simplifying debugging if persistence issues arise.When data structures evolve, migrations may drop fields that still need to be accessed for legacy purposes. In such cases, a specific "legacyMessage" function bypasses the main migration to retrieve old data, acknowledging that deleting fields is not entirely without cost. The overarching rule is that a file should explicitly state how it was written, facilitating clear error handling and enabling external analysis without requiring specific code execution.