import { Injectable, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as crypto from "crypto" import { TelebirrDto } from '../dto/telebirr.dto'; @Injectable() export class TelebirrWebhookService { // private readonly logger = new Logger(TelebirrWebhookService.name); constructor( private readonly config: ConfigService ) { } verifyTelebirrNotification(payload: TelebirrDto) { // 1. Extract the signature provided by Telebirr const { sign, ...bizContent } = payload; if (!sign) { throw new Error("Missing 'sign' field from Telebirr payload"); } // 2. Sort the remaining keys alphabetically to rebuild the raw string const sortedKeys = Object.keys(bizContent).sort(); const signString = sortedKeys .map(key => `${key}=${typeof bizContent[key] === 'object' ? JSON.stringify(bizContent[key]) : bizContent[key]}`) .join('&'); // 3. Convert Telebirr's public key into an object specifying RSA-PSS padding const publicKey = { key: this.config.get("telebirr.publicKey") ?? "", padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 // Telebirr standard salt length }; // 4. Verify the signature against the sorted string const isVerified = crypto.verify( "sha256", Buffer.from(signString), publicKey, Buffer.from(sign, 'base64') ); return isVerified; } async handle(payload: TelebirrDto): Promise { console.log(payload) } }