8000 feat(security): encrypt the files Lens keeps at rest by adeelahmad · Pull Request #89 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(security): encrypt the files Lens keeps at rest - #89

Merged
adeelahmad merged 7 commits into
mainfrom
claude/project-thread-a0ft5t
Oct 3, 2026
Merged

adeelahmad merged 7 commits into
mainfrom
claude/project-thread-a0ft5t

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 3, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: uploads, email attachments, captured web pages and IIIF imports sat on disk as plain files.

After: with encryption.files on, each of those files is stored encrypted with its namespace's key from #77. Players still stream and seek, and downloads arrive exactly as uploaded. New archives turn this on at their first start. An archive that already has files keeps its setting until lens encrypt (or lens encrypt --off) converts it. Files in scanned folders are never rewritten. The Fedora copy (#88) still receives each file as it was, not Lens's encrypted form.

How:

  • keyring.protect() runs at each place a file is stored: uploads, supplementary files, attachment resources, web captures and IIIF imports. It runs after the fingerprint and probe, so fingerprints and sizes stay those of the plain file and duplicates are still recognised.
  • streaming.file_response and the new stored_file decrypt only the chunks a byte range touches. A locked vault answers 423 and a damaged file says so.
  • Tools that need a path (ffmpeg, pdftoppm, LibreOffice) get a plain working copy under data_dir/tmp/work, keeping its own name, through ingest.audio_path. A job, or one recording of a CLI batch, holds a shared flock on each copy until it ends. Sweeps remove only copies they can lock exclusively, once those copies have gone unused for encryption.work_minutes.
  • setup.mark_fresh turns encryption on only for an empty archive.

Planned next, as noted in docs/encryption.md: derived files (frames, renditions, reports, exports), the storage-source cache, re-keying on namespace moves, a web toggle that also converts existing files, and passkey vaults for the namespaces you choose.

Motivation and Context

This is the second step of encryption at rest, which Adeel asked for.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Because every test app starts as a fresh archive, the whole suite now runs with encryption on. Full local backend suite after merging main: 449 passed, 5 skipped. The one failure is the known LibreOffice environment failure (test_office_and_text_files_become_documents). Ruff and mypy are clean on the app. Four self-review rounds ran, and their findings are fixed in the later commits.

🤖 Generated with Claude Code

https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ

claude added 4 commits October 3, 2026 03:39
Uploads, email attachments, captured web pages, IIIF imports and
supplementary files are stored encrypted with their namespace's key when
encryption.files is on. Players still seek (only the chunks a range
touches are decrypted), downloads decrypt as they stream, and tools get a
plain working copy that is swept once unused. New archives start with it
on; lens encrypt converts an archive that already has files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ
…rypted downloads with ranges

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ
… copies being taken

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ
…-a0ft5t

# Conflicts:
#	CHANGELOG.md
#	fastapi_backend/app/domain/settings.py
@adeelahmad adeelahmad self-assigned this Oct 3, 2026
claude added 3 commits October 3, 2026 04:05
…nd never hand out a swept one

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R1moYBoaoY4cZFbhBWqzEJ
…-a0ft5t

# Conflicts:
#	CHANGELOG.md
#	fastapi_backend/app/domain/settings.py
@adeelahmad
adeelahmad merged commit e6336d1 into main Oct 3, 2026
0 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

470C Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0