117 lines
4.7 KiB
TypeScript
117 lines
4.7 KiB
TypeScript
import Joi from 'joi';
|
|
|
|
export interface RuntimeConfig {
|
|
service: {
|
|
name: string;
|
|
};
|
|
http: {
|
|
host: string;
|
|
port: number;
|
|
};
|
|
logging: {
|
|
level: string;
|
|
requestIdHeader: string;
|
|
};
|
|
database: {
|
|
url: string;
|
|
};
|
|
redis: {
|
|
url: string;
|
|
};
|
|
activeCalls: {
|
|
mode: 'http' | 'ssh';
|
|
httpUrl: string;
|
|
sshHost: string;
|
|
sshConfig?: string;
|
|
remoteCommand: string;
|
|
timeoutMs: number;
|
|
};
|
|
auth: {
|
|
accessTokenSecret: string;
|
|
accessTokenTtlSeconds: number;
|
|
refreshTokenTtlDays: number;
|
|
lockMaxFailures: number;
|
|
lockWindowSeconds: number;
|
|
loginThrottleMaxFailures: number;
|
|
loginThrottleWindowSeconds: number;
|
|
cookieSecure: boolean;
|
|
tokenIssuer: string;
|
|
tokenAudience: string;
|
|
};
|
|
}
|
|
|
|
export const validationSchema = Joi.object({
|
|
NODE_ENV: Joi.string().valid('development', 'test', 'production').default('development'),
|
|
LISGLOSIPS_SERVICE_NAME: Joi.string().default('api'),
|
|
LISGLOSIPS_HOST: Joi.string().hostname().default('127.0.0.1'),
|
|
LISGLOSIPS_PORT: Joi.number().port().default(3000),
|
|
LISGLOSIPS_LOG_LEVEL: Joi.string().valid('trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent').default('info'),
|
|
LISGLOSIPS_REQUEST_ID_HEADER: Joi.string().default('x-request-id'),
|
|
DATABASE_URL: Joi.string().uri({ scheme: ['mysql'] }).required(),
|
|
REDIS_URL: Joi.string().uri({ scheme: ['redis', 'rediss'] }).required(),
|
|
ACTIVE_CALLS_MODE: Joi.string().valid('http', 'ssh').default('http'),
|
|
ACTIVE_CALLS_HTTP_URL: Joi.string().uri({ scheme: ['http', 'https'] }).default('http://127.0.0.1:8888/mi'),
|
|
ACTIVE_CALLS_SSH_HOST: Joi.string().allow('').default('lisglosips-a'),
|
|
ACTIVE_CALLS_SSH_CONFIG: Joi.string().allow('').optional(),
|
|
ACTIVE_CALLS_REMOTE_COMMAND: Joi.string().default('/usr/local/sbin/lisglosips-call-control'),
|
|
ACTIVE_CALLS_TIMEOUT_MS: Joi.number().integer().min(1000).max(30000).default(5000),
|
|
AUTH_ACCESS_TOKEN_SECRET: Joi.string().min(32).when('NODE_ENV', {
|
|
is: 'production',
|
|
then: Joi.required(),
|
|
otherwise: Joi.string().default('dev-only-change-this-auth-secret-32-bytes-min')
|
|
}),
|
|
AUTH_ACCESS_TOKEN_TTL_SECONDS: Joi.number().integer().min(60).max(86_400).default(900),
|
|
AUTH_REFRESH_TOKEN_TTL_DAYS: Joi.number().integer().min(1).max(30).default(7),
|
|
AUTH_LOCK_MAX_FAILURES: Joi.number().integer().min(3).max(20).default(5),
|
|
AUTH_LOCK_WINDOW_SECONDS: Joi.number().integer().min(60).max(86_400).default(900),
|
|
AUTH_LOGIN_THROTTLE_MAX_FAILURES: Joi.number().integer().min(3).max(100).default(10),
|
|
AUTH_LOGIN_THROTTLE_WINDOW_SECONDS: Joi.number().integer().min(60).max(86_400).default(300),
|
|
AUTH_COOKIE_SECURE: Joi.any().default(true),
|
|
AUTH_TOKEN_ISSUER: Joi.string().default('lisglosips-api'),
|
|
AUTH_TOKEN_AUDIENCE: Joi.string().default('lisglosips-web')
|
|
});
|
|
|
|
export function appConfig(): RuntimeConfig {
|
|
const cookieSecureValue = (process.env.AUTH_COOKIE_SECURE ?? 'true').trim().replace(/^['"]|['"]$/g, '').toLowerCase();
|
|
|
|
return {
|
|
service: {
|
|
name: process.env.LISGLOSIPS_SERVICE_NAME ?? 'api'
|
|
},
|
|
http: {
|
|
host: process.env.LISGLOSIPS_HOST ?? '127.0.0.1',
|
|
port: Number(process.env.LISGLOSIPS_PORT ?? 3000)
|
|
},
|
|
logging: {
|
|
level: process.env.LISGLOSIPS_LOG_LEVEL ?? 'info',
|
|
requestIdHeader: process.env.LISGLOSIPS_REQUEST_ID_HEADER ?? 'x-request-id'
|
|
},
|
|
database: {
|
|
url: process.env.DATABASE_URL ?? ''
|
|
},
|
|
redis: {
|
|
url: process.env.REDIS_URL ?? ''
|
|
},
|
|
activeCalls: {
|
|
mode: process.env.ACTIVE_CALLS_MODE === 'ssh' ? 'ssh' : 'http',
|
|
httpUrl: process.env.ACTIVE_CALLS_HTTP_URL ?? 'http://127.0.0.1:8888/mi',
|
|
sshHost: process.env.ACTIVE_CALLS_SSH_HOST || 'lisglosips-a',
|
|
sshConfig: process.env.ACTIVE_CALLS_SSH_CONFIG || undefined,
|
|
remoteCommand: process.env.ACTIVE_CALLS_REMOTE_COMMAND ?? '/usr/local/sbin/lisglosips-call-control',
|
|
timeoutMs: Number(process.env.ACTIVE_CALLS_TIMEOUT_MS ?? 5000)
|
|
},
|
|
auth: {
|
|
accessTokenSecret: process.env.AUTH_ACCESS_TOKEN_SECRET ?? 'dev-only-change-this-auth-secret-32-bytes-min',
|
|
accessTokenTtlSeconds: Number(process.env.AUTH_ACCESS_TOKEN_TTL_SECONDS ?? 900),
|
|
refreshTokenTtlDays: Number(process.env.AUTH_REFRESH_TOKEN_TTL_DAYS ?? 7),
|
|
lockMaxFailures: Number(process.env.AUTH_LOCK_MAX_FAILURES ?? 5),
|
|
lockWindowSeconds: Number(process.env.AUTH_LOCK_WINDOW_SECONDS ?? 900),
|
|
loginThrottleMaxFailures: Number(process.env.AUTH_LOGIN_THROTTLE_MAX_FAILURES ?? 10),
|
|
loginThrottleWindowSeconds: Number(process.env.AUTH_LOGIN_THROTTLE_WINDOW_SECONDS ?? 300),
|
|
cookieSecure: cookieSecureValue !== 'false' && cookieSecureValue !== '0',
|
|
tokenIssuer: process.env.AUTH_TOKEN_ISSUER ?? 'lisglosips-api',
|
|
tokenAudience: process.env.AUTH_TOKEN_AUDIENCE ?? 'lisglosips-web'
|
|
}
|
|
};
|
|
}
|