Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add verify presentation API and update StatusList APIs [DEV-2811] & [DEV-2669] #265

Merged
merged 29 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fcf464f
feat: Init presentation
DaevMithran Jun 16, 2023
c4f69b8
feat: Add did:key resolver
DaevMithran Jun 16, 2023
453339f
Merge branch 'develop' into presentation
DaevMithran Jun 26, 2023
62c04a6
feat: Add uniresolver && update policies
DaevMithran Jun 26, 2023
be462bb
feat: Add broadcast statusList api
DaevMithran Jun 26, 2023
3d92bcd
feat: Update swagger
DaevMithran Jun 26, 2023
db54f70
Merge branch 'develop' into presentation
DaevMithran Jun 27, 2023
57f3b32
feat: Add did update && deactivate operations
DaevMithran Jun 27, 2023
8bd9489
feat: Update swagger
DaevMithran Jun 27, 2023
92387f5
fix: External db bug && api paths
DaevMithran Jun 27, 2023
253b7ea
feat: Support urlencoded request body
DaevMithran Jun 28, 2023
28a196c
feat: Update swagger
DaevMithran Jun 28, 2023
623f8ad
feat: Refactor inputs
DaevMithran Jun 29, 2023
545aa91
fix: Array issues with urlencoded
DaevMithran Jun 30, 2023
6f14a3c
feat: Add credential-status update api
DaevMithran Jul 3, 2023
ec7ef80
Merge branch 'develop' into presentation
DaevMithran Jul 3, 2023
a89799e
Merge branch 'develop' into presentation
DaevMithran Jul 3, 2023
d2949b7
Merge branch 'develop' into presentation
DaevMithran Jul 3, 2023
24ee606
fix: DID update in chunks
DaevMithran Jul 3, 2023
47655b6
bump deps
ankurdotb Jul 3, 2023
d681f32
feat: Update credential-status and verify api's
DaevMithran Jul 4, 2023
f8bbf94
fix: credential verify
DaevMithran Jul 4, 2023
4b62e03
feat: Update indices mandatory in statusUpdate
DaevMithran Jul 5, 2023
aeb2026
Merge branch 'develop' into presentation
ankurdotb Jul 6, 2023
fe40b98
Update package-lock.json
ankurdotb Jul 6, 2023
a8a2724
fix: Presentation api example
DaevMithran Jul 7, 2023
1b1426b
fix: Minor issues
DaevMithran Jul 7, 2023
669a1cb
Update package-lock.json
ankurdotb Jul 7, 2023
bce5f8d
Merge branch 'presentation' of https://github.com/cheqd/credential-se…
ankurdotb Jul 7, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"README.md"
],
"dependencies": {
"@cheqd/did-provider-cheqd": "3.3.1",
"@cheqd/did-provider-cheqd": "^3.4.0",
"@cosmjs/amino": "^0.30.1",
"@cosmjs/encoding": "^0.30.1",
"@logto/express": "^2.0.1",
Expand All @@ -52,13 +52,13 @@
"@veramo/credential-w3c": "^5.2.0",
"@veramo/data-store": "^5.2.0",
"@veramo/did-manager": "^5.1.2",
"@veramo/did-provider-key": "^5.2.0",
"@veramo/did-resolver": "^5.2.0",
"@veramo/key-manager": "^5.1.2",
"@veramo/kms-local": "^5.1.2",
"@verida/account-node": "^2.3.5",
"@verida/client-ts": "^2.3.5",
"@verida/types": "^2.3.1",
"@verida/vda-did-resolver": "^2.3.5",
"cookie-parser": "^1.4.6",
"copyfiles": "^2.4.1",
"cors": "^2.8.5",
Expand Down
17 changes: 11 additions & 6 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cors from 'cors'
import swaggerUi from 'swagger-ui-express'
import session from 'express-session'
import cookieParser from 'cookie-parser'
import {withLogto, handleAuthRoutes } from '@logto/express'
import { withLogto, handleAuthRoutes } from '@logto/express'

import { CredentialController } from './controllers/credentials.js'
import { StoreController } from './controllers/store.js'
Expand Down Expand Up @@ -55,9 +55,9 @@ class App {
this.express.use(cookieParser())
if (process.env.ENABLE_AUTHENTICATION === 'true') {
this.express.use(session({secret: process.env.COOKIE_SECRET, cookie: { maxAge: 14 * 24 * 60 * 60 }}))
this.express.use(handleAuthRoutes(configLogToExpress))
this.express.use(withLogto(configLogToExpress))
}
this.express.use(handleAuthRoutes(configLogToExpress))
this.express.use(withLogto(configLogToExpress))
this.express.use(express.text())

this.express.use(
Expand Down Expand Up @@ -85,9 +85,14 @@ class App {
app.post('/credential/suspend', new CredentialController().suspend)
app.post('/credential/reinstate', new CredentialController().reinstate)

// presentation
app.post(`/presentation/verify`, CredentialController.presentationValidator, new CredentialController().verifyPresentation)

//revocation
app.post('/revocation/statusList2021/create', RevocationController.didValidator, RevocationController.statusListValidator, new RevocationController().createStatusList)
app.get('/revocation/statusList2021/list', RevocationController.didValidator, new RevocationController().fetchStatusList)
app.post('/credential-status/statusList2021/create', RevocationController.didValidator, RevocationController.statusListValidator, new RevocationController().createStatusList)
app.post('/credential-status/statusList2021/publish', RevocationController.didValidator, new RevocationController().createStatusList)
app.get('/credential-status/statusList2021/list', RevocationController.didValidator, new RevocationController().fetchStatusList)

Tweeddalex marked this conversation as resolved.
Show resolved Hide resolved
// store
app.post(`/store`, new StoreController().set)
app.get(`/store/:id`, new StoreController().get)
Expand All @@ -98,7 +103,7 @@ class App {
app.post(`/did/create`, IssuerController.didValidator, new IssuerController().createDid)
app.get(`/did/list`, new IssuerController().getDids)
app.get(`/did/:did`, new IssuerController().getDids)
app.post(`/:did/create-resource`, IssuerController.resourceValidator, new IssuerController().createResource)
app.post(`/:did/resource/create`, IssuerController.resourceValidator, new IssuerController().createResource)
DaevMithran marked this conversation as resolved.
Show resolved Hide resolved

// customer
app.post(`/account`, new CustomerController().create)
Expand Down
26 changes: 26 additions & 0 deletions src/controllers/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ export class CredentialController {
check('publish').optional().isBoolean().withMessage('publish should be a boolean value')
]

public static presentationValidator = [
check('presentation').exists().withMessage('W3c verifiable presentation was not provided')
.custom((value) => {
if (typeof value === 'string' || typeof value === 'object') {
return true
}
return false
})
.withMessage('Entry must be a jwt string or a presentation'),
]

public async issue(request: Request, response: Response) {
const result = validationResult(request)
if (!result.isEmpty()) {
Expand Down Expand Up @@ -111,4 +122,19 @@ export class CredentialController {
})
}
}

public async verifyPresentation(request: Request, response: Response) {
const result = validationResult(request)
if (!result.isEmpty()) {
return response.status(400).json({ error: result.array()[0].msg })
}

try {
return response.status(200).json(await Identity.instance.verifyPresentation(request.body.presentation, request.body.statusOptions, response.locals.customerId))
} catch (error) {
return response.status(500).json({
error: `${error}`
})
}
}
}
24 changes: 16 additions & 8 deletions src/controllers/revocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { fromString } from 'uint8arrays'

import { Identity } from '../services/identity/index.js'
import { Veramo } from '../services/identity/agent.js'
import { ResourceMetadata } from '../types/types.js'
import { ResourceMetadata, StatusList2021ResourceTypes } from '../types/types.js'

export class RevocationController {

Expand All @@ -26,14 +26,17 @@ export class RevocationController {
}

let { length, encoding } = request.body
let { data, name, type, alsoKnownAs, version, network } = request.body
let { data, name, statusPurpose, alsoKnownAs, version } = request.body

const did = request.query.did as string
network = network || (did.split(':'))[2]
data = data ? fromString(data, 'base64') : undefined

try {
const result = await Identity.instance.createStatusList2021(did, network, { data, name, alsoKnownAs, version, resourceType: type }, { length, encoding }, response.locals.customerId)
let result: any
if (data) {
result = await Identity.instance.broadcastStatusList2021(did, { data, name, alsoKnownAs, version }, { encoding, statusPurpose }, response.locals.customerId)
}
result = await Identity.instance.createStatusList2021(did, { name, alsoKnownAs, version }, { length, encoding, statusPurpose }, response.locals.customerId)
return response.status(200).json({
success: result
})
Expand All @@ -51,10 +54,15 @@ export class RevocationController {
}

try {
let result = await Veramo.instance.resolve(`${request.query.did}?resourceType=StatusList2021&resourceMetadata=true`)
result = result.contentStream?.linkedResourceMetadata || []
const statusList = result
.filter((resource: ResourceMetadata)=>resource.mediaType=='application/octet-stream' || resource.mediaType=='application/gzip')
const resourceTypes = request.query.resourceType ? [request.query.resourceType] : [StatusList2021ResourceTypes.revocation, StatusList2021ResourceTypes.suspension];
let metadata: ResourceMetadata[] = [];

for (const resourceType of resourceTypes) {
const result = await Veramo.instance.resolve(`${request.query.did}?resourceType=${resourceType}&resourceMetadata=true`);
metadata = metadata.concat(result.contentStream?.linkedResourceMetadata || []);
}
const statusList = metadata
.filter((resource: ResourceMetadata)=>resource.mediaType=='application/json')
.map((resource: ResourceMetadata)=>{
return {
statusListName: resource.resourceName,
Expand Down
2 changes: 1 addition & 1 deletion src/services/connectors/verida.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Context, Network } from '@verida/client-ts'
import { AutoAccount } from '@verida/account-node'

import { CredentialDataRecord, DataRecord } from '../../types/verida.js'
import { VC_CONTEXT, VERIDA_APP_NAME, VERIDA_CREDENTIAL_RECORD_SCHEMA } from '../../types/constants.js'
import { VERIDA_APP_NAME, VERIDA_CREDENTIAL_RECORD_SCHEMA } from '../../types/constants.js'

import * as dotenv from 'dotenv'
import { VerifiableCredential } from '@veramo/core'
Expand Down
8 changes: 4 additions & 4 deletions src/services/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
VC_CONTEXT,
VC_TYPE
} from '../types/constants.js'
import { CredentialRequest, VerifyStatusOptions } from '../types/types.js'
import { CredentialRequest, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../types/types.js'
import { Identity } from './identity/index.js'
import { VeridaService } from '../services/connectors/verida.js'
import { v4 } from 'uuid'
Expand Down Expand Up @@ -51,14 +51,14 @@ export class Credentials {
return verifiable_credential
}

async verify_credentials(credential: W3CVerifiableCredential | string, statusOptions: VerifyStatusOptions | null, agentId: string): Promise<IVerifyResult> {
async verify_credentials(credential: W3CVerifiableCredential | string, statusOptions: VerifyCredentialStatusOptions | null, agentId: string): Promise<IVerifyResult> {
const result = await Identity.instance.verifyCredential(credential, statusOptions, agentId)
delete(result.payload)
return result
}

async verify_presentation(presentation: W3CVerifiablePresentation, agentId: string): Promise<IVerifyResult> {
const result = await Identity.instance.verifyPresentation(presentation, agentId)
async verify_presentation(presentation: W3CVerifiablePresentation, statusOptions: VerifyPresentationStatusOptions | null, agentId: string): Promise<IVerifyResult> {
const result = await Identity.instance.verifyPresentation(presentation, statusOptions, agentId)
return result
}
}
17 changes: 9 additions & 8 deletions src/services/identity/IIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import type {
} from '@veramo/core'
import type { AbstractPrivateKeyStore } from '@veramo/key-manager'
import type { ResourcePayload } from '@cheqd/did-provider-cheqd'
import type { RevocationResult, SuspensionResult, UnsuspensionResult } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd'
import type { CreateStatusListOptions, CredentialRequest, StatusOptions, VeramoAgent, VerifyStatusOptions } from '../../types/types'
import type { BulkRevocationResult, BulkSuspensionResult, BulkUnsuspensionResult, CreateEncryptedStatusList2021Result, CreateStatusList2021Result, RevocationResult, SuspensionResult, UnsuspensionResult } from '@cheqd/did-provider-cheqd/build/types/agent/ICheqd'
import type { BroadCastStatusListOptions, CreateStatusListOptions, CredentialRequest, StatusOptions, VeramoAgent, VerifyCredentialStatusOptions, VerifyPresentationStatusOptions } from '../../types/types'

export interface IIdentity {
agent?: TAgent<any>
Expand All @@ -28,10 +28,11 @@ export interface IIdentity {
importDid(did: string, privateKeyHex: string, publicKeyHex: string, agentId?: string): Promise<IIdentifier>
createResource(network: string, payload: ResourcePayload, agentId?: string): Promise<any>
createCredential(credential: CredentialPayload, format: CredentialRequest['format'], statusListOptions: StatusOptions | null, agentId?: string): Promise<VerifiableCredential>
verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyStatusOptions | null, agentId?: string): Promise<IVerifyResult>
verifyPresentation(presentation: VerifiablePresentation | string, agentId?: string): Promise<IVerifyResult>
createStatusList2021(did: string, network: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions, agentId: string): Promise<boolean>
revokeCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<RevocationResult| RevocationResult[]>
suspendCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<SuspensionResult| SuspensionResult[]>
reinstateCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<UnsuspensionResult| UnsuspensionResult[]>
verifyCredential(credential: VerifiableCredential | string, statusOptions: VerifyCredentialStatusOptions | null, agentId?: string): Promise<IVerifyResult>
verifyPresentation(presentation: VerifiablePresentation | string, statusOptions: VerifyPresentationStatusOptions, agentId?: string): Promise<IVerifyResult>
createStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: CreateStatusListOptions, agentId: string): Promise<CreateStatusList2021Result | CreateEncryptedStatusList2021Result>
broadcastStatusList2021(did: string, resourceOptions: ResourcePayload, statusOptions: BroadCastStatusListOptions, agentId?: string): Promise<boolean>
revokeCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<RevocationResult| BulkRevocationResult>
suspendCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<SuspensionResult| BulkSuspensionResult>
reinstateCredentials(credential: VerifiableCredential | VerifiableCredential[], publish: boolean, agentId?: string): Promise<UnsuspensionResult| BulkUnsuspensionResult>
}
Loading