From 36493920f32912229b57422342786b882edcc601 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Sun, 26 Nov 2023 07:23:42 -0500 Subject: [PATCH] Before refactoring --- sw_scripts/safari-notifications.js | 743 ++++++++++++++++------------- 1 file changed, 405 insertions(+), 338 deletions(-) diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index 7a468c2..b9fa4e0 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -1,37 +1,37 @@ function bufferFromBase64(base64) { - const binaryString = atob(base64); - const length = binaryString.length; - const bytes = new Uint8Array(length); + const binaryString = atob(base64); + const length = binaryString.length; + const bytes = new Uint8Array(length); - for (let i = 0; i < length; i++) { - bytes[i] = binaryString.charCodeAt(i); - } + for (let i = 0; i < length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } - return bytes; + return bytes; } function fromString(str, encoding = "utf8") { - if (encoding === "utf8") { - return new TextEncoder().encode(str); - } else if (encoding === "base16") { - if (str.length % 2 !== 0) { - throw new Error("Invalid hex string length."); - } - let bytes = new Uint8Array(str.length / 2); - for (let i = 0; i < str.length; i += 2) { - 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 += "="; + if (encoding === "utf8") { + return new TextEncoder().encode(str); + } else if (encoding === "base16") { + if (str.length % 2 !== 0) { + throw new Error("Invalid hex string length."); + } + let bytes = new Uint8Array(str.length / 2); + for (let i = 0; i < str.length; i += 2) { + 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 new Uint8Array(bufferFromBase64(str)); - } else { - throw new Error(`Unsupported encoding "${encoding}"`); - } } /** @@ -43,16 +43,16 @@ function fromString(str, encoding = "utf8") { * @throws {Error} - Throws an error if the encoding is unsupported. */ function toString(byteArray, encoding = "utf8") { - switch (encoding) { + switch (encoding) { case "utf8": - return decodeUTF8(byteArray); + return decodeUTF8(byteArray); case "base16": - return toBase16(byteArray); + return toBase16(byteArray); case "base64url": - return toBase64Url(byteArray); + return toBase64Url(byteArray); default: - throw new Error(`Unsupported encoding "${encoding}"`); - } + throw new Error(`Unsupported encoding "${encoding}"`); + } } /** @@ -62,7 +62,7 @@ function toString(byteArray, encoding = "utf8") { * @returns {string} */ function decodeUTF8(byteArray) { - return new TextDecoder().decode(byteArray); + return new TextDecoder().decode(byteArray); } /** @@ -72,9 +72,9 @@ function decodeUTF8(byteArray) { * @returns {string} */ function toBase16(byteArray) { - return Array.from(byteArray) - .map((byte) => byte.toString(16).padStart(2, "0")) - .join(""); + return Array.from(byteArray) + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); } /** @@ -84,391 +84,458 @@ function toBase16(byteArray) { * @returns {string} */ function toBase64Url(byteArray) { - let uint8Array = new Uint8Array(byteArray); - let binaryString = ""; - for (let i = 0; i < uint8Array.length; i++) { - binaryString += String.fromCharCode(uint8Array[i]); - } + let uint8Array = new Uint8Array(byteArray); + let binaryString = ""; + for (let i = 0; i < uint8Array.length; i++) { + binaryString += String.fromCharCode(uint8Array[i]); + } - // Encode to base64 - let base64 = btoa(binaryString); + // Encode to base64 + let base64 = btoa(binaryString); - return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); + return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); } const u8a = { toString, fromString }; function sha256(payload) { - const data = typeof payload === "string" ? u8a.fromString(payload) : payload; - return nobleHashes.sha256(data); + const data = typeof payload === "string" ? u8a.fromString(payload) : payload; + return nobleHashes.sha256(data); } async function accessToken(identifier) { - const did = identifier["did"]; - const privateKeyHex = identifier["keys"][0]["privateKeyHex"]; - - const signer = await SimpleSigner(privateKeyHex); - - const nowEpoch = Math.floor(Date.now() / 1000); - const endEpoch = nowEpoch + 60; // add one minute - - const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; - const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R - const jwt = await createJWT(tokenPayload, { - alg, - issuer: did, - signer, - }); - console.error(jwt); - return jwt; + const did = identifier["did"]; + const privateKeyHex = identifier["keys"][0]["privateKeyHex"]; + + const signer = await SimpleSigner(privateKeyHex); + + const nowEpoch = Math.floor(Date.now() / 1000); + const endEpoch = nowEpoch + 60; // add one minute + + const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did }; + const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R + const jwt = await createJWT(tokenPayload, { + alg, + issuer: did, + signer, + }); + console.error(jwt); + return jwt; } async function createJWT(payload, options, header = {}) { - const { issuer, signer, alg, expiresIn, canonicalize } = options; - - if (!signer) - throw new Error( - "missing_signer: No Signer functionality has been configured", - ); - if (!issuer) - throw new Error("missing_issuer: No issuing DID has been configured"); - if (!header.typ) header.typ = "JWT"; - if (!header.alg) header.alg = alg; - - const timestamps = { - iat: Math.floor(Date.now() / 1000), - exp: undefined, - }; - - if (expiresIn) { - if (typeof expiresIn === "number") { - timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn); - } else { - throw new Error("invalid_argument: JWT expiresIn is not a number"); + const { issuer, signer, alg, expiresIn, canonicalize } = options; + + if (!signer) + throw new Error( + "missing_signer: No Signer functionality has been configured", + ); + if (!issuer) + throw new Error("missing_issuer: No issuing DID has been configured"); + if (!header.typ) header.typ = "JWT"; + if (!header.alg) header.alg = alg; + + const timestamps = { + iat: Math.floor(Date.now() / 1000), + exp: undefined, + }; + + if (expiresIn) { + if (typeof expiresIn === "number") { + timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn); + } else { + throw new Error("invalid_argument: JWT expiresIn is not a number"); + } } - } - const fullPayload = { ...timestamps, ...payload, iss: issuer }; - return createJWS(fullPayload, signer, header, { canonicalize }); + const fullPayload = { ...timestamps, ...payload, iss: issuer }; + return createJWS(fullPayload, signer, header, { canonicalize }); } const defaultAlg = "ES256K"; async function createJWS(payload, signer, header = {}, options = {}) { - if (!header.alg) header.alg = defaultAlg; - const encodedPayload = - typeof payload === "string" - ? payload - : encodeSection(payload, options.canonicalize); - const signingInput = [ - encodeSection(header, options.canonicalize), - encodedPayload, - ].join("."); - - const jwtSigner = ES256KSignerAlg(false); - const signature = await jwtSigner(signingInput, signer); - - // JWS Compact Serialization - // https://www.rfc-editor.org/rfc/rfc7515#section-7.1 - return [signingInput, signature].join("."); + if (!header.alg) header.alg = defaultAlg; + const encodedPayload = + typeof payload === "string" + ? payload + : encodeSection(payload, options.canonicalize); + const signingInput = [ + encodeSection(header, options.canonicalize), + encodedPayload, + ].join("."); + + const jwtSigner = ES256KSignerAlg(false); + const signature = await jwtSigner(signingInput, signer); + + // JWS Compact Serialization + // https://www.rfc-editor.org/rfc/rfc7515#section-7.1 + return [signingInput, signature].join("."); } function canonicalizeData(object) { - if (typeof object === "number" && isNaN(object)) { - throw new Error("NaN is not allowed"); - } - - if (typeof object === "number" && !isFinite(object)) { - throw new Error("Infinity is not allowed"); - } - - if (object === null || typeof object !== "object") { - return JSON.stringify(object); - } - - if (object.toJSON instanceof Function) { - return serialize(object.toJSON()); - } - - if (Array.isArray(object)) { - const values = object.reduce((t, cv, ci) => { - const comma = ci === 0 ? "" : ","; - const value = cv === undefined || typeof cv === "symbol" ? null : cv; - return `${t}${comma}${serialize(value)}`; - }, ""); - return `[${values}]`; - } - - const values = Object.keys(object) - .sort() - .reduce((t, cv) => { - if (object[cv] === undefined || typeof object[cv] === "symbol") { - return t; - } - const comma = t.length === 0 ? "" : ","; - return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`; - }, ""); - return `{${values}}`; + if (typeof object === "number" && isNaN(object)) { + throw new Error("NaN is not allowed"); + } + + if (typeof object === "number" && !isFinite(object)) { + throw new Error("Infinity is not allowed"); + } + + if (object === null || typeof object !== "object") { + return JSON.stringify(object); + } + + if (object.toJSON instanceof Function) { + return serialize(object.toJSON()); + } + + if (Array.isArray(object)) { + const values = object.reduce((t, cv, ci) => { + const comma = ci === 0 ? "" : ","; + const value = cv === undefined || typeof cv === "symbol" ? null : cv; + return `${t}${comma}${serialize(value)}`; + }, ""); + return `[${values}]`; + } + + const values = Object.keys(object) + .sort() + .reduce((t, cv) => { + if (object[cv] === undefined || typeof object[cv] === "symbol") { + return t; + } + const comma = t.length === 0 ? "" : ","; + return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`; + }, ""); + return `{${values}}`; } function encodeSection(data, shouldCanonicalize = false) { - if (shouldCanonicalize) { - return encodeBase64url(canonicalizeData(data)); - } else { - return encodeBase64url(JSON.stringify(data)); - } + if (shouldCanonicalize) { + return encodeBase64url(canonicalizeData(data)); + } else { + return encodeBase64url(JSON.stringify(data)); + } } function encodeBase64url(s) { - return bytesToBase64url(u8a.fromString(s)); + return bytesToBase64url(u8a.fromString(s)); } 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) { - return async function sign(payload, signer) { - const signature = await signer(payload); - if (instanceOfEcdsaSignature(signature)) { - return toJose(signature, recoverable); - } else { - if ( - recoverable && - typeof fromJose(signature).recoveryParam === "undefined" - ) { - throw new Error( - `not_supported: ES256K-R not supported when signer doesn't provide a recovery param`, - ); - } - return signature; - } - }; + return async function sign(payload, signer) { + const signature = await signer(payload); + if (instanceOfEcdsaSignature(signature)) { + return toJose(signature, recoverable); + } else { + if ( + recoverable && + typeof fromJose(signature).recoveryParam === "undefined" + ) { + throw new Error( + `not_supported: ES256K-R not supported when signer doesn't provide a recovery param`, + ); + } + return signature; + } + }; } function leftpad(data, size = 64) { - if (data.length === size) return data; - return "0".repeat(size - data.length) + data; + if (data.length === size) return data; + return "0".repeat(size - data.length) + data; } async function SimpleSigner(hexPrivateKey) { - const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true); - return async (data) => { - const signature = await signer(data); - return fromJose(signature); - }; + const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true); + return async (data) => { + const signature = await signer(data); + return fromJose(signature); + }; } 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) { - input = `0${input}`; - } + if (input.length % 2 !== 0) { + input = `0${input}`; + } - if (minLength) { - const paddedLength = Math.max(input.length, minLength * 2); - input = input.padStart(paddedLength, "00"); - } + if (minLength) { + const paddedLength = Math.max(input.length, minLength * 2); + input = input.padStart(paddedLength, "00"); + } - return u8a.fromString(input.toLowerCase(), "base16"); + return u8a.fromString(input.toLowerCase(), "base16"); } function ES256KSigner(privateKey, recoverable = false) { - const privateKeyBytes = privateKey; - if (privateKeyBytes.length !== 32) { - throw new Error( - `bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`, - ); - } - - return async function (data) { - const signature = nobleCurves.secp256k1.sign(sha256(data), privateKeyBytes); - console.error(signature); - return toJose( - { - r: leftpad(signature.r.toString(16)), - s: leftpad(signature.s.toString(16)), - recoveryParam: signature.recovery, - }, - recoverable, - ); - }; + const privateKeyBytes = privateKey; + if (privateKeyBytes.length !== 32) { + throw new Error( + `bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`, + ); + } + + return async function (data) { + const signature = nobleCurves.secp256k1.sign(sha256(data), privateKeyBytes); + console.error(signature); + return toJose( + { + r: leftpad(signature.r.toString(16)), + s: leftpad(signature.s.toString(16)), + recoveryParam: signature.recovery, + }, + recoverable, + ); + }; } function toJose(signature, recoverable) { - const { r, s, recoveryParam } = signature; - const jose = new Uint8Array(recoverable ? 65 : 64); - jose.set(u8a.fromString(r, "base16"), 0); - jose.set(u8a.fromString(s, "base16"), 32); - - if (recoverable) { - if (typeof recoveryParam === "undefined") { - throw new Error("Signer did not return a recoveryParam"); + const { r, s, recoveryParam } = signature; + const jose = new Uint8Array(recoverable ? 65 : 64); + jose.set(u8a.fromString(r, "base16"), 0); + jose.set(u8a.fromString(s, "base16"), 32); + + if (recoverable) { + if (typeof recoveryParam === "undefined") { + throw new Error("Signer did not return a recoveryParam"); + } + jose[64] = recoveryParam; } - jose[64] = recoveryParam; - } - return bytesToBase64url(jose); + return bytesToBase64url(jose); } function bytesToBase64url(b) { - return u8a.toString(b, "base64url"); + return u8a.toString(b, "base64url"); } function base64ToBytes(s) { - const inputBase64Url = s - .replace(/\+/g, "-") - .replace(/\//g, "_") - .replace(/=/g, ""); - return u8a.fromString(inputBase64Url, "base64url"); + const inputBase64Url = s + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=/g, ""); + return u8a.fromString(inputBase64Url, "base64url"); } function bytesToHex(b) { - return u8a.toString(b, "base16"); + return u8a.toString(b, "base16"); } function fromJose(signature) { - const signatureBytes = base64ToBytes(signature); - if (signatureBytes.length < 64 || signatureBytes.length > 65) { - throw new TypeError( - `Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`, - ); - } - const r = bytesToHex(signatureBytes.slice(0, 32)); - const s = bytesToHex(signatureBytes.slice(32, 64)); - const recoveryParam = - signatureBytes.length === 65 ? signatureBytes[64] : undefined; - - return { r, s, recoveryParam }; + const signatureBytes = base64ToBytes(signature); + if (signatureBytes.length < 64 || signatureBytes.length > 65) { + throw new TypeError( + `Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`, + ); + } + const r = bytesToHex(signatureBytes.slice(0, 32)); + const s = bytesToHex(signatureBytes.slice(32, 64)); + const recoveryParam = + signatureBytes.length === 65 ? signatureBytes[64] : undefined; + + return { r, s, recoveryParam }; } function validateBase64(s) { - if ( - !/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test( - s, - ) - ) { - throw new TypeError("invalid encoding"); - } + if ( + !/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test( + s, + ) + ) { + throw new TypeError("invalid encoding"); + } } function decodeBase64(s) { - validateBase64(s); - var i, - d = atob(s), - b = new Uint8Array(d.length); - for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); - return b; + validateBase64(s); + var i, + d = atob(s), + b = new Uint8Array(d.length); + for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); + return b; } async function getSettingById(id) { - return new Promise((resolve, reject) => { - let openRequest = indexedDB.open("TimeSafari"); - - openRequest.onupgradeneeded = (event) => { - // Handle database setup if necessary - let db = event.target.result; - if (!db.objectStoreNames.contains("settings")) { - db.createObjectStore("settings", { keyPath: "id" }); - } - }; - - openRequest.onsuccess = (event) => { - let db = event.target.result; - let transaction = db.transaction("settings", "readonly"); - let objectStore = transaction.objectStore("settings"); - let getRequest = objectStore.get(id); - - getRequest.onsuccess = () => resolve(getRequest.result); - getRequest.onerror = () => reject(getRequest.error); - }; - - openRequest.onerror = () => reject(openRequest.error); - }); + return new Promise((resolve, reject) => { + let openRequest = indexedDB.open("TimeSafari"); + + openRequest.onupgradeneeded = (event) => { + // Handle database setup if necessary + let db = event.target.result; + if (!db.objectStoreNames.contains("settings")) { + db.createObjectStore("settings", { keyPath: "id" }); + } + }; + + openRequest.onsuccess = (event) => { + let db = event.target.result; + let transaction = db.transaction("settings", "readonly"); + let objectStore = transaction.objectStore("settings"); + let getRequest = objectStore.get(id); + + getRequest.onsuccess = () => resolve(getRequest.result); + getRequest.onerror = () => reject(getRequest.error); + }; + + openRequest.onerror = () => 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" }); - } - }; +async function setMostRecentNotified(id) { + return new Promise((resolve, reject) => { + + const dbName = "TimeSafari"; + const storeName = "settings"; + const key = 1; // The ID of the record you want to update + const propertyToUpdate = "lastNotifiedClaimId"; // The property you want to update + const newValue = id; // The new value for the property + + 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); + } + }; + + + }); +} - 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() { - let secret = null; - let accounts = []; - let result = null; - if ("secret" in self) { - secret = self.secret; - const secretUint8Array = self.decodeBase64(secret); - const settings = await getSettingById(1); - const activeDid = settings["activeDid"]; - accounts = await fetchAllAccounts(); - let did = null; - for (var i = 0; i < accounts.length; i++) { - let account = accounts[i]; - let did = account["did"]; - if (did == activeDid) { - let publicKeyHex = account["publicKeyHex"]; - let identity = account["identity"]; - const messageWithNonceAsUint8Array = self.decodeBase64(identity); - const nonce = messageWithNonceAsUint8Array.slice(0, 24); - const message = messageWithNonceAsUint8Array.slice(24, identity.length); - const decoder = new TextDecoder("utf-8"); - const decrypted = self.secretbox.open(message, nonce, secretUint8Array); - - const msg = decoder.decode(decrypted); - const identifier = JSON.parse(JSON.parse(msg)); - - console.log(identifier); - - const headers = { - "Content-Type": "application/json", - }; - - headers["Authorization"] = "Bearer " + (await accessToken(identifier)); - - let response = await fetch( - "https://test-api.endorser.ch/api/v2/report/claims", - { - method: "GET", - headers: headers, - }, - ); - console.error(did, response.status); - console.error(await response.json()); - - result = decrypted; - - break; - } + let secret = null; + let accounts = []; + let result = null; + if ("secret" in self) { + secret = self.secret; + const secretUint8Array = self.decodeBase64(secret); + const settings = await getSettingById(1); + const activeDid = settings["activeDid"]; + accounts = await fetchAllAccounts(); + let did = null; + for (var i = 0; i < accounts.length; i++) { + let account = accounts[i]; + let did = account["did"]; + if (did == activeDid) { + let publicKeyHex = account["publicKeyHex"]; + let identity = account["identity"]; + const messageWithNonceAsUint8Array = self.decodeBase64(identity); + const nonce = messageWithNonceAsUint8Array.slice(0, 24); + const message = messageWithNonceAsUint8Array.slice(24, identity.length); + const decoder = new TextDecoder("utf-8"); + const decrypted = self.secretbox.open(message, nonce, secretUint8Array); + + const msg = decoder.decode(decrypted); + const identifier = JSON.parse(JSON.parse(msg)); + + console.log(identifier); + + const headers = { + "Content-Type": "application/json", + }; + + headers["Authorization"] = "Bearer " + (await accessToken(identifier)); + + let response = await fetch( + "https://test-api.endorser.ch/api/v2/report/claims", + { + method: "GET", + headers: headers, + }, + ); + console.error(did, response.status); + const claims = await response.json(); + // first claim is the most recent (?) + const most_recent_notified = claims[0]['id'] + + + break; + } + } + return result; } - return result; - } } self.getNotificationCount = getNotificationCount;