- Add MongoDB connection module for database access - Implement Mailgun email service for sending notifications - Add shareChecksum utility for generating secure share links - Implement three email sender functions: - Email verification requests (highest priority) - Rent due notifications (CET timezone) - Utility bills due notifications - Create main email worker with budget-based email sending - Add environment variables for configuration - Install dependencies: mongodb, mailgun.js, form-data - Update package.json description to reflect email worker purpose - Add .env.example with all required configuration The worker processes emails in priority order and respects a configurable budget to prevent overwhelming the mail server. All database operations are atomic and updates are performed immediately after each email send. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
37 lines
1.0 KiB
TypeScript
37 lines
1.0 KiB
TypeScript
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;
|
|
}
|