From fc0350735c8cd42a60e1152add9cb49da5c39e62 Mon Sep 17 00:00:00 2001 From: Niels Klomp Date: Thu, 13 Jul 2023 00:15:41 +0200 Subject: [PATCH] feat: Move VC API endpoints to functions, to more easily create your own API server, only supporting certain endpoints --- packages/w3c-vc-api/__tests__/agent.ts | 17 +- packages/w3c-vc-api/package.json | 7 +- packages/w3c-vc-api/src/VCAPIServer.ts | 283 ----------------------- packages/w3c-vc-api/src/api-functions.ts | 183 +++++++++++++++ packages/w3c-vc-api/src/index.ts | 3 +- packages/w3c-vc-api/src/types.ts | 68 ++++++ packages/w3c-vc-api/src/vc-api-server.ts | 85 +++++++ 7 files changed, 344 insertions(+), 302 deletions(-) delete mode 100644 packages/w3c-vc-api/src/VCAPIServer.ts create mode 100644 packages/w3c-vc-api/src/api-functions.ts create mode 100644 packages/w3c-vc-api/src/vc-api-server.ts diff --git a/packages/w3c-vc-api/__tests__/agent.ts b/packages/w3c-vc-api/__tests__/agent.ts index 4adf2e758..be7c26014 100644 --- a/packages/w3c-vc-api/__tests__/agent.ts +++ b/packages/w3c-vc-api/__tests__/agent.ts @@ -25,7 +25,7 @@ import { KeyManager } from '@veramo/key-manager' import { KeyManagementSystem, SecretBox } from '@veramo/kms-local' import Debug from 'debug' import { Resolver } from 'did-resolver' -import { VCAPIServer } from '../src' +import { VcApiServer } from '../src' import { DB_CONNECTION_NAME, DB_ENCRYPTION_KEY, getDbConnection } from './database' import { JwkDIDProvider } from '@sphereon/ssi-sdk-ext.did-provider-jwk' @@ -62,24 +62,11 @@ const PRIVATE_UPDATE_KEY_HEX = '7288a92f6219c873446abd1f8d26fcbbe1caa5274b47f6f0 // const RP_DID_KID = `${RP_DID}#auth-key` export const resolver = new Resolver({ - /*// const SPHEREON_UNIRESOLVER_RESOLVE_URL = 'https://uniresolver.test.sphereon.io/1.0/identifiers' - ...getUniResolver('jwk', { - resolveUrl: DIF_UNIRESOLVER_RESOLVE_URL - }), - ...getUniResolver('ion', { - resolveUrl: DIF_UNIRESOLVER_RESOLVE_URL - }), - ..getUniResolver('lto', { - resolveUrl: SPHEREON_UNIRESOLVER_RESOLVE_URL - }),*/ ...getUniResolver('ethr', { resolveUrl: DIF_UNIRESOLVER_RESOLVE_URL, }), ...getDidKeyResolver(), ...getDidJwkResolver(), - ...getUniResolver('jwk', { - resolveUrl: DIF_UNIRESOLVER_RESOLVE_URL, - }), ...getDidIonResolver(), }) @@ -202,7 +189,7 @@ agent }) .finally( () => - new VCAPIServer({ + new VcApiServer({ opts: { issueCredentialOpts: { proofFormat: 'lds', diff --git a/packages/w3c-vc-api/package.json b/packages/w3c-vc-api/package.json index 8e389a172..930bb4e98 100644 --- a/packages/w3c-vc-api/package.json +++ b/packages/w3c-vc-api/package.json @@ -8,12 +8,13 @@ "build": "tsc --build", "build:clean": "tsc --build --clean && tsc --build", "start:prod": "node build/index.js", - "start:dev": "ts-node __tests__/RestAPI.ts" + "start:dev": "ts-node __tests__/agent.ts" }, "dependencies": { "@sphereon/did-auth-siop": "0.3.2-unstable.6", "@sphereon/ssi-sdk.kv-store-temp": "workspace:*", "@sphereon/ssi-sdk.presentation-exchange": "workspace:*", + "@sphereon/ssi-sdk.core": "workspace:*", "@sphereon/ssi-types": "workspace:*", "@types/uuid": "^9.0.1", "@veramo/core": "4.2.0", @@ -32,8 +33,8 @@ "@sphereon/did-uni-client": "^0.6.0", "@sphereon/pex": "^2.0.1", "@sphereon/pex-models": "^2.0.2", - "@sphereon/ssi-sdk-ext.did-provider-jwk": "0.12.2-next.3", - "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.12.2-next.3", + "@sphereon/ssi-sdk-ext.did-provider-jwk": "0.12.2-next.4", + "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.12.2-next.4", "@sphereon/ssi-sdk.data-store": "workspace:*", "@sphereon/ssi-sdk.vc-handler-ld-local": "workspace:*", "@types/body-parser": "^1.19.2", diff --git a/packages/w3c-vc-api/src/VCAPIServer.ts b/packages/w3c-vc-api/src/VCAPIServer.ts deleted file mode 100644 index 6708d1663..000000000 --- a/packages/w3c-vc-api/src/VCAPIServer.ts +++ /dev/null @@ -1,283 +0,0 @@ -// noinspection JSUnusedGlobalSymbols - -import { CredentialPayload, TAgent, VerifiableCredential } from '@veramo/core' -import { ProofFormat } from '@veramo/core/src/types/ICredentialIssuer' -import { W3CVerifiableCredential } from '@veramo/core/src/types/vc-data-model' -import bodyParser from 'body-parser' -import cookieParser from 'cookie-parser' -import * as dotenv from 'dotenv-flow' -import express, { Express, Request, Response } from 'express' -import { v4 } from 'uuid' -import { IRequiredPlugins } from './types' - -export interface IVCAPIOpts { - issueCredentialOpts?: IIssueOpts - serverOpts?: IServerOpts -} - -export interface IServerOpts { - port?: number // The port to listen on - cookieSigningKey?: string - hostname?: string // defaults to "0.0.0.0", meaning it will listen on all IP addresses. Can be an IP address or hostname -} - -export interface IIssueOpts { - issueCredentialPath?: string - getCredentialsPath?: string - getCredentialPath?: string - deleteCredentialPath?: string - verifyCredentialPath?: string - verifyPresentationPath?: string - - persistIssuedCredentials?: boolean // Whether the issuer persists issued credentials or not. Defaults to true - - /** - * The desired format for the VerifiablePresentation to be created. - */ - proofFormat: ProofFormat - - /** - * Remove payload members during JWT-JSON transformation. Defaults to `true`. - * See https://www.w3.org/TR/vc-data-model/#jwt-encoding - */ - removeOriginalFields?: boolean - - /** - * [Optional] The ID of the key that should sign this credential. - * If this is not specified, the first matching key will be used. - */ - keyRef?: string - - /** - * When dealing with JSON-LD you also MUST provide the proper contexts. - * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are not preloaded. - * The context definitions SHOULD rather be provided at startup instead of being fetched. - * - * Defaults to `false` - */ - fetchRemoteContexts?: boolean -} - -export interface IIssueOptionsPayload { - created?: string - challenge?: string - domain?: string - credentialStatus?: { - type: string - } -} - -export interface ChallengeOptsPayload { - challenge?: string - domain?: string -} - -export class VCAPIServer { - private readonly _express: Express - private readonly _agent: TAgent - private readonly _opts?: IVCAPIOpts - - constructor(args: { agent: TAgent; express?: Express; opts?: IVCAPIOpts }) { - const { agent, opts } = args - this._agent = agent - this._opts = opts - const existingExpress = !!args.express - this._express = args.express ?? express() - this.setupExpress(existingExpress) - - // Credential endpoints - this.issueCredentialEndpoint() - this.getCredentialEndpoint() - this.getCredentialsEndpoint() - this.deleteCredentialEndpoint() // not in spec. TODO: Authz - this.verifyCredentialEndpoint() - } - - get agent(): TAgent { - return this._agent - } - - get opts(): IVCAPIOpts | undefined { - return this._opts - } - - get express(): Express { - return this._express - } - - private setupExpress(existingExpress: boolean) { - dotenv.config() - if (!existingExpress) { - const port = this.opts?.serverOpts?.port || process.env.PORT || 5000 - const secret = this.opts?.serverOpts?.cookieSigningKey || process.env.COOKIE_SIGNING_KEY - const hostname = this.opts?.serverOpts?.hostname || '0.0.0.0' - this._express.use((req, res, next) => { - res.header('Access-Control-Allow-Origin', '*') - // Request methods you wish to allow - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE') - - // Request headers you wish to allow - res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type') - - // Set to true if you need the website to include cookies in the requests sent - // to the API (e.g. in case you use sessions) - res.setHeader('Access-Control-Allow-Credentials', 'true') - next() - }) - // this.express.use(cors({ credentials: true })); - // this.express.use('/proxy', proxy('www.gssoogle.com')); - this._express.use(bodyParser.urlencoded({ extended: true })) - this._express.use(bodyParser.json()) - this._express.use(cookieParser(secret)) - this._express.listen(port as number, hostname, () => console.log(`Listening on ${hostname}, port ${port}`)) - } - } - - private static sendErrorResponse(response: Response, statusCode: number, message: string) { - console.log(message) - response.statusCode = statusCode - response.status(statusCode).send(message) - } - - private getCredentialsEndpoint() { - this._express.get(this.opts?.issueCredentialOpts?.getCredentialsPath ?? '/credentials', async (request: Request, response: Response) => { - try { - const uniqueVCs = await this.agent.dataStoreORMGetVerifiableCredentials() - response.statusCode = 202 - return response.send(uniqueVCs.map((uVC) => uVC.verifiableCredential)) - } catch (e) { - console.log(e) - return VCAPIServer.sendErrorResponse(response, 500, e.message as string) - } - }) - } - - private getCredentialEndpoint() { - this._express.get(this.opts?.issueCredentialOpts?.getCredentialPath ?? '/credentials/:id', async (request: Request, response: Response) => { - try { - const id = request.params.id - if (!id) { - return VCAPIServer.sendErrorResponse(response, 400, 'no id provided') - } - let vcInfo = await this.getCredentialByIdOrHash(id) - if (!vcInfo.vc) { - return VCAPIServer.sendErrorResponse(response, 404, `id ${id} not found`) - } - response.statusCode = 200 - return response.send(vcInfo.vc) - } catch (e) { - console.log(e) - return VCAPIServer.sendErrorResponse(response, 500, e.message as string) - } - }) - } - - private verifyCredentialEndpoint() { - this._express.post( - this.opts?.issueCredentialOpts?.verifyCredentialPath ?? '/credentials/verify', - async (request: Request, response: Response) => { - try { - console.log(request.body) - const credential: W3CVerifiableCredential = request.body.verifiableCredential - // const options: IIssueOptionsPayload = request.body.options - if (!credential) { - return VCAPIServer.sendErrorResponse(response, 400, 'No verifiable credential supplied') - } - const verifyResult = await this.agent.verifyCredential({ - credential, - fetchRemoteContexts: this.opts?.issueCredentialOpts?.fetchRemoteContexts, - }) - - response.statusCode = 200 - return response.send(verifyResult) - } catch (e) { - console.log(e) - return VCAPIServer.sendErrorResponse(response, 500, e.message as string) - } - } - ) - } - - private deleteCredentialEndpoint() { - this._express.delete(this.opts?.issueCredentialOpts?.getCredentialsPath ?? '/credentials/:id', async (request: Request, response: Response) => { - try { - const id = request.params.id - if (!id) { - return VCAPIServer.sendErrorResponse(response, 400, 'no id provided') - } - let vcInfo = await this.getCredentialByIdOrHash(id) - if (!vcInfo.vc || !vcInfo.hash) { - return VCAPIServer.sendErrorResponse(response, 404, `id ${id} not found`) - } - const success = this.agent.dataStoreDeleteVerifiableCredential({ hash: vcInfo.hash }) - if (!success) { - return VCAPIServer.sendErrorResponse(response, 400, `Could not delete Verifiable Credential with id ${id}`) - } - response.statusCode = 200 - return response.send() - } catch (e) { - console.log(e) - return VCAPIServer.sendErrorResponse(response, 500, e.message as string) - } - }) - } - - private issueCredentialEndpoint() { - this._express.post(this.opts?.issueCredentialOpts?.issueCredentialPath ?? '/credentials/issue', async (request: Request, response: Response) => { - try { - const credential: CredentialPayload = request.body.credential - // const options: IIssueOptionsPayload = request.body.options - if (!credential) { - return VCAPIServer.sendErrorResponse(response, 400, 'No credential supplied') - } - if (!credential.id) { - credential.id = `urn:uuid:${v4()}` - } - const issueOpts = this.opts?.issueCredentialOpts - const vc = await this._agent.createVerifiableCredential({ - credential, - save: issueOpts?.persistIssuedCredentials ?? true, - proofFormat: issueOpts?.proofFormat ?? 'lds', - fetchRemoteContexts: issueOpts?.fetchRemoteContexts || true, - }) - response.statusCode = 201 - return response.send({ verifiableCredential: vc }) - } catch (e) { - console.log(e) - return VCAPIServer.sendErrorResponse(response, 500, e.message as string) - } - }) - } - - private async getCredentialByIdOrHash(idOrHash: string): Promise<{ - id: string - hash?: string - vc?: VerifiableCredential - }> { - let vc: VerifiableCredential - let hash: string - const uniqueVCs = await this.agent.dataStoreORMGetVerifiableCredentials({ - where: [ - { - column: 'id', - value: [idOrHash], - op: 'Equal', - }, - ], - }) - if (uniqueVCs.length === 0) { - hash = idOrHash - vc = await this.agent.dataStoreGetVerifiableCredential({ hash }) - } else { - const uniqueVC = uniqueVCs[0] - hash = uniqueVC.hash - vc = uniqueVC.verifiableCredential - } - - return { - vc, - id: idOrHash, - hash, - } - } -} diff --git a/packages/w3c-vc-api/src/api-functions.ts b/packages/w3c-vc-api/src/api-functions.ts new file mode 100644 index 000000000..cae833f11 --- /dev/null +++ b/packages/w3c-vc-api/src/api-functions.ts @@ -0,0 +1,183 @@ +import { CredentialPayload, VerifiableCredential } from '@veramo/core' +import { W3CVerifiableCredential } from '@veramo/core/src/types/vc-data-model' +import { Request, Response, Router } from 'express' +import { v4 } from 'uuid' +import { IRequiredContext, IVCAPIIssueOpts } from './types' + +export function issueCredentialEndpoint( + router: Router, + context: IRequiredContext, + opts?: { + issueCredentialOpts?: IVCAPIIssueOpts + issueCredentialPath?: string + persistIssuedCredentials?: boolean + } +) { + router.post(opts?.issueCredentialPath ?? '/credentials/issue', async (request: Request, response: Response) => { + try { + const credential: CredentialPayload = request.body.credential + if (!credential) { + return sendErrorResponse(response, 400, 'No credential supplied') + } + if (!credential.id) { + credential.id = `urn:uuid:${v4()}` + } + const issueOpts: IVCAPIIssueOpts | undefined = opts?.issueCredentialOpts + const vc = await context.agent.createVerifiableCredential({ + credential, + save: opts?.persistIssuedCredentials ?? true, + proofFormat: issueOpts?.proofFormat ?? 'lds', + fetchRemoteContexts: issueOpts?.fetchRemoteContexts || true, + }) + response.statusCode = 201 + return response.send({ verifiableCredential: vc }) + } catch (e) { + return sendErrorResponse(response, 500, e.message as string, e) + } + }) +} + +export function getCredentialsEndpoint( + router: Router, + context: IRequiredContext, + opts?: { + getCredentialsPath?: string + } +) { + router.get(opts?.getCredentialsPath ?? '/credentials', async (request: Request, response: Response) => { + try { + const uniqueVCs = await context.agent.dataStoreORMGetVerifiableCredentials() + response.statusCode = 202 + return response.send(uniqueVCs.map((uVC) => uVC.verifiableCredential)) + } catch (e) { + return sendErrorResponse(response, 500, e.message as string, e) + } + }) +} + +export function getCredentialEndpoint( + router: Router, + context: IRequiredContext, + opts?: { + getCredentialPath?: string + } +) { + router.get(opts?.getCredentialPath ?? '/credentials/:id', async (request: Request, response: Response) => { + try { + const id = request.params.id + if (!id) { + return sendErrorResponse(response, 400, 'no id provided') + } + let vcInfo = await getCredentialByIdOrHash(context, id) + if (!vcInfo.vc) { + return sendErrorResponse(response, 404, `id ${id} not found`) + } + response.statusCode = 200 + return response.send(vcInfo.vc) + } catch (e) { + return sendErrorResponse(response, 500, e.message as string, e) + } + }) +} + +export function verifyCredentialEndpoint( + router: Router, + context: IRequiredContext, + opts?: { + verifyCredentialPath?: string + fetchRemoteContexts?: boolean + } +) { + router.post(opts?.verifyCredentialPath ?? '/credentials/verify', async (request: Request, response: Response) => { + try { + console.log(request.body) + const credential: W3CVerifiableCredential = request.body.verifiableCredential + // const options: IIssueOptionsPayload = request.body.options + if (!credential) { + return sendErrorResponse(response, 400, 'No verifiable credential supplied') + } + const verifyResult = await context.agent.verifyCredential({ + credential, + fetchRemoteContexts: opts?.fetchRemoteContexts !== false, + }) + + response.statusCode = 200 + return response.send(verifyResult) + } catch (e) { + return sendErrorResponse(response, 500, e.message as string, e) + } + }) +} + +export function deleteCredentialEndpoint( + router: Router, + context: IRequiredContext, + opts?: { + deleteCredentialsPath?: string + } +) { + router.delete(opts?.deleteCredentialsPath ?? '/credentials/:id', async (request: Request, response: Response) => { + try { + const id = request.params.id + if (!id) { + return sendErrorResponse(response, 400, 'no id provided') + } + let vcInfo = await getCredentialByIdOrHash(context, id) + if (!vcInfo.vc || !vcInfo.hash) { + return sendErrorResponse(response, 404, `id ${id} not found`) + } + const success = context.agent.dataStoreDeleteVerifiableCredential({ hash: vcInfo.hash }) + if (!success) { + return sendErrorResponse(response, 400, `Could not delete Verifiable Credential with id ${id}`) + } + response.statusCode = 200 + return response.send() + } catch (e) { + return sendErrorResponse(response, 500, e.message as string, e) + } + }) +} + +function sendErrorResponse(response: Response, statusCode: number, message: string, error?: Error) { + console.log(message) + if (error) { + console.log(error) + } + response.statusCode = statusCode + return response.status(statusCode).send(message) +} + +export async function getCredentialByIdOrHash( + context: IRequiredContext, + idOrHash: string +): Promise<{ + id: string + hash?: string + vc?: VerifiableCredential +}> { + let vc: VerifiableCredential + let hash: string + const uniqueVCs = await context.agent.dataStoreORMGetVerifiableCredentials({ + where: [ + { + column: 'id', + value: [idOrHash], + op: 'Equal', + }, + ], + }) + if (uniqueVCs.length === 0) { + hash = idOrHash + vc = await context.agent.dataStoreGetVerifiableCredential({ hash }) + } else { + const uniqueVC = uniqueVCs[0] + hash = uniqueVC.hash + vc = uniqueVC.verifiableCredential + } + + return { + vc, + id: idOrHash, + hash, + } +} diff --git a/packages/w3c-vc-api/src/index.ts b/packages/w3c-vc-api/src/index.ts index ae323cb46..49fb20c71 100644 --- a/packages/w3c-vc-api/src/index.ts +++ b/packages/w3c-vc-api/src/index.ts @@ -1,5 +1,6 @@ /** * @public */ -export * from './VCAPIServer' +export * from './vc-api-server' export * from './types' +export * from './api-functions' diff --git a/packages/w3c-vc-api/src/types.ts b/packages/w3c-vc-api/src/types.ts index 85702e755..2130cb0d5 100644 --- a/packages/w3c-vc-api/src/types.ts +++ b/packages/w3c-vc-api/src/types.ts @@ -10,6 +10,7 @@ import { IResolver, } from '@veramo/core' import { IPresentationExchange } from '@sphereon/ssi-sdk.presentation-exchange' +import { ProofFormat } from '@veramo/core/src/types/ICredentialIssuer' export type IRequiredPlugins = IDataStore & IDataStoreORM & @@ -21,3 +22,70 @@ export type IRequiredPlugins = IDataStore & ICredentialPlugin & IResolver export type IRequiredContext = IAgentContext + +export interface IVCAPIOpts { + pathOpts?: IVCAPIPathOpts + issueCredentialOpts?: IVCAPIIssueOpts + + serverOpts?: IServerOpts +} + +export interface IServerOpts { + port?: number // The port to listen on + cookieSigningKey?: string + hostname?: string // defaults to "0.0.0.0", meaning it will listen on all IP addresses. Can be an IP address or hostname +} + +export interface IVCAPIPathOpts { + basePath?: string + issueCredentialPath?: string + getCredentialsPath?: string + getCredentialPath?: string + deleteCredentialPath?: string + verifyCredentialPath?: string + verifyPresentationPath?: string +} + +export interface IVCAPIIssueOpts { + persistIssuedCredentials?: boolean // Whether the issuer persists issued credentials or not. Defaults to true + + /** + * The desired format for the VerifiablePresentation to be created. + */ + proofFormat: ProofFormat + + /** + * Remove payload members during JWT-JSON transformation. Defaults to `true`. + * See https://www.w3.org/TR/vc-data-model/#jwt-encoding + */ + removeOriginalFields?: boolean + + /** + * [Optional] The ID of the key that should sign this credential. + * If this is not specified, the first matching key will be used. + */ + keyRef?: string + + /** + * When dealing with JSON-LD you also MUST provide the proper contexts. + * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are not preloaded. + * The context definitions SHOULD rather be provided at startup instead of being fetched. + * + * Defaults to `false` + */ + fetchRemoteContexts?: boolean +} + +export interface IIssueOptionsPayload { + created?: string + challenge?: string + domain?: string + credentialStatus?: { + type: string + } +} + +export interface ChallengeOptsPayload { + challenge?: string + domain?: string +} diff --git a/packages/w3c-vc-api/src/vc-api-server.ts b/packages/w3c-vc-api/src/vc-api-server.ts new file mode 100644 index 000000000..448a327ee --- /dev/null +++ b/packages/w3c-vc-api/src/vc-api-server.ts @@ -0,0 +1,85 @@ +import { agentContext } from '@sphereon/ssi-sdk.core' +import { TAgent } from '@veramo/core' +import bodyParser from 'body-parser' +import cookieParser from 'cookie-parser' +import * as dotenv from 'dotenv-flow' +import express, { Express } from 'express' +import { + deleteCredentialEndpoint, + getCredentialEndpoint, + getCredentialsEndpoint, + issueCredentialEndpoint, + verifyCredentialEndpoint, +} from './api-functions' +import { IRequiredPlugins, IVCAPIOpts } from './types' + +export class VcApiServer { + private readonly _express: Express + private readonly _agent: TAgent + private readonly _opts?: IVCAPIOpts + + constructor(args: { agent: TAgent; express?: Express; opts?: IVCAPIOpts }) { + const { agent, opts } = args + this._agent = agent + this._opts = opts + const existingExpress = !!args.express + this._express = args.express ?? express() + this.setupExpress(existingExpress) + const router = express.Router() + const context = agentContext(agent) + + // Credential endpoints + issueCredentialEndpoint(router, context, { + issueCredentialOpts: opts?.issueCredentialOpts, + issueCredentialPath: opts?.pathOpts?.issueCredentialPath, + }) + getCredentialEndpoint(router, context, { getCredentialPath: opts?.pathOpts?.getCredentialPath }) + getCredentialsEndpoint(router, context, { getCredentialsPath: opts?.pathOpts?.getCredentialsPath }) + deleteCredentialEndpoint(router, context, { deleteCredentialsPath: opts?.pathOpts?.deleteCredentialPath }) // not in spec. TODO: Authz + verifyCredentialEndpoint(router, context, { + verifyCredentialPath: opts?.pathOpts?.verifyCredentialPath, + fetchRemoteContexts: opts?.issueCredentialOpts?.fetchRemoteContexts, + }) + this._express.use(opts?.pathOpts?.basePath ?? '', router) + } + + get agent(): TAgent { + return this._agent + } + + get opts(): IVCAPIOpts | undefined { + return this._opts + } + + get express(): Express { + return this._express + } + + private setupExpress(existingExpress: boolean) { + dotenv.config() + if (!existingExpress) { + const port = this.opts?.serverOpts?.port || process.env.PORT || 5000 + const secret = this.opts?.serverOpts?.cookieSigningKey || process.env.COOKIE_SIGNING_KEY + const hostname = this.opts?.serverOpts?.hostname || '0.0.0.0' + this._express.use((req, res, next) => { + res.header('Access-Control-Allow-Origin', '*') + // Request methods you wish to allow + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE') + + // Request headers you wish to allow + res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type') + + // Set to true if you need the website to include cookies in the requests sent + // to the API (e.g. in case you use sessions) + res.setHeader('Access-Control-Allow-Credentials', 'true') + next() + }) + // this.express.use(cors({ credentials: true })); + // this.express.use('/proxy', proxy('www.gssoogle.com')); + this._express.use(bodyParser.urlencoded({ extended: true })) + this._express.use(bodyParser.json()) + this._express.use(cookieParser(secret)) + this._express.listen(port as number, hostname, () => console.log(`Listening on ${hostname}, port ${port}`)) + } + } +}