65 lines
2 KiB
TypeScript
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)}`);
|
|
}
|
|
}
|