diff --git a/backend/server.js b/backend/server.js index ead40e6..57f5d4e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -13,6 +13,8 @@ const port = 3001; app.use(cors()); app.use(express.json()); app.use(compression()); +// Disable Express auto-ETag to avoid weak ETags on JSON bodies +app.set('etag', false); // Expose important headers to browser JS (for CORS) app.use((req, res, next) => { @@ -27,9 +29,13 @@ app.use(express.static(path.join(__dirname, 'public'))); const s3 = new AWS.S3({ endpoint: 'https://storage.yandexcloud.net', region: process.env.AWS_REGION, + s3ForcePathStyle: true, + signatureVersion: 'v4', + httpOptions: { timeout: 15000 }, + maxRetries: 3, credentials: { - accessKeyId: process.env.AWS_ACCESS_KEY_ID, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + accessKeyId: process.env.AWS_ACCESS_KEY_ID || process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || process.env.S3_SECRET_ACCESS_KEY, } }); @@ -365,11 +371,10 @@ app.post('/api/asns', async (req, res) => { if (!validateAsns(asns || [])) { return res.status(400).json({ message: 'Invalid payload format for asns' }); } - if (etag) { - const current = await headS3ObjectEtag('bgp_data/asns.txt').catch(() => undefined); - if (current && current.replace(/\"/g, '"') !== String(etag)) { - return res.status(412).json({ message: 'Precondition Failed: ETag mismatch' }); - } + let current = null; + try { current = await headS3ObjectEtag('bgp_data/asns.txt'); } catch {} + if (current && etag && current !== String(etag)) { + return res.status(412).json({ message: 'Precondition Failed: ETag mismatch', currentEtag: current }); } } catch {} @@ -388,7 +393,7 @@ app.post('/api/asns', async (req, res) => { if (head.LastModified) res.set('Last-Modified', new Date(head.LastModified).toUTCString()); if (typeof head.ContentLength === 'number') res.set('Content-Length-Source', String(head.ContentLength)); } catch {} - res.send('File updated successfully'); + res.json({ ok: true }); } catch (error) { console.error(error); res.status(500).send('Error writing to S3'); @@ -453,11 +458,10 @@ app.post('/api/domains-new', async (req, res) => { if (!validateDomainsNew(domains || [])) { return res.status(400).json({ message: 'Invalid payload format for domains-new' }); } - if (etag) { - const current = await headS3ObjectEtag('bgp_data/domains_community.txt').catch(() => undefined); - if (current && current.replace(/\"/g, '"') !== String(etag)) { - return res.status(412).json({ message: 'Precondition Failed: ETag mismatch' }); - } + let current = null; + try { current = await headS3ObjectEtag('bgp_data/domains_community.txt'); } catch {} + if (current && etag && current !== String(etag)) { + return res.status(412).json({ message: 'Precondition Failed: ETag mismatch', currentEtag: current }); } } catch {} @@ -476,7 +480,7 @@ app.post('/api/domains-new', async (req, res) => { if (head.LastModified) res.set('Last-Modified', new Date(head.LastModified).toUTCString()); if (typeof head.ContentLength === 'number') res.set('Content-Length-Source', String(head.ContentLength)); } catch {} - res.send('File updated successfully'); + res.json({ ok: true }); } catch (error) { console.error(error); res.status(500).send('Error writing to S3'); @@ -541,11 +545,10 @@ app.post('/api/ip-ranges', async (req, res) => { if (!validateIpRanges(ipRanges || [])) { return res.status(400).json({ message: 'Invalid payload format for ip-ranges' }); } - if (etag) { - const current = await headS3ObjectEtag('bgp_data/ips.txt').catch(() => undefined); - if (current && current.replace(/\"/g, '"') !== String(etag)) { - return res.status(412).json({ message: 'Precondition Failed: ETag mismatch' }); - } + let current = null; + try { current = await headS3ObjectEtag('bgp_data/ips.txt'); } catch {} + if (current && etag && current !== String(etag)) { + return res.status(412).json({ message: 'Precondition Failed: ETag mismatch', currentEtag: current }); } } catch {} @@ -564,7 +567,7 @@ app.post('/api/ip-ranges', async (req, res) => { if (head.LastModified) res.set('Last-Modified', new Date(head.LastModified).toUTCString()); if (typeof head.ContentLength === 'number') res.set('Content-Length-Source', String(head.ContentLength)); } catch {} - res.send('File updated successfully'); + res.json({ ok: true }); } catch (error) { console.error(error); res.status(500).send('Error writing to S3');