Skip to content

Commit ca8bce1

Browse files
committed
chore: public key retrieval logic
1 parent 7952d68 commit ca8bce1

File tree

7 files changed

+336
-18
lines changed

7 files changed

+336
-18
lines changed

infrastructure/eid-wallet/src/lib/global/controllers/evault.ts

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { PUBLIC_REGISTRY_URL } from "$env/static/public";
1+
import { PUBLIC_REGISTRY_URL, PUBLIC_PROVISIONER_URL } from "$env/static/public";
22
import type { Store } from "@tauri-apps/plugin-store";
33
import axios from "axios";
44
import { GraphQLClient } from "graphql-request";
55
import NotificationService from "../../services/NotificationService";
66
import type { UserController } from "./user";
7+
import type { KeyService } from "./key";
78

89
const STORE_META_ENVELOPE = `
910
mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) {
@@ -47,12 +48,14 @@ export class VaultController {
4748
#client: GraphQLClient | null = null;
4849
#endpoint: string | null = null;
4950
#userController: UserController;
51+
#keyService: KeyService | null = null;
5052
#profileCreationStatus: "idle" | "loading" | "success" | "failed" = "idle";
5153
#notificationService: NotificationService;
5254

53-
constructor(store: Store, userController: UserController) {
55+
constructor(store: Store, userController: UserController, keyService?: KeyService) {
5456
this.#store = store;
5557
this.#userController = userController;
58+
this.#keyService = keyService || null;
5659
this.#notificationService = NotificationService.getInstance();
5760
}
5861

@@ -74,6 +77,92 @@ export class VaultController {
7477
this.#profileCreationStatus = status;
7578
}
7679

80+
/**
81+
* Sync public key to eVault core
82+
* Checks if public key was already saved, calls /whois, and PATCH if needed
83+
*/
84+
private async syncPublicKey(eName: string): Promise<void> {
85+
try {
86+
// Check if we've already saved the public key
87+
const savedKey = localStorage.getItem(`publicKeySaved_${eName}`);
88+
if (savedKey === "true") {
89+
console.log(`Public key already saved for ${eName}, skipping sync`);
90+
return;
91+
}
92+
93+
if (!this.#keyService) {
94+
console.warn("KeyService not available, cannot sync public key");
95+
return;
96+
}
97+
98+
// Get the eVault URI
99+
const vault = await this.vault;
100+
if (!vault?.uri) {
101+
console.warn("No vault URI available, cannot sync public key");
102+
return;
103+
}
104+
105+
// Call /whois to check if public key exists
106+
const whoisUrl = new URL("/whois", vault.uri).toString();
107+
const whoisResponse = await axios.get(whoisUrl, {
108+
headers: {
109+
"X-ENAME": eName,
110+
},
111+
});
112+
113+
const existingPublicKey = whoisResponse.data?.publicKey;
114+
if (existingPublicKey) {
115+
// Public key already exists, mark as saved
116+
localStorage.setItem(`publicKeySaved_${eName}`, "true");
117+
console.log(`Public key already exists for ${eName}`);
118+
return;
119+
}
120+
121+
// Get public key from KeyService
122+
const publicKey = await this.#keyService.getPublicKey(eName, "signing");
123+
if (!publicKey) {
124+
console.warn(`No public key found for ${eName}, cannot sync`);
125+
return;
126+
}
127+
128+
// Get authentication token from registry
129+
let authToken: string | null = null;
130+
try {
131+
const entropyResponse = await axios.get(
132+
new URL("/entropy", PUBLIC_REGISTRY_URL).toString()
133+
);
134+
authToken = entropyResponse.data?.token || null;
135+
} catch (error) {
136+
console.error("Failed to get auth token from registry:", error);
137+
// Continue without token - server will reject if auth is required
138+
}
139+
140+
// Call PATCH /public-key to save the public key
141+
const patchUrl = new URL("/public-key", vault.uri).toString();
142+
const headers: Record<string, string> = {
143+
"X-ENAME": eName,
144+
"Content-Type": "application/json",
145+
};
146+
147+
if (authToken) {
148+
headers["Authorization"] = `Bearer ${authToken}`;
149+
}
150+
151+
await axios.patch(
152+
patchUrl,
153+
{ publicKey },
154+
{ headers }
155+
);
156+
157+
// Mark as saved
158+
localStorage.setItem(`publicKeySaved_${eName}`, "true");
159+
console.log(`Public key synced successfully for ${eName}`);
160+
} catch (error) {
161+
console.error("Failed to sync public key:", error);
162+
// Don't throw - this is a non-critical operation
163+
}
164+
}
165+
77166
/**
78167
* Register device for notifications
79168
*/
@@ -352,6 +441,9 @@ export class VaultController {
352441
// Register device for notifications
353442
this.registerDeviceForNotifications(vault.ename);
354443

444+
// Sync public key to eVault core
445+
this.syncPublicKey(vault.ename);
446+
355447
if (this.profileCreationStatus === "success") return;
356448
// Set loading status
357449
this.profileCreationStatus = "loading";

infrastructure/eid-wallet/src/lib/global/state.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ export class GlobalState {
3434
this.#store = store;
3535
this.securityController = new SecurityController(store);
3636
this.userController = new UserController(store);
37-
this.vaultController = new VaultController(store, this.userController);
38-
this.notificationService = NotificationService.getInstance();
3937
this.keyService = keyService;
38+
this.vaultController = new VaultController(store, this.userController, keyService);
39+
this.notificationService = NotificationService.getInstance();
4040
}
4141

4242
/**

infrastructure/evault-core/src/core/db/db.service.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,48 @@ export class DbService {
590590
});
591591
}
592592

593+
/**
594+
* Gets the public key for a given eName.
595+
* @param eName - The eName identifier
596+
* @returns The public key string, or null if not found
597+
*/
598+
async getPublicKey(eName: string): Promise<string | null> {
599+
if (!eName) {
600+
throw new Error("eName is required for getting public key");
601+
}
602+
603+
const result = await this.runQuery(
604+
`MATCH (u:User { eName: $eName }) RETURN u.publicKey AS publicKey`,
605+
{ eName }
606+
);
607+
608+
if (!result.records[0]) {
609+
return null;
610+
}
611+
612+
return result.records[0].get("publicKey") || null;
613+
}
614+
615+
/**
616+
* Sets or updates the public key for a given eName.
617+
* @param eName - The eName identifier
618+
* @param publicKey - The public key to store
619+
*/
620+
async setPublicKey(eName: string, publicKey: string): Promise<void> {
621+
if (!eName) {
622+
throw new Error("eName is required for setting public key");
623+
}
624+
if (!publicKey) {
625+
throw new Error("publicKey is required");
626+
}
627+
628+
await this.runQuery(
629+
`MERGE (u:User { eName: $eName })
630+
SET u.publicKey = $publicKey`,
631+
{ eName, publicKey }
632+
);
633+
}
634+
593635
/**
594636
* Closes the database connection.
595637
*/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Neo4j Migration: Add User node index for eName property
3+
*
4+
* This migration creates an index on the eName property of User nodes
5+
* to ensure optimal query performance for public key lookups.
6+
*
7+
* Run this migration once to create the index:
8+
* ```cypher
9+
* CREATE INDEX user_ename_index FOR (u:User) ON (u.eName)
10+
* ```
11+
*/
12+
13+
import { Driver } from "neo4j-driver";
14+
15+
export async function createUserIndex(driver: Driver): Promise<void> {
16+
const session = driver.session();
17+
try {
18+
await session.run(
19+
`CREATE INDEX user_ename_index IF NOT EXISTS FOR (u:User) ON (u.eName)`
20+
);
21+
console.log("Created User eName index");
22+
} catch (error) {
23+
// Index might already exist, which is fine
24+
if (error instanceof Error && error.message.includes("already exists")) {
25+
console.log("User eName index already exists");
26+
} else {
27+
console.error("Error creating User eName index:", error);
28+
throw error;
29+
}
30+
} finally {
31+
await session.close();
32+
}
33+
}
34+

0 commit comments

Comments
 (0)