-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstorage.js
More file actions
199 lines (171 loc) · 6.07 KB
/
Copy pathstorage.js
File metadata and controls
199 lines (171 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**
* Podkey - Secure storage for Nostr keys
*
* Two layers, by design:
* - At rest: the private key is persisted only as an AES-GCM ciphertext via
* vault.js (chrome.storage.local, passphrase-wrapped). The raw key never
* touches disk.
* - In use: once unlocked, the plaintext private key is cached here in
* chrome.storage.session (in-memory, browser-session scoped) so signing is
* fast. A browser restart clears the session; the user re-unlocks with
* their passphrase (see vault.unlockVault).
*
* Public keys remain in chrome.storage.local so the popup can display the
* user's pubkey/DID even while the vault is locked.
*/
const STORAGE_KEYS = {
PRIVATE_KEY: 'podkey_private_key',
PUBLIC_KEY: 'podkey_public_key',
TRUSTED_ORIGINS: 'podkey_trusted_origins',
AUTO_SIGN: 'podkey_auto_sign',
PROFILES: 'podkey_profiles',
CURRENT_PROFILE: 'podkey_current_profile'
};
/**
* Store keypair securely.
* Private key goes to session storage (in-memory only).
* Public key goes to local storage (persisted, but not secret).
* @param {string} privateKey - 64-char hex private key
* @param {string} publicKey - 64-char hex public key
*/
export async function storeKeypair(privateKey, publicKey) {
// Validate key formats
if (privateKey.length !== 64 || publicKey.length !== 64) {
throw new Error('Keys must be 64-char hex');
}
// Private key: session storage only (in-memory, never written to disk)
await chrome.storage.session.set({
[STORAGE_KEYS.PRIVATE_KEY]: privateKey
});
// Public key: local storage (needs to survive service worker restarts
// so the popup can show the user's identity without the private key)
await chrome.storage.local.set({
[STORAGE_KEYS.PUBLIC_KEY]: publicKey
});
// Remove any legacy private key from local storage left by older versions
await chrome.storage.local.remove([STORAGE_KEYS.PRIVATE_KEY]);
console.log('[Podkey] Keypair stored (private key in session storage only)');
}
/**
* Get stored keypair.
* Private key comes from session storage, public key from local storage.
* Returns null if either key is missing (e.g. service worker restarted and
* session storage was cleared -- user will need to re-import).
* @returns {Promise<{privateKey: string, publicKey: string} | null>}
*/
export async function getKeypair() {
const { [STORAGE_KEYS.PRIVATE_KEY]: privateKey } =
await chrome.storage.session.get([STORAGE_KEYS.PRIVATE_KEY]);
const { [STORAGE_KEYS.PUBLIC_KEY]: publicKey } =
await chrome.storage.local.get([STORAGE_KEYS.PUBLIC_KEY]);
if (!privateKey || !publicKey) {
return null;
}
return { privateKey, publicKey };
}
/**
* Check if a usable keypair exists (private key in session + public key on disk).
* @returns {Promise<boolean>}
*/
export async function hasKeypair() {
const keypair = await getKeypair();
return keypair !== null;
}
/**
* Check if a public key exists on disk (may not have a private key in session).
* Useful for the popup to show identity even when the session has expired.
* @returns {Promise<string|null>} The public key hex, or null
*/
export async function getStoredPublicKey() {
const { [STORAGE_KEYS.PUBLIC_KEY]: publicKey } =
await chrome.storage.local.get([STORAGE_KEYS.PUBLIC_KEY]);
return publicKey || null;
}
/**
* Delete stored keypair from both session and local storage.
* @returns {Promise<void>}
*/
export async function deleteKeypair() {
await chrome.storage.session.remove([STORAGE_KEYS.PRIVATE_KEY]);
await chrome.storage.local.remove([
STORAGE_KEYS.PRIVATE_KEY, // clean up any legacy local copy
STORAGE_KEYS.PUBLIC_KEY
]);
console.log('[Podkey] Keypair deleted from all storage');
}
/**
* Lock the session: drop the in-memory private key but keep the encrypted
* vault and public key on disk. The user re-unlocks with their passphrase.
* @returns {Promise<void>}
*/
export async function clearSessionKey() {
await chrome.storage.session.remove([STORAGE_KEYS.PRIVATE_KEY]);
}
/**
* Add a trusted origin
* @param {string} origin - Origin to trust (e.g., https://example.com)
*/
export async function addTrustedOrigin(origin) {
const { [STORAGE_KEYS.TRUSTED_ORIGINS]: trusted = {} } =
await chrome.storage.local.get([STORAGE_KEYS.TRUSTED_ORIGINS]);
trusted[origin] = {
addedAt: Date.now(),
lastUsed: Date.now()
};
await chrome.storage.local.set({
[STORAGE_KEYS.TRUSTED_ORIGINS]: trusted
});
}
/**
* Remove a trusted origin
* @param {string} origin - Origin to untrust
*/
export async function removeTrustedOrigin(origin) {
const { [STORAGE_KEYS.TRUSTED_ORIGINS]: trusted = {} } =
await chrome.storage.local.get([STORAGE_KEYS.TRUSTED_ORIGINS]);
delete trusted[origin];
await chrome.storage.local.set({
[STORAGE_KEYS.TRUSTED_ORIGINS]: trusted
});
}
/**
* Check if origin is trusted
* @param {string} origin - Origin to check
* @returns {Promise<boolean>}
*/
export async function isTrustedOrigin(origin) {
const { [STORAGE_KEYS.TRUSTED_ORIGINS]: trusted = {} } =
await chrome.storage.local.get([STORAGE_KEYS.TRUSTED_ORIGINS]);
return trusted[origin] !== undefined;
}
/**
* Get all trusted origins
* @returns {Promise<Object>} Map of origin -> metadata
*/
export async function getTrustedOrigins() {
const { [STORAGE_KEYS.TRUSTED_ORIGINS]: trusted = {} } =
await chrome.storage.local.get([STORAGE_KEYS.TRUSTED_ORIGINS]);
return trusted;
}
/**
* Get auto-sign setting.
* Defaults to OFF: a freshly installed extension must not silently sign or
* auto-trust any origin (including recognised Solid hosts) until the user
* deliberately enables auto-sign from the popup. This keeps the silent
* trusted-origin Solid / NIP-98 path strictly opt-in.
* @returns {Promise<boolean>}
*/
export async function getAutoSign() {
const { [STORAGE_KEYS.AUTO_SIGN]: autoSign = false } =
await chrome.storage.local.get([STORAGE_KEYS.AUTO_SIGN]);
return autoSign;
}
/**
* Set auto-sign setting
* @param {boolean} enabled - Enable or disable auto-sign
*/
export async function setAutoSign(enabled) {
await chrome.storage.local.set({
[STORAGE_KEYS.AUTO_SIGN]: enabled
});
}