Browse Source

Beefing up registration and activation of the service worker.

home-view-notification-improvements
Matthew Raymer 1 year ago
parent
commit
d6dc7fbb10
  1. 55
      package-lock.json
  2. 4
      package.json
  3. 3
      src/App.vue
  4. 12
      src/libs/endorserServer.ts
  5. 2
      src/registerServiceWorker.ts
  6. 4
      src/views/ContactsView.vue
  7. 73
      sw_scripts/additional-scripts.js
  8. 1766
      sw_scripts/nacl.js
  9. 119
      sw_scripts/safari-notifications.js
  10. 465
      sw_scripts/secp256k1.js
  11. 742
      sw_scripts/sw-bn.js
  12. 8
      vue.config.js

55
package-lock.json

@ -75,13 +75,13 @@
"@vue/cli-service": "~5.0.8", "@vue/cli-service": "~5.0.8",
"@vue/eslint-config-typescript": "^11.0.3", "@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.15",
"eslint": "^8.48.0", "eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0", "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.17.0", "eslint-plugin-vue": "^9.17.0",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"postcss": "^8.4.29", "postcss": "^8.4.29",
"prettier": "^3.0.3", "prettier": "^3.1.0",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"typescript": "~5.2.2" "typescript": "~5.2.2"
} }
@ -2824,9 +2824,9 @@
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
"integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"ajv": "^6.12.4", "ajv": "^6.12.4",
@ -2874,9 +2874,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "8.51.0", "version": "8.53.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
"integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -5501,12 +5501,12 @@
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.11", "version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
"integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@humanwhocodes/object-schema": "^1.2.1", "@humanwhocodes/object-schema": "^2.0.1",
"debug": "^4.1.1", "debug": "^4.1.1",
"minimatch": "^3.0.5" "minimatch": "^3.0.5"
}, },
@ -5528,9 +5528,9 @@
} }
}, },
"node_modules/@humanwhocodes/object-schema": { "node_modules/@humanwhocodes/object-schema": {
"version": "1.2.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true "dev": true
}, },
"node_modules/@jest/create-cache-key-function": { "node_modules/@jest/create-cache-key-function": {
@ -9225,6 +9225,12 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
"node_modules/@unimodules/core": { "node_modules/@unimodules/core": {
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/@unimodules/core/-/core-7.1.2.tgz", "resolved": "https://registry.npmjs.org/@unimodules/core/-/core-7.1.2.tgz",
@ -14239,18 +14245,19 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "8.51.0", "version": "8.53.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
"integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2", "@eslint/eslintrc": "^2.1.3",
"@eslint/js": "8.51.0", "@eslint/js": "8.53.0",
"@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4", "ajv": "^6.12.4",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.2",
@ -23164,9 +23171,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.0.3", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
"integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"

4
package.json

@ -75,13 +75,13 @@
"@vue/cli-service": "~5.0.8", "@vue/cli-service": "~5.0.8",
"@vue/eslint-config-typescript": "^11.0.3", "@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.15",
"eslint": "^8.48.0", "eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0", "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.17.0", "eslint-plugin-vue": "^9.17.0",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"postcss": "^8.4.29", "postcss": "^8.4.29",
"prettier": "^3.0.3", "prettier": "^3.1.0",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"typescript": "~5.2.2" "typescript": "~5.2.2"
} }

3
src/App.vue

@ -295,6 +295,9 @@ export default class App extends Vue {
.then((response: VapidResponse) => { .then((response: VapidResponse) => {
this.b64 = response.data.vapidKey; this.b64 = response.data.vapidKey;
console.log(this.b64); console.log(this.b64);
navigator.serviceWorker.addEventListener("controllerchange", () => {
console.log("New service worker is now controlling the page");
});
}) })
.catch((error: AxiosError) => { .catch((error: AxiosError) => {
console.error("API error", error); console.error("API error", error);

12
src/libs/endorserServer.ts

@ -134,8 +134,8 @@ export function didInfo(
return contact return contact
? contact.name || "Contact With No Name" ? contact.name || "Contact With No Name"
: isHiddenDid(did) : isHiddenDid(did)
? "Someone Not In Network" ? "Someone Not In Network"
: "Someone Not In Contacts"; : "Someone Not In Contacts";
} }
export interface ResultWithType { export interface ResultWithType {
@ -231,10 +231,10 @@ export async function createAndSubmitGive(
error === null error === null
? "Null error" ? "Null error"
: error instanceof Error : error instanceof Error
? error.message ? error.message
: typeof error === "object" && error !== null && "message" in error : typeof error === "object" && error !== null && "message" in error
? (error as { message: string }).message ? (error as { message: string }).message
: "Unknown error"; : "Unknown error";
return { return {
type: "error", type: "error",

2
src/registerServiceWorker.ts

@ -3,7 +3,7 @@
import { register } from "register-service-worker"; import { register } from "register-service-worker";
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === "production") {
register(`${process.env.BASE_URL}service-worker.js`, { register("/additional-scripts.js", {
ready() { ready() {
console.log( console.log(
"App is being served from cache by a service worker.\n" + "App is being served from cache by a service worker.\n" +

4
src/views/ContactsView.vue

@ -67,8 +67,8 @@
showGiveTotals showGiveTotals
? "Total" ? "Total"
: showGiveConfirmed : showGiveConfirmed
? "Confirmed" ? "Confirmed"
: "Unconfirmed" : "Unconfirmed"
}} }}
</button> </button>
<br /> <br />

73
sw_scripts/additional-scripts.js

@ -1,30 +1,55 @@
/* eslint-env serviceworker */
/* global workbox */
importScripts(
"https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js",
);
self.addEventListener("install", (event) => {
event.waitUntil(
(async () => {
importScripts("safari-notifications.js");
})(),
);
});
self.addEventListener("push", function (event) { self.addEventListener("push", function (event) {
event.waitUntil((async () => { event.waitUntil(
try { (async () => {
let payload; try {
if (event.data) { let payload;
payload = JSON.parse(event.data.text()); if (event.data) {
} payload = JSON.parse(event.data.text());
let value = await self.getNotificationCount(); }
const title = payload ? payload.title : "Custom Title"; const value = await self.getNotificationCount();
const options = { const title = payload ? payload.title : "Custom Title";
body: payload ? value : "SAMPLE", const options = {
icon: payload ? payload.icon : "icon.png", body: payload ? value : "SAMPLE",
badge: payload ? payload.badge : "badge.png", icon: payload ? payload.icon : "icon.png",
}; badge: payload ? payload.badge : "badge.png",
await self.registration.showNotification(title, options); };
} catch (error) { await self.registration.showNotification(title, options);
console.error('Error in processing the push event:', error); } catch (error) {
} console.error("Error in processing the push event:", error);
})()); }
})(),
);
});
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SEND_LOCAL_DATA") {
self.secret = event.data.data;
console.log("Data stored in service worker:", self.secret);
event.ports[0].postMessage({ success: true });
}
}); });
self.addEventListener("activate", (event) => {
event.waitUntil(clients.claim());
console.log("Service worker activated", event);
});
self.addEventListener('message', event => { self.addEventListener("fetch", (event) => {
if (event.data && event.data.type === 'SEND_LOCAL_DATA') { console.log(event.request);
self.secret = event.data.data;
console.log('Data stored in service worker:', self.secret);
event.ports[0].postMessage({ success: true });
}
}); });
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);

1766
sw_scripts/nacl.js

File diff suppressed because it is too large

119
sw_scripts/safari-notifications.js

@ -1,43 +1,48 @@
async function generateSHA256Hash(data) { async function generateSHA256Hash(data) {
const buffer = new TextEncoder().encode(data); const buffer = new TextEncoder().encode(data);
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer); const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join(''); const hashHex = hashArray
return hashHex; .map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
return hashHex;
} }
function validateBase64(s) { 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))) { if (
throw new TypeError('invalid encoding'); !/^(?:[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) { function decodeBase64(s) {
validateBase64(s); validateBase64(s);
var i, d = atob(s), b = new Uint8Array(d.length); var i,
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); d = atob(s),
return b; b = new Uint8Array(d.length);
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
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);
@ -48,66 +53,64 @@ async function getSettingById(id) {
}); });
} }
async function fetchAllAccounts() { async function fetchAllAccounts() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let openRequest = indexedDB.open('TimeSafariAccounts'); let openRequest = indexedDB.open("TimeSafariAccounts");
openRequest.onupgradeneeded = function(event) { openRequest.onupgradeneeded = function (event) {
let db = event.target.result; let db = event.target.result;
if (!db.objectStoreNames.contains('accounts')) { if (!db.objectStoreNames.contains("accounts")) {
db.createObjectStore('accounts', { keyPath: 'id' }); db.createObjectStore("accounts", { keyPath: "id" });
} }
}; };
openRequest.onsuccess = function(event) { openRequest.onsuccess = function (event) {
let db = event.target.result; let db = event.target.result;
let transaction = db.transaction('accounts', 'readonly'); let transaction = db.transaction("accounts", "readonly");
let objectStore = transaction.objectStore('accounts'); let objectStore = transaction.objectStore("accounts");
let getAllRequest = objectStore.getAll(); let getAllRequest = objectStore.getAll();
getAllRequest.onsuccess = function() { getAllRequest.onsuccess = function () {
resolve(getAllRequest.result); resolve(getAllRequest.result);
}; };
getAllRequest.onerror = function() { getAllRequest.onerror = function () {
reject(getAllRequest.error); reject(getAllRequest.error);
}; };
}; };
openRequest.onerror = function() { openRequest.onerror = function () {
reject(openRequest.error); reject(openRequest.error);
}; };
}); });
} }
async function getNotificationCount() { async function getNotificationCount() {
let secret = null; let secret = null;
if ('secret' in self) { let accounts = [];
secret = self.secret; if ("secret" in self) {
const secretUint8Array = self.decodeBase64(secret); secret = self.secret;
const settings = await getSettingById(1); const secretUint8Array = self.decodeBase64(secret);
const activeDid = settings['activeDid']; const settings = await getSettingById(1);
/** const activeDid = settings["activeDid"];
const accounts = await fetchAllAccounts(); accounts = await fetchAllAccounts();
let did = null; let did = null;
let result = null; let result = null;
for (var i = 0; i < accounts.length; i++) { /**
let account = accounts[i]; for (var i = 0; i < accounts.length; i++) {
let did = account['did']; let account = accounts[i];
if (did == activeDid) { let did = account['did'];
let publicKeyHex = account['publicKeyHex']; if (did == activeDid) {
let identity = account['identity']; let publicKeyHex = account['publicKeyHex'];
let identity = account['identity'];
const messageWithNonceAsUint8Array = decodeBase64(identity);
const nonce = messageWithNonceAsUint8Array.slice(0, 24); const messageWithNonceAsUint8Array = decodeBase64(identity);
const message = messageWithNonceAsUint8Array.slice(24, identity.length); const nonce = messageWithNonceAsUint8Array.slice(0, 24);
} const message = messageWithNonceAsUint8Array.slice(24, identity.length);
**/ }
} **/
} }
return secret; return accounts.length;
} }
self.getNotificationCount = getNotificationCount; self.getNotificationCount = getNotificationCount;
self.decodeBase64 = decodeBase64 self.decodeBase64 = decodeBase64;

