+8
-8
README.md
+8
-8
README.md
···
1
1
# Cistern
2
2
3
3
Cistern is an attempt at implementing a private, personal quick-capture system
4
-
on AT Protocol. Cistern "items" are encrypted, so that they are only readable
5
-
by the holder of the correct secret key—stored off-protocol. These items are
4
+
on AT Protocol. Cistern "items" are encrypted, so that they are only readable by
5
+
the holder of the correct secret key—stored off-protocol. These items are
6
6
intended to be ephemeral, and to be deleted after they've been read.
7
7
8
8
The intention is for Cistern to bridge the gap between where ideas are had and
9
9
where they can be stored long-term. For example, let's say you have an idea
10
-
while at a restaurant. You create an item using your phone, and once you're
11
-
back at your desk and you open Obsidian, that item is automatically pulled from
12
-
your PDS, decrypted, and deleted from your PDS. If your notebook was open at
13
-
the time you created your item, the Cistern Obsidian plugin would have been
14
-
notified of the new item via the Jetstream, and so you would find your memo
15
-
waiting for you once you got home.
10
+
while at a restaurant. You create an item using your phone, and once you're back
11
+
at your desk and you open Obsidian, that item is automatically pulled from your
12
+
PDS, decrypted, and deleted from your PDS. If your notebook was open at the time
13
+
you created your item, the Cistern Obsidian plugin would have been notified of
14
+
the new item via the Jetstream, and so you would find your memo waiting for you
15
+
once you got home.
+1
-1
packages/crypto/deno.jsonc
+1
-1
packages/crypto/deno.jsonc
+4
-3
packages/crypto/src/keys.ts
+4
-3
packages/crypto/src/keys.ts
···
1
1
import { XWing } from "@noble/post-quantum/hybrid.js";
2
+
import type { KeyPair } from "./types.ts";
2
3
3
-
export function generateKeys() {
4
+
export function generateKeys(): KeyPair {
4
5
return XWing.keygen();
5
6
}
6
7
7
-
export function serializeKey(key: Uint8Array) {
8
+
export function serializeKey(key: Uint8Array): string {
8
9
return key.toBase64();
9
10
}
10
11
11
-
export function deserializeKey(key: string) {
12
+
export function deserializeKey(key: string): Uint8Array {
12
13
return Uint8Array.fromBase64(key);
13
14
}
+5
packages/crypto/src/types.ts
+5
packages/crypto/src/types.ts
+1
-1
packages/lexicon/deno.jsonc
+1
-1
packages/lexicon/deno.jsonc
+4
-4
packages/lexicon/mod.ts
+4
-4
packages/lexicon/mod.ts
···
1
1
import item from "./schemas/item.json" with { type: "json" };
2
2
import pubkey from "./schemas/pubkey.json" with { type: "json" };
3
3
4
-
import { Lexicons } from "@atproto/lexicon";
4
+
import { type LexiconDoc, Lexicons } from "@atproto/lexicon";
5
5
6
-
const lexicons = new Lexicons();
6
+
const lexicons: Lexicons = new Lexicons();
7
7
8
-
lexicons.add(item);
9
-
lexicons.add(pubkey);
8
+
lexicons.add(item as LexiconDoc);
9
+
lexicons.add(pubkey as LexiconDoc);
10
10
11
11
export { item, lexicons, pubkey };
+4
-4
packages/lexicon/schemas/item.json
+4
-4
packages/lexicon/schemas/item.json
···
1
1
{
2
-
"version": 1,
2
+
"lexicon": 1,
3
3
"id": "app.cistern.lexicon.item",
4
4
"description": "An encrypted memo intended to be accessed and deleted later.",
5
5
"defs": {
···
23
23
"type": "string",
24
24
"description": "TID representing when this item was created",
25
25
"format": "tid"
26
-
}
26
+
},
27
27
"ciphertext": {
28
28
"type": "string",
29
29
"description": "Encapsulated shared ciphertext",
···
32
32
"nonce": {
33
33
"type": "string",
34
34
"description": "Base64-encoded nonce used for content encryption",
35
-
"maxLength": 32,
35
+
"maxLength": 32
36
36
},
37
37
"algorithm": {
38
38
"type": "string",
···
50
50
},
51
51
"contentLength": {
52
52
"type": "integer",
53
-
"description": "Original content length in bytes",
53
+
"description": "Original content length in bytes"
54
54
},
55
55
"contentHash": {
56
56
"type": "string",