refactor: migrate email-worker to use shared-code package
Update email-worker to use @evidencija-rezija/shared-code for common types and utilities instead of maintaining duplicate copies. Changes: - Add shared-code dependency to package.json - Update imports in emailSenders.ts to use shared-code - Remove duplicate db-types.ts and shareChecksum.ts files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
"author": "Nikola",
|
"author": "Nikola",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@evidencija-rezija/shared-code": "^1.0.0",
|
||||||
"debug": "^2.6.9",
|
"debug": "^2.6.9",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"form-data": "^4.0.5",
|
"form-data": "^4.0.5",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Db, ObjectId } from 'mongodb';
|
import { Db, ObjectId } from 'mongodb';
|
||||||
import { BillingLocation, EmailStatus, UserSettings } from '../types/db-types';
|
import { BillingLocation, EmailStatus, UserSettings, generateShareId } from '@evidencija-rezija/shared-code';
|
||||||
import { generateShareId } from './shareChecksum';
|
|
||||||
import { sendEmail } from './mailgunService';
|
import { sendEmail } from './mailgunService';
|
||||||
import { createLogger } from './logger';
|
import { createLogger } from './logger';
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import crypto from 'crypto';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checksum length in hex characters (16 chars = 64 bits of entropy)
|
|
||||||
*/
|
|
||||||
export const CHECKSUM_LENGTH = 16;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate share link checksum for location
|
|
||||||
* Uses HMAC-SHA256 for cryptographic integrity
|
|
||||||
*
|
|
||||||
* SECURITY: Prevents location ID enumeration while allowing stateless validation
|
|
||||||
*/
|
|
||||||
export function generateShareChecksum(locationId: string): string {
|
|
||||||
const secret = process.env.SHARE_LINK_SECRET;
|
|
||||||
|
|
||||||
if (!secret) {
|
|
||||||
throw new Error('SHARE_LINK_SECRET environment variable not configured');
|
|
||||||
}
|
|
||||||
|
|
||||||
return crypto
|
|
||||||
.createHmac('sha256', secret)
|
|
||||||
.update(locationId)
|
|
||||||
.digest('hex')
|
|
||||||
.substring(0, CHECKSUM_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate combined location ID with checksum appended
|
|
||||||
* @param locationId - The MongoDB location ID (24 chars)
|
|
||||||
* @returns Combined ID: locationId + checksum (40 chars total)
|
|
||||||
*/
|
|
||||||
export function generateShareId(locationId: string): string {
|
|
||||||
const checksum = generateShareChecksum(locationId);
|
|
||||||
return locationId + checksum;
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import { ObjectId } from 'mongodb';
|
|
||||||
|
|
||||||
export interface YearMonth {
|
|
||||||
year: number;
|
|
||||||
month: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum EmailStatus {
|
|
||||||
/** Email is not yet verified - recipient has not yet confirmed their email address */
|
|
||||||
Unverified = "unverified",
|
|
||||||
/** Email is not yet verified - a verification request has been sent */
|
|
||||||
VerificationPending = "verification-pending",
|
|
||||||
/** sending of verification email failed */
|
|
||||||
VerificationFailed = "verification-failed",
|
|
||||||
/** Email is verified and is in good standing: emails are being successfully delivered */
|
|
||||||
Verified = "verified",
|
|
||||||
/** Recepient has unsubscribed from receiving emails via link - no further emails will be sent */
|
|
||||||
Unsubscribed = "unsubscribed"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** User settings data */
|
|
||||||
export interface UserSettings {
|
|
||||||
/** user's ID */
|
|
||||||
userId: string;
|
|
||||||
/** owner name */
|
|
||||||
ownerName?: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Billing location document from MongoDB */
|
|
||||||
export interface BillingLocation {
|
|
||||||
_id: ObjectId;
|
|
||||||
/** user's ID */
|
|
||||||
userId: string;
|
|
||||||
/** name of the location */
|
|
||||||
name: string;
|
|
||||||
/** billing period year and month */
|
|
||||||
yearMonth: YearMonth;
|
|
||||||
/** (optional) tenant name */
|
|
||||||
tenantName?: string | null;
|
|
||||||
/** (optional) tenant email */
|
|
||||||
tenantEmail?: string | null;
|
|
||||||
/** (optional) tenant email status */
|
|
||||||
tenantEmailStatus?: EmailStatus | null;
|
|
||||||
/** (optional) whether to automatically notify tenant */
|
|
||||||
billFwdEnabled?: boolean | null;
|
|
||||||
/** (optional) bill forwarding status */
|
|
||||||
billFwdStatus?: "pending" | "sent" | "failed" | null;
|
|
||||||
/** (optional) whether to automatically send rent notification */
|
|
||||||
rentDueNotificationEnabled?: boolean | null;
|
|
||||||
/** (optional) day of month when rent is due (1-31) */
|
|
||||||
rentDueDay?: number | null;
|
|
||||||
/** (optional) when was the rent due notification sent */
|
|
||||||
rentDueNotificationStatus?: "sent" | "failed" | null;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user