From 23ed0dc0b5fba7471072f82bdb66b524fde00bc5 Mon Sep 17 00:00:00 2001 From: Mirko Mollik Date: Mon, 22 Apr 2024 18:34:57 +0200 Subject: [PATCH] fix: use jwks instead of dids Signed-off-by: Mirko Mollik --- apps/backend/.gitignore | 1 + apps/backend/README.md | 24 + apps/backend/package.json | 11 +- apps/backend/src/db/db.module.ts | 62 ++- .../backend/src/keys/dto/proof-request.dto.ts | 3 - apps/backend/src/keys/keys.service.ts | 13 +- .../src/oid4vc/oid4vci/oid4vci.service.ts | 29 +- .../src/oid4vc/oid4vp/oid4vp.service.ts | 5 +- apps/holder/package.json | 3 +- .../src/app/app.component.html | 4 +- .../src/app/app.component.scss | 2 + .../browser-extension/src/app/app.config.ts | 1 - .../projects/pwa/src/app/app.component.html | 8 +- .../projects/pwa/src/app/app.component.scss | 9 +- .../pwa/src/app/scanner/scanner.component.ts | 14 +- .../credentials-list.component.html | 35 +- .../credentials-list.component.scss | 4 + .../credentials-list.component.ts | 26 +- .../issuance-request.component.ts | 5 +- .../shared/settings/settings.component.html | 19 +- .../shared/settings/settings.component.ts | 14 +- apps/issuer/src/did.ts | 34 -- apps/issuer/src/keys.ts | 15 +- apps/issuer/src/main.ts | 72 +-- apps/verifier/src/keys.ts | 22 +- apps/verifier/src/main.ts | 36 +- docker/browser.Dockerfile | 2 + pnpm-lock.yaml | 418 ++++++++++++++++-- 28 files changed, 713 insertions(+), 178 deletions(-) create mode 100644 apps/backend/README.md delete mode 100644 apps/issuer/src/did.ts diff --git a/apps/backend/.gitignore b/apps/backend/.gitignore index 4b56acfb..981738de 100644 --- a/apps/backend/.gitignore +++ b/apps/backend/.gitignore @@ -2,6 +2,7 @@ /dist /node_modules /build +db.sqlite # Logs logs diff --git a/apps/backend/README.md b/apps/backend/README.md new file mode 100644 index 00000000..9a852e93 --- /dev/null +++ b/apps/backend/README.md @@ -0,0 +1,24 @@ +# Backend + +## Database +The backend supports multiple types of databases. The type has to be set via the environment variable `DB_TYPE`. The following types are supported: + +`postgres`: default database +If used, the following values have to be set: +```bash +DB_TYPE=postgres +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=nestjs +DB_USERNAME=user +DB_PASSWORD=pass +``` + +`sqlite` +If used, the following values have to be set: +```bash +DB_TYPE=sqlite +DB_NAME=db.sqlite +``` + +There are no specific requirements for the used database, so using other types like `mysql` are possible to be added later. \ No newline at end of file diff --git a/apps/backend/package.json b/apps/backend/package.json index 5908f3c7..2db29279 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -46,6 +46,7 @@ "pg": "^8.11.3", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", + "sqlite3": "^5.1.7", "typeorm": "^0.3.20", "uuid": "^9.0.1" }, @@ -68,13 +69,19 @@ "typescript": "^5.1.3" }, "jest": { - "moduleFileExtensions": ["js", "json", "ts"], + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], "rootDir": "src", "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" }, - "collectCoverageFrom": ["**/*.(t|j)s"], + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], "coverageDirectory": "../coverage", "testEnvironment": "node" } diff --git a/apps/backend/src/db/db.module.ts b/apps/backend/src/db/db.module.ts index b5cafc1e..acdfcdcb 100644 --- a/apps/backend/src/db/db.module.ts +++ b/apps/backend/src/db/db.module.ts @@ -2,12 +2,34 @@ import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import * as Joi from 'joi'; +import { DatabaseType } from 'typeorm'; export const DB_VALIDATION_SCHEMA = { - DB_HOST: Joi.string().required(), - DB_PORT: Joi.number().required(), - DB_USERNAME: Joi.string().required(), - DB_PASSWORD: Joi.string().required(), + DB_TYPE: Joi.string().default('postgres'), + DB_HOST: Joi.string().when('DB_TYPE', { + is: 'postgres', + // biome-ignore lint/suspicious/noThenProperty: + then: Joi.required(), + otherwise: Joi.optional(), + }), + DB_PORT: Joi.number().when('DB_TYPE', { + is: 'postgres', + // biome-ignore lint/suspicious/noThenProperty: + then: Joi.required(), + otherwise: Joi.optional(), + }), + DB_USERNAME: Joi.string().when('DB_TYPE', { + is: 'postgres', + // biome-ignore lint/suspicious/noThenProperty: + then: Joi.required(), + otherwise: Joi.optional(), + }), + DB_PASSWORD: Joi.string().when('DB_TYPE', { + is: 'postgres', + // biome-ignore lint/suspicious/noThenProperty: + then: Joi.required(), + otherwise: Joi.optional(), + }), DB_NAME: Joi.string().required(), }; @@ -16,16 +38,28 @@ export const DB_VALIDATION_SCHEMA = { TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], - useFactory: (configService: ConfigService) => ({ - type: 'postgres', - host: configService.get('DB_HOST'), - port: configService.get('DB_PORT'), - username: configService.get('DB_USERNAME'), - password: configService.get('DB_PASSWORD'), - database: configService.get('DB_NAME'), - synchronize: true, - autoLoadEntities: true, - }), + useFactory: (configService: ConfigService) => { + switch (configService.get('DB_TYPE') as DatabaseType) { + case 'sqlite': + return { + type: 'sqlite', + database: configService.get('DB_NAME'), + synchronize: true, + autoLoadEntities: true, + }; + case 'postgres': + return { + type: 'postgres', + host: configService.get('DB_HOST'), + port: configService.get('DB_PORT'), + username: configService.get('DB_USERNAME'), + password: configService.get('DB_PASSWORD'), + database: configService.get('DB_NAME'), + synchronize: true, + autoLoadEntities: true, + }; + } + }, }), ], }) diff --git a/apps/backend/src/keys/dto/proof-request.dto.ts b/apps/backend/src/keys/dto/proof-request.dto.ts index 158837dd..5a8cade4 100644 --- a/apps/backend/src/keys/dto/proof-request.dto.ts +++ b/apps/backend/src/keys/dto/proof-request.dto.ts @@ -6,9 +6,6 @@ export class ProofRequest { @IsOptional() kid?: string; - @IsString() - aud: string; - @IsObject() payload: JWTPayload; } diff --git a/apps/backend/src/keys/keys.service.ts b/apps/backend/src/keys/keys.service.ts index 68f17b76..20052083 100644 --- a/apps/backend/src/keys/keys.service.ts +++ b/apps/backend/src/keys/keys.service.ts @@ -124,17 +124,18 @@ export class KeysService { where: { id: newKey.id }, }); } + //TODO: add the key id when the key is interset into the database. For this the primary get has to be generated first + key.publicKey.kid = key.id; const jwk = await importJWK(key.privateKey, 'ES256'); - key.publicKey.kid = key.id; - const kid = this.encodeDidJWK(key.publicKey); return { jwt: await new SignJWT({ ...value.payload }) - .setProtectedHeader({ alg: 'ES256', kid, typ: 'openid4vci-proof+jwt' }) + .setProtectedHeader({ + alg: 'ES256', + typ: 'openid4vci-proof+jwt', + jwk: key.publicKey, + }) .setIssuedAt() - .setIssuer(kid) - .setSubject(kid) - // .setAudience(value.payload.payload.aud!) .setExpirationTime('2h') .sign(jwk), }; diff --git a/apps/backend/src/oid4vc/oid4vci/oid4vci.service.ts b/apps/backend/src/oid4vc/oid4vci/oid4vci.service.ts index e1a3791f..93fcad6a 100644 --- a/apps/backend/src/oid4vc/oid4vci/oid4vci.service.ts +++ b/apps/backend/src/oid4vc/oid4vci/oid4vci.service.ts @@ -4,6 +4,7 @@ import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc'; import { OpenID4VCIClient } from '@sphereon/oid4vci-client'; import { Alg, + JwtVerifyResult, type CredentialSupported, type CredentialSupportedSdJwtVc, type Jwt, @@ -17,6 +18,7 @@ import { KeysService } from 'src/keys/keys.service'; import { v4 as uuid } from 'uuid'; import { Oid4vciParseRepsonse } from './dto/parse-response.dto'; import { Oid4vciParseRequest } from './dto/parse-request.dto'; +import { decodeJwt } from 'jose'; type Session = { //instead of storing the client, we could also generate it on demand. In this case we need to store the uri @@ -92,25 +94,22 @@ export class Oid4vciService { key = keys[0]; } const proofCallbacks: ProofOfPossessionCallbacks = { - // verifyCallback: async (args: { - // jwt: string; - // kid?: string; - // }): Promise> => { - // console.log(args); - // return Promise.resolve({ - // jwt: JSON.parse(args.jwt) as Jwt, - // alg: 'ES256', - // }); - // }, - signCallback: async (args: Jwt): Promise => { - return this.keysService + verifyCallback: async (args: { + jwt: string; + }): Promise> => + Promise.resolve({ + jwt: decodeJwt(args.jwt), + alg: Alg.ES256, + //instead of using the key referene, we could extract the key from the jwt + jwk: key.publicKey, + }), + signCallback: async (args: Jwt): Promise => + this.keysService .proof(user, { payload: args.payload, kid: key.id, - aud: '', }) - .then((response) => response.jwt); - }, + .then((response) => response.jwt), }; await data.client.acquireAccessToken(); for (const credential of data.credentials) { diff --git a/apps/backend/src/oid4vc/oid4vp/oid4vp.service.ts b/apps/backend/src/oid4vc/oid4vp/oid4vp.service.ts index 33846e38..a1fe240c 100644 --- a/apps/backend/src/oid4vc/oid4vp/oid4vp.service.ts +++ b/apps/backend/src/oid4vc/oid4vp/oid4vp.service.ts @@ -156,14 +156,13 @@ export class Oid4vpService { args.presentation as SdJwtDecodedVerifiableCredentialWithKbJwtInput ).kbJwt; args.selectedCredentials[0]; - //TODO: set the correct value for aud const aud = session.verifiedAuthReqWithJWT.authorizationRequest.payload.client_id; const cnf = args.presentation.decodedPayload.cnf; - const kid = this.keysService.decodeDidJWK(cnf.kid).kid as string; + //const kid = this.keysService.decodeDidJWK(cnf.kid).kid as string; const signwedKbJwt = await this.keysService.signkbJwt( user, - kid, + cnf.kid, kbJwt, aud ); diff --git a/apps/holder/package.json b/apps/holder/package.json index 39138f56..fd1b00b2 100644 --- a/apps/holder/package.json +++ b/apps/holder/package.json @@ -5,7 +5,8 @@ "ng": "ng", "start:pwa": "ng serve pwa", "build": "ng build --project pwa", - "start:extension": "concurrently --kill-others \"ng build --project browser-extension --watch\" \"nodemon\"", + "start:extension": "concurrently --kill-others \"ng build --project browser-extension --configuration development --watch\" \"nodemon\"", + "start:extension-prod": "concurrently --kill-others \"ng build --project browser-extension --watch\" \"nodemon\"", "api": "npx @openapitools/openapi-generator-cli generate -g typescript-angular -i http://localhost:3000/api-json -o projects/shared/api/kms --api-name-suffix=Kms --additional-properties=supportsES6=true,enumPropertyNaming=original,serviceSuffix=ApiService", "test": "ng test", "lint": "ng lint", diff --git a/apps/holder/projects/browser-extension/src/app/app.component.html b/apps/holder/projects/browser-extension/src/app/app.component.html index cd4a55ed..67097654 100644 --- a/apps/holder/projects/browser-extension/src/app/app.component.html +++ b/apps/holder/projects/browser-extension/src/app/app.component.html @@ -8,13 +8,13 @@ >
qr_codeqr_code_scanner scan
badgeaccount_balance_wallet credentials
diff --git a/apps/holder/projects/browser-extension/src/app/app.component.scss b/apps/holder/projects/browser-extension/src/app/app.component.scss index aa879566..750b9766 100644 --- a/apps/holder/projects/browser-extension/src/app/app.component.scss +++ b/apps/holder/projects/browser-extension/src/app/app.component.scss @@ -2,12 +2,14 @@ background-color: #D7E3FF; padding: 10px 40px; height: 84px; + position: fixed; } .content { height: calc(100vh - 84px); overflow: auto; width: 100%; + padding-bottom: 84px; } diff --git a/apps/holder/projects/browser-extension/src/app/app.config.ts b/apps/holder/projects/browser-extension/src/app/app.config.ts index 2a890d00..2fb93acc 100644 --- a/apps/holder/projects/browser-extension/src/app/app.config.ts +++ b/apps/holder/projects/browser-extension/src/app/app.config.ts @@ -14,7 +14,6 @@ function getConfiguration() { basePath: environment.backendUrl, credentials: { oauth2: () => { - console.log(localStorage.getItem('accessToken')); return localStorage.getItem('accessToken') as string; }, }, diff --git a/apps/holder/projects/pwa/src/app/app.component.html b/apps/holder/projects/pwa/src/app/app.component.html index cda1ac14..64da542f 100644 --- a/apps/holder/projects/pwa/src/app/app.component.html +++ b/apps/holder/projects/pwa/src/app/app.component.html @@ -3,14 +3,14 @@
- qr_codeqr_code_scanner - scan +
badgeaccount_balance_wallet credentials
diff --git a/apps/holder/projects/pwa/src/app/app.component.scss b/apps/holder/projects/pwa/src/app/app.component.scss index 59380e89..ed16f27a 100644 --- a/apps/holder/projects/pwa/src/app/app.component.scss +++ b/apps/holder/projects/pwa/src/app/app.component.scss @@ -2,10 +2,17 @@ background-color: #D7E3FF; padding: 10px 40px; height: 84px; - position: absolute; + position: fixed; bottom: 0px; } .info { font-size: 14px; } + +.content { + height: calc(100vh - 84px); + overflow: auto; + width: 100%; + padding-bottom: 84px; +} diff --git a/apps/holder/projects/pwa/src/app/scanner/scanner.component.ts b/apps/holder/projects/pwa/src/app/scanner/scanner.component.ts index 917aaf62..7f6d42ef 100644 --- a/apps/holder/projects/pwa/src/app/scanner/scanner.component.ts +++ b/apps/holder/projects/pwa/src/app/scanner/scanner.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { CameraDevice, Html5Qrcode } from 'html5-qrcode'; import { Html5QrcodeError } from 'html5-qrcode/esm/core'; import { MatMenuModule } from '@angular/material/menu'; @@ -29,7 +29,7 @@ type Status = 'scanning' | 'showRequest' | 'showVerificationRequest'; VerifyRequestComponent, ], }) -export class ScannerComponent implements OnInit { +export class ScannerComponent implements OnInit, OnDestroy { scanner?: Html5Qrcode; devices: CameraDevice[] = []; selectedDevice?: string; @@ -44,7 +44,6 @@ export class ScannerComponent implements OnInit { ngOnInit(): void { const fragment = this.route.snapshot.fragment; - console.log(fragment); if (fragment === 'issue') { this.getCredential(); return; @@ -79,6 +78,12 @@ export class ScannerComponent implements OnInit { }); } + async ngOnDestroy(): Promise { + if (this.scanner) { + await this.scanner.stop(); + } + } + async startCamera() { this.scanner = new Html5Qrcode('reader'); //TODO: we need to set the correct dimensions. @@ -116,9 +121,6 @@ export class ScannerComponent implements OnInit { onScanFailure(errorMessage: string, error: Html5QrcodeError) { // handle scan failure, usually better to ignore and keep scanning. - // for example: - // console.log(error.errorMessage); - // console.warn(`Code scan error = ${error}`); } getCredential() { diff --git a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.html b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.html index e234f226..38477ed8 100644 --- a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.html +++ b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.html @@ -1,4 +1,29 @@ -

