|
|
const express = require('express'); |
|
|
const bodyParser = require('body-parser'); |
|
|
const rateLimit = require('express-rate-limit'); |
|
|
const fs = require('fs'); |
|
|
const path = require('path'); |
|
|
|
|
|
const app = express(); |
|
|
const PORT = process.env.PORT || 3000; |
|
|
const DATA_FILE = path.join(__dirname, '../data/ressentis.json'); |
|
|
const APP_PASSWORD = process.env.APP_PASSWORD || 'parox'; |
|
|
|
|
|
app.use(bodyParser.json()); |
|
|
app.use(express.static(path.join(__dirname, 'public'))); |
|
|
|
|
|
|
|
|
const checkAuth = (req, res, next) => { |
|
|
|
|
|
const token = req.headers['x-auth-token']; |
|
|
if (token === APP_PASSWORD) { |
|
|
next(); |
|
|
} else { |
|
|
res.status(401).json({ error: 'Unauthorized' }); |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
const { Storage } = require('@google-cloud/storage'); |
|
|
const GCS_BUCKET_NAME = process.env.GCS_BUCKET_NAME; |
|
|
|
|
|
|
|
|
if (process.env.GCS_KEY_JSON && !fs.existsSync('/app/gcs-key.json')) { |
|
|
try { |
|
|
console.log("> Writing GCS Key from ENV (GCS_KEY_JSON) to file..."); |
|
|
fs.writeFileSync('/app/gcs-key.json', process.env.GCS_KEY_JSON); |
|
|
process.env.GOOGLE_APPLICATION_CREDENTIALS = '/app/gcs-key.json'; |
|
|
} catch (e) { |
|
|
console.error("! Failed to write GCS Key from ENV:", e); |
|
|
} |
|
|
} |
|
|
|
|
|
let gcsBucket = null; |
|
|
if (GCS_BUCKET_NAME) { |
|
|
try { |
|
|
const storage = new Storage(); |
|
|
gcsBucket = storage.bucket(GCS_BUCKET_NAME); |
|
|
console.log(`> GCS Enabled: Using bucket '${GCS_BUCKET_NAME}'`); |
|
|
} catch (e) { |
|
|
console.error("! GCS config found but failed to init:", e); |
|
|
} |
|
|
} else { |
|
|
console.log("> GCS Disabled: Using local filesystem"); |
|
|
|
|
|
if (!fs.existsSync(DATA_FILE)) { |
|
|
try { |
|
|
fs.mkdirSync(path.dirname(DATA_FILE), { recursive: true }); |
|
|
fs.writeFileSync(DATA_FILE, JSON.stringify([], null, 2)); |
|
|
} catch (e) { console.error("FS Init Error:", e); } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async function readData() { |
|
|
if (gcsBucket) { |
|
|
try { |
|
|
const [contents] = await gcsBucket.file('ressentis.json').download(); |
|
|
return JSON.parse(contents.toString()); |
|
|
} catch (e) { |
|
|
if (e.code === 404) return []; |
|
|
throw e; |
|
|
} |
|
|
} else { |
|
|
if (fs.existsSync(DATA_FILE)) { |
|
|
return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); |
|
|
} |
|
|
return []; |
|
|
} |
|
|
} |
|
|
|
|
|
async function writeData(data) { |
|
|
const jsonStr = JSON.stringify(data, null, 2); |
|
|
if (gcsBucket) { |
|
|
await gcsBucket.file('ressentis.json').save(jsonStr, { |
|
|
contentType: 'application/json', |
|
|
resumable: false |
|
|
}); |
|
|
} else { |
|
|
fs.writeFileSync(DATA_FILE, jsonStr); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const loginLimiter = rateLimit({ |
|
|
windowMs: 15 * 60 * 1000, |
|
|
max: 5, |
|
|
messsage: { error: 'Too many login attempts, please try again after 15 minutes' }, |
|
|
standardHeaders: true, |
|
|
legacyHeaders: false, |
|
|
}); |
|
|
|
|
|
app.post('/api/login', loginLimiter, (req, res) => { |
|
|
const { password } = req.body; |
|
|
if (password === APP_PASSWORD) { |
|
|
res.json({ success: true, token: password }); |
|
|
} else { |
|
|
res.status(401).json({ success: false, error: 'Invalid Password' }); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
app.get('/api/data', checkAuth, async (req, res) => { |
|
|
try { |
|
|
const data = await readData(); |
|
|
res.json(data); |
|
|
} catch (e) { |
|
|
console.error("Read Error:", e); |
|
|
res.status(500).json({ error: 'Failed to read data' }); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
app.post('/api/data', checkAuth, async (req, res) => { |
|
|
const newData = req.body; |
|
|
try { |
|
|
await writeData(newData); |
|
|
res.json({ success: true }); |
|
|
} catch (e) { |
|
|
console.error("Save Error:", e); |
|
|
res.status(500).json({ error: 'Failed to save data' }); |
|
|
} |
|
|
}); |
|
|
|
|
|
app.listen(PORT, () => { |
|
|
console.log(`Server running on http://localhost:${PORT}`); |
|
|
}); |
|
|
|