Complete API

This commit is contained in:
Richie Bendall 2019-06-01 20:36:28 +12:00
parent ded72c6140
commit 0b0afb9a83
No known key found for this signature in database
GPG key ID: 1C6A99DFA9D306FC
7 changed files with 85 additions and 207 deletions

View file

@ -13,7 +13,8 @@
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
"sourceType": "module",
"warnOnUnsupportedTypeScriptVersion": false
},
"rules": {
"indent": ["error", 4],

View file

@ -192,15 +192,22 @@ The following types of requests can be made to this project:
- <http://rem.mit-license.org/license.html> HTML
- <http://rem.mit-license.org/license.txt> Text
The url also supports including a start year:
The URL also supports including a start year:
- <http://rem.mit-license.org/2009/> 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/)
- <http://rem.mit-license.org/2009-2010>
allows me to force the year range
- <http://rem.mit-license.org/2009-2010/license.txt> 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:
- <http://rem.mit-license.org/+MIT> will
show the MIT License (default)
- <http://rem.mit-license.org/+ISC>
shows the ISC license instead
Finally, the URL also supports pinning the year
- <http://rem.mit-license.org/@2009>
this is useful for when your software copyright should expire ([as discussed here](https://github.com/remy/mit-license/issues/771))

165
index.php
View file

@ -1,165 +0,0 @@
<?php
date_default_timezone_set('Europe/London'); // stop php from whining
$format = 'html';
$theme = 'default';
$cname = '';
// use a match instead of preg_replace to ensure we got the cname
preg_match('/^([a-z0-9\-]+)\.mit-license\..*$/', $_SERVER['HTTP_HOST'], $match);
if (count($match) == 2) {
$cname = $match[1];
}
$user_file = 'users/' . $cname . '.json';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $cname) {
echo ('>>> 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 = '<a href="' . $user->url . '">' . $holder . '</a>';
}
if (property_exists($user, 'email')) {
$holder = $holder . ' &lt;<a href="mailto:' . $user->email . '">' . $user->email . '</a>&gt;';
if (property_exists($user, 'gravatar') && $user->gravatar === true) {
$gravatar = '<img id="gravatar" src="https://www.gravatar.com/avatar/' . md5(strtolower(trim($user->email))) . '" />';
}
}
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 = "&lt;copyright holders&gt;";
}
/**
* 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('</article>', array_pop(explode('<article>', $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;

View file

@ -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",

View file

@ -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`)
}
}
})
})

20
util.ts
View file

@ -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)
}

BIN
yarn.lock

Binary file not shown.