File

src/issuer/configuration/credentials/entities/credential.entity.ts

Index

Properties

Properties

Optional cert
Type : CertEntity
Decorators :
@ManyToOne(undefined, {createForeignKeyConstraints: false})
@JoinColumn(['undefined', 'undefined'])
Optional certId
Type : string
Decorators :
@IsOptional()
@IsString()
@Column('varchar', {nullable: true})

Reference to the certificate used for signing. Note: No DB-level FK constraint because CertEntity has a composite PK (id + tenantId) and SET NULL behavior cannot work when tenantId is part of this entity's own PK.

Optional claims
Type : Record<string | any> | null
Decorators :
@Column('json', {nullable: true})
@IsOptional()
@IsObject()
Optional claimsWebhook
Type : WebhookConfig | null
Decorators :
@IsOptional()
@ValidateNested()
@Type(undefined)
@Column('json', {nullable: true})

Webhook to receive claims for the issuance process.

config
Type : IssuerMetadataCredentialConfig
Decorators :
@Column('json')
@ValidateNested()
@Type(undefined)
Optional description
Type : string | null
Decorators :
@IsString()
@Column('varchar', {nullable: true})
Optional disclosureFrame
Type : Record<string | any> | null
Decorators :
@Column('json', {nullable: true})
@IsOptional()
@IsObject()
Optional embeddedDisclosurePolicy
Type : EmbeddedDisclosurePolicy | null
Decorators :
@IsOptional()
@ValidateNested()
@ApiProperty({oneOf: undefined})
@Type(undefined, {discriminator: undefined, keepDiscriminatorProperty: true})
@Column('json', {nullable: true})

Embedded disclosure policy (discriminated union by policy). The discriminator makes class-transformer instantiate the right subclass, and then class-validator runs that subclass’s rules.

Optional iaeActions
Type : IaeAction[] | null
Decorators :
@IsOptional()
@IsArray()
@ValidateNested({each: true})
@Type(undefined, {discriminator: undefined, keepDiscriminatorProperty: true})
@ApiProperty({description: 'List of IAE actions to execute before credential issuance', type: 'array', items: undefined, nullable: true, required: false})
@Column('json', {nullable: true})

List of Interactive Authorization Endpoint (IAE) actions to execute before credential issuance. Actions are executed in order.

Each action can be:

  • openid4vp_presentation: Request a verifiable presentation from the wallet
  • redirect_to_web: Redirect user to a web page for additional interaction

If empty or not set, no interactive authorization is required.

Example :
[
  { "type": "openid4vp_presentation", "presentationConfigId": "pid-config" },
  { "type": "redirect_to_web", "url": "https://example.com/verify", "label": "Additional Verification" }
]
id
Type : string
Decorators :
@IsString()
@Column('varchar', {primary: true})
Optional keyBinding
Type : boolean
Decorators :
@IsOptional()
@Column('boolean', {default: false})
@IsBoolean()
Optional lifeTime
Type : number
Decorators :
@IsOptional()
@Column('int', {nullable: true})
@IsNumber()
Optional notificationWebhook
Type : WebhookConfig | null
Decorators :
@IsOptional()
@ValidateNested()
@Type(undefined)
@Column('json', {nullable: true})

Webhook to receive claims for the issuance process.

Optional schema
Type : SchemaResponse | null
Decorators :
@IsOptional()
@ValidateNested()
@Type(undefined)
@Column('json', {nullable: true})
Optional statusManagement
Type : boolean
Decorators :
@IsOptional()
@Column('boolean', {default: false})
@IsBoolean()
tenant
Type : TenantEntity
Decorators :
@ManyToOne(undefined, {cascade: true, onDelete: 'CASCADE'})

The tenant that owns this object.

