From 0b0afb9a83d8ed4e9c92d8b3959d686b59b35781 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sat, 1 Jun 2019 20:36:28 +1200 Subject: [PATCH] Complete API --- .eslintrc.json | 3 +- README.md | 13 +++- index.php | 165 ------------------------------------------------- package.json | 1 + server.ts | 90 +++++++++++++++++++++------ util.ts | 20 ------ yarn.lock | Bin 145003 -> 145026 bytes 7 files changed, 85 insertions(+), 207 deletions(-) delete mode 100644 index.php delete mode 100644 util.ts diff --git a/.eslintrc.json b/.eslintrc.json index e034281e..a96e3840 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,7 +13,8 @@ }, "parserOptions": { "ecmaVersion": 2018, - "sourceType": "module" + "sourceType": "module", + "warnOnUnsupportedTypeScriptVersion": false }, "rules": { "indent": ["error", 4], diff --git a/README.md b/README.md index f0b92908..f3bae505 100644 --- a/README.md +++ b/README.md @@ -192,15 +192,22 @@ The following types of requests can be made to this project: - HTML - Text -The url also supports including a start year: +The URL also supports including a start year: - will show a license year range of 2009-2016 (2016 being the current year) -- [http://rem.mit-license.org/2009-2010](http://rem.mit-license.org/2009-2010/) +- allows me to force the year range - year range of 2009-2010 in plain text -Finally, the url also supports pinning the year +You can also specify either the `MIT` or `ISC` license in the URL: + +- will + show the MIT License (default) +- + shows the ISC license instead + +Finally, the URL also supports pinning the year - this is useful for when your software copyright should expire ([as discussed here](https://github.com/remy/mit-license/issues/771)) diff --git a/index.php b/index.php deleted file mode 100644 index 5d8968eb..00000000 --- a/index.php +++ /dev/null @@ -1,165 +0,0 @@ ->> curl API has been temporarily disabled. Please send a pull request in the short term. Service will resume as normal again soon ❤'); - exit; - - try { - $data = json_decode(file_get_contents('php://input')); - if (!property_exists($data, 'copyright')) { - Throw new Exception('>>> JSON requires "copyright" property and value'); - } - - if (file_exists($user_file)) { - Throw new Exception(wordwrap('>>> User already exists - to update values, please send a pull request on https://github.com/remy/mit-license')); - } - - if (!file_put_contents($user_file, json_encode($data))) { - Throw new Exception(wordwrap('>>> Unable to create new user - please send a pull request on https://github.com/remy/mit-license')); - } - - // try to add to github...! - exec('cd /WWW/mit-license && /usr/bin/git add ' . $user_file . ' && /usr/bin/git commit -m"automated creation of ' . $user_file . '"', $out, $r); - //print_r($out); echo "\n"; print_r($r); echo "\n"; - $out = array(); - exec('cd /WWW/mit-license && /usr/bin/git push origin master -v 2>&1', $out, $r); - //print_r($out); echo "\n"; print_r($r); echo "\n"; - - echo '>>> MIT license page created: https://' . $_SERVER['HTTP_HOST'] . "\n\n"; - } - catch (Exception $e) { - echo $e->getMessage() . "\n\n"; - } - exit; -} - -/** - * Load up the user.json file and read properties in - **/ -if ($cname && file_exists($user_file)) { - $user = json_decode(file_get_contents($user_file)); - $holder = htmlentities($user->copyright, ENT_COMPAT | ENT_HTML401, 'UTF-8'); - if (property_exists($user, 'url')) { - $holder = '' . $holder . ''; - } - - if (property_exists($user, 'email')) { - $holder = $holder . ' <' . $user->email . '>'; - - if (property_exists($user, 'gravatar') && $user->gravatar === true) { - $gravatar = ''; - } - - } - - if (property_exists($user, 'format')) { - if (strtolower($user->format) == 'txt') { - $format = 'txt'; - } - } - - if (property_exists($user, 'theme')) { - if (file_exists('themes/' . $user->theme . '.css')) { - $theme = $user->theme; - } - } -} else { - $holder = "<copyright holders>"; -} - -/** - * Now process the request url. Optional parts of the url are (in order): - * [sha]/[year|year-range]/license.[format] - * eg. http://rem.mit-license.org/a526bf7ad1/2009-2010/license.txt - **/ - -// grab sha from request uri -$request_uri = explode('/', $_SERVER["REQUEST_URI"]); - -$request = array_pop($request_uri); -// in case there's a trailing slash (unlikely) -if ($request == '') - $request = array_pop($request_uri); - -// url file format overrides user preference -if (stripos($request, 'license') === 0) { - $format = array_pop(explode('.', strtolower($request))) == 'txt' ? 'txt' : 'html'; - - // move down to the next part of the request - $request = array_pop($request_uri); -} - -// check if we have a year or a year range up front -$year = date('Y'); -preg_match('/^(@?\d{4})(?:(?:\-)(\d{4}))?$/', $request, $match); - -if (count($match) > 1) { - if ($match[2] && $match[1][0] != '@') { // 2nd segment - $year = $match[2]; - } - if ($match[1]) { - if ($match[1][0] == '@') { - $year = substr($match[1], 1); - } else { - $year = $match[1] == $year ? $year : $match[1] . '-' . $year; - } - } - $request = array_pop($request_uri); -} - -// check if there's a SHA on the url and read this to switch license versions -$sha = ''; -if ($request != "" && $request != "/" && $request != "/index.php") { - $sha = preg_replace('/[^a-f0-9]/', '', $request); -} else if (isset($user) && property_exists($user, 'version')) { - $sha = preg_replace('/[^a-f0-9]/', '', $user->version); -} - -// if sha specified, use that revision of licence -$license = ''; -if ($sha != "") { - $out = array(); - // preg_replace should save us - but: please help me Obi Wan... - exec("/usr/local/bin/git show " . $sha . ":LICENSE.html", $out, $r); - if ($r == 0) { - $license = implode("\n", $out); - } -} - -// if we didn't manage to read one in, use latest -if ($license == "") { - $license = file_get_contents('LICENSE.html'); -} - -// replace info tag and display -$info = $year . ' ' . $holder; -$license = str_replace('{{info}}', $info, $license); -$license = str_replace('{{theme}}', $theme, $license); -$license = str_replace('{{gravatar}}', $gravatar, $license); - -// if we want text format, strip out the license from the article tag -// and then strip any other tags in the license. -if ($format == 'txt') { - $license = array_shift(explode('', array_pop(explode('
', $license)))); - $license = preg_replace('/<[^>]*>/', '', trim($license)); - $license = html_entity_decode($license, ENT_COMPAT | ENT_HTML401, 'UTF-8'); - $license .= "\n"; - header('content-type: text/plain; charset=UTF-8'); -} - -echo $license; diff --git a/package.json b/package.json index 41bb9f28..3441f475 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@types/express": "^4.16.1", "@types/express-minify": "^0.1.34", "@types/md5": "^2.1.33", + "@types/node": "^12.0.4", "@types/tmp": "^0.1.0", "@typescript-eslint/eslint-plugin": "^1.9.0", "css": "^2.2.4", diff --git a/server.ts b/server.ts index e4a25a96..abbc357f 100644 --- a/server.ts +++ b/server.ts @@ -19,10 +19,11 @@ import postcssMiddleware = require('postcss-middleware') // License viewing import * as ejs from 'ejs' -import {yearNow, stripTags, trimArray} from './util' +import { yearNow, stripTags, trimArray } from './util' import * as HTML from 'node-html-parser' import md5 = require('md5'); import humanizeList from 'humanize-list' +import dayjs from 'dayjs' // License creation import btoa = require('btoa') @@ -35,6 +36,26 @@ const github = require('@octokit/rest')({ userAgent: `mit-license v${require('./package.json').version}`, }) +// Helpers +const yearNow = dayjs().year() +const stripTags = (val: any) => val.replace(/<(?:.|\n)*?>/gm, '') +function trimArray(arr: any[]) { + // Example: trimArray(['', '', 'abc', '', 'abc', 'abc', '', '']) -> ["abc", "", "abc", "abc"] + const handleVal = (val: any) => { + if (val !== '') { + valPassed = true + return val + } + else if (!valPassed) return null + else return val + } + let valPassed = false + arr = arr.map(handleVal) + valPassed = false + arr = arr.reverse().map(handleVal) + return arr.reverse().filter((val) => val !== null) +} + // Prepare application const app = express() app.use(compression()) @@ -47,7 +68,7 @@ app.set('view engine', 'ejs') app.use('/robots.txt', express.static('robots.txt')) app.use('/users', express.static('users')) app.use('/themes', postcssMiddleware({ - plugins: [require('postcss-preset-env')({browsers: '>= 0%', stage: 0})], + plugins: [require('postcss-preset-env')({ browsers: '>= 0%', stage: 0 })], src: (req) => path.join(__dirname, 'themes', req.path), })) app.use('/themes', express.static('themes')) @@ -61,7 +82,7 @@ app.use((_req, res, next) => { }) // Parse URL-encoded bodies (as sent by HTML forms) -app.use(express.urlencoded({extended: true})) +app.use(express.urlencoded({ extended: true })) // Parse JSON bodies (as sent by API clients) app.use(express.json()) @@ -71,26 +92,59 @@ app.post('/', (req, res) => { // Get differnet parts of hostname (example: remy.mit-license.org -> ['remy', 'mit-license', 'org']) const params = req.hostname.split('.') + const conf = (() => { + // If query parameters provided + if (Object.keys(req.query).length > 0) return req.query + + // If the data parsed as {'{data: "value"}': ''} + const keys = Object.keys(req.body) + if (keys.length === 1 && !Object.values(req.body)[0]) return JSON.parse(keys[0]) + + // Fallback + return 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.') - github.repos.createFile({ - owner: 'remy', - repo: 'mit-license', - path: `users/${params[0]}.json`, - message: `Automated creation of user ${params[0]}.`, - content: btoa(''), - committer: { - name: 'MIT License Bot', - email: 'remy@leftlogic.com', - }, - }) + // Extract the name from the URL + const name = params[0] - gitpull(__dirname, (err: any, _consoleOutput: any) => { - if (err) { - res.status(502).end() + // Check if the user file exists in the users directory + fs.access(path.join('users', `${name}.json`), fs.constants.F_OK, (err) => { + if (!err) { + // File already exists + res.status(409).send('User already exists - to update values, please send a pull request on https://github.com/remy/mit-license') } else { - res.status(201).end() + try { + // File doesn't exist + + // If copyright property and key doesn't exist + if (!conf.copyright) res.status(400).send(`JSON requires "copyright" property and value`) + else { + github.repos.createFile({ + owner: 'remy', + repo: 'mit-license', + path: `users/${params[0]}.json`, + message: `Automated creation of user ${params[0]}.`, + content: btoa(JSON.stringify(conf, null, 4)), + committer: { + name: 'MIT License Bot', + email: 'remy@leftlogic.com', + }, + }) + + gitpull(__dirname, (err: any, _consoleOutput: any) => { + if (err) { + res.status(502).send(`Unable to create new user - please send a pull request on https://github.com/remy/mit-license`) + } else { + res.status(201).send(`MIT license page created: https://${req.hostname}`) + } + }) + } + } catch (e) { + res.status(502).send(`Unable to create new user - please send a pull request on https://github.com/remy/mit-license`) + } } }) }) diff --git a/util.ts b/util.ts deleted file mode 100644 index 28271234..00000000 --- a/util.ts +++ /dev/null @@ -1,20 +0,0 @@ -import dayjs = require('dayjs'); - -export const yearNow = dayjs().year() -export const stripTags = (val: any) => val.replace(/<(?:.|\n)*?>/gm, '') -export function trimArray(arr: any[]) { - // Example: trimArray(['', '', 'abc', '', 'abc', 'abc', '', '']) -> ["abc", "", "abc", "abc"] - const handleVal = (val: any) => { - if (val !== '') { - valPassed = true - return val - } - else if (!valPassed) return null - else return val - } - let valPassed = false - arr = arr.map(handleVal) - valPassed = false - arr = arr.reverse().map(handleVal) - return arr.reverse().filter((val) => val !== null) -} diff --git a/yarn.lock b/yarn.lock index 0a29655337542741eea6d0285bab98bd83b47458..10498797bfeadb907480d33cbd5e4f849cd8f1f5 100644 GIT binary patch delta 45 zcmaF;hNI~%#|Cd1F&zaZhmy*I)MEX-{FGFOI71^n13i;wFPU~P8OH5iGE9n60C{8% AE&u=k delta 22 dcmZpA%klaR#|Cei<|LW+BpJr-Nis|dQUGt~2j&0(