enable ssl for pg connection

This commit is contained in:
2026-05-04 11:02:48 +02:00
parent 8cfeb1ed49
commit 33aadc8c1d
+229 -239
View File
@@ -15,320 +15,310 @@ app.use(express.json({ limit: '10mb' }));
// PostgreSQL connection pool // PostgreSQL connection pool
function handleHeaders(headers) { function handleHeaders(headers) {
const alias = (headers['db-alias'] || 'default').toUpperCase().replace(/-/g, '_');
const alias = (headers['db-alias'] || 'default').toUpperCase().replace(/-/g, '_'); let pool = {
host: process.env[`DB_${alias}_HOST`],
port: process.env[`DB_${alias}_PORT`],
database: process.env[`DB_${alias}_DATABASE`],
user: process.env[`DB_${alias}_USER`],
password: process.env[`DB_${alias}_PASSWORD`],
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
};
let pool={ const allUndefined =
host: process.env[`DB_${alias}_HOST`], pool.host === undefined && pool.port === undefined && pool.database === undefined && pool.user === undefined && pool.password === undefined;
port: process.env[`DB_${alias}_PORT`], const someUndefined = pool.host === '' || pool.port === '' || pool.database === '' || pool.user === '' || pool.password === '';
database: process.env[`DB_${alias}_DATABASE`], const someDefined = pool.host != undefined || pool.port != undefined || pool.database != undefined || pool.user != undefined || pool.password != undefined;
user: process.env[`DB_${alias}_USER`],
password: process.env[`DB_${alias}_PASSWORD`],
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
};
const allUndefined = pool.host=== undefined && pool.port=== undefined && pool.database=== undefined && pool.user=== undefined && pool.password=== undefined; if (allUndefined) {
const someUndefined = pool.host=== '' || pool.port=== '' || pool.database=== '' || pool.user=== '' || pool.password=== ''; throw new Error('Invalid db alias');
const someDefined = pool.host != undefined || pool.port != undefined || pool.database != undefined || pool.user != undefined || pool.password != undefined; } else if (someUndefined && someDefined) {
console.log(pool);
if (allUndefined) { if (pool.host === '') {
throw new Error('Invalid db alias'); throw new Error('Host is not configured for the specified db alias');
} }
else if(someUndefined && someDefined) { if (pool.port === '') {
console.log(pool); throw new Error('Port is not configured for the specified db alias');
if(pool.host === '') {
throw new Error('Host is not configured for the specified db alias');
}
if(pool.port === '') {
throw new Error('Port is not configured for the specified db alias');
}
if(pool.database === '') {
throw new Error('Database is not configured for the specified db alias');
}
if(pool.user === '') {
throw new Error('User is not configured for the specified db alias');
}
if(pool.password === '') {
throw new Error('Password is not configured for the specified db alias');
}
} }
else{ if (pool.database === '') {
return new Pool({ throw new Error('Database is not configured for the specified db alias');
host: process.env[`DB_${alias}_HOST`],
port: process.env[`DB_${alias}_PORT`],
database: process.env[`DB_${alias}_DATABASE`],
user: process.env[`DB_${alias}_USER`],
password: process.env[`DB_${alias}_PASSWORD`],
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
} }
if (pool.user === '') {
throw new Error('User is not configured for the specified db alias');
}
if (pool.password === '') {
throw new Error('Password is not configured for the specified db alias');
}
} else {
return new Pool({
host: process.env[`DB_${alias}_HOST`],
port: process.env[`DB_${alias}_PORT`],
database: process.env[`DB_${alias}_DATABASE`],
user: process.env[`DB_${alias}_USER`],
password: process.env[`DB_${alias}_PASSWORD`],
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
ssl: { rejectUnauthorized: false },
});
}
} }
// Health check endpoint // Health check endpoint
app.get('/api/health', (req, res) => { app.get('/api/health', (req, res) => {
res.json({ res.json({
status: 'ok', status: 'ok',
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
node_version: process.version node_version: process.version,
}); });
}); });
// SELECT query endpoint // SELECT query endpoint
app.post('/api/postgres/select', async (req, res) => { app.post('/api/postgres/select', async (req, res) => {
const { query, bindings = [] } = req.body; const { query, bindings = [] } = req.body;
if (!query) { if (!query) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Query is required' error: 'Query is required',
}); });
} }
let pool; let pool;
try { try {
pool = handleHeaders(req.headers); pool = handleHeaders(req.headers);
const result = await pool.query(query, bindings); const result = await pool.query(query, bindings);
res.json({ res.json({
success: true, success: true,
data: result.rows, data: result.rows,
count: result.rowCount count: result.rowCount,
}); });
} catch (error) { } catch (error) {
console.error('SELECT Error:', error); console.error('SELECT Error:', error);
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: error.message error: error.message,
}); });
} finally { } finally {
if (pool) await pool.end(); if (pool) await pool.end();
} }
}); });
// EXECUTE query endpoint (INSERT, UPDATE, DELETE) // EXECUTE query endpoint (INSERT, UPDATE, DELETE)
app.post('/api/postgres/execute', async (req, res) => { app.post('/api/postgres/execute', async (req, res) => {
const { query, bindings = [] } = req.body; const { query, bindings = [] } = req.body;
if (!query) { if (!query) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Query is required' error: 'Query is required',
}); });
} }
let pool; let pool;
try { try {
pool = handleHeaders(req.headers); pool = handleHeaders(req.headers);
const result = await pool.query(query, bindings); const result = await pool.query(query, bindings);
res.json({ res.json({
success: true, success: true,
affected_rows: result.rowCount affected_rows: result.rowCount,
}); });
} catch (error) { } catch (error) {
console.error('EXECUTE Error:', error); console.error('EXECUTE Error:', error);
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: error.message error: error.message,
}); });
} finally { } finally {
if (pool) await pool.end(); if (pool) await pool.end();
} }
}); });
// TRANSACTION endpoint // TRANSACTION endpoint
app.post('/api/postgres/transaction', async (req, res) => { app.post('/api/postgres/transaction', async (req, res) => {
const { queries } = req.body; const { queries } = req.body;
if (!queries || !Array.isArray(queries)) { if (!queries || !Array.isArray(queries)) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Queries array is required' error: 'Queries array is required',
}); });
}
let pool;
let client;
try {
pool = handleHeaders(req.headers);
client = await pool.connect();
await client.query('BEGIN');
const results = [];
for (const item of queries) {
const result = await client.query(item.query, item.bindings || []);
results.push({
rowCount: result.rowCount,
success: true,
});
} }
let pool; await client.query('COMMIT');
let client;
try {
pool = handleHeaders(req.headers);
client = await pool.connect();
await client.query('BEGIN'); res.json({
success: true,
const results = []; results: results,
for (const item of queries) { });
const result = await client.query(item.query, item.bindings || []); } catch (error) {
results.push({ if (client) await client.query('ROLLBACK');
rowCount: result.rowCount, console.error('TRANSACTION Error:', error);
success: true res.status(400).json({
}); success: false,
} error: error.message,
});
await client.query('COMMIT'); } finally {
if (client) client.release();
res.json({ if (pool) await pool.end();
success: true, }
results: results
});
} catch (error) {
if (client) await client.query('ROLLBACK');
console.error('TRANSACTION Error:', error);
res.status(400).json({
success: false,
error: error.message
});
} finally {
if (client) client.release();
if (pool) await pool.end();
}
}); });
// INSERT simplified endpoint // INSERT simplified endpoint
app.post('/api/postgres/insert', async (req, res) => { app.post('/api/postgres/insert', async (req, res) => {
const { table, data } = req.body; const { table, data } = req.body;
if (!table || !data) { if (!table || !data) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Table and data are required' error: 'Table and data are required',
}); });
} }
let pool; let pool;
try { try {
pool = handleHeaders(req.headers); pool = handleHeaders(req.headers);
const columns = Object.keys(data); const columns = Object.keys(data);
const values = Object.values(data); const values = Object.values(data);
const placeholders = values.map((_, i) => `$${i + 1}`).join(', '); const placeholders = values.map((_, i) => `$${i + 1}`).join(', ');
const query = ` const query = `
INSERT INTO "${table}" (${columns.map(c => `"${c}"`).join(', ')}) INSERT INTO "${table}" (${columns.map((c) => `"${c}"`).join(', ')})
VALUES (${placeholders}) VALUES (${placeholders})
RETURNING * RETURNING *
`; `;
const result = await pool.query(query, values); const result = await pool.query(query, values);
res.json({ res.json({
success: true, success: true,
data: result.rows[0] data: result.rows[0],
}); });
} catch (error) { } catch (error) {
console.error('INSERT Error:', error); console.error('INSERT Error:', error);
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: error.message error: error.message,
}); });
} finally { } finally {
if (pool) await pool.end(); if (pool) await pool.end();
} }
}); });
// UPDATE simplified endpoint // UPDATE simplified endpoint
app.post('/api/postgres/update', async (req, res) => { app.post('/api/postgres/update', async (req, res) => {
const { table, data, where } = req.body; const { table, data, where } = req.body;
if (!table || !data || !where) { if (!table || !data || !where) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Table, data and where are required' error: 'Table, data and where are required',
}); });
} }
let pool; let pool;
try { try {
pool = handleHeaders(req.headers); pool = handleHeaders(req.headers);
const setColumns = Object.keys(data); const setColumns = Object.keys(data);
const setValues = Object.values(data); const setValues = Object.values(data);
const whereColumns = Object.keys(where); const whereColumns = Object.keys(where);
const whereValues = Object.values(where); const whereValues = Object.values(where);
const setClause = setColumns const setClause = setColumns.map((col, i) => `"${col}" = $${i + 1}`).join(', ');
.map((col, i) => `"${col}" = $${i + 1}`)
.join(', ');
const whereClause = whereColumns const whereClause = whereColumns.map((col, i) => `"${col}" = $${setValues.length + i + 1}`).join(' AND ');
.map((col, i) => `"${col}" = $${setValues.length + i + 1}`)
.join(' AND ');
const query = ` const query = `
UPDATE "${table}" UPDATE "${table}"
SET ${setClause} SET ${setClause}
WHERE ${whereClause} WHERE ${whereClause}
`; `;
const result = await pool.query(query, [...setValues, ...whereValues]); const result = await pool.query(query, [...setValues, ...whereValues]);
res.json({ res.json({
success: true, success: true,
affected_rows: result.rowCount affected_rows: result.rowCount,
}); });
} catch (error) { } catch (error) {
console.error('UPDATE Error:', error); console.error('UPDATE Error:', error);
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: error.message error: error.message,
}); });
} finally { } finally {
if (pool) await pool.end(); if (pool) await pool.end();
} }
}); });
// DELETE simplified endpoint // DELETE simplified endpoint
app.post('/api/postgres/delete', async (req, res) => { app.post('/api/postgres/delete', async (req, res) => {
const { table, where } = req.body; const { table, where } = req.body;
if (!table || !where) { if (!table || !where) {
return res.status(422).json({ return res.status(422).json({
success: false, success: false,
error: 'Table and where are required' error: 'Table and where are required',
}); });
} }
let pool; let pool;
try { try {
pool = handleHeaders(req.headers); pool = handleHeaders(req.headers);
const whereColumns = Object.keys(where); const whereColumns = Object.keys(where);
const whereValues = Object.values(where); const whereValues = Object.values(where);
const whereClause = whereColumns const whereClause = whereColumns.map((col, i) => `"${col}" = $${i + 1}`).join(' AND ');
.map((col, i) => `"${col}" = $${i + 1}`)
.join(' AND ');
const query = `DELETE FROM "${table}" WHERE ${whereClause}`; const query = `DELETE FROM "${table}" WHERE ${whereClause}`;
const result = await pool.query(query, whereValues); const result = await pool.query(query, whereValues);
res.json({ res.json({
success: true, success: true,
affected_rows: result.rowCount affected_rows: result.rowCount,
}); });
} catch (error) { } catch (error) {
console.error('DELETE Error:', error); console.error('DELETE Error:', error);
res.status(400).json({ res.status(400).json({
success: false, success: false,
error: error.message error: error.message,
}); });
} finally { } finally {
if (pool) await pool.end(); if (pool) await pool.end();
} }
}); });
// Start server // Start server
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`✓ Postgres API running on http://localhost:${PORT}`); console.log(`✓ Postgres API running on http://localhost:${PORT}`);
console.log(`✓ Health check: http://localhost:${PORT}/api/health`); console.log(`✓ Health check: http://localhost:${PORT}/api/health`);
}); });
// Handle shutdown gracefully // Handle shutdown gracefully
process.on('SIGINT', async () => { process.on('SIGINT', async () => {
console.log('\nShutting down gracefully...'); console.log('\nShutting down gracefully...');
process.exit(0); process.exit(0);
}); });