// SECURE - Using environment variables and connection management
const mongoose = require('mongoose');
const redis = require('redis');
const { Client } = require('@elastic/elasticsearch');
const { MongoClient } = require('mongodb');
class SecureNoSQLConnections {
constructor() {
this.connections = {};
}
async connectMongoDB() {
// Build connection string from environment
const config = {
username: process.env.MONGODB_USERNAME,
password: process.env.MONGODB_PASSWORD,
host: process.env.MONGODB_HOST,
port: process.env.MONGODB_PORT || 27017,
database: process.env.MONGODB_DATABASE,
authSource: process.env.MONGODB_AUTH_SOURCE || 'admin'
};
// Validate required fields
if (!config.username || !config.password || !config.host) {
throw new Error('MongoDB configuration incomplete');
}
// Build URI with proper encoding
const uri = this.buildMongoUri(config);
// Connection options for production
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
maxPoolSize: 10,
minPoolSize: 2,
ssl: process.env.NODE_ENV === 'production',
sslValidate: true,
sslCA: process.env.MONGODB_CA_CERT,
authMechanism: 'SCRAM-SHA-256',
retryWrites: true,
w: 'majority'
};
try {
const client = new MongoClient(uri, options);
await client.connect();
// Verify connection
await client.db().admin().ping();
this.connections.mongodb = client;
console.log('MongoDB connected securely');
return client;
} catch (error) {
console.error('MongoDB connection failed:', error.message);
throw error;
}
}
buildMongoUri(config) {
const credentials = encodeURIComponent(config.username) + ':' +
encodeURIComponent(config.password);
// Support replica sets
const hosts = config.host.includes(',')
? config.host
: `${config.host}:${config.port}`;
let uri = `mongodb://${credentials}@${hosts}/${config.database}`;
// Add query parameters
const params = [];
if (config.authSource) params.push(`authSource=${config.authSource}`);
if (process.env.MONGODB_REPLICA_SET) {
params.push(`replicaSet=${process.env.MONGODB_REPLICA_SET}`);
}
if (params.length > 0) {
uri += '?' + params.join('&');
}
return uri;
}
async connectRedis() {
const redisOptions = {
socket: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT) || 6379,
tls: process.env.NODE_ENV === 'production',
rejectUnauthorized: true
},
password: process.env.REDIS_PASSWORD,
database: parseInt(process.env.REDIS_DB) || 0,
lazyConnect: true,
reconnectStrategy: (retries) => {
if (retries > 10) {
return new Error('Redis reconnection attempts exhausted');
}
return Math.min(retries * 100, 3000);
}
};
// Use Redis Sentinel for HA
if (process.env.REDIS_SENTINELS) {
redisOptions.sentinels = JSON.parse(process.env.REDIS_SENTINELS);
redisOptions.name = process.env.REDIS_MASTER_NAME;
}
const client = redis.createClient(redisOptions);
// Error handling
client.on('error', (err) => {
console.error('Redis error:', err);
});
await client.connect();
// Test connection
await client.ping();
this.connections.redis = client;
console.log('Redis connected securely');
return client;
}
async connectElasticsearch() {
// Use Cloud ID for Elastic Cloud
const config = process.env.ELASTIC_CLOUD_ID ? {
cloud: {
id: process.env.ELASTIC_CLOUD_ID
},
auth: {
apiKey: process.env.ELASTIC_API_KEY
}
} : {
node: process.env.ELASTICSEARCH_URL,
auth: {
username: process.env.ELASTIC_USERNAME,
password: process.env.ELASTIC_PASSWORD
},
ssl: {
rejectUnauthorized: true,
ca: process.env.ELASTIC_CA_CERT
}
};
const client = new Client(config);
// Test connection
const info = await client.info();
console.log('Elasticsearch connected:', info.body.cluster_name);
this.connections.elasticsearch = client;
return client;
}
async closeAll() {
for (const [name, connection] of Object.entries(this.connections)) {
try {
if (connection.close) {
await connection.close();
} else if (connection.quit) {
await connection.quit();
}
console.log(`${name} connection closed`);
} catch (error) {
console.error(`Error closing ${name}:`, error);
}
}
}
}
// Kubernetes Secret example
const k8sSecret = `
apiVersion: v1
kind: Secret
metadata:
name: nosql-credentials
type: Opaque
stringData:
mongodb-uri: mongodb://user:pass@mongo:27017/db
redis-password: your-redis-password
elastic-api-key: your-elastic-api-key
`;