|
| 1 | +import fs from 'fs'; |
| 2 | +import path from 'path'; |
| 3 | +import crypto from 'crypto'; |
| 4 | +import fetchRepoDetails from '../utils/fetchRepoDetails.js'; |
| 5 | +import dotenv from 'dotenv'; |
| 6 | + |
| 7 | +dotenv.config(); |
| 8 | + |
| 9 | +const JSON_FILE = path.join(process.cwd(), 'data/community_projects.json'); |
| 10 | +const LATEST_PROJECT_FILE = path.join(process.cwd(), 'data/latest_project.txt'); |
| 11 | +const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; |
| 12 | + |
| 13 | +// Ensure JSON file exists |
| 14 | +const ensureFileExists = () => { |
| 15 | + if (!fs.existsSync(JSON_FILE)) fs.writeFileSync(JSON_FILE, '[]'); |
| 16 | + if (!fs.existsSync(LATEST_PROJECT_FILE)) fs.writeFileSync(LATEST_PROJECT_FILE, ''); |
| 17 | +}; |
| 18 | + |
| 19 | +// Load existing projects |
| 20 | +const loadProjects = () => { |
| 21 | + ensureFileExists(); |
| 22 | + return JSON.parse(fs.readFileSync(JSON_FILE, 'utf8')); |
| 23 | +}; |
| 24 | + |
| 25 | +// Save projects |
| 26 | +const saveProjects = (projects, latestProject) => { |
| 27 | + ensureFileExists(); |
| 28 | + fs.writeFileSync(JSON_FILE, JSON.stringify(projects, null, 2)); |
| 29 | + fs.writeFileSync(LATEST_PROJECT_FILE, latestProject); |
| 30 | +}; |
| 31 | + |
| 32 | +// Verify GitHub Webhook Signature |
| 33 | +const verifySignature = (req) => { |
| 34 | + const signature = req.headers['x-hub-signature-256']; |
| 35 | + if (!signature) return false; |
| 36 | + |
| 37 | + const payload = JSON.stringify(req.body); |
| 38 | + const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET); |
| 39 | + hmac.update(payload); |
| 40 | + const calculatedSignature = `sha256=${hmac.digest('hex')}`; |
| 41 | + |
| 42 | + return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(calculatedSignature)); |
| 43 | +}; |
| 44 | + |
| 45 | +// Handle Webhook |
| 46 | +export const handleWebhook = async (req, res) => { |
| 47 | + if (!verifySignature(req)) { |
| 48 | + return res.status(401).json({ error: 'Invalid signature' }); |
| 49 | + } |
| 50 | + |
| 51 | + const event = req.headers['x-github-event']; |
| 52 | + const payload = req.body; |
| 53 | + |
| 54 | + if (event === 'repository' || event === 'push') { |
| 55 | + const { name, owner, html_url, description, topics } = payload.repository; |
| 56 | + |
| 57 | + if ((description && description.toLowerCase().includes('soplang')) || |
| 58 | + (topics && topics.includes('soplang'))) { |
| 59 | + |
| 60 | + let projects = loadProjects(); |
| 61 | + if (!projects.some(p => p.url === html_url)) { |
| 62 | + const repoDetails = await fetchRepoDetails(owner.login, name); |
| 63 | + if (repoDetails) { |
| 64 | + projects.push(repoDetails); |
| 65 | + saveProjects(projects, name); |
| 66 | + } |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + res.status(200).json({ message: 'Webhook received' }); |
| 72 | +}; |
0 commit comments