Skip to content

Commit

Permalink
CWALL-174: created branch & first v13 classes
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Apr 24, 2024
1 parent dc70d52 commit d0769d0
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 0 deletions.
153 changes: 153 additions & 0 deletions packages/issuer/lib/builder/CredentialSupportedBuilderV1_13.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {
CredentialsSupportedDisplay,
CredentialSupported,
isFormat,
isNotFormat,
IssuerCredentialSubject,
IssuerCredentialSubjectDisplay,
OID4VCICredentialFormat,
TokenErrorResponse,
} from '@sphereon/oid4vci-common'

export class CredentialSupportedBuilderV1_13 {
format?: OID4VCICredentialFormat
id?: string
types?: string[]
cryptographicBindingMethodsSupported?: ('jwk' | 'cose_key' | 'did' | string)[]
cryptographicSuitesSupported?: ('jwt_vc' | 'ldp_vc' | string)[]
display?: CredentialsSupportedDisplay[]
credentialSubject?: IssuerCredentialSubject

withFormat(credentialFormat: OID4VCICredentialFormat): CredentialSupportedBuilderV1_13 {
this.format = credentialFormat
return this
}

withId(id: string): CredentialSupportedBuilderV1_13 {
this.id = id
return this
}

addTypes(type: string | string[]): CredentialSupportedBuilderV1_13 {
if (!Array.isArray(type)) {
this.types = this.types ? [...this.types, type] : [type]
} else {
this.cryptographicBindingMethodsSupported = this.cryptographicBindingMethodsSupported
? [...this.cryptographicBindingMethodsSupported, ...type]
: type
}
return this
}

withTypes(type: string | string[]): CredentialSupportedBuilderV1_13 {
if (this.format === 'vc+sd-jwt' && Array.isArray(type) && type.length > 1) {
throw new Error('Only one type is allowed for vc+sd-jwt')
}
this.types = Array.isArray(type) ? type : [type]
return this
}

addCryptographicBindingMethod(method: string | string[]): CredentialSupportedBuilderV1_13 {
if (!Array.isArray(method)) {
this.cryptographicBindingMethodsSupported = this.cryptographicBindingMethodsSupported
? [...this.cryptographicBindingMethodsSupported, method]
: [method]
} else {
this.cryptographicBindingMethodsSupported = this.cryptographicBindingMethodsSupported
? [...this.cryptographicBindingMethodsSupported, ...method]
: method
}
return this
}

withCryptographicBindingMethod(method: string | string[]): CredentialSupportedBuilderV1_13 {
this.cryptographicBindingMethodsSupported = Array.isArray(method) ? method : [method]
return this
}

addCryptographicSuitesSupported(suit: string | string[]): CredentialSupportedBuilderV1_13 {
if (!Array.isArray(suit)) {
this.cryptographicSuitesSupported = this.cryptographicSuitesSupported ? [...this.cryptographicSuitesSupported, suit] : [suit]
} else {
this.cryptographicSuitesSupported = this.cryptographicSuitesSupported ? [...this.cryptographicSuitesSupported, ...suit] : suit
}
return this
}

withCryptographicSuitesSupported(suit: string | string[]): CredentialSupportedBuilderV1_13 {
this.cryptographicSuitesSupported = Array.isArray(suit) ? suit : [suit]
return this
}

addCredentialSupportedDisplay(credentialDisplay: CredentialsSupportedDisplay | CredentialsSupportedDisplay[]): CredentialSupportedBuilderV1_13 {
if (!Array.isArray(credentialDisplay)) {
this.display = this.display ? [...this.display, credentialDisplay] : [credentialDisplay]
} else {
this.display = this.display ? [...this.display, ...credentialDisplay] : credentialDisplay
}
return this
}

withCredentialSupportedDisplay(credentialDisplay: CredentialsSupportedDisplay | CredentialsSupportedDisplay[]): CredentialSupportedBuilderV1_13 {
this.display = Array.isArray(credentialDisplay) ? credentialDisplay : [credentialDisplay]
return this
}

withCredentialSubjectDisplay(credentialSubject: IssuerCredentialSubject) {
this.credentialSubject = credentialSubject
return this
}

addCredentialSubjectPropertyDisplay(
subjectProperty: string,
issuerCredentialSubjectDisplay: IssuerCredentialSubjectDisplay,
): CredentialSupportedBuilderV1_13 {
if (!this.credentialSubject) {
this.credentialSubject = {}
}
this.credentialSubject[subjectProperty] = issuerCredentialSubjectDisplay
return this
}

public build(): CredentialSupported {
if (!this.format) {
throw new Error(TokenErrorResponse.invalid_request)
}
const credentialSupported: Partial<CredentialSupported> = {
format: this.format,
}
if (!this.types) {
throw new Error('types are required')
}

// SdJwtVc has a different format
if (isFormat(credentialSupported, 'vc+sd-jwt')) {
if (this.types.length > 1) {
throw new Error('Only one type is allowed for vc+sd-jwt')
}
credentialSupported.vct = this.types[0]
}
// And else would work here, but this way we get the correct typing
else if (isNotFormat(credentialSupported, 'vc+sd-jwt')) {
credentialSupported.types = this.types

if (this.credentialSubject) {
credentialSupported.credentialSubject = this.credentialSubject
}
}

if (this.cryptographicSuitesSupported) {
credentialSupported.cryptographic_suites_supported = this.cryptographicSuitesSupported
}
if (this.cryptographicBindingMethodsSupported) {
credentialSupported.cryptographic_binding_methods_supported = this.cryptographicBindingMethodsSupported
}
if (this.id) {
credentialSupported.id = this.id
}
if (this.display) {
credentialSupported.display = this.display
}
return credentialSupported as CredentialSupported
}
}
112 changes: 112 additions & 0 deletions packages/issuer/lib/builder/IssuerMetadataBuilderV1_13.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { CredentialIssuerMetadata, CredentialSupported, MetadataDisplay } from '@sphereon/oid4vci-common'

import { CredentialSupportedBuilderV1_13 } from './CredentialSupportedBuilderV1_13'
import { DisplayBuilder } from './DisplayBuilder'

export class IssuerMetadataBuilderV1_13 {
credentialEndpoint: string | undefined
credentialIssuer: string | undefined
supportedBuilders: CredentialSupportedBuilderV1_13[] = []
supportedCredentials: CredentialSupported[] = []
displayBuilders: DisplayBuilder[] = []
display: MetadataDisplay[] = []
batchCredentialEndpoint?: string
authorizationServers?: string[]
tokenEndpoint?: string

public withBatchCredentialEndpoint(batchCredentialEndpoint: string) {
this.batchCredentialEndpoint = batchCredentialEndpoint
throw Error(`Not supported yet`)
}

public withAuthorizationServers(authorizationServers: string[]) {
this.authorizationServers = authorizationServers
return this
}

public withAuthorizationServer(authorizationServer: string) {
if(this.authorizationServers === undefined) {
this.authorizationServers = []
}
this.authorizationServers.push(authorizationServer)
return this
}

public withTokenEndpoint(tokenEndpoint: string) {
this.tokenEndpoint = tokenEndpoint
return this
}

public withCredentialEndpoint(credentialEndpoint: string): IssuerMetadataBuilderV1_13 {
this.credentialEndpoint = credentialEndpoint
return this
}

public withCredentialIssuer(credentialIssuer: string): IssuerMetadataBuilderV1_13 {
this.credentialIssuer = credentialIssuer
return this
}

public newSupportedCredentialBuilder(): CredentialSupportedBuilderV1_13 {
const builder = new CredentialSupportedBuilderV1_13()
this.addSupportedCredentialBuilder(builder)
return builder
}

public addSupportedCredentialBuilder(supportedCredentialBuilder: CredentialSupportedBuilderV1_13) {
this.supportedBuilders.push(supportedCredentialBuilder)
return this
}

public addSupportedCredential(supportedCredential: CredentialSupported) {
this.supportedCredentials.push(supportedCredential)
return this
}

public withIssuerDisplay(issuerDisplay: MetadataDisplay[] | MetadataDisplay): IssuerMetadataBuilderV1_13 {
this.display = Array.isArray(issuerDisplay) ? issuerDisplay : [issuerDisplay]
return this
}

public addDisplay(display: MetadataDisplay) {
this.display.push(display)
}

public addDisplayBuilder(displayBuilder: DisplayBuilder) {
this.displayBuilders.push(displayBuilder)
}

public newDisplayBuilder(): DisplayBuilder {
const builder = new DisplayBuilder()
this.addDisplayBuilder(builder)
return builder
}

public build(): CredentialIssuerMetadata {
if (!this.credentialIssuer) {
throw Error('No credential issuer supplied')
} else if (!this.credentialEndpoint) {
throw Error('No credential endpoint supplied')
}
const supportedCredentials: CredentialSupported[] = []
supportedCredentials.push(...this.supportedCredentials)
supportedCredentials.push(...this.supportedBuilders.map((builder) => builder.build()))
if (supportedCredentials.length === 0) {
throw Error('No supported credentials supplied')
}

const display: MetadataDisplay[] = []
display.push(...this.display)
display.push(...this.displayBuilders.map((builder) => builder.build()))

return {
credential_issuer: this.credentialIssuer,
credential_endpoint: this.credentialEndpoint,
credentials_supported: supportedCredentials,
// batch_credential_endpoint: this.batchCredentialEndpoint; // not implemented yet
...(this.authorizationServer && { authorization_server: this.authorizationServer }),
...(this.tokenEndpoint && { token_endpoint: this.tokenEndpoint }),
...(display.length > 0 && { display }),
}
}
}

0 comments on commit d0769d0

Please sign in to comment.