import express = require('express') import * as path from 'path' import * as fs from 'fs' const PORT = process.env.PORT || 80 import compression = require('compression') import md5 = require('md5'); import humanizeList from 'humanize-list' import minify = require('express-minify') import ejs = require('ejs') import { yearNow, stripTags, trimArray } from './util' import HTML = require('node-html-parser') import postcssMiddleware = require('postcss-middleware') import btoa = require('btoa') const github = require("@octokit/rest")({ // GitHub personal access token auth: process.env.github_token, // User agent with version from package.json userAgent: `mit-license v${require('./package.json').version}`, }) // Prepare application const app = express() app.use(compression()) app.use(minify({ cache: require('tmp').dirSync().name, })) app.set('view engine', 'ejs') // Setup static files app.use('/users', express.static('users')) app.use('/themes', postcssMiddleware({ plugins: [require('postcss-preset-env')({ browsers: '>= 0%', stage: 0 })], src: req => path.join(__dirname, 'themes', req.path) })) app.use('/themes', express.static('themes')) app.use('/favicon.ico', express.static(__dirname + '/favicon.ico')) // Allow CORS app.use((_req, res, next) => { res.header('Access-Control-Allow-Origin', '*') res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept') next() }) // Parse URL-encoded bodies (as sent by HTML forms) // app.use(express.urlencoded({ extended: true })) // // Parse JSON bodies (as sent by API clients) app.use(express.json()) // HTTP POST API app.post('/', (req, res) => { // Get differnet parts of hostname (example: remy.mit-license.org -> ['remy', 'mit-license', 'org']) const params = req.hostname.split(".") console.log(req.body) // If there isn't enough part of the hostname if (params.length < 2) res.status(400).send("Please specify a subdomain in the URL.") res.json(req.body) return github.repos.createFile({ owner: "remy", repo: "mit-license", path: `users/${params[0]}.json`, message: `Automated creation of user ${params[0]}.`, content: btoa() }) }) // Any other HTTP GET request app.get('*', (req, res) => { // Get user id (example: 'rem.mit-license.org/@2019' -> 'rem') const id = req.hostname.split('.')[0] // Get params (example: 'rem.mit-license.org/@2019' -> ['@2019']) const params = req.path.split('/') params.shift() // Load the user data (example: from 'rem.mit-license.org/@2019' -> 'users/rem.json') fs.readFile(path.join('users', `${id}.json`), 'utf8', (err, data: string) => { let name: string; let theme: string; let gravatar: string const user = JSON.parse(data || '{}') // If error opening if (err) { if (err.code === 'ENOENT') { // File not found name = '' theme = 'default' gravatar = '' } else { // Other error res.status(500).end() return } } else { // No error name = typeof user.copyright === 'string' ? user.copyright : humanizeList(user.copyright) theme = user.theme || 'default' gravatar = user.gravatar ? `Profile image` : '' } const year = (() => { // rem.mit-license.org/@2019 const customYear = params.find((val) => val.startsWith('@')) // rem.mit-license.org/2019 const fromYear = params.find((val) => !isNaN(parseInt(val.replace('-', '')))) // If current year if (customYear) return customYear.replace(/[@-]/g, '') // If from year if (fromYear) { // If from year is same as current if (parseInt(fromYear) === yearNow) return yearNow return `${fromYear.replace('-', '')}-${yearNow.toString().replace('-', '')}` } return yearNow })() const customLicense = params.find((val) => val.startsWith('+')) const license = customLicense ? customLicense.replace('+', '') : user.license || 'MIT' const format = params.find((val) => val === 'license.html') ? 'html' : params.find((val) => val === 'license.txt') ? 'txt' : user.format || 'html' const args = { info: `${year} ${name}`, theme, gravatar, } if (format === 'html') res.render(path.join(__dirname, 'licenses', license), args) else { ejs.renderFile(path.join(__dirname, 'licenses', `${license}.ejs`), args, (_err: any, str: string) => res .set('Content-Type', 'text/plain; charset=UTF-8') .send( trimArray( stripTags(HTML.parse(str).childNodes[0].childNodes[3].childNodes[1].toString()) .split('\n') .map((val: string) => val.trim()) ) .join('\n') ) ) } }) }) // Start listening for HTTP requests app.listen(PORT)