+
{@render children?.()}
{/if}
-
+
diff --git a/infrastructure/eid-wallet/static/images/CameraCircle.svg b/infrastructure/eid-wallet/static/images/CameraCircle.svg
new file mode 100644
index 00000000..fe2ba93a
--- /dev/null
+++ b/infrastructure/eid-wallet/static/images/CameraCircle.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/infrastructure/eid-wallet/static/images/CameraFrame.svg b/infrastructure/eid-wallet/static/images/CameraFrame.svg
new file mode 100644
index 00000000..24451d32
--- /dev/null
+++ b/infrastructure/eid-wallet/static/images/CameraFrame.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/infrastructure/eid-wallet/svelte.config.js b/infrastructure/eid-wallet/svelte.config.js
index 1b6a6b8d..9e995d0f 100644
--- a/infrastructure/eid-wallet/svelte.config.js
+++ b/infrastructure/eid-wallet/svelte.config.js
@@ -6,10 +6,13 @@ import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
const config = {
- preprocess: vitePreprocess(),
- kit: {
- adapter: adapter(),
- },
+ preprocess: vitePreprocess(),
+ kit: {
+ adapter: adapter(),
+ env: {
+ dir: "../../",
+ },
+ },
};
export default config;
diff --git a/infrastructure/evault-provisioner/package.json b/infrastructure/evault-provisioner/package.json
index 5c560787..ffe10dd9 100644
--- a/infrastructure/evault-provisioner/package.json
+++ b/infrastructure/evault-provisioner/package.json
@@ -3,26 +3,36 @@
"version": "1.0.0",
"description": "API for provisioning evault instances on Nomad",
"main": "dist/index.js",
- "type": "module",
"scripts": {
"start": "node dist/index.js",
- "dev": "tsx watch src/index.ts",
+ "dev": "ts-node-dev --respawn --transpile-only src/index.ts",
"build": "tsc",
- "test": "vitest"
+ "test": "vitest",
+ "typeorm": "typeorm-ts-node-commonjs",
+ "migration:generate": "npm run typeorm migration:generate -- -d src/config/database.ts",
+ "migration:run": "npm run typeorm migration:run -- -d src/config/database.ts",
+ "migration:revert": "npm run typeorm migration:revert -- -d src/config/database.ts"
},
"dependencies": {
"@kubernetes/client-node": "^1.3.0",
"axios": "^1.6.7",
+ "cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.18.2",
"jose": "^5.2.2",
+ "pg": "^8.11.3",
+ "reflect-metadata": "^0.2.1",
"sha256": "^0.2.0",
+ "typeorm": "^0.3.24",
"w3id": "workspace:*"
},
"devDependencies": {
+ "@types/cors": "^2.8.18",
"@types/express": "^4.17.21",
"@types/node": "^20.11.24",
+ "@types/sha256": "^0.2.2",
"nodemon": "^3.0.3",
+ "ts-node-dev": "^2.0.0",
"tsx": "^4.7.1",
"typescript": "^5.3.3",
"vitest": "^1.3.1"
diff --git a/infrastructure/evault-provisioner/src/config/database.ts b/infrastructure/evault-provisioner/src/config/database.ts
new file mode 100644
index 00000000..2ae7b03c
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/config/database.ts
@@ -0,0 +1,17 @@
+import { DataSource } from "typeorm"
+import { Verification } from "../entities/Verification"
+import * as dotenv from "dotenv"
+import { join } from "path"
+
+// Load environment variables from root .env file
+dotenv.config({ path: join(__dirname, "../../../../.env") })
+
+export const AppDataSource = new DataSource({
+ type: "postgres",
+ url: process.env.PROVISIONER_DATABASE_URL || "postgresql://postgres:postgres@localhost:5432/evault",
+ logging: process.env.NODE_ENV !== "production",
+ entities: [Verification],
+ migrations: [join(__dirname, "../migrations/*.{ts,js}")],
+ migrationsTableName: "migrations",
+ subscribers: [],
+})
\ No newline at end of file
diff --git a/infrastructure/evault-provisioner/src/controllers/VerificationController.ts b/infrastructure/evault-provisioner/src/controllers/VerificationController.ts
new file mode 100644
index 00000000..c31adf0d
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/controllers/VerificationController.ts
@@ -0,0 +1,255 @@
+import { Request, Response } from "express";
+import { VerificationService } from "../services/VerificationService";
+import { eventEmitter } from "../utils/eventEmitter";
+import { createHmacSignature } from "../utils/hmac";
+import { default as Axios } from "axios";
+
+const veriffClient = Axios.create({
+ baseURL: "https://stationapi.veriff.com",
+ withCredentials: true,
+});
+
+veriffClient.interceptors.response.use(
+ (response) => {
+ return response;
+ },
+ async function (error) {
+ if (!error.response) return Promise.reject(error);
+ return Promise.reject(error);
+ },
+);
+
+export class VerificationController {
+ constructor(private readonly verificationService: VerificationService) {}
+
+ registerRoutes(app: any) {
+ // SSE endpoint for verification status updates
+
+ app.get(
+ "/verification/sessions/:id",
+ async (req: Request, res: Response) => {
+ const { id } = req.params;
+
+ // Set headers for SSE
+ res.writeHead(200, {
+ "Content-Type": "text/event-stream",
+ "Cache-Control": "no-cache",
+ Connection: "keep-alive",
+ "Access-Control-Allow-Origin": "*",
+ });
+
+ // Initial heartbeat to keep connection open
+ res.write(
+ `event: connected\ndata: ${JSON.stringify({ hi: "hi" })}\n\n`,
+ );
+
+ const handler = (data: any) => {
+ console.log("hi?");
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
+ };
+
+ eventEmitter.on(id, handler);
+
+ // Handle client disconnect
+ req.on("close", () => {
+ eventEmitter.off(id, handler);
+ res.end();
+ });
+
+ req.on("error", (error) => {
+ console.error("SSE Error:", error);
+ eventEmitter.off(id, handler);
+ res.end();
+ });
+ },
+ );
+
+ app.post(
+ "/verification/:id/media",
+ async (req: Request, res: Response) => {
+ const { img, type } = req.body;
+ const types = ["document-front", "document-back", "face"];
+ if (!types.includes(type))
+ throw new Error(
+ `Wrong type specified, accepted types are ${types}`,
+ );
+ const verification = await this.verificationService.findById(
+ req.params.id,
+ );
+ if (!verification) throw new Error("Verification not found");
+ const veriffBody = {
+ image: {
+ context: type,
+ content: img,
+ },
+ };
+
+ const signature = createHmacSignature(
+ veriffBody,
+ process.env.VERIFF_HMAC_KEY as string,
+ );
+ await veriffClient.post(
+ `/v1/sessions/${verification.veriffId}/media`,
+ veriffBody,
+ {
+ headers: {
+ "X-HMAC-SIGNATURE": signature,
+ "X-AUTH-CLIENT": process.env.PUBLIC_VERIFF_KEY,
+ },
+ },
+ );
+ res.sendStatus(201);
+ },
+ );
+
+ // Get verification session
+ app.get("/verification/:id", async (req: Request, res: Response) => {
+ const { id } = req.params;
+ const session = await this.verificationService.findById(id);
+ if (!session) {
+ return res
+ .status(404)
+ .json({ error: "Verification session not found" });
+ }
+ return res.json(session);
+ });
+
+ // Create new verification
+ app.post("/verification", async (req: Request, res: Response) => {
+ const { referenceId } = req.body;
+
+ if (referenceId) {
+ const existing = await this.verificationService.findOne({
+ referenceId,
+ });
+ if (existing) {
+ return res
+ .status(409)
+ .json({ error: "Reference ID Already Exists" });
+ }
+ }
+
+ const verification = await this.verificationService.create({
+ referenceId,
+ });
+ const veriffBody = {
+ verification: {
+ vendorData: verification.id,
+ },
+ };
+ const signature = createHmacSignature(
+ veriffBody,
+ process.env.VERIFF_HMAC_KEY as string,
+ );
+ const { data: veriffSession } = await veriffClient.post(
+ "/v1/sessions",
+ veriffBody,
+ {
+ headers: {
+ "X-HMAC-SIGNATURE": signature,
+ "X-AUTH-CLIENT": process.env.PUBLIC_VERIFF_KEY,
+ },
+ },
+ );
+ await this.verificationService.findByIdAndUpdate(verification.id, {
+ veriffId: veriffSession.verification.id,
+ });
+
+ return res.status(201).json(verification);
+ });
+
+ app.patch("/verification/:id", async (req: Request, res: Response) => {
+ const verification = await this.verificationService.findById(
+ req.params.id,
+ );
+ const body = {
+ verification: {
+ status: "submitted",
+ },
+ };
+ const signature = createHmacSignature(
+ body,
+ process.env.VERIFF_HMAC_KEY as string,
+ );
+ await veriffClient.patch(
+ `/v1/sessions/${verification?.veriffId}`,
+ body,
+ {
+ headers: {
+ "X-HMAC-SIGNATURE": signature,
+ "X-AUTH-CLIENT": process.env.PUBLIC_VERIFF_KEY,
+ },
+ },
+ );
+ res.sendStatus(201);
+ });
+
+ // Webhook for verification decisions
+ app.post(
+ "/verification/decisions",
+ async (req: Request, res: Response) => {
+ const body = req.body;
+ console.log(body);
+ const id = body.vendorData;
+
+ const verification =
+ await this.verificationService.findById(id);
+ if (!verification) {
+ return res
+ .status(404)
+ .json({ error: "Verification not found" });
+ }
+
+ let status = body.data.verification.decision;
+ let reason = body.data.verification.decision;
+
+ const affirmativeStatusTypes = [
+ "approved",
+ "declined",
+ "expired",
+ "abandoned",
+ ];
+ if (
+ affirmativeStatusTypes.includes(
+ body.data.verification.decision,
+ )
+ ) {
+ let approved =
+ body.data.verification.decision === "approved";
+ if (process.env.DUPLICATES_POLICY !== "allow") {
+ const verificationMatch =
+ await this.verificationService.findOne({
+ documentId:
+ body.data.verification.document.number.value
+ });
+ console.log("matched", verificationMatch)
+ if (verificationMatch) {
+ approved = false;
+ status = "declined";
+ reason =
+ "Document already used to create an eVault";
+ }
+ }
+ await this.verificationService.findByIdAndUpdate(id, {
+ approved,
+ data: {
+ person: body.data.verification.person,
+ document: body.data.verification.document,
+ },
+ documentId:
+ body.data.verification.document.number.value,
+ });
+ }
+
+ eventEmitter.emit(id, {
+ reason,
+ status,
+ person: body.data.verification.person ?? null,
+ document: body.data.verification.document,
+ });
+
+ return res.json({ success: true });
+ },
+ );
+ }
+}
diff --git a/infrastructure/evault-provisioner/src/entities/Verification.ts b/infrastructure/evault-provisioner/src/entities/Verification.ts
new file mode 100644
index 00000000..7b258309
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/entities/Verification.ts
@@ -0,0 +1,37 @@
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+} from "typeorm";
+
+@Entity()
+export class Verification {
+ @PrimaryGeneratedColumn("uuid")
+ id!: string;
+
+ @Column({ nullable: true })
+ veriffId!: string;
+
+ @Column({ nullable: true })
+ approved!: boolean;
+
+ @Column({ type: "jsonb", nullable: true })
+ data!: Record
;
+
+ @Column({ nullable: true })
+ referenceId!: string;
+
+ @Column({ nullable: true })
+ documentId!: string;
+
+ @Column({ default: false })
+ consumed!: boolean;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
diff --git a/infrastructure/evault-provisioner/src/index.ts b/infrastructure/evault-provisioner/src/index.ts
index 23f1912a..ae4cce77 100644
--- a/infrastructure/evault-provisioner/src/index.ts
+++ b/infrastructure/evault-provisioner/src/index.ts
@@ -1,29 +1,64 @@
+import "reflect-metadata";
import express, { Request, Response } from "express";
import axios, { AxiosError } from "axios";
-import { provisionEVault } from "./templates/evault.nomad.js";
+import { provisionEVault } from "./templates/evault.nomad";
import dotenv from "dotenv";
import { W3IDBuilder } from "w3id";
import * as jose from "jose";
import path from "path";
-import { fileURLToPath } from "url";
+import { createHmacSignature } from "./utils/hmac";
+import cors from "cors";
+import { AppDataSource } from "./config/database";
+import { VerificationService } from "./services/VerificationService";
+import { VerificationController } from "./controllers/VerificationController";
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
const app = express();
const port = process.env.PORT || 3001;
-app.use(express.json());
+// Configure CORS for SSE
+app.use(
+ cors({
+ origin: "*",
+ methods: ["GET", "POST", "OPTIONS", "PATCH"],
+ allowedHeaders: ["Content-Type", "Authorization"],
+ credentials: true,
+ }),
+);
+
+// Increase JSON payload limit to 50MB
+app.use(express.json({ limit: "50mb" }));
+// Increase URL-encoded payload limit to 50MB
+app.use(express.urlencoded({ limit: "50mb", extended: true }));
+
+// Initialize database connection
+const initializeDatabase = async () => {
+ try {
+ await AppDataSource.initialize();
+ console.log("Database connection initialized");
+ } catch (error) {
+ console.error("Error during database initialization:", error);
+ process.exit(1);
+ }
+};
+
+// Initialize services and controllers
+const verificationService = new VerificationService(
+ AppDataSource.getRepository("Verification"),
+);
+const verificationController = new VerificationController(verificationService);
interface ProvisionRequest {
registryEntropy: string;
namespace: string;
+ verificationId: string;
}
interface ProvisionResponse {
success: boolean;
uri?: string;
+ w3id?: string;
message?: string;
error?: string | unknown;
}
@@ -41,20 +76,30 @@ app.post(
res: Response,
) => {
try {
-
- if (!process.env.REGISTRY_URI) throw new Error("REGISTRY_URI is not set");
- const { registryEntropy, namespace } = req.body;
-
- if (!registryEntropy || !namespace) {
+ if (!process.env.PUBLIC_REGISTRY_URL)
+ throw new Error("PUBLIC_REGISTRY_URL is not set");
+ const { registryEntropy, namespace, verificationId } = req.body;
+ if (!registryEntropy || !namespace || !verificationId) {
return res.status(400).json({
success: false,
error: "registryEntropy and namespace are required",
message:
- "Missing required fields: registryEntropy, namespace",
+ "Missing required fields: registryEntropy, namespace, verifficationId",
});
}
+ const verification =
+ await verificationService.findById(verificationId);
+ if (!verification) throw new Error("verification doesn't exist");
+ if (!verification.approved)
+ throw new Error("verification not approved");
+ if (verification.consumed)
+ throw new Error("This verification ID has already been used");
+
const jwksResponse = await axios.get(
- `http://localhost:4321/.well-known/jwks.json`,
+ new URL(
+ `/.well-known/jwks.json`,
+ process.env.PUBLIC_REGISTRY_URL,
+ ).toString(),
);
const JWKS = jose.createLocalJWKSet(jwksResponse.data);
@@ -72,23 +117,28 @@ app.post(
const uri = await provisionEVault(w3id, evaultId.id);
-
- await axios.post(new URL("/register", process.env.REGISTRY_URI).toString(), {
- ename: w3id,
- uri,
- evault: evaultId.id,
- }, {
- headers: {
- "Authorization": `Bearer ${process.env.REGISTRY_SHARED_SECRET}`
- }
- });
+ await axios.post(
+ new URL(
+ "/register",
+ process.env.PUBLIC_REGISTRY_URL,
+ ).toString(),
+ {
+ ename: w3id,
+ uri,
+ evault: evaultId.id,
+ },
+ {
+ headers: {
+ Authorization: `Bearer ${process.env.REGISTRY_SHARED_SECRET}`,
+ },
+ },
+ );
res.json({
success: true,
+ w3id,
uri,
});
-
-
} catch (error) {
const axiosError = error as AxiosError;
res.status(500).json({
@@ -100,6 +150,20 @@ app.post(
},
);
-app.listen(port, () => {
- console.log(`Evault Provisioner API running on port ${port}`);
-});
+// Register verification routes
+verificationController.registerRoutes(app);
+
+// Start the server
+const start = async () => {
+ try {
+ await initializeDatabase();
+ app.listen(port, () => {
+ console.log(`Evault Provisioner API running on port ${port}`);
+ });
+ } catch (err) {
+ console.error(err);
+ process.exit(1);
+ }
+};
+
+start();
diff --git a/infrastructure/evault-provisioner/src/migrations/1748932757644-migration.ts b/infrastructure/evault-provisioner/src/migrations/1748932757644-migration.ts
new file mode 100644
index 00000000..b9e70e53
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/migrations/1748932757644-migration.ts
@@ -0,0 +1,14 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class Migration1748932757644 implements MigrationInterface {
+ name = 'Migration1748932757644'
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`CREATE TABLE "verification" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "veriffId" character varying, "approved" boolean, "data" jsonb, "referenceId" character varying, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_f7e3a90ca384e71d6e2e93bb340" PRIMARY KEY ("id"))`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`DROP TABLE "verification"`);
+ }
+
+}
diff --git a/infrastructure/evault-provisioner/src/migrations/1748966722767-migration.ts b/infrastructure/evault-provisioner/src/migrations/1748966722767-migration.ts
new file mode 100644
index 00000000..f51e3af8
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/migrations/1748966722767-migration.ts
@@ -0,0 +1,14 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class Migration1748966722767 implements MigrationInterface {
+ name = 'Migration1748966722767'
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "verification" ADD "documentId" character varying`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "verification" DROP COLUMN "documentId"`);
+ }
+
+}
diff --git a/infrastructure/evault-provisioner/src/migrations/1748968097591-migration.ts b/infrastructure/evault-provisioner/src/migrations/1748968097591-migration.ts
new file mode 100644
index 00000000..aa2e5b82
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/migrations/1748968097591-migration.ts
@@ -0,0 +1,14 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class Migration1748968097591 implements MigrationInterface {
+ name = 'Migration1748968097591'
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "verification" ADD "consumed" boolean NOT NULL DEFAULT false`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "verification" DROP COLUMN "consumed"`);
+ }
+
+}
diff --git a/infrastructure/evault-provisioner/src/services/VerificationService.ts b/infrastructure/evault-provisioner/src/services/VerificationService.ts
new file mode 100644
index 00000000..ced2185f
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/services/VerificationService.ts
@@ -0,0 +1,50 @@
+import { DeepPartial, Repository } from "typeorm";
+import { Verification } from "../entities/Verification";
+
+export class VerificationService {
+ constructor(
+ private readonly verificationRepository: Repository,
+ ) {}
+
+ async create(data: Partial): Promise {
+ const verification = this.verificationRepository.create(data);
+ return await this.verificationRepository.save(verification);
+ }
+
+ async findById(id: string): Promise {
+ return await this.verificationRepository.findOneBy({ id });
+ }
+
+ async findByIdAndUpdate(
+ id: string,
+ data: DeepPartial,
+ ): Promise {
+ const current = await this.findById(id);
+ const toSave = this.verificationRepository.create({
+ ...current,
+ ...data,
+ });
+
+ const updated = await this.verificationRepository.save(toSave);
+ return updated;
+ }
+
+ async findOne(where: Partial): Promise {
+ return await this.verificationRepository.findOneBy(where);
+ }
+
+ async findManyAndCount(
+ where: Partial,
+ relations: Record = {},
+ order: Record = {},
+ pagination: { take: number; skip: number } = { take: 10, skip: 0 },
+ ): Promise<[Verification[], number]> {
+ return await this.verificationRepository.findAndCount({
+ where,
+ relations,
+ order,
+ take: pagination.take,
+ skip: pagination.skip,
+ });
+ }
+}
diff --git a/infrastructure/evault-provisioner/src/utils/eventEmitter.ts b/infrastructure/evault-provisioner/src/utils/eventEmitter.ts
new file mode 100644
index 00000000..669fe1f8
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/utils/eventEmitter.ts
@@ -0,0 +1,3 @@
+import { EventEmitter } from "events"
+
+export const eventEmitter = new EventEmitter()
\ No newline at end of file
diff --git a/infrastructure/evault-provisioner/src/utils/hmac.ts b/infrastructure/evault-provisioner/src/utils/hmac.ts
new file mode 100644
index 00000000..2091f7f2
--- /dev/null
+++ b/infrastructure/evault-provisioner/src/utils/hmac.ts
@@ -0,0 +1,31 @@
+import { createHmac } from "crypto";
+
+/**
+ * Generates an HMAC SHA-256 signature for a JSON-serializable object using the provided secret key.
+ *
+ * @param body - The object to be signed.
+ * @param secret - The secret key used for HMAC generation.
+ * @returns The hexadecimal string representation of the HMAC signature.
+ */
+export function createHmacSignature(body: Record, secret: string) {
+ return createHmac("sha256", secret)
+ .update(JSON.stringify(body))
+ .digest("hex");
+}
+
+/**
+ * Verifies that a provided HMAC signature matches the expected signature for a given object and secret key.
+ *
+ * @param body - The object whose signature is to be verified.
+ * @param signature - The HMAC signature to compare against.
+ * @param secret - The secret key used to generate the expected signature.
+ * @returns `true` if the signature is valid; otherwise, `false`.
+ */
+export function verifyHmacSignature(
+ body: Record,
+ signature: string,
+ secret: string,
+) {
+ const expectedSignature = createHmacSignature(body, secret);
+ return expectedSignature === signature;
+}
diff --git a/infrastructure/evault-provisioner/tsconfig.json b/infrastructure/evault-provisioner/tsconfig.json
index 0b488cd7..87ff34e2 100644
--- a/infrastructure/evault-provisioner/tsconfig.json
+++ b/infrastructure/evault-provisioner/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
- "module": "ESNext",
+ "module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
@@ -10,7 +10,9 @@
"outDir": "dist",
"rootDir": "src",
"sourceMap": true,
- "declaration": true
+ "declaration": true,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
diff --git a/platforms/registry/package.json b/platforms/registry/package.json
index 850d23f1..005264dd 100644
--- a/platforms/registry/package.json
+++ b/platforms/registry/package.json
@@ -1,7 +1,7 @@
{
"name": "registry",
"version": "1.0.0",
- "description": "Registry service for entropy and service discovery",
+ "description": "Registry service for managing vault entries",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
@@ -15,6 +15,7 @@
"migration:create": "npm run typeorm migration:create"
},
"dependencies": {
+ "@fastify/cors": "8.4.1",
"@fastify/jwt": "^7.2.3",
"axios": "^1.6.7",
"dotenv": "^16.5.0",
diff --git a/platforms/registry/src/index.ts b/platforms/registry/src/index.ts
index bd381b9c..28fe83ab 100644
--- a/platforms/registry/src/index.ts
+++ b/platforms/registry/src/index.ts
@@ -4,11 +4,20 @@ import dotenv from "dotenv";
import path from "path";
import { AppDataSource } from "./config/database";
import { VaultService } from "./services/VaultService";
+import cors from "@fastify/cors";
dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
const server = fastify({ logger: true });
+// Register CORS
+server.register(cors, {
+ origin: "*",
+ methods: ["GET", "POST", "OPTIONS"],
+ allowedHeaders: ["Content-Type", "Authorization"],
+ credentials: true,
+});
+
// Initialize database connection
const initializeDatabase = async () => {
try {
@@ -26,91 +35,103 @@ const vaultService = new VaultService(AppDataSource.getRepository("Vault"));
// Middleware to check shared secret
const checkSharedSecret = async (request: any, reply: any) => {
const authHeader = request.headers.authorization;
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
- return reply.status(401).send({ error: 'Missing or invalid authorization header' });
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
+ return reply
+ .status(401)
+ .send({ error: "Missing or invalid authorization header" });
}
- const secret = authHeader.split(' ')[1];
+ const secret = authHeader.split(" ")[1];
if (secret !== process.env.REGISTRY_SHARED_SECRET) {
- return reply.status(401).send({ error: 'Invalid shared secret' });
+ return reply.status(401).send({ error: "Invalid shared secret" });
}
};
// Create a new vault entry
-server.post("/register", {
- preHandler: checkSharedSecret
-}, async (request, reply) => {
- try {
- const { ename, uri, evault } = request.body as { ename: string; uri: string; evault: string };
-
- if (!ename || !uri || !evault) {
- return reply.status(400).send({
- error: "Missing required fields. Please provide ename, uri, and evault"
- });
+server.post(
+ "/register",
+ {
+ preHandler: checkSharedSecret,
+ },
+ async (request, reply) => {
+ try {
+ const { ename, uri, evault } = request.body as {
+ ename: string;
+ uri: string;
+ evault: string;
+ };
+
+ if (!ename || !uri || !evault) {
+ return reply.status(400).send({
+ error: "Missing required fields. Please provide ename, uri, and evault",
+ });
+ }
+
+ const vault = await vaultService.create(ename, uri, evault);
+ return reply.status(201).send(vault);
+ } catch (error) {
+ server.log.error(error);
+ reply.status(500).send({ error: "Failed to create vault entry" });
}
+ },
+);
- const vault = await vaultService.create(ename, uri, evault);
- return reply.status(201).send(vault);
+// Generate and return a signed JWT with entropy
+server.get("/entropy", async (request, reply) => {
+ try {
+ const token = await generateEntropy();
+ return { token };
} catch (error) {
server.log.error(error);
- reply.status(500).send({ error: "Failed to create vault entry" });
+ reply.status(500).send({ error: "Failed to generate entropy" });
}
});
-// Generate and return a signed JWT with entropy
-server.get("/entropy", async (request, reply) => {
- try {
- const token = await generateEntropy();
- return { token };
- } catch (error) {
- server.log.error(error);
- reply.status(500).send({ error: "Failed to generate entropy" });
- }
-});
-
// Expose the JWK used for signing
server.get("/.well-known/jwks.json", async (request, reply) => {
- try {
- const jwk = await getJWK();
- return jwk;
- } catch (error) {
- server.log.error(error);
- reply.status(500).send({ error: "Failed to get JWK" });
- }
+ try {
+ const jwk = await getJWK();
+ return jwk;
+ } catch (error) {
+ server.log.error(error);
+ reply.status(500).send({ error: "Failed to get JWK" });
+ }
});
// Resolve service from database based on w3id
server.get("/resolve", async (request, reply) => {
- try {
- const { w3id } = request.query as { w3id: string };
- if (!w3id) {
- return reply.status(400).send({ error: "w3id parameter is required" });
- }
+ try {
+ const { w3id } = request.query as { w3id: string };
+ if (!w3id) {
+ return reply
+ .status(400)
+ .send({ error: "w3id parameter is required" });
+ }
- const vault = await vaultService.findByEname(w3id);
- if (!vault) {
- return reply.status(404).send({ error: "Service not found" });
- }
+ const vault = await vaultService.findByEname(w3id);
+ if (!vault) {
+ return reply.status(404).send({ error: "Service not found" });
+ }
- return {
- ename: vault.ename,
- uri: vault.uri,
- evault: vault.evault
- };
- } catch (error) {
- server.log.error(error);
- reply.status(500).send({ error: "Failed to resolve service" });
- }
+ return {
+ ename: vault.ename,
+ uri: vault.uri,
+ evault: vault.evault,
+ };
+ } catch (error) {
+ server.log.error(error);
+ reply.status(500).send({ error: "Failed to resolve service" });
+ }
});
const start = async () => {
- try {
- await initializeDatabase();
- await server.listen({ port: 4321, host: "0.0.0.0" });
- } catch (err) {
- server.log.error(err);
- process.exit(1);
- }
+ try {
+ await initializeDatabase();
+ await server.listen({ port: 4321, host: "0.0.0.0" });
+ } catch (err) {
+ server.log.error(err);
+ process.exit(1);
+ }
};
start();
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0b943e3a..6bd9cdb4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -44,15 +44,36 @@ importers:
'@tauri-apps/plugin-store':
specifier: ^2.2.0
version: 2.2.0
+ '@veriff/incontext-sdk':
+ specifier: ^2.4.0
+ version: 2.4.0
+ '@veriff/js-sdk':
+ specifier: ^1.5.1
+ version: 1.5.1
+ axios:
+ specifier: ^1.6.7
+ version: 1.9.0
clsx:
specifier: ^2.1.1
version: 2.1.1
+ dotenv:
+ specifier: ^16.5.0
+ version: 16.5.0
flag-icons:
specifier: ^7.3.2
version: 7.3.2
+ import:
+ specifier: ^0.0.6
+ version: 0.0.6
+ svelte-loading-spinners:
+ specifier: ^0.3.6
+ version: 0.3.6
tailwind-merge:
specifier: ^3.0.2
version: 3.3.0
+ uuid:
+ specifier: ^11.1.0
+ version: 11.1.0
devDependencies:
'@biomejs/biome':
specifier: ^1.9.4
@@ -232,6 +253,9 @@ importers:
axios:
specifier: ^1.6.7
version: 1.9.0
+ cors:
+ specifier: ^2.8.5
+ version: 2.8.5
dotenv:
specifier: ^16.4.5
version: 16.5.0
@@ -241,22 +265,40 @@ importers:
jose:
specifier: ^5.2.2
version: 5.10.0
+ pg:
+ specifier: ^8.11.3
+ version: 8.16.0
+ reflect-metadata:
+ specifier: ^0.2.1
+ version: 0.2.2
sha256:
specifier: ^0.2.0
version: 0.2.0
+ typeorm:
+ specifier: ^0.3.24
+ version: 0.3.24(babel-plugin-macros@3.1.0)(pg@8.16.0)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3))
w3id:
specifier: workspace:*
version: link:../w3id
devDependencies:
+ '@types/cors':
+ specifier: ^2.8.18
+ version: 2.8.18
'@types/express':
specifier: ^4.17.21
version: 4.17.22
'@types/node':
specifier: ^20.11.24
version: 20.17.50
+ '@types/sha256':
+ specifier: ^0.2.2
+ version: 0.2.2
nodemon:
specifier: ^3.0.3
version: 3.1.10
+ ts-node-dev:
+ specifier: ^2.0.0
+ version: 2.0.0(@types/node@20.17.50)(typescript@5.8.3)
tsx:
specifier: ^4.7.1
version: 4.19.4
@@ -308,7 +350,7 @@ importers:
version: 3.3.0
vitest:
specifier: ^3.1.2
- version: 3.1.4(@types/node@22.15.21)(@vitest/browser@3.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ version: 3.1.4(@types/node@20.17.50)(@vitest/browser@3.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
devDependencies:
'@types/jest':
specifier: ^29.5.0
@@ -324,10 +366,10 @@ importers:
version: 8.57.1
jest:
specifier: ^29.5.0
- version: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
+ version: 29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3))
ts-jest:
specifier: ^29.1.0
- version: 29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0))(typescript@5.8.3)
+ version: 29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3)))(typescript@5.8.3)
typescript:
specifier: ^5.0.4
version: 5.8.3
@@ -481,6 +523,9 @@ importers:
platforms/registry:
dependencies:
+ '@fastify/cors':
+ specifier: 8.4.1
+ version: 8.4.1
'@fastify/jwt':
specifier: ^7.2.3
version: 7.2.4
@@ -1202,6 +1247,9 @@ packages:
'@fastify/busboy@3.1.1':
resolution: {integrity: sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==}
+ '@fastify/cors@8.4.1':
+ resolution: {integrity: sha512-iYQJtrY3pFiDS5mo5zRaudzg2OcUdJ96PD6xfkKOOEilly5nnrFZx/W6Sce2T79xxlEn2qpU3t5+qS2phS369w==}
+
'@fastify/error@3.4.1':
resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==}
@@ -2249,6 +2297,9 @@ packages:
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+ '@types/cors@2.8.18':
+ resolution: {integrity: sha512-nX3d0sxJW41CqQvfOzVG1NCTXfFDrDWIghCZncpHeWlVFd81zxB/DLhg7avFg6eHLCRX7ckBmoIIcqa++upvJA==}
+
'@types/docker-modem@3.0.6':
resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==}
@@ -2341,6 +2392,9 @@ packages:
'@types/serve-static@1.15.7':
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
+ '@types/sha256@0.2.2':
+ resolution: {integrity: sha512-uKMaDzyzfcDYGEwTgLh+hmgDMxXWyIVodY8T+qt7A+NYvikW0lmGLMGbQ7BipCB8dzXHa55C9g+Ii/3Lgt1KmA==}
+
'@types/ssh2-streams@0.1.12':
resolution: {integrity: sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg==}
@@ -2356,6 +2410,12 @@ packages:
'@types/stream-buffers@3.0.7':
resolution: {integrity: sha512-azOCy05sXVXrO+qklf0c/B07H/oHaIuDDAiHPVwlk3A9Ek+ksHyTeMajLZl3r76FxpPpxem//4Te61G1iW3Giw==}
+ '@types/strip-bom@3.0.0':
+ resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==}
+
+ '@types/strip-json-comments@0.0.30':
+ resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==}
+
'@types/uuid@9.0.8':
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
@@ -2473,6 +2533,13 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+ '@veriff/incontext-sdk@2.4.0':
+ resolution: {integrity: sha512-Bz+sRoIQvarH/bfGXFtAp3LK7cpA4G4AOD4Cr63V0Y4bJDYX8uHSeBfRH1HxL2l6dFlO+2H+HwEhkrkKL5wBRQ==}
+
+ '@veriff/js-sdk@1.5.1':
+ resolution: {integrity: sha512-THHcyRTctdtXUpKAEGnddTkwgFdRi2taAigtnhOfGmoCp23m+9vlZp5GnT7qmswfyZk48BCZ4Uc2gT7AUIhqTA==}
+ engines: {node: '>=16', npm: '>=8'}
+
'@vitest/browser@3.1.4':
resolution: {integrity: sha512-2L4vR/tuUZBxKU72Qe+unIp1P8lZ0T5nlqPegkXxyZFR5gWqItV8VPPR261GOzl49Zw2AhzMABzMMHJagQ0a2g==}
peerDependencies:
@@ -3109,6 +3176,10 @@ packages:
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
cosmiconfig@7.1.0:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'}
@@ -3299,6 +3370,9 @@ packages:
dom-accessibility-api@0.6.3:
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+ dom-focus-lock@1.0.4:
+ resolution: {integrity: sha512-Tiz2EYedB14UW0/lY5PEzFAie66e9itoEVKhz0M9xz1cHqP4Jd0XUg/AT2m6DtbhCFa9DHo6nQyePuLH7Mx9+A==}
+
dom-helpers@5.2.1:
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
@@ -3335,6 +3409,9 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
+ dynamic-dedupe@0.3.0:
+ resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==}
+
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -3770,6 +3847,9 @@ packages:
flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ focus-lock@0.6.8:
+ resolution: {integrity: sha512-vkHTluRCoq9FcsrldC0ulQHiyBYgVJB2CX53I8r0nTC6KnEij7Of0jpBspjt3/CuNb6fyoj3aOh9J2HgQUM0og==}
+
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
@@ -4032,6 +4112,11 @@ packages:
engines: {node: '>=8'}
hasBin: true
+ import@0.0.6:
+ resolution: {integrity: sha512-QPhTdjy9J4wUzmWSG7APkSgMFuPGPw+iJTYUblcfc2AfpqaatbwgCldK1HoLYx+v/+lWvab63GWZtNkcnj9JcQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@@ -4752,6 +4837,9 @@ packages:
mlly@1.7.4:
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
+ mnemonist@0.39.5:
+ resolution: {integrity: sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ==}
+
mnemonist@0.39.8:
resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==}
@@ -4905,6 +4993,9 @@ packages:
openid-client@6.5.0:
resolution: {integrity: sha512-fAfYaTnOYE2kQCqEJGX9KDObW2aw7IQy4jWpU/+3D3WoCFLbix5Hg6qIPQ6Js9r7f8jDUmsnnguRNCSw4wU/IQ==}
+ optimist@0.3.7:
+ resolution: {integrity: sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -5727,6 +5818,10 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
+ strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+
strip-bom@4.0.0:
resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
engines: {node: '>=8'}
@@ -5743,6 +5838,10 @@ packages:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
+ strip-json-comments@2.0.1:
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ engines: {node: '>=0.10.0'}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -5795,6 +5894,9 @@ packages:
svelte-gestures@5.1.4:
resolution: {integrity: sha512-gfSO/GqWLu9nRMCz12jqdyA0+NTsojYcIBcRqZjwWrpQbqMXr0zWPFpZBtzfYbRHtuFxZImMZp9MrVaFCYbhDg==}
+ svelte-loading-spinners@0.3.6:
+ resolution: {integrity: sha512-mthHQ2TwiwzTWzbFry3CBnVEfzqPOD9WkVw84OfSYzHRq6N9wgQ+yv37u81uPeuLU/ZOIPqhujpXquB1aol5ZQ==}
+
svelte-preprocess@5.1.4:
resolution: {integrity: sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==}
engines: {node: '>= 16.0.0'}
@@ -5967,6 +6069,10 @@ packages:
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ tree-kill@1.2.2:
+ resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+ hasBin: true
+
ts-api-utils@2.1.0:
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
engines: {node: '>=18.12'}
@@ -6001,6 +6107,17 @@ packages:
esbuild:
optional: true
+ ts-node-dev@2.0.0:
+ resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+ peerDependencies:
+ node-notifier: '*'
+ typescript: '*'
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
ts-node@10.9.2:
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
@@ -6015,6 +6132,9 @@ packages:
'@swc/wasm':
optional: true
+ tsconfig@7.0.0:
+ resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==}
+
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@@ -6032,6 +6152,9 @@ packages:
engines: {node: '>=18.0.0'}
hasBin: true
+ tua-body-scroll-lock@1.2.1:
+ resolution: {integrity: sha512-DuGbQxIBSbz7/aAwh0oMThOwCwDdYzsU8nF5XQPAvoeOBWp/qhjrZfOtc84gj6CQLZu5L1+TgMNX6fW3OuafHA==}
+
turbo-darwin-64@2.5.3:
resolution: {integrity: sha512-YSItEVBUIvAGPUDpAB9etEmSqZI3T6BHrkBkeSErvICXn3dfqXUfeLx35LfptLDEbrzFUdwYFNmt8QXOwe9yaw==}
cpu: [x64]
@@ -6475,6 +6598,10 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
+ wordwrap@0.0.3:
+ resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==}
+ engines: {node: '>=0.4.0'}
+
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -7148,6 +7275,11 @@ snapshots:
'@fastify/busboy@3.1.1': {}
+ '@fastify/cors@8.4.1':
+ dependencies:
+ fastify-plugin: 4.5.1
+ mnemonist: 0.39.5
+
'@fastify/error@3.4.1': {}
'@fastify/fast-json-stringify-compiler@4.3.0':
@@ -8452,6 +8584,10 @@ snapshots:
'@types/cookie@0.6.0': {}
+ '@types/cors@2.8.18':
+ dependencies:
+ '@types/node': 20.17.50
+
'@types/docker-modem@3.0.6':
dependencies:
'@types/node': 20.17.50
@@ -8529,7 +8665,7 @@ snapshots:
'@types/pg@8.15.4':
dependencies:
- '@types/node': 20.17.50
+ '@types/node': 22.15.21
pg-protocol: 1.10.0
pg-types: 2.2.0
@@ -8562,6 +8698,10 @@ snapshots:
'@types/node': 20.17.50
'@types/send': 0.17.4
+ '@types/sha256@0.2.2':
+ dependencies:
+ '@types/node': 20.17.50
+
'@types/ssh2-streams@0.1.12':
dependencies:
'@types/node': 20.17.50
@@ -8581,6 +8721,10 @@ snapshots:
dependencies:
'@types/node': 20.17.50
+ '@types/strip-bom@3.0.0': {}
+
+ '@types/strip-json-comments@0.0.30': {}
+
'@types/uuid@9.0.8': {}
'@types/yargs-parser@21.0.3': {}
@@ -8752,6 +8896,33 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
+ '@veriff/incontext-sdk@2.4.0':
+ dependencies:
+ dom-focus-lock: 1.0.4
+ tua-body-scroll-lock: 1.2.1
+
+ '@veriff/js-sdk@1.5.1': {}
+
+ '@vitest/browser@3.1.4(playwright@1.52.0)(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))(vitest@3.1.4)':
+ dependencies:
+ '@testing-library/dom': 10.4.0
+ '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0)
+ '@vitest/mocker': 3.1.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/utils': 3.1.4
+ magic-string: 0.30.17
+ sirv: 3.0.1
+ tinyrainbow: 2.0.0
+ vitest: 3.1.4(@types/node@20.17.50)(@vitest/browser@3.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ ws: 8.18.2
+ optionalDependencies:
+ playwright: 1.52.0
+ transitivePeerDependencies:
+ - bufferutil
+ - msw
+ - utf-8-validate
+ - vite
+ optional: true
+
'@vitest/browser@3.1.4(playwright@1.52.0)(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))(vitest@3.1.4)':
dependencies:
'@testing-library/dom': 10.4.0
@@ -8811,6 +8982,14 @@ snapshots:
chai: 5.2.0
tinyrainbow: 2.0.0
+ '@vitest/mocker@3.1.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
+ dependencies:
+ '@vitest/spy': 3.1.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.17
+ optionalDependencies:
+ vite: 6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+
'@vitest/mocker@3.1.4(vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
dependencies:
'@vitest/spy': 3.1.4
@@ -9488,6 +9667,11 @@ snapshots:
core-util-is@1.0.3: {}
+ cors@2.8.5:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
cosmiconfig@7.1.0:
dependencies:
'@types/parse-json': 4.0.2
@@ -9524,21 +9708,6 @@ snapshots:
- supports-color
- ts-node
- create-jest@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/types': 29.6.3
- chalk: 4.1.2
- exit: 0.1.2
- graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- prompts: 2.4.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
create-require@1.1.1: {}
cross-inspect@1.0.1:
@@ -9701,6 +9870,10 @@ snapshots:
dom-accessibility-api@0.6.3: {}
+ dom-focus-lock@1.0.4:
+ dependencies:
+ focus-lock: 0.6.8
+
dom-helpers@5.2.1:
dependencies:
'@babel/runtime': 7.27.1
@@ -9740,6 +9913,10 @@ snapshots:
es-errors: 1.3.0
gopd: 1.2.0
+ dynamic-dedupe@0.3.0:
+ dependencies:
+ xtend: 4.0.2
+
eastasianwidth@0.2.0: {}
ecdsa-sig-formatter@1.0.11:
@@ -10475,6 +10652,8 @@ snapshots:
flatted@3.3.3: {}
+ focus-lock@0.6.8: {}
+
follow-redirects@1.15.9: {}
for-each@0.3.5:
@@ -10736,6 +10915,10 @@ snapshots:
pkg-dir: 4.2.0
resolve-cwd: 3.0.0
+ import@0.0.6:
+ dependencies:
+ optimist: 0.3.7
+
imurmurhash@0.1.4: {}
indent-string@4.0.0: {}
@@ -11028,25 +11211,6 @@ snapshots:
- supports-color
- ts-node
- jest-cli@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3))
- '@jest/test-result': 29.7.0
- '@jest/types': 29.6.3
- chalk: 4.1.2
- create-jest: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
- exit: 0.1.2
- import-local: 3.2.0
- jest-config: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- jest-validate: 29.7.0
- yargs: 17.7.2
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jest-config@29.7.0(@types/node@20.17.50)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3)):
dependencies:
'@babel/core': 7.27.1
@@ -11078,36 +11242,6 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-config@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0):
- dependencies:
- '@babel/core': 7.27.1
- '@jest/test-sequencer': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.27.1)
- chalk: 4.1.2
- ci-info: 3.9.0
- deepmerge: 4.3.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- jest-circus: 29.7.0(babel-plugin-macros@3.1.0)
- jest-environment-node: 29.7.0
- jest-get-type: 29.6.3
- jest-regex-util: 29.6.3
- jest-resolve: 29.7.0
- jest-runner: 29.7.0
- jest-util: 29.7.0
- jest-validate: 29.7.0
- micromatch: 4.0.8
- parse-json: 5.2.0
- pretty-format: 29.7.0
- slash: 3.0.0
- strip-json-comments: 3.1.1
- optionalDependencies:
- '@types/node': 22.15.21
- transitivePeerDependencies:
- - babel-plugin-macros
- - supports-color
-
jest-diff@29.7.0:
dependencies:
chalk: 4.1.2
@@ -11335,18 +11469,6 @@ snapshots:
- supports-color
- ts-node
- jest@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0):
- dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3))
- '@jest/types': 29.6.3
- import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
- transitivePeerDependencies:
- - '@types/node'
- - babel-plugin-macros
- - supports-color
- - ts-node
-
jiti@2.4.2: {}
jose@5.10.0: {}
@@ -11648,6 +11770,10 @@ snapshots:
pkg-types: 1.3.1
ufo: 1.6.1
+ mnemonist@0.39.5:
+ dependencies:
+ obliterator: 2.0.5
+
mnemonist@0.39.8:
dependencies:
obliterator: 2.0.5
@@ -11801,6 +11927,10 @@ snapshots:
jose: 6.0.11
oauth4webapi: 3.5.1
+ optimist@0.3.7:
+ dependencies:
+ wordwrap: 0.0.3
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -12676,6 +12806,8 @@ snapshots:
dependencies:
ansi-regex: 6.1.0
+ strip-bom@3.0.0: {}
+
strip-bom@4.0.0: {}
strip-final-newline@2.0.0: {}
@@ -12686,6 +12818,8 @@ snapshots:
dependencies:
min-indent: 1.0.1
+ strip-json-comments@2.0.1: {}
+
strip-json-comments@3.1.1: {}
strip-literal@2.1.1:
@@ -12751,6 +12885,8 @@ snapshots:
svelte-gestures@5.1.4: {}
+ svelte-loading-spinners@0.3.6: {}
+
svelte-preprocess@5.1.4(@babel/core@7.27.1)(postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@22.15.21)(typescript@5.6.3)))(postcss@8.5.3)(svelte@5.33.1)(typescript@5.8.3):
dependencies:
'@types/pug': 2.0.10
@@ -12949,6 +13085,8 @@ snapshots:
tr46@0.0.3: {}
+ tree-kill@1.2.2: {}
+
ts-api-utils@2.1.0(typescript@5.8.3):
dependencies:
typescript: 5.8.3
@@ -12975,25 +13113,23 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.27.1)
- ts-jest@29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0))(typescript@5.8.3):
+ ts-node-dev@2.0.0(@types/node@20.17.50)(typescript@5.8.3):
dependencies:
- bs-logger: 0.2.6
- ejs: 3.1.10
- fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@22.15.21)(babel-plugin-macros@3.1.0)
- jest-util: 29.7.0
- json5: 2.2.3
- lodash.memoize: 4.1.2
- make-error: 1.3.6
- semver: 7.7.2
- type-fest: 4.41.0
+ chokidar: 3.6.0
+ dynamic-dedupe: 0.3.0
+ minimist: 1.2.8
+ mkdirp: 1.0.4
+ resolve: 1.22.10
+ rimraf: 2.7.1
+ source-map-support: 0.5.13
+ tree-kill: 1.2.2
+ ts-node: 10.9.2(@types/node@20.17.50)(typescript@5.8.3)
+ tsconfig: 7.0.0
typescript: 5.8.3
- yargs-parser: 21.1.1
- optionalDependencies:
- '@babel/core': 7.27.1
- '@jest/transform': 29.7.0
- '@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.27.1)
+ transitivePeerDependencies:
+ - '@swc/core'
+ - '@swc/wasm'
+ - '@types/node'
ts-node@10.9.2(@types/node@20.17.50)(typescript@5.8.3):
dependencies:
@@ -13051,6 +13187,13 @@ snapshots:
yn: 3.1.1
optional: true
+ tsconfig@7.0.0:
+ dependencies:
+ '@types/strip-bom': 3.0.0
+ '@types/strip-json-comments': 0.0.30
+ strip-bom: 3.0.0
+ strip-json-comments: 2.0.1
+
tslib@1.14.1: {}
tslib@2.8.1: {}
@@ -13067,6 +13210,8 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
+ tua-body-scroll-lock@1.2.1: {}
+
turbo-darwin-64@2.5.3:
optional: true
@@ -13286,6 +13431,27 @@ snapshots:
- supports-color
- terser
+ vite-node@3.1.4(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.4.1(supports-color@5.5.0)
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ transitivePeerDependencies:
+ - '@types/node'
+ - jiti
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
vite-node@3.1.4(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
cac: 6.7.14
@@ -13317,6 +13483,22 @@ snapshots:
fsevents: 2.3.3
lightningcss: 1.30.1
+ vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ dependencies:
+ esbuild: 0.25.4
+ fdir: 6.4.4(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.3
+ rollup: 4.41.0
+ tinyglobby: 0.2.13
+ optionalDependencies:
+ '@types/node': 20.17.50
+ fsevents: 2.3.3
+ jiti: 2.4.2
+ lightningcss: 1.30.1
+ tsx: 4.19.4
+ yaml: 2.8.0
+
vite@6.3.5(@types/node@22.15.21)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
esbuild: 0.25.4
@@ -13371,6 +13553,46 @@ snapshots:
- supports-color
- terser
+ vitest@3.1.4(@types/node@20.17.50)(@vitest/browser@3.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
+ dependencies:
+ '@vitest/expect': 3.1.4
+ '@vitest/mocker': 3.1.4(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))
+ '@vitest/pretty-format': 3.1.4
+ '@vitest/runner': 3.1.4
+ '@vitest/snapshot': 3.1.4
+ '@vitest/spy': 3.1.4
+ '@vitest/utils': 3.1.4
+ chai: 5.2.0
+ debug: 4.4.1(supports-color@5.5.0)
+ expect-type: 1.2.1
+ magic-string: 0.30.17
+ pathe: 2.0.3
+ std-env: 3.9.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.13
+ tinypool: 1.0.2
+ tinyrainbow: 2.0.0
+ vite: 6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ vite-node: 3.1.4(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 20.17.50
+ '@vitest/browser': 3.1.4(playwright@1.52.0)(vite@6.3.5(@types/node@20.17.50)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))(vitest@3.1.4)
+ transitivePeerDependencies:
+ - jiti
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
vitest@3.1.4(@types/node@22.15.21)(@vitest/browser@3.1.4)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0):
dependencies:
'@vitest/expect': 3.1.4
@@ -13476,6 +13698,8 @@ snapshots:
word-wrap@1.2.5: {}
+ wordwrap@0.0.3: {}
+
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0