Merge branch 'master' into remove-image-cache
This commit is contained in:
@@ -167,7 +167,7 @@ export default class ContactInputForm extends Vue {
|
||||
*/
|
||||
@Emit("qr-scan")
|
||||
private handleQRScan(): void {
|
||||
console.log("[ContactInputForm] QR scan button clicked");
|
||||
// QR scan button clicked - event emitted for parent handling
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1348,12 +1348,12 @@ export async function createEndorserJwtVcFromClaim(
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JWT for a RegisterAction claim.
|
||||
* Create a JWT for a RegisterAction claim, used for registrations & invites.
|
||||
*
|
||||
* @param activeDid - The DID of the user creating the invite
|
||||
* @param contact - The contact to register, with a 'did' field (all optional for invites)
|
||||
* @param identifier - The identifier for the invite, usually random
|
||||
* @param expiresIn - The number of seconds until the invite expires
|
||||
* @param contact - Optional - The contact to register, with a 'did' field (all optional for invites)
|
||||
* @param identifier - Optional - The identifier for the invite, usually random
|
||||
* @param expiresIn - Optional - The number of seconds until the invite expires
|
||||
* @returns The JWT for the RegisterAction claim
|
||||
*/
|
||||
export async function createInviteJwt(
|
||||
@@ -1367,7 +1367,7 @@ export async function createInviteJwt(
|
||||
"@type": "RegisterAction",
|
||||
agent: { identifier: activeDid },
|
||||
object: SERVICE_ID,
|
||||
identifier: identifier,
|
||||
identifier: identifier, // not sent if undefined
|
||||
};
|
||||
if (contact?.did) {
|
||||
vcClaim.participant = { identifier: contact.did };
|
||||
|
||||
@@ -82,6 +82,15 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: "database-migration",
|
||||
component: () => import("../views/DatabaseMigration.vue"),
|
||||
},
|
||||
{
|
||||
path: "/deep-link-error",
|
||||
name: "deep-link-error",
|
||||
component: () => import("../views/DeepLinkErrorView.vue"),
|
||||
meta: {
|
||||
title: "Invalid Deep Link",
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/did/:did?",
|
||||
name: "did",
|
||||
@@ -276,15 +285,6 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: "user-profile",
|
||||
component: () => import("../views/UserProfileView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/deep-link-error",
|
||||
name: "deep-link-error",
|
||||
component: () => import("../views/DeepLinkErrorView.vue"),
|
||||
meta: {
|
||||
title: "Invalid Deep Link",
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const isElectron = window.location.protocol === "file:";
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// **WORKER-COMPATIBLE CRYPTO POLYFILL**: Must be at the very top
|
||||
// This prevents "crypto is not defined" errors when running in worker context
|
||||
if (typeof window === "undefined" && typeof crypto === "undefined") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).crypto = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getRandomValues: (array: any) => {
|
||||
// Simple fallback for worker context
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
|
||||
@@ -179,7 +179,7 @@ export class DeepLinkHandler {
|
||||
const validRoute = routeSchema.parse(path) as DeepLinkRoute;
|
||||
routeName = ROUTE_MAP[validRoute].name;
|
||||
} catch (error) {
|
||||
console.error(`[DeepLink] Invalid route path: ${path}`);
|
||||
logger.error(`[DeepLink] Invalid route path: ${path}`);
|
||||
|
||||
// Redirect to error page with information about the invalid link
|
||||
await this.router.replace({
|
||||
|
||||
@@ -693,7 +693,8 @@ export class WebPlatformService implements PlatformService {
|
||||
const setClause = keys.map((key) => `${key} = ?`).join(", ");
|
||||
const sql = `UPDATE settings SET ${setClause} WHERE accountDid = ?`;
|
||||
const params = [...keys.map((key) => settings[key]), did];
|
||||
console.log(
|
||||
// Log update operation for debugging
|
||||
logger.debug(
|
||||
"[WebPlatformService] updateDidSpecificSettings",
|
||||
sql,
|
||||
JSON.stringify(params, null, 2),
|
||||
|
||||
@@ -92,6 +92,7 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||
})
|
||||
export default class PlatformServiceMixinTest extends Vue {
|
||||
result: string = "";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
userZeroTestResult: any = null;
|
||||
activeTest: string = ""; // Track which test is currently active
|
||||
|
||||
@@ -267,6 +268,7 @@ This tests the complete save → retrieve cycle with actual database interaction
|
||||
this.result = `User #0 settings test completed. isRegistered: ${accountSettings.isRegistered}`;
|
||||
} catch (error) {
|
||||
this.result = `Error testing User #0 settings: ${error}`;
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error testing User #0 settings:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import axios from "axios";
|
||||
import * as didJwt from "did-jwt";
|
||||
import { SERVICE_ID } from "../libs/endorserServer";
|
||||
import { deriveAddress, newIdentifier } from "../libs/crypto";
|
||||
import {
|
||||
DEFAULT_ROOT_DERIVATION_PATH,
|
||||
deriveAddress,
|
||||
newIdentifier,
|
||||
} from "../libs/crypto";
|
||||
import { logger } from "../utils/logger";
|
||||
import { AppString } from "../constants/app";
|
||||
import { saveNewIdentity } from "@/libs/util";
|
||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||
|
||||
const TEST_USER_0_MNEMONIC =
|
||||
"rigid shrug mobile smart veteran half all pond toilet brave review universe ship congress found yard skate elite apology jar uniform subway slender luggage";
|
||||
|
||||
export async function testBecomeUser0() {
|
||||
const [addr, privateHex, publicHex, deriPath] = deriveAddress(TEST_USER_0_MNEMONIC);
|
||||
|
||||
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
|
||||
await saveNewIdentity(identity0, TEST_USER_0_MNEMONIC, DEFAULT_ROOT_DERIVATION_PATH);
|
||||
const platformService = await PlatformServiceFactory.getInstance();
|
||||
await platformService.updateDidSpecificSettings(identity0.did, {
|
||||
isRegistered: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get User #0 to sign & submit a RegisterAction for the user's activeDid.
|
||||
@@ -15,10 +35,7 @@ import { AppString } from "../constants/app";
|
||||
* @throws Error if registration fails or database access fails
|
||||
*/
|
||||
export async function testServerRegisterUser() {
|
||||
const testUser0Mnem =
|
||||
"seminar accuse mystery assist delay law thing deal image undo guard initial shallow wrestle list fragile borrow velvet tomorrow awake explain test offer control";
|
||||
|
||||
const [addr, privateHex, publicHex, deriPath] = deriveAddress(testUser0Mnem);
|
||||
const [addr, privateHex, publicHex, deriPath] = deriveAddress(TEST_USER_0_MNEMONIC);
|
||||
|
||||
const identity0 = newIdentifier(addr, publicHex, privateHex, deriPath);
|
||||
|
||||
@@ -32,9 +49,9 @@ export async function testServerRegisterUser() {
|
||||
const vcClaim = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "RegisterAction",
|
||||
agent: { did: identity0.did },
|
||||
agent: { identifier: identity0.did },
|
||||
object: SERVICE_ID,
|
||||
participant: { did: settings.activeDid },
|
||||
participant: { identifier: settings.activeDid },
|
||||
};
|
||||
|
||||
// Make a payload for the claim
|
||||
@@ -71,4 +88,5 @@ export async function testServerRegisterUser() {
|
||||
|
||||
const resp = await axios.post(url, payload, { headers });
|
||||
logger.log("User registration result:", resp);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ export const PlatformServiceMixin = {
|
||||
* Used for change detection and component updates
|
||||
*/
|
||||
currentActiveDid(): string | null {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (this as any)._currentActiveDid;
|
||||
},
|
||||
|
||||
@@ -200,7 +201,9 @@ export const PlatformServiceMixin = {
|
||||
* This method should be called when the user switches identities
|
||||
*/
|
||||
async $updateActiveDid(newDid: string | null): Promise<void> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const oldDid = (this as any)._currentActiveDid;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(this as any)._currentActiveDid = newDid;
|
||||
|
||||
if (newDid !== oldDid) {
|
||||
@@ -291,6 +294,7 @@ export const PlatformServiceMixin = {
|
||||
|
||||
// Convert searchBoxes array to JSON string if present
|
||||
if (settings.searchBoxes !== undefined) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(converted as any).searchBoxes = Array.isArray(settings.searchBoxes)
|
||||
? JSON.stringify(settings.searchBoxes)
|
||||
: String(settings.searchBoxes);
|
||||
@@ -692,6 +696,7 @@ export const PlatformServiceMixin = {
|
||||
typeof method.value === "string";
|
||||
|
||||
if (!isValid && method !== undefined) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
"[ContactNormalization] Invalid contact method:",
|
||||
method,
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
/>
|
||||
|
||||
<!-- Notifications -->
|
||||
<!-- Currently disabled because it doesn't work, even on Chrome. If restored, make sure it works or doesn't show on mobile/electron. -->
|
||||
<!-- Currently disabled because it doesn't work, even on Chrome.
|
||||
If restored, make sure it works or doesn't show on mobile/electron. -->
|
||||
<section
|
||||
v-if="false"
|
||||
id="sectionNotifications"
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
<!-- Breadcrumb -->
|
||||
<div id="ViewBreadcrumb" class="mb-8">
|
||||
<h1 id="ViewHeading" class="text-lg text-center font-light relative px-7">
|
||||
<!-- Go to 'contacts' instead of just 'back' because they could get here from an edit page (and going back there is annoying). -->
|
||||
<!-- Go to 'contacts' instead of just 'back' because they could get here from an edit page
|
||||
(and going back there is annoying). -->
|
||||
<router-link
|
||||
:to="{ name: 'contacts' }"
|
||||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||
|
||||
@@ -21,7 +21,17 @@
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div v-if="isNotProdServer">
|
||||
<h2 class="text-xl font-bold mb-4">User Registration</h2>
|
||||
<button :class="primaryButtonClasses" @click="registerMe()">
|
||||
Register Yourself
|
||||
</button>
|
||||
<button :class="primaryButtonClasses" @click="becomeUser0()">
|
||||
Become User 0 (who can register others)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<h2 class="text-xl font-bold mb-4">Notiwind Alerts</h2>
|
||||
|
||||
<!-- Notification test buttons using computed configuration -->
|
||||
@@ -99,7 +109,7 @@
|
||||
|
||||
<div>
|
||||
Register Passkey
|
||||
<button :class="primaryButtonClasses" @click="register()">
|
||||
<button :class="primaryButtonClasses" @click="registerPasskey()">
|
||||
Simplewebauthn
|
||||
</button>
|
||||
</div>
|
||||
@@ -235,6 +245,7 @@ import {
|
||||
registerAndSavePasskey,
|
||||
SHARED_PHOTO_BASE64_KEY,
|
||||
} from "../libs/util";
|
||||
import { testBecomeUser0, testServerRegisterUser } from "@/test";
|
||||
import { logger } from "../utils/logger";
|
||||
import { Account } from "../db/tables/accounts";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
@@ -300,6 +311,7 @@ export default class Help extends Vue {
|
||||
// for passkeys
|
||||
credIdHex?: string;
|
||||
activeDid?: string;
|
||||
apiServer?: string;
|
||||
jwt?: string;
|
||||
peerSetup?: PeerSetup;
|
||||
userName?: string;
|
||||
@@ -521,17 +533,6 @@ export default class Help extends Vue {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to trigger notification test
|
||||
* Centralizes notification testing logic
|
||||
*/
|
||||
triggerTestNotification(config: {
|
||||
notification: NotificationIface;
|
||||
timeout?: number;
|
||||
}) {
|
||||
this.$notify(config.notification, config.timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component initialization
|
||||
*
|
||||
@@ -541,6 +542,7 @@ export default class Help extends Vue {
|
||||
async mounted() {
|
||||
const settings = await this.$accountSettings();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.userName = settings.firstName;
|
||||
|
||||
const account = await retrieveAccountMetadata(this.activeDid);
|
||||
@@ -553,6 +555,43 @@ export default class Help extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on production server
|
||||
*
|
||||
* @returns True if not on production server (enables test utilities)
|
||||
*/
|
||||
public isNotProdServer() {
|
||||
return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER;
|
||||
}
|
||||
|
||||
async registerMe() {
|
||||
const response = await testServerRegisterUser();
|
||||
if (response.status === 201) {
|
||||
alert("Registration successful.");
|
||||
this.$router.push({ name: "home" }); // because this page checks for registered status and sets things if it detects a change
|
||||
} else {
|
||||
logger.error("Registration failure response:", response);
|
||||
alert("Registration failed: " + (response.data.error || response.data));
|
||||
}
|
||||
}
|
||||
|
||||
async becomeUser0() {
|
||||
await testBecomeUser0();
|
||||
alert("You are now User 0.");
|
||||
this.$router.push({ name: "home" }); // because this page checks for registered status and sets things if it detects a change
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to trigger notification test
|
||||
* Centralizes notification testing logic
|
||||
*/
|
||||
triggerTestNotification(config: {
|
||||
notification: NotificationIface;
|
||||
timeout?: number;
|
||||
}) {
|
||||
this.$notify(config.notification, config.timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles file upload for image sharing tests
|
||||
*
|
||||
@@ -609,7 +648,7 @@ export default class Help extends Vue {
|
||||
* Includes validation and user confirmation workflow
|
||||
* Uses notification helpers for consistent messaging
|
||||
*/
|
||||
public async register() {
|
||||
public async registerPasskey() {
|
||||
const DEFAULT_USERNAME = AppString.APP_NAME + " Tester";
|
||||
if (!this.userName) {
|
||||
const modalConfig = createPasskeyNameModal(
|
||||
|
||||
Reference in New Issue
Block a user