tenantId
Type : string
Decorators :
@ApiHideProperty()
@Column('varchar', {primary: true})
Optional vct
Type : string | VCT | null
Decorators :
@IsOptional()
@ApiProperty({description: 'VCT as a URI string (e.g., urn:eudi:pid:de:1) or as an object for EUDIPLO-hosted VCT', nullable: true, oneOf: undefined})
@Column('json', {nullable: true})
import {
    ApiExtraModels,
    ApiHideProperty,
    ApiProperty,
    getSchemaPath,
} from "@nestjs/swagger";
import { Type } from "class-transformer";
import {
    IsArray,
    IsBoolean,
    IsEnum,
    IsNumber,
    IsObject,
    IsOptional,
    IsString,
    ValidateNested,
} from "class-validator";
import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
import { TenantEntity } from "../../../../auth/tenant/entitites/tenant.entity";
import { CertEntity } from "../../../../crypto/key/entities/cert.entity";
import { WebhookConfig } from "../../../../shared/utils/webhook/webhook.dto";
import { SchemaResponse } from "../../../issuance/oid4vci/metadata/dto/schema-response.dto";
import { VCT } from "../../../issuance/oid4vci/metadata/dto/vct.dto";
import {
    IaeAction,
    IaeActionBase,
    IaeActionOpenid4vpPresentation,
    IaeActionRedirectToWeb,
    IaeActionType,
} from "./iae-action.dto";
import {
    AllowListPolicy,
    AttestationBasedPolicy,
    EmbeddedDisclosurePolicy,
    NoneTrustPolicy,
    RootOfTrustPolicy,
} from "./policies.dto";

export class DisplayImage {
    @IsString()
    uri!: string;
}
export class Display {
    @IsString()
    name!: string;
    @IsString()
    description!: string;
    @IsString()
    locale!: string;
    @IsOptional()
    @IsString()
    background_color?: string;
    @IsOptional()
    @IsString()
    text_color?: string;
    @IsOptional()
    @ValidateNested()
    @Type(() => DisplayImage)
    background_image?: DisplayImage;
    @IsOptional()
    @ValidateNested()
    @Type(() => DisplayImage)
    logo?: DisplayImage;
}

export enum CredentialFormat {
    MSO_MDOC = "mso_mdoc",
    SD_JWT = "dc+sd-jwt",
}

export class IssuerMetadataCredentialConfig {
    @IsEnum(CredentialFormat)
    format!: CredentialFormat;
    @ValidateNested()
    @Type(() => Display)
    display!: Display[];
    @IsOptional()
    @IsString()
    scope?: string;

    /**
     * Document type for mDOC credentials (e.g., "org.iso.18013.5.1.mDL").
     * Only applicable when format is "mso_mdoc".
     */
    @IsOptional()
    @IsString()
    docType?: string;

    /**
     * Namespace for mDOC credentials (e.g., "org.iso.18013.5.1").
     * Only applicable when format is "mso_mdoc".
     * Used when claims are provided as a flat object.
     */
    @IsOptional()
    @IsString()
    namespace?: string;

    /**
     * Claims organized by namespace for mDOC credentials.
     * Allows specifying claims across multiple namespaces.
     * Only applicable when format is "mso_mdoc".
     * Example:
     * {
     *   "org.iso.18013.5.1": { "given_name": "John", "family_name": "Doe" },
     *   "org.iso.18013.5.1.aamva": { "DHS_compliance": "F" }
     * }
     */
    @IsOptional()
    @IsObject()
    claimsByNamespace?: Record<string, Record<string, any>>;
}

@ApiExtraModels(
    AttestationBasedPolicy,
    NoneTrustPolicy,
    AllowListPolicy,
    RootOfTrustPolicy,
    VCT,
    IaeActionOpenid4vpPresentation,
    IaeActionRedirectToWeb,
)
@Entity()
export class CredentialConfig {
    @IsString()
    @Column("varchar", { primary: true })
    id!: string;

    @IsString()
    @Column("varchar", { nullable: true })
    description?: string | null;

    @ApiHideProperty()
    @Column("varchar", { primary: true })
    tenantId!: string;

    /**
     * The tenant that owns this object.
     */
    @ManyToOne(() => TenantEntity, { cascade: true, onDelete: "CASCADE" })
    tenant!: TenantEntity;

    @Column("json")
    @ValidateNested()
    @Type(() => IssuerMetadataCredentialConfig)
    config!: IssuerMetadataCredentialConfig;

    @Column("json", { nullable: true })
    @IsOptional()
    @IsObject()
    claims?: Record<string, any> | null;

    /**
     * Webhook to receive claims for the issuance process.
     */
    @IsOptional()
    @ValidateNested()
    @Type(() => WebhookConfig)
    @Column("json", { nullable: true })
    claimsWebhook?: WebhookConfig | null;

    /**
     * Webhook to receive claims for the issuance process.
     */
    @IsOptional()
    @ValidateNested()
    @Type(() => WebhookConfig)
    @Column("json", { nullable: true })
    notificationWebhook?: WebhookConfig | null;

