Fix jwt-token
This commit is contained in:
313
server/routes/auth.js
Normal file
313
server/routes/auth.js
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Multi-Tenant Authentication Routes
|
||||
* Handles authentication for different providers and tenants
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const passport = require('passport');
|
||||
const session = require('express-session');
|
||||
const { Tenant } = require('../models');
|
||||
const MultiTenantAuth = require('../middleware/multi-tenant-auth');
|
||||
const SAMLAuth = require('../middleware/saml-auth');
|
||||
const OAuthAuth = require('../middleware/oauth-auth');
|
||||
const LDAPAuth = require('../middleware/ldap-auth');
|
||||
|
||||
// Initialize multi-tenant auth
|
||||
const multiAuth = new MultiTenantAuth();
|
||||
|
||||
// Session middleware for OAuth state management
|
||||
router.use(session({
|
||||
secret: process.env.SESSION_SECRET || 'your-session-secret',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: { maxAge: 10 * 60 * 1000 } // 10 minutes
|
||||
}));
|
||||
|
||||
// Initialize passport
|
||||
router.use(passport.initialize());
|
||||
router.use(passport.session());
|
||||
|
||||
passport.serializeUser((user, done) => done(null, user));
|
||||
passport.deserializeUser((obj, done) => done(null, obj));
|
||||
|
||||
/**
|
||||
* GET /auth/config/:tenantId
|
||||
* Get authentication configuration for a tenant
|
||||
*/
|
||||
router.get('/config/:tenantId', async (req, res) => {
|
||||
try {
|
||||
const { tenantId } = req.params;
|
||||
|
||||
const tenant = await Tenant.findOne({ where: { slug: tenantId } });
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Return public auth configuration (no secrets)
|
||||
const publicConfig = {
|
||||
provider: tenant.auth_provider,
|
||||
enabled: tenant.is_active,
|
||||
features: {
|
||||
local_login: tenant.auth_provider === 'local',
|
||||
sso_login: ['saml', 'oauth', 'ldap'].includes(tenant.auth_provider),
|
||||
registration: tenant.auth_provider === 'local'
|
||||
}
|
||||
};
|
||||
|
||||
// Add provider-specific public config
|
||||
if (tenant.auth_provider === 'saml') {
|
||||
publicConfig.saml = {
|
||||
login_url: `/auth/saml/${tenantId}/login`,
|
||||
metadata_url: `/auth/saml/${tenantId}/metadata`
|
||||
};
|
||||
} else if (tenant.auth_provider === 'oauth') {
|
||||
publicConfig.oauth = {
|
||||
login_url: `/auth/oauth/${tenantId}/login`
|
||||
};
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: publicConfig
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching auth config:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch authentication configuration'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /auth/login
|
||||
* Universal login endpoint that routes to appropriate provider
|
||||
*/
|
||||
router.post('/login', async (req, res, next) => {
|
||||
try {
|
||||
// Determine tenant
|
||||
const tenantId = await multiAuth.determineTenant(req);
|
||||
const authConfig = await multiAuth.getTenantAuthConfig(tenantId);
|
||||
|
||||
req.tenant = { id: tenantId, authConfig };
|
||||
|
||||
// Route based on authentication provider
|
||||
switch (authConfig.type) {
|
||||
case 'local':
|
||||
return require('../routes/user').loginLocal(req, res, next);
|
||||
|
||||
case 'ldap':
|
||||
const ldapAuth = new LDAPAuth();
|
||||
return ldapAuth.authenticate(req, res, next);
|
||||
|
||||
case 'saml':
|
||||
case 'oauth':
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Please use SSO login for ${authConfig.type} authentication`,
|
||||
redirect_url: `/auth/${authConfig.type}/${tenantId}/login`
|
||||
});
|
||||
|
||||
default:
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Authentication provider not configured'
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Login failed'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* SAML Authentication Routes
|
||||
*/
|
||||
|
||||
// GET /auth/saml/:tenantId/login - Initiate SAML login
|
||||
router.get('/saml/:tenantId/login', async (req, res, next) => {
|
||||
try {
|
||||
const tenantId = req.params.tenantId;
|
||||
req.tenant = {
|
||||
id: tenantId,
|
||||
authConfig: await multiAuth.getTenantAuthConfig(tenantId)
|
||||
};
|
||||
|
||||
const samlAuth = new SAMLAuth();
|
||||
return samlAuth.authenticate(req, res, next);
|
||||
|
||||
} catch (error) {
|
||||
console.error('SAML login error:', error);
|
||||
res.redirect(`/login?error=saml_error&tenant=${req.params.tenantId}`);
|
||||
}
|
||||
});
|
||||
|
||||
// POST /auth/saml/:tenantId/callback - SAML callback
|
||||
router.post('/saml/:tenantId/callback', async (req, res, next) => {
|
||||
const samlAuth = new SAMLAuth();
|
||||
return samlAuth.handleCallback(req, res, next);
|
||||
});
|
||||
|
||||
// GET /auth/saml/:tenantId/metadata - SAML metadata
|
||||
router.get('/saml/:tenantId/metadata', async (req, res) => {
|
||||
try {
|
||||
const { tenantId } = req.params;
|
||||
const authConfig = await multiAuth.getTenantAuthConfig(tenantId);
|
||||
|
||||
if (authConfig.type !== 'saml') {
|
||||
return res.status(404).json({ message: 'SAML not configured for this tenant' });
|
||||
}
|
||||
|
||||
const samlAuth = new SAMLAuth();
|
||||
const metadata = samlAuth.generateMetadata(tenantId, authConfig.config);
|
||||
|
||||
res.set('Content-Type', 'application/xml');
|
||||
res.send(metadata);
|
||||
|
||||
} catch (error) {
|
||||
console.error('SAML metadata error:', error);
|
||||
res.status(500).json({ message: 'Failed to generate SAML metadata' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* OAuth Authentication Routes
|
||||
*/
|
||||
|
||||
// GET /auth/oauth/:tenantId/login - Initiate OAuth login
|
||||
router.get('/oauth/:tenantId/login', async (req, res, next) => {
|
||||
try {
|
||||
const tenantId = req.params.tenantId;
|
||||
req.tenant = {
|
||||
id: tenantId,
|
||||
authConfig: await multiAuth.getTenantAuthConfig(tenantId)
|
||||
};
|
||||
|
||||
const oauthAuth = new OAuthAuth();
|
||||
return oauthAuth.authenticate(req, res, next);
|
||||
|
||||
} catch (error) {
|
||||
console.error('OAuth login error:', error);
|
||||
res.redirect(`/login?error=oauth_error&tenant=${req.params.tenantId}`);
|
||||
}
|
||||
});
|
||||
|
||||
// GET /auth/oauth/:tenantId/callback - OAuth callback
|
||||
router.get('/oauth/:tenantId/callback', async (req, res, next) => {
|
||||
const oauthAuth = new OAuthAuth();
|
||||
return oauthAuth.handleCallback(req, res, next);
|
||||
});
|
||||
|
||||
/**
|
||||
* Logout endpoint for all providers
|
||||
*/
|
||||
router.post('/logout', async (req, res) => {
|
||||
try {
|
||||
const tenantId = await multiAuth.determineTenant(req);
|
||||
const authConfig = await multiAuth.getTenantAuthConfig(tenantId);
|
||||
|
||||
// Clear local session
|
||||
req.logout((err) => {
|
||||
if (err) console.error('Logout error:', err);
|
||||
});
|
||||
|
||||
// Provider-specific logout
|
||||
if (authConfig.type === 'saml' && authConfig.config.logout_url) {
|
||||
return res.json({
|
||||
success: true,
|
||||
logout_url: authConfig.config.logout_url,
|
||||
message: 'Please complete logout with your identity provider'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Logged out successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Logout failed'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Test authentication configuration
|
||||
*/
|
||||
router.post('/test/:tenantId', async (req, res) => {
|
||||
try {
|
||||
const { tenantId } = req.params;
|
||||
const authConfig = await multiAuth.getTenantAuthConfig(tenantId);
|
||||
|
||||
let testResult = { success: false, message: 'Unknown provider' };
|
||||
|
||||
switch (authConfig.type) {
|
||||
case 'ldap':
|
||||
const ldapAuth = new LDAPAuth();
|
||||
try {
|
||||
await ldapAuth.testConnection(authConfig.config);
|
||||
testResult = { success: true, message: 'LDAP connection successful' };
|
||||
} catch (error) {
|
||||
testResult = { success: false, message: error.message };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'local':
|
||||
testResult = { success: true, message: 'Local authentication ready' };
|
||||
break;
|
||||
|
||||
case 'saml':
|
||||
// Test SAML configuration validity
|
||||
const requiredSamlFields = ['sso_url', 'certificate', 'issuer'];
|
||||
const missingSamlFields = requiredSamlFields.filter(field => !authConfig.config[field]);
|
||||
|
||||
if (missingSamlFields.length > 0) {
|
||||
testResult = {
|
||||
success: false,
|
||||
message: `Missing SAML configuration: ${missingSamlFields.join(', ')}`
|
||||
};
|
||||
} else {
|
||||
testResult = { success: true, message: 'SAML configuration valid' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'oauth':
|
||||
// Test OAuth configuration validity
|
||||
const requiredOAuthFields = ['client_id', 'client_secret', 'authorization_url', 'token_url'];
|
||||
const missingOAuthFields = requiredOAuthFields.filter(field => !authConfig.config[field]);
|
||||
|
||||
if (missingOAuthFields.length > 0) {
|
||||
testResult = {
|
||||
success: false,
|
||||
message: `Missing OAuth configuration: ${missingOAuthFields.join(', ')}`
|
||||
};
|
||||
} else {
|
||||
testResult = { success: true, message: 'OAuth configuration valid' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
res.json(testResult);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Auth test error:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Authentication test failed'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
381
server/routes/tenants.js
Normal file
381
server/routes/tenants.js
Normal file
@@ -0,0 +1,381 @@
|
||||
/**
|
||||
* Tenant Management Routes
|
||||
* Admin interface for managing tenants and their authentication configurations
|
||||
*/
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const Joi = require('joi');
|
||||
const { Tenant, User } = require('../models');
|
||||
const { validateRequest } = require('../middleware/validation');
|
||||
const { authenticateToken, requireRole } = require('../middleware/auth');
|
||||
|
||||
// Validation schemas
|
||||
const tenantSchema = Joi.object({
|
||||
name: Joi.string().required(),
|
||||
slug: Joi.string().pattern(/^[a-z0-9-]+$/).required(),
|
||||
domain: Joi.string().optional(),
|
||||
subscription_type: Joi.string().valid('free', 'basic', 'premium', 'enterprise').default('basic'),
|
||||
auth_provider: Joi.string().valid('local', 'saml', 'oauth', 'ldap', 'custom_sso').default('local'),
|
||||
auth_config: Joi.object().optional(),
|
||||
user_mapping: Joi.object().optional(),
|
||||
role_mapping: Joi.object().optional(),
|
||||
branding: Joi.object().optional(),
|
||||
features: Joi.object().optional(),
|
||||
admin_email: Joi.string().email().optional(),
|
||||
admin_phone: Joi.string().optional(),
|
||||
billing_email: Joi.string().email().optional()
|
||||
});
|
||||
|
||||
const authConfigSchema = Joi.object({
|
||||
// SAML Configuration
|
||||
sso_url: Joi.string().uri().when('auth_provider', { is: 'saml', then: Joi.required() }),
|
||||
certificate: Joi.string().when('auth_provider', { is: 'saml', then: Joi.required() }),
|
||||
issuer: Joi.string().when('auth_provider', { is: 'saml', then: Joi.required() }),
|
||||
logout_url: Joi.string().uri().optional(),
|
||||
|
||||
// OAuth Configuration
|
||||
client_id: Joi.string().when('auth_provider', { is: 'oauth', then: Joi.required() }),
|
||||
client_secret: Joi.string().when('auth_provider', { is: 'oauth', then: Joi.required() }),
|
||||
authorization_url: Joi.string().uri().when('auth_provider', { is: 'oauth', then: Joi.required() }),
|
||||
token_url: Joi.string().uri().when('auth_provider', { is: 'oauth', then: Joi.required() }),
|
||||
userinfo_url: Joi.string().uri().optional(),
|
||||
scopes: Joi.array().items(Joi.string()).optional(),
|
||||
|
||||
// LDAP Configuration
|
||||
url: Joi.string().when('auth_provider', { is: 'ldap', then: Joi.required() }),
|
||||
base_dn: Joi.string().when('auth_provider', { is: 'ldap', then: Joi.required() }),
|
||||
bind_dn: Joi.string().optional(),
|
||||
bind_password: Joi.string().optional(),
|
||||
user_search_filter: Joi.string().optional(),
|
||||
domain: Joi.string().optional()
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/tenants - List all tenants (super admin only)
|
||||
*/
|
||||
router.get('/', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const { limit = 50, offset = 0, search, auth_provider } = req.query;
|
||||
|
||||
const whereClause = {};
|
||||
if (search) {
|
||||
whereClause[Op.or] = [
|
||||
{ name: { [Op.iLike]: `%${search}%` } },
|
||||
{ slug: { [Op.iLike]: `%${search}%` } },
|
||||
{ domain: { [Op.iLike]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
if (auth_provider) {
|
||||
whereClause.auth_provider = auth_provider;
|
||||
}
|
||||
|
||||
const tenants = await Tenant.findAndCountAll({
|
||||
where: whereClause,
|
||||
attributes: { exclude: ['auth_config'] }, // Don't expose auth secrets
|
||||
include: [{
|
||||
model: User,
|
||||
as: 'users',
|
||||
attributes: ['id', 'username', 'email', 'role'],
|
||||
limit: 5
|
||||
}],
|
||||
limit: Math.min(parseInt(limit), 100),
|
||||
offset: parseInt(offset),
|
||||
order: [['created_at', 'DESC']]
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: tenants.rows,
|
||||
pagination: {
|
||||
total: tenants.count,
|
||||
limit: parseInt(limit),
|
||||
offset: parseInt(offset),
|
||||
pages: Math.ceil(tenants.count / parseInt(limit))
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching tenants:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch tenants'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/tenants - Create new tenant
|
||||
*/
|
||||
router.post('/', authenticateToken, requireRole(['admin']), validateRequest(tenantSchema), async (req, res) => {
|
||||
try {
|
||||
const tenantData = req.body;
|
||||
|
||||
// Check if slug is unique
|
||||
const existingTenant = await Tenant.findOne({ where: { slug: tenantData.slug } });
|
||||
if (existingTenant) {
|
||||
return res.status(409).json({
|
||||
success: false,
|
||||
message: 'Tenant slug already exists'
|
||||
});
|
||||
}
|
||||
|
||||
// Set default features based on subscription type
|
||||
if (!tenantData.features) {
|
||||
tenantData.features = getDefaultFeatures(tenantData.subscription_type);
|
||||
}
|
||||
|
||||
const tenant = await Tenant.create(tenantData);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: tenant,
|
||||
message: 'Tenant created successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating tenant:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to create tenant'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/tenants/:id - Get tenant details
|
||||
*/
|
||||
router.get('/:id', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const tenant = await Tenant.findByPk(req.params.id, {
|
||||
include: [{
|
||||
model: User,
|
||||
as: 'users',
|
||||
attributes: ['id', 'username', 'email', 'role', 'last_login', 'created_at']
|
||||
}]
|
||||
});
|
||||
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Mask sensitive auth configuration
|
||||
const tenantData = tenant.toJSON();
|
||||
if (tenantData.auth_config) {
|
||||
tenantData.auth_config = maskSensitiveConfig(tenantData.auth_config);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: tenantData
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching tenant:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch tenant'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT /api/tenants/:id - Update tenant
|
||||
*/
|
||||
router.put('/:id', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const tenant = await Tenant.findByPk(req.params.id);
|
||||
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
await tenant.update(req.body);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: tenant,
|
||||
message: 'Tenant updated successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error updating tenant:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to update tenant'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT /api/tenants/:id/auth-config - Update tenant authentication configuration
|
||||
*/
|
||||
router.put('/:id/auth-config', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const tenant = await Tenant.findByPk(req.params.id);
|
||||
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
const { auth_provider, auth_config, user_mapping, role_mapping } = req.body;
|
||||
|
||||
// Validate auth configuration based on provider
|
||||
const validationSchema = authConfigSchema.fork('auth_provider', (schema) =>
|
||||
schema.default(auth_provider)
|
||||
);
|
||||
|
||||
const { error } = validationSchema.validate({ auth_provider, ...auth_config });
|
||||
if (error) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid authentication configuration',
|
||||
details: error.details
|
||||
});
|
||||
}
|
||||
|
||||
await tenant.update({
|
||||
auth_provider,
|
||||
auth_config,
|
||||
user_mapping,
|
||||
role_mapping
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Authentication configuration updated successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error updating auth config:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to update authentication configuration'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/tenants/:id/test-auth - Test authentication configuration
|
||||
*/
|
||||
router.post('/:id/test-auth', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const tenant = await Tenant.findByPk(req.params.id);
|
||||
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Use the auth test endpoint
|
||||
const authTestRoute = require('./auth');
|
||||
req.params.tenantId = tenant.slug;
|
||||
|
||||
return authTestRoute.testAuth(req, res);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error testing auth config:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to test authentication configuration'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* DELETE /api/tenants/:id - Delete tenant (soft delete)
|
||||
*/
|
||||
router.delete('/:id', authenticateToken, requireRole(['admin']), async (req, res) => {
|
||||
try {
|
||||
const tenant = await Tenant.findByPk(req.params.id);
|
||||
|
||||
if (!tenant) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Tenant not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Soft delete by setting is_active to false
|
||||
await tenant.update({ is_active: false });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Tenant deactivated successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error deleting tenant:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to delete tenant'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Helper function to get default features based on subscription type
|
||||
*/
|
||||
function getDefaultFeatures(subscriptionType) {
|
||||
const featureMap = {
|
||||
free: {
|
||||
max_devices: 2,
|
||||
max_users: 1,
|
||||
api_rate_limit: 100,
|
||||
data_retention_days: 7,
|
||||
features: ['basic_detection']
|
||||
},
|
||||
basic: {
|
||||
max_devices: 10,
|
||||
max_users: 5,
|
||||
api_rate_limit: 1000,
|
||||
data_retention_days: 90,
|
||||
features: ['basic_detection', 'alerts', 'dashboard']
|
||||
},
|
||||
premium: {
|
||||
max_devices: 50,
|
||||
max_users: 20,
|
||||
api_rate_limit: 5000,
|
||||
data_retention_days: 365,
|
||||
features: ['basic_detection', 'alerts', 'dashboard', 'advanced_analytics', 'api_access']
|
||||
},
|
||||
enterprise: {
|
||||
max_devices: -1, // Unlimited
|
||||
max_users: -1, // Unlimited
|
||||
api_rate_limit: 50000,
|
||||
data_retention_days: -1, // Unlimited
|
||||
features: ['all']
|
||||
}
|
||||
};
|
||||
|
||||
return featureMap[subscriptionType] || featureMap.basic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to mask sensitive configuration data
|
||||
*/
|
||||
function maskSensitiveConfig(config) {
|
||||
const maskedConfig = { ...config };
|
||||
const sensitiveFields = ['client_secret', 'private_key', 'bind_password', 'admin_password'];
|
||||
|
||||
sensitiveFields.forEach(field => {
|
||||
if (maskedConfig[field]) {
|
||||
maskedConfig[field] = '****';
|
||||
}
|
||||
});
|
||||
|
||||
return maskedConfig;
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user