Skip to content

Commit

Permalink
feat: create utility store
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszjasiuk committed Jul 10, 2023
1 parent 5ac2bcf commit b9ad4ee
Show file tree
Hide file tree
Showing 13 changed files with 48 additions and 52 deletions.
11 changes: 4 additions & 7 deletions apps/extension/src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import {
init as initKeyRing,
SDK_KEY,
PARENT_ACCOUNT_ID_KEY,
UtilityStore,
} from "./keyring";

const store = new IndexedDBKVStore(KVPrefix.IndexedDB);

const activeAccountStore = new IndexedDBKVStore(KVPrefix.ActiveAccount);
const authkeyStore = new IndexedDBKVStore(KVPrefix.ActiveAccount);
const utilityStore = new IndexedDBKVStore<UtilityStore>(KVPrefix.Utility);
// TODO: For now we will be running two stores side by side
const sdkStore = new IndexedDBKVStore(KVPrefix.SDK);
const extensionStore = new ExtensionKVStore(KVPrefix.LocalStorage, {
Expand Down Expand Up @@ -72,9 +72,7 @@ const { REACT_APP_NAMADA_URL = DEFAULT_URL } = process.env;
const sdkData: Record<string, string> | undefined = await sdkStore.get(
SDK_KEY
);
const activeAccount = await activeAccountStore.get<string>(
PARENT_ACCOUNT_ID_KEY
);
const activeAccount = await utilityStore.get<string>(PARENT_ACCOUNT_ID_KEY);

if (sdkData && activeAccount) {
const data = new TextEncoder().encode(sdkData[activeAccount]);
Expand All @@ -85,8 +83,7 @@ const { REACT_APP_NAMADA_URL = DEFAULT_URL } = process.env;
const keyRingService = new KeyRingService(
store,
sdkStore,
activeAccountStore,
authkeyStore,
utilityStore,
connectedTabsStore,
extensionStore,
defaultChainId,
Expand Down
4 changes: 2 additions & 2 deletions apps/extension/src/background/keyring/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ export class Crypto {
const aes = new AES(newKey, cipher.iv);
const vecU8Pointer = aes.decrypt(cipher.text);
const decrypted = readVecU8Pointer(vecU8Pointer, cryptoMemory);
const phrase = new TextDecoder().decode(decrypted);
const plainText = new TextDecoder().decode(decrypted);

aes.free();
vecU8Pointer.free();

return phrase;
return plainText;
}

private encryptionParams(password: string): {
Expand Down
19 changes: 11 additions & 8 deletions apps/extension/src/background/keyring/keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
ResetPasswordError,
DeleteAccountError,
CryptoRecord,
UtilityStore,
} from "./types";
import {
readVecStringPointer,
Expand Down Expand Up @@ -85,8 +86,7 @@ export class KeyRing {
constructor(
protected readonly kvStore: KVStore<KeyStore[]>,
protected readonly sdkStore: KVStore<Record<string, string>>,
protected readonly activeAccountStore: KVStore<string>,
protected readonly authkeyStore: KVStore<{ [id: string]: CryptoRecord }>,
protected readonly utilityStore: KVStore<UtilityStore>,
protected readonly extensionStore: KVStore<number>,
protected readonly chainId: string,
protected readonly sdk: Sdk,
Expand Down Expand Up @@ -118,11 +118,11 @@ export class KeyRing {
}

public async getActiveAccountId(): Promise<string | undefined> {
return await this.activeAccountStore.get(PARENT_ACCOUNT_ID_KEY);
return await this.utilityStore.get(PARENT_ACCOUNT_ID_KEY);
}

public async setActiveAccountId(parentId: string): Promise<void> {
await this.activeAccountStore.set(PARENT_ACCOUNT_ID_KEY, parentId);
await this.utilityStore.set(PARENT_ACCOUNT_ID_KEY, parentId);

// To sync sdk wallet with DB
const sdkData = await this.sdkStore.get(SDK_KEY);
Expand All @@ -141,8 +141,9 @@ export class KeyRing {
throw new Error("No account to check password against");
}

const authKeys = await this.authkeyStore.get(AUTHKEY_KEY);
// TODO: Generate arbitrary data to check decryption against
const authKeys = await this.utilityStore.get<{
[id: string]: CryptoRecord;
}>(AUTHKEY_KEY);
if (authKeys) {
try {
crypto.decrypt(authKeys[idToCheck], password, this._cryptoMemory);
Expand Down Expand Up @@ -291,8 +292,10 @@ export class KeyRing {
): Promise<void> {
const id = uuidV4();
const authKey = crypto.encryptAuthKey(password, id);
const entries = await this.authkeyStore.get(AUTHKEY_KEY);
await this.authkeyStore.set(AUTHKEY_KEY, {
const entries = await this.utilityStore.get<{ [id: string]: CryptoRecord }>(
AUTHKEY_KEY
);
await this.utilityStore.set(AUTHKEY_KEY, {
...entries,
[accountId]: authKey,
});
Expand Down
8 changes: 3 additions & 5 deletions apps/extension/src/background/keyring/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
TabStore,
ResetPasswordError,
DeleteAccountError,
CryptoRecord,
UtilityStore,
} from "./types";
import { syncTabs, updateTabStorage } from "./utils";
import { ExtensionRequester, getAnomaRouterId } from "extension";
Expand All @@ -38,8 +38,7 @@ export class KeyRingService {
constructor(
protected readonly kvStore: KVStore<KeyStore[]>,
protected readonly sdkStore: KVStore<Record<string, string>>,
protected readonly accountAccountStore: KVStore<string>,
protected readonly authkeyStore: KVStore<{ [id: string]: CryptoRecord }>,
protected readonly utilityStore: KVStore<UtilityStore>,
protected readonly connectedTabsStore: KVStore<TabStore[]>,
protected readonly extensionStore: KVStore<number>,
protected readonly chainId: string,
Expand All @@ -51,8 +50,7 @@ export class KeyRingService {
this._keyRing = new KeyRing(
kvStore,
sdkStore,
accountAccountStore,
authkeyStore,
utilityStore,
extensionStore,
chainId,
sdk,
Expand Down
2 changes: 2 additions & 0 deletions apps/extension/src/background/keyring/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export type TabStore = {
timestamp: number;
};

export type UtilityStore = string | { [id: string]: CryptoRecord };

export enum ResetPasswordError {
BadPassword,
KeyStoreError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ import {
(async function init() {
await initShared();
const sdkStore = new IndexedDBKVStore(KVPrefix.SDK);
const activeAccountStore = new IndexedDBKVStore(KVPrefix.ActiveAccount);
const utilityStore = new IndexedDBKVStore(KVPrefix.Utility);
const sdk = new Sdk(chains[defaultChainId].rpc);
await sdk.load_masp_params();

//TODO: import sdk-store and parent-account-id keys - can't import from the keyring
const sdkData: Record<string, string> | undefined = await sdkStore.get(
"sdk-store"
);
const activeAccount = await activeAccountStore.get<string>(
"parent-account-id"
);
const activeAccount = await utilityStore.get<string>("parent-account-id");

if (sdkData && activeAccount) {
const data = new TextEncoder().encode(sdkData[activeAccount]);
Expand Down
7 changes: 4 additions & 3 deletions apps/extension/src/provider/Anoma.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
KeyStore,
KEYSTORE_KEY,
PARENT_ACCOUNT_ID_KEY,
UtilityStore,
} from "background/keyring";
import { Sdk } from "@anoma/shared";
import * as utils from "extension/utils";
Expand All @@ -36,12 +37,12 @@ jest.mock("webextension-polyfill", () => ({}));
describe("Anoma", () => {
let anoma: Anoma;
let iDBStore: KVStoreMock<Chain[] | KeyStore[]>;
let activeAccountStore: KVStoreMock<string>;
let utilityStore: KVStoreMock<UtilityStore>;
let keyRingService: KeyRingService;

beforeAll(async () => {
jest.spyOn(utils, "getAnomaRouterId").mockResolvedValue(1);
({ anoma, iDBStore, activeAccountStore, keyRingService } = await init());
({ anoma, iDBStore, utilityStore, keyRingService } = await init());

jest
.spyOn(KeyRing.prototype, "checkPassword")
Expand Down Expand Up @@ -70,7 +71,7 @@ describe("Anoma", () => {

it("should return all accounts", async () => {
iDBStore.set(KEYSTORE_KEY, keyStore);
activeAccountStore.set(PARENT_ACCOUNT_ID_KEY, ACTIVE_ACCOUNT_ID);
utilityStore.set(PARENT_ACCOUNT_ID_KEY, ACTIVE_ACCOUNT_ID);
const storedKeyStore = keyStore.map(
({ crypto: _crypto, owner: _owner, ...account }) => account
);
Expand Down
2 changes: 1 addition & 1 deletion apps/extension/src/router/types/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export enum KVPrefix {
LocalStorage = "Anoma::LocalStorage",
Memory = "Anoma::Memory",
SDK = "Anoma::SDK",
ActiveAccount = "Anoma::ActiveAccount",
Utility = "Anoma::Utility",
ConnectedTabs = "Anoma::ConnectedTabs",
}

Expand Down
25 changes: 12 additions & 13 deletions apps/extension/src/test/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
init as initKeyRing,
KeyStore,
TabStore,
CryptoRecord,
UtilityStore,
} from "../background/keyring";

import {
Expand All @@ -34,12 +34,15 @@ const chainId = "namada-75a7e12.69483d59a9fb174";
export class KVStoreMock<T> implements KVStore<T> {
private storage: { [key: string]: T | null } = {};

constructor(private readonly _prefix: string) {}
constructor(readonly _prefix: string) {}

get(key: string): Promise<T | undefined> {
return Promise.resolve(this.storage[key] || undefined);
get<U extends T>(key: string): Promise<U | undefined> {
return new Promise((resolve) => {
const data = this.storage[key];
return resolve(data ? (data as U) : undefined);
});
}
set(key: string, data: T | null): Promise<void> {
set<U extends T>(key: string, data: U | null): Promise<void> {
this.storage[key] = data;
return Promise.resolve();
}
Expand All @@ -52,18 +55,15 @@ export const init = async (): Promise<{
anoma: Anoma;
iDBStore: KVStoreMock<Chain[] | KeyStore[]>;
extStore: KVStoreMock<number>;
activeAccountStore: KVStoreMock<string>;
utilityStore: KVStoreMock<UtilityStore>;
chainsService: ChainsService;
keyRingService: KeyRingService;
}> => {
const messenger = new ExtensionMessengerMock();
const iDBStore = new KVStoreMock<Chain[] | KeyStore[]>(KVPrefix.IndexedDB);
const sdkStore = new KVStoreMock<Record<string, string>>(KVPrefix.SDK);
const extStore = new KVStoreMock<number>(KVPrefix.IndexedDB);
const activeAccountStore = new KVStoreMock<string>(KVPrefix.ActiveAccount);
const authKeyStore = new KVStoreMock<{ [id: string]: CryptoRecord }>(
KVPrefix.ActiveAccount
);
const utilityStore = new KVStoreMock<UtilityStore>(KVPrefix.Utility);
const connectedTabsStore = new KVStoreMock<TabStore[]>(
KVPrefix.ConnectedTabs
);
Expand Down Expand Up @@ -93,8 +93,7 @@ export const init = async (): Promise<{
const keyRingService = new KeyRingService(
iDBStore as KVStore<KeyStore[]>,
sdkStore,
activeAccountStore,
authKeyStore,
utilityStore,
connectedTabsStore,
extStore,
chainId,
Expand Down Expand Up @@ -125,7 +124,7 @@ export const init = async (): Promise<{
anoma,
iDBStore,
extStore,
activeAccountStore,
utilityStore,
chainsService,
keyRingService,
};
Expand Down
3 changes: 1 addition & 2 deletions packages/crypto/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ lto = true
opt-level = "s"

[profile.dev]
# We do not wan't to make any optimizations for dev
opt-level = 0
opt-level = "s"

# wasm-pack sepcific configuration
[package.metadata.wasm-pack.profile.release]
Expand Down
3 changes: 1 addition & 2 deletions packages/shared/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ lto = true
opt-level = "s"

[profile.dev]
# We do not wan't to make any optimizations for dev
opt-level = 0
opt-level = "s"

# wasm-pack sepcific configuration
[package.metadata.wasm-pack.profile.release]
Expand Down
6 changes: 3 additions & 3 deletions packages/storage/src/store/IndexedDBKVStore.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { KVStore } from "./types";

export class IndexedDBKVStore<T> implements KVStore<T[]> {
export class IndexedDBKVStore<T> implements KVStore<T> {
protected cachedDB?: IDBDatabase;

constructor(protected readonly _prefix: string) {}

public async get<T = unknown>(key: string): Promise<T | undefined> {
public async get<U extends T>(key: string): Promise<U | undefined> {
const tx = (await this.getDB()).transaction([this.prefix()], "readonly");
const store = tx.objectStore(this.prefix());

Expand All @@ -26,7 +26,7 @@ export class IndexedDBKVStore<T> implements KVStore<T[]> {
});
}

public async set<T = unknown>(key: string, data: T | null): Promise<void> {
public async set<U extends T>(key: string, data: U | null): Promise<void> {
if (data === null) {
const tx = (await this.getDB()).transaction([this.prefix()], "readwrite");
const store = tx.objectStore(this.prefix());
Expand Down
4 changes: 2 additions & 2 deletions packages/storage/src/store/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface KVStore<T> {
get(key: string): Promise<T | undefined>;
set(key: string, data: T | null): Promise<void>;
get<U extends T>(key: string): Promise<U | undefined>;
set<U extends T>(key: string, data: U | null): Promise<void>;
prefix(): string;
}

Expand Down

0 comments on commit b9ad4ee

Please sign in to comment.