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 parse JSON payloads app.use(bodyParser.json()); // Custom middleware to handle URLs without .html for specific routes app.use((req, res, next) => { // Extract the path without any query parameters const urlPath = req.path.split('?')[0]; // Define routes that should render HTML files without .html extension const htmlRoutes = ['/about', '/list', '/gallery']; // Check if the requested path is in the htmlRoutes array if (htmlRoutes.includes(urlPath)) { // Append .html to the path and continue req.url += '.html'; } // Continue to the next middleware 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) => { console.log(req) const signature = req.headers['x-gitea-signature']; const payload = JSON.stringify(req.body); 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 = `sha256=${hmac.update(payload).digest('hex')}`; // Ensure both buffers have the same length before comparing const bufferSignature = Buffer.from(signature); const bufferDigest = Buffer.from(digest); console.log(bufferDigest.length, bufferSignature.length) if (bufferSignature.length === bufferDigest.length && crypto.timingSafeEqual(bufferSignature, bufferDigest)) { // Secret is valid, update the repository res.status(200).send('Repository updated successfully'); } 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}`); });