Skip to content

Commit

Permalink
feat: Add auth toggle && missing api's (#234)
Browse files Browse the repository at this point in the history
* feat: Add create resource

* feat: Add auth toggle
  • Loading branch information
DaevMithran committed May 30, 2023
1 parent 8eefb0e commit 5c44288
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ OIDC_ISSUER='http://localhost:3001/oidc'

# Root endpoint for credential service backend
AUDIENCE_ENDPOINT='http://localhost:8787/1.0/api/'


# Authentication
ENABLE_AUTH="boolean,default:false"
CUSTOMER_ID="default customer id"
3 changes: 2 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ class App {
// issuer
app.post(`/key/create`, new IssuerController().createKey)
app.get(`/key/:kid`, new IssuerController().getKey)
app.post(`/did/create`, new IssuerController().createDid)
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)

// customer
app.post(`/account`, new CustomerController().create)
Expand Down
95 changes: 93 additions & 2 deletions src/controllers/issuer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,49 @@ import type { Request, Response } from 'express'

import { DIDDocument } from 'did-resolver'
import { v4 } from 'uuid'
import { MethodSpecificIdAlgo } from '@cheqd/sdk'
import { MethodSpecificIdAlgo, VerificationMethods, CheqdNetwork } from '@cheqd/sdk'
import { MsgCreateResourcePayload } from '@cheqd/ts-proto/cheqd/resource/v2/index.js'

import { Identity } from '../services/identity.js'
import { CustomerService } from '../services/customer.js'
import { generateDidDoc, validateSpecCompliantPayload } from '../helpers/helpers.js'
import { CustomerEntity } from '../database/entities/customer.entity.js'
import { check, param, validationResult } from 'express-validator'
import { fromString } from 'uint8arrays'

