const express = require('express'); const rateLimit = require('express-rate-limit'); const { success, error: errorResponse } = require('../src/utils/responses'); const { ValidationError } = require('../src/utilities/errors'); // Dedicated rate limiter for license activation — prevents brute-force key guessing. // Pro keys follow a predictable format (DC-XXX-XXXXX-XXXXXX), so without rate // limiting an attacker could enumerate valid keys. const licenseActivateLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 10, // 10 attempts per window per IP standardHeaders: true, legacyHeaders: false, message: { success: false, error: 'Too many license activation attempts. Please try again later.' }, skip: () => process.env.NODE_ENV === 'test', }); /** * License routes factory * @param {Object} deps - Explicit dependencies * @param {Object} deps.licenseManager - License management module * @param {Function} deps.asyncHandler - Async route handler wrapper * @returns {express.Router} */ module.exports = function({ licenseManager, asyncHandler }) { const router = express.Router(); // Activate a license code router.post('/activate', licenseActivateLimiter, asyncHandler(async (req, res) => { const { code } = req.body; if (!code) { throw new ValidationError('License code is required'); } const result = await licenseManager.activate(code); if (result.success) { success(res, { message: result.message, license: result.activation }); } else { errorResponse(res, result.message, 400); } }, 'license-activate')); // Get current license status router.get('/status', asyncHandler(async (req, res) => { await licenseManager.refreshOnline?.(); const status = licenseManager.getStatus(); success(res, { license: status }); }, 'license-status')); // Deactivate current license router.post('/deactivate', asyncHandler(async (req, res) => { const result = await licenseManager.deactivate(); if (result.success) { success(res, { message: result.message }); } else { errorResponse(res, result.message, 400); } }, 'license-deactivate')); // Check if a specific feature is available (lightweight check for frontend) router.get('/feature/:feature', asyncHandler(async (req, res) => { const { feature } = req.params; const available = licenseManager.hasFeature(feature); const status = licenseManager.getStatus(); success(res, { feature, available, tier: status.tier, ...(available ? {} : { upgradeUrl: '/settings#license', message: `${status.premiumFeatures[feature]?.name || feature} requires DashCaddy Premium` }) }); }, 'license-feature-check')); return router; };