File

src/auth/client.service.ts

Index

Properties
Methods

Constructor

constructor(configService: ConfigService, cryptoService: CryptoService, encryptionService: EncryptionService, statutsListService: StatusListService, registrarService: RegistrarService, clientRepository: Repository<ClientEntry>, tenantClientTotal: Gauge)
Parameters :
Name Type Optional
configService ConfigService No
cryptoService CryptoService No
encryptionService EncryptionService No
statutsListService StatusListService No
registrarService RegistrarService No
clientRepository Repository<ClientEntry> No
tenantClientTotal Gauge<string> No

Methods

findClientById
findClientById(clientId: string)

Find client by ID

Parameters :
Name Type Optional
clientId string No
Returns : Client | null
Private getClients
getClients()

Get clients from configuration

Returns : Client[]
Async isSetUp
isSetUp(id: string)

Check if the client is set up, if not, set it up.

Parameters :
Name Type Optional
id string No
Returns : any
Private loadClients
loadClients()

Load clients from configuration

Returns : Client[]
Async onApplicationBootstrap
onApplicationBootstrap()
Returns : any
Async setUpClient
setUpClient(id: string)

Sends an event to set up a client, allowing all other services to listen and react accordingly.

Parameters :
Name Type Optional
id string No
Returns : any
validateClient
validateClient(clientId: string, clientSecret: string)

Validate client credentials (OAuth2 Client Credentials flow) This is the primary authentication method for service integration

Parameters :
Name Type Optional
clientId string No
clientSecret string No
Returns : Client | null

Properties

Private clients
Type : Client[] | null
Default value : null
import {
    BadRequestException,
    Injectable,
    OnApplicationBootstrap,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { join } from 'path';
import { CryptoService } from '../crypto/crypto.service';
import { EncryptionService } from '../crypto/encryption/encryption.service';
import { StatusListService } from '../issuer/status-list/status-list.service';
import { RegistrarService } from '../registrar/registrar.service';
import { InjectRepository } from '@nestjs/typeorm';
import { ClientEntry } from './entitites/client.entity';
import { Repository } from 'typeorm/repository/Repository';
import { InjectMetric } from '@willsoto/nestjs-prometheus';
import { Gauge } from 'prom-client';

// Client interface for service integration
export interface Client {
    id: string;
    secret: string;
}

@Injectable()
export class ClientService implements OnApplicationBootstrap {
    private clients: Client[] | null = null;

    constructor(
        private configService: ConfigService,
        private cryptoService: CryptoService,
        private encryptionService: EncryptionService,
        private statutsListService: StatusListService,
        private registrarService: RegistrarService,
        @InjectRepository(ClientEntry)
        private clientRepository: Repository<ClientEntry>,
        @InjectMetric('tenant_client_total')
        private tenantClientTotal: Gauge<string>,
    ) {}

    async onApplicationBootstrap() {
        // Initialize the client metrics
        const count = await this.clientRepository.countBy({ status: 'set up' });
        this.tenantClientTotal.set({}, count);
    }

    /**
     * Get clients from configuration
     * @returns
     */
    private getClients(): Client[] {
        if (!this.clients) {
            this.clients = this.loadClients();
        }
        return this.clients;
    }

    /**
     * Load clients from configuration
     */
    private loadClients(): Client[] {
        // Default clients for development/testing
        return [
            {
                id: this.configService.getOrThrow<string>('AUTH_CLIENT_ID'),
                secret: this.configService.getOrThrow<string>(
                    'AUTH_CLIENT_SECRET',
                ),
            },
        ];
    }

    /**
     * Validate client credentials (OAuth2 Client Credentials flow)
     * This is the primary authentication method for service integration
     */
    validateClient(clientId: string, clientSecret: string): Client | null {
        const client = this.getClients().find((c) => c.id === clientId);

        if (!client || client.secret !== clientSecret) {
            return null;
        }

        return client;
    }

    /**
     * Find client by ID
     */
    findClientById(clientId: string): Client | null {
        return this.getClients().find((c) => c.id === clientId) || null;
    }

    /**
     * Check if the client is set up, if not, set it up.
     * @param id
     * @returns
     */
    async isSetUp(id: string) {
        void this.clientRepository
            .countBy({ status: 'set up' })
            .then((count) => {
                this.tenantClientTotal.set({}, count);
            });

        await this.clientRepository.findOneByOrFail({ id }).then(
            (res) => {
                if (res.status === 'set up') {
                    return true;
                }
                throw new BadRequestException(
                    `Client ${id} is not set up. Please retry later.`,
                );
            },
            async () => {
                // create it to signl that the client getting set up
                await this.clientRepository.save({ id });
                await this.setUpClient(id).catch(async (err) => {
                    console.error(err);
                    // if there is an error, update the client status"
                    await this.clientRepository.update(
                        { id },
                        { status: 'error', error: err.message },
                    );
                    throw new BadRequestException(
                        `Error setting up client ${id}. Please retry later.`,
                    );
                });
                // if everything is fine, update the client status
                return this.clientRepository.update(
                    { id },
                    { status: 'set up' },
                );
            },
        );
    }

    /**
     * Sends an event to set up a client, allowing all other services to listen and react accordingly.
     * @param id
     */
    async setUpClient(id: string) {
        const folder = join(
            this.configService.getOrThrow<string>('FOLDER'),
            id,
        );
        if (!existsSync(folder)) {
            mkdirSync(folder, { recursive: true });
        }

        const displayInfo = [
            {
                name: 'EUDI Wallet dev',
                locale: 'de-DE',
                logo: {
                    uri: '<PUBLIC_URL>/issuer.png',
                    url: '<PUBLIC_URL>/issuer.png',
                },
            },
        ];
        writeFileSync(
            join(folder, 'display.json'),
            JSON.stringify(displayInfo, null, 2),
        );
        await this.cryptoService.onTenantInit(id);
        await this.encryptionService.onTenantInit(id);
        await this.statutsListService.onTenantInit(id);
        await this.registrarService.onTenantInit(id);
    }
}

results matching ""

    No results matching ""