diff --git a/.env.example b/.env.example index d81932bd..b31437a3 100644 --- a/.env.example +++ b/.env.example @@ -71,3 +71,5 @@ EREPUTATION_MAPPING_DB_PATH="/path/to/erep/mapping/db" VITE_EREPUTATION_BASE_URL=http://localhost:8765 LOAD_TEST_USER_COUNT=6 + +PUBLIC_EID_WALLET_TOKEN=obtained-from-post-registry-service-/platforms/certification diff --git a/db/init-multiple-databases.sh b/db/init-multiple-databases.sh new file mode 100755 index 00000000..299ad717 --- /dev/null +++ b/db/init-multiple-databases.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e + +# Get the list of databases from environment variable +# Default to empty if not set +POSTGRES_MULTIPLE_DATABASES=${POSTGRES_MULTIPLE_DATABASES:-} + +# If no databases specified, exit +if [ -z "$POSTGRES_MULTIPLE_DATABASES" ]; then + echo "No databases specified in POSTGRES_MULTIPLE_DATABASES" + exit 0 +fi + +echo "Creating multiple databases..." + +# Split the comma-separated list and create each database +IFS=',' read -ra DATABASES <<< "$POSTGRES_MULTIPLE_DATABASES" +for db in "${DATABASES[@]}"; do + # Trim whitespace + db=$(echo "$db" | xargs) + + if [ -n "$db" ]; then + # Check if database exists + DB_EXISTS=$(psql -v ON_ERROR_STOP=0 --username "$POSTGRES_USER" --dbname postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$db'" 2>/dev/null || echo "") + + if [ "$DB_EXISTS" = "1" ]; then + echo "Database $db already exists, skipping..." + else + echo "Creating database: $db" + # Create the database directly (not inside a function) + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname postgres <<-EOSQL + CREATE DATABASE "$db"; +EOSQL + fi + fi +done + +echo "Multiple databases created successfully!" + diff --git a/dev-docker-compose.yaml b/dev-docker-compose.yaml index f17b6dbc..ec998f71 100644 --- a/dev-docker-compose.yaml +++ b/dev-docker-compose.yaml @@ -126,6 +126,19 @@ services: networks: - metastate-network <<: *common-host-access + entrypoint: ["/bin/sh", "-c"] + command: + - | + # Remove any stale PID files before starting Neo4j + # Neo4j stores PID files in /var/lib/neo4j/run/neo4j.pid + rm -f /var/lib/neo4j/run/neo4j.pid 2>/dev/null || true + rm -f /var/lib/neo4j/data/run/neo4j.pid 2>/dev/null || true + rm -f /var/lib/neo4j/data/neo4j.pid 2>/dev/null || true + # Also clean up any other PID files + find /var/lib/neo4j -name "*.pid" -type f -delete 2>/dev/null || true + find /var/lib/neo4j/data -name "*.pid" -type f -delete 2>/dev/null || true + # Start Neo4j with the original entrypoint + exec /startup/docker-entrypoint.sh neo4j healthcheck: test: [ "CMD-SHELL", "cypher-shell -u neo4j -p ${NEO4J_PASSWORD:-neo4j} 'RETURN 1' || exit 1" ] interval: 10s diff --git a/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/Project.xml b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..7643783a --- /dev/null +++ b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/Project.xml @@ -0,0 +1,123 @@ + + + + + + + + + + \ No newline at end of file diff --git a/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/codeStyleConfig.xml b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/infrastructure/eid-wallet/src-tauri/gen/android/.idea/kotlinc.xml b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/kotlinc.xml index 4cb74572..fe63bb67 100644 --- a/infrastructure/eid-wallet/src-tauri/gen/android/.idea/kotlinc.xml +++ b/infrastructure/eid-wallet/src-tauri/gen/android/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/infrastructure/eid-wallet/src/lib/global/controllers/evault.ts b/infrastructure/eid-wallet/src/lib/global/controllers/evault.ts index 917f6ab4..349f9618 100644 --- a/infrastructure/eid-wallet/src/lib/global/controllers/evault.ts +++ b/infrastructure/eid-wallet/src/lib/global/controllers/evault.ts @@ -1,14 +1,14 @@ import { - PUBLIC_REGISTRY_URL, - PUBLIC_PROVISIONER_URL, PUBLIC_EID_WALLET_TOKEN, + PUBLIC_PROVISIONER_URL, + PUBLIC_REGISTRY_URL, } from "$env/static/public"; import type { Store } from "@tauri-apps/plugin-store"; import axios from "axios"; import { GraphQLClient } from "graphql-request"; import NotificationService from "../../services/NotificationService"; -import type { UserController } from "./user"; import type { KeyService } from "./key"; +import type { UserController } from "./user"; const STORE_META_ENVELOPE = ` mutation StoreMetaEnvelope($input: MetaEnvelopeInput!) { @@ -176,7 +176,7 @@ export class VaultController { }; if (authToken) { - headers["Authorization"] = `Bearer ${authToken}`; + headers.Authorization = `Bearer ${authToken}`; } await axios.patch(patchUrl, { publicKey }, { headers }); diff --git a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte index 5027dc51..6628964f 100644 --- a/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte @@ -198,6 +198,7 @@ onMount(async () => { new URL("/entropy", PUBLIC_REGISTRY_URL).toString(), ); const registryEntropy = entropyRes.data.token; + console.log("Registry entropy:", registryEntropy); const provisionRes = await axios.post( new URL("/provision", PUBLIC_PROVISIONER_URL).toString(), @@ -208,6 +209,7 @@ onMount(async () => { publicKey: await getApplicationPublicKey(), }, ); + console.log("Provision response:", provisionRes.data); if (!provisionRes.data?.success) { throw new Error("Invalid verification code"); diff --git a/infrastructure/evault-core/src/core/http/server.ts b/infrastructure/evault-core/src/core/http/server.ts index 898901de..c4cacb63 100644 --- a/infrastructure/evault-core/src/core/http/server.ts +++ b/infrastructure/evault-core/src/core/http/server.ts @@ -1,116 +1,125 @@ -import fastify, { FastifyInstance } from "fastify"; import swagger from "@fastify/swagger"; import swaggerUi from "@fastify/swagger-ui"; -import { WatcherRequest, TypedRequest, TypedReply } from "./types"; -import { ProvisioningService, ProvisionRequest } from "../../services/ProvisioningService"; -import { DbService } from "../db/db.service"; -import * as jose from "jose"; import axios from "axios"; +import fastify, { type FastifyInstance } from "fastify"; +import * as jose from "jose"; +import type { + ProvisionRequest, + ProvisioningService, +} from "../../services/ProvisioningService"; +import type { DbService } from "../db/db.service"; +import { type TypedReply, type TypedRequest, WatcherRequest } from "./types"; interface WatcherSignatureRequest { - w3id: string; - logEntryId: string; - proof: { - signature: string; - alg: string; - kid: string; - }; + w3id: string; + logEntryId: string; + proof: { + signature: string; + alg: string; + kid: string; + }; } export async function registerHttpRoutes( - server: FastifyInstance, - evault: any, // EVault instance to access publicKey - provisioningService?: ProvisioningService, - dbService?: DbService + server: FastifyInstance, + evault: any, // EVault instance to access publicKey + provisioningService?: ProvisioningService, + dbService?: DbService, ): Promise { - // Register Swagger - await server.register(swagger, { - swagger: { - info: { - title: "eVault Core API", - description: "API documentation for eVault Core HTTP endpoints", - version: "1.0.0", - }, - tags: [ - { name: "identity", description: "Identity related endpoints" }, - { - name: "watchers", - description: "Watcher signature related endpoints", - }, - { - name: "provisioning", - description: "eVault provisioning endpoints", + // Register Swagger + await server.register(swagger, { + swagger: { + info: { + title: "eVault Core API", + description: "API documentation for eVault Core HTTP endpoints", + version: "1.0.0", + }, + tags: [ + { name: "identity", description: "Identity related endpoints" }, + { + name: "watchers", + description: "Watcher signature related endpoints", + }, + { + name: "provisioning", + description: "eVault provisioning endpoints", + }, + ], }, - ], - }, - }); + }); - await server.register(swaggerUi, { - routePrefix: "/docs", - }); + await server.register(swaggerUi, { + routePrefix: "/docs", + }); - // Whois endpoint - returns both W3ID identifier and public key - server.get( - "/whois", - { - schema: { - tags: ["identity"], - description: "Get eVault W3ID identifier and public key", - headers: { - type: "object", - required: ["X-ENAME"], - properties: { - "X-ENAME": { type: "string" }, - }, - }, - response: { - 200: { - type: "object", - properties: { - w3id: { type: "string" }, - publicKey: { type: "string", nullable: true }, - }, - }, - 400: { - type: "object", - properties: { - error: { type: "string" }, + // Whois endpoint - returns both W3ID identifier and public key + server.get( + "/whois", + { + schema: { + tags: ["identity"], + description: "Get eVault W3ID identifier and public key", + headers: { + type: "object", + required: ["X-ENAME"], + properties: { + "X-ENAME": { type: "string" }, + }, + }, + response: { + 200: { + type: "object", + properties: { + w3id: { type: "string" }, + publicKey: { type: "string", nullable: true }, + }, + }, + 400: { + type: "object", + properties: { + error: { type: "string" }, + }, + }, + }, }, - }, }, - }, - }, - async (request: TypedRequest<{}>, reply: TypedReply) => { - const eName = request.headers["x-ename"] || request.headers["X-ENAME"]; - - if (!eName || typeof eName !== "string") { - return reply.status(400).send({ error: "X-ENAME header is required" }); - } - - // Get public key from database if dbService is available - let publicKey: string | null = null; - if (dbService) { - try { - publicKey = await dbService.getPublicKey(eName); - } catch (error) { - console.error("Error getting public key from database:", error); - // Continue with null publicKey - } - } - - const result = { - w3id: eName, - publicKey: publicKey, - }; - console.log("Whois request:", result); - return result; - } - ); + async (request: TypedRequest<{}>, reply: TypedReply) => { + const eName = + request.headers["x-ename"] || request.headers["X-ENAME"]; + + if (!eName || typeof eName !== "string") { + return reply + .status(400) + .send({ error: "X-ENAME header is required" }); + } + + // Get public key from database if dbService is available + let publicKey: string | null = null; + if (dbService) { + try { + publicKey = await dbService.getPublicKey(eName); + } catch (error) { + console.error( + "Error getting public key from database:", + error, + ); + // Continue with null publicKey + } + } + + const result = { + w3id: eName, + publicKey: publicKey, + }; + console.log("Whois request:", result); + return result; + }, + ); - // Watchers signature endpoint - DISABLED: Requires W3ID functionality - // This endpoint is disabled because the eVault no longer creates/manages W3IDs - // The private key is now stored on the user's phone - /* + // Watchers signature endpoint - DISABLED: Requires W3ID functionality + // This endpoint is disabled because the eVault no longer creates/manages W3IDs + // The private key is now stored on the user's phone + /* server.post<{ Body: WatcherSignatureRequest }>( "/watchers/sign", { @@ -199,10 +208,10 @@ export async function registerHttpRoutes( ); */ - // Watchers request endpoint - DISABLED: Requires W3ID functionality - // This endpoint is disabled because the eVault no longer creates/manages W3IDs - // The private key is now stored on the user's phone - /* + // Watchers request endpoint - DISABLED: Requires W3ID functionality + // This endpoint is disabled because the eVault no longer creates/manages W3IDs + // The private key is now stored on the user's phone + /* server.post<{ Body: WatcherRequest }>( "/watchers/request", { @@ -283,181 +292,228 @@ export async function registerHttpRoutes( ); */ - // Helper function to validate JWT token - async function validateToken(authHeader: string | null): Promise { - if (!authHeader || !authHeader.startsWith("Bearer ")) { - console.error("Token validation: Missing or invalid Authorization header format"); - return null; - } - - const token = authHeader.substring(7); // Remove 'Bearer ' prefix + // Helper function to validate JWT token + async function validateToken( + authHeader: string | null, + ): Promise { + if (!authHeader || !authHeader.startsWith("Bearer ")) { + console.error( + "Token validation: Missing or invalid Authorization header format", + ); + return null; + } - try { - // Try REGISTRY_URL first, fallback to PUBLIC_REGISTRY_URL - const registryUrl = process.env.REGISTRY_URL || process.env.PUBLIC_REGISTRY_URL; - if (!registryUrl) { - console.error("Token validation: REGISTRY_URL or PUBLIC_REGISTRY_URL is not set"); - return null; - } + const token = authHeader.substring(7); // Remove 'Bearer ' prefix - const jwksUrl = new URL(`/.well-known/jwks.json`, registryUrl).toString(); - console.log(`Token validation: Fetching JWKS from ${jwksUrl}`); - - const jwksResponse = await axios.get(jwksUrl, { - timeout: 5000, - }); - - console.log(`Token validation: JWKS response keys count: ${jwksResponse.data?.keys?.length || 0}`); - - const JWKS = jose.createLocalJWKSet(jwksResponse.data); - - // Decode token header to see what kid it's using - const decodedHeader = jose.decodeProtectedHeader(token); - console.log(`Token validation: Token header - alg: ${decodedHeader.alg}, kid: ${decodedHeader.kid}`); - - const { payload } = await jose.jwtVerify(token, JWKS); - - console.log(`Token validation: Token verified successfully, payload:`, payload); - return payload; - } catch (error: any) { - console.error("Token validation failed:", error.message || error); - if (error.code) { - console.error(`Token validation error code: ${error.code}`); - } - if (error.response) { - console.error(`Token validation HTTP error: ${error.response.status} - ${error.response.statusText}`); - } - if (error.cause) { - console.error(`Token validation error cause:`, error.cause); - } - return null; + try { + // Try REGISTRY_URL first, fallback to PUBLIC_REGISTRY_URL + const registryUrl = + process.env.REGISTRY_URL || process.env.PUBLIC_REGISTRY_URL; + if (!registryUrl) { + console.error( + "Token validation: REGISTRY_URL or PUBLIC_REGISTRY_URL is not set", + ); + return null; + } + + const jwksUrl = new URL( + "/.well-known/jwks.json", + registryUrl, + ).toString(); + console.log(`Token validation: Fetching JWKS from ${jwksUrl}`); + + const jwksResponse = await axios.get(jwksUrl, { + timeout: 5000, + }); + + console.log( + `Token validation: JWKS response keys count: ${jwksResponse.data?.keys?.length || 0}`, + ); + + const JWKS = jose.createLocalJWKSet(jwksResponse.data); + + // Decode token header to see what kid it's using + const decodedHeader = jose.decodeProtectedHeader(token); + console.log( + `Token validation: Token header - alg: ${decodedHeader.alg}, kid: ${decodedHeader.kid}`, + ); + + const { payload } = await jose.jwtVerify(token, JWKS); + + console.log( + `Token validation: Token verified successfully, payload:`, + payload, + ); + return payload; + } catch (error: any) { + console.error("Token validation failed:", error.message || error); + if (error.code) { + console.error(`Token validation error code: ${error.code}`); + } + if (error.response) { + console.error( + `Token validation HTTP error: ${error.response.status} - ${error.response.statusText}`, + ); + } + if (error.cause) { + console.error(`Token validation error cause:`, error.cause); + } + return null; + } } - } - // PATCH endpoint to save public key - server.patch<{ Body: { publicKey: string } }>( - "/public-key", - { - schema: { - tags: ["identity"], - description: "Save public key for a user's eName", - headers: { - type: "object", - required: ["X-ENAME", "Authorization"], - properties: { - "X-ENAME": { type: "string" }, - "Authorization": { type: "string" }, - }, - }, - body: { - type: "object", - required: ["publicKey"], - properties: { - publicKey: { type: "string" }, - }, - }, - response: { - 200: { - type: "object", - properties: { - success: { type: "boolean" }, - message: { type: "string" }, - }, - }, - 400: { - type: "object", - properties: { - error: { type: "string" }, - }, - }, - 401: { - type: "object", - properties: { - error: { type: "string" }, + // PATCH endpoint to save public key + server.patch<{ Body: { publicKey: string } }>( + "/public-key", + { + schema: { + tags: ["identity"], + description: "Save public key for a user's eName", + headers: { + type: "object", + required: ["X-ENAME", "Authorization"], + properties: { + "X-ENAME": { type: "string" }, + Authorization: { type: "string" }, + }, + }, + body: { + type: "object", + required: ["publicKey"], + properties: { + publicKey: { type: "string" }, + }, + }, + response: { + 200: { + type: "object", + properties: { + success: { type: "boolean" }, + message: { type: "string" }, + }, + }, + 400: { + type: "object", + properties: { + error: { type: "string" }, + }, + }, + 401: { + type: "object", + properties: { + error: { type: "string" }, + }, + }, + }, }, - }, }, - }, - }, - async (request: TypedRequest<{ publicKey: string }>, reply: TypedReply) => { - const eName = request.headers["x-ename"] || request.headers["X-ENAME"]; - - if (!eName || typeof eName !== "string") { - return reply.status(400).send({ error: "X-ENAME header is required" }); - } - - const authHeader = request.headers.authorization || request.headers["Authorization"]; - const tokenPayload = await validateToken( - typeof authHeader === "string" ? authHeader : null - ); - - if (!tokenPayload) { - return reply.status(401).send({ error: "Invalid or missing authentication token" }); - } - - const { publicKey } = request.body; - if (!publicKey) { - return reply.status(400).send({ error: "publicKey is required in request body" }); - } - - if (!dbService) { - return reply.status(500).send({ error: "Database service not available" }); - } - - try { - await dbService.setPublicKey(eName, publicKey); - return { - success: true, - message: "Public key saved successfully", - }; - } catch (error) { - console.error("Error saving public key:", error); - return reply.status(500).send({ - error: error instanceof Error ? error.message : "Failed to save public key", - }); - } - } - ); + async ( + request: TypedRequest<{ publicKey: string }>, + reply: TypedReply, + ) => { + const eName = + request.headers["x-ename"] || request.headers["X-ENAME"]; + + if (!eName || typeof eName !== "string") { + return reply + .status(400) + .send({ error: "X-ENAME header is required" }); + } + + const authHeader = + request.headers.authorization || + request.headers["Authorization"]; + const tokenPayload = await validateToken( + typeof authHeader === "string" ? authHeader : null, + ); + + if (!tokenPayload) { + return reply + .status(401) + .send({ error: "Invalid or missing authentication token" }); + } + + const { publicKey } = request.body; + if (!publicKey) { + return reply + .status(400) + .send({ error: "publicKey is required in request body" }); + } + + if (!dbService) { + return reply + .status(500) + .send({ error: "Database service not available" }); + } + + try { + await dbService.setPublicKey(eName, publicKey); + return { + success: true, + message: "Public key saved successfully", + }; + } catch (error) { + console.error("Error saving public key:", error); + return reply.status(500).send({ + error: + error instanceof Error + ? error.message + : "Failed to save public key", + }); + } + }, + ); - // Provision eVault endpoint - if (provisioningService) { - server.post<{ Body: ProvisionRequest }>( - "/provision", - { - schema: { - tags: ["provisioning"], - description: "Provision a new eVault instance (logical only, no infrastructure)", - body: { - type: "object", - required: ["registryEntropy", "namespace", "verificationId", "publicKey"], - properties: { - registryEntropy: { type: "string" }, - namespace: { type: "string" }, - verificationId: { type: "string" }, - publicKey: { type: "string" }, + // Provision eVault endpoint + if (provisioningService) { + server.post<{ Body: ProvisionRequest }>( + "/provision", + { + schema: { + tags: ["provisioning"], + description: + "Provision a new eVault instance (logical only, no infrastructure)", + body: { + type: "object", + required: [ + "registryEntropy", + "namespace", + "verificationId", + "publicKey", + ], + properties: { + registryEntropy: { type: "string" }, + namespace: { type: "string" }, + verificationId: { type: "string" }, + publicKey: { type: "string" }, + }, + }, + response: { + 200: { + type: "object", + properties: { + success: { type: "boolean" }, + w3id: { type: "string" }, + uri: { type: "string" }, + message: { type: "string" }, + error: { type: "string" }, + }, + }, + }, + }, }, - }, - response: { - 200: { - type: "object", - properties: { - success: { type: "boolean" }, - w3id: { type: "string" }, - uri: { type: "string" }, - message: { type: "string" }, - error: { type: "string" }, - }, + async ( + request: TypedRequest, + reply: TypedReply, + ) => { + const result = await provisioningService.provisionEVault( + request.body, + ); + if (!result.success) { + return reply.status(500).send(result); + } + return result; }, - }, - }, - }, - async (request: TypedRequest, reply: TypedReply) => { - const result = await provisioningService.provisionEVault(request.body); - if (!result.success) { - return reply.status(500).send(result); - } - return result; - } - ); - } + ); + } } diff --git a/platforms/registry/src/index.ts b/platforms/registry/src/index.ts index 0bf76ede..04eb6c03 100644 --- a/platforms/registry/src/index.ts +++ b/platforms/registry/src/index.ts @@ -1,19 +1,22 @@ -import fastify from "fastify"; -import { generateEntropy, generatePlatformToken, getJWK } from "./jwt"; -import dotenv from "dotenv"; import path from "node:path"; +import cors from "@fastify/cors"; +import dotenv from "dotenv"; +import fastify from "fastify"; import { AppDataSource } from "./config/database"; -import { VaultService } from "./services/VaultService"; +import { generateEntropy, generatePlatformToken, getJWK } from "./jwt"; import { UriResolutionService } from "./services/UriResolutionService"; -import cors from "@fastify/cors"; +import { VaultService } from "./services/VaultService"; import fs from "node:fs"; function loadMotdJSON() { - const motdJSON = fs.readFileSync(path.resolve(__dirname, "../motd.json"), "utf8"); + const motdJSON = fs.readFileSync( + path.resolve(__dirname, "../motd.json"), + "utf8", + ); return JSON.parse(motdJSON) as { - status: "up" | "maintenance" - message: string + status: "up" | "maintenance"; + message: string; }; } @@ -41,7 +44,10 @@ const initializeDatabase = async () => { await AppDataSource.initialize(); server.log.info("Database connection initialized"); } catch (error) { - server.log.error({message: "Error during database initialization", detail: error}); + server.log.error({ + message: "Error during database initialization", + detail: error, + }); process.exit(1); } }; @@ -102,6 +108,7 @@ server.post( // Generate and return a signed JWT with entropy server.get("/entropy", async (request, reply) => { + console.log("Generating entropy"); try { const token = await generateEntropy(); return { token }; @@ -123,21 +130,19 @@ server.post("/platforms/certification", async (request, reply) => { }); server.get("/platforms", async (request, reply) => { - const platforms = [ - process.env.PUBLIC_PICTIQUE_BASE_URL, - process.env.PUBLIC_BLABSY_BASE_URL, - process.env.PUBLIC_GROUP_CHARTER_BASE_URL, - process.env.PUBLIC_CERBERUS_BASE_URL, + const platforms = [ + process.env.PUBLIC_PICTIQUE_BASE_URL, + process.env.PUBLIC_BLABSY_BASE_URL, + process.env.PUBLIC_GROUP_CHARTER_BASE_URL, + process.env.PUBLIC_CERBERUS_BASE_URL, process.env.PUBLIC_EVOTING_BASE_URL, process.env.VITE_DREAMSYNC_BASE_URL, - process.env.VITE_EREPUTATION_BASE_URL - ] + process.env.VITE_EREPUTATION_BASE_URL, + ]; - return platforms + return platforms; }); - - // Expose the JWK used for signing server.get("/.well-known/jwks.json", async (request, reply) => { try { @@ -184,11 +189,13 @@ server.get("/resolve", async (request, reply) => { server.get("/list", async (request, reply) => { try { const vaults = await vaultService.findAll(); - + // Resolve URIs for all vaults const resolvedVaults = await Promise.all( vaults.map(async (vault) => { - const resolvedUri = await uriResolutionService.resolveUri(vault.uri); + const resolvedUri = await uriResolutionService.resolveUri( + vault.uri, + ); return { ename: vault.ename, uri: resolvedUri, @@ -196,9 +203,9 @@ server.get("/list", async (request, reply) => { originalUri: vault.uri, resolved: resolvedUri !== vault.uri, }; - }) + }), ); - + return resolvedVaults; } catch (error) { server.log.error(error); diff --git a/platforms/registry/src/services/HealthCheckService.ts b/platforms/registry/src/services/HealthCheckService.ts index 55e36631..0a0cdb2c 100644 --- a/platforms/registry/src/services/HealthCheckService.ts +++ b/platforms/registry/src/services/HealthCheckService.ts @@ -1,4 +1,4 @@ -import axios from 'axios'; +import axios from "axios"; export class HealthCheckService { private readonly timeout = 5000; // 5 second timeout @@ -10,7 +10,7 @@ export class HealthCheckService { try { // Parse the URI to extract IP:PORT const { ip, port } = this.parseUri(uri); - + if (!ip || !port) { console.log(`Invalid URI format: ${uri}`); return false; @@ -18,20 +18,22 @@ export class HealthCheckService { // Construct the whois endpoint URL const whoisUrl = `http://${ip}:${port}/whois`; - + console.log(`Health checking: ${whoisUrl}`); - + // Make a request to the whois endpoint with timeout const response = await axios.get(whoisUrl, { timeout: this.timeout, - validateStatus: (status) => status < 500 // Accept any status < 500 as "reachable" + validateStatus: (status) => status < 500, // Accept any status < 500 as "reachable" }); - + console.log(`Health check passed for ${uri}: ${response.status}`); return true; - } catch (error) { - console.log(`Health check failed for ${uri}:`, error instanceof Error ? error.message : 'Unknown error'); + console.log( + `Health check failed for ${uri}:`, + error instanceof Error ? error.message : "Unknown error", + ); return false; } } @@ -43,21 +45,21 @@ export class HealthCheckService { private parseUri(uri: string): { ip: string | null; port: string | null } { try { // Remove protocol if present - const cleanUri = uri.replace(/^https?:\/\//, ''); - + const cleanUri = uri.replace(/^https?:\/\//, ""); + // Split by colon to get IP and PORT - const parts = cleanUri.split(':'); - + const parts = cleanUri.split(":"); + if (parts.length === 2) { const ip = parts[0]; const port = parts[1]; - + // Basic validation if (this.isValidIp(ip) && this.isValidPort(port)) { return { ip, port }; } } - + return { ip: null, port: null }; } catch (error) { console.error(`Error parsing URI ${uri}:`, error); @@ -70,7 +72,8 @@ export class HealthCheckService { */ private isValidIp(ip: string): boolean { // Simple regex for IP validation - const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + const ipRegex = + /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; return ipRegex.test(ip); } @@ -78,7 +81,7 @@ export class HealthCheckService { * Basic port validation */ private isValidPort(port: string): boolean { - const portNum = parseInt(port, 10); + const portNum = Number.parseInt(port, 10); return portNum >= 1 && portNum <= 65535; } -} \ No newline at end of file +} diff --git a/platforms/registry/src/services/VaultService.ts b/platforms/registry/src/services/VaultService.ts index 899f6fcc..36886de1 100644 --- a/platforms/registry/src/services/VaultService.ts +++ b/platforms/registry/src/services/VaultService.ts @@ -1,32 +1,32 @@ -import { Repository } from "typeorm" -import { Vault} from "../entities/Vault" +import type { Repository } from "typeorm"; +import type { Vault } from "../entities/Vault"; export class VaultService { constructor(private readonly serviceRepository: Repository) {} async create(ename: string, uri: string, evault: string): Promise { - const service = this.serviceRepository.create({ ename, uri, evault }) - return await this.serviceRepository.save(service) + const service = this.serviceRepository.create({ ename, uri, evault }); + return await this.serviceRepository.save(service); } async findAll(): Promise { - return await this.serviceRepository.find() + return await this.serviceRepository.find(); } - async findOne(id: number): Promise { - return await this.serviceRepository.findOneBy({ id }) + async findOne(id: number): Promise { + return await this.serviceRepository.findOneBy({ id }); } async findByEname(ename: string): Promise { - return await this.serviceRepository.findOneBy({ ename }) + return await this.serviceRepository.findOneBy({ ename }); } - async update(id: number, data: Partial): Promise { - await this.serviceRepository.update(id, data) - return await this.findOne(id) + async update(id: number, data: Partial): Promise { + await this.serviceRepository.update(id, data); + return await this.findOne(id); } async delete(id: number): Promise { - await this.serviceRepository.delete(id) + await this.serviceRepository.delete(id); } -} \ No newline at end of file +} diff --git a/scripts/get-eid-wallet-token.sh b/scripts/get-eid-wallet-token.sh new file mode 100755 index 00000000..6f2f845b --- /dev/null +++ b/scripts/get-eid-wallet-token.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Get the registry URL from environment or use default +REGISTRY_URL="${PUBLIC_REGISTRY_URL:-http://localhost:4321}" + +# Request platform token for eid-wallet +echo "Requesting platform token from registry at $REGISTRY_URL..." +echo "" + +RESPONSE=$(curl -s -X POST "$REGISTRY_URL/platforms/certification" \ + -H "Content-Type: application/json" \ + -d '{"platform": "eid-wallet"}') + +# Check if curl was successful +if [ $? -ne 0 ]; then + echo "Error: Failed to connect to registry at $REGISTRY_URL" + exit 1 +fi + +# Extract token using jq if available, otherwise use grep/sed +if command -v jq &> /dev/null; then + TOKEN=$(echo "$RESPONSE" | jq -r '.token') + if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then + echo "Error: Failed to get token from response:" + echo "$RESPONSE" + exit 1 + fi +else + # Fallback: extract token manually + TOKEN=$(echo "$RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4) + if [ -z "$TOKEN" ]; then + echo "Error: Failed to parse token from response:" + echo "$RESPONSE" + exit 1 + fi +fi + +echo "Token obtained successfully!" +echo "" +echo "Add this to your .env file:" +echo "PUBLIC_EID_WALLET_TOKEN=\"$TOKEN\"" +echo "" +echo "Or use it directly:" +echo "$TOKEN" + + +