backend: refactor environment variable usage across services and tests

This commit is contained in:
juancarmore 2025-11-18 18:43:05 +01:00
parent e3fe104b05
commit fad38b696d
33 changed files with 289 additions and 384 deletions

View File

@ -1,5 +1,5 @@
import { Container } from 'inversify';
import { MEET_BLOB_STORAGE_MODE } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import {
ApiKeyRepository,
BaseRepository,
@ -89,7 +89,7 @@ export const registerDependencies = () => {
container.bind(ApiKeyService).toSelf().inSingletonScope();
container.bind(GlobalConfigService).toSelf().inSingletonScope();
configureStorage(MEET_BLOB_STORAGE_MODE);
configureStorage(MEET_ENV.BLOB_STORAGE_MODE);
container.bind(StorageFactory).toSelf().inSingletonScope();
container.bind(BlobStorageService).toSelf().inSingletonScope();
container.bind(StorageInitService).toSelf().inSingletonScope();

View File

@ -16,22 +16,22 @@ if (process.env.MEET_CONFIG_DIR) {
dotenv.config(envPath ? { path: envPath } : {});
// Extract environment variables with defaults
const envVars = {
export const MEET_ENV = {
SERVER_PORT: process.env.SERVER_PORT || '6080',
SERVER_CORS_ORIGIN: process.env.SERVER_CORS_ORIGIN || '*',
MEET_LOG_LEVEL: process.env.MEET_LOG_LEVEL || 'info',
MEET_NAME_ID: process.env.MEET_NAME_ID || 'openviduMeet',
MEET_BASE_URL: process.env.MEET_BASE_URL || '',
MEET_EDITION: process.env.MEET_EDITION || 'CE',
LOG_LEVEL: process.env.MEET_LOG_LEVEL || 'info',
NAME_ID: process.env.MEET_NAME_ID || 'openviduMeet',
BASE_URL: process.env.MEET_BASE_URL || '',
EDITION: process.env.MEET_EDITION || 'CE',
// Authentication configuration
MEET_INITIAL_ADMIN_USER: process.env.MEET_INITIAL_ADMIN_USER || 'admin',
MEET_INITIAL_ADMIN_PASSWORD: process.env.MEET_INITIAL_ADMIN_PASSWORD || 'admin',
MEET_INITIAL_API_KEY: process.env.MEET_INITIAL_API_KEY || '',
INITIAL_ADMIN_USER: process.env.MEET_INITIAL_ADMIN_USER || 'admin',
INITIAL_ADMIN_PASSWORD: process.env.MEET_INITIAL_ADMIN_PASSWORD || 'admin',
INITIAL_API_KEY: process.env.MEET_INITIAL_API_KEY || '',
// Webhook configuration
MEET_INITIAL_WEBHOOK_ENABLED: process.env.MEET_INITIAL_WEBHOOK_ENABLED || 'false',
MEET_INITIAL_WEBHOOK_URL: process.env.MEET_INITIAL_WEBHOOK_URL || '',
INITIAL_WEBHOOK_ENABLED: process.env.MEET_INITIAL_WEBHOOK_ENABLED || 'false',
INITIAL_WEBHOOK_URL: process.env.MEET_INITIAL_WEBHOOK_URL || '',
// LiveKit configuration
LIVEKIT_URL: process.env.LIVEKIT_URL || 'ws://localhost:7880',
@ -40,31 +40,31 @@ const envVars = {
LIVEKIT_API_SECRET: process.env.LIVEKIT_API_SECRET || 'secret',
// MongoDB configuration
MEET_MONGO_ENABLED: process.env.MEET_MONGO_ENABLED || 'true',
MEET_MONGO_URI: process.env.MEET_MONGO_URI || '',
MEET_MONGO_NODES: process.env.MEET_MONGO_NODES || 'localhost',
MEET_MONGO_PORT: process.env.MEET_MONGO_PORT || '27017',
MEET_MONGO_ADMIN_USERNAME: process.env.MEET_MONGO_ADMIN_USERNAME || 'mongoadmin',
MEET_MONGO_ADMIN_PASSWORD: process.env.MEET_MONGO_ADMIN_PASSWORD || 'mongoadmin',
MEET_MONGO_REPLICA_SET_NAME: process.env.MEET_MONGO_REPLICA_SET_NAME || 'rs0',
MEET_MONGO_DB_NAME: process.env.MEET_MONGO_DB_NAME || 'openvidu-meet',
MONGO_ENABLED: process.env.MEET_MONGO_ENABLED || 'true',
MONGO_URI: process.env.MEET_MONGO_URI || '',
MONGO_NODES: process.env.MEET_MONGO_NODES || 'localhost',
MONGO_PORT: process.env.MEET_MONGO_PORT || '27017',
MONGO_ADMIN_USERNAME: process.env.MEET_MONGO_ADMIN_USERNAME || 'mongoadmin',
MONGO_ADMIN_PASSWORD: process.env.MEET_MONGO_ADMIN_PASSWORD || 'mongoadmin',
MONGO_REPLICA_SET_NAME: process.env.MEET_MONGO_REPLICA_SET_NAME || 'rs0',
MONGO_DB_NAME: process.env.MEET_MONGO_DB_NAME || 'openvidu-meet',
MEET_BLOB_STORAGE_MODE: process.env.MEET_BLOB_STORAGE_MODE || 's3', // Options: 's3', 'abs', 'gcs'
BLOB_STORAGE_MODE: process.env.MEET_BLOB_STORAGE_MODE || 's3', // Options: 's3', 'abs', 'gcs'
// S3 or GCS configuration
MEET_S3_BUCKET: process.env.MEET_S3_BUCKET || 'openvidu-appdata',
MEET_S3_SUBBUCKET: process.env.MEET_S3_SUBBUCKET || 'openvidu-meet',
MEET_S3_SERVICE_ENDPOINT: process.env.MEET_S3_SERVICE_ENDPOINT || 'http://localhost:9000',
MEET_S3_ACCESS_KEY: process.env.MEET_S3_ACCESS_KEY || 'minioadmin',
MEET_S3_SECRET_KEY: process.env.MEET_S3_SECRET_KEY || 'minioadmin',
MEET_AWS_REGION: process.env.MEET_AWS_REGION || 'us-east-1',
MEET_S3_WITH_PATH_STYLE_ACCESS: process.env.MEET_S3_WITH_PATH_STYLE_ACCESS || 'true',
S3_BUCKET: process.env.MEET_S3_BUCKET || 'openvidu-appdata',
S3_SUBBUCKET: process.env.MEET_S3_SUBBUCKET || 'openvidu-meet',
S3_SERVICE_ENDPOINT: process.env.MEET_S3_SERVICE_ENDPOINT || 'http://localhost:9000',
S3_ACCESS_KEY: process.env.MEET_S3_ACCESS_KEY || 'minioadmin',
S3_SECRET_KEY: process.env.MEET_S3_SECRET_KEY || 'minioadmin',
AWS_REGION: process.env.MEET_AWS_REGION || 'us-east-1',
S3_WITH_PATH_STYLE_ACCESS: process.env.MEET_S3_WITH_PATH_STYLE_ACCESS || 'true',
// Azure Blob storage configuration
MEET_AZURE_CONTAINER_NAME: process.env.MEET_AZURE_CONTAINER_NAME || 'openvidu-appdata',
MEET_AZURE_SUBCONTAINER_NAME: process.env.MEET_AZURE_SUBCONTAINER_NAME || 'openvidu-meet',
MEET_AZURE_ACCOUNT_NAME: process.env.MEET_AZURE_ACCOUNT_NAME || '',
MEET_AZURE_ACCOUNT_KEY: process.env.MEET_AZURE_ACCOUNT_KEY || '',
AZURE_CONTAINER_NAME: process.env.MEET_AZURE_CONTAINER_NAME || 'openvidu-appdata',
AZURE_SUBCONTAINER_NAME: process.env.MEET_AZURE_SUBCONTAINER_NAME || 'openvidu-meet',
AZURE_ACCOUNT_NAME: process.env.MEET_AZURE_ACCOUNT_NAME || '',
AZURE_ACCOUNT_KEY: process.env.MEET_AZURE_ACCOUNT_KEY || '',
// Redis configuration
REDIS_HOST: process.env.MEET_REDIS_HOST || 'localhost',
@ -84,75 +84,10 @@ const envVars = {
ENABLED_MODULES: process.env.ENABLED_MODULES || ''
};
// Export environment as an object for extensibility
export const environment = envVars;
/**
* Helper function to create individual exports from an environment object.
* This is used to maintain backward compatibility with code that imports individual variables.
*/
export const createEnvironmentExports = <T extends Record<string, unknown>>(env: T): T => {
return env;
};
// Export individual variables for backward compatibility
export const {
SERVER_PORT,
SERVER_CORS_ORIGIN,
MEET_LOG_LEVEL,
MEET_NAME_ID,
MEET_BASE_URL,
MEET_EDITION,
MEET_INITIAL_ADMIN_USER,
MEET_INITIAL_ADMIN_PASSWORD,
MEET_INITIAL_API_KEY,
MEET_INITIAL_WEBHOOK_ENABLED,
MEET_INITIAL_WEBHOOK_URL,
LIVEKIT_URL,
LIVEKIT_URL_PRIVATE,
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
MEET_MONGO_ENABLED,
MEET_MONGO_URI,
MEET_MONGO_NODES,
MEET_MONGO_PORT,
MEET_MONGO_ADMIN_USERNAME,
MEET_MONGO_ADMIN_PASSWORD,
MEET_MONGO_REPLICA_SET_NAME,
MEET_MONGO_DB_NAME,
MEET_BLOB_STORAGE_MODE,
MEET_S3_BUCKET,
MEET_S3_SUBBUCKET,
MEET_S3_SERVICE_ENDPOINT,
MEET_S3_ACCESS_KEY,
MEET_S3_SECRET_KEY,
MEET_AWS_REGION,
MEET_S3_WITH_PATH_STYLE_ACCESS,
MEET_AZURE_CONTAINER_NAME,
MEET_AZURE_SUBCONTAINER_NAME,
MEET_AZURE_ACCOUNT_NAME,
MEET_AZURE_ACCOUNT_KEY,
REDIS_HOST,
REDIS_PORT,
REDIS_USERNAME,
REDIS_PASSWORD,
REDIS_DB,
REDIS_SENTINEL_HOST_LIST,
REDIS_SENTINEL_PASSWORD,
REDIS_SENTINEL_MASTER_NAME,
MODULES_FILE,
MODULE_NAME,
ENABLED_MODULES
} = envVars;
export const getExportedEnvironment = () => {
return { ...envVars };
};
export function checkModuleEnabled() {
if (MODULES_FILE) {
const moduleName = MODULE_NAME;
const enabledModules = ENABLED_MODULES.split(',').map((module) => module.trim());
if (MEET_ENV.MODULES_FILE) {
const moduleName = MEET_ENV.MODULE_NAME;
const enabledModules = MEET_ENV.ENABLED_MODULES.split(',').map((module) => module.trim());
if (!enabledModules.includes(moduleName)) {
console.error(`Module ${moduleName} is not enabled`);
@ -161,7 +96,7 @@ export function checkModuleEnabled() {
}
// If MongoDB is not enabled, exit the process
if (environment.MEET_MONGO_ENABLED.toLowerCase() !== 'true') {
if (MEET_ENV.MONGO_ENABLED.toLowerCase() !== 'true') {
console.error('MongoDB integration is not enabled. Exiting the process.');
process.exit(0);
}
@ -173,82 +108,82 @@ export const logEnvVars = () => {
console.log(' ');
console.log('---------------------------------------------------------');
console.log(`OpenVidu Meet ${MEET_EDITION} Server Configuration`);
console.log(`OpenVidu Meet ${MEET_ENV.EDITION} Server Configuration`);
console.log('---------------------------------------------------------');
console.log('SERVICE NAME ID: ', text(MEET_NAME_ID));
console.log('CORS ORIGIN:', text(SERVER_CORS_ORIGIN));
console.log('MEET LOG LEVEL: ', text(MEET_LOG_LEVEL));
console.log('MEET BLOB STORAGE MODE:', text(MEET_BLOB_STORAGE_MODE));
console.log('MEET INITIAL ADMIN USER: ', credential('****' + MEET_INITIAL_ADMIN_USER.slice(-3)));
console.log('MEET INITIAL ADMIN PASSWORD: ', credential('****' + MEET_INITIAL_ADMIN_PASSWORD.slice(-3)));
console.log('SERVICE NAME ID: ', text(MEET_ENV.NAME_ID));
console.log('CORS ORIGIN:', text(MEET_ENV.SERVER_CORS_ORIGIN));
console.log('LOG LEVEL: ', text(MEET_ENV.LOG_LEVEL));
console.log('BLOB STORAGE MODE:', text(MEET_ENV.BLOB_STORAGE_MODE));
console.log('INITIAL ADMIN USER: ', credential('****' + MEET_ENV.INITIAL_ADMIN_USER.slice(-3)));
console.log('INITIAL ADMIN PASSWORD: ', credential('****' + MEET_ENV.INITIAL_ADMIN_PASSWORD.slice(-3)));
if (!MEET_INITIAL_API_KEY) {
console.log(chalk.red('MEET INITIAL API KEY: none'));
if (!MEET_ENV.INITIAL_API_KEY) {
console.log(chalk.red('INITIAL API KEY: none'));
} else {
console.log('MEET INITIAL API KEY: ', credential('****' + MEET_INITIAL_API_KEY.slice(-3)));
console.log('INITIAL API KEY: ', credential('****' + MEET_ENV.INITIAL_API_KEY.slice(-3)));
}
console.log('MEET INITIAL WEBHOOK ENABLED:', text(MEET_INITIAL_WEBHOOK_ENABLED));
console.log('INITIAL WEBHOOK ENABLED:', text(MEET_ENV.INITIAL_WEBHOOK_ENABLED));
if (MEET_INITIAL_WEBHOOK_ENABLED === 'true') {
console.log('MEET INITIAL WEBHOOK URL:', text(MEET_INITIAL_WEBHOOK_URL));
if (MEET_ENV.INITIAL_WEBHOOK_ENABLED === 'true') {
console.log('INITIAL WEBHOOK URL:', text(MEET_ENV.INITIAL_WEBHOOK_URL));
}
console.log('---------------------------------------------------------');
console.log('LIVEKIT Configuration');
console.log('---------------------------------------------------------');
console.log('LIVEKIT URL: ', text(LIVEKIT_URL));
console.log('LIVEKIT URL PRIVATE: ', text(LIVEKIT_URL_PRIVATE));
console.log('LIVEKIT API SECRET: ', credential('****' + LIVEKIT_API_SECRET.slice(-3)));
console.log('LIVEKIT API KEY: ', credential('****' + LIVEKIT_API_KEY.slice(-3)));
console.log('LIVEKIT URL: ', text(MEET_ENV.LIVEKIT_URL));
console.log('LIVEKIT URL PRIVATE: ', text(MEET_ENV.LIVEKIT_URL_PRIVATE));
console.log('LIVEKIT API SECRET: ', credential('****' + MEET_ENV.LIVEKIT_API_SECRET.slice(-3)));
console.log('LIVEKIT API KEY: ', credential('****' + MEET_ENV.LIVEKIT_API_KEY.slice(-3)));
console.log('---------------------------------------------------------');
if (MEET_MONGO_URI === '') {
if (MEET_ENV.MONGO_URI === '') {
console.log('MongoDB Configuration');
console.log('---------------------------------------------------------');
console.log('MONGODB NODES: ', text(MEET_MONGO_NODES));
console.log('MONGODB PORT: ', text(MEET_MONGO_PORT));
console.log('MONGODB ADMIN USERNAME: ', credential('****' + MEET_MONGO_ADMIN_USERNAME.slice(-3)));
console.log('MONGODB ADMIN PASSWORD: ', credential('****' + MEET_MONGO_ADMIN_PASSWORD.slice(-3)));
console.log('MONGODB REPLICA SET NAME: ', text(MEET_MONGO_REPLICA_SET_NAME));
console.log('MONGODB DB NAME: ', text(MEET_MONGO_DB_NAME));
console.log('MONGODB NODES: ', text(MEET_ENV.MONGO_NODES));
console.log('MONGODB PORT: ', text(MEET_ENV.MONGO_PORT));
console.log('MONGODB ADMIN USERNAME: ', credential('****' + MEET_ENV.MONGO_ADMIN_USERNAME.slice(-3)));
console.log('MONGODB ADMIN PASSWORD: ', credential('****' + MEET_ENV.MONGO_ADMIN_PASSWORD.slice(-3)));
console.log('MONGODB REPLICA SET NAME: ', text(MEET_ENV.MONGO_REPLICA_SET_NAME));
console.log('MONGODB DB NAME: ', text(MEET_ENV.MONGO_DB_NAME));
console.log('---------------------------------------------------------');
}
if (MEET_BLOB_STORAGE_MODE === 's3') {
if (MEET_ENV.BLOB_STORAGE_MODE === 's3') {
console.log('S3 Configuration');
console.log('---------------------------------------------------------');
console.log('MEET S3 BUCKET:', text(MEET_S3_BUCKET));
console.log('MEET S3 SERVICE ENDPOINT:', text(MEET_S3_SERVICE_ENDPOINT));
console.log('MEET S3 ACCESS KEY:', credential('****' + MEET_S3_ACCESS_KEY.slice(-3)));
console.log('MEET S3 SECRET KEY:', credential('****' + MEET_S3_SECRET_KEY.slice(-3)));
console.log('MEET AWS REGION:', text(MEET_AWS_REGION));
console.log('MEET S3 WITH PATH STYLE ACCESS:', text(MEET_S3_WITH_PATH_STYLE_ACCESS));
console.log('S3 BUCKET:', text(MEET_ENV.S3_BUCKET));
console.log('S3 SERVICE ENDPOINT:', text(MEET_ENV.S3_SERVICE_ENDPOINT));
console.log('S3 ACCESS KEY:', credential('****' + MEET_ENV.S3_ACCESS_KEY.slice(-3)));
console.log('S3 SECRET KEY:', credential('****' + MEET_ENV.S3_SECRET_KEY.slice(-3)));
console.log('AWS REGION:', text(MEET_ENV.AWS_REGION));
console.log('S3 WITH PATH STYLE ACCESS:', text(MEET_ENV.S3_WITH_PATH_STYLE_ACCESS));
console.log('---------------------------------------------------------');
} else if (MEET_BLOB_STORAGE_MODE === 'abs') {
} else if (MEET_ENV.BLOB_STORAGE_MODE === 'abs') {
console.log('Azure Blob Storage Configuration');
console.log('---------------------------------------------------------');
console.log('MEET AZURE ACCOUNT NAME:', text(MEET_AZURE_ACCOUNT_NAME));
console.log('MEET AZURE ACCOUNT KEY:', credential('****' + MEET_AZURE_ACCOUNT_KEY.slice(-3)));
console.log('MEET AZURE CONTAINER NAME:', text(MEET_AZURE_CONTAINER_NAME));
console.log('AZURE ACCOUNT NAME:', text(MEET_ENV.AZURE_ACCOUNT_NAME));
console.log('AZURE ACCOUNT KEY:', credential('****' + MEET_ENV.AZURE_ACCOUNT_KEY.slice(-3)));
console.log('AZURE CONTAINER NAME:', text(MEET_ENV.AZURE_CONTAINER_NAME));
console.log('---------------------------------------------------------');
} else if (MEET_BLOB_STORAGE_MODE === 'gcs') {
} else if (MEET_ENV.BLOB_STORAGE_MODE === 'gcs') {
console.log('GCS Configuration');
console.log('---------------------------------------------------------');
console.log('MEET GCS BUCKET:', text(MEET_S3_BUCKET));
console.log('GCS BUCKET:', text(MEET_ENV.S3_BUCKET));
console.log('---------------------------------------------------------');
}
console.log('Redis Configuration');
console.log('---------------------------------------------------------');
console.log('REDIS HOST:', text(REDIS_HOST));
console.log('REDIS PORT:', text(REDIS_PORT));
console.log('REDIS USERNAME:', credential('****' + REDIS_USERNAME.slice(-3)));
console.log('REDIS PASSWORD:', credential('****' + REDIS_PASSWORD.slice(-3)));
console.log('REDIS HOST:', text(MEET_ENV.REDIS_HOST));
console.log('REDIS PORT:', text(MEET_ENV.REDIS_PORT));
console.log('REDIS USERNAME:', credential('****' + MEET_ENV.REDIS_USERNAME.slice(-3)));
console.log('REDIS PASSWORD:', credential('****' + MEET_ENV.REDIS_PASSWORD.slice(-3)));
if (REDIS_SENTINEL_HOST_LIST !== '') {
if (MEET_ENV.REDIS_SENTINEL_HOST_LIST !== '') {
console.log('REDIS SENTINEL IS ENABLED');
console.log('REDIS SENTINEL HOST LIST:', text(REDIS_SENTINEL_HOST_LIST));
console.log('REDIS SENTINEL HOST LIST:', text(MEET_ENV.REDIS_SENTINEL_HOST_LIST));
}
console.log('---------------------------------------------------------');

View File

@ -1,5 +1,5 @@
import { MeetRoom, MeetRoomOptions } from '@openvidu-meet/typings';
import { MEET_NAME_ID } from '../environment.js';
import { MEET_ENV } from '../environment.js';
export class MeetRoomHelper {
private constructor() {
@ -69,7 +69,7 @@ export class MeetRoomHelper {
}
/**
* Safely parses JSON metadata and checks if createdBy matches MEET_NAME_ID.
* Safely parses JSON metadata and checks if createdBy matches NAME_ID.
* @returns true if metadata indicates OpenVidu Meet as creator, false otherwise
*/
static checkIfMeetingBelogsToOpenViduMeet(metadata?: string): boolean {
@ -77,7 +77,7 @@ export class MeetRoomHelper {
try {
const parsed = JSON.parse(metadata);
const isOurs = parsed?.createdBy === MEET_NAME_ID;
const isOurs = parsed?.createdBy === MEET_ENV.NAME_ID;
return isOurs;
} catch (err: unknown) {
return false;

View File

@ -4,7 +4,7 @@ import cors from 'cors';
import express, { Express, Request, Response } from 'express';
import { initializeEagerServices, registerDependencies } from './config/index.js';
import { INTERNAL_CONFIG } from './config/internal-config.js';
import { MEET_BASE_URL, MEET_EDITION, SERVER_CORS_ORIGIN, SERVER_PORT, logEnvVars } from './environment.js';
import { MEET_ENV, logEnvVars } from './environment.js';
import { initRequestContext, jsonSyntaxErrorHandler, setBaseUrlMiddleware } from './middlewares/index.js';
import {
analyticsRouter,
@ -31,10 +31,10 @@ const createApp = () => {
const app: Express = express();
// Enable CORS support
if (SERVER_CORS_ORIGIN) {
if (MEET_ENV.SERVER_CORS_ORIGIN) {
app.use(
cors({
origin: SERVER_CORS_ORIGIN,
origin: MEET_ENV.SERVER_CORS_ORIGIN,
credentials: true
})
);
@ -57,8 +57,8 @@ const createApp = () => {
app.use(initRequestContext);
// Middleware to set base URL for each request
// Only if MEET_BASE_URL is not set
if (!MEET_BASE_URL) {
// Only if BASE_URL is not set
if (!MEET_ENV.BASE_URL) {
app.use(setBaseUrlMiddleware);
}
@ -103,14 +103,14 @@ const createApp = () => {
};
const startServer = (app: express.Application) => {
app.listen(SERVER_PORT, async () => {
app.listen(MEET_ENV.SERVER_PORT, async () => {
console.log(' ');
console.log('---------------------------------------------------------');
console.log(' ');
console.log(`OpenVidu Meet ${MEET_EDITION} is listening on port`, chalk.cyanBright(SERVER_PORT));
console.log(`OpenVidu Meet ${MEET_ENV.EDITION} is listening on port`, chalk.cyanBright(MEET_ENV.SERVER_PORT));
console.log(
'REST API Docs: ',
chalk.cyanBright(`http://localhost:${SERVER_PORT}${INTERNAL_CONFIG.API_BASE_PATH_V1}/docs`)
chalk.cyanBright(`http://localhost:${MEET_ENV.SERVER_PORT}${INTERNAL_CONFIG.API_BASE_PATH_V1}/docs`)
);
logEnvVars();
});

View File

@ -1,6 +1,6 @@
import { MeetApiKey } from '@openvidu-meet/typings';
import { inject, injectable } from 'inversify';
import { MEET_INITIAL_API_KEY } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { PasswordHelper } from '../helpers/index.js';
import { errorApiKeyNotConfigured } from '../models/error.model.js';
import { ApiKeyRepository } from '../repositories/index.js';
@ -27,7 +27,7 @@ export class ApiKeyService {
}
// Check if initial API key is configured
const initialApiKey = MEET_INITIAL_API_KEY;
const initialApiKey = MEET_ENV.INITIAL_API_KEY;
if (!initialApiKey) {
this.logger.info('No initial API key configured, skipping API key initialization');

View File

@ -1,6 +1,6 @@
import { Request } from 'express';
import { injectable } from 'inversify';
import { SERVER_PORT } from '../environment.js';
import { MEET_ENV } from '../environment.js';
@injectable()
export class BaseUrlService {
@ -34,6 +34,6 @@ export class BaseUrlService {
}
private getDefaultBaseUrl(): string {
return `http://localhost:${SERVER_PORT}`;
return `http://localhost:${MEET_ENV.SERVER_PORT}`;
}
}

View File

@ -1,11 +1,6 @@
import { AuthMode, AuthType, GlobalConfig } from '@openvidu-meet/typings';
import { inject, injectable } from 'inversify';
import {
MEET_INITIAL_API_KEY,
MEET_INITIAL_WEBHOOK_ENABLED,
MEET_INITIAL_WEBHOOK_URL,
MEET_NAME_ID
} from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { GlobalConfigRepository } from '../repositories/index.js';
import { LoggerService } from './index.js';
@ -83,10 +78,10 @@ export class GlobalConfigService {
*/
protected getDefaultConfig(): GlobalConfig {
const defaultConfig: GlobalConfig = {
projectId: MEET_NAME_ID,
projectId: MEET_ENV.NAME_ID,
webhooksConfig: {
enabled: MEET_INITIAL_WEBHOOK_ENABLED === 'true' && !!MEET_INITIAL_API_KEY,
url: MEET_INITIAL_WEBHOOK_URL
enabled: MEET_ENV.INITIAL_WEBHOOK_ENABLED === 'true' && !!MEET_ENV.INITIAL_API_KEY,
url: MEET_ENV.INITIAL_WEBHOOK_URL
},
securityConfig: {
authentication: {

View File

@ -2,7 +2,7 @@ import { MeetingEndAction, MeetRecordingInfo, MeetRecordingStatus, MeetRoomStatu
import { inject, injectable } from 'inversify';
import { EgressInfo, ParticipantInfo, Room, WebhookEvent, WebhookReceiver } from 'livekit-server-sdk';
import ms from 'ms';
import { LIVEKIT_API_KEY, LIVEKIT_API_SECRET } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { MeetLock, MeetRoomHelper, RecordingHelper } from '../helpers/index.js';
import { DistributedEventType } from '../models/distributed-event.model.js';
import { RecordingRepository, RoomRepository } from '../repositories/index.js';
@ -34,7 +34,7 @@ export class LivekitWebhookService {
@inject(RoomMemberService) protected roomMemberService: RoomMemberService,
@inject(LoggerService) protected logger: LoggerService
) {
this.webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
this.webhookReceiver = new WebhookReceiver(MEET_ENV.LIVEKIT_API_KEY, MEET_ENV.LIVEKIT_API_SECRET);
}
/**

View File

@ -14,7 +14,7 @@ import {
SendDataOptions,
StreamOutput
} from 'livekit-server-sdk';
import { LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL_PRIVATE } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { RecordingHelper } from '../helpers/index.js';
import {
errorLivekitNotAvailable,
@ -32,9 +32,13 @@ export class LiveKitService {
private roomClient: RoomServiceClient;
constructor(@inject(LoggerService) protected logger: LoggerService) {
const livekitUrlHostname = LIVEKIT_URL_PRIVATE.replace(/^ws:/, 'http:').replace(/^wss:/, 'https:');
this.egressClient = new EgressClient(livekitUrlHostname, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
this.roomClient = new RoomServiceClient(livekitUrlHostname, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
const livekitUrlHostname = MEET_ENV.LIVEKIT_URL_PRIVATE.replace(/^ws:/, 'http:').replace(/^wss:/, 'https:');
this.egressClient = new EgressClient(livekitUrlHostname, MEET_ENV.LIVEKIT_API_KEY, MEET_ENV.LIVEKIT_API_SECRET);
this.roomClient = new RoomServiceClient(
livekitUrlHostname,
MEET_ENV.LIVEKIT_API_KEY,
MEET_ENV.LIVEKIT_API_SECRET
);
}
async createRoom(options: CreateOptions): Promise<Room> {

View File

@ -1,6 +1,6 @@
import { injectable } from 'inversify';
import winston from 'winston';
import { MEET_EDITION, MEET_LOG_LEVEL } from '../environment.js';
import { MEET_ENV } from '../environment.js';
@injectable()
export class LoggerService {
@ -8,7 +8,7 @@ export class LoggerService {
constructor() {
this.logger = winston.createLogger({
level: MEET_LOG_LEVEL,
level: MEET_ENV.LOG_LEVEL,
format: winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
@ -20,7 +20,7 @@ export class LoggerService {
? JSON.stringify(info.metadata)
: ''
: '';
return `${info.timestamp} | ${MEET_EDITION} | [${info.level}] ${info.message} ${meta}`;
return `${info.timestamp} | ${MEET_ENV.EDITION} | [${info.level}] ${info.message} ${meta}`;
// return `${info.timestamp} [${info.level}] ${info.message}`;
}),
@ -41,7 +41,7 @@ export class LoggerService {
? JSON.stringify(info.metadata)
: ''
: '';
return `${info.timestamp} | ${MEET_EDITION} | [${info.level}] ${info.message} ${meta}`;
return `${info.timestamp} | ${MEET_ENV.EDITION} | [${info.level}] ${info.message} ${meta}`;
// return `${info.timestamp} [${info.level}] ${info.message}`;
})

View File

@ -5,7 +5,7 @@ import ms from 'ms';
import { Readable } from 'stream';
import { uid } from 'uid';
import { INTERNAL_CONFIG } from '../config/internal-config.js';
import { MEET_S3_SUBBUCKET } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { MeetLock, RecordingHelper, UtilsHelper } from '../helpers/index.js';
import {
DistributedEventType,
@ -644,7 +644,7 @@ export class RecordingService {
const recordingName = `${roomId}--${uid(10)}`;
// Generate the file path with the openviud-meet subbucket and the recording prefix
const filepath = `${MEET_S3_SUBBUCKET}/${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/${roomId}/${recordingName}`;
const filepath = `${MEET_ENV.S3_SUBBUCKET}/${INTERNAL_CONFIG.S3_RECORDINGS_PREFIX}/${roomId}/${recordingName}`;
return new EncodedFileOutput({
fileType: EncodedFileType.DEFAULT_FILETYPE,

View File

@ -1,20 +1,10 @@
import { Redlock } from '@sesamecare-oss/redlock';
import { EventEmitter } from 'events';
import { inject, injectable } from 'inversify';
import { Redis, RedisOptions, SentinelAddress } from 'ioredis';
import ms from 'ms';
import { Redlock } from '@sesamecare-oss/redlock';
import {
checkModuleEnabled,
REDIS_DB,
REDIS_HOST,
REDIS_PASSWORD,
REDIS_PORT,
REDIS_SENTINEL_HOST_LIST,
REDIS_SENTINEL_MASTER_NAME,
REDIS_SENTINEL_PASSWORD,
REDIS_USERNAME
} from '../environment.js';
import { internalError, DistributedEventPayload } from '../models/index.js';
import { checkModuleEnabled, MEET_ENV } from '../environment.js';
import { DistributedEventPayload, internalError } from '../models/index.js';
import { LoggerService } from './index.js';
@injectable()
@ -353,9 +343,9 @@ export class RedisService extends EventEmitter {
checkModuleEnabled();
//Check if Redis Sentinel is configured
if (REDIS_SENTINEL_HOST_LIST) {
if (MEET_ENV.REDIS_SENTINEL_HOST_LIST) {
const sentinels: Array<SentinelAddress> = [];
const sentinelHosts = REDIS_SENTINEL_HOST_LIST.split(',');
const sentinelHosts = MEET_ENV.REDIS_SENTINEL_HOST_LIST.split(',');
sentinelHosts.forEach((host) => {
const rawHost = host.split(':');
@ -368,26 +358,26 @@ export class RedisService extends EventEmitter {
sentinels.push({ host: hostName, port });
});
if (!REDIS_SENTINEL_PASSWORD) throw new Error('The Redis Sentinel password is required');
if (!MEET_ENV.REDIS_SENTINEL_PASSWORD) throw new Error('The Redis Sentinel password is required');
this.logger.verbose('Using Redis Sentinel');
return {
sentinels,
sentinelPassword: REDIS_SENTINEL_PASSWORD,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
name: REDIS_SENTINEL_MASTER_NAME,
db: Number(REDIS_DB),
sentinelPassword: MEET_ENV.REDIS_SENTINEL_PASSWORD,
username: MEET_ENV.REDIS_USERNAME,
password: MEET_ENV.REDIS_PASSWORD,
name: MEET_ENV.REDIS_SENTINEL_MASTER_NAME,
db: Number(MEET_ENV.REDIS_DB),
maxRetriesPerRequest: null // Infinite retries
};
} else {
this.logger.verbose('Using Redis standalone');
return {
port: Number(REDIS_PORT),
host: REDIS_HOST,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
db: Number(REDIS_DB),
port: Number(MEET_ENV.REDIS_PORT),
host: MEET_ENV.REDIS_HOST,
username: MEET_ENV.REDIS_USERNAME,
password: MEET_ENV.REDIS_PASSWORD,
db: Number(MEET_ENV.REDIS_DB),
maxRetriesPerRequest: null // Infinite retries
};
}

View File

@ -17,7 +17,7 @@ import ms from 'ms';
import { uid as secureUid } from 'uid/secure';
import { uid } from 'uid/single';
import { INTERNAL_CONFIG } from '../config/internal-config.js';
import { MEET_NAME_ID } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { MeetRoomHelper, UtilsHelper } from '../helpers/index.js';
import {
errorDeletingRoom,
@ -114,7 +114,7 @@ export class RoomService {
const livekitRoomOptions: CreateOptions = {
name: roomId,
metadata: JSON.stringify({
createdBy: MEET_NAME_ID,
createdBy: MEET_ENV.NAME_ID,
roomOptions: MeetRoomHelper.toOpenViduOptions(meetRoom)
}),
emptyTimeout: MEETING_EMPTY_TIMEOUT ? ms(MEETING_EMPTY_TIMEOUT) / 1000 : undefined,

View File

@ -1,6 +1,6 @@
import { inject, injectable } from 'inversify';
import mongoose from 'mongoose';
import { environment, MEET_MONGO_DB_NAME } from '../../environment.js';
import { MEET_ENV } from '../../environment.js';
import { LoggerService } from '../index.js';
/**
@ -15,7 +15,7 @@ export class MongoDBService {
constructor(@inject(LoggerService) private logger: LoggerService) {
this.connectionString = this.buildMongoConnectionString();
this.dbName = MEET_MONGO_DB_NAME;
this.dbName = MEET_ENV.MONGO_DB_NAME;
}
/**
@ -30,13 +30,13 @@ export class MongoDBService {
*/
private buildMongoConnectionString(): string {
const {
MEET_MONGO_URI: mongoUri,
MEET_MONGO_NODES: nodes,
MEET_MONGO_PORT: port,
MEET_MONGO_ADMIN_USERNAME: adminUser,
MEET_MONGO_ADMIN_PASSWORD: adminPass,
MEET_MONGO_REPLICA_SET_NAME: replicaSet
} = environment;
MONGO_URI: mongoUri,
MONGO_NODES: nodes,
MONGO_PORT: port,
MONGO_ADMIN_USERNAME: adminUser,
MONGO_ADMIN_PASSWORD: adminPass,
MONGO_REPLICA_SET_NAME: replicaSet
} = MEET_ENV;
if (mongoUri && mongoUri.trim() !== '') {
this.logger.info('Using provided MongoDB URI from environment variable MEET_MONGO_URI');

View File

@ -7,12 +7,7 @@ import {
} from '@azure/storage-blob';
import { inject, injectable } from 'inversify';
import { Readable } from 'stream';
import {
MEET_AZURE_ACCOUNT_KEY,
MEET_AZURE_ACCOUNT_NAME,
MEET_AZURE_CONTAINER_NAME,
MEET_AZURE_SUBCONTAINER_NAME
} from '../../../../environment.js';
import { MEET_ENV } from '../../../../environment.js';
import { errorAzureNotAvailable, internalError } from '../../../../models/error.model.js';
import { LoggerService } from '../../../index.js';
@ -22,13 +17,13 @@ export class ABSService {
private containerClient: ContainerClient;
constructor(@inject(LoggerService) protected logger: LoggerService) {
if (!MEET_AZURE_ACCOUNT_NAME || !MEET_AZURE_ACCOUNT_KEY || !MEET_AZURE_CONTAINER_NAME) {
if (!MEET_ENV.AZURE_ACCOUNT_NAME || !MEET_ENV.AZURE_ACCOUNT_KEY || !MEET_ENV.AZURE_CONTAINER_NAME) {
throw new Error('Azure Blob Storage configuration is incomplete');
}
const AZURE_STORAGE_CONNECTION_STRING = `DefaultEndpointsProtocol=https;AccountName=${MEET_AZURE_ACCOUNT_NAME};AccountKey=${MEET_AZURE_ACCOUNT_KEY};EndpointSuffix=core.windows.net`;
const AZURE_STORAGE_CONNECTION_STRING = `DefaultEndpointsProtocol=https;AccountName=${MEET_ENV.AZURE_ACCOUNT_NAME};AccountKey=${MEET_ENV.AZURE_ACCOUNT_KEY};EndpointSuffix=core.windows.net`;
this.blobServiceClient = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
this.containerClient = this.blobServiceClient.getContainerClient(MEET_AZURE_CONTAINER_NAME);
this.containerClient = this.blobServiceClient.getContainerClient(MEET_ENV.AZURE_CONTAINER_NAME);
this.logger.debug('Azure Client initialized');
}
@ -279,7 +274,7 @@ export class ABSService {
}
protected getFullKey(name: string): string {
const prefix = `${MEET_AZURE_SUBCONTAINER_NAME}`;
const prefix = `${MEET_ENV.AZURE_SUBCONTAINER_NAME}`;
if (name.startsWith(prefix)) {
return name;
@ -299,11 +294,11 @@ export class ABSService {
if (exists) {
this.logger.verbose(
`ABS health check: service accessible and container '${MEET_AZURE_CONTAINER_NAME}' exists`
`ABS health check: service accessible and container '${MEET_ENV.AZURE_CONTAINER_NAME}' exists`
);
return { accessible: true, containerExists: true };
} else {
this.logger.error(`ABS container '${MEET_AZURE_CONTAINER_NAME}' does not exist`);
this.logger.error(`ABS container '${MEET_ENV.AZURE_CONTAINER_NAME}' does not exist`);
return { accessible: true, containerExists: false };
}
} catch (error: any) {

View File

@ -2,7 +2,7 @@ import { Bucket, File, GetFilesOptions, Storage } from '@google-cloud/storage';
import { inject, injectable } from 'inversify';
import { Readable } from 'stream';
import { INTERNAL_CONFIG } from '../../../../config/internal-config.js';
import { MEET_S3_BUCKET, MEET_S3_SUBBUCKET } from '../../../../environment.js';
import { MEET_ENV } from '../../../../environment.js';
import { errorS3NotAvailable, internalError } from '../../../../models/error.model.js';
import { LoggerService } from '../../../index.js';
@ -13,16 +13,16 @@ export class GCSService {
constructor(@inject(LoggerService) protected logger: LoggerService) {
this.storage = new Storage();
this.bucket = this.storage.bucket(MEET_S3_BUCKET); // Use S3_BUCKET as GCS bucket name
this.bucket = this.storage.bucket(MEET_ENV.S3_BUCKET); // Use S3_BUCKET as GCS bucket name
this.logger.debug('GCS Storage Client initialized');
}
/**
* Checks if a file exists in the specified GCS bucket.
*/
async exists(name: string, bucket: string = MEET_S3_BUCKET): Promise<boolean> {
async exists(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<boolean> {
try {
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const file = bucketObj.file(this.getFullKey(name));
const [exists] = await file.exists();
@ -45,11 +45,11 @@ export class GCSService {
* Saves an object to a GCS bucket.
* Uses an internal retry mechanism in case of errors.
*/
async saveObject(name: string, body: Record<string, unknown>, bucket: string = MEET_S3_BUCKET): Promise<any> {
async saveObject(name: string, body: Record<string, unknown>, bucket: string = MEET_ENV.S3_BUCKET): Promise<any> {
const fullKey = this.getFullKey(name);
try {
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const file = bucketObj.file(fullKey);
const result = await this.retryOperation(async () => {
await file.save(JSON.stringify(body), {
@ -76,15 +76,15 @@ export class GCSService {
/**
* Bulk deletes objects from GCS Storage.
* @param keys Array of object keys to delete
* @param bucket GCS bucket name (default: MEET_S3_BUCKET)
* @param bucket GCS bucket name (default: S3_BUCKET)
*/
async deleteObjects(keys: string[], bucket: string = MEET_S3_BUCKET): Promise<any> {
async deleteObjects(keys: string[], bucket: string = MEET_ENV.S3_BUCKET): Promise<any> {
try {
this.logger.verbose(
`GCS deleteObjects: attempting to delete ${keys.length} objects from bucket '${bucket}'`
);
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const deletePromises = keys.map((key) => {
const file = bucketObj.file(this.getFullKey(key));
return file.delete();
@ -110,7 +110,7 @@ export class GCSService {
* @param additionalPrefix Additional prefix relative to the subbucket.
* @param maxKeys Maximum number of objects to return. Defaults to 50.
* @param continuationToken Token to retrieve the next page.
* @param bucket Optional bucket name. Defaults to MEET_S3_BUCKET.
* @param bucket Optional bucket name. Defaults to S3_BUCKET.
*
* @returns S3-compatible response object.
*/
@ -118,7 +118,7 @@ export class GCSService {
additionalPrefix = '',
maxResults = 50,
continuationToken?: string,
bucket: string = MEET_S3_BUCKET
bucket: string = MEET_ENV.S3_BUCKET
): Promise<{
items: Array<{ Key?: string; LastModified?: Date; Size?: number; ETag?: string }>;
continuationToken?: string;
@ -129,7 +129,7 @@ export class GCSService {
try {
maxResults = Number(maxResults);
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const options: GetFilesOptions = {
prefix: basePrefix,
@ -181,9 +181,9 @@ export class GCSService {
}
}
async getObjectAsJson(name: string, bucket: string = MEET_S3_BUCKET): Promise<object | undefined> {
async getObjectAsJson(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<object | undefined> {
try {
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const file = bucketObj.file(this.getFullKey(name));
const [exists] = await file.exists();
@ -220,10 +220,10 @@ export class GCSService {
async getObjectAsStream(
name: string,
range?: { start: number; end: number },
bucket: string = MEET_S3_BUCKET
bucket: string = MEET_ENV.S3_BUCKET
): Promise<Readable> {
try {
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const file = bucketObj.file(this.getFullKey(name));
const options: any = {};
@ -252,9 +252,9 @@ export class GCSService {
}
}
async getObjectHeaders(name: string, bucket: string = MEET_S3_BUCKET): Promise<any> {
async getObjectHeaders(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<any> {
try {
const bucketObj = bucket === MEET_S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const bucketObj = bucket === MEET_ENV.S3_BUCKET ? this.bucket : this.storage.bucket(bucket);
const file = bucketObj.file(this.getFullKey(name));
const [metadata] = await file.getMetadata();
@ -289,14 +289,14 @@ export class GCSService {
await this.bucket.getMetadata();
// If we reach here, both service and bucket are accessible
this.logger.verbose(`GCS health check: service accessible and bucket '${MEET_S3_BUCKET}' exists`);
this.logger.verbose(`GCS health check: service accessible and bucket '${MEET_ENV.S3_BUCKET}' exists`);
return { accessible: true, bucketExists: true };
} catch (error: any) {
this.logger.error(`GCS health check failed: ${error.message}`);
// Check if it's a bucket-specific error
if (error.code === 404) {
this.logger.error(`GCS bucket '${MEET_S3_BUCKET}' does not exist`);
this.logger.error(`GCS bucket '${MEET_ENV.S3_BUCKET}' does not exist`);
return { accessible: true, bucketExists: false };
}
@ -311,7 +311,7 @@ export class GCSService {
* Otherwise, the prefix is prepended to the name.
*/
protected getFullKey(name: string): string {
const prefix = `${MEET_S3_SUBBUCKET}`; // Use S3_SUBBUCKET for compatibility
const prefix = `${MEET_ENV.S3_SUBBUCKET}`; // Use S3_SUBBUCKET for compatibility
if (name.startsWith(prefix)) {
return name;

View File

@ -15,15 +15,7 @@ import {
import { inject, injectable } from 'inversify';
import { Readable } from 'stream';
import { INTERNAL_CONFIG } from '../../../../config/internal-config.js';
import {
MEET_AWS_REGION,
MEET_S3_ACCESS_KEY,
MEET_S3_BUCKET,
MEET_S3_SECRET_KEY,
MEET_S3_SERVICE_ENDPOINT,
MEET_S3_SUBBUCKET,
MEET_S3_WITH_PATH_STYLE_ACCESS
} from '../../../../environment.js';
import { MEET_ENV } from '../../../../environment.js';
import { errorS3NotAvailable, internalError } from '../../../../models/error.model.js';
import { LoggerService } from '../../../index.js';
@ -33,17 +25,17 @@ export class S3Service {
constructor(@inject(LoggerService) protected logger: LoggerService) {
const config: S3ClientConfig = {
region: MEET_AWS_REGION,
endpoint: MEET_S3_SERVICE_ENDPOINT,
forcePathStyle: MEET_S3_WITH_PATH_STYLE_ACCESS === 'true'
region: MEET_ENV.AWS_REGION,
endpoint: MEET_ENV.S3_SERVICE_ENDPOINT,
forcePathStyle: MEET_ENV.S3_WITH_PATH_STYLE_ACCESS === 'true'
};
// Configure credentials only if both access key and secret key are provided
// This allow IAM Role usage without hardcoding credentials
if (MEET_S3_ACCESS_KEY && MEET_S3_SECRET_KEY) {
if (MEET_ENV.S3_ACCESS_KEY && MEET_ENV.S3_SECRET_KEY) {
config.credentials = {
accessKeyId: MEET_S3_ACCESS_KEY,
secretAccessKey: MEET_S3_SECRET_KEY
accessKeyId: MEET_ENV.S3_ACCESS_KEY,
secretAccessKey: MEET_ENV.S3_SECRET_KEY
};
}
@ -54,7 +46,7 @@ export class S3Service {
/**
* Checks if a file exists in the specified S3 bucket.
*/
async exists(name: string, bucket: string = MEET_S3_BUCKET): Promise<boolean> {
async exists(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<boolean> {
try {
await this.getObjectHeaders(name, bucket);
this.logger.verbose(`S3 exists: file '${this.getFullKey(name)}' found in bucket '${bucket}'`);
@ -72,7 +64,7 @@ export class S3Service {
async saveObject(
name: string,
body: Record<string, unknown>,
bucket: string = MEET_S3_BUCKET
bucket: string = MEET_ENV.S3_BUCKET
): Promise<PutObjectCommandOutput> {
const fullKey = this.getFullKey(name);
@ -99,9 +91,9 @@ export class S3Service {
/**
* Bulk deletes objects from S3.
* @param keys Array of object keys to delete
* @param bucket S3 bucket name (default: MEET_S3_BUCKET)
* @param bucket S3 bucket name (default: S3_BUCKET)
*/
async deleteObjects(keys: string[], bucket: string = MEET_S3_BUCKET): Promise<DeleteObjectsCommandOutput> {
async deleteObjects(keys: string[], bucket: string = MEET_ENV.S3_BUCKET): Promise<DeleteObjectsCommandOutput> {
try {
this.logger.verbose(
`S3 deleteObjects: attempting to delete ${keys.length} objects from bucket '${bucket}'`
@ -129,7 +121,7 @@ export class S3Service {
* @param additionalPrefix Additional prefix relative to the subbucket.
* @param maxKeys Maximum number of objects to return. Defaults to 50.
* @param continuationToken Token to retrieve the next page.
* @param bucket Optional bucket name. Defaults to MEET_S3_BUCKET.
* @param bucket Optional bucket name. Defaults to S3_BUCKET.
*
* @returns The ListObjectsV2CommandOutput with Keys and NextContinuationToken.
*/
@ -137,7 +129,7 @@ export class S3Service {
additionalPrefix = '',
maxKeys = 50,
continuationToken?: string,
bucket: string = MEET_S3_BUCKET
bucket: string = MEET_ENV.S3_BUCKET
): Promise<ListObjectsV2CommandOutput> {
// The complete prefix is constructed by combining the subbucket and the additionalPrefix.
// Example: if s3Subbucket is "recordings" and additionalPrefix is ".metadata/",
@ -160,7 +152,7 @@ export class S3Service {
}
}
async getObjectAsJson(name: string, bucket: string = MEET_S3_BUCKET): Promise<object | undefined> {
async getObjectAsJson(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<object | undefined> {
try {
const obj = await this.getObject(name, bucket);
const str = await obj.Body?.transformToString();
@ -189,7 +181,7 @@ export class S3Service {
async getObjectAsStream(
name: string,
range?: { start: number; end: number },
bucket: string = MEET_S3_BUCKET
bucket: string = MEET_ENV.S3_BUCKET
): Promise<Readable> {
try {
const obj = await this.getObject(name, bucket, range);
@ -215,7 +207,7 @@ export class S3Service {
}
}
async getObjectHeaders(name: string, bucket: string = MEET_S3_BUCKET): Promise<HeadObjectCommandOutput> {
async getObjectHeaders(name: string, bucket: string = MEET_ENV.S3_BUCKET): Promise<HeadObjectCommandOutput> {
try {
const fullKey = this.getFullKey(name);
const headParams: HeadObjectCommand = new HeadObjectCommand({
@ -247,20 +239,20 @@ export class S3Service {
// Check if we can access the S3 service by listing objects with a small limit
await this.run(
new ListObjectsV2Command({
Bucket: MEET_S3_BUCKET,
Bucket: MEET_ENV.S3_BUCKET,
MaxKeys: 1
})
);
// If we reach here, both service and bucket are accessible
this.logger.verbose(`S3 health check: service accessible and bucket '${MEET_S3_BUCKET}' exists`);
this.logger.verbose(`S3 health check: service accessible and bucket '${MEET_ENV.S3_BUCKET}' exists`);
return { accessible: true, bucketExists: true };
} catch (error: any) {
this.logger.error(`S3 health check failed: ${error.message}`);
// Check if it's a bucket-specific error
if (error.name === 'NoSuchBucket') {
this.logger.error(`S3 bucket '${MEET_S3_BUCKET}' does not exist`);
this.logger.error(`S3 bucket '${MEET_ENV.S3_BUCKET}' does not exist`);
return { accessible: true, bucketExists: false };
}
@ -275,7 +267,7 @@ export class S3Service {
* Otherwise, the prefix is prepended to the name.
*/
protected getFullKey(name: string): string {
const prefix = `${MEET_S3_SUBBUCKET}`;
const prefix = `${MEET_ENV.S3_SUBBUCKET}`;
if (name.startsWith(prefix)) {
return name;
@ -286,7 +278,7 @@ export class S3Service {
protected async getObject(
name: string,
bucket: string = MEET_S3_BUCKET,
bucket: string = MEET_ENV.S3_BUCKET,
range?: { start: number; end: number }
): Promise<GetObjectCommandOutput> {
const fullKey = this.getFullKey(name);

View File

@ -1,6 +1,6 @@
import { inject, injectable } from 'inversify';
import ms from 'ms';
import { MEET_NAME_ID } from '../../environment.js';
import { MEET_ENV } from '../../environment.js';
import { MeetLock } from '../../helpers/index.js';
import { internalError } from '../../models/index.js';
import { GlobalConfigRepository } from '../../repositories/index.js';
@ -89,7 +89,7 @@ export class StorageInitService {
// Check if it's from the same project
const existingProjectId = existingConfig.projectId;
const currentProjectId = MEET_NAME_ID;
const currentProjectId = MEET_ENV.NAME_ID;
if (existingProjectId !== currentProjectId) {
this.logger.info(

View File

@ -8,7 +8,7 @@ import { inject, injectable } from 'inversify';
import { jwtDecode } from 'jwt-decode';
import { AccessToken, AccessTokenOptions, ClaimGrants, TokenVerifier, VideoGrant } from 'livekit-server-sdk';
import { INTERNAL_CONFIG } from '../config/internal-config.js';
import { LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { LoggerService } from './index.js';
@injectable()
@ -44,7 +44,7 @@ export class TokenService {
participantIdentity?: string
): Promise<string> {
const metadata: MeetRoomMemberTokenMetadata = {
livekitUrl: LIVEKIT_URL,
livekitUrl: MEET_ENV.LIVEKIT_URL,
role,
permissions: permissions.meet
};
@ -59,7 +59,7 @@ export class TokenService {
}
private async generateJwtToken(tokenOptions: AccessTokenOptions, grants?: VideoGrant): Promise<string> {
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, tokenOptions);
const at = new AccessToken(MEET_ENV.LIVEKIT_API_KEY, MEET_ENV.LIVEKIT_API_SECRET, tokenOptions);
if (grants) {
at.addGrant(grants);
@ -69,7 +69,7 @@ export class TokenService {
}
async verifyToken(token: string): Promise<ClaimGrants> {
const verifyer = new TokenVerifier(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
const verifyer = new TokenVerifier(MEET_ENV.LIVEKIT_API_KEY, MEET_ENV.LIVEKIT_API_SECRET);
return await verifyer.verify(token, 0);
}

View File

@ -1,7 +1,7 @@
import { MeetUser, MeetUserDTO, MeetUserRole } from '@openvidu-meet/typings';
import { inject, injectable } from 'inversify';
import { INTERNAL_CONFIG } from '../config/internal-config.js';
import { MEET_INITIAL_ADMIN_PASSWORD, MEET_INITIAL_ADMIN_USER } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { PasswordHelper } from '../helpers/password.helper.js';
import { errorInvalidPassword, internalError } from '../models/error.model.js';
import { UserRepository } from '../repositories/index.js';
@ -19,7 +19,7 @@ export class UserService {
*/
async initializeAdminUser(): Promise<void> {
// Check if the admin user already exists
const existingUser = await this.userRepository.findByUsername(MEET_INITIAL_ADMIN_USER);
const existingUser = await this.userRepository.findByUsername(MEET_ENV.INITIAL_ADMIN_USER);
if (existingUser) {
this.logger.info('Admin user already initialized, skipping admin user initialization');
@ -27,8 +27,8 @@ export class UserService {
}
const admin: MeetUser = {
username: MEET_INITIAL_ADMIN_USER,
passwordHash: await PasswordHelper.hashPassword(MEET_INITIAL_ADMIN_PASSWORD),
username: MEET_ENV.INITIAL_ADMIN_USER,
passwordHash: await PasswordHelper.hashPassword(MEET_ENV.INITIAL_ADMIN_PASSWORD),
roles: [MeetUserRole.ADMIN, MeetUserRole.USER]
};

View File

@ -1,19 +1,19 @@
import { container } from '../config/dependency-injector.config.js';
import { MEET_BASE_URL } from '../environment.js';
import { MEET_ENV } from '../environment.js';
import { BaseUrlService } from '../services/base-url.service.js';
/**
* Returns the base URL for the application.
*
* If the global `MEET_BASE_URL` variable is defined, it returns its value,
* If the global `BASE_URL` variable is defined, it returns its value,
* ensuring there is no trailing slash and removing default ports (443 for HTTPS, 80 for HTTP).
* Otherwise, it retrieves the base URL from the `HttpContextService` instance.
*
* @returns {string} The base URL as a string.
*/
export const getBaseUrl = (): string => {
if (MEET_BASE_URL) {
let baseUrl = MEET_BASE_URL.endsWith('/') ? MEET_BASE_URL.slice(0, -1) : MEET_BASE_URL;
if (MEET_ENV.BASE_URL) {
let baseUrl = MEET_ENV.BASE_URL.endsWith('/') ? MEET_ENV.BASE_URL.slice(0, -1) : MEET_ENV.BASE_URL;
// Remove default port 443 for HTTPS URLs
if (baseUrl.startsWith('https://') && baseUrl.includes(':443')) {

View File

@ -23,20 +23,14 @@ import ms, { StringValue } from 'ms';
import request, { Response } from 'supertest';
import { container, initializeEagerServices } from '../../src/config/index.js';
import { INTERNAL_CONFIG } from '../../src/config/internal-config.js';
import {
LIVEKIT_API_KEY,
LIVEKIT_API_SECRET,
MEET_INITIAL_ADMIN_PASSWORD,
MEET_INITIAL_ADMIN_USER,
MEET_INITIAL_API_KEY
} from '../../src/environment.js';
import { MEET_ENV } from '../../src/environment.js';
import { createApp, registerDependencies } from '../../src/server.js';
import { ApiKeyService, GlobalConfigService, RecordingService, RoomService } from '../../src/services/index.js';
const CREDENTIALS = {
admin: {
username: MEET_INITIAL_ADMIN_USER,
password: MEET_INITIAL_ADMIN_PASSWORD
username: MEET_ENV.INITIAL_ADMIN_USER,
password: MEET_ENV.INITIAL_ADMIN_PASSWORD
}
};
@ -231,7 +225,7 @@ export const createRoom = async (options: MeetRoomOptions = {}): Promise<MeetRoo
const response = await request(app)
.post(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(options)
.expect(201);
return response.body;
@ -242,7 +236,7 @@ export const getRooms = async (query: Record<string, unknown> = {}) => {
return await request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.query(query);
};
@ -263,7 +257,7 @@ export const getRoom = async (roomId: string, fields?: string, roomMemberToken?:
if (roomMemberToken) {
req.set(INTERNAL_CONFIG.ROOM_MEMBER_TOKEN_HEADER, roomMemberToken);
} else {
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
}
return await req;
@ -274,7 +268,7 @@ export const getRoomConfig = async (roomId: string): Promise<Response> => {
return await request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/config`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send();
};
@ -283,7 +277,7 @@ export const updateRoomConfig = async (roomId: string, config: Partial<MeetRoomC
return await request(app)
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/config`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ config });
};
@ -302,7 +296,7 @@ export const updateRoomStatus = async (roomId: string, status: MeetRoomStatus) =
return await request(app)
.put(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}/status`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ status });
};
@ -311,7 +305,7 @@ export const deleteRoom = async (roomId: string, query: Record<string, unknown>
const result = await request(app)
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms/${roomId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.query(query);
await sleep('1s');
return result;
@ -322,7 +316,7 @@ export const bulkDeleteRooms = async (roomIds: string[], withMeeting?: string, w
const result = await request(app)
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/rooms`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.query({ roomIds: roomIds.join(','), withMeeting, withRecordings });
await sleep('1s');
return result;
@ -434,9 +428,9 @@ export const joinFakeParticipant = async (roomId: string, participantIdentity: s
'--publish-demo',
roomId,
'--api-key',
LIVEKIT_API_KEY,
MEET_ENV.LIVEKIT_API_KEY,
'--api-secret',
LIVEKIT_API_SECRET
MEET_ENV.LIVEKIT_API_SECRET
]);
// Store the process to be able to terminate it later
@ -468,9 +462,9 @@ export const updateParticipantMetadata = async (
'--metadata',
JSON.stringify(metadata),
'--api-key',
LIVEKIT_API_KEY,
MEET_ENV.LIVEKIT_API_KEY,
'--api-secret',
LIVEKIT_API_SECRET
MEET_ENV.LIVEKIT_API_SECRET
]);
await sleep('1s');
};
@ -595,7 +589,7 @@ export const getRecording = async (recordingId: string) => {
return await request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
};
export const getRecordingMedia = async (recordingId: string, range?: string) => {
@ -603,7 +597,7 @@ export const getRecordingMedia = async (recordingId: string, range?: string) =>
const req = request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}/media`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
if (range) {
req.set('range', range);
@ -618,7 +612,7 @@ export const getRecordingUrl = async (recordingId: string, privateAccess = false
return await request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}/url`)
.query({ privateAccess })
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
};
export const deleteRecording = async (recordingId: string) => {
@ -626,7 +620,7 @@ export const deleteRecording = async (recordingId: string) => {
return await request(app)
.delete(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings/${recordingId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
};
export const bulkDeleteRecordings = async (recordingIds: string[], roomMemberToken?: string): Promise<Response> => {
@ -639,7 +633,7 @@ export const bulkDeleteRecordings = async (recordingIds: string[], roomMemberTok
if (roomMemberToken) {
req.set(INTERNAL_CONFIG.ROOM_MEMBER_TOKEN_HEADER, roomMemberToken);
} else {
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
}
return await req;
@ -659,7 +653,7 @@ export const downloadRecordings = async (
if (roomMemberToken) {
req.set(INTERNAL_CONFIG.ROOM_MEMBER_TOKEN_HEADER, roomMemberToken);
} else {
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
req.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
}
if (asBuffer) {
@ -707,7 +701,7 @@ export const getAllRecordings = async (query: Record<string, unknown> = {}) => {
return await request(app)
.get(`${INTERNAL_CONFIG.API_BASE_PATH_V1}/recordings`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.query(query);
};

View File

@ -1,6 +1,6 @@
import { afterAll, afterEach, beforeAll, describe, expect, it } from '@jest/globals';
import { Request } from 'express';
import { MEET_INITIAL_WEBHOOK_ENABLED, MEET_INITIAL_WEBHOOK_URL } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
import {
getWebbhookConfig,
@ -107,8 +107,8 @@ describe('Webhook Config API Tests', () => {
expect(response.status).toBe(200);
expect(response.body).toEqual({
enabled: MEET_INITIAL_WEBHOOK_ENABLED === 'true',
url: MEET_INITIAL_WEBHOOK_URL
enabled: MEET_ENV.INITIAL_WEBHOOK_ENABLED === 'true',
url: MEET_ENV.INITIAL_WEBHOOK_URL
});
});
});

View File

@ -1,7 +1,7 @@
import { afterAll, beforeAll, beforeEach, describe, expect, it, jest } from '@jest/globals';
import { MeetRoomMemberRole, MeetRoomMemberTokenMetadata, MeetSignalType } from '@openvidu-meet/typings';
import { container } from '../../../../src/config/index.js';
import { LIVEKIT_URL } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { FrontendEventService, LiveKitService } from '../../../../src/services/index.js';
import { getPermissions } from '../../../helpers/assertion-helpers.js';
import {
@ -33,7 +33,7 @@ describe('Meetings API Tests', () => {
describe('Update Participant Tests', () => {
const setParticipantMetadata = async (roomId: string, role: MeetRoomMemberRole) => {
const metadata: MeetRoomMemberTokenMetadata = {
livekitUrl: LIVEKIT_URL,
livekitUrl: MEET_ENV.LIVEKIT_URL,
role,
permissions: getPermissions(roomId, role, true, true).meet
};

View File

@ -8,7 +8,7 @@ import { Express } from 'express';
import ms from 'ms';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
import { createRoom, deleteAllRooms, startTestServer } from '../../../helpers/request-helpers.js';
@ -284,7 +284,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -301,7 +301,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -319,7 +319,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -334,7 +334,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -349,7 +349,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -365,7 +365,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -384,7 +384,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -403,7 +403,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -424,7 +424,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -441,7 +441,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -456,7 +456,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -472,7 +472,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -497,7 +497,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -508,7 +508,7 @@ describe('Room API Tests', () => {
// In this case, instead of sending JSON object, send an invalid JSON string.
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.set('Content-Type', 'application/json')
.send('{"roomName": "TestRoom",') // invalid JSON syntax
.expect(400);
@ -526,7 +526,7 @@ describe('Room API Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);

View File

@ -3,7 +3,7 @@ import { MeetRecordingAccess, MeetRoom } from '@openvidu-meet/typings';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidRoom } from '../../../helpers/assertion-helpers.js';
import {
createRoom,
@ -133,7 +133,7 @@ describe('E2EE Room Configuration Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -156,7 +156,7 @@ describe('E2EE Room Configuration Tests', () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(payload)
.expect(422);
@ -225,7 +225,7 @@ describe('E2EE Room Configuration Tests', () => {
const response = await request(app)
.get(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.expect(200);
// Filter out any rooms from other test suites

View File

@ -2,7 +2,7 @@ import { beforeAll, describe, expect, it } from '@jest/globals';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { loginUser, startTestServer } from '../../../helpers/request-helpers.js';
const ANALYTICS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/analytics`;
@ -20,7 +20,7 @@ describe('Analytics API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.get(ANALYTICS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});

View File

@ -3,7 +3,7 @@ import { AuthMode, AuthType, MeetRoomThemeMode } from '@openvidu-meet/typings';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { loginUser, restoreDefaultGlobalConfig, startTestServer } from '../../../helpers/request-helpers.js';
const CONFIG_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/config`;
@ -26,7 +26,7 @@ describe('Global Config API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.put(`${CONFIG_PATH}/webhooks`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(webhookConfig);
expect(response.status).toBe(401);
});
@ -51,7 +51,7 @@ describe('Global Config API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.get(`${CONFIG_PATH}/webhooks`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
@ -81,7 +81,7 @@ describe('Global Config API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.put(`${CONFIG_PATH}/security`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(securityConfig);
expect(response.status).toBe(401);
});
@ -125,7 +125,7 @@ describe('Global Config API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.put(`${CONFIG_PATH}/rooms/appearance`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send(appearanceConfig);
expect(response.status).toBe(401);
});

View File

@ -3,7 +3,7 @@ import { MeetRoomMemberRole, MeetRoomMemberTokenMetadata } from '@openvidu-meet/
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { LIVEKIT_URL, MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { getPermissions } from '../../../helpers/assertion-helpers.js';
import {
deleteAllRooms,
@ -39,7 +39,7 @@ describe('Meeting API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
@ -80,7 +80,7 @@ describe('Meeting API Security Tests', () => {
beforeEach(async () => {
const metadata: MeetRoomMemberTokenMetadata = {
livekitUrl: LIVEKIT_URL,
livekitUrl: MEET_ENV.LIVEKIT_URL,
role: MeetRoomMemberRole.SPEAKER,
permissions: getPermissions(roomData.room.roomId, MeetRoomMemberRole.SPEAKER, true, true).meet
};
@ -90,7 +90,7 @@ describe('Meeting API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.put(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_NAME}/role`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ role });
expect(response.status).toBe(401);
});
@ -136,7 +136,7 @@ describe('Meeting API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.delete(`${MEETINGS_PATH}/${roomData.room.roomId}/participants/${PARTICIPANT_IDENTITY}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});

View File

@ -3,7 +3,7 @@ import { MeetRecordingAccess } from '@openvidu-meet/typings';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidStopRecordingResponse } from '../../../helpers/assertion-helpers.js';
import {
deleteAllRecordings,
@ -48,7 +48,7 @@ describe('Recording API Security Tests', () => {
const response = await request(app)
.post(INTERNAL_RECORDINGS_PATH)
.send({ roomId: roomData.room.roomId })
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
@ -106,7 +106,7 @@ describe('Recording API Security Tests', () => {
it('should fail when request includes API key', async () => {
const response = await request(app)
.post(`${INTERNAL_RECORDINGS_PATH}/${roomData.recordingId}/stop`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(401);
});
@ -158,7 +158,7 @@ describe('Recording API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(RECORDINGS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -228,7 +228,7 @@ describe('Recording API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(`${RECORDINGS_PATH}/${recordingId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -353,7 +353,7 @@ describe('Recording API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.delete(`${RECORDINGS_PATH}/${fakeRecordingId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(404);
});
@ -435,7 +435,7 @@ describe('Recording API Security Tests', () => {
const response = await request(app)
.delete(RECORDINGS_PATH)
.query({ recordingIds: fakeRecordingId })
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(400);
});
@ -510,7 +510,7 @@ describe('Recording API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(`${RECORDINGS_PATH}/${recordingId}/media`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -650,7 +650,7 @@ describe('Recording API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(`${RECORDINGS_PATH}/${recordingId}/url`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -721,7 +721,7 @@ describe('Recording API Security Tests', () => {
const response = await request(app)
.get(`${RECORDINGS_PATH}/download`)
.query({ recordingIds: recordingId })
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});

View File

@ -3,7 +3,7 @@ import { AuthMode, MeetRecordingAccess } from '@openvidu-meet/typings';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_API_KEY } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import {
changeSecurityConfig,
createRoom,
@ -34,7 +34,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.post(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({});
expect(response.status).toBe(201);
});
@ -57,7 +57,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(ROOMS_PATH)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -86,7 +86,7 @@ describe('Room API Security Tests', () => {
const response = await request(app)
.delete(ROOMS_PATH)
.query({ roomIds: roomId })
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -114,7 +114,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(`${ROOMS_PATH}/${roomData.room.roomId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -183,7 +183,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.delete(`${ROOMS_PATH}/${roomId}`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -210,7 +210,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.get(`${ROOMS_PATH}/${roomData.room.roomId}/config`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY);
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY);
expect(response.status).toBe(200);
});
@ -279,7 +279,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.put(`${ROOMS_PATH}/${roomId}/config`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ config: roomConfig });
expect(response.status).toBe(200);
});
@ -309,7 +309,7 @@ describe('Room API Security Tests', () => {
it('should succeed when request includes API key', async () => {
const response = await request(app)
.put(`${ROOMS_PATH}/${roomId}/status`)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_INITIAL_API_KEY)
.set(INTERNAL_CONFIG.API_KEY_HEADER, MEET_ENV.INITIAL_API_KEY)
.send({ status: 'open' });
expect(response.status).toBe(200);
});

View File

@ -2,7 +2,7 @@ import { beforeAll, describe, expect, it } from '@jest/globals';
import { Express } from 'express';
import request from 'supertest';
import { INTERNAL_CONFIG } from '../../../../src/config/internal-config.js';
import { MEET_INITIAL_ADMIN_PASSWORD } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { changePassword, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
const USERS_PATH = `${INTERNAL_CONFIG.INTERNAL_API_BASE_PATH_V1}/users`;
@ -36,7 +36,7 @@ describe('User API Security Tests', () => {
describe('Change Password Tests', () => {
const changePasswordRequest = {
currentPassword: MEET_INITIAL_ADMIN_PASSWORD,
currentPassword: MEET_ENV.INITIAL_ADMIN_PASSWORD,
newPassword: 'newpassword123'
};
@ -54,7 +54,7 @@ describe('User API Security Tests', () => {
expect(response.status).toBe(200);
// Reset password
await changePassword(changePasswordRequest.newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminAccessToken);
await changePassword(changePasswordRequest.newPassword, MEET_ENV.INITIAL_ADMIN_PASSWORD, adminAccessToken);
});
it('should fail when user is not authenticated', async () => {

View File

@ -1,5 +1,5 @@
import { beforeAll, describe, expect, it } from '@jest/globals';
import { MEET_INITIAL_ADMIN_PASSWORD } from '../../../../src/environment.js';
import { MEET_ENV } from '../../../../src/environment.js';
import { expectValidationError } from '../../../helpers/assertion-helpers.js';
import { changePassword, loginUser, startTestServer } from '../../../helpers/request-helpers.js';
@ -14,11 +14,11 @@ describe('Users API Tests', () => {
describe('Change Password Tests', () => {
it('should successfully change password', async () => {
const newPassword = 'newpassword123';
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, newPassword, adminAccessToken);
const response = await changePassword(MEET_ENV.INITIAL_ADMIN_PASSWORD, newPassword, adminAccessToken);
expect(response.status).toBe(200);
// Reset password
await changePassword(newPassword, MEET_INITIAL_ADMIN_PASSWORD, adminAccessToken);
await changePassword(newPassword, MEET_ENV.INITIAL_ADMIN_PASSWORD, adminAccessToken);
});
it('should fail when current password is incorrect', async () => {
@ -28,7 +28,7 @@ describe('Users API Tests', () => {
});
it('should fail when new password is not 5 characters long', async () => {
const response = await changePassword(MEET_INITIAL_ADMIN_PASSWORD, '1234', adminAccessToken);
const response = await changePassword(MEET_ENV.INITIAL_ADMIN_PASSWORD, '1234', adminAccessToken);
expectValidationError(response, 'newPassword', 'New password must be at least 5 characters long');
});
});