465
sw_scripts/secp256k1.js

@ -1,256 +1,283 @@
(function () { (function () {
randomBytes = (length) => self.crypto.getRandomValues(new Uint8Array(length));
self.Secp256k1 = exports = {};
randomBytes = length => self.crypto.getRandomValues(new Uint8Array(length)) function uint256(x, base) {
self.Secp256k1 = exports = {} return new BN(x, base);
}
function uint256(x, base) { function rnd(P) {
return new BN(x, base) return uint256(randomBytes(32)).umod(P); //TODO red
} }
function rnd(P) { const A = uint256(0);
return uint256(randomBytes(32)).umod(P)//TODO red const B = uint256(7);
} const GX = uint256(
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
16,
);
const GY = uint256(
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
16,
);
const P = uint256(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
16,
);
const N = uint256(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
16,
);
//const RED = BN.red(P)
const _0 = uint256(0);
const _1 = uint256(1);
const A = uint256(0) // function for elliptic curve multiplication in jacobian coordinates using Double-and-add method
const B = uint256(7) function ecmul(_p, _d) {
const GX = uint256("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) let R = [_0, _0, _0];
const GY = uint256("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
const P = uint256("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
const N = uint256("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
//const RED = BN.red(P)
const _0 = uint256(0)
const _1 = uint256(1)
// function for elliptic curve multiplication in jacobian coordinates using Double-and-add method //return (0,0) if d=0 or (x1,y1)=(0,0)
function ecmul(_p, _d) { if (_d == 0 || (_p[0] == 0 && _p[1] == 0)) {
let R = [_0,_0,_0] return R;
}
let T = [
_p[0], //x-coordinate temp
_p[1], //y-coordinate temp
_p[2], //z-coordinate temp
];
//return (0,0) if d=0 or (x1,y1)=(0,0) const d = _d.clone();
if (_d == 0 || ((_p[0] == 0) && (_p[1] == 0)) ) { while (d != 0) {
return R if (d.testn(0)) {
} //if last bit is 1 add T to result
let T = [ R = ecadd(T, R);
_p[0], //x-coordinate temp }
_p[1], //y-coordinate temp T = ecdouble(T); //double temporary coordinates
_p[2], //z-coordinate temp d.iushrn(1); //"cut off" last bit
] }
const d = _d.clone() return R;
while (d != 0) { }
if (d.testn(0)) { //if last bit is 1 add T to result
R = ecadd(T,R)
}
T = ecdouble(T); //double temporary coordinates
d.iushrn(1); //"cut off" last bit
}
return R function mulmod(a, b, P) {
} return a.mul(b).umod(P); //TODO red
}
function mulmod(a, b, P) { function addmod(a, b, P) {
return a.mul(b).umod(P)//TODO red return a.add(b).umod(P); //TODO red
} }
function addmod(a, b, P) { function invmod(a, P) {
return a.add(b).umod(P)//TODO red return a.invm(P); //TODO redq
} }
function invmod(a, P) { function mulG(k) {
return a.invm(P)//TODO redq const GinJ = AtoJ(GX, GY);
} const PUBinJ = ecmul(GinJ, k);
return JtoA(PUBinJ);
}
function mulG(k) { function assert(cond, msg) {
const GinJ = AtoJ(GX, GY) if (!cond) {
const PUBinJ = ecmul(GinJ, k) throw Error("assertion failed: " + msg);
return JtoA(PUBinJ)
} }
}
function assert(cond, msg) { function ecsign(d, z) {
if (!cond) { assert(d != 0, "d must not be 0");
throw Error("assertion failed: " + msg) assert(z != 0, "z must not be 0");
} while (true) {
const k = rnd(P);
const R = mulG(k);
if (R[0] == 0) continue;
const s = mulmod(invmod(k, N), addmod(z, mulmod(R[0], d, N), N), N);
if (s == 0) continue;
//FIXME: why do I need this
if (s.testn(255)) continue;
return { r: toHex(R[0]), s: toHex(s), v: R[1].testn(0) ? 1 : 0 };
} }
}
function ecsign(d, z) { function JtoA(p) {
assert(d != 0, "d must not be 0") const zInv = invmod(p[2], P);
assert(z != 0, "z must not be 0") const zInv2 = mulmod(zInv, zInv, P);
while (true) { return [mulmod(p[0], zInv2, P), mulmod(p[1], mulmod(zInv, zInv2, P), P)];
const k = rnd(P) }
const R = mulG(k)
if (R[0] == 0) continue
const s = mulmod(invmod(k, N), addmod(z, mulmod(R[0], d, N), N), N)
if (s == 0) continue
//FIXME: why do I need this
if (s.testn(255)) continue
return {r: toHex(R[0]), s: toHex(s), v: R[1].testn(0) ? 1 : 0}
}
}
function JtoA(p) { //point doubling for elliptic curve in jacobian coordinates
const zInv = invmod(p[2], P) //formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
const zInv2 = mulmod(zInv, zInv, P) function ecdouble(_p) {
return [mulmod(p[0], zInv2, P), mulmod(p[1], mulmod(zInv, zInv2, P), P)] if (_p[1] == 0) {
//return point at infinity
return [_1, _1, _0];
} }
//point doubling for elliptic curve in jacobian coordinates const z2 = mulmod(_p[2], _p[2], P);
//formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates const m = addmod(
function ecdouble(_p) { mulmod(A, mulmod(z2, z2, P), P),
if (_p[1] == 0) { mulmod(uint256(3), mulmod(_p[0], _p[0], P), P),
//return point at infinity P,
return [_1, _1, _0] );
} const y2 = mulmod(_p[1], _p[1], P);
const s = mulmod(uint256(4), mulmod(_p[0], y2, P), P);
const z2 = mulmod(_p[2], _p[2], P) const x = addmod(mulmod(m, m, P), negmod(mulmod(s, uint256(2), P), P), P);
const m = addmod(mulmod(A, mulmod(z2, z2, P), P), mulmod(uint256(3), mulmod(_p[0], _p[0], P), P), P) return [
const y2 = mulmod(_p[1], _p[1], P) x,
const s = mulmod(uint256(4), mulmod(_p[0], y2, P), P) addmod(
mulmod(m, addmod(s, negmod(x, P), P), P),
negmod(mulmod(uint256(8), mulmod(y2, y2, P), P), P),
P,
),
mulmod(uint256(2), mulmod(_p[1], _p[2], P), P),
];
}
const x = addmod(mulmod(m, m, P), negmod(mulmod(s, uint256(2), P), P), P) function negmod(a, P) {
return [ return P.sub(a);
x, }
addmod(mulmod(m, addmod(s, negmod(x, P), P), P), negmod(mulmod(uint256(8), mulmod(y2, y2, P), P), P), P),
mulmod(uint256(2), mulmod(_p[1], _p[2], P), P)
]
}
function negmod(a, P) { // point addition for elliptic curve in jacobian coordinates
return P.sub(a) // formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
function ecadd(_p, _q) {
if (_q[0] == 0 && _q[1] == 0 && _q[2] == 0) {
return _p;
} }
// point addition for elliptic curve in jacobian coordinates let z2 = mulmod(_q[2], _q[2], P);
// formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates const u1 = mulmod(_p[0], z2, P);
function ecadd(_p, _q) { const s1 = mulmod(_p[1], mulmod(z2, _q[2], P), P);
if (_q[0] == 0 && _q[1] == 0 && _q[2] == 0) { z2 = mulmod(_p[2], _p[2], P);
return _p let u2 = mulmod(_q[0], z2, P);
} let s2 = mulmod(_q[1], mulmod(z2, _p[2], P), P);
let z2 = mulmod(_q[2], _q[2], P)
const u1 = mulmod(_p[0], z2, P)
const s1 = mulmod(_p[1], mulmod(z2, _q[2], P), P)
z2 = mulmod(_p[2], _p[2], P)
let u2 = mulmod(_q[0], z2, P)
let s2 = mulmod(_q[1], mulmod(z2, _p[2], P), P)
if (u1.eq(u2)) {
if (!s1.eq(s2)) {
//return point at infinity
return [_1, _1, _0]
}
else {
return ecdouble(_p)
}
}
u2 = addmod(u2, negmod(u1, P), P) if (u1.eq(u2)) {
z2 = mulmod(u2, u2, P) if (!s1.eq(s2)) {
const t2 = mulmod(u1, z2, P) //return point at infinity
z2 = mulmod(u2, z2, P) return [_1, _1, _0];
s2 = addmod(s2, negmod(s1, P), P) } else {
const x = addmod(addmod(mulmod(s2, s2, P), negmod(z2, P), P), negmod(mulmod(uint256(2), t2, P), P), P) return ecdouble(_p);
return [ }
x,
addmod(mulmod(s2, addmod(t2, negmod(x, P), P), P), negmod(mulmod(s1, z2, P), P), P),
mulmod(u2, mulmod(_p[2], _q[2], P), P)
]
} }
function AtoJ(x, y) { u2 = addmod(u2, negmod(u1, P), P);
return [ z2 = mulmod(u2, u2, P);
uint256(x), const t2 = mulmod(u1, z2, P);
uint256(y), z2 = mulmod(u2, z2, P);
_1 s2 = addmod(s2, negmod(s1, P), P);
] const x = addmod(
} addmod(mulmod(s2, s2, P), negmod(z2, P), P),
negmod(mulmod(uint256(2), t2, P), P),
P,
);
return [
x,
addmod(
mulmod(s2, addmod(t2, negmod(x, P), P), P),
negmod(mulmod(s1, z2, P), P),
P,
),
mulmod(u2, mulmod(_p[2], _q[2], P), P),
];
}
function isValidPoint(x, y) { function AtoJ(x, y) {
const yy = addmod(mulmod(mulmod(x, x, P), x, P), B, P) return [uint256(x), uint256(y), _1];
return yy.eq(mulmod(y, y, P)) }
}
function toHex(bn) { function isValidPoint(x, y) {
return ('00000000000000000000000000000000000000000000000000000000000000000000000000000000' + bn.toString(16)).slice(-64) const yy = addmod(mulmod(mulmod(x, x, P), x, P), B, P);
} return yy.eq(mulmod(y, y, P));
}
function decompressKey(x, yBit) { function toHex(bn) {
let redP = BN.red('k256'); return (
x = x.toRed(redP) "00000000000000000000000000000000000000000000000000000000000000000000000000000000" +
const y = x.redMul(x).redMul(x).redAdd(B.toRed(redP)).redSqrt() bn.toString(16)
const sign = y.testn(0) ).slice(-64);
return (sign != yBit ? y.redNeg() : y).fromRed() }
}
function generatePublicKeyFromPrivateKeyData(pk) { function decompressKey(x, yBit) {
const p = mulG(pk) let redP = BN.red("k256");
return {x: toHex(p[0]), y: toHex(p[1])} x = x.toRed(redP);
} const y = x.redMul(x).redMul(x).redAdd(B.toRed(redP)).redSqrt();
const sign = y.testn(0);
return (sign != yBit ? y.redNeg() : y).fromRed();
}
function generatePublicKeyFromPrivateKeyData(pk) {
const p = mulG(pk);
return { x: toHex(p[0]), y: toHex(p[1]) };
}
function ecrecover(recId, sigr, sigs, message) { function ecrecover(recId, sigr, sigs, message) {
assert(recId >= 0 && recId <= 3, "recId must be 0..3") assert(recId >= 0 && recId <= 3, "recId must be 0..3");
assert(sigr != 0, "sigr must not be 0") assert(sigr != 0, "sigr must not be 0");
assert(sigs != 0, "sigs must not be 0") assert(sigs != 0, "sigs must not be 0");
// 1.0 For j from 0 to h (h == recId here and the loop is outside this function) // 1.0 For j from 0 to h (h == recId here and the loop is outside this function)
// 1.1 Let x = r + jn // 1.1 Let x = r + jn
const x = addmod(uint256(sigr), P.muln(recId >> 1), P) const x = addmod(uint256(sigr), P.muln(recId >> 1), P);
// 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine // 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine
// specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. // specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉.
// 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the
// conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then // conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then
// do another iteration of Step 1. // do another iteration of Step 1.
// //
// More concisely, what these points mean is to use X as a compressed public key. // More concisely, what these points mean is to use X as a compressed public key.
if (x.gte(P)) { if (x.gte(P)) {
// Cannot have point co-ordinates larger than this as everything takes place modulo Q. // Cannot have point co-ordinates larger than this as everything takes place modulo Q.
return null return null;
}
// Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities.
// So it's encoded in the recId.
const y = decompressKey(x, (recId & 1) == 1)
// 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility).
// if (!R.mul(N).isInfinity())
// return null
// 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification.
const e = uint256(message)
// 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId)
// 1.6.1. Compute a candidate public key as:
// Q = mi(r) * (sR - eG)
//
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
// Q = (mi(r) * s ** R) + (mi(r) * -e ** G)
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
// ** is point multiplication and + is point addition (the EC group operator).
//
// We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive
// inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.
const eNeg = negmod(e, N)
const rInv = invmod(sigr, N)
const srInv = mulmod(rInv, sigs, N)
const eNegrInv = mulmod(rInv, eNeg, N)
const R = AtoJ(x, y)
const G = AtoJ(GX, GY)
const qinJ = ecadd(ecmul(G, eNegrInv), ecmul(R, srInv))
const p = JtoA(qinJ)
return {x: toHex(p[0]), y: toHex(p[1])}
} }
// Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities.
// So it's encoded in the recId.
const y = decompressKey(x, (recId & 1) == 1);
// 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility).
// if (!R.mul(N).isInfinity())
// return null
// 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification.
const e = uint256(message);
// 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId)
// 1.6.1. Compute a candidate public key as:
// Q = mi(r) * (sR - eG)
//
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
// Q = (mi(r) * s ** R) + (mi(r) * -e ** G)
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
// ** is point multiplication and + is point addition (the EC group operator).
//
// We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive
// inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.
const eNeg = negmod(e, N);
const rInv = invmod(sigr, N);
const srInv = mulmod(rInv, sigs, N);
const eNegrInv = mulmod(rInv, eNeg, N);
const R = AtoJ(x, y);
const G = AtoJ(GX, GY);
const qinJ = ecadd(ecmul(G, eNegrInv), ecmul(R, srInv));
const p = JtoA(qinJ);
return { x: toHex(p[0]), y: toHex(p[1]) };
}
function ecverify (Qx, Qy, sigr, sigs, z) { function ecverify(Qx, Qy, sigr, sigs, z) {
if (sigs == 0 || sigr == 0) { if (sigs == 0 || sigr == 0) {
return false return false;
}
const w = invmod(sigs, N)
const u1 = mulmod(z, w, N)
const u2 = mulmod(sigr, w, N)
const Q = AtoJ(Qx, Qy)
const G = AtoJ(GX, GY)
const RinJ = ecadd(ecmul(G, u1), ecmul(Q, u2))
const r = JtoA(RinJ)
return sigr.eq(r[0])
} }
const w = invmod(sigs, N);
const u1 = mulmod(z, w, N);
const u2 = mulmod(sigr, w, N);
const Q = AtoJ(Qx, Qy);
const G = AtoJ(GX, GY);
const RinJ = ecadd(ecmul(G, u1), ecmul(Q, u2));
const r = JtoA(RinJ);
return sigr.eq(r[0]);
}
exports.uint256 = uint256 exports.uint256 = uint256;
exports.ecsign = ecsign exports.ecsign = ecsign;
exports.ecrecover = ecrecover exports.ecrecover = ecrecover;
exports.generatePublicKeyFromPrivateKeyData = generatePublicKeyFromPrivateKeyData exports.generatePublicKeyFromPrivateKeyData =
exports.decompressKey = decompressKey generatePublicKeyFromPrivateKeyData;
exports.isValidPoint = isValidPoint exports.decompressKey = decompressKey;
exports.ecverify = ecverify exports.isValidPoint = isValidPoint;
})() exports.ecverify = ecverify;
})();

742
sw_scripts/sw-bn.js

File diff suppressed because it is too large

8
vue.config.js

@ -11,13 +11,9 @@ module.exports = defineConfig({
iconPaths: { iconPaths: {
faviconSVG: "img/icons/safari-pinned-tab.svg", faviconSVG: "img/icons/safari-pinned-tab.svg",
}, },
workboxPluginMode: "InjectManifest",
workboxOptions: { workboxOptions: {
importScripts: [ swSrc: "./sw_scripts/additional-scripts.js",
"additional-scripts.js",
"safari-notifications.js",
"nacl.js",
"sw-bn.js",
],
}, },
}, },
}); });

Loading…
Cancel
Save