feat: database context
This commit is contained in:
30
web/src/util/account.ts
Normal file
30
web/src/util/account.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { deriveDeviceKey, getDeviceId } from "./deviceId";
|
||||
import { encryptToken } from "./token";
|
||||
|
||||
const storeTokensForAccount = async (
|
||||
accountId: string,
|
||||
accessToken: string,
|
||||
refreshToken: string
|
||||
) => {
|
||||
const deviceKeyId = await getDeviceId();
|
||||
const key = await deriveDeviceKey(deviceKeyId);
|
||||
|
||||
const access = await encryptToken(accessToken, key);
|
||||
const refresh = await encryptToken(refreshToken, key);
|
||||
|
||||
const entry = {
|
||||
accountId,
|
||||
label: `Account for ${accountId}`,
|
||||
access: {
|
||||
data: Array.from(new Uint8Array(access.cipherText)),
|
||||
iv: Array.from(access.iv),
|
||||
},
|
||||
refresh: {
|
||||
data: Array.from(new Uint8Array(refresh.cipherText)),
|
||||
iv: Array.from(refresh.iv),
|
||||
},
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
// Save this `entry` in IndexedDB (or use a localforage wrapper)
|
||||
};
|
@ -29,3 +29,26 @@ export const getDeviceId = async () => {
|
||||
|
||||
return deviceId; // A 64-character hex string
|
||||
};
|
||||
|
||||
export const deriveDeviceKey = async (deviceKeyId: string) => {
|
||||
const encoder = new TextEncoder();
|
||||
const baseKey = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
encoder.encode(deviceKeyId),
|
||||
{ name: "PBKDF2" },
|
||||
false,
|
||||
["deriveKey"]
|
||||
);
|
||||
return crypto.subtle.deriveKey(
|
||||
{
|
||||
name: "PBKDF2",
|
||||
salt: encoder.encode("guard_salt"),
|
||||
iterations: 100000,
|
||||
hash: "SHA-256",
|
||||
},
|
||||
baseKey,
|
||||
{ name: "AES-GCM", length: 256 },
|
||||
false,
|
||||
["encrypt", "decrypt"]
|
||||
);
|
||||
};
|
||||
|
18
web/src/util/token.ts
Normal file
18
web/src/util/token.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export type EncryptedToken = {
|
||||
cipherText: ArrayBuffer;
|
||||
iv: Uint8Array<ArrayBuffer>;
|
||||
};
|
||||
|
||||
export const encryptToken = async (
|
||||
token: string,
|
||||
key: CryptoKey
|
||||
): Promise<EncryptedToken> => {
|
||||
const encoder = new TextEncoder();
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
const cipherText = await crypto.subtle.encrypt(
|
||||
{ name: "AES-GCM", iv },
|
||||
key,
|
||||
encoder.encode(token)
|
||||
);
|
||||
return { cipherText, iv };
|
||||
};
|
Reference in New Issue
Block a user