File

src/issuer/credentials/credential-config/credential-config.service.ts

Description

Service for managing credential configurations.

Index

Methods

Constructor

constructor(credentialConfigRepository: Repository<CredentialConfig>, configService: ConfigService, logger: PinoLogger, cryptoService: CryptoService)

Constructor for CredentialConfigService.

Parameters :
Name Type Optional Description
credentialConfigRepository Repository<CredentialConfig> No
  • Repository for CredentialConfig entity.
configService ConfigService No
logger PinoLogger No
cryptoService CryptoService No

Methods

delete
delete(tenantId: string, id: string)

Deletes a credential configuration for a given tenant.

Parameters :
Name Type Optional Description
tenantId string No
  • The ID of the tenant.
id string No
  • The ID of the CredentialConfig entity to delete.
Returns : any

A promise that resolves to the result of the delete operation.

get
get(tenantId: string)

Retrieves all credential configurations for a given tenant.

Parameters :
Name Type Optional Description
tenantId string No
  • The ID of the tenant.
Returns : any

A promise that resolves to an array of CredentialConfig entities.

getById
getById(tenantId: string, id: string)

Retrieves a credential configuration by its ID for a given tenant.

Parameters :
Name Type Optional
tenantId string No
id string No
Returns : any
Public Async import
import()

Imports the configs

Returns : any
Async onTenantDelete
onTenantDelete(tenantId: string)
Parameters :
Name Type Optional
tenantId string No
Returns : any
store
store(tenantId: string, config: CredentialConfigCreate)

Stores a credential configuration for a given tenant. If the configuration already exists, it will be overwritten.

Parameters :
Name Type Optional Description
tenantId string No
  • The ID of the tenant.
config CredentialConfigCreate No
  • The CredentialConfig entity to store.
Returns : any

A promise that resolves to the stored CredentialConfig entity.

import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { InjectRepository } from "@nestjs/typeorm";
import { plainToClass } from "class-transformer";
import { validate } from "class-validator";
import { readdirSync, readFileSync } from "fs";
import { PinoLogger } from "nestjs-pino";
import { join } from "path";
import { Repository } from "typeorm";
import { CryptoService } from "../../../crypto/crypto.service";
import { CredentialConfigCreate } from "../dto/credential-config-create.dto";
import { CredentialConfig } from "../entities/credential.entity";

/**
 * Service for managing credential configurations.
 */
@Injectable()
export class CredentialConfigService {
    /**
     * Constructor for CredentialConfigService.
     * @param credentialConfigRepository - Repository for CredentialConfig entity.
     */
    constructor(
        @InjectRepository(CredentialConfig)
        private readonly credentialConfigRepository: Repository<CredentialConfig>,
        private configService: ConfigService,
        private logger: PinoLogger,
        private cryptoService: CryptoService,
    ) {}

    /**
     * Imports the configs
     */
    public async import() {
        const configPath = this.configService.getOrThrow("CONFIG_FOLDER");
        const subfolder = "issuance/credentials";
        const force = this.configService.get<boolean>("CONFIG_IMPORT_FORCE");
        if (this.configService.get<boolean>("CONFIG_IMPORT")) {
            const tenantFolders = readdirSync(configPath, {
                withFileTypes: true,
            }).filter((tenant) => tenant.isDirectory());
            for (const tenant of tenantFolders) {
                let counter = 0;
                //iterate over all elements in the folder and import them
                const path = join(configPath, tenant.name, subfolder);
                const files = readdirSync(path);
                for (const file of files) {
                    try {
                        const payload = JSON.parse(
                            readFileSync(join(path, file), "utf8"),
                        );

                        const id = file.replace(".json", "");
                        payload.id = id;
                        const exists = await this.getById(
                            tenant.name,
                            id,
                        ).catch(() => false);
                        if (exists && !force) {
                            continue; // Skip if config already exists and force is not set
                        } else if (exists && force) {
                            //delete old element so removed elements are not present
                            await this.credentialConfigRepository.delete({
                                id,
                                tenantId: tenant.name,
                            });
                        }

                        // Validate the payload against CredentialConfig
                        const config = plainToClass(
                            CredentialConfigCreate,
                            payload,
                        );
                        const validationErrors = await validate(config, {
                            whitelist: true,
                            forbidUnknownValues: false, // avoid false positives on plain objects
                            forbidNonWhitelisted: false,
                            stopAtFirstError: false,
                        });

                        // Check if keyId is provided and if the certificate exists
                        if (config.keyId) {
                            console.log(config.keyId);
                            console.log(tenant.name);
                            const cert = await this.cryptoService.getCertEntry(
                                tenant.name,
                                config.keyId,
                            );
                            if (!cert) {
                                this.logger.error(
                                    {
                                        event: "ValidationError",
                                        file,
                                        tenant: tenant.name,
                                        errors: [
                                            {
                                                property: "keyId",
                                                constraints: {
                                                    isDefined:
                                                        "Key ID must be defined in the crypto service.",
                                                },
                                                value: config.keyId,
                                            },
                                        ],
                                    },
                                    `Validation failed for credentials config ${file} in tenant ${tenant.name}`,
                                );
                                continue; // Skip this invalid config
                            }
                            (config as CredentialConfig).key = cert;
                        }

                        if (validationErrors.length > 0) {
                            this.logger.error(
                                {
                                    event: "ValidationError",
                                    file,
                                    tenant: tenant.name,
                                    //we need to extract the constraints because they tell what is wrong, also from the children elements
                                    errors: validationErrors,
                                },
                                `Validation failed for credentials config ${file} in tenant ${tenant.name}`,
                            );
                            continue; // Skip this invalid config
                        }

                        await this.store(tenant.name, config);
                        counter++;
                    } catch (e) {
                        this.logger.error(
                            {
                                event: "ImportError",
                                file,
                                tenant: tenant.name,
                                error: e.message,
                            },
                            `Failed to import credentials config ${file} in tenant ${tenant.name}`,
                        );
                    }
                }
                this.logger.info(
                    {
                        event: "Import",
                    },
                    `${counter} credential configs imported for ${tenant.name}`,
                );
            }
        }
    }

    async onTenantDelete(tenantId: string) {
        await this.credentialConfigRepository.delete({ tenantId });
    }

    /**
     * Retrieves all credential configurations for a given tenant.
     * @param tenantId - The ID of the tenant.
     * @returns A promise that resolves to an array of CredentialConfig entities.
     */
    get(tenantId: string) {
        return this.credentialConfigRepository.find({
            where: { tenantId },
            relations: ["key"],
        });
    }

    /**
     * Retrieves a credential configuration by its ID for a given tenant.
     * @param tenantId
     * @param id
     * @returns
     */
    getById(tenantId: string, id: string) {
        return this.credentialConfigRepository.findOneByOrFail({
            id,
            tenantId,
        });
    }

    /**
     * Stores a credential configuration for a given tenant.
     * If the configuration already exists, it will be overwritten.
     * @param tenantId - The ID of the tenant.
     * @param config - The CredentialConfig entity to store.
     * @returns A promise that resolves to the stored CredentialConfig entity.
     */
    store(tenantId: string, config: CredentialConfigCreate) {
        return this.credentialConfigRepository.save({
            ...config,
            tenantId,
        });
    }

    /**
     * Deletes a credential configuration for a given tenant.
     * @param tenantId - The ID of the tenant.
     * @param id - The ID of the CredentialConfig entity to delete.
     * @returns A promise that resolves to the result of the delete operation.
     */
    delete(tenantId: string, id: string) {
        return this.credentialConfigRepository.delete({
            id,
            tenantId,
        });
    }
}

results matching ""

    No results matching ""