@sphereon/ssi-sdk.siopv2-oid4vp-rp-rest-api 0.34.1-feature.SSISDK.58.host.nonce.endpoint.145 → 0.34.1-feature.SSISDK.62.218
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +186 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -9
- package/dist/index.d.ts +49 -9
- package/dist/index.js +185 -132
- package/dist/index.js.map +1 -1
- package/package.json +21 -18
- package/src/index.ts +1 -1
- package/src/middleware/validationMiddleware.ts +20 -0
- package/src/siop-api-functions.ts +31 -20
- package/src/siopv2-rp-api-server.ts +9 -10
- package/src/types/types.ts +60 -3
- package/src/universal-oid4vp-api-functions.ts +195 -0
- package/src/webapp-api-functions.ts +26 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.siopv2-oid4vp-rp-rest-api",
|
|
3
|
-
"version": "0.34.1-feature.SSISDK.
|
|
3
|
+
"version": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
"start:dev": "ts-node __tests__/RestAPI.ts"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@sphereon/did-auth-siop": "0.19.1-feature.SSISDK.
|
|
27
|
-
"@sphereon/ssi-express-support": "0.34.1-feature.SSISDK.
|
|
28
|
-
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.
|
|
29
|
-
"@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.SSISDK.
|
|
30
|
-
"@sphereon/ssi-sdk.kv-store-temp": "0.34.1-feature.SSISDK.
|
|
31
|
-
"@sphereon/ssi-sdk.pd-manager": "0.34.1-feature.SSISDK.
|
|
32
|
-
"@sphereon/ssi-sdk.presentation-exchange": "0.34.1-feature.SSISDK.
|
|
33
|
-
"@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.SSISDK.
|
|
34
|
-
"@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth": "0.34.1-feature.SSISDK.
|
|
35
|
-
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.
|
|
26
|
+
"@sphereon/did-auth-siop": "0.19.1-feature.SSISDK.62.162",
|
|
27
|
+
"@sphereon/ssi-express-support": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
28
|
+
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
29
|
+
"@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
30
|
+
"@sphereon/ssi-sdk.kv-store-temp": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
31
|
+
"@sphereon/ssi-sdk.pd-manager": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
32
|
+
"@sphereon/ssi-sdk.presentation-exchange": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
33
|
+
"@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
34
|
+
"@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
35
|
+
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
36
36
|
"@veramo/core": "4.2.0",
|
|
37
37
|
"@veramo/credential-w3c": "4.2.0",
|
|
38
38
|
"awesome-qr": "^2.1.5-rc.0",
|
|
@@ -44,18 +44,21 @@
|
|
|
44
44
|
"express": "^4.19.2",
|
|
45
45
|
"short-uuid": "^4.2.2",
|
|
46
46
|
"swagger-ui-express": "^5.0.1",
|
|
47
|
-
"uuid": "^9.0.1"
|
|
47
|
+
"uuid": "^9.0.1",
|
|
48
|
+
"zod": "^4.1.5"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@decentralized-identity/ion-sdk": "^0.6.0",
|
|
51
|
-
"@sphereon/did-auth-siop-adapter": "0.19.1-feature.SSISDK.
|
|
52
|
+
"@sphereon/did-auth-siop-adapter": "0.19.1-feature.SSISDK.62.162",
|
|
52
53
|
"@sphereon/did-uni-client": "^0.6.3",
|
|
53
54
|
"@sphereon/pex": "5.0.0-unstable.28",
|
|
54
55
|
"@sphereon/pex-models": "^2.3.2",
|
|
55
|
-
"@sphereon/ssi-sdk-ext.did-provider-jwk": "0.34.1-feature.SSISDK.
|
|
56
|
-
"@sphereon/ssi-sdk.
|
|
57
|
-
"@sphereon/ssi-sdk.
|
|
58
|
-
"@sphereon/ssi-sdk.
|
|
56
|
+
"@sphereon/ssi-sdk-ext.did-provider-jwk": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
57
|
+
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
58
|
+
"@sphereon/ssi-sdk-ext.jwt-service": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
59
|
+
"@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
60
|
+
"@sphereon/ssi-sdk.credential-vcdm-jsonld-provider": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
61
|
+
"@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.62.218+da5863f4",
|
|
59
62
|
"@types/body-parser": "^1.19.5",
|
|
60
63
|
"@types/cookie-parser": "^1.4.7",
|
|
61
64
|
"@types/cors": "^2.8.17",
|
|
@@ -114,5 +117,5 @@
|
|
|
114
117
|
"OpenID Connect",
|
|
115
118
|
"Authenticator"
|
|
116
119
|
],
|
|
117
|
-
"gitHead": "
|
|
120
|
+
"gitHead": "da5863f4eaa8081dde4e943fe78c1217d62d1079"
|
|
118
121
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { z, ZodError } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const validateData = (schema: z.ZodObject<any, any>) => {
|
|
5
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
6
|
+
try {
|
|
7
|
+
schema.parse(req.body);
|
|
8
|
+
next();
|
|
9
|
+
} catch (error) {
|
|
10
|
+
if (error instanceof ZodError) {
|
|
11
|
+
const errorMessages = error.issues.map((issue: any) => ({
|
|
12
|
+
message: `${issue.path.join('.')} is ${issue.message}`,
|
|
13
|
+
}))
|
|
14
|
+
res.status(400).json({ status: 400, message: 'Invalid data', error_details: errorMessages[0].message });
|
|
15
|
+
} else {
|
|
16
|
+
res.status(500).json({ status: 500, message: 'Internal Server Error' });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -46,21 +46,32 @@ export function verifyAuthResponseSIOPv2Endpoint(router: Router, context: IRequi
|
|
|
46
46
|
console.log(`verifyAuthResponse SIOP endpoint is disabled`)
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
|
-
const path = opts?.path ?? '/siop/
|
|
49
|
+
const path = opts?.path ?? '/siop/queries/:queryId/auth-responses/:correlationId'
|
|
50
50
|
router.post(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
|
|
51
51
|
try {
|
|
52
|
-
const { correlationId,
|
|
53
|
-
if (!correlationId
|
|
54
|
-
console.log(`No authorization request could be found for the given url. correlationId: ${correlationId}
|
|
52
|
+
const { correlationId, queryId, tenantId, version } = request.params
|
|
53
|
+
if (!correlationId) {
|
|
54
|
+
console.log(`No authorization request could be found for the given url. correlationId: ${correlationId}`)
|
|
55
55
|
return sendErrorResponse(response, 404, 'No authorization request could be found')
|
|
56
56
|
}
|
|
57
|
-
console.
|
|
58
|
-
console.
|
|
59
|
-
const definitionItems = await context.agent.pdmGetDefinitions({
|
|
57
|
+
console.debug('Authorization Response (siop-sessions') // TODO use logger
|
|
58
|
+
console.debug(JSON.stringify(request.body, null, 2))
|
|
59
|
+
const definitionItems = await context.agent.pdmGetDefinitions({
|
|
60
|
+
filter: [
|
|
61
|
+
{
|
|
62
|
+
queryId,
|
|
63
|
+
...(tenantId && { tenantId }),
|
|
64
|
+
...(version && { version }),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: queryId,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
})
|
|
60
71
|
if (definitionItems.length === 0) {
|
|
61
|
-
console.log(`Could not get
|
|
72
|
+
console.log(`Could not get dcql query with id ${queryId} from agent. Will return 404`)
|
|
62
73
|
response.statusCode = 404
|
|
63
|
-
response.statusMessage = `No definition ${
|
|
74
|
+
response.statusMessage = `No definition ${queryId}`
|
|
64
75
|
return response.send()
|
|
65
76
|
}
|
|
66
77
|
|
|
@@ -71,8 +82,8 @@ export function verifyAuthResponseSIOPv2Endpoint(router: Router, context: IRequi
|
|
|
71
82
|
const verifiedResponse = await context.agent.siopVerifyAuthResponse({
|
|
72
83
|
authorizationResponse,
|
|
73
84
|
correlationId,
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
queryId,
|
|
86
|
+
dcqlQuery: definitionItem.query,
|
|
76
87
|
})
|
|
77
88
|
|
|
78
89
|
// FIXME SSISDK-55 add proper support for checking for DCQL presentations
|
|
@@ -89,7 +100,7 @@ export function verifyAuthResponseSIOPv2Endpoint(router: Router, context: IRequi
|
|
|
89
100
|
return response.send(JSON.stringify(authorizationChallengeValidationResponse))
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
const responseRedirectURI = await context.agent.siopGetRedirectURI({ correlationId,
|
|
103
|
+
const responseRedirectURI = await context.agent.siopGetRedirectURI({ correlationId, queryId, state: verifiedResponse.state })
|
|
93
104
|
if (responseRedirectURI) {
|
|
94
105
|
response.setHeader('Content-Type', 'application/json')
|
|
95
106
|
return response.send(JSON.stringify({ redirect_uri: responseRedirectURI }))
|
|
@@ -113,23 +124,23 @@ export function getAuthRequestSIOPv2Endpoint(router: Router, context: IRequiredC
|
|
|
113
124
|
console.log(`getAuthRequest SIOP endpoint is disabled`)
|
|
114
125
|
return
|
|
115
126
|
}
|
|
116
|
-
const path = opts?.path ?? '/siop/
|
|
127
|
+
const path = opts?.path ?? '/siop/queries/:queryId/auth-requests/:correlationId'
|
|
117
128
|
router.get(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
|
|
118
129
|
try {
|
|
119
130
|
const correlationId = request.params.correlationId
|
|
120
|
-
const
|
|
121
|
-
if (!correlationId || !
|
|
122
|
-
console.log(`No authorization request could be found for the given url. correlationId: ${correlationId},
|
|
131
|
+
const queryId = request.params.queryId
|
|
132
|
+
if (!correlationId || !queryId) {
|
|
133
|
+
console.log(`No authorization request could be found for the given url. correlationId: ${correlationId}, queryId: ${queryId}`)
|
|
123
134
|
return sendErrorResponse(response, 404, 'No authorization request could be found')
|
|
124
135
|
}
|
|
125
136
|
const requestState = await context.agent.siopGetAuthRequestState({
|
|
126
137
|
correlationId,
|
|
127
|
-
|
|
138
|
+
queryId,
|
|
128
139
|
errorOnNotFound: false,
|
|
129
140
|
})
|
|
130
141
|
if (!requestState) {
|
|
131
142
|
console.log(
|
|
132
|
-
`No authorization request could be found for the given url in the state manager. correlationId: ${correlationId}, definitionId: ${
|
|
143
|
+
`No authorization request could be found for the given url in the state manager. correlationId: ${correlationId}, definitionId: ${queryId}`,
|
|
133
144
|
)
|
|
134
145
|
return sendErrorResponse(response, 404, `No authorization request could be found`)
|
|
135
146
|
}
|
|
@@ -148,8 +159,8 @@ export function getAuthRequestSIOPv2Endpoint(router: Router, context: IRequiredC
|
|
|
148
159
|
} finally {
|
|
149
160
|
await context.agent.siopUpdateAuthRequestState({
|
|
150
161
|
correlationId,
|
|
151
|
-
|
|
152
|
-
state: '
|
|
162
|
+
queryId: queryId,
|
|
163
|
+
state: 'authorization_request_created',
|
|
153
164
|
error,
|
|
154
165
|
})
|
|
155
166
|
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { agentContext } from '@sphereon/ssi-sdk.core'
|
|
2
2
|
import { copyGlobalAuthToEndpoints, ExpressSupport } from '@sphereon/ssi-express-support'
|
|
3
|
-
import { IPresentationExchange } from '@sphereon/ssi-sdk.presentation-exchange'
|
|
4
3
|
import { ISIOPv2RP } from '@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth'
|
|
5
4
|
import { TAgent } from '@veramo/core'
|
|
6
5
|
import express, { Express, Request, Response, Router } from 'express'
|
|
7
6
|
import { getAuthRequestSIOPv2Endpoint, verifyAuthResponseSIOPv2Endpoint } from './siop-api-functions'
|
|
8
7
|
import { IRequiredPlugins, ISIOPv2RPRestAPIOpts } from './types'
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
authStatusUniversalOID4VPEndpoint,
|
|
10
|
+
createAuthRequestUniversalOID4VPEndpoint,
|
|
12
11
|
getDefinitionsEndpoint,
|
|
13
|
-
|
|
14
|
-
} from './
|
|
12
|
+
removeAuthRequestStateUniversalOID4VPEndpoint,
|
|
13
|
+
} from './universal-oid4vp-api-functions'
|
|
15
14
|
import swaggerUi from 'swagger-ui-express'
|
|
16
15
|
|
|
17
16
|
export class SIOPv2RPApiServer {
|
|
18
17
|
private readonly _express: Express
|
|
19
18
|
private readonly _router: Router
|
|
20
|
-
private readonly _agent: TAgent<
|
|
19
|
+
private readonly _agent: TAgent<ISIOPv2RP>
|
|
21
20
|
private readonly _opts?: ISIOPv2RPRestAPIOpts
|
|
22
21
|
private readonly _basePath: string
|
|
23
22
|
|
|
@@ -40,9 +39,9 @@ export class SIOPv2RPApiServer {
|
|
|
40
39
|
|
|
41
40
|
// Webapp endpoints
|
|
42
41
|
if (features.includes('rp-status')) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
createAuthRequestUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappCreateAuthRequest)
|
|
43
|
+
authStatusUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappAuthStatus)
|
|
44
|
+
removeAuthRequestStateUniversalOID4VPEndpoint(this._router, context, opts?.endpointOpts?.webappDeleteAuthRequest)
|
|
46
45
|
getDefinitionsEndpoint(this._router, context, opts?.endpointOpts?.webappGetDefinitions)
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -92,7 +91,7 @@ export class SIOPv2RPApiServer {
|
|
|
92
91
|
return this._router
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
get agent(): TAgent<
|
|
94
|
+
get agent(): TAgent<ISIOPv2RP> {
|
|
96
95
|
return this._agent
|
|
97
96
|
}
|
|
98
97
|
|
package/src/types/types.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { CreateAuthorizationRequestPayload, CreateAuthorizationResponsePayload } from '@sphereon/did-auth-siop'
|
|
1
2
|
import { GenericAuthArgs, ISingleEndpointOpts } from '@sphereon/ssi-express-support'
|
|
2
|
-
import {
|
|
3
|
+
import { IPDManager } from '@sphereon/ssi-sdk.pd-manager'
|
|
4
|
+
import { AuthorizationRequestStateStatus, AuthorizationResponseStateStatus } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
|
|
3
5
|
import { ISIOPv2RP } from '@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth'
|
|
6
|
+
import { AdditionalClaims } from '@sphereon/ssi-types'
|
|
4
7
|
import { IAgentContext, ICredentialVerifier } from '@veramo/core'
|
|
5
|
-
import {
|
|
8
|
+
import { Request, Response } from 'express'
|
|
6
9
|
import { QRCodeOpts } from './QRCode.types'
|
|
7
10
|
|
|
8
11
|
export type SiopFeatures = 'rp-status' | 'siop'
|
|
12
|
+
|
|
9
13
|
export interface ISIOPv2RPRestAPIOpts {
|
|
10
14
|
enableFeatures?: SiopFeatures[]
|
|
11
15
|
endpointOpts?: {
|
|
@@ -28,5 +32,58 @@ export interface ICreateAuthRequestWebappEndpointOpts extends ISingleEndpointOpt
|
|
|
28
32
|
responseRedirectURI?: string
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
export type IRequiredPlugins = ICredentialVerifier & ISIOPv2RP &
|
|
35
|
+
export type IRequiredPlugins = ICredentialVerifier & ISIOPv2RP & IPDManager
|
|
32
36
|
export type IRequiredContext = IAgentContext<IRequiredPlugins>
|
|
37
|
+
|
|
38
|
+
export type CreateAuthorizationRequestPayloadRequest = Request<Record<string, never>, any, CreateAuthorizationRequestPayload, Record<string, never>>
|
|
39
|
+
|
|
40
|
+
export type CreateAuthorizationResponsePayloadResponse = Response<CreateAuthorizationResponsePayload>
|
|
41
|
+
|
|
42
|
+
export type DeleteAuthorizationRequest = Request<DeleteAuthorizationRequestPathParameters, any, Record<string, any>, Record<string, any>>
|
|
43
|
+
|
|
44
|
+
export type DeleteAuthorizationRequestPathParameters = {
|
|
45
|
+
correlationId: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type GetAuthorizationRequestStatus = Request<GetAuthorizationRequestStatusPathParameters, any, Record<string, any>, Record<string, any>>
|
|
49
|
+
|
|
50
|
+
export type GetAuthorizationRequestStatusPathParameters = {
|
|
51
|
+
correlationId: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type RequestError = {
|
|
55
|
+
status: number
|
|
56
|
+
message: string
|
|
57
|
+
error_details?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface AuthStatusResponse {
|
|
61
|
+
status: AuthorizationRequestStateStatus | AuthorizationResponseStateStatus
|
|
62
|
+
correlation_id: string
|
|
63
|
+
query_id: string
|
|
64
|
+
last_updated: number
|
|
65
|
+
verified_data?: VerifiedData
|
|
66
|
+
error?: RequestError
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type VerifiedData = {
|
|
70
|
+
authorization_response?: AuthorizationResponse
|
|
71
|
+
credential_claims?: AdditionalClaims
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type AuthorizationResponse = {
|
|
75
|
+
presentation_submission?: Record<string, any>
|
|
76
|
+
vp_token?: VpToken
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type SingleObjectVpTokenPE = Record<string, any>
|
|
80
|
+
|
|
81
|
+
export type SingleStringVpTokenPE = string
|
|
82
|
+
|
|
83
|
+
export type MultipleVpTokens = Array<SingleObjectVpTokenPE> | Array<SingleStringVpTokenPE>
|
|
84
|
+
|
|
85
|
+
export type MultipleVpTokenDCQL = {
|
|
86
|
+
[key: string]: MultipleVpTokens
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type VpToken = SingleObjectVpTokenPE | SingleStringVpTokenPE | MultipleVpTokens | MultipleVpTokenDCQL
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthorizationRequestStateStatus,
|
|
3
|
+
AuthorizationResponseStateStatus,
|
|
4
|
+
CreateAuthorizationRequest,
|
|
5
|
+
createAuthorizationRequestFromPayload,
|
|
6
|
+
CreateAuthorizationRequestPayloadSchema,
|
|
7
|
+
CreateAuthorizationResponsePayload,
|
|
8
|
+
} from '@sphereon/did-auth-siop'
|
|
9
|
+
import { checkAuth, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support'
|
|
10
|
+
import { uriWithBase } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
|
|
11
|
+
import { VerifiedDataMode } from '@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth'
|
|
12
|
+
import { Request, Response, Router } from 'express'
|
|
13
|
+
import uuid from 'short-uuid'
|
|
14
|
+
import { validateData } from './middleware/validationMiddleware'
|
|
15
|
+
import {
|
|
16
|
+
AuthStatusResponse,
|
|
17
|
+
CreateAuthorizationRequestPayloadRequest,
|
|
18
|
+
CreateAuthorizationResponsePayloadResponse,
|
|
19
|
+
DeleteAuthorizationRequest,
|
|
20
|
+
GetAuthorizationRequestStatus,
|
|
21
|
+
ICreateAuthRequestWebappEndpointOpts,
|
|
22
|
+
IRequiredContext,
|
|
23
|
+
QRCodeOpts,
|
|
24
|
+
} from './types'
|
|
25
|
+
|
|
26
|
+
export function createAuthRequestUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ICreateAuthRequestWebappEndpointOpts) {
|
|
27
|
+
if (opts?.enabled === false) {
|
|
28
|
+
console.log(`createAuthRequest universal OID4VP endpoint is disabled`)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const path = opts?.path ?? '/backend/auth/requests'
|
|
33
|
+
router.post(
|
|
34
|
+
path,
|
|
35
|
+
checkAuth(opts?.endpoint),
|
|
36
|
+
validateData(CreateAuthorizationRequestPayloadSchema),
|
|
37
|
+
async (request: CreateAuthorizationRequestPayloadRequest, response: CreateAuthorizationResponsePayloadResponse) => {
|
|
38
|
+
try {
|
|
39
|
+
const authRequest: CreateAuthorizationRequest = createAuthorizationRequestFromPayload(request.body)
|
|
40
|
+
const correlationId = authRequest.correlationId ?? uuid.uuid()
|
|
41
|
+
const qrCodeOpts = authRequest.qrCode ? ({ ...authRequest.qrCode } satisfies QRCodeOpts) : opts?.qrCodeOpts
|
|
42
|
+
const queryId = authRequest.queryId
|
|
43
|
+
|
|
44
|
+
const definitionItems = await context.agent.pdmGetDefinitions({
|
|
45
|
+
filter: [
|
|
46
|
+
{ id: queryId }, // Allow both PK (unique queryId + version combi) or just plain queryId which assumes the latest version
|
|
47
|
+
{ queryId },
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
if (definitionItems.length === 0) {
|
|
51
|
+
console.log(`No query could be found for the given id. Query id: ${queryId}`)
|
|
52
|
+
return sendErrorResponse(response, 404, { status: 404, message: 'No query could be found' })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const requestByReferenceURI = uriWithBase(`/siop/queries/${queryId}/auth-requests/${correlationId}`, {
|
|
56
|
+
baseURI: authRequest.requestUriBase ?? opts?.siopBaseURI,
|
|
57
|
+
})
|
|
58
|
+
const responseURI = uriWithBase(`/siop/queries/${queryId}/auth-responses/${correlationId}`, { baseURI: opts?.siopBaseURI })
|
|
59
|
+
|
|
60
|
+
const authRequestURI = await context.agent.siopCreateAuthRequestURI({
|
|
61
|
+
queryId,
|
|
62
|
+
correlationId,
|
|
63
|
+
nonce: uuid.uuid(),
|
|
64
|
+
requestByReferenceURI,
|
|
65
|
+
responseURIType: 'response_uri',
|
|
66
|
+
responseURI,
|
|
67
|
+
...(authRequest.directPostResponseRedirectUri && { responseRedirectURI: authRequest.directPostResponseRedirectUri }),
|
|
68
|
+
...(authRequest.callback && { callback: authRequest.callback }),
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
let qrCodeDataUri: string | undefined
|
|
72
|
+
if (qrCodeOpts) {
|
|
73
|
+
const { AwesomeQR } = await import('awesome-qr')
|
|
74
|
+
const qrCode = new AwesomeQR({ ...qrCodeOpts, text: authRequestURI })
|
|
75
|
+
qrCodeDataUri = `data:image/png;base64,${(await qrCode.draw())!.toString('base64')}`
|
|
76
|
+
} else {
|
|
77
|
+
qrCodeDataUri = authRequestURI
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const authRequestBody = {
|
|
81
|
+
query_id: queryId,
|
|
82
|
+
correlation_id: correlationId,
|
|
83
|
+
request_uri: authRequestURI,
|
|
84
|
+
status_uri: `${uriWithBase(opts?.webappAuthStatusPath ?? `/backend/auth/status/${correlationId}`, { baseURI: opts?.webappBaseURI })}`,
|
|
85
|
+
...(qrCodeDataUri && { qr_uri: qrCodeDataUri }),
|
|
86
|
+
} satisfies CreateAuthorizationResponsePayload
|
|
87
|
+
console.log(`Auth Request URI data to send back: ${JSON.stringify(authRequestBody)}`)
|
|
88
|
+
|
|
89
|
+
return response.status(201).json(authRequestBody)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return sendErrorResponse(response, 500, { status: 500, message: 'Could not create an authorization request URI' }, error)
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function removeAuthRequestStateUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
|
|
98
|
+
if (opts?.enabled === false) {
|
|
99
|
+
console.log(`removeAuthStatus universal OID4VP endpoint is disabled`)
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const path = opts?.path ?? '/backend/auth/requests/:correlationId'
|
|
104
|
+
router.delete(path, checkAuth(opts?.endpoint), async (request: DeleteAuthorizationRequest, response: Response) => {
|
|
105
|
+
try {
|
|
106
|
+
const correlationId: string = request.params.correlationId
|
|
107
|
+
|
|
108
|
+
const authRequestState = await context.agent.siopGetAuthRequestState({
|
|
109
|
+
correlationId,
|
|
110
|
+
errorOnNotFound: false,
|
|
111
|
+
})
|
|
112
|
+
if (!authRequestState) {
|
|
113
|
+
console.log(`No authorization request could be found for the given correlationId. correlationId: ${correlationId}`)
|
|
114
|
+
return sendErrorResponse(response, 404, { status: 404, message: 'No authorization request could be found' })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await context.agent.siopDeleteAuthState({ correlationId })
|
|
118
|
+
|
|
119
|
+
return response.status(204).json()
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function authStatusUniversalOID4VPEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
|
|
127
|
+
if (opts?.enabled === false) {
|
|
128
|
+
console.log(`authStatus universal OID4VP endpoint is disabled`)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const path = opts?.path ?? '/backend/auth/status/:correlationId'
|
|
133
|
+
router.get(path, checkAuth(opts?.endpoint), async (request: GetAuthorizationRequestStatus, response: Response) => {
|
|
134
|
+
try {
|
|
135
|
+
console.log('Received auth-status request...')
|
|
136
|
+
const correlationId: string = request.params.correlationId
|
|
137
|
+
|
|
138
|
+
const requestState = await context.agent.siopGetAuthRequestState({
|
|
139
|
+
correlationId,
|
|
140
|
+
errorOnNotFound: false,
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (!requestState) {
|
|
144
|
+
console.log(`No authorization request could be found for the given correlationId. correlationId: ${correlationId}`)
|
|
145
|
+
return sendErrorResponse(response, 404, { status: 404, message: 'No authorization request could be found' })
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let responseState
|
|
149
|
+
if (requestState.status === AuthorizationRequestStateStatus.RETRIEVED) {
|
|
150
|
+
responseState = await context.agent.siopGetAuthResponseState({
|
|
151
|
+
correlationId,
|
|
152
|
+
errorOnNotFound: false,
|
|
153
|
+
includeVerifiedData: VerifiedDataMode.VERIFIED_PRESENTATION,
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
const overallState = responseState ?? requestState
|
|
157
|
+
|
|
158
|
+
const statusBody = {
|
|
159
|
+
status: overallState.status,
|
|
160
|
+
correlation_id: overallState.correlationId,
|
|
161
|
+
query_id: overallState.queryId,
|
|
162
|
+
last_updated: overallState.lastUpdated,
|
|
163
|
+
...(responseState?.status === AuthorizationResponseStateStatus.VERIFIED &&
|
|
164
|
+
responseState.verifiedData !== undefined && { verified_data: responseState.verifiedData }),
|
|
165
|
+
...(overallState.error && { message: overallState.error.message }),
|
|
166
|
+
} satisfies AuthStatusResponse
|
|
167
|
+
console.debug(`Will send auth status: ${JSON.stringify(statusBody)}`)
|
|
168
|
+
|
|
169
|
+
if (overallState.status === 'error') {
|
|
170
|
+
return response.status(500).json(statusBody)
|
|
171
|
+
}
|
|
172
|
+
return response.status(200).json(statusBody)
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function getDefinitionsEndpoint(router: Router, context: IRequiredContext, opts?: ISingleEndpointOpts) {
|
|
180
|
+
if (opts?.enabled === false) {
|
|
181
|
+
console.log(`getDefinitions universal OID4VP endpoint is disabled`)
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const path = opts?.path ?? '/backend/definitions'
|
|
186
|
+
router.get(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => {
|
|
187
|
+
try {
|
|
188
|
+
const definitions = await context.agent.pdmGetDefinitions()
|
|
189
|
+
response.statusCode = 200
|
|
190
|
+
return response.json(definitions)
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return sendErrorResponse(response, 500, { status: 500, message: error.message }, error)
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
}
|