Compare commits

...

21 Commits

Author SHA1 Message Date
Matthew Raymer 2b8cd180a1 Refactored last viewed notification code. Appears to work now. 1 year ago
Matthew Raymer abc4a93b34 Added counting of pending notifications 1 year ago
Matthew Raymer 36493920f3 Before refactoring 1 year ago
Matthew Raymer 96fd4f68ef Updates using noble single file modules 1 year ago
Matthew Raymer fc37f475d5 Added noble-curves.js 1 year ago
Matthew Raymer 80b7ab2f82 adding fetching of claims. WIP: JWT verification 1 year ago
Matthew Raymer 5f2658fd01 able to sign -- let's see what happens next 1 year ago
Matthew Raymer 267ed40946 WIP: fixing secp256k1 and BN 1 year ago
Matthew Raymer 1ce9e788e9 NACL integrated 1 year ago
Matthew Raymer fe7b30ee32 Alert dialog for odd edge-case 1 year ago
Matthew Raymer ad3cb10722 Selected active account and did a little decoding an extraction before building JWT 1 year ago
Matthew Raymer d6dc7fbb10 Beefing up registration and activation of the service worker. 1 year ago
Matthew Raymer cf2fec75ea STopping here. Weird behavior while debugging. Sometimes works; sometimes now 1 year ago
Matthew Raymer 9216be523a All of salt cleared. Ready to test tomorrow 1 year ago
Matthew Raymer 7ab3cb2d1f One grain of salt 1 year ago
Matthew Raymer aba0d832db Up to loading accounts; looping and cryptograhy next 1 year ago
Matthew Raymer 7906aab36e WIP: fixing askPermission chain 1 year ago
Matthew Raymer 9b3d2b4c52 Added stripped down nacl and nudged toward integration 1 year ago
Matthew Raymer ceb12ef5bc Added grabbing settings 1 year ago
Matthew Raymer 805c7b4810 Added messaging to service worker. Restarting integration procss 1 year ago
Jose Olarte III c344d37bd9 Prettified identifier and register notices up top 1 year ago
  1. 86
      package-lock.json
  2. 7
      package.json
  3. 172
      src/App.vue
  4. 12
      src/libs/endorserServer.ts
  5. 2
      src/registerServiceWorker.ts
  6. 4
      src/views/ContactsView.vue
  7. 40
      src/views/HomeView.vue
  8. 80
      sw_scripts/additional-scripts.js
  9. 1051
      sw_scripts/nacl.js
  10. 5248
      sw_scripts/noble-curves.js
  11. 3068
      sw_scripts/noble-hashes.js
  12. 5684
      sw_scripts/safari-notifications.js
  13. 3
      vue.config.js

86
package-lock.json

@ -1,17 +1,18 @@
{ {
"name": "kickstart-for-time-pwa", "name": "kickstart-for-time-pwa",
"version": "0.1.0", "version": "0.1.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "kickstart-for-time-pwa", "name": "kickstart-for-time-pwa",
"version": "0.1.0", "version": "0.1.3",
"dependencies": { "dependencies": {
"@ethersproject/hdnode": "^5.7.0", "@ethersproject/hdnode": "^5.7.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/vue-fontawesome": "^3.0.3", "@fortawesome/vue-fontawesome": "^3.0.3",
"@lionello/secp256k1-js": "^1.1.0",
"@pvermeer/dexie-encrypted-addon": "^3.0.0", "@pvermeer/dexie-encrypted-addon": "^3.0.0",
"@tweenjs/tween.js": "^21.0.0", "@tweenjs/tween.js": "^21.0.0",
"@veramo/core": "^5.4.1", "@veramo/core": "^5.4.1",
@ -30,11 +31,13 @@
"dexie": "^3.2.4", "dexie": "^3.2.4",
"dexie-export-import": "^4.0.7", "dexie-export-import": "^4.0.7",
"did-jwt": "^7.2.7", "did-jwt": "^7.2.7",
"elliptic": "^6.5.4",
"ethereum-cryptography": "^2.1.2", "ethereum-cryptography": "^2.1.2",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"ethr-did-resolver": "^8.1.2", "ethr-did-resolver": "^8.1.2",
"jdenticon": "^3.2.0", "jdenticon": "^3.2.0",
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"jssha": "^3.3.1",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"luxon": "^3.4.3", "luxon": "^3.4.3",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
@ -72,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"
} }
@ -2821,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",
@ -2871,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"
@ -5498,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"
}, },
@ -5525,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": {
@ -6058,6 +6061,22 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true "dev": true
}, },
"node_modules/@lionello/secp256k1-js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@lionello/secp256k1-js/-/secp256k1-js-1.1.0.tgz",
"integrity": "sha512-frvrdwwgWm0gq43rYcGwwZee+k5sX9HfWnB80740h1dvRT0FO0Z6Wt5C5I7bS0dXKy1pt6IomkR1VcXirP+g4Q==",
"dependencies": {
"bn.js": "^4.11.8"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@lionello/secp256k1-js/node_modules/bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"node_modules/@noble/ciphers": { "node_modules/@noble/ciphers": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.3.0.tgz", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.3.0.tgz",
@ -9206,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",
@ -14220,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",
@ -18859,6 +18885,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/jssha": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.3.1.tgz",
"integrity": "sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==",
"engines": {
"node": "*"
}
},
"node_modules/keccak": { "node_modules/keccak": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz",
@ -23137,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"

7
package.json

@ -12,6 +12,7 @@
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/vue-fontawesome": "^3.0.3", "@fortawesome/vue-fontawesome": "^3.0.3",
"@lionello/secp256k1-js": "^1.1.0",
"@pvermeer/dexie-encrypted-addon": "^3.0.0", "@pvermeer/dexie-encrypted-addon": "^3.0.0",
"@tweenjs/tween.js": "^21.0.0", "@tweenjs/tween.js": "^21.0.0",
"@veramo/core": "^5.4.1", "@veramo/core": "^5.4.1",
@ -30,11 +31,13 @@
"dexie": "^3.2.4", "dexie": "^3.2.4",
"dexie-export-import": "^4.0.7", "dexie-export-import": "^4.0.7",
"did-jwt": "^7.2.7", "did-jwt": "^7.2.7",
"elliptic": "^6.5.4",
"ethereum-cryptography": "^2.1.2", "ethereum-cryptography": "^2.1.2",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"ethr-did-resolver": "^8.1.2", "ethr-did-resolver": "^8.1.2",
"jdenticon": "^3.2.0", "jdenticon": "^3.2.0",
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"jssha": "^3.3.1",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"luxon": "^3.4.3", "luxon": "^3.4.3",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
@ -72,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"
} }

172
src/App.vue

@ -261,7 +261,30 @@
<script lang="ts"> <script lang="ts">
import { Vue, Component } from "vue-facing-decorator"; import { Vue, Component } from "vue-facing-decorator";
import axios from "axios"; import axios, { AxiosError } from "axios";
interface ServiceWorkerMessage {
type: string;
data: string;
}
interface ServiceWorkerResponse {
// Define the properties and their types
success: boolean;
message?: string;
}
// Example interface for error
interface ErrorResponse {
message: string;
// Other properties as needed
}
interface VapidResponse {
data: {
vapidKey: string;
};
}
@Component @Component
export default class App extends Vue { export default class App extends Vue {
@ -269,45 +292,87 @@ export default class App extends Vue {
mounted() { mounted() {
axios axios
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid") .get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid")
.then((response) => { .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) => { .catch((error: AxiosError) => {
console.error("API error", error); console.error("API error", error);
}); });
} }
private sendMessageToServiceWorker(
message: ServiceWorkerMessage,
): Promise<unknown> {
return new Promise((resolve, reject) => {
if (navigator.serviceWorker.controller) {
const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = (event: MessageEvent) => {
if (event.data.error) {
reject(event.data.error as ErrorResponse);
} else {
resolve(event.data as ServiceWorkerResponse);
}
};
navigator.serviceWorker.controller.postMessage(message, [
messageChannel.port2,
]);
} else {
reject("Service worker controller not available");
}
});
}
private askPermission(): Promise<NotificationPermission> { private askPermission(): Promise<NotificationPermission> {
// Check if Notifications are supported if (!("serviceWorker" in navigator && navigator.serviceWorker.controller)) {
return Promise.reject("Service worker not available.");
}
const secret = localStorage.getItem("secret");
if (!secret) {
return Promise.reject("No secret found.");
}
return this.sendSecretToServiceWorker(secret)
.then(() => this.checkNotificationSupport())
.then(() => this.requestNotificationPermission())
.catch((error) => Promise.reject(error));
}
private sendSecretToServiceWorker(secret: string): Promise<void> {
const message: ServiceWorkerMessage = {
type: "SEND_LOCAL_DATA",
data: secret,
};
return this.sendMessageToServiceWorker(message).then((response) => {
console.log("Response from service worker:", response);
});
}
private checkNotificationSupport(): Promise<void> {
if (!("Notification" in window)) { if (!("Notification" in window)) {
alert("This browser does not support notifications."); alert("This browser does not support notifications.");
return Promise.reject("This browser does not support notifications."); return Promise.reject("This browser does not support notifications.");
} }
// Check existing permissions
if (Notification.permission === "granted") { if (Notification.permission === "granted") {
return Promise.resolve("granted"); return Promise.resolve();
} }
return Promise.resolve();
}
// Request permission private requestNotificationPermission(): Promise<NotificationPermission> {
return new Promise((resolve, reject) => { return Notification.requestPermission().then((permission) => {
const permissionResult = Notification.requestPermission((result) => { if (permission !== "granted") {
resolve(result);
});
if (permissionResult) {
permissionResult.then(resolve, reject);
}
}).then((permissionResult) => {
console.log("Permission result:", permissionResult);
if (permissionResult !== "granted") {
alert("We need notification permission to provide certain features."); alert("We need notification permission to provide certain features.");
return Promise.reject("We weren't granted permission."); throw new Error("We weren't granted permission.");
} }
return permission;
return permissionResult;
}); });
} }
@ -366,34 +431,49 @@ export default class App extends Vue {
return outputArray; return outputArray;
} }
// The subscribeToPush method
private subscribeToPush(): Promise<void> { private subscribeToPush(): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
if ("serviceWorker" in navigator && "PushManager" in window) { if (!("serviceWorker" in navigator && "PushManager" in window)) {
const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
const options: PushSubscriptionOptions = {
userVisibleOnly: true,
applicationServerKey: applicationServerKey,
};
console.log(options);
navigator.serviceWorker.ready
.then((registration) => {
return registration.pushManager.subscribe(options);
})
.then((subscription) => {
console.log("Push subscription successful:", subscription);
resolve();
})
.catch((error) => {
console.error("Push subscription failed:", error, options);
reject(error);
});
} else {
const errorMsg = "Push messaging is not supported"; const errorMsg = "Push messaging is not supported";
console.warn(errorMsg); console.warn(errorMsg);
reject(new Error(errorMsg)); return reject(new Error(errorMsg));
}
if (Notification.permission !== "granted") {
const errorMsg = "Notification permission not granted";
console.warn(errorMsg);
return reject(new Error(errorMsg));
} }
const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
const options: PushSubscriptionOptions = {
userVisibleOnly: true,
applicationServerKey: applicationServerKey,
};
navigator.serviceWorker.ready
.then((registration) => {
return registration.pushManager.subscribe(options);
})
.then((subscription) => {
console.log("Push subscription successful:", subscription);
resolve();
})
.catch((error) => {
console.error(
"Subscription or server communication failed:",
error,
options,
);
// Inform the user about the issue
alert(
"We encountered an issue setting up push notifications. " +
"If you wish to revoke notification permissions, please do so in your browser settings.",
);
reject(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 />

40
src/views/HomeView.vue

@ -8,22 +8,38 @@
<!-- show the actions for recognizing a give --> <!-- show the actions for recognizing a give -->
<div class="mb-8"> <div class="mb-8">
<div v-if="!activeDid"> <div
To record others' giving, v-if="!activeDid"
<router-link :to="{ name: 'start' }" class="text-blue-500"> class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
create your identifier.</router-link >
<p class="text-lg mb-3">
You need an <b>identifier</b> before you can record others' giving.
</p>
<router-link
:to="{ name: 'start' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
>
Create Your Identifier</router-link
> >
</div> </div>
<div v-else-if="!isRegistered"> <div
To record others' giving, someone must register your account, so show v-else-if="!isRegistered"
them class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
<router-link :to="{ name: 'contact-qr' }" class="text-blue-500"> >
your identity info</router-link Someone must register your account before you can record others' giving.
To do this:
<router-link
:to="{ name: 'contact-qr' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
>
1. Show Them Your Identity Info</router-link
>
<router-link
:to="{ name: 'account' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
> >
and then 2. Check Your Limits</router-link
<router-link :to="{ name: 'account' }" class="text-blue-500">
check your limits.</router-link
> >
</div> </div>

80
sw_scripts/additional-scripts.js

@ -1,33 +1,63 @@
const notifications = require("./safari-notifications.js"); /* eslint-env serviceworker */
/* global workbox */
importScripts(
"https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js",
);
self.addEventListener("install", (event) => {
importScripts(
"safari-notifications.js",
"nacl.js",
"noble-curves.js",
"noble-hashes.js",
);
});
self.addEventListener("push", function (event) { self.addEventListener("push", function (event) {
let payload; event.waitUntil(
if (event.data) { (async () => {
payload = JSON.parse(event.data.text()); try {
} let payload;
if (event.data) {
const title = payload ? payload.title : "Custom Title"; payload = JSON.parse(event.data.text());
const options = { }
body: payload ? payload.body : "Custom body text", const message = await self.getNotificationCount();
icon: payload ? payload.icon : "icon.png", const title = payload ? payload.title : "Custom Title";
badge: payload ? payload.badge : "badge.png", const options = {
}; body: message,
icon: payload ? payload.icon : "icon.png",
event.waitUntil(self.registration.showNotification(title, options)); badge: payload ? payload.badge : "badge.png",
};
await self.registration.showNotification(title, options);
} 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;
event.ports[0].postMessage({ success: true });
}
});
self.addEventListener("message", function (event) { self.addEventListener("activate", (event) => {
const data = event.data; event.waitUntil(clients.claim());
console.log("Service worker activated", event);
const result = notifications.getNotificationCount() });
switch (data.command) { self.addEventListener("fetch", (event) => {
case "account": console.log(event.request);
break; });
default: self.addEventListener("error", (event) => {
console.log("Unknown command:", data.command); console.error("Error in Service Worker:", event.message);
} console.error("File:", event.filename);
console.error("Line:", event.lineno);
console.error("Column:", event.colno);
console.error("Error Object:", event.error);
}); });
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);

1051
sw_scripts/nacl.js

File diff suppressed because it is too large

5248
sw_scripts/noble-curves.js

File diff suppressed because it is too large

3068
sw_scripts/noble-hashes.js

File diff suppressed because it is too large

5684
sw_scripts/safari-notifications.js

File diff suppressed because it is too large

3
vue.config.js

@ -11,8 +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: ["additional-scripts.js"], swSrc: "./sw_scripts/additional-scripts.js",
}, },
}, },
}); });

Loading…
Cancel
Save