export class IssuerController {

public static didValidator = [
check('didDocument').optional().isArray().custom((value)=>{
const { valid } = validateSpecCompliantPayload(value)
return valid
}).withMessage('Invalid didDocument'),
check('secret.verificationMethod.type')
.optional()
.isString()
.isIn([VerificationMethods.Ed255192020, VerificationMethods.Ed255192018, VerificationMethods.JWK])
.withMessage('Invalid verificationMethod'),
check('secret.verificationMethod.id')
.optional()
.isString()
.withMessage('Invalid verificationMethod'),
check('options.methodSpecificIdAlgo').optional().isString().isIn([MethodSpecificIdAlgo.Base58, MethodSpecificIdAlgo.Uuid]).withMessage('Invalid methodSpecificIdAlgo'),
check('options.network').optional().isString().isIn([CheqdNetwork.Mainnet, CheqdNetwork.Testnet]).withMessage('Invalid network'),
]

public static resourceValidator = [
param('did').exists().isString().contains('did:cheqd').withMessage('Invalid DID'),
check('jobId').custom((value, {req})=>{
if(!value && !(req.body.name && req.body.type && req.body.data)) return false
return true
}).withMessage('name, type and data are required'),
check('name').optional().isString().withMessage('Invalid name'),
check('type').optional().isString().withMessage('Invalid type'),
check('data').optional().isString().withMessage('Invalid data'),
check('alsoKnownAs').optional().isArray().withMessage('Invalid alsoKnownAs'),
check('alsoKnownAs.*.uri').isString().withMessage('Invalid uri'),
check('alsoKnownAs.*.description').isString().withMessage('Invalid description')
]

public async createKey(request: Request, response: Response) {
try {
Expand Down Expand Up @@ -39,13 +74,20 @@ export class IssuerController {
}

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

const { options, secret } = request.body
const { methodSpecificIdAlgo, network, versionId = v4()} = options
const verificationMethod = secret?.verificationMethod
let didDocument: DIDDocument
let kids: string[] = []
try {
if (options.didDocument && validateSpecCompliantPayload(options.didDocument)) {
if (options.didDocument) {
didDocument = options.didDocument
} else if (verificationMethod) {
const key = await Identity.instance.createKey()
Expand Down Expand Up @@ -74,6 +116,55 @@ export class IssuerController {
}
}

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

const { did } = request.params
let { data, name, type, alsoKnownAs, version } = request.body

let resourcePayload: Partial<MsgCreateResourcePayload> = {}
try {
// check if did is registered on the ledger
let resolvedDocument = await Identity.instance.resolveDid(did)
if(!resolvedDocument?.didDocument || resolvedDocument.didDocumentMetadata.deactivated) {
return response.status(400).send({
error: `${did} is a Deactivated DID`
})
} else {
resolvedDocument = resolvedDocument.didDocument
}

resourcePayload = {
collectionId: did.split(':').pop()!,
id: v4(),
name,
resourceType: type,
data: fromString(data, 'base64'),
version,
alsoKnownAs
}
const result = await Identity.instance.createResource(resourcePayload, response.locals.customerId)
if ( result ) {
return response.status(201).json({
resource: resourcePayload
})
} else {
return response.status(500).json({
error: 'Error creating resource'
})
}
} catch (error) {
return response.status(500).json({
error: `${error}`
})
}
}

public async getDids(request: Request, response: Response) {
try {
let did: any
Expand Down
42 changes: 25 additions & 17 deletions src/middleware/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { IncomingHttpHeaders } from 'http';
import * as dotenv from 'dotenv'
dotenv.config()

const { OIDC_JWKS_ENDPOINT, AUDIENCE_ENDPOINT, OIDC_ISSUER } = process.env
const bearerTokenIdentifier = 'Bearer';
const { OIDC_JWKS_ENDPOINT, AUDIENCE_ENDPOINT, OIDC_ISSUER, ENABLE_AUTH, CUSTOMER_ID } = process.env
const bearerTokenIdentifier = 'Bearer'

export const extractBearerTokenFromHeaders = ({ authorization }: IncomingHttpHeaders) => {
if (!authorization) {
Expand Down Expand Up @@ -58,21 +58,29 @@ export class Authentication {
if (jwtRequest.path == '/' || jwtRequest.path == '/swagger') return next()

try {
const token = extractBearerTokenFromHeaders(jwtRequest.headers)

const { payload } = await jwtVerify(
token, // The raw Bearer Token extracted from the request header
createRemoteJWKSet(new URL(OIDC_JWKS_ENDPOINT)), // generate a jwks using jwks_uri inquired from Logto server
{
// expected issuer of the token, should be issued by the Logto server
issuer: OIDC_ISSUER,
// expected audience token, should be the resource indicator of the current API
audience: AUDIENCE_ENDPOINT,
}
);

// custom payload logic
response.locals.customerId = payload.sub
if (ENABLE_AUTH) {
const token = extractBearerTokenFromHeaders(jwtRequest.headers)

const { payload } = await jwtVerify(
token, // The raw Bearer Token extracted from the request header
createRemoteJWKSet(new URL(OIDC_JWKS_ENDPOINT)), // generate a jwks using jwks_uri inquired from Logto server
{
// expected issuer of the token, should be issued by the Logto server
issuer: OIDC_ISSUER,
// expected audience token, should be the resource indicator of the current API
audience: AUDIENCE_ENDPOINT,
}
);

// custom payload logic
response.locals.customerId = payload.sub
} else if (CUSTOMER_ID) {
response.locals.customerId = CUSTOMER_ID
} else {
return response.status(400).json({
error: `Unauthorized error`
})
}
next()
} catch (err) {
return response.status(500).send({
Expand Down
26 changes: 24 additions & 2 deletions src/services/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import { DIDResolverPlugin } from '@veramo/did-resolver'
import { KeyManager } from '@veramo/key-manager'
import { KeyManagementSystem, SecretBox } from '@veramo/kms-local'
import { KeyStore, DIDStore, PrivateKeyStore } from '@veramo/data-store'
import { CredentialIssuerLD, LdDefaultContexts, VeramoEd25519Signature2018, VeramoEd25519Signature2020 } from '@veramo/credential-ld'
import { CheqdDIDProvider, getResolver as CheqdDidResolver } from '@cheqd/did-provider-cheqd'
import { CredentialIssuerLD, LdDefaultContexts, VeramoEd25519Signature2018 } from '@veramo/credential-ld'
import { CheqdDIDProvider, getResolver as CheqdDidResolver, ResourcePayload } from '@cheqd/did-provider-cheqd'
import { CheqdNetwork } from '@cheqd/sdk'
import { Resolver, ResolverRegistry } from 'did-resolver'
import { v4 } from 'uuid'
Expand Down Expand Up @@ -194,4 +194,26 @@ export class Identity {

return identifier
}

async createResource(resource: ResourcePayload, agentId?: string) {
try {
const agentService = agentId ? await this.create_agent(agentId) : this.agent
if (!agentService) throw new Error('No initialised agent found.')

const [kms] = await agentService.keyManagerGetKeyManagementSystems()

const result: boolean = await agentService.execute(
'cheqdCreateLinkedResource',
{
kms,
payload: {
data: resource
}
}
)
return result
} catch (error) {
throw new Error(`${error}`)
}
}
}
6 changes: 5 additions & 1 deletion src/types/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ declare global {
interface ProcessEnv {
MAINNET_RPC_URL: string
TESTNET_RPC_URL: string
RESOLVER_URL: string
RESOLVER_URL: string
ALLOWED_ORIGINS: string | undefined
DB_CONNECTION_URL: string
DB_ENCRYPTION_KEY: string
Expand All @@ -20,6 +20,10 @@ declare global {
ISSUER_VERIDA_PRIVATE_KEY: string
POLYGON_PRIVATE_KEY: string
VERIDA_NETWORK: EnvironmentType

// auth
ENABLE_AUTH: boolean | undefined
CUSTOMER_ID: string | undefined
}
}
}
Expand Down

0 comments on commit 5c44288

Please sign in to comment.