From 2adb93395e5cc28d5c6a8b1a553eaf8c75f8fdd2 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 20 Feb 2019 17:12:29 -0500 Subject: [PATCH] ActivityPub attempt 2: it actually works this time Use Node.js Express app to serve both statically generated content and dynamic AP stuff --- .gitignore | 2 + .vscode/launch.json | 10 +- lib/activitypub/activity.ts | 40 ++ lib/activitypub/actor.ts | 44 +++ lib/activitypub/articles.ts | 79 ++++ lib/activitypub/federate.ts | 99 +++++ lib/activitypub/followers.ts | 27 ++ lib/activitypub/inbox.ts | 102 ++++++ lib/activitypub/index.ts | 15 + lib/activitypub/webfinger.ts | 23 ++ lib/generate/activitypub.ts | 59 --- lib/generate/index.ts | 2 - lib/index.ts | 50 ++- package-lock.json | 684 ++++++++++++++++++++++++++++++++++- package.json | 11 + 15 files changed, 1171 insertions(+), 76 deletions(-) create mode 100644 lib/activitypub/activity.ts create mode 100644 lib/activitypub/actor.ts create mode 100644 lib/activitypub/articles.ts create mode 100644 lib/activitypub/federate.ts create mode 100644 lib/activitypub/followers.ts create mode 100644 lib/activitypub/inbox.ts create mode 100644 lib/activitypub/index.ts create mode 100644 lib/activitypub/webfinger.ts delete mode 100644 lib/generate/activitypub.ts diff --git a/.gitignore b/.gitignore index d687fe3..3fae5da 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules/ built/ out/ +*.pem +*.db diff --git a/.vscode/launch.json b/.vscode/launch.json index acf131f..d8ad498 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,15 @@ "preLaunchTask": "tsc: build - tsconfig.json", "outFiles": [ "${workspaceFolder}/built/*.js" - ] + ], + "env": { + // "DOMAIN": "shadowfacts.net", + "DOMAIN": "b2dee2f2.ngrok.io", + "DB_PATH": "activitypub.db", + "PUB_KEY_PEM": "public.pem", + "PRIV_KEY_PEM": "private.pem" + }, + "console": "integratedTerminal" } ] } \ No newline at end of file diff --git a/lib/activitypub/activity.ts b/lib/activitypub/activity.ts new file mode 100644 index 0000000..3c0d13d --- /dev/null +++ b/lib/activitypub/activity.ts @@ -0,0 +1,40 @@ +export interface Activity { + actor: string; + type: string; + id: string; +} + +export interface Article extends Activity { + to: string[]; + cc: string[]; +} + +export interface Create extends Activity { + to: string[]; + cc: string[]; + object: Activity; +} + +export interface Follow extends Activity { + object: string; +} + +export interface Accept extends Activity { + object: Follow; +} + +export interface Undo extends Activity { + object: Activity; +} + +export interface Note extends Activity { + inReplyTo: string; + published: string; + content: string; + attributedTo: string; +} + +export interface Actor { + id: string; + inbox: string; +} \ No newline at end of file diff --git a/lib/activitypub/actor.ts b/lib/activitypub/actor.ts new file mode 100644 index 0000000..a259547 --- /dev/null +++ b/lib/activitypub/actor.ts @@ -0,0 +1,44 @@ +import express, { Router } from "express"; +import { promises as fs } from "fs"; + +const domain = process.env.DOMAIN; + +export default async function actor(): Promise { + const router = Router(); + + const pubKeyPem = (await fs.readFile(process.env.PUB_KEY_PEM!)).toString(); + const actorObj = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1" + ], + "type": "Person", + "id": `https://${domain}/ap/actor`, + "preferredUsername": "shadowfacts", + "name": "shadowfacts' blog", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": `https://${domain}/shadowfacts.png` + }, + "inbox": `https://${domain}/ap/inbox`, + "followers": `https://${domain}/ap/actor/followers`, + "publicKey": { + "id": `https://${domain}/ap/actor#main-key`, + "owner": `https://${domain}/ap/actor`, + "publicKeyPem": pubKeyPem + } + }; + + router.get("/ap/actor", (req, res) => { + if (req.accepts("application/activity+json")) { + res.type("application/activity+json"); + res.json(actorObj); + res.end(); + } else { + res.redirect("/"); + } + }); + + return router; +} \ No newline at end of file diff --git a/lib/activitypub/articles.ts b/lib/activitypub/articles.ts new file mode 100644 index 0000000..00f47c4 --- /dev/null +++ b/lib/activitypub/articles.ts @@ -0,0 +1,79 @@ +import express, { Router, Request, Response } from "express"; +import { Page, PostMetadata } from "../metadata"; +import { Article } from "./activity"; +import { Database } from "sqlite3"; + +const domain = process.env.DOMAIN; + +export async function setup(posts: Page[], db: Database) { + for (const post of posts) { + const postMeta = post.metadata; + const articleObject = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + ], + "type": "Article", + "id": `https://${domain}${post.metadata.permalink}`, + "published": (postMeta.date).toISOString(), + "inReplyTo": null, + "url": `https://${domain}${postMeta.permalink}`, + "attributedTo": `https://${domain}/ap/actor`, + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + `https://${domain}/ap/actor/followers` + ], + "name": postMeta.title, + "content": post.text + }; + db.run("INSERT OR IGNORE INTO articles(id, article_doc, has_federated) VALUES($id, $article_doc, $has_federated)", { + $id: postMeta.permalink, + $article_doc: JSON.stringify(articleObject), + $has_federated: 0 + }, (err) => { + if (err) console.log(`Encountered error inserting article ${postMeta.permalink}`, err); + }); + } +} + +export async function toFederate(db: Database): Promise<[string, Article][]> { + return new Promise((resolve, reject) => { + db.all("SELECT id, article_doc FROM articles WHERE has_federated = $has_federated", { + $has_federated: 0 + }, (err, rows) => { + if (err) reject(err); + else { + let result: [string, Article][] = []; + for (const row of rows) { + result.push([row.id, JSON.parse(row.article_doc)]); + } + resolve(result); + } + }); + }); +} + +export function router(): Router { + const router = Router(); + + router.use("/:category/:year/:slug/", (req, res, next) => { + if (req.accepts("text/html")) { + next(); + } else { + const db = req.app.get("db") + db.get("SELECT article_doc FROM articles WHERE id = $id", { + $id: `/${req.params.category}/${req.params.year}/${req.params.slug}/` + }, (err, result) => { + if (err) { + res.status(500).end(err); + return; + } + res.type("application/json"); + res.end(result.article_doc); + }); + } + }); + + return router; +} \ No newline at end of file diff --git a/lib/activitypub/federate.ts b/lib/activitypub/federate.ts new file mode 100644 index 0000000..517f75d --- /dev/null +++ b/lib/activitypub/federate.ts @@ -0,0 +1,99 @@ +import { promises as fs } from "fs"; +import crypto from "crypto"; +import uuidv4 from "uuid/v4"; +import request from "request"; +import { Database } from "sqlite3"; +import { Activity, Article, Create, Actor, Follow, Accept } from "./activity"; +import { URL } from "url"; + +const domain = process.env.DOMAIN; + +function createActivity(article: Article): Create { + const uuid = uuidv4(); + const createObject = { + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "type": "Create", + "id": `https://${domain}/ap/${uuid}`, + "actor": `https://${domain}/ap/actor`, + "to": article.to, + "cc": article.cc, + "object": article + }; + return createObject; +} + +export async function fetchActor(url: string): Promise { + return new Promise((resolve, reject) => { + request({ + url, + headers: { + "Accept": "application/activity+json" + }, + method: "GET", + json: true + }, (err, res) => { + if (err) reject(err); + else resolve(res.body); + }); + }); +} + +export async function signAndSend(activity: Activity, inbox: string) { + const targetDomain = new URL(inbox).hostname; + const inboxFragment = inbox.replace("https://" + targetDomain, ""); + const date = new Date(); + const privKey = (await fs.readFile(process.env.PRIV_KEY_PEM!)).toString(); + const signer = crypto.createSign("sha256"); + const stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${date.toUTCString()}`; + signer.update(stringToSign); + signer.end(); + const signature = signer.sign(privKey); + const base64Signature = signature.toString("base64"); + const header = `keyId="https://${domain}/ap/actor#main-key",headers="(request-target) host date",signature="${base64Signature}"`; + console.log("Sending:", activity); + console.log("stringToSign:", stringToSign); + console.log("Signature: " + header); + request({ + url: inbox, + headers: { + "Host": targetDomain, + "Date": date.toUTCString(), + "Signature": header, + "Accept": "application/activity+json, application/json" + }, + method: "POST", + json: true, + body: activity + }, (err, res) => { + console.log("Sent message to inbox at", targetDomain); + console.log("Response status code", res.statusCode); + console.log(res.body); + if (err) console.log("Error:", err, res); + }); +} + +async function sendToFollowers(activity: Create, db: Database) { + db.each("SELECT inbox FROM followers", (err, result) => { + if (err) { + console.log("Error getting followers: ", err); + return; + } + const inbox = "https://" + new URL(result.inbox).host + "/inbox"; + console.log(`Federating ${activity.object.id} to ${inbox}`); + signAndSend(activity, inbox); + }); +} + +export default function federate(toFederate: [string, Article][], db: Database) { + for (const [id, article] of toFederate) { + + sendToFollowers(createActivity(article), db); + db.run("UPDATE articles SET has_federated = 1 WHERE id = $id", { + $id: id + }); + break; + } +} + diff --git a/lib/activitypub/followers.ts b/lib/activitypub/followers.ts new file mode 100644 index 0000000..13d7c9a --- /dev/null +++ b/lib/activitypub/followers.ts @@ -0,0 +1,27 @@ +import express, { Router } from "express"; +import { Database } from "sqlite3"; + +const domain = process.env.DOMAIN; + +export default function followers(): Router { + const router = Router(); + + router.get("/ap/actor/followers", (req, res) => { + const db = req.app.get("db"); + + db.all("SELECT id FROM followers", (err, rows) => { + res.json({ + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "type": "OrderedCollection", + "id": `https://${domain}/ap/actor/followers`, + "totalItems": rows.length, + "items": rows.map(row => row.id) + }); + res.end(); + }); + }); + + return router; +} \ No newline at end of file diff --git a/lib/activitypub/inbox.ts b/lib/activitypub/inbox.ts new file mode 100644 index 0000000..5839013 --- /dev/null +++ b/lib/activitypub/inbox.ts @@ -0,0 +1,102 @@ +import { Router, Request, Response } from "express"; +import uuidv4 from "uuid/v4"; +import { fetchActor, signAndSend } from "./federate"; +import { Activity, Follow, Accept, Undo, Create, Note } from "./activity"; +import { Database } from "sqlite3"; +import { URL } from "url"; + +const domain = process.env.DOMAIN; + +export default function inbox(): Router { + const router = Router(); + + router.post("/ap/inbox", handleInbox); + router.post("/inbox", handleInbox); + + return router; +} + +async function handleInbox(req: Request, res: Response) { + console.log(req.body); + const activity = req.body as Activity; + if (activity.type === "Follow") { + handleFollow(activity, req, res); + } else if (activity.type === "Create") { + handleCreate(activity, req, res); + } else if (activity.type === "Undo") { + handleUndo(activity, req, res); + } else { + res.end(); // TODO: handle this better + } +} + +async function handleFollow(activity: Activity, req: Request, res: Response) { + if (typeof req.body.object !== "string") { + res.end(); // TODO: handle this better + return; + } + const follow = activity as Follow; + if (follow.object !== `https://${domain}/ap/actor`) { + res.end(); + return; + } + const actor = await fetchActor(follow.actor); + const acceptObject = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + // "https://w3id.org/security/v1" + ], + "id": `https://${domain}/ap/${uuidv4()}`, + "type": "Accept", + "actor": `https://${domain}/ap/actor`, + "object": follow + }; + signAndSend(acceptObject, actor.inbox); + const db = req.app.get("db") as Database; + const serverInbox = new URL("/inbox", actor.inbox).toString(); + db.run("INSERT OR IGNORE INTO followers(id, inbox) VALUES($id, $inbox)", { + $id: actor.id, + $inbox: serverInbox + }, (err) => { + if (err) console.error(`Encountered error adding follower ${follow.actor}`, err); + }); + res.end(); +} + +async function handleCreate(activity: Activity, req: Request, res: Response) { + const create = activity as Create; + if (create.object.type == "Note") { + handleCreateNote(create, req, res); + } else { + res.end(); + } +} + +async function handleCreateNote(create: Create, req: Request, res: Response) { + const note = create.object as Note; + console.log(note); +} + +async function handleUndo(activity: Activity, req: Request, res: Response) { + const undo = activity as Undo; + if (undo.object.type === "Follow") { + handleUndoFollow(undo, req, res); + } else { + res.end(); + } +} + +async function handleUndoFollow(undo: Undo, req: Request, res: Response) { + const follow = undo.object as Follow; + if (follow.object !== `https://${domain}/ap/actor`) { + res.end(); + return; + } + const db = req.app.get("db") as Database; + db.run("DELETE FROM followers WHERE id = $id", { + $id: follow.actor + }, (err) => { + if (err) console.error(`Error unfollowing ${follow.actor}`, err); + }); + res.end(); +} \ No newline at end of file diff --git a/lib/activitypub/index.ts b/lib/activitypub/index.ts new file mode 100644 index 0000000..a9309e4 --- /dev/null +++ b/lib/activitypub/index.ts @@ -0,0 +1,15 @@ +import actor from "./actor"; +import * as articles from "./articles"; +import federate from "./federate"; +import followers from "./followers"; +import inbox from "./inbox"; +import webfinger from "./webfinger"; + +export = { + actor, + articles, + federate, + followers, + inbox, + webfinger +}; \ No newline at end of file diff --git a/lib/activitypub/webfinger.ts b/lib/activitypub/webfinger.ts new file mode 100644 index 0000000..9d9b2ef --- /dev/null +++ b/lib/activitypub/webfinger.ts @@ -0,0 +1,23 @@ +import express, { Router } from "express"; + +const domain = process.env.DOMAIN; + +export default function webfinger(): Router { + const router = Router(); + + router.get("/.well-known/webfinger", (req, res) => { + res.json({ + "subject": `acct:shadowfacts@${domain}`, + "links": [ + { + "rel": "self", + "type": "application/activity+json", + "href": `https://${domain}/ap/actor` + } + ] + }); + res.end(); + }); + + return router; +} \ No newline at end of file diff --git a/lib/generate/activitypub.ts b/lib/generate/activitypub.ts deleted file mode 100644 index 9d52b39..0000000 --- a/lib/generate/activitypub.ts +++ /dev/null @@ -1,59 +0,0 @@ -import path from "path"; -import { Page, PostMetadata } from "../metadata"; -import * as util from "../util"; - -const baseURL = process.env.BASE_URL || "shadowfacts.net"; - -export default async function activitypub(posts: Page[]) { - for (const post of posts) { - const object = postObject(post); - const dir = path.dirname(post.metadata.permalink); - const base = path.basename(post.metadata.permalink); - const dest = path.format({ - dir, - name: base, - ext: ".json" - }); - const data = JSON.stringify(object); - util.write(dest, data); - util.write(path.join(post.metadata.permalink, "index.html.json"), data); - } - - util.write(".well-known/webfinger", JSON.stringify(webfingerObject())); -} - -function postObject(post: Page): object { - const postMeta = post.metadata; - return { - "@context": [ - "https://www.w3.org/ns/activitystreams" - ], - "type": "Article", - "id": `https://${baseURL}${post.metadata.permalink}`, - "published": (postMeta.date).toISOString(), - "inReplyTo": null, - "url": `https://${baseURL}${postMeta.permalink}`, - "attributedTo": `https://${baseURL}/ap/actor`, - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - `https://${baseURL}/ap/followers` - ], - "name": postMeta.title, - "content": post.text - }; -} - -function webfingerObject() { - return { - "subject": `acct:shadowfacts@${baseURL}`, - "links": [ - { - "rel": "self", - "type": "application/activity+json", - "href": `https://${baseURL}/ap/actor` - } - ] - }; -} \ No newline at end of file diff --git a/lib/generate/index.ts b/lib/generate/index.ts index d36ac41..c46aebf 100644 --- a/lib/generate/index.ts +++ b/lib/generate/index.ts @@ -1,4 +1,3 @@ -import activitypub from "./activitypub"; import categories from "./categories"; import copy from "./copy"; import css from "./css"; @@ -10,7 +9,6 @@ import rss from "./rss"; import tutorials from "./tutorials"; export = { - activitypub, categories, copy, css, diff --git a/lib/index.ts b/lib/index.ts index 135f626..892d13f 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,6 +1,20 @@ -import generators = require("./generate"); +import { Page } from "./metadata"; +import generators from "./generate"; -async function generate() { +import express from "express"; +import morgan from "morgan"; +import bodyParser from "body-parser"; +import activitypub from "./activitypub"; + +import sqlite3 from "sqlite3"; + +const db = new (sqlite3.verbose().Database)(process.env.DB_PATH!); + +db.run("CREATE TABLE IF NOT EXISTS followers (id TEXT PRIMARY KEY, inbox TEXT)"); +db.run("CREATE TABLE IF NOT EXISTS articles (id TEXT PRIMARY KEY, article_doc TEXT, has_federated INT)"); +db.run("CREATE TABLE IF NOT EXISTS notes (id TEXT PRIMARY KEY, content TEXT, attributed_to TEXT, in_reply_to TEXT, published TEXT)"); + +async function generate(): Promise { generators.copy(); generators.css(); generators.missing(); @@ -13,7 +27,35 @@ async function generate() { const categories = await generators.categories(posts); await generators.rss(posts, categories, tutorials); - generators.activitypub(posts); + return posts; } -generate(); \ No newline at end of file +const app = express(); +app.set("db", db); +app.use(morgan("dev")); +app.use(bodyParser.json({ type: "application/activity+json" })); + +//db.run("DELETE FROM articles"); + +(async () => { + const posts = await generate(); + + await activitypub.articles.setup(posts, db); + const toFederate = await activitypub.articles.toFederate(db); + + + app.use(await activitypub.actor()); + app.use(activitypub.followers()); + app.use(activitypub.inbox()); + app.use(activitypub.webfinger()); + app.use(activitypub.articles.router()); + app.use(express.static("out")); + + const port = process.env.PORT || 8083; + app.listen(port, () => { + console.log(`Listening on port ${port}`); + + activitypub.federate(toFederate, db); + }); +})(); + diff --git a/package-lock.json b/package-lock.json index bec3b57..8e20203 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,61 @@ "lodash.deburr": "^4.1.0" } }, + "@types/body-parser": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", + "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/caseless": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz", + "integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A==" + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "requires": { + "@types/node": "*" + } + }, "@types/ejs": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-2.6.1.tgz", "integrity": "sha512-WD8015V8Y+uDfFIjiVHU7t9SgHptqTGGN8w0A2LcrL0NLtqColM15cswkHZMUfodyuTf35sup8vW0hpWRHu0dQ==", "dev": true }, + "@types/express": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.1.tgz", + "integrity": "sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.1.tgz", + "integrity": "sha512-QgbIMRU1EVRry5cIu1ORCQP4flSYqLM1lS5LYyGWfKnFT3E58f0gKto7BR13clBFVrVZ0G0rbLZ1hUpSkgQQOA==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/form-data": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", + "integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==", + "requires": { + "@types/node": "*" + } + }, "@types/highlight.js": { "version": "9.12.3", "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", @@ -40,11 +89,23 @@ "@types/linkify-it": "*" } }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, + "@types/morgan": { + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.7.35.tgz", + "integrity": "sha512-E9qFi0seOkdlQnCTPv54brNfGWeFdRaEhI5tSue4pdx/V+xfxvMETsxXhOEcj1cYL+0n/jcTEmj/jD2gjzCwMg==", + "requires": { + "@types/express": "*" + } + }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", - "dev": true + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, "@types/node-sass": { "version": "3.10.32", @@ -55,21 +116,76 @@ "@types/node": "*" } }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/request": { + "version": "2.48.1", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz", + "integrity": "sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg==", + "requires": { + "@types/caseless": "*", + "@types/form-data": "*", + "@types/node": "*", + "@types/tough-cookie": "*" + } + }, + "@types/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "@types/sindresorhus__slugify": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/sindresorhus__slugify/-/sindresorhus__slugify-0.6.0.tgz", "integrity": "sha512-e67QA1mn1St20y/Ews9EQjUXvfrhZSoD9mqfgQ1LjaSip3zjFwyfiMOdyD6OeBQsuwabTML4ytKyn+PcOwblKA==", "dev": true }, + "@types/sqlite3": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.4.tgz", + "integrity": "sha512-EZ/fWzLSKclqFyvMQEw2Ii/NYRTbIWzkdbm56Lgnq/GKNX0o3rkAvNvggXgWkUzgC28nC7yYVgfhWUHvUPd/Fg==", + "requires": { + "@types/node": "*" + } + }, + "@types/tough-cookie": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==" + }, + "@types/uuid": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz", + "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==", + "requires": { + "@types/node": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, "ajv": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", - "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", + "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -119,6 +235,11 @@ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -163,6 +284,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -179,6 +308,33 @@ "inherits": "~2.0.0" } }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -193,6 +349,11 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -224,6 +385,11 @@ "supports-color": "^2.0.0" } }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -263,6 +429,26 @@ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -318,6 +504,11 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -328,6 +519,21 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -349,11 +555,21 @@ "url-join": "^2.0.5" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "ejs": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==" }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", @@ -367,17 +583,74 @@ "is-arrayish": "^0.2.1" } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", "dev": true }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -398,6 +671,30 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -431,6 +728,24 @@ "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "requires": { + "minipass": "^2.2.1" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -559,6 +874,17 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", @@ -596,6 +922,22 @@ "sshpk": "^1.7.0" } }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "requires": { + "minimatch": "^3.0.4" + } + }, "in-publish": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", @@ -623,11 +965,21 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -811,6 +1163,11 @@ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, "meow": { "version": "3.7.0", "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -828,6 +1185,16 @@ "trim-newlines": "^1.0.0" } }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -860,6 +1227,30 @@ "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "requires": { + "minipass": "^2.2.1" + } + }, "mkdirp": { "version": "0.5.1", "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -875,17 +1266,63 @@ } } }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" }, + "needle": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, "node-gyp": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", @@ -912,6 +1349,53 @@ } } }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "dependencies": { + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } + } + }, "node-sass": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", @@ -957,6 +1441,20 @@ "validate-npm-package-license": "^3.0.1" } }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" + }, + "npm-packlist": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.3.0.tgz", + "integrity": "sha512-qPBc6CnxEzpOcc4bjoIBJbYdy0D/LFFPUdxvfwor4/w3vxeE0h6TiOVurCEPpQ6trjN77u/ShyfeJGsbAfB3dA==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", @@ -983,6 +1481,19 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1050,6 +1561,11 @@ "error-ex": "^1.2.0" } }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -1063,6 +1579,11 @@ "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -1123,6 +1644,15 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -1143,6 +1673,33 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -1265,6 +1822,11 @@ "yargs": "^7.0.0" } }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "scss-tokenizer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", @@ -1279,11 +1841,62 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -1330,10 +1943,27 @@ "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "sqlite3": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.6.tgz", + "integrity": "sha512-EqBXxHdKiwvNMRCgml86VTL5TK1i0IKiumnfxykX0gh6H6jaKijAXvE9O1N7+omfNSawR2fOmIyJZcfe8HYWpw==", + "requires": { + "nan": "~2.10.0", + "node-pre-gyp": "^0.11.0", + "request": "^2.87.0" + }, + "dependencies": { + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + } + } + }, "sshpk": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", - "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -1346,6 +1976,11 @@ "tweetnacl": "~0.14.0" } }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, "stdout-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", @@ -1396,6 +2031,11 @@ "get-stdin": "^4.0.1" } }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, "supports-color": { "version": "2.0.0", "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -1453,6 +2093,15 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, "typescript": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", @@ -1480,6 +2129,11 @@ } } }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1499,6 +2153,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -1513,6 +2172,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/package.json b/package.json index 1be324d..f7a27a3 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,22 @@ }, "dependencies": { "@sindresorhus/slugify": "^0.6.0", + "@types/body-parser": "^1.17.0", + "@types/express": "^4.16.1", + "@types/morgan": "^1.7.35", + "@types/request": "^2.48.1", + "@types/sqlite3": "^3.1.4", + "@types/uuid": "^3.4.4", + "body-parser": "^1.18.3", "date-fns": "^1.30.1", "ejs": "^2.6.1", + "express": "^4.16.4", "highlight.js": "^9.13.1", "markdown-it": "^8.4.2", + "morgan": "^1.9.1", "node-sass": "^4.11.0", + "request": "^2.88.0", + "sqlite3": "^4.0.6", "typescript": "^3.2.2", "uuid": "^3.3.2" },