    // has to be optional since there may be credentials that are disclosed without a frame
    @Column("json", { nullable: true })
    @IsOptional()
    @IsObject()
    disclosureFrame?: Record<string, any> | null;

    @IsOptional()
    @ApiProperty({
        description:
            "VCT as a URI string (e.g., urn:eudi:pid:de:1) or as an object for EUDIPLO-hosted VCT",
        nullable: true,
        oneOf: [
            { type: "string", description: "VCT URI string" },
            { $ref: getSchemaPath(VCT) },
        ],
    })
    @Column("json", { nullable: true })
    vct?: string | VCT | null;

    @IsOptional()
    @Column("boolean", { default: false })
    @IsBoolean()
    keyBinding?: boolean;

    /**
     * Reference to the certificate used for signing.
     * Note: No DB-level FK constraint because CertEntity has a composite PK
     * (id + tenantId) and SET NULL behavior cannot work when tenantId is
     * part of this entity's own PK.
     */
    @IsOptional()
    @IsString()
    @Column("varchar", { nullable: true })
    certId?: string;

    @ManyToOne(() => CertEntity, { createForeignKeyConstraints: false })
    @JoinColumn([
        { name: "certId", referencedColumnName: "id" },
        { name: "tenantId", referencedColumnName: "tenantId" },
    ])
    cert?: CertEntity;

    @IsOptional()
    @Column("boolean", { default: false })
    @IsBoolean()
    statusManagement?: boolean;

    /**
     * List of Interactive Authorization Endpoint (IAE) actions to execute
     * before credential issuance. Actions are executed in order.
     *
     * Each action can be:
     * - `openid4vp_presentation`: Request a verifiable presentation from the wallet
     * - `redirect_to_web`: Redirect user to a web page for additional interaction
     *
     * If empty or not set, no interactive authorization is required.
     *
     * @example
     * [
     *   { "type": "openid4vp_presentation", "presentationConfigId": "pid-config" },
     *   { "type": "redirect_to_web", "url": "https://example.com/verify", "label": "Additional Verification" }
     * ]
     */
    @IsOptional()
    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => IaeActionBase, {
        discriminator: {
            property: "type",
            subTypes: [
                {
                    name: IaeActionType.OPENID4VP_PRESENTATION,
                    value: IaeActionOpenid4vpPresentation,
                },
                {
                    name: IaeActionType.REDIRECT_TO_WEB,
                    value: IaeActionRedirectToWeb,
                },
            ],
        },
        keepDiscriminatorProperty: true,
    })
    @ApiProperty({
        description:
            "List of IAE actions to execute before credential issuance",
        type: "array",
        items: {
            oneOf: [
                { $ref: getSchemaPath(IaeActionOpenid4vpPresentation) },
                { $ref: getSchemaPath(IaeActionRedirectToWeb) },
            ],
        },
        nullable: true,
        required: false,
    })
    @Column("json", { nullable: true })
    iaeActions?: IaeAction[] | null;

    @IsOptional()
    @Column("int", { nullable: true })
    @IsNumber()
    lifeTime?: number;

    @IsOptional()
    @ValidateNested()
    @Type(() => SchemaResponse)
    @Column("json", { nullable: true })
    schema?: SchemaResponse | null;

    /**
     * Embedded disclosure policy (discriminated union by `policy`).
     * The discriminator makes class-transformer instantiate the right subclass,
     * and then class-validator runs that subclass’s rules.
     */
    @IsOptional()
    @ValidateNested()
    @ApiProperty({
        oneOf: [
            { $ref: getSchemaPath(AttestationBasedPolicy) },
            { $ref: getSchemaPath(NoneTrustPolicy) },
            { $ref: getSchemaPath(AllowListPolicy) },
            { $ref: getSchemaPath(RootOfTrustPolicy) },
        ],
    })
    @Type(() => AttestationBasedPolicy, {
        discriminator: {
            property: "policy",
            subTypes: [
                { name: "none", value: NoneTrustPolicy },
                { name: "allowList", value: AllowListPolicy },
                { name: "rootOfTrust", value: RootOfTrustPolicy },
                {
                    name: "attestationBased",
                    value: AttestationBasedPolicy,
                },
            ],
        },
        keepDiscriminatorProperty: true, // keep `policy` on the instance
    })
    @Column("json", { nullable: true })
    embeddedDisclosurePolicy?: EmbeddedDisclosurePolicy | null;
}

results matching ""

    No results matching ""