mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
vault: a sealed folder stays sealed
`:encrypt` on a folder sealed the files in it once; whatever arrived afterwards was plaintext. A folder or space that is encrypted now carries `sealed` (0015), and so does every folder under it, so "is this place sealed?" is one column of the parent. What lands there is sealed on the way in, or refused with 423 while the vault is shut: - uploads, with or without `?encrypt`, encrypted as they stream - imports, sealed where they lie before any row names them - SFTP writes, sealed out of their `.part`, and refused at the open when the vault is shut - files and folders moved in, through the web or SFTP: seal::enter seals them first and the move happens only if that worked Triggers make it hold for any path: a folder made inside a sealed one is sealed, and a file node whose media is not encrypted cannot be inserted into or moved into a sealed folder (a 400, not a 500). Decrypting the sealed folder lifts the flag on its subtree and opens its files; a file or folder inside it cannot be decrypted on its own. An empty folder can be sealed. Documents are not files and stay as they are. The list shows a lock on sealed folders, the touch menu offers to unseal one, and an upload or import into one asks for the vault password first. Tests cover sealing, inheritance, the trigger, moves with the vault open and shut, unsealing, an SFTP write and an import.
This commit is contained in:
1 parent
1ae0665206
commit
889f99f8d6
15 files changed
+659
-39
No files matched your search
+10
-6
@@ -75,12 +75,16 @@ const sealTarget = (encrypt: boolean) =>
|
||||
if (node.file && node.file.encrypted === encrypt) {
|
||||
return workspace.say(encrypt ? 'already in the vault' : 'not in the vault')
|
||||
}
|
||||
if (!encrypt && workspace.parentSealed) {
|
||||
return workspace.say(`this ${node.kind} is inside a sealed folder — decrypt that folder instead`, 'error')
|
||||
}
|
||||
const name = node.name || node.slug
|
||||
if (isContainer(node)) {
|
||||
const verb = encrypt ? 'seal every file in' : 'take every file in'
|
||||
const tail = encrypt ? 'into the vault' : 'out of the vault'
|
||||
if (!(await workspace.ask(`${verb} ${node.kind} "${node.name || node.slug}" ${tail}?`))) return
|
||||
const question = encrypt
|
||||
? `seal ${node.kind} "${name}" — every file in it now, and every file added later? documents stay readable`
|
||||
: `unseal ${node.kind} "${name}" and take every file in it out of the vault?`
|
||||
if (!(await workspace.ask(question))) return
|
||||
} else if (!encrypt) {
|
||||
const name = node.name || node.slug
|
||||
if (!(await workspace.ask(`store "${name}" unencrypted again, and in the readable files/ view on proton drive?`))) return
|
||||
}
|
||||
if (!(await workspace.ensureUnlocked())) return
|
||||
@@ -865,14 +869,14 @@ export const commands: CommandSpec[] = [
|
||||
name: 'encrypt',
|
||||
aliases: ['seal'],
|
||||
group: 'vault',
|
||||
help: 'seal the file under the cursor in the vault — on a folder, every file inside it',
|
||||
help: 'seal the file under the cursor in the vault — a folder stays sealed: every file in it, and every file added later',
|
||||
run: () => sealTarget(true),
|
||||
},
|
||||
{
|
||||
name: 'decrypt',
|
||||
aliases: ['unseal'],
|
||||
group: 'vault',
|
||||
help: 'take the file under the cursor back out of the vault — on a folder, every file inside it',
|
||||
help: 'take the file under the cursor back out of the vault — on a sealed folder, unseal it and every file inside',
|
||||
run: () => sealTarget(false),
|
||||
},
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user