My Credentials

+
+

Credentials

+ + + + + +
+ + Search + + search +
@for (credential of credentials; track credential) { {{ credential.display.name }}
} + +
+

No credentials found

+
diff --git a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.scss b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.scss index d3898d66..3fa77f92 100644 --- a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.scss +++ b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.scss @@ -31,3 +31,7 @@ margin: 0; } } + +#search { + width: 100%; +} diff --git a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.ts b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.ts index bdddac7e..48816572 100644 --- a/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.ts +++ b/apps/holder/projects/shared/credentials/credentials-list/credentials-list.component.ts @@ -11,6 +11,11 @@ import { } from '@sphereon/oid4vci-common'; import { RouterLink } from '@angular/router'; import { FlexLayoutModule } from 'ng-flex-layout'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatButtonModule } from '@angular/material/button'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; export interface CredentialList extends Credential { display: CredentialsSupportedDisplay; @@ -27,6 +32,11 @@ export interface CredentialList extends Credential { MatCardModule, CredentialsShowComponent, FlexLayoutModule, + MatIconModule, + MatMenuModule, + MatButtonModule, + ReactiveFormsModule, + MatInputModule, ], templateUrl: './credentials-list.component.html', styleUrl: './credentials-list.component.scss', @@ -34,13 +44,27 @@ export interface CredentialList extends Credential { export class CredentialsListComponent implements OnInit { credentials: CredentialList[] = []; + search: FormControl = new FormControl(''); + render: 'image' | 'card' = 'card'; constructor(private credentialsApiService: CredentialsApiService) {} async ngOnInit(): Promise { - this.credentials = await firstValueFrom( + const credentials: CredentialList[] = await firstValueFrom( this.credentialsApiService.credentialsControllerFindAll() ); + this.search.valueChanges.subscribe((value: string) => { + if (!value) { + this.credentials = credentials; + return; + } + this.credentials = credentials.filter((credential) => { + return credential.display.name + .toLowerCase() + .includes(value.toLowerCase()); + }); + }); + this.credentials = credentials; } } diff --git a/apps/holder/projects/shared/oid4vc/issuance-request/issuance-request.component.ts b/apps/holder/projects/shared/oid4vc/issuance-request/issuance-request.component.ts index 17f283fd..f771edd0 100644 --- a/apps/holder/projects/shared/oid4vc/issuance-request/issuance-request.component.ts +++ b/apps/holder/projects/shared/oid4vc/issuance-request/issuance-request.component.ts @@ -57,7 +57,10 @@ export class IssuanceRequestComponent implements OnInit { } deny() { - throw new Error('Method not implemented.'); + this.snackbar.open('Issuance Request denied', undefined, { + duration: 3000, + }); + this.router.navigate(['/']); } async accept() { await firstValueFrom( diff --git a/apps/holder/projects/shared/settings/settings.component.html b/apps/holder/projects/shared/settings/settings.component.html index f75fb488..c676a1fc 100644 --- a/apps/holder/projects/shared/settings/settings.component.html +++ b/apps/holder/projects/shared/settings/settings.component.html @@ -1,6 +1,13 @@ -
- Automate issuance and verify process - -
+ + + Automate issuance and verify process + + + + + + + + diff --git a/apps/holder/projects/shared/settings/settings.component.ts b/apps/holder/projects/shared/settings/settings.component.ts index f30537e9..4518f744 100644 --- a/apps/holder/projects/shared/settings/settings.component.ts +++ b/apps/holder/projects/shared/settings/settings.component.ts @@ -5,6 +5,9 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { SettingsService } from './settings.service'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FlexLayoutModule } from 'ng-flex-layout'; +import { MatListModule } from '@angular/material/list'; +import { HttpClient, HttpClientModule } from '@angular/common/http'; +import { firstValueFrom } from 'rxjs'; @Component({ selector: 'app-settings', @@ -14,6 +17,8 @@ import { FlexLayoutModule } from 'ng-flex-layout'; MatSlideToggleModule, ReactiveFormsModule, FlexLayoutModule, + MatListModule, + HttpClientModule, ], templateUrl: './settings.component.html', styleUrl: './settings.component.scss', @@ -23,11 +28,18 @@ export class SettingsComponent { constructor( public authService: AuthService, - public settingsService: SettingsService + public settingsService: SettingsService, + private httpClient: HttpClient ) { this.automateControl = new FormControl(this.settingsService.getAuto()); this.automateControl.valueChanges.subscribe((value) => this.settingsService.setAuto(value) ); } + async showLicense() { + const licencse = await firstValueFrom( + this.httpClient.get('/3rdpartylicenses.txt', { responseType: 'text' }) + ); + alert(licencse); + } } diff --git a/apps/issuer/src/did.ts b/apps/issuer/src/did.ts deleted file mode 100644 index 70114c0d..00000000 --- a/apps/issuer/src/did.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { type JWK, importJWK } from 'jose'; - -/** - * Decodes a DID JWK to a public key - * @param did - * @returns Json Web Key as JWK - */ -export function decodeDidJWK(did: string) { - return JSON.parse( - Buffer.from(did.split('#')[0].split(':')[2], 'base64url').toString() - ) as JWK; -} - -/** - * Encodes a public key as a DID JWK. - * @param key - * @returns - */ -export function encodeDidJWK(key: JWK) { - key.key_ops = undefined; - key.ext = undefined; - return `did:jwk:${Buffer.from(JSON.stringify(key)).toString('base64url')}`; -} - -/** - * Get the JWK from a DID and returns a key object. - * @param did encoded as a did:jwk - * @returns KeyLike object - */ -export function getJWK(did: string) { - const jwk = decodeDidJWK(did); - //We are only supoprting ES256 for now. - return importJWK(jwk, 'ES256'); -} diff --git a/apps/issuer/src/keys.ts b/apps/issuer/src/keys.ts index 0916b2f4..52a95d33 100644 --- a/apps/issuer/src/keys.ts +++ b/apps/issuer/src/keys.ts @@ -1,21 +1,26 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { ES256 } from '@sd-jwt/crypto-nodejs'; +import { JWK } from 'jose'; +import { v4 } from 'uuid'; /** * Get the keys for the issuer. If the keys do not exist, they are generated and saved to the file system. * @returns The private and public keys. */ export async function getKeys() { - let privateKey: JsonWebKey; - let publicKey: JsonWebKey; + let privateKey: JWK; + let publicKey: JWK; const folder = 'tmp'; if (!existsSync(folder)) { mkdirSync(folder); } - if (!existsSync(`${folder}/keys`)) { + if (!existsSync(`${folder}`)) { const keys = await ES256.generateKeyPair(); - privateKey = keys.privateKey; - publicKey = keys.publicKey; + privateKey = keys.privateKey as JWK; + publicKey = keys.publicKey as JWK; + //add a random key id for reference + publicKey.kid = v4(); + privateKey.kid = publicKey.kid; writeFileSync(`${folder}/private.json`, JSON.stringify(privateKey)); writeFileSync(`${folder}/public.json`, JSON.stringify(publicKey)); } else { diff --git a/apps/issuer/src/main.ts b/apps/issuer/src/main.ts index 0632a834..e6bd266d 100644 --- a/apps/issuer/src/main.ts +++ b/apps/issuer/src/main.ts @@ -1,6 +1,6 @@ import { KeyObject } from 'node:crypto'; import { ES256, digest, generateSalt } from '@sd-jwt/crypto-nodejs'; -import { SDJwtVcInstance, type SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'; +import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc'; import { Alg, type CNonceState, @@ -24,14 +24,14 @@ import expressListRoutes from 'express-list-routes'; import * as jose from 'jose'; import { JWK } from 'jose'; import { v4 } from 'uuid'; -import { getJWK } from './did.js'; -import { encodeDidJWK } from './did.js'; import { getKeys } from './keys.js'; import { disclosureFrame, metadata } from './metadata.js'; import { expressSupport } from './server.js'; const { privateKey, publicKey } = await getKeys(); +const privateKeyLike = await jose.importJWK(privateKey); + // get the signer and verifier. Only ES256 is supported for now. const signer = await ES256.getSigner(privateKey); const verifier = await ES256.getVerifier(publicKey); @@ -40,26 +40,24 @@ const verifier = await ES256.getVerifier(publicKey); const sdjwt = new SDJwtVcInstance({ signer, verifier, - signAlg: 'EdDSA', + signAlg: 'ES256', hasher: digest, hashAlg: 'SHA-256', saltGenerator: generateSalt, }); -const issuer = encodeDidJWK(publicKey as JWK); - const credentialDataSupplier: CredentialDataSupplier = async (args) => { - const claims = { - prename: 'Mirko', - surname: 'Mollik', - }; - //TODO: add values from the request. They should be added when the request was created + const jwt = jose.decodeJwt(args.credentialRequest.proof?.jwt as string); const credential: SdJwtDecodedVerifiableCredentialPayload = { iat: new Date().getTime(), - iss: issuer, + iss: args.credentialOffer.credential_offer.credential_issuer, vct: (args.credentialRequest as CredentialRequestSdJwtVc).vct, jti: v4(), - ...claims, + ...args.credentialDataSupplierInput.credentialSubject, + // validate this https://github.com/Sphereon-Opensource/OID4VCI/blob/dc70d5282479b18bcd691f99f88d6cd4ad15131f/packages/issuer/lib/VcIssuer.ts#L307 + // cnf: { + // jwk: jwt.jwk, + // }, }; return Promise.resolve({ credential, @@ -75,11 +73,9 @@ const credentialDataSupplier: CredentialDataSupplier = async (args) => { */ const signerCallback = async (jwt: Jwt, kid?: string): Promise => { //TODO: use the kid to select the correct key - const privateKey = (await jose.generateKeyPair(Alg.ES256)) - .privateKey as KeyObject; return new jose.SignJWT({ ...jwt.payload }) - .setProtectedHeader({ ...jwt.header, alg: Alg.ES256 }) - .sign(privateKey); + .setProtectedHeader({ ...jwt.header, alg: Alg.ES256, kid: privateKey.kid }) + .sign(privateKeyLike); }; /** @@ -93,21 +89,12 @@ async function jwtVerifyCallback(args: { }): Promise> { //verify the jwt const decoded = jose.decodeProtectedHeader(args.jwt); - const publicKey = await getJWK(decoded.kid as string); + const publicKey = await jose.importJWK(decoded.jwk as JWK); const result = await jose.jwtVerify(args.jwt, publicKey); - const kid = result.protectedHeader.kid ?? (args.kid as string); - const did = kid.split('#')[0]; - //TODO: do we need to extend the did document with more information? Like this is not the transformed did:jwk transformation to a did document since the key is missing. - const didDocument: DIDDocument = { - '@context': 'https://www.w3.org/ns/did/v1', - id: did, - }; const alg = result.protectedHeader.alg; return { alg, - kid, - did, - didDocument, + jwk: result.protectedHeader.jwk as JWK, jwt: { header: result.protectedHeader, payload: result.payload, @@ -128,7 +115,8 @@ const credentialSignerCallback: CredentialSignerCallback = async ( // biome-ignore lint/suspicious/noExplicitAny: correct type passing is not implemented in the lib return sdjwt.issue( args.credential as SdJwtDecodedVerifiableCredentialPayload, - disclosureFrame + disclosureFrame, + { header: { kid: privateKey.kid } } ); }; @@ -161,7 +149,10 @@ const vcIssuerServer = new OID4VCIServer(expressSupport, { */ vcIssuerServer.router.post('/request', async (req, res) => { //TODO: in production this route should be protected with a middleware that checks the authorization header! - const credentialSubject = req.body.credentialSubject ?? {}; + const credentialSubject = req.body.credentialSubject ?? { + prename: 'Max', + surname: 'Mustermann', + }; const response = await vcIssuer.createCredentialOfferURI({ credentials: [metadata.credentials_supported[0].id as string], grants: { @@ -179,6 +170,27 @@ vcIssuerServer.router.post('/request', async (req, res) => { res.send(response); }); +interface IssuerMetadata { + issuer: string; + jwks_uri?: string; + jwks?: { + keys: JWK[]; + }; +} + +/** + * Returns the issuers metadata. + */ +expressSupport.express.get('/.well-known/jwt-vc-issuer', async (req, res) => { + const metadata: IssuerMetadata = { + issuer: process.env.ISSUER_BASE_URL as string, + jwks: { + keys: [publicKey as JWK], + }, + }; + res.send(metadata); +}); + // start the webserver. expressSupport.start(); //print the routes, only for debugging purposes diff --git a/apps/verifier/src/keys.ts b/apps/verifier/src/keys.ts index 0916b2f4..e48fe911 100644 --- a/apps/verifier/src/keys.ts +++ b/apps/verifier/src/keys.ts @@ -1,5 +1,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { ES256 } from '@sd-jwt/crypto-nodejs'; +import axios from 'axios'; +import { JWK } from 'jose'; /** * Get the keys for the issuer. If the keys do not exist, they are generated and saved to the file system. @@ -12,7 +14,7 @@ export async function getKeys() { if (!existsSync(folder)) { mkdirSync(folder); } - if (!existsSync(`${folder}/keys`)) { + if (!existsSync(`${folder}`)) { const keys = await ES256.generateKeyPair(); privateKey = keys.privateKey; publicKey = keys.publicKey; @@ -24,3 +26,21 @@ export async function getKeys() { } return { privateKey, publicKey }; } + +interface IssuerMetadata { + issuer: string; + jwks: { + keys: JWK[]; + }; +} + +export async function getPublicKey(issuer: string, kid: string): Promise { + const response = await axios + .get(`${issuer}/.well-known/jwt-vc-issuer`) + .then((r) => r.data); + const key = response.jwks.keys.find((key) => key.kid === kid); + if (!key) { + throw new Error('Key not found'); + } + return key; +} diff --git a/apps/verifier/src/main.ts b/apps/verifier/src/main.ts index 9e9a54de..c4b623b2 100644 --- a/apps/verifier/src/main.ts +++ b/apps/verifier/src/main.ts @@ -23,11 +23,11 @@ import { PresentationSubmission } from '@sphereon/pex-models'; import { CompactJWT, W3CVerifiablePresentation } from '@sphereon/ssi-types'; import 'dotenv/config'; import expressListRoutes from 'express-list-routes'; -import { JWK } from 'jose'; +import { JWK, JWTPayload } from 'jose'; import { v4 } from 'uuid'; -import { decodeDidJWK, encodeDidJWK } from './did.js'; +import { encodeDidJWK } from './did.js'; import { JWkResolver } from './did.js'; -import { getKeys } from './keys.js'; +import { getKeys, getPublicKey } from './keys.js'; import { presentationDefinition } from './metadata.js'; import { expressSupport } from './server.js'; @@ -81,6 +81,7 @@ const rp = RP.builder() ) .withScope('openid') .withHasher(digest) + //TODO: check if did and kid can be blank .withSuppliedSignature(withSuppliedSignature, did, kid, SigningAlgo.ES256) .withRevocationVerification(RevocationVerification.NEVER) .withSessionManager(sessionManager) @@ -132,12 +133,23 @@ expressSupport.express.get( } ); +interface Header extends Record { + alg: string; + typ: string; + kid: string; +} + +interface Payload extends Record { + iss: string; +} + /** * Add the route to get the response object */ expressSupport.express.post( '/siop/auth-response/:correlationId', async (req, res) => { + console.log(req.body); try { req.body.presentation_submission = JSON.parse( req.body.presentation_submission @@ -149,8 +161,7 @@ expressSupport.express.post( location: PresentationDefinitionLocation.CLAIMS_VP_TOKEN, }, }); - // console.log(response); - res.send(); + res.send({}); } catch (e) { console.error(e); res.status(500).send((e as Error).message); @@ -207,11 +218,12 @@ async function presentationVerificationCallback( */ const verifier: Verifier = async (data, signature) => { const decodedVC = await sdjwtInstance.decode(`${data}.${signature}`); - const issuer: string = ( - (decodedVC.jwt as Jwt).payload as Record - ).iss as string; - //decode the issuer to get the public key. We assume the issuer is a did:jwk. - const publicKey = decodeDidJWK(issuer); + const payload = decodedVC.jwt?.payload as JWTPayload; + const header = decodedVC.jwt?.header as JWK; + const publicKey = await getPublicKey( + payload.iss as string, + header.kid as string + ); const verify = await ES256.getVerifier(publicKey); return verify(data, signature); }; @@ -238,10 +250,10 @@ async function presentationVerificationCallback( kbVerifier, }); // verify the presentation. - const sdjwt = await sdjwtInstance.verify( + await sdjwtInstance.verify( args as CompactJWT, requiredClaimKeys, - //since there is an error with the sdHash for now, we are not validating the key binding + //TODO: since there is an error with the sdHash for now, we are not validating the key binding false ); return Promise.resolve({ verified: true }); diff --git a/docker/browser.Dockerfile b/docker/browser.Dockerfile index dc8d0ea0..0b730971 100644 --- a/docker/browser.Dockerfile +++ b/docker/browser.Dockerfile @@ -32,3 +32,5 @@ RUN mkdir -p /etc/nginx && \ echo ' }' >> /etc/nginx/nginx.conf && \ echo '}' >> /etc/nginx/nginx.conf COPY --from=build /usr/src/app/apps/${PROJECT}/dist/${SUB_PROJECT}/browser . +# copy the 3rd party licenses +COPY --from=build /usr/src/app/apps/${PROJECT}/dist/${SUB_PROJECT}/3rdpartylicenses.txt . diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6434a5c2..6e71666b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,9 +92,12 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + sqlite3: + specifier: ^5.1.7 + version: 5.1.7 typeorm: specifier: ^0.3.20 - version: 0.3.20(pg@8.11.3)(ts-node@10.9.2) + version: 0.3.20(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2) uuid: specifier: ^9.0.1 version: 9.0.1 @@ -3408,6 +3411,12 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@gar/promisify@1.1.3: + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + requiresBuild: true + dev: false + optional: true + /@hapi/hoek@9.3.0: resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} dev: false @@ -4655,7 +4664,7 @@ packages: '@nestjs/core': 10.3.5(@nestjs/common@10.3.5)(@nestjs/platform-express@10.3.5)(reflect-metadata@0.2.1)(rxjs@7.8.1) reflect-metadata: 0.2.1 rxjs: 7.8.1 - typeorm: 0.3.20(pg@8.11.3)(ts-node@10.9.2) + typeorm: 0.3.20(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2) uuid: 9.0.1 dev: false @@ -4710,6 +4719,15 @@ packages: - supports-color dev: true + /@npmcli/fs@1.1.1: + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + requiresBuild: true + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.6.0 + dev: false + optional: true + /@npmcli/fs@3.1.0: resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -4742,6 +4760,17 @@ packages: npm-normalize-package-bin: 3.0.1 dev: true + /@npmcli/move-file@1.1.2: + resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} + engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs + requiresBuild: true + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + dev: false + optional: true + /@npmcli/node-gyp@3.0.0: resolution: {integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5545,6 +5574,13 @@ packages: dev: false optional: true + /@tootallnate/once@1.1.2: + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + requiresBuild: true + dev: false + optional: true + /@tootallnate/quickjs-emscripten@0.23.0: resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} requiresBuild: true @@ -6270,13 +6306,21 @@ packages: transitivePeerDependencies: - supports-color + /agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + requiresBuild: true + dependencies: + humanize-ms: 1.2.1 + dev: false + optional: true + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - dev: true /ajv-formats@2.1.1(ajv@8.12.0): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -6413,6 +6457,16 @@ packages: readable-stream: 3.6.2 dev: false + /are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: false + optional: true + /arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -6724,13 +6778,18 @@ packages: engines: {node: '>=8'} dev: true + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 + dev: false + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true /bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} @@ -6840,7 +6899,6 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true /buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -6886,6 +6944,34 @@ packages: engines: {node: '>=8'} dev: true + /cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + '@npmcli/fs': 1.1.1 + '@npmcli/move-file': 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.2.1 + unique-filename: 1.1.1 + transitivePeerDependencies: + - bluebird + dev: false + optional: true + /cacache@18.0.2: resolution: {integrity: sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -7032,6 +7118,10 @@ packages: fsevents: 2.3.3 dev: true + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -7041,8 +7131,8 @@ packages: engines: {node: '>=6.0'} dev: true - /chromedriver@123.0.1: - resolution: {integrity: sha512-YQUIP/zdlzDIRCZNCv6rEVDSY4RAxo/tDL0OiGPPuai+z8unRNqJr/9V6XTBypVFyDheXNalKt9QxEqdMPuLAQ==} + /chromedriver@123.0.4: + resolution: {integrity: sha512-3Yi7y7q35kkSAOTbRisiww/SL2w+DqafDPAaUShpSuLMmPaOvHQR0i3bm2/33QBiQ8fUb1J/MzppzVL6IDqvhA==} engines: {node: '>=18'} hasBin: true requiresBuild: true @@ -7082,7 +7172,6 @@ packages: /clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - dev: true /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} @@ -7673,6 +7762,13 @@ packages: mimic-response: 2.1.0 dev: false + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + /dedent@1.5.1: resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} peerDependencies: @@ -7689,6 +7785,11 @@ packages: type-detect: 4.0.8 dev: true + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -7987,7 +8088,6 @@ packages: requiresBuild: true dependencies: iconv-lite: 0.6.3 - dev: true optional: true /end-of-stream@1.4.4: @@ -8047,11 +8147,9 @@ packages: /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - dev: true /err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - dev: true /errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} @@ -8497,6 +8595,11 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8724,6 +8827,10 @@ packages: flat-cache: 3.2.0 dev: true + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: false + /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: @@ -8896,7 +9003,6 @@ packages: /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} @@ -8985,6 +9091,22 @@ packages: wide-align: 1.1.5 dev: false + /gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + optional: true + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -9055,6 +9177,10 @@ packages: dev: false optional: true + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -9301,7 +9427,6 @@ packages: /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - dev: true /http-deceiver@1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} @@ -9331,6 +9456,19 @@ packages: resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} dev: true + /http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + requiresBuild: true + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + dev: false + optional: true + /http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -9409,6 +9547,14 @@ packages: engines: {node: '>=16.17.0'} dev: true + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + requiresBuild: true + dependencies: + ms: 2.1.3 + dev: false + optional: true + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -9420,7 +9566,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: true /icss-utils@5.1.0(postcss@8.4.35): resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} @@ -9482,12 +9627,16 @@ packages: /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - dev: true + + /infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + requiresBuild: true + dev: false + optional: true /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} @@ -9503,6 +9652,10 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + /ini@4.1.2: resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -9701,7 +9854,6 @@ packages: /is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - dev: true /is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} @@ -10620,7 +10772,7 @@ packages: dependencies: jwk-to-pem: 2.0.5 optionalDependencies: - chromedriver: 123.0.1 + chromedriver: 123.0.4 transitivePeerDependencies: - debug - supports-color @@ -10935,6 +11087,33 @@ packages: - supports-color dev: true + /make-fetch-happen@9.1.0: + resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + agentkeepalive: 4.5.0 + cacache: 15.3.0 + http-cache-semantics: 4.1.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 6.2.1 + ssri: 8.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + /makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: @@ -11016,6 +11195,11 @@ packages: engines: {node: '>=8'} dev: false + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + /mini-css-extract-plugin@2.8.1(webpack@5.90.3): resolution: {integrity: sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==} engines: {node: '>= 12.13.0'} @@ -11078,6 +11262,15 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} requiresBuild: true + /minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + /minipass-collect@2.0.1: resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} engines: {node: '>=16 || 14 >=14.17'} @@ -11085,6 +11278,19 @@ packages: minipass: 7.0.4 dev: true + /minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: false + optional: true + /minipass-fetch@3.0.4: resolution: {integrity: sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -11101,7 +11307,6 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.3.6 - dev: true /minipass-json-stream@1.0.1: resolution: {integrity: sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==} @@ -11115,14 +11320,12 @@ packages: engines: {node: '>=8'} dependencies: minipass: 3.3.6 - dev: true /minipass-sized@1.0.3: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} dependencies: minipass: 3.3.6 - dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -11150,6 +11353,10 @@ packages: minipass: 3.3.6 yallist: 4.0.0 + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -11277,6 +11484,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -11357,6 +11568,13 @@ packages: dev: true optional: true + /node-abi@3.60.0: + resolution: {integrity: sha512-zcGgwoXbzw9NczqbGzAWL/ToDYAxv1V8gL1D67ClbdkIfeeDBbY0GelZtC25ayLvVjr2q2cloHeQV1R0QAWqRQ==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.0 + dev: false + /node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} dev: true @@ -11367,6 +11585,11 @@ packages: dev: true optional: true + /node-addon-api@7.1.0: + resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} + engines: {node: ^16 || ^18 || >= 20} + dev: false + /node-cleanup@2.1.2: resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==} dev: true @@ -11418,6 +11641,28 @@ packages: - supports-color dev: true + /node-gyp@8.4.1: + resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==} + engines: {node: '>= 10.12.0'} + hasBin: true + requiresBuild: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 9.1.0 + nopt: 5.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.6.0 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + optional: true + /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true @@ -11589,6 +11834,18 @@ packages: set-blocking: 2.0.0 dev: false + /npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + dev: false + optional: true + /nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} dependencies: @@ -11868,7 +12125,6 @@ packages: engines: {node: '>=10'} dependencies: aggregate-error: 3.1.0 - dev: true /p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} @@ -12390,6 +12646,25 @@ packages: xtend: 4.0.2 dev: false + /prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.60.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -12435,7 +12710,6 @@ packages: peerDependenciesMeta: bluebird: optional: true - dev: true /promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} @@ -12443,7 +12717,6 @@ packages: dependencies: err-code: 2.0.3 retry: 0.12.0 - dev: true /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} @@ -12507,7 +12780,6 @@ packages: end-of-stream: 1.4.4 once: 1.4.0 dev: false - optional: true /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -12562,6 +12834,16 @@ packages: iconv-lite: 0.4.24 unpipe: 1.0.0 + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: false + /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true @@ -12748,7 +13030,6 @@ packages: /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} - dev: true /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} @@ -13149,6 +13430,14 @@ packages: simple-concat: 1.0.1 dev: false + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + /simple-update-notifier@2.0.0: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} @@ -13221,6 +13510,19 @@ packages: websocket-driver: 0.7.4 dev: true + /socks-proxy-agent@6.2.1: + resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} + engines: {node: '>= 10'} + requiresBuild: true + dependencies: + agent-base: 6.0.2 + debug: 4.3.4(supports-color@5.5.0) + socks: 2.8.1 + transitivePeerDependencies: + - supports-color + dev: false + optional: true + /socks-proxy-agent@8.0.3: resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==} engines: {node: '>= 14'} @@ -13350,6 +13652,21 @@ packages: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} requiresBuild: true + /sqlite3@5.1.7: + resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} + requiresBuild: true + dependencies: + bindings: 1.5.0 + node-addon-api: 7.1.0 + prebuild-install: 7.1.2 + tar: 6.2.1 + optionalDependencies: + node-gyp: 8.4.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: false + /ssri@10.0.5: resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -13357,6 +13674,15 @@ packages: minipass: 7.0.4 dev: true + /ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + requiresBuild: true + dependencies: + minipass: 3.3.6 + dev: false + optional: true + /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -13524,6 +13850,11 @@ packages: engines: {node: '>=12'} dev: true + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -13611,6 +13942,15 @@ packages: engines: {node: '>=6'} dev: true + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + /tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -13620,7 +13960,6 @@ packages: fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true /tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} @@ -14043,6 +14382,12 @@ packages: - supports-color dev: true + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + /type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} @@ -14135,7 +14480,7 @@ packages: /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - /typeorm@0.3.20(pg@8.11.3)(ts-node@10.9.2): + /typeorm@0.3.20(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2): resolution: {integrity: sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==} engines: {node: '>=16.13.0'} hasBin: true @@ -14206,6 +14551,7 @@ packages: pg: 8.11.3 reflect-metadata: 0.2.1 sha.js: 2.4.11 + sqlite3: 5.1.7 ts-node: 10.9.2(@types/node@20.11.30)(typescript@5.2.2) tslib: 2.6.2 uuid: 9.0.1 @@ -14307,6 +14653,14 @@ packages: engines: {node: '>=4'} dev: true + /unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + requiresBuild: true + dependencies: + unique-slug: 2.0.2 + dev: false + optional: true + /unique-filename@3.0.0: resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -14314,6 +14668,14 @@ packages: unique-slug: 4.0.0 dev: true + /unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + requiresBuild: true + dependencies: + imurmurhash: 0.1.4 + dev: false + optional: true + /unique-slug@4.0.0: resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}