ceo-api/src/modules/webhooks/webhooks.service.ts

65 lines
2 KiB
TypeScript

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as crypto from 'crypto';
export interface PaperlessPayload {
document_id?: number;
id?: number;
title?: string;
document_type?: string;
correspondent?: string;
tags?: string[];
created?: string;
added?: string;
content?: string;
original_file_name?: string;
}
@Injectable()
export class WebhooksService {
private readonly logger = new Logger(WebhooksService.name);
private readonly secret: string;
constructor(private readonly config: ConfigService) {
this.secret = config.get('PAPERLESS_WEBHOOK_SECRET', '');
}
validateSignature(payload: string, signature: string): boolean {
if (!this.secret) return true; // secret not configured → allow (dev mode)
const expected = 'sha256=' + crypto
.createHmac('sha256', this.secret)
.update(payload)
.digest('hex');
try {
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
} catch {
return false;
}
}
buildObservation(doc: PaperlessPayload) {
const docId = doc.document_id ?? doc.id ?? 0;
const tags = ['document', 'inbox', ...(doc.tags ?? [])];
if (doc.document_type) tags.push(doc.document_type.toLowerCase().replace(/\s+/g, '-'));
return {
metric: 'document-received',
value: doc.title ?? `Document #${docId}`,
unit: doc.document_type ?? 'document',
subjectType: 'document',
confidence: 1,
source: doc.correspondent ?? undefined,
observedAt: doc.added ?? doc.created ?? new Date().toISOString(),
metadata: {
paperlessId: docId,
originalFile: doc.original_file_name,
tags: doc.tags,
excerpt: doc.content?.slice(0, 500),
},
};
}
logIncoming(type: string, payload: unknown) {
this.logger.log(`Webhook received: ${type}${JSON.stringify(payload).slice(0, 200)}`);
}
}