mirror of
https://github.com/samsonjs/mit-license.git
synced 2026-04-27 15:07:42 +00:00
fix: Properly parse gravatar boolean and switch to standard linter.
Signed-off-by: Richie Bendall <richiebendall@gmail.com>
This commit is contained in:
parent
dfcaa303de
commit
f189d33f29
11 changed files with 201 additions and 188 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
module.exports = (_req, res, next) => {
|
module.exports = (_req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*')
|
||||||
res.header(
|
res.header(
|
||||||
'Access-Control-Allow-Headers',
|
'Access-Control-Allow-Headers',
|
||||||
'Origin, X-Requested-With, Content-Type, Accept'
|
'Origin, X-Requested-With, Content-Type, Accept'
|
||||||
);
|
)
|
||||||
next();
|
next()
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,63 @@
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear()
|
||||||
|
|
||||||
module.exports = (req, res, next) => {
|
module.exports = (req, res, next) => {
|
||||||
const parts = req.url.split('/');
|
const parts = req.url.split('/')
|
||||||
|
|
||||||
res.locals.options = parts.reduce(
|
res.locals.options = parts.reduce(
|
||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
if (!curr) return acc;
|
if (!curr) return acc
|
||||||
|
|
||||||
let match = curr.match(/^@?(\d{4})$/) || [];
|
let match = curr.match(/^@?(\d{4})$/) || []
|
||||||
|
|
||||||
if (match.length) {
|
if (match.length) {
|
||||||
// Pinned year
|
// Pinned year
|
||||||
if (curr.startsWith('@')) {
|
if (curr.startsWith('@')) {
|
||||||
acc.pinnedYear = parseInt(curr.substr(1), 10);
|
acc.pinnedYear = parseInt(curr.substr(1), 10)
|
||||||
} else {
|
} else {
|
||||||
acc.startYear = parseInt(curr, 10);
|
acc.startYear = parseInt(curr, 10)
|
||||||
}
|
}
|
||||||
return acc;
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
match = curr.match(/^(\d{4})-(\d{4})$/) || [];
|
match = curr.match(/^(\d{4})-(\d{4})$/) || []
|
||||||
|
|
||||||
if (match.length) {
|
if (match.length) {
|
||||||
acc.startYear = parseInt(match[1], 10);
|
acc.startYear = parseInt(match[1], 10)
|
||||||
acc.endYear = parseInt(match[2], 10);
|
acc.endYear = parseInt(match[2], 10)
|
||||||
|
|
||||||
return acc;
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr.startsWith('license')) {
|
if (curr.startsWith('license')) {
|
||||||
acc.format = curr
|
acc.format = curr
|
||||||
.split('.')
|
.split('.')
|
||||||
.pop()
|
.pop()
|
||||||
.trim();
|
.trim()
|
||||||
return acc;
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr.startsWith('+')) {
|
if (curr.startsWith('+')) {
|
||||||
acc.license = curr.substr(1).toUpperCase();
|
acc.license = curr.substr(1).toUpperCase()
|
||||||
return acc;
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.sha = curr; // not actually supported now - 2019-06-19
|
acc.sha = curr // not actually supported now - 2019-06-19
|
||||||
return acc;
|
return acc
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
format: 'html',
|
format: 'html',
|
||||||
startYear: null,
|
startYear: null,
|
||||||
endYear: currentYear,
|
endYear: currentYear,
|
||||||
sha: null,
|
sha: null
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.locals.options.sha) {
|
if (res.locals.options.sha) {
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
'X-note',
|
'X-note',
|
||||||
'SHA and commit pinning is no longer supported, showing you latest release'
|
'SHA and commit pinning is no longer supported, showing you latest release'
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next()
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra')
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
|
|
||||||
module.exports = async (req, res, next) => {
|
module.exports = async (req, res, next) => {
|
||||||
const id = req.hostname.split('.')[0];
|
const id = req.hostname.split('.')[0]
|
||||||
res.locals.id = id;
|
res.locals.id = id
|
||||||
|
|
||||||
if (req.method.toUpperCase() !== 'GET') {
|
if (req.method.toUpperCase() !== 'GET') {
|
||||||
return next();
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise load up the user json file
|
// Otherwise load up the user json file
|
||||||
res.locals.user = {
|
res.locals.user = {
|
||||||
copyright: '<copyright holders>',
|
copyright: '<copyright holders>'
|
||||||
};
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await fs.readFile(
|
const data = await fs.readFile(
|
||||||
path.join(__dirname, '..', 'users', `${id}.json`),
|
path.join(__dirname, '..', 'users', `${id}.json`),
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
)
|
||||||
res.locals.user = { ...res.locals.user, ...JSON.parse(data) };
|
res.locals.user = { ...res.locals.user, ...JSON.parse(data) }
|
||||||
} catch ({ code, message }) {
|
} catch ({ code, message }) {
|
||||||
if (code !== 'ENOENT') {
|
if (code !== 'ENOENT') {
|
||||||
res
|
res
|
||||||
.code(500)
|
.code(500)
|
||||||
.send(
|
.send(
|
||||||
`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`
|
`An internal error occurred - open an issue on https://github.com/remy/mit-license with the following information: ${message}`
|
||||||
);
|
)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next()
|
||||||
};
|
}
|
||||||
|
|
|
||||||
14
package.json
14
package.json
|
|
@ -23,7 +23,7 @@
|
||||||
"dev": "nodemon .",
|
"dev": "nodemon .",
|
||||||
"serve": "node server.js",
|
"serve": "node server.js",
|
||||||
"test": "node test.js",
|
"test": "node test.js",
|
||||||
"lint": "eslint server.js middleware/*.js routes/*.js --color"
|
"lint": "standard"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/remy/mit-license/issues"
|
"url": "https://github.com/remy/mit-license/issues"
|
||||||
|
|
@ -41,17 +41,15 @@
|
||||||
"postcss-middleware": "^1.1.4",
|
"postcss-middleware": "^1.1.4",
|
||||||
"postcss-preset-env": "^6.7.0",
|
"postcss-preset-env": "^6.7.0",
|
||||||
"serve-favicon": "^2.5.0",
|
"serve-favicon": "^2.5.0",
|
||||||
"temp-dir": "^2.0.0"
|
"temp-dir": "^2.0.0",
|
||||||
|
"yn": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@remy/eslint": "^3.2.2",
|
|
||||||
"babel-eslint": "^10.0.3",
|
|
||||||
"css": "^2.2.4",
|
"css": "^2.2.4",
|
||||||
"eslint": "^6.8.0",
|
|
||||||
"eslint-plugin-node": "^11.0.0",
|
|
||||||
"has-flag": "^4.0.0",
|
"has-flag": "^4.0.0",
|
||||||
"husky": "^3.1.0",
|
"husky": "^4.0.7",
|
||||||
"nodemon": "^2.0.2"
|
"nodemon": "^2.0.2",
|
||||||
|
"standard": "^14.3.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"postcss-middleware/vinyl-fs/glob-stream/micromatch/braces": "^3.0.2"
|
"postcss-middleware/vinyl-fs/glob-stream/micromatch/braces": "^3.0.2"
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
const md5 = require('md5');
|
const md5 = require('md5')
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const { stripTags, escapeTags, unescapeTags } = require('./utils');
|
const { stripTags, escapeTags, unescapeTags } = require('./utils')
|
||||||
const _ = require('lodash');
|
const _ = require('lodash')
|
||||||
|
|
||||||
function getCopyrightHTML(user, plain) {
|
function getCopyrightHTML (user, plain) {
|
||||||
let html = '';
|
let html = ''
|
||||||
|
|
||||||
const name = _.isString(user)
|
const name = _.isString(user)
|
||||||
? user
|
? user
|
||||||
: plain
|
: plain
|
||||||
? user.name || user.copyright
|
? user.name || user.copyright
|
||||||
: escapeTags(user.name || user.copyright);
|
: escapeTags(user.name || user.copyright)
|
||||||
|
|
||||||
if (user.url) {
|
if (user.url) {
|
||||||
html = `<a href="${stripTags(user.url)}">${name}</a>`;
|
html = `<a href="${stripTags(user.url)}">${name}</a>`
|
||||||
} else {
|
} else {
|
||||||
html = name;
|
html = name
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.email) {
|
if (user.email) {
|
||||||
html += ` <<a href="mailto:${stripTags(user.email)}">${
|
html += ` <<a href="mailto:${stripTags(user.email)}">${
|
||||||
plain ? user.email : escapeTags(user.email)
|
plain ? user.email : escapeTags(user.email)
|
||||||
}</a>>`;
|
}</a>>`
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = (req, res) => {
|
module.exports = (req, res) => {
|
||||||
const { user, options } = res.locals;
|
const { user, options } = res.locals
|
||||||
let name;
|
let name
|
||||||
let gravatar;
|
let gravatar
|
||||||
|
|
||||||
// No error and valid
|
// No error and valid
|
||||||
if (user.copyright) {
|
if (user.copyright) {
|
||||||
if (_.isString(user.copyright)) {
|
if (_.isString(user.copyright)) {
|
||||||
name = getCopyrightHTML(user, options.format !== 'html');
|
name = getCopyrightHTML(user, options.format !== 'html')
|
||||||
} else if (_.isArray(user.copyright) && user.copyright.every(val => _.isString(val))) {
|
} else if (_.isArray(user.copyright) && user.copyright.every(val => _.isString(val))) {
|
||||||
// Supports: ['Remy Sharp', 'Richie Bendall']
|
// Supports: ['Remy Sharp', 'Richie Bendall']
|
||||||
name = user.copyright
|
name = user.copyright
|
||||||
.map(v => (options.format !== 'html' ? v : escapeTags(v)))
|
.map(v => (options.format !== 'html' ? v : escapeTags(v)))
|
||||||
.join(', ');
|
.join(', ')
|
||||||
} else {
|
} else {
|
||||||
name = user.copyright.map(getCopyrightHTML).join(', ');
|
name = user.copyright.map(getCopyrightHTML).join(', ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,47 +50,47 @@ module.exports = (req, res) => {
|
||||||
// Supports regular format
|
// Supports regular format
|
||||||
gravatar = `<img id="gravatar" alt="Profile image" src="https://www.gravatar.com/avatar/${md5(
|
gravatar = `<img id="gravatar" alt="Profile image" src="https://www.gravatar.com/avatar/${md5(
|
||||||
user.email.trim().toLowerCase()
|
user.email.trim().toLowerCase()
|
||||||
)}" />`;
|
)}" />`
|
||||||
} else if (_.isObject(user.copyright[0]) && user.gravatar) {
|
} else if (_.isObject(user.copyright[0]) && user.gravatar) {
|
||||||
// Supports multi-user format
|
// Supports multi-user format
|
||||||
gravatar = `<img id="gravatar" alt="Profile image" src="https://www.gravatar.com/avatar/${md5(
|
gravatar = `<img id="gravatar" alt="Profile image" src="https://www.gravatar.com/avatar/${md5(
|
||||||
user.copyright[0].email.trim().toLowerCase()
|
user.copyright[0].email.trim().toLowerCase()
|
||||||
)}" />`;
|
)}" />`
|
||||||
}
|
}
|
||||||
|
|
||||||
const year = options.pinnedYear
|
const year = options.pinnedYear
|
||||||
? options.pinnedYear
|
? options.pinnedYear
|
||||||
: [options.startYear, options.endYear].filter(Boolean).join('-');
|
: [options.startYear, options.endYear].filter(Boolean).join('-')
|
||||||
const license = (options.license || user.license || 'MIT').toUpperCase();
|
const license = (options.license || user.license || 'MIT').toUpperCase()
|
||||||
const format = options.format || user.format || 'html';
|
const format = options.format || user.format || 'html'
|
||||||
|
|
||||||
const args = {
|
const args = {
|
||||||
info: `${year} ${name}`,
|
info: `${year} ${name}`,
|
||||||
theme: user.theme || 'default',
|
theme: user.theme || 'default',
|
||||||
gravatar,
|
gravatar
|
||||||
};
|
}
|
||||||
|
|
||||||
const filename = path.join(__dirname, '..', 'licenses', license);
|
const filename = path.join(__dirname, '..', 'licenses', license)
|
||||||
req.app.render(filename, args, (error, content) => {
|
req.app.render(filename, args, (error, content) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
res.status(500).send(error);
|
res.status(500).send(error)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === 'txt') {
|
if (format === 'txt') {
|
||||||
const plain = content.match(/<article>(.*)<\/article>/ms)[1];
|
const plain = content.match(/<article>(.*)<\/article>/ms)[1]
|
||||||
|
|
||||||
res
|
res
|
||||||
.set('Content-Type', 'text/plain; charset=UTF-8')
|
.set('Content-Type', 'text/plain; charset=UTF-8')
|
||||||
.send(unescapeTags(stripTags(plain)).trim());
|
.send(unescapeTags(stripTags(plain)).trim())
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format === 'html') {
|
if (format === 'html') {
|
||||||
res.send(content);
|
res.send(content)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ ...user, ...options });
|
res.json({ ...user, ...options })
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,44 @@
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra')
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const btoa = require('btoa');
|
const btoa = require('btoa')
|
||||||
const { version } = require(path.join(__dirname, '..', 'package.json'));
|
const { version } = require(path.join(__dirname, '..', 'package.json'))
|
||||||
const _ = require('lodash');
|
const _ = require('lodash')
|
||||||
const github = require('@octokit/rest')({
|
const github = require('@octokit/rest')({
|
||||||
// GitHub personal access token
|
// GitHub personal access token
|
||||||
auth: process.env.github_token,
|
auth: process.env.github_token,
|
||||||
// User agent with version from package.json
|
// User agent with version from package.json
|
||||||
userAgent: `mit-license v${version}`,
|
userAgent: `mit-license v${version}`
|
||||||
});
|
})
|
||||||
const { validDomainId } = require('./utils');
|
const yn = require('yn')
|
||||||
|
|
||||||
function getUserData({ query, body }) {
|
const { validDomainId } = require('./utils')
|
||||||
|
|
||||||
|
function getUserData ({ query, body }) {
|
||||||
// If query parameters provided
|
// If query parameters provided
|
||||||
if (_.size(query) > 0) return query;
|
if (_.size(query) > 0) return query
|
||||||
// If the data parsed as {'{data: "value"}': ''}
|
// If the data parsed as {'{data: "value"}': ''}
|
||||||
if (_.size(body) === 1 && !_.first(_.values(body))) return JSON.parse(_.first(_.keys(body)));
|
if (_.size(body) === 1 && !_.first(_.values(body))) return JSON.parse(_.first(_.keys(body)))
|
||||||
// Fallback
|
// Fallback
|
||||||
return body;
|
return body
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP POST API
|
// HTTP POST API
|
||||||
module.exports = async (req, res) => {
|
module.exports = async (req, res) => {
|
||||||
const { hostname } = req;
|
const { hostname } = req
|
||||||
// Get different parts of hostname (example: remy.mit-license.org -> ['remy', 'mit-license', 'org'])
|
// Get different parts of hostname (example: remy.mit-license.org -> ['remy', 'mit-license', 'org'])
|
||||||
const params = hostname.split('.');
|
const params = hostname.split('.')
|
||||||
|
|
||||||
// This includes the copyright, year, etc.
|
// This includes the copyright, year, etc.
|
||||||
const userData = getUserData(req);
|
const userData = getUserData(req)
|
||||||
|
|
||||||
// If there isn't enough part of the hostname
|
// If there isn't enough part of the hostname
|
||||||
if (params.length < 2) {
|
if (params.length < 2) {
|
||||||
res.status(400).send('Please specify a subdomain in the URL.');
|
res.status(400).send('Please specify a subdomain in the URL.')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the name from the URL
|
// Extract the name from the URL
|
||||||
const id = _.first(params);
|
const id = _.first(params)
|
||||||
|
|
||||||
if (!validDomainId(id)) {
|
if (!validDomainId(id)) {
|
||||||
// Return a vague error intentionally
|
// Return a vague error intentionally
|
||||||
|
|
@ -44,31 +46,44 @@ module.exports = async (req, res) => {
|
||||||
.status(400)
|
.status(400)
|
||||||
.send(
|
.send(
|
||||||
'User already exists - to update values, please send a pull request on https://github.com/remy/mit-license'
|
'User already exists - to update values, please send a pull request on https://github.com/remy/mit-license'
|
||||||
);
|
)
|
||||||
|
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user file exists in the users directory
|
// Check if the user file exists in the users directory
|
||||||
const exists = await fs.pathExists(path.join(__dirname, '..', 'users', `${id}.json`));
|
const exists = await fs.pathExists(path.join(__dirname, '..', 'users', `${id}.json`))
|
||||||
if (exists) {
|
if (exists) {
|
||||||
res
|
res
|
||||||
.status(409)
|
.status(409)
|
||||||
.send(
|
.send(
|
||||||
'User already exists - to update values, please send a pull request on https://github.com/remy/mit-license'
|
'User already exists - to update values, please send a pull request on https://github.com/remy/mit-license'
|
||||||
);
|
)
|
||||||
return;
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userData.gravatar) {
|
||||||
|
// Parse the string version of a boolean or similar
|
||||||
|
userData.gravatar = yn(userData.gravatar, { lenient: true })
|
||||||
|
if (_.isUndefined(userData.gravatar)) {
|
||||||
|
res
|
||||||
|
.status(400)
|
||||||
|
.send(
|
||||||
|
'The "gravatar" JSON property must be a boolean.'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// File doesn't exist
|
// File doesn't exist
|
||||||
// If copyright property and key doesn't exist
|
// If copyright property and key doesn't exist
|
||||||
if (!userData.copyright) {
|
if (!userData.copyright) {
|
||||||
res.status(400).send('JSON requires "copyright" property and value');
|
res.status(400).send('JSON requires "copyright" property and value')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileContent = JSON.stringify(userData, 0, 2);
|
const fileContent = JSON.stringify(userData, 0, 2)
|
||||||
|
|
||||||
await github.repos.createOrUpdateFile({
|
await github.repos.createOrUpdateFile({
|
||||||
owner: 'remy',
|
owner: 'remy',
|
||||||
|
|
@ -78,18 +93,18 @@ module.exports = async (req, res) => {
|
||||||
content: btoa(fileContent),
|
content: btoa(fileContent),
|
||||||
committer: {
|
committer: {
|
||||||
name: 'MIT License Bot',
|
name: 'MIT License Bot',
|
||||||
email: 'remy@leftlogic.com',
|
email: 'remy@leftlogic.com'
|
||||||
},
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
await fs.writeFile(path.join(__dirname, '..', 'users', `${id}.json`), fileContent);
|
await fs.writeFile(path.join(__dirname, '..', 'users', `${id}.json`), fileContent)
|
||||||
|
|
||||||
res.status(201).send(`MIT license page created: https://${hostname}`);
|
res.status(201).send(`MIT license page created: https://${hostname}`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res
|
res
|
||||||
.status(500)
|
.status(500)
|
||||||
.send(
|
.send(
|
||||||
`Unable to create new user - please send a pull request on https://github.com/remy/mit-license`
|
'Unable to create new user - please send a pull request on https://github.com/remy/mit-license'
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
const _ = require('lodash');
|
const _ = require('lodash')
|
||||||
|
|
||||||
const tags = {
|
const tags = {
|
||||||
'<': '<',
|
'<': '<',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
'&': '&',
|
'&': '&'
|
||||||
};
|
}
|
||||||
const untags = _.invert(tags);
|
const untags = _.invert(tags)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
escapeTags: str => (str || '').replace(/[<>&]/g, m => tags[m]),
|
escapeTags: str => (str || '').replace(/[<>&]/g, m => tags[m]),
|
||||||
unescapeTags: str =>
|
unescapeTags: str =>
|
||||||
(str || '').replace(/(<|>|&)/g, m => untags[m]),
|
(str || '').replace(/(<|>|&)/g, m => untags[m]),
|
||||||
stripTags: str => (str || '').replace(/<(?:.|\n)*?>/gm, ''),
|
stripTags: str => (str || '').replace(/<(?:.|\n)*?>/gm, ''),
|
||||||
validDomainId: str => /^[\w-_]+$/.test(str),
|
validDomainId: str => /^[\w-_]+$/.test(str)
|
||||||
};
|
}
|
||||||
|
|
|
||||||
62
server.js
62
server.js
|
|
@ -5,68 +5,68 @@ IMPORTANT: Set the `github_token` environment variable to a personal access to
|
||||||
Server port: The `PORT` environment variable can also be set to control the port the server
|
Server port: The `PORT` environment variable can also be set to control the port the server
|
||||||
should be hosted on.
|
should be hosted on.
|
||||||
*/
|
*/
|
||||||
const express = require('express');
|
const express = require('express')
|
||||||
const minify = require('express-minify');
|
const minify = require('express-minify')
|
||||||
const favicon = require('serve-favicon');
|
const favicon = require('serve-favicon')
|
||||||
const postcssMiddleware = require('postcss-middleware');
|
const postcssMiddleware = require('postcss-middleware')
|
||||||
const tmpdir = require('temp-dir');
|
const tmpdir = require('temp-dir')
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
|
|
||||||
// Server
|
// Server
|
||||||
var PORT = process.env.PORT || 8080;
|
var PORT = process.env.PORT || 8080
|
||||||
|
|
||||||
// Prepare application
|
// Prepare application
|
||||||
const app = express();
|
const app = express()
|
||||||
app.use(
|
app.use(
|
||||||
minify({
|
minify({
|
||||||
cache: tmpdir,
|
cache: tmpdir
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
app.use(favicon(path.join(__dirname, 'favicon.ico')));
|
app.use(favicon(path.join(__dirname, 'favicon.ico')))
|
||||||
app.set('views', path.join(__dirname, '/licenses'));
|
app.set('views', path.join(__dirname, '/licenses'))
|
||||||
app.set('view engine', 'ejs');
|
app.set('view engine', 'ejs')
|
||||||
|
|
||||||
// Setup static files
|
// Setup static files
|
||||||
app.use('/robots.txt', express.static('robots.txt'));
|
app.use('/robots.txt', express.static('robots.txt'))
|
||||||
app.use('/favicon.ico', express.static(`${__dirname}/favicon.ico`));
|
app.use('/favicon.ico', express.static(`${__dirname}/favicon.ico`))
|
||||||
app.use(
|
app.use(
|
||||||
'/themes',
|
'/themes',
|
||||||
postcssMiddleware({
|
postcssMiddleware({
|
||||||
plugins: [
|
plugins: [
|
||||||
require('postcss-preset-env')({
|
require('postcss-preset-env')({
|
||||||
overrideBrowserslist: '>= 0%',
|
overrideBrowserslist: '>= 0%',
|
||||||
stage: 0,
|
stage: 0
|
||||||
}),
|
})
|
||||||
],
|
],
|
||||||
src(req) {
|
src (req) {
|
||||||
return path.join(__dirname, 'themes', req.path);
|
return path.join(__dirname, 'themes', req.path)
|
||||||
},
|
}
|
||||||
}),
|
}),
|
||||||
express.static('themes')
|
express.static('themes')
|
||||||
);
|
)
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
|
|
||||||
// CORS
|
// CORS
|
||||||
app.use(require('./middleware/cors'));
|
app.use(require('./middleware/cors'))
|
||||||
// Parse URL-encoded bodies (as sent by HTML forms)
|
// Parse URL-encoded bodies (as sent by HTML forms)
|
||||||
app.use(
|
app.use(
|
||||||
express.urlencoded({
|
express.urlencoded({
|
||||||
extended: true,
|
extended: true
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
// Parse JSON bodies (as sent by API clients)
|
// Parse JSON bodies (as sent by API clients)
|
||||||
app.use(express.json());
|
app.use(express.json())
|
||||||
|
|
||||||
// Capture the id from the subdomain
|
// Capture the id from the subdomain
|
||||||
app.use(require('./middleware/load-user'));
|
app.use(require('./middleware/load-user'))
|
||||||
app.use(require('./middleware/load-options'));
|
app.use(require('./middleware/load-options'))
|
||||||
|
|
||||||
// HTTP POST API
|
// HTTP POST API
|
||||||
app.post('/', require('./routes/post'));
|
app.post('/', require('./routes/post'))
|
||||||
app.get('/*', require('./routes/get'));
|
app.get('/*', require('./routes/get'))
|
||||||
|
|
||||||
// Start listening for HTTP requests
|
// Start listening for HTTP requests
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 on http://localhost:${PORT}`);
|
console.log(`🚀 on http://localhost:${PORT}`)
|
||||||
});
|
})
|
||||||
|
|
|
||||||
66
test.js
66
test.js
|
|
@ -1,68 +1,68 @@
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra')
|
||||||
const CSS = require('css');
|
const CSS = require('css')
|
||||||
const { validDomainId } = require('./routes/utils');
|
const { validDomainId } = require('./routes/utils')
|
||||||
const hasFlag = require('has-flag');
|
const hasFlag = require('has-flag')
|
||||||
|
|
||||||
function report(content, fix) {
|
function report (content, fix) {
|
||||||
console.error(content);
|
console.error(content)
|
||||||
if (fix && hasFlag('--fix')) fix();
|
if (fix && hasFlag('--fix')) fix()
|
||||||
process.exitCode = 1;
|
process.exitCode = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const users = await fs.readdir('users');
|
const users = await fs.readdir('users')
|
||||||
users.forEach(async user => {
|
users.forEach(async user => {
|
||||||
if (!user.endsWith('json')) {
|
if (!user.endsWith('json')) {
|
||||||
report(`${user} is not a json file`, () =>
|
report(`${user} is not a json file`, () =>
|
||||||
fs.unlink(path.join('users', user), () => { })
|
fs.unlink(path.join('users', user), () => { })
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
if (!validDomainId(user.replace('.json', ''))) {
|
if (!validDomainId(user.replace('.json', ''))) {
|
||||||
report(`${user} is not a valid domain id.`);
|
report(`${user} is not a valid domain id.`)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const data = await fs.readFile(path.join('users', user), 'utf8');
|
const data = await fs.readFile(path.join('users', user), 'utf8')
|
||||||
try {
|
try {
|
||||||
const u = JSON.parse(data);
|
const u = JSON.parse(data)
|
||||||
if (!u.locked && !u.copyright) {
|
if (!u.locked && !u.copyright) {
|
||||||
report(`Copyright not specified in ${user}`);
|
report(`Copyright not specified in ${user}`)
|
||||||
}
|
}
|
||||||
if (u.version) {
|
if (u.version) {
|
||||||
report(`Version tag found in ${user}`, () => {
|
report(`Version tag found in ${user}`, () => {
|
||||||
delete u.version;
|
delete u.version
|
||||||
const stringified = `${JSON.stringify(u, 0, 2)}\n`;
|
const stringified = `${JSON.stringify(u, 0, 2)}\n`
|
||||||
fs.writeFile(path.join('users', user), stringified, () => { });
|
fs.writeFile(path.join('users', user), stringified, () => { })
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
if (typeof u.gravatar === 'string') {
|
if (typeof u.gravatar === 'string') {
|
||||||
report(`Gravatar boolean encoded as string found in ${user}`, () => {
|
report(`Gravatar boolean encoded as string found in ${user}`, () => {
|
||||||
u.gravatar = u.gravatar === 'true';
|
u.gravatar = u.gravatar === 'true'
|
||||||
const stringified = `${JSON.stringify(u, 0, 2)}\n`;
|
const stringified = `${JSON.stringify(u, 0, 2)}\n`
|
||||||
fs.writeFile(path.join('users', user), stringified, () => { });
|
fs.writeFile(path.join('users', user), stringified, () => { })
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
} catch ({ message }) {
|
} catch ({ message }) {
|
||||||
report(`Invalid JSON in ${user} (${message})`);
|
report(`Invalid JSON in ${user} (${message})`)
|
||||||
}
|
}
|
||||||
} catch ({ message }) {
|
} catch ({ message }) {
|
||||||
report(`Unable to read ${user} (${message})`);
|
report(`Unable to read ${user} (${message})`)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
const themes = await fs.readdir('themes');
|
const themes = await fs.readdir('themes')
|
||||||
await themes.forEach(async theme => {
|
await themes.forEach(async theme => {
|
||||||
if (theme.endsWith('css')) {
|
if (theme.endsWith('css')) {
|
||||||
try {
|
try {
|
||||||
const data = await fs.readFile(path.join('themes', theme), 'utf8');
|
const data = await fs.readFile(path.join('themes', theme), 'utf8')
|
||||||
try {
|
try {
|
||||||
CSS.parse(data);
|
CSS.parse(data)
|
||||||
} catch ({ message }) {
|
} catch ({ message }) {
|
||||||
report(`Invalid CSS in ${theme} (${message})`);
|
report(`Invalid CSS in ${theme} (${message})`)
|
||||||
}
|
}
|
||||||
} catch ({ message }) {
|
} catch ({ message }) {
|
||||||
report(`Unable to read ${theme} (${message})`);
|
report(`Unable to read ${theme} (${message})`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
})();
|
})()
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@
|
||||||
"format": "text",
|
"format": "text",
|
||||||
"license": "mit",
|
"license": "mit",
|
||||||
"theme": "default",
|
"theme": "default",
|
||||||
"gravatar": "false"
|
"gravatar": false
|
||||||
}
|
}
|
||||||
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue