Browse Source

misc tweaks and linting clean-up

master
Trent Larson 5 months ago
parent
commit
33d6b9df96
  1. 3
      src/App.vue
  2. 6
      src/constants/app.ts
  3. 10
      src/libs/didPeer.ts
  4. 4
      src/views/IdentitySwitcherView.vue
  5. 2
      src/views/NewEditAccountView.vue
  6. 31
      src/views/TestView.vue
  7. 2
      vite.config.mjs

3
src/App.vue

@ -181,6 +181,7 @@
class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2" class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
> >
Yes Yes
{{ notification.yesText ? ", " + notification.yesText : "" }}
</button> </button>
<button <button
@ -192,7 +193,7 @@
" "
class="block w-full text-center text-md font-bold uppercase bg-yellow-600 text-white px-2 py-2 rounded-md mb-2" class="block w-full text-center text-md font-bold uppercase bg-yellow-600 text-white px-2 py-2 rounded-md mb-2"
> >
No No {{ notification.noText ? ", " + notification.noText : "" }}
</button> </button>
<label <label

6
src/constants/app.ts

@ -4,6 +4,10 @@
* See also ../libs/veramo/setup.ts * See also ../libs/veramo/setup.ts
*/ */
export enum AppString { export enum AppString {
// This is used in titles and verbiage inside the app.
// There is also an app name without spaces, for packaging in the package.json file used in the manifest.
APP_NAME = "Time Safari",
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch", PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch", TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch",
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000", LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
@ -41,8 +45,10 @@ export interface NotificationIface {
type: string; // "toast" | "info" | "success" | "warning" | "danger" type: string; // "toast" | "info" | "success" | "warning" | "danger"
title: string; title: string;
text?: string; text?: string;
noText?: string;
onCancel?: (stopAsking: boolean) => Promise<void>; onCancel?: (stopAsking: boolean) => Promise<void>;
onNo?: (stopAsking: boolean) => Promise<void>; onNo?: (stopAsking: boolean) => Promise<void>;
onYes?: () => Promise<void>; onYes?: () => Promise<void>;
promptToStopAsking?: boolean; promptToStopAsking?: boolean;
yesText?: string;
} }

10
src/libs/didPeer.ts

@ -1,4 +1,3 @@
import asn1 from "asn1-ber";
import { Buffer } from "buffer/"; import { Buffer } from "buffer/";
import { decode as cborDecode } from "cbor-x"; import { decode as cborDecode } from "cbor-x";
import { bytesToMultibase, JWTPayload, multibaseToBytes } from "did-jwt"; import { bytesToMultibase, JWTPayload, multibaseToBytes } from "did-jwt";
@ -195,12 +194,12 @@ export class PeerSetup {
allowCredentials: [ allowCredentials: [
{ {
id: credentialId, id: credentialId,
type: "public-key", type: "public-key" as const,
}, },
], ],
challenge: this.challenge.buffer, challenge: this.challenge.buffer,
rpID: window.location.hostname, rpID: window.location.hostname,
userVerification: "preferred", userVerification: "preferred" as const,
}, },
}; };
@ -209,7 +208,7 @@ export class PeerSetup {
this.authenticatorData = credential?.response.authenticatorData; this.authenticatorData = credential?.response.authenticatorData;
const authenticatorDataBase64Url = arrayBufferToBase64URLString( const authenticatorDataBase64Url = arrayBufferToBase64URLString(
this.authenticatorData, this.authenticatorData as ArrayBuffer,
); );
this.clientDataJsonBase64Url = arrayBufferToBase64URLString( this.clientDataJsonBase64Url = arrayBufferToBase64URLString(
@ -249,6 +248,9 @@ export class PeerSetup {
return jwt; return jwt;
} }
// To use this, add the asn1-ber library and add this import:
// import asn1 from "asn1-ber";
//
// return a low-level signing function, similar to createJWS approach // return a low-level signing function, similar to createJWS approach
// async webAuthnES256KSigner(credentialID: string) { // async webAuthnES256KSigner(credentialID: string) {
// return async (data: string | Uint8Array) => { // return async (data: string | Uint8Array) => {

4
src/views/IdentitySwitcherView.vue

@ -164,7 +164,7 @@ export default class IdentitySwitcherView extends Vue {
group: "modal", group: "modal",
type: "confirm", type: "confirm",
title: "Delete Identity?", title: "Delete Identity?",
text: "Are you sure you want to permanently delete this identity? (There is no undo.)", text: "Are you sure you want to erase this identity? (There is no undo. You may want to select it and back it up just in case.)",
onYes: async () => { onYes: async () => {
await accountsDB.open(); await accountsDB.open();
await accountsDB.accounts.delete(id); await accountsDB.accounts.delete(id);
@ -185,7 +185,7 @@ export default class IdentitySwitcherView extends Vue {
title: "Cannot Delete", title: "Cannot Delete",
text: "You cannot delete the active identity.", text: "You cannot delete the active identity.",
}, },
5000, 3000,
); );
} }
} }

2
src/views/NewEditAccountView.vue

@ -68,8 +68,6 @@ export default class NewEditAccountView extends Vue {
firstName: this.givenName, firstName: this.givenName,
lastName: "", // deprecated, pre v 0.1.3 lastName: "", // deprecated, pre v 0.1.3
}); });
localStorage.setItem("firstName", this.givenName as string);
localStorage.setItem("lastName", ""); // deprecated, pre v 0.1.3
this.$router.back(); this.$router.back();
} }

31
src/views/TestView.vue

@ -176,8 +176,8 @@
<br /> <br />
See existing passkeys in Chrome at: chrome://settings/passkeys See existing passkeys in Chrome at: chrome://settings/passkeys
<br /> <br />
Active DID: {{ activeDid }} Active DID: {{ activeDid || "nothing, which" }}
{{ credIdHex ? "has passkey ID" : "has no passkey ID" }} {{ credIdHex ? "has a passkey ID" : "has no passkey ID" }}
<div> <div>
Register Passkey Register Passkey
@ -244,6 +244,7 @@ import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index"; import { accountsDB, db } from "@/db/index";
import { import {
createPeerDid, createPeerDid,
@ -269,6 +270,8 @@ const TEST_PAYLOAD = {
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav } })
export default class Help extends Vue { export default class Help extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
// for file import // for file import
fileName?: string; fileName?: string;
@ -300,7 +303,7 @@ export default class Help extends Vue {
} }
async uploadFile(event: Event) { async uploadFile(event: Event) {
inputFileNameRef.value = event.target.files[0]; inputFileNameRef.value = event.target?.["files"][0];
// https://developer.mozilla.org/en-US/docs/Web/API/File // https://developer.mozilla.org/en-US/docs/Web/API/File
// ... plus it has a `type` property from my testing // ... plus it has a `type` property from my testing
const file = inputFileNameRef.value; const file = inputFileNameRef.value;
@ -330,7 +333,27 @@ export default class Help extends Vue {
} }
public async register() { public async register() {
const cred = await registerCredential(this.userName); const DEFAULT_USERNAME = "Time Safari Tester";
if (!this.userName) {
this.$notify(
{
group: "modal",
type: "confirm",
title: "No Name",
text: "You must have a name to attach to this passkey. Would you like to enter your own name first?",
onNo: async () => {
this.userName = DEFAULT_USERNAME;
},
onYes: async () => {
this.$router.push({ name: "new-edit-account" });
},
noText: "try again and use " + DEFAULT_USERNAME,
},
-1,
);
return;
}
const cred = await registerCredential("Time Safari - " + this.userName);
const publicKeyBytes = cred.publicKeyBytes; const publicKeyBytes = cred.publicKeyBytes;
this.activeDid = createPeerDid(publicKeyBytes as Uint8Array); this.activeDid = createPeerDid(publicKeyBytes as Uint8Array);
this.credIdHex = cred.credIdHex as string; this.credIdHex = cred.credIdHex as string;

2
vite.config.mjs

@ -16,6 +16,8 @@ export default defineConfig({
srcDir: '.', srcDir: '.',
filename: 'sw_scripts-combined.js', filename: 'sw_scripts-combined.js',
manifest: { manifest: {
// This is used for the app name. It doesn't include a space, because iOS complains if i recall correctly.
// There is a name with spaces in the constants/app.js file for use internally.
name: process.env.TIME_SAFARI_APP_TITLE || require('./package.json').name, name: process.env.TIME_SAFARI_APP_TITLE || require('./package.json').name,
short_name: process.env.TIME_SAFARI_APP_TITLE || require('./package.json').name, short_name: process.env.TIME_SAFARI_APP_TITLE || require('./package.json').name,
// 192x192 and 512x512 are important for Chrome to show that it's installable // 192x192 and 512x512 are important for Chrome to show that it's installable

Loading…
Cancel
Save