diff --git a/middleware/load-user.js b/middleware/load-user.js index a56f6e28..182567a7 100644 --- a/middleware/load-user.js +++ b/middleware/load-user.js @@ -10,17 +10,21 @@ module.exports = async (req, res, next) => { return next(); } - // otherwise load up the user json file + // Otherwise load up the user json file res.locals.user = { copyright: '', }; - readFile( - path.join(__dirname, '..', 'users', `${id}.json`), - 'utf8' - ) - .then(data => res.locals.user = JSON.parse(data)) - .catch(({code, message}) => { - if (code !== 'ENOENT') res.code(500).send(`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`) - }) - .finally(() => next()) + + try { + const data = await readFile( + path.join(__dirname, '..', 'users', `${id}.json`), + 'utf8' + ); + res.locals.user = JSON.parse(data); + } catch ({code, message}) { + res.code(500).send(`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`) + return; + } + + next(); }; diff --git a/routes/post.js b/routes/post.js index 4624e321..fc0cdf53 100644 --- a/routes/post.js +++ b/routes/post.js @@ -12,6 +12,7 @@ var github = require('@octokit/rest')({ // User agent with version from package.json userAgent: 'mit-license v' + require(path.join(__dirname, "..", "package.json")).version, }); +const { validDomainId } = require('./utils'); function getUserData({ query, @@ -26,8 +27,6 @@ function getUserData({ return body; } -const validDomain = s => /^[\w-_]+$/.test(s); - // HTTP POST API module.exports = async (req, res) => { const { @@ -48,7 +47,7 @@ module.exports = async (req, res) => { // Extract the name from the URL const id = params[0]; - if (!validDomain(id)) { + if (!validDomainId(id)) { // Return a vague error intentionally res .status(400) @@ -59,47 +58,53 @@ module.exports = async (req, res) => { return; } - // Check if the user file exists in the users directory - access(path.join(__dirname, '..', 'users', `${id}.json`)) - .then(() => { - res + try { + // Check if the user file exists in the users directory + await access(path.join(__dirname, '..', 'users', `${id}.json`)); + res .status(409) .send( 'User already exists - to update values, please send a pull request on https://github.com/remy/mit-license' ) + return; + } catch ({code, message}) { + if (code !== "ENOENT") { + res.code(500).send(`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`) + return; + } + } + + // File doesn't exist + // If copyright property and key doesn't exist + if (!userData.copyright) { + res.status(400).send('JSON requires "copyright" property and value'); + return; + } + + try { + const fileContent = JSON.stringify(userData, 0, 2) + + await github.repos.createFile({ + owner: 'remy', + repo: 'mit-license', + path: `users/${id}.json`, + message: `Automated creation of user ${id}.`, + content: btoa(fileContent), + committer: { + name: 'MIT License Bot', + email: 'remy@leftlogic.com', + }, }) - .catch(({code, message}) => { - if (code !== 'ENOENT') { - res.code(500).send(`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`) - return; - } - // File doesn't exist - // If copyright property and key doesn't exist - if (!userData.copyright) { - res.status(400).send('JSON requires "copyright" property and value'); - return; - } + writeFile( + path.join(__dirname, "..", "users", `${id}.json`), + fileContent + ); - const fileContent = JSON.stringify(userData, 0, 2) + res.status(201).send(`MIT license page created: https://${hostname}`); + } catch(err) { + res.status(500).send(`Unable to create new user - please send a pull request on https://github.com/remy/mit-license`) + } - github.repos.createFile({ - owner: 'remy', - repo: 'mit-license', - path: `users/${id}.json`, - message: `Automated creation of user ${id}.`, - content: btoa(fileContent), - committer: { - name: 'MIT License Bot', - email: 'remy@leftlogic.com', - }, - }) - .then(() => writeFile( - path.join(__dirname, "..", "users", `${id}.json`), - fileContent - ) - .then(() => res.status(201).send(`MIT license page created: https://${hostname}`)) - .catch(() => res.status(500).send('Unable to create new user - please send a pull request on https://github.com/remy/mit-license')) - ) - }) + next(); }; diff --git a/routes/utils.js b/routes/utils.js index 9a0ae698..3e78ed8b 100644 --- a/routes/utils.js +++ b/routes/utils.js @@ -5,3 +5,4 @@ const tags = { }; exports.escapeTags = str => (str || '').replace(/[<>&]/g, m => tags[m]); exports.stripTags = str => (str || '').replace(/<(?:.|\n)*?>/gm, ''); +exports.validDomainId = s => /^[\w-_]+$/.test(s); diff --git a/test.js b/test.js index 66ab0151..957dbd5c 100644 --- a/test.js +++ b/test.js @@ -1,58 +1,66 @@ const path = require('path'); const fs = require('fs'); const CSS = require('css'); +const { + validDomainId +} = require('./routes/utils'); +const { + promisify +} = require('util'); +const readFile = promisify(fs.readFile); +const readdir = promisify(fs.readdir); +const hasFlag = require('has-flag') + let errored = false; -const users = fs.readdirSync('users'); -users.forEach(async user => { - if (user.endsWith('json')) { - if (encodeURIComponent(user) === user) { - fs.readFile(path.join('users', user), 'utf8', async (err, content) => { - if (err) { - errored = true; - console.error(`Unable to read ${user}`); - } else { - try { - const u = JSON.parse(content); - if (!u.locked && !u.copyright) { - errored = true; - console.error(`Copyright not specified in ${user} (${e})`); - } - } catch (e) { - errored = true; - console.error(`Invalid JSON in ${user} (${e})`); - } - } - }); - } else { - errored = true; - console.error(`${user} is not URL safe`); - } - } else { - errored = true; - console.error(`${user} is not a json file`); - } -}); +function report(content, fix) { + errored = true; + console.error(content); + if (fix && hasFlag("--fix")) fix() +} -const themes = fs.readdirSync('themes'); -themes.forEach(async theme => { - if (theme.endsWith('css')) { - fs.readFile(path.join('themes', theme), 'utf8', async (err, content) => { - if (err) { - errored = true; - console.error(`Unable to read ${theme}`); - } else { - try { - CSS.parse(content); - } catch (e) { - errored = true; - console.error(`Invalid CSS in ${theme} (${e})`); - } +(async () => { + const users = await readdir('users'); + await users.forEach(async user => { + if (!user.endsWith('json')) report(`${user} is not a json file`, () => fs.unlink(path.join('users', user), () => {})) + if (!validDomainId(user.replace(".json", ""))) report(`${user} is not a valid domain id.`) + try { + const data = await readFile(path.join('users', user), "utf8") + try { + const u = JSON.parse(data); + if (!u.locked && !u.copyright) report(`Copyright not specified in ${user}`) + const stringified = JSON.stringify(u, 0, 2) + if (data !== stringified) report(`Non-regular formatting in ${user}`, () => fs.writeFile(path.join('users', user), stringified, () => {})) + } catch ({ + message + }) { + report(`Invalid JSON in ${user} (${message})`) } - }); - } -}); + } catch ({ + message + }) { + report(`Unable to read ${user} (${message})`) + } + }); -setTimeout(() => { + const themes = await readdir('themes'); + await themes.forEach(async theme => { + if (theme.endsWith('css')) { + try { + const data = await readFile(path.join('themes', theme), "utf8") + try { + CSS.parse(data); + } catch ({ + message + }) { + report(`Invalid CSS in ${theme} (${message})`) + } + } catch ({ + message + }) { + report(`Unable to read ${theme} (${message})`) + } + } + }); if (errored) process.exit(1); -}, 500); +})() diff --git a/yarn.lock b/yarn.lock index 4eae0594..7527ce61 100644 Binary files a/yarn.lock and b/yarn.lock differ