Browse Source

Refactored last viewed notification code. Appears to work now.

home-view-notification-improvements
Matthew Raymer 1 year ago
parent
commit
2b8cd180a1
  1. 7
      sw_scripts/additional-scripts.js
  2. 818
      sw_scripts/safari-notifications.js

7
sw_scripts/additional-scripts.js

@ -5,14 +5,12 @@ importScripts(
); );
self.addEventListener("install", (event) => { self.addEventListener("install", (event) => {
console.log("Install event fired.");
importScripts( importScripts(
"safari-notifications.js", "safari-notifications.js",
"nacl.js", "nacl.js",
"noble-curves.js", "noble-curves.js",
"noble-hashes.js", "noble-hashes.js",
); );
console.log("scripts imported", event);
}); });
self.addEventListener("push", function (event) { self.addEventListener("push", function (event) {
@ -23,10 +21,10 @@ self.addEventListener("push", function (event) {
if (event.data) { if (event.data) {
payload = JSON.parse(event.data.text()); payload = JSON.parse(event.data.text());
} }
const value = await self.getNotificationCount(); const message = await self.getNotificationCount();
const title = payload ? payload.title : "Custom Title"; const title = payload ? payload.title : "Custom Title";
const options = { const options = {
body: payload ? value : "SAMPLE", body: message,
icon: payload ? payload.icon : "icon.png", icon: payload ? payload.icon : "icon.png",
badge: payload ? payload.badge : "badge.png", badge: payload ? payload.badge : "badge.png",
}; };
@ -41,7 +39,6 @@ self.addEventListener("push", function (event) {
self.addEventListener("message", (event) => { self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SEND_LOCAL_DATA") { if (event.data && event.data.type === "SEND_LOCAL_DATA") {
self.secret = event.data.data; self.secret = event.data.data;
console.log("Data stored in service worker:", self.secret);
event.ports[0].postMessage({ success: true }); event.ports[0].postMessage({ success: true });
} }
}); });

818
sw_scripts/safari-notifications.js

@ -1,37 +1,36 @@
function bufferFromBase64(base64) { function bufferFromBase64(base64) {
const binaryString = atob(base64); const binaryString = atob(base64);
const length = binaryString.length; const length = binaryString.length;
const bytes = new Uint8Array(length); const bytes = new Uint8Array(length);
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
bytes[i] = binaryString.charCodeAt(i); bytes[i] = binaryString.charCodeAt(i);
} }
return bytes; return bytes;
} }
function fromString(str, encoding = "utf8") { function fromString(str, encoding = "utf8") {
if (encoding === "utf8") { if (encoding === "utf8") {
return new TextEncoder().encode(str); return new TextEncoder().encode(str);
} else if (encoding === "base16") { } else if (encoding === "base16") {
if (str.length % 2 !== 0) { if (str.length % 2 !== 0) {
throw new Error("Invalid hex string length."); throw new Error("Invalid hex string length.");
} }
let bytes = new Uint8Array(str.length / 2); let bytes = new Uint8Array(str.length / 2);
for (let i = 0; i < str.length; i += 2) { for (let i = 0; i < str.length; i += 2) {
bytes[i / 2] = parseInt(str.substring(i, i + 2), 16); bytes[i / 2] = parseInt(str.substring(i, i + 2), 16);
}
return bytes;
} else if (encoding === "base64url") {
str = str.replace(/-/g, "+").replace(/_/g, "/");
while (str.length % 4) {
str += "=";
}
return new Uint8Array(bufferFromBase64(str));
} else {
throw new Error(`Unsupported encoding "${encoding}"`);
} }
return bytes;
} else if (encoding === "base64url") {
str = str.replace(/-/g, "+").replace(/_/g, "/");
while (str.length % 4) {
str += "=";
}
return new Uint8Array(bufferFromBase64(str));
} else {
throw new Error(`Unsupported encoding "${encoding}"`);
}
} }
/** /**
@ -43,16 +42,16 @@ function fromString(str, encoding = "utf8") {
* @throws {Error} - Throws an error if the encoding is unsupported. * @throws {Error} - Throws an error if the encoding is unsupported.
*/ */
function toString(byteArray, encoding = "utf8") { function toString(byteArray, encoding = "utf8") {
switch (encoding) { switch (encoding) {
case "utf8": case "utf8":
return decodeUTF8(byteArray); return decodeUTF8(byteArray);
case "base16": case "base16":
return toBase16(byteArray); return toBase16(byteArray);
case "base64url": case "base64url":
return toBase64Url(byteArray); return toBase64Url(byteArray);
default: default:
throw new Error(`Unsupported encoding "${encoding}"`); throw new Error(`Unsupported encoding "${encoding}"`);
} }
} }
/** /**
@ -62,7 +61,7 @@ function toString(byteArray, encoding = "utf8") {
* @returns {string} * @returns {string}
*/ */
function decodeUTF8(byteArray) { function decodeUTF8(byteArray) {
return new TextDecoder().decode(byteArray); return new TextDecoder().decode(byteArray);
} }
/** /**
@ -72,9 +71,9 @@ function decodeUTF8(byteArray) {
* @returns {string} * @returns {string}
*/ */
function toBase16(byteArray) { function toBase16(byteArray) {
return Array.from(byteArray) return Array.from(byteArray)
.map((byte) => byte.toString(16).padStart(2, "0")) .map((byte) => byte.toString(16).padStart(2, "0"))
.join(""); .join("");
} }
/** /**
@ -84,475 +83,462 @@ function toBase16(byteArray) {
* @returns {string} * @returns {string}
*/ */
function toBase64Url(byteArray) { function toBase64Url(byteArray) {
let uint8Array = new Uint8Array(byteArray); let uint8Array = new Uint8Array(byteArray);
let binaryString = ""; let binaryString = "";
for (let i = 0; i < uint8Array.length; i++) { for (let i = 0; i < uint8Array.length; i++) {
binaryString += String.fromCharCode(uint8Array[i]); binaryString += String.fromCharCode(uint8Array[i]);
} }
// Encode to base64 // Encode to base64
let base64 = btoa(binaryString); let base64 = btoa(binaryString);
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
} }
const u8a = { toString, fromString }; const u8a = { toString, fromString };
function sha256(payload) { function sha256(payload) {
const data = typeof payload === "string" ? u8a.fromString(payload) : payload; const data = typeof payload === "string" ? u8a.fromString(payload) : payload;
return nobleHashes.sha256(data); return nobleHashes.sha256(data);
} }
async function accessToken(identifier) { async function accessToken(identifier) {
const did = identifier["did"]; const did = identifier["did"];
const privateKeyHex = identifier["keys"][0]["privateKeyHex"]; const privateKeyHex = identifier["keys"][0]["privateKeyHex"];
const signer = await SimpleSigner(privateKeyHex); const signer = await SimpleSigner(privateKeyHex);
const nowEpoch = Math.floor(Date.now() / 1000); const nowEpoch = Math.floor(Date.now() / 1000);
const endEpoch = nowEpoch + 60; // add one minute const endEpoch = nowEpoch + 60; // add one minute
const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did };
const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R
const jwt = await createJWT(tokenPayload, { const jwt = await createJWT(tokenPayload, {
alg, alg,
issuer: did, issuer: did,
signer, signer,
}); });
console.error(jwt); return jwt;
return jwt;
} }
async function createJWT(payload, options, header = {}) { async function createJWT(payload, options, header = {}) {
const { issuer, signer, alg, expiresIn, canonicalize } = options; const { issuer, signer, alg, expiresIn, canonicalize } = options;
if (!signer) if (!signer)
throw new Error( throw new Error(
"missing_signer: No Signer functionality has been configured", "missing_signer: No Signer functionality has been configured",
); );
if (!issuer) if (!issuer)
throw new Error("missing_issuer: No issuing DID has been configured"); throw new Error("missing_issuer: No issuing DID has been configured");
if (!header.typ) header.typ = "JWT"; if (!header.typ) header.typ = "JWT";
if (!header.alg) header.alg = alg; if (!header.alg) header.alg = alg;
const timestamps = { const timestamps = {
iat: Math.floor(Date.now() / 1000), iat: Math.floor(Date.now() / 1000),
exp: undefined, exp: undefined,
}; };
if (expiresIn) { if (expiresIn) {
if (typeof expiresIn === "number") { if (typeof expiresIn === "number") {
timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn); timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn);
} else { } else {
throw new Error("invalid_argument: JWT expiresIn is not a number"); throw new Error("invalid_argument: JWT expiresIn is not a number");
}
} }
}
const fullPayload = { ...timestamps, ...payload, iss: issuer }; const fullPayload = { ...timestamps, ...payload, iss: issuer };
return createJWS(fullPayload, signer, header, { canonicalize }); return createJWS(fullPayload, signer, header, { canonicalize });
} }
const defaultAlg = "ES256K"; const defaultAlg = "ES256K";
async function createJWS(payload, signer, header = {}, options = {}) { async function createJWS(payload, signer, header = {}, options = {}) {
if (!header.alg) header.alg = defaultAlg; if (!header.alg) header.alg = defaultAlg;
const encodedPayload = const encodedPayload =
typeof payload === "string" typeof payload === "string"
? payload ? payload
: encodeSection(payload, options.canonicalize); : encodeSection(payload, options.canonicalize);
const signingInput = [ const signingInput = [
encodeSection(header, options.canonicalize), encodeSection(header, options.canonicalize),
encodedPayload, encodedPayload,
].join("."); ].join(".");
const jwtSigner = ES256KSignerAlg(false); const jwtSigner = ES256KSignerAlg(false);
const signature = await jwtSigner(signingInput, signer); const signature = await jwtSigner(signingInput, signer);
// JWS Compact Serialization // JWS Compact Serialization
// https://www.rfc-editor.org/rfc/rfc7515#section-7.1 // https://www.rfc-editor.org/rfc/rfc7515#section-7.1
return [signingInput, signature].join("."); return [signingInput, signature].join(".");
} }
function canonicalizeData(object) { function canonicalizeData(object) {
if (typeof object === "number" && isNaN(object)) { if (typeof object === "number" && isNaN(object)) {
throw new Error("NaN is not allowed"); throw new Error("NaN is not allowed");
} }
if (typeof object === "number" && !isFinite(object)) { if (typeof object === "number" && !isFinite(object)) {
throw new Error("Infinity is not allowed"); throw new Error("Infinity is not allowed");
} }
if (object === null || typeof object !== "object") { if (object === null || typeof object !== "object") {
return JSON.stringify(object); return JSON.stringify(object);
} }
if (object.toJSON instanceof Function) { if (object.toJSON instanceof Function) {
return serialize(object.toJSON()); return serialize(object.toJSON());
} }
if (Array.isArray(object)) { if (Array.isArray(object)) {
const values = object.reduce((t, cv, ci) => { const values = object.reduce((t, cv, ci) => {
const comma = ci === 0 ? "" : ","; const comma = ci === 0 ? "" : ",";
const value = cv === undefined || typeof cv === "symbol" ? null : cv; const value = cv === undefined || typeof cv === "symbol" ? null : cv;
return `${t}${comma}${serialize(value)}`; return `${t}${comma}${serialize(value)}`;
}, ""); }, "");
return `[${values}]`; return `[${values}]`;
} }
const values = Object.keys(object) const values = Object.keys(object)
.sort() .sort()
.reduce((t, cv) => { .reduce((t, cv) => {
if (object[cv] === undefined || typeof object[cv] === "symbol") { if (object[cv] === undefined || typeof object[cv] === "symbol") {
return t; return t;
} }
const comma = t.length === 0 ? "" : ","; const comma = t.length === 0 ? "" : ",";
return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`; return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`;
}, ""); }, "");
return `{${values}}`; return `{${values}}`;
} }
function encodeSection(data, shouldCanonicalize = false) { function encodeSection(data, shouldCanonicalize = false) {
if (shouldCanonicalize) { if (shouldCanonicalize) {
return encodeBase64url(canonicalizeData(data)); return encodeBase64url(canonicalizeData(data));
} else { } else {
return encodeBase64url(JSON.stringify(data)); return encodeBase64url(JSON.stringify(data));
} }
} }
function encodeBase64url(s) { function encodeBase64url(s) {
return bytesToBase64url(u8a.fromString(s)); return bytesToBase64url(u8a.fromString(s));
} }
function instanceOfEcdsaSignature(object) { function instanceOfEcdsaSignature(object) {
return typeof object === "object" && "r" in object && "s" in object; return typeof object === "object" && "r" in object && "s" in object;
} }
function ES256KSignerAlg(recoverable) { function ES256KSignerAlg(recoverable) {
return async function sign(payload, signer) { return async function sign(payload, signer) {
const signature = await signer(payload); const signature = await signer(payload);
if (instanceOfEcdsaSignature(signature)) { if (instanceOfEcdsaSignature(signature)) {
return toJose(signature, recoverable); return toJose(signature, recoverable);
} else { } else {
if ( if (
recoverable && recoverable &&
typeof fromJose(signature).recoveryParam === "undefined" typeof fromJose(signature).recoveryParam === "undefined"
) { ) {
throw new Error( throw new Error(
`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`, `not_supported: ES256K-R not supported when signer doesn't provide a recovery param`,
); );
} }
return signature; return signature;
} }
}; };
} }
function leftpad(data, size = 64) { function leftpad(data, size = 64) {
if (data.length === size) return data; if (data.length === size) return data;
return "0".repeat(size - data.length) + data; return "0".repeat(size - data.length) + data;
} }
async function SimpleSigner(hexPrivateKey) { async function SimpleSigner(hexPrivateKey) {
const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true); const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true);
return async (data) => { return async (data) => {
const signature = await signer(data); const signature = await signer(data);
return fromJose(signature); return fromJose(signature);
}; };
} }
function hexToBytes(s, minLength) { function hexToBytes(s, minLength) {
let input = s.startsWith("0x") ? s.substring(2) : s; let input = s.startsWith("0x") ? s.substring(2) : s;
if (input.length % 2 !== 0) { if (input.length % 2 !== 0) {
input = `0${input}`; input = `0${input}`;
} }
if (minLength) { if (minLength) {
const paddedLength = Math.max(input.length, minLength * 2); const paddedLength = Math.max(input.length, minLength * 2);
input = input.padStart(paddedLength, "00"); input = input.padStart(paddedLength, "00");
} }
return u8a.fromString(input.toLowerCase(), "base16"); return u8a.fromString(input.toLowerCase(), "base16");
} }
function ES256KSigner(privateKey, recoverable = false) { function ES256KSigner(privateKey, recoverable = false) {
const privateKeyBytes = privateKey; const privateKeyBytes = privateKey;
if (privateKeyBytes.length !== 32) { if (privateKeyBytes.length !== 32) {
throw new Error( throw new Error(
`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`, `bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`,
); );
} }
return async function (data) { return async function (data) {
const signature = nobleCurves.secp256k1.sign(sha256(data), privateKeyBytes); const signature = nobleCurves.secp256k1.sign(sha256(data), privateKeyBytes);
console.error(signature); return toJose(
return toJose( {
{ r: leftpad(signature.r.toString(16)),
r: leftpad(signature.r.toString(16)), s: leftpad(signature.s.toString(16)),
s: leftpad(signature.s.toString(16)), recoveryParam: signature.recovery,
recoveryParam: signature.recovery, },
}, recoverable,
recoverable, );
); };
};
} }
function toJose(signature, recoverable) { function toJose(signature, recoverable) {
const { r, s, recoveryParam } = signature; const { r, s, recoveryParam } = signature;
const jose = new Uint8Array(recoverable ? 65 : 64); const jose = new Uint8Array(recoverable ? 65 : 64);
jose.set(u8a.fromString(r, "base16"), 0); jose.set(u8a.fromString(r, "base16"), 0);
jose.set(u8a.fromString(s, "base16"), 32); jose.set(u8a.fromString(s, "base16"), 32);
if (recoverable) { if (recoverable) {
if (typeof recoveryParam === "undefined") { if (typeof recoveryParam === "undefined") {
throw new Error("Signer did not return a recoveryParam"); throw new Error("Signer did not return a recoveryParam");
}
jose[64] = recoveryParam;
} }
return bytesToBase64url(jose); jose[64] = recoveryParam;
}
return bytesToBase64url(jose);
} }
function bytesToBase64url(b) { function bytesToBase64url(b) {
return u8a.toString(b, "base64url"); return u8a.toString(b, "base64url");
} }
function base64ToBytes(s) { function base64ToBytes(s) {
const inputBase64Url = s const inputBase64Url = s
.replace(/\+/g, "-") .replace(/\+/g, "-")
.replace(/\//g, "_") .replace(/\//g, "_")
.replace(/=/g, ""); .replace(/=/g, "");
return u8a.fromString(inputBase64Url, "base64url"); return u8a.fromString(inputBase64Url, "base64url");
} }
function bytesToHex(b) { function bytesToHex(b) {
return u8a.toString(b, "base16"); return u8a.toString(b, "base16");
} }
function fromJose(signature) { function fromJose(signature) {
const signatureBytes = base64ToBytes(signature); const signatureBytes = base64ToBytes(signature);
if (signatureBytes.length < 64 || signatureBytes.length > 65) { if (signatureBytes.length < 64 || signatureBytes.length > 65) {
throw new TypeError( throw new TypeError(
`Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`, `Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`,
); );
} }
const r = bytesToHex(signatureBytes.slice(0, 32)); const r = bytesToHex(signatureBytes.slice(0, 32));
const s = bytesToHex(signatureBytes.slice(32, 64)); const s = bytesToHex(signatureBytes.slice(32, 64));
const recoveryParam = const recoveryParam =
signatureBytes.length === 65 ? signatureBytes[64] : undefined; signatureBytes.length === 65 ? signatureBytes[64] : undefined;
return { r, s, recoveryParam }; return { r, s, recoveryParam };
} }
function validateBase64(s) { function validateBase64(s) {
if ( if (
!/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test( !/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(
s, s,
) )
) { ) {
throw new TypeError("invalid encoding"); throw new TypeError("invalid encoding");
} }
} }
function decodeBase64(s) { function decodeBase64(s) {
validateBase64(s); validateBase64(s);
var i, var i,
d = atob(s), d = atob(s),
b = new Uint8Array(d.length); b = new Uint8Array(d.length);
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
return b; return b;
} }
async function getSettingById(id) { async function getSettingById(id) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let openRequest = indexedDB.open("TimeSafari"); let openRequest = indexedDB.open("TimeSafari");
openRequest.onupgradeneeded = (event) => { openRequest.onupgradeneeded = (event) => {
// Handle database setup if necessary // Handle database setup if necessary
let db = event.target.result; let db = event.target.result;
if (!db.objectStoreNames.contains("settings")) { if (!db.objectStoreNames.contains("settings")) {
db.createObjectStore("settings", { keyPath: "id" }); db.createObjectStore("settings", { keyPath: "id" });
} }
}; };
openRequest.onsuccess = (event) => { openRequest.onsuccess = (event) => {
let db = event.target.result; let db = event.target.result;
let transaction = db.transaction("settings", "readonly"); let transaction = db.transaction("settings", "readonly");
let objectStore = transaction.objectStore("settings"); let objectStore = transaction.objectStore("settings");
let getRequest = objectStore.get(id); let getRequest = objectStore.get(id);
getRequest.onsuccess = () => resolve(getRequest.result); getRequest.onsuccess = () => resolve(getRequest.result);
getRequest.onerror = () => reject(getRequest.error); getRequest.onerror = () => reject(getRequest.error);
}; };
openRequest.onerror = () => reject(openRequest.error); openRequest.onerror = () => reject(openRequest.error);
}); });
} }
async function setMostRecentNotified(id) { async function setMostRecentNotified(id) {
try {
const db = await openIndexedDB("TimeSafari");
const transaction = db.transaction("settings", "readwrite");
const store = transaction.objectStore("settings");
const data = await getRecord(store, 1);
if (data) {
data["lastNotifiedClaimId"] = id;
await updateRecord(store, data);
} else {
console.error("Record not found");
}
transaction.oncomplete = () => db.close();
} catch (error) {
console.error("Database error: " + error.message);
}
}
function openIndexedDB(dbName) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains("settings")) {
db.createObjectStore("settings");
}
};
});
}
const dbName = "TimeSafari"; function getRecord(store, key) {
const storeName = "settings"; return new Promise((resolve, reject) => {
const key = 1; const request = store.get(key);
const propertyToUpdate = "lastNotifiedClaimId"; request.onsuccess = () => resolve(request.result);
const newValue = id; request.onerror = () => reject(request.error);
let request = indexedDB.open(dbName);
request.onerror = function(event) {
console.error("Database error: " + event.target.errorCode);
};
request.onsuccess = function(event) {
let db = event.target.result;
let transaction = db.transaction(storeName, "readwrite");
let store = transaction.objectStore(storeName);
let getRequest = store.get(key);
getRequest.onsuccess = function(event) {
let data = event.target.result;
// Only update if the object exists
if (data) {
// Update the specific property
data[propertyToUpdate] = newValue;
// Put the updated object back into the database
let putRequest = store.put(data);
putRequest.onsuccess = function() {
console.error("Record updated successfully");
};
putRequest.onerror = function(event) {
console.error("Error updating record: " + event.target.errorCode);
};
} else {
console.error("Record not found");
}
};
getRequest.onerror = function(event) {
console.error("Error fetching record: " + event.target.errorCode);
};
transaction.oncomplete = function() {
db.close();
};
};
request.onupgradeneeded = function(event) {
let db = event.target.result;
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName);
}
};
}); });
} }
async function fetchAllAccounts() { function updateRecord(store, data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let openRequest = indexedDB.open("TimeSafariAccounts"); const request = store.put(data);
request.onsuccess = () => resolve(request.result);
openRequest.onupgradeneeded = function (event) { request.onerror = () => reject(request.error);
let db = event.target.result;
if (!db.objectStoreNames.contains("accounts")) {
db.createObjectStore("accounts", { keyPath: "id" });
}
};
openRequest.onsuccess = function (event) {
let db = event.target.result;
let transaction = db.transaction("accounts", "readonly");
let objectStore = transaction.objectStore("accounts");
let getAllRequest = objectStore.getAll();
getAllRequest.onsuccess = function () {
resolve(getAllRequest.result);
};
getAllRequest.onerror = function () {
reject(getAllRequest.error);
};
};
openRequest.onerror = function () {
reject(openRequest.error);
};
}); });
} }
async function fetchAllAccounts() {
return new Promise((resolve, reject) => {
let openRequest = indexedDB.open("TimeSafariAccounts");
openRequest.onupgradeneeded = function (event) {
let db = event.target.result;
if (!db.objectStoreNames.contains("accounts")) {
db.createObjectStore("accounts", { keyPath: "id" });
}
};
openRequest.onsuccess = function (event) {
let db = event.target.result;
let transaction = db.transaction("accounts", "readonly");
let objectStore = transaction.objectStore("accounts");
let getAllRequest = objectStore.getAll();
getAllRequest.onsuccess = function () {
resolve(getAllRequest.result);
};
getAllRequest.onerror = function () {
reject(getAllRequest.error);
};
};
openRequest.onerror = function () {
reject(openRequest.error);
};
});
}
async function getNotificationCount() { async function getNotificationCount() {
let secret = null; let secret = null;
let accounts = []; let accounts = [];
let result = null; let result = null;
if ("secret" in self) { if ("secret" in self) {
secret = self.secret; secret = self.secret;
const secretUint8Array = self.decodeBase64(secret); const secretUint8Array = self.decodeBase64(secret);
const settings = await getSettingById(1); const settings = await getSettingById(1);
const activeDid = settings["activeDid"]; let lastNotifiedClaimId = null;
accounts = await fetchAllAccounts(); if ("lastNotifiedClaimId" in settings) {
let did = null; lastNotifiedClaimId = settings["lastNotifiedClaimId"];
for (var i = 0; i < accounts.length; i++) { }
let account = accounts[i]; const activeDid = settings["activeDid"];
let did = account["did"]; accounts = await fetchAllAccounts();
if (did == activeDid) { let did = null;
let publicKeyHex = account["publicKeyHex"]; for (var i = 0; i < accounts.length; i++) {
let identity = account["identity"]; let account = accounts[i];
const messageWithNonceAsUint8Array = self.decodeBase64(identity); let did = account["did"];
const nonce = messageWithNonceAsUint8Array.slice(0, 24); if (did == activeDid) {
const message = messageWithNonceAsUint8Array.slice(24, identity.length); let publicKeyHex = account["publicKeyHex"];
const decoder = new TextDecoder("utf-8"); let identity = account["identity"];
const decrypted = self.secretbox.open(message, nonce, secretUint8Array); const messageWithNonceAsUint8Array = self.decodeBase64(identity);
const nonce = messageWithNonceAsUint8Array.slice(0, 24);
const msg = decoder.decode(decrypted); const message = messageWithNonceAsUint8Array.slice(24, identity.length);
const identifier = JSON.parse(JSON.parse(msg)); const decoder = new TextDecoder("utf-8");
const decrypted = self.secretbox.open(message, nonce, secretUint8Array);
console.log(identifier);
const msg = decoder.decode(decrypted);
const headers = { const identifier = JSON.parse(JSON.parse(msg));
"Content-Type": "application/json",
}; const headers = {
"Content-Type": "application/json",
headers["Authorization"] = "Bearer " + (await accessToken(identifier)); };
let response = await fetch( headers["Authorization"] = "Bearer " + (await accessToken(identifier));
"https://test-api.endorser.ch/api/v2/report/claims",
{ let response = await fetch(
method: "GET", "https://test-api.endorser.ch/api/v2/report/claims",
headers: headers, {
}, method: "GET",
); headers: headers,
console.error(did, response.status); },
const claims = await response.json(); );
// formulate a message back for notifications if (response.status == 200) {
let lastNotifiedClaimId = null; let json = await response.json();
if ('lastNotifiedClaimId' in settings) { let claims = json["data"];
lastNotifiedClaimId = settings['lastNotifiedClaimId']; let newClaims = 0;
} for (var i = 0; i < claims.length; i++) {
let newClaims = 0; let claim = claims[i];
// search for id recent notified -- if it exists if not return everything count if (claim["id"] === lastNotifiedClaimId) {
for (var i=0; i< response.json()['data'].length; i++) { break;
let claim = response.json()['data']; }
if (claim['id'] == lastNotifiedClaimId) { newClaims++;
break; }
} if (newClaims === 0) {
newClaims++; result = "You have no new claims today.";
} } else {
// make the notification message here result = `${newClaims} have been shared with you`;
}
// first claim is the most recent (?) const most_recent_notified = claims[0]["id"];
const most_recent_notified = claims[0]['id']; await setMostRecentNotified(most_recent_notified);
await setMostRecentNotified(most_recent_notified); return "TEST";
} else {
console.error(response.status);
break; }
} }
}
return result;
} }
}
return result;
} }
self.getNotificationCount = getNotificationCount; self.getNotificationCount = getNotificationCount;

Loading…
Cancel
Save