const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const crypto = require('crypto'); const { exec } = require('child_process'); require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 3000; const GITEA_SECRET = process.env.GITEA_SECRET // Serve static files from the 'public' directory app.use(express.static(path.join(__dirname, 'public'))); // Middleware to capture raw body app.use(bodyParser.json({ verify: (req, res, buf, encoding) => { req.rawBody = buf.toString(encoding || 'utf8'); } })); // Custom middleware to handle URLs without .html for specific routes app.use((req, res, next) => { const urlPath = req.path.split('?')[0]; const htmlRoutes = ['/about', '/list', '/gallery']; if (htmlRoutes.includes(urlPath)) { req.url += '.html'; } next(); }); // Route to serve the index.html file app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // Routes to serve the HTML files without .html extension app.get('/about.html', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'about.html')); }); app.get('/list.html', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'list.html')); }); app.get('/gallery.html', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'gallery.html')); }); // Serve articles without .html extension app.get('/articles/:articleName', (req, res) => { const articleName = req.params.articleName; res.sendFile(path.join(__dirname, 'public/articles', `${articleName}.html`)); }); // Webhook handler app.post('/api', (req, res) => { const signature = req.headers['x-gitea-signature']; const payload = req.rawBody; if (!signature || !payload) { return res.status(400).send('Invalid payload or missing signature'); } // Verify the secret const hmac = crypto.createHmac('sha256', GITEA_SECRET); const digest = hmac.update(payload).digest('hex'); const bufferSignature = Buffer.from(signature, 'hex'); const bufferDigest = Buffer.from(digest, 'hex'); if (bufferSignature.length === bufferDigest.length && crypto.timingSafeEqual(bufferSignature, bufferDigest)) { // Secret is valid, update the repository res.status(200).send('Repository updated successfully'); // Optionally, execute a shell command to pull the latest changes exec('git pull', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); } else { res.status(401).send('Invalid secret'); } }); // Error handling app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!'); }); // Start the server app.listen(PORT, (err) => { if (err) { console.error('Error starting the server:', err); process.exit(1); } console.log(`Server is running on http://localhost:${PORT}`); });