Skip to content

Commit

Permalink
fix: reorganize a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
jurevans committed Sep 17, 2024
1 parent 4c8ea66 commit 90ba773
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 181 deletions.
6 changes: 6 additions & 0 deletions apps/namadillo/sw/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const sha256Hash = async (msg: Uint8Array): Promise<string> => {
const hashBuffer = await crypto.subtle.digest("SHA-256", msg);
const hashArray = Array.from(new Uint8Array(hashBuffer));
// Return hash as hex
return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
};
46 changes: 1 addition & 45 deletions apps/namadillo/sw/indexedDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let durability: IDBTransactionMode = "readwrite";
class IndexedDBKVStore<T> implements KVStore<T> {
protected cachedDB?: IDBDatabase;

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

public async get<U extends T>(key: string): Promise<U | undefined> {
const tx = (await this.getDB()).transaction([this.prefix()], "readonly");
Expand Down Expand Up @@ -106,48 +106,4 @@ class IndexedDBKVStore<T> implements KVStore<T> {
};
});
}

public static async durabilityCheck(): Promise<boolean> {
const { TARGET } = process.env;
let isDurable: boolean;

if (TARGET === "chrome") {
durability = "readwrite";
isDurable = true;
} else {
const prefix = "durability-check";
const db: IDBDatabase = await new Promise((resolve, reject) => {
const request = indexedDB.open(prefix);
request.onerror = (event) => {
event.stopPropagation();
reject(event.target);
};

request.onupgradeneeded = (event) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const db = event.target.result;

db.createObjectStore(prefix, { keyPath: "key" });
};

request.onsuccess = () => {
resolve(request.result);
};
});

try {
db.transaction([prefix], "readwriteflush" as IDBTransactionMode, {
durability: "strict",
});
durability = "readwriteflush" as IDBTransactionMode;
isDurable = true;
} catch {
durability = "readwrite";
isDurable = false;
}
}

return isDurable;
}
}
90 changes: 90 additions & 0 deletions apps/namadillo/sw/masp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
type MaspParamBytes = {
param: MaspParam;
bytes: Uint8Array;
};

const fetchMaspParam = async (
maspParam: MaspParam,
onRead?: (value?: Uint8Array) => void,
onComplete?: () => void
): Promise<MaspParamBytes> => {
return fetch([MASP_MPC_URL, maspParam].join("/"))
.then(async (response) => {
if (response.ok) {
const reader = response.body?.getReader();
if (!reader) {
throw new Error("No readable stream returned!");
}
return new ReadableStream({
start(controller) {
return pump();
function pump() {
return reader?.read().then(({ done, value }) => {
// Invoke callback if provided
if (onRead && value) onRead(value);
// When no more data needs to be consumed, close the stream
if (done) {
controller.close();
// Invoke callback if provided
if (onComplete) onComplete();
return;
}
// Enqueue the next data chunk into our target stream
controller.enqueue(value);
return pump();
});
}
},
});
}
})
.then((stream) => new Response(stream))
.then((response) => response.blob())
.then(async (blob) => {
const arrayBuffer = await blob.arrayBuffer();
return {
param: maspParam,
bytes: new Uint8Array(arrayBuffer),
};
});
};

const storeMaspParam = async ({
param,
bytes,
}: MaspParamBytes): Promise<MaspParamBytes> => {
console.info(`Storing ${param}...`);
await store.set(param, bytes);
return {
param,
bytes,
};
};

const validateMaspParamBytes = async ({
param,
bytes,
}: MaspParamBytes): Promise<MaspParamBytes> => {
const { length, sha256sum } = MASP_PARAM_LEN[param];

// Reject if invalid length (incomplete download or invalid)
console.log(`Validating data length for ${param}, expecting ${length}...`);

if (length !== bytes.length) {
return Promise.reject(
`Invalid data length! Expected ${length}, received ${bytes.length}!`
);
}

// Reject if invalid hash (otherwise invalid data)
console.log(`Validating sha256sum for ${param}, expecting ${sha256sum}...`);
const hash = await sha256Hash(bytes);

if (hash !== sha256sum) {
return Promise.reject(
`Invalid sha256sum! Expected ${sha256sum}, received ${hash}!`
);
}

return { param, bytes };
};
154 changes: 18 additions & 136 deletions apps/namadillo/sw/sw.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
importScripts("indexedDb.js");
importScripts("constants.js");
importScripts("crypto.js");
importScripts("fetch.js");
importScripts("masp.js");
importScripts("indexedDb.js");

const urlParams = new URLSearchParams(location.search);
const { isProxy } = Object.fromEntries(urlParams);

const MASP_MPC_URL =
isProxy === "true" ?
"http://localhost:8010/proxy"
: "https://github.com/anoma/masp-mpc/releases/download/namada-trusted-setup";
: "https://github.com/anoma/masp-mpc/releases/download/namada-trusted-setup";

const store = new IndexedDBKVStore(STORAGE_PREFIX);

Expand All @@ -17,142 +20,21 @@ const resetMaspParamStore = async (): Promise<void> => {
store.set(MaspParam.Convert, null);
};

const sha256Hash = async (msg: Uint8Array): Promise<string> => {
const hashBuffer = await crypto.subtle.digest("SHA-256", msg);
const hashArray = Array.from(new Uint8Array(hashBuffer));
// Return hash as hex
return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
};

type MaspParamBytes = {
param: MaspParam;
bytes: Uint8Array;
};

const fetchMaspParam = async (
maspParam: MaspParam,
onRead?: (value?: Uint8Array) => void,
onComplete?: () => void
): Promise<MaspParamBytes> => {
return fetch([MASP_MPC_URL, maspParam].join("/"))
.then(async (response) => {
if (response.ok) {
const reader = response.body?.getReader();
if (!reader) {
throw new Error("No readable stream returned!");
}
return new ReadableStream({
start(controller) {
return pump();
function pump() {
return reader?.read().then(({ done, value }) => {
// Invoke callback if provided
if (onRead && value) onRead(value);
// When no more data needs to be consumed, close the stream
if (done) {
controller.close();
// Invoke callback if provided
if (onComplete) onComplete();
return;
}
// Enqueue the next data chunk into our target stream
controller.enqueue(value);
return pump();
});
}
},
});
}
})
.then((stream) => new Response(stream))
.then((response) => response.blob())
.then(async (blob) => {
const arrayBuffer = await blob.arrayBuffer();
return {
param: maspParam,
bytes: new Uint8Array(arrayBuffer),
};
});
};

const storeMaspParam = async ({
param,
bytes,
}: MaspParamBytes): Promise<MaspParamBytes> => {
console.info(`Storing ${param} => `, bytes);
await store.set(param, bytes);
console.info(`Successfully stored ${param}`);

return {
param,
bytes,
};
};

const validateMaspParamBytes = async ({
param,
bytes,
}: MaspParamBytes): Promise<MaspParamBytes> => {
const { length, sha256sum } = MASP_PARAM_LEN[param];
// resetMaspParamStore();

// Reject if invalid length (incomplete download or invalid)
console.log(`Validating data length for ${param}, expecting ${length}...`);
const logSuccess = ({ param, bytes }: MaspParamBytes): void =>
console.info(`Fetched and stored ${param}`, bytes);

if (length !== bytes.length) {
return Promise.reject(
`Invalid data length! Expected ${length}, received ${bytes.length}!`
);
}
const logError = (e: any) => console.error(e);

// Reject if invalid hash (otherwise invalid data)
console.log(`Validating sha256sum for ${param}, expecting ${sha256sum}...`);
const hash = await sha256Hash(bytes);

if (hash !== sha256sum) {
return Promise.reject(
`Invalid sha256sum! Expected ${sha256sum}, received ${hash}!`
);
}

return { param, bytes };
};

const logSuccess = ({ param, bytes }: MaspParamBytes): void => {
console.info(`Fetched and stored ${param}:`, bytes);
};

// MOVE TO INVOKE IN HANDLER
(async () => {
const maspOutputParamBytes = await store.get(MaspParam.Output);
console.log("Found output?: ", maspOutputParamBytes);

const maspSpendParamBytes = await store.get(MaspParam.Spend);
console.log("Found spend?: ", maspSpendParamBytes);

const maspConvertParamBytes = await store.get(MaspParam.Convert);
console.log("Found convert?", maspConvertParamBytes);

if (!maspOutputParamBytes) {
await fetchMaspParam(MaspParam.Output)
.then(validateMaspParamBytes)
.then(storeMaspParam)
.then(logSuccess)
.catch((e) => console.error(e));
}

if (!maspSpendParamBytes) {
await fetchMaspParam(MaspParam.Spend)
.then(validateMaspParamBytes)
.then(storeMaspParam)
.then(logSuccess)
.catch((e) => console.error(e));
}

if (!maspConvertParamBytes) {
await fetchMaspParam(MaspParam.Convert)
.then(validateMaspParamBytes)
.then(storeMaspParam)
.then(logSuccess)
.catch((e) => console.error(e));
}
[MaspParam.Output, MaspParam.Spend, MaspParam.Convert].map(async (param) => {
if (!(await store.get(param))) {
await fetchMaspParam(param)
.then(validateMaspParamBytes)
.then(storeMaspParam)
.then(logSuccess)
.catch(logError);
}
});
})();

0 comments on commit 90ba773

Please sign in to comment.