'use strict'; const express = require('express'); const next = require('next'); const fs = require('fs'); const path = require('path'); const sqlite3 = require('sqlite3').verbose(); const nodeGit = require('nodegit'); const repositoryDirectory = './user-content-access/'; const dbFile = './gitcub.db'; const dev = process.env.NODE_ENV !== 'production'; const port = 3000; const app = next({ dev }); const handle = app.getRequestHandler(); const directoryExists = (path) => fs.existsSync(path) ? fs.statSync(path).isDirectory() : false; const repositoryExists = (name, rows) => ( directoryExists(repositoryDirectory + name + '.git') && rows.some((x) => x.name === name) ); const sendResult = (res, resultType, resultPath, resultContent = '') => { const result = { resultType: resultType, resultPath: resultPath, resultContent: resultContent, }; res.json(result); }; const sendError = (res, message) => { sendResult(res, 'error', [], message); }; const sendDirectoryPathResult = (res, pathArray, tree) => { const recursion = (depth, tree) => { if (pathArray.length > depth) { const entries = tree.entries(); const isMatchingTree = (x) => x.name() === pathArray[depth] && x.isTree(); const isMatchingBlob = (x) => x.name() === pathArray[depth] && x.isBlob(); if (entries.some(isMatchingTree)) { entries.find(isMatchingTree).getTree().then((tree) => { const newDepth = depth + 1; recursion(newDepth, tree); }); } else if (pathArray.length === depth + 1) { if (entries.some(isMatchingBlob)) { entries.find(isMatchingBlob).getBlob().then((blob) => { if (blob.isBinary()) { sendResult(res, 'binaryBlob', pathArray); } else { const text = blob.toString(); sendResult(res, 'textBlob', pathArray, text); } }); } else { sendError(res, 'File or directory does not exist.'); } } else { sendError(res, 'File or directory does not exist.'); } } else { const entryNamesSorted = { trees: tree.entries().filter((entry) => entry.isTree()).map((entry) => entry.name()), blobs: tree.entries().filter((entry) => entry.isBlob()).map((entry) => entry.name()), }; sendResult(res, 'treeContents', pathArray, entryNamesSorted); } }; recursion(2, tree); }; const sendRootResult = (res, pathArray, tree) => { const entryNamesSorted = { trees: tree.entries().filter((entry) => entry.isTree()).map((entry) => entry.name()), blobs: tree.entries().filter((entry) => entry.isBlob()).map((entry) => entry.name()), }; sendResult(res, 'treeContents', pathArray, entryNamesSorted); } const sendRepositoryResult = (res, pathArray, repo) => { if (pathArray.length > 1) { if (pathArray[1] === 'master') { repo.getMasterCommit() .then((commit) => commit.getTree()) .then((tree) => { sendDirectoryPathResult(res, pathArray, tree); }); } else { sendError(res, 'Commit does not exist.'); } } else { repo.getMasterCommit() .then((commit) => commit.getTree()) .then((tree) => { sendRootResult(res, pathArray, tree); }); } } const sendAPIResult = (req, res, rows) => { if (req.originalUrl.indexOf('\0') === -1) { const pathNormalized = path.normalize(req.path); const pathArray = pathNormalized.split('/').filter((x) => x.length > 0); // remove 'api' pathArray.shift(); if (pathArray.length > 0) { if (repositoryExists(pathArray[0], rows)) { const pathToRepo = repositoryDirectory + pathArray[0] + '.git'; nodeGit.Repository.openBare(pathToRepo) .then((repo) => { sendRepositoryResult(res, pathArray, repo); }); } else { sendError(res, 'Repository does not exist.'); } } else { sendError(res, 'Repository not specified.'); } } else { sendError(res, 'Null byte found in url. Nice try :)'); } }; app.prepare() .then(() => { const server = express(); const db = new sqlite3.Database(dbFile, sqlite3.OPEN_READWRITE); server.get('/api/*', (req, res) => { db.all('select name from repositories', (err, rows) => { sendAPIResult(req, res, rows); }); }); server.get('*', (req, res) => { return handle(req, res); }); server.listen(port, () => { console.log(`Example app listening on port ${port}`); }); }) .catch((ex) => { console.error(ex.stack); process.exit(1); });