diff --git a/certbot.ini b/certbot.ini index 891ebf6..dab450e 100644 --- a/certbot.ini +++ b/certbot.ini @@ -1,7 +1,7 @@ config-dir = /home/ubuntu/.certbot/config work-dir = /home/ubuntu/.certbot/work logs-dir = /home/ubuntu/.certbot/logs -email = jason.park@gatech.edu +email = parkjs814@gmail.com authenticator = webroot webroot-path = /home/ubuntu/server/public/frontend-built domains = algorithm-visualizer.org diff --git a/package-lock.json b/package-lock.json index 646e43c..80b8362 100644 --- a/package-lock.json +++ b/package-lock.json @@ -112,6 +112,12 @@ "integrity": "sha512-1YKeT4JitGgE4SOzyB9eMwO0nGVNkNEsm9qlIt1Lqm/tG2QEiSMTD4kS3aO6L+w5SClLVxALmIBESK6Mk5wX0A==", "dev": true }, + "@types/node-cron": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.1.tgz", + "integrity": "sha512-BkMHHonDT8NJUE/pQ3kr5v2GLDKm5or9btLBoBx4F2MB2cuqYC748LYMDC55VlrLI5qZZv+Qgc3m4P3dBPcmeg==", + "dev": true + }, "@types/range-parser": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", @@ -199,13 +205,13 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "aws-sdk": { - "version": "2.480.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.480.0.tgz", - "integrity": "sha512-X6xOgBeg8ZZJPnL4/wHXFIP6QF2SBABqw/F5l5zT/vEPUfmrIg24LVSUwPXmV6ZMh4hwsuuOjO910MbjNoHXXg==", + "version": "2.814.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.814.0.tgz", + "integrity": "sha512-empd1m/J/MAkL6d9OeRpmg9thobULu0wk4v8W3JToaxGi2TD7PIdvE6yliZKyOVAdJINhBWEBhxR4OUIHhcGbQ==", "requires": { - "buffer": "4.9.1", + "buffer": "4.9.2", "events": "1.1.1", - "ieee754": "1.1.8", + "ieee754": "1.1.13", "jmespath": "0.15.0", "querystring": "0.2.0", "sax": "1.2.1", @@ -215,12 +221,11 @@ } }, "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.2.tgz", + "integrity": "sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg==", "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" + "follow-redirects": "^1.14.0" } }, "balanced-match": { @@ -230,9 +235,9 @@ "dev": true }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-auth": { "version": "2.0.1", @@ -280,9 +285,9 @@ } }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -449,14 +454,6 @@ "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==", "dev": true }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -651,12 +648,9 @@ } }, "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" }, "forwarded": { "version": "0.1.2", @@ -722,9 +716,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-errors": { @@ -748,9 +742,9 @@ } }, "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "indent-string": { "version": "2.1.0", @@ -787,11 +781,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", @@ -970,6 +959,19 @@ } } }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz", + "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==", + "requires": { + "moment": ">= 2.9.0" + } + }, "morgan": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", @@ -1002,6 +1004,14 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "node-cron": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz", + "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==", + "requires": { + "moment-timezone": "^0.5.31" + } + }, "node-notifier": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", @@ -1091,9 +1101,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-to-regexp": { @@ -1423,9 +1433,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, "trim-newlines": { diff --git a/package.json b/package.json index 5c7f111..d33045a 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,15 @@ "@types/fs-extra": "^7.0.0", "@types/morgan": "^1.7.35", "@types/node": "^12.0.0", + "@types/node-cron": "^3.0.1", "@types/remove-markdown": "^0.1.1", "@types/uuid": "^3.4.4", "ts-node-dev": "^1.0.0-pre.39", "tslint": "^5.16.0" }, "dependencies": { - "aws-sdk": "^2.480.0", - "axios": "^0.19.0", + "aws-sdk": "^2.814.0", + "axios": "^0.21.2", "body-parser": "^1.18.2", "compression": "^1.7.3", "dotenv": "^8.0.0", @@ -36,6 +37,7 @@ "express-github-webhook": "^1.0.6", "fs-extra": "^6.0.1", "morgan": "^1.9.1", + "node-cron": "^3.0.0", "remove-markdown": "^0.3.0", "ts-httpexceptions": "^4.1.0", "ts-node": "^8.1.0", diff --git a/src/Server.ts b/src/Server.ts index 3130322..637b2df 100644 --- a/src/Server.ts +++ b/src/Server.ts @@ -7,18 +7,19 @@ import compression from 'compression'; import { __PROD__, credentials, httpPort, httpsPort, webhookOptions } from 'config/environments'; import http from 'http'; import https from 'https'; +import cron from 'node-cron'; import { Hierarchy } from 'models'; import * as Tracers from 'tracers'; import { errorHandlerMiddleware, frontendMiddleware, redirectMiddleware } from 'middlewares'; -import { execute, pull } from 'utils/misc'; +import { execute, issueHttpsCertificate, pull } from 'utils/misc'; import { frontendBuildDir, frontendBuiltDir, frontendDir, rootDir } from 'config/paths'; const Webhook = require('express-github-webhook'); export default class Server { - private readonly app = express(); readonly hierarchy = new Hierarchy(); readonly tracers = Object.values(Tracers).map(Tracer => new Tracer()); + private readonly app = express(); private readonly webhook = webhookOptions && Webhook(webhookOptions); constructor() { @@ -27,7 +28,7 @@ export default class Server { .use(morgan(__PROD__ ? 'tiny' : 'dev')) .use(redirectMiddleware()) .use(bodyParser.json()) - .use(bodyParser.urlencoded({extended: true})) + .use(bodyParser.urlencoded({ extended: true })) .use('/api', this.getApiRouter()) .use(frontendMiddleware(this)); if (this.webhook) { @@ -37,7 +38,7 @@ export default class Server { if (this.webhook) { this.webhook.on('push', async (repo: string, data: any) => { - const {ref, head_commit} = data; + const { ref, head_commit } = data; if (ref !== 'refs/heads/master') return; if (!head_commit) throw new Error('The `head_commit` is empty.'); @@ -62,6 +63,12 @@ export default class Server { await tracer.update(data.release); }); } + + if (credentials) { + cron.schedule('0 0 1 * *', () => { + issueHttpsCertificate(); + }); + } } getApiRouter() { diff --git a/src/config/environments.ts b/src/config/environments.ts index 088dca7..912d9c8 100644 --- a/src/config/environments.ts +++ b/src/config/environments.ts @@ -1,8 +1,7 @@ import fs from 'fs'; import { ServerOptions } from 'https'; import path from 'path'; -import { spawn } from 'child_process'; -import { rootDir } from 'config/paths'; +import { issueHttpsCertificate } from '../utils/misc'; require('dotenv-flow').config(); @@ -75,18 +74,7 @@ if (isEnabled(CREDENTIALS_ENABLED)) { cert: readCredentials(CREDENTIALS_CERT), }; } else { - const certbotIniPath = path.resolve(rootDir, 'certbot.ini'); - const childProcess = spawn('certbot', ['certonly', '--non-interactive', '--agree-tos', '--config', certbotIniPath]); - childProcess.stdout.pipe(process.stdout); - childProcess.stderr.pipe(process.stderr); - childProcess.on('error', console.error); - childProcess.on('exit', code => { - if (code === 0) { - process.exit(0); - } else { - console.error(new Error(`certbot failed with exit code ${code}.`)); - } - }); + issueHttpsCertificate(); } } diff --git a/src/utils/misc.ts b/src/utils/misc.ts index 56f73c1..1b5fe67 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -3,10 +3,12 @@ import fs from 'fs-extra'; import { File } from 'models'; import removeMarkdown from 'remove-markdown'; import * as child_process from 'child_process'; -import { ExecOptions } from 'child_process'; +import { ExecOptions, spawn } from 'child_process'; +import { rootDir } from '../config/paths'; +import path from 'path'; export function download(url: string, localPath: string) { - return axios({url, method: 'GET', responseType: 'stream'}) + return axios({ url, method: 'GET', responseType: 'stream' }) .then(response => new Promise((resolve, reject) => { const writer = fs.createWriteStream(localPath); writer.on('finish', resolve); @@ -41,7 +43,7 @@ export function getDescription(files: File[]) { const lines = readmeFile.content.split('\n'); lines.shift(); while (lines.length && !lines[0].trim()) lines.shift(); - let descriptionLines = []; + const descriptionLines = []; while (lines.length && lines[0].trim()) descriptionLines.push(lines.shift()); return removeMarkdown(descriptionLines.join(' ')); } @@ -49,9 +51,9 @@ export function getDescription(files: File[]) { type ExecuteOptions = ExecOptions & { stdout?: NodeJS.WriteStream; stderr?: NodeJS.WriteStream; -} +}; -export function execute(command: string, {stdout, stderr, ...options}: ExecuteOptions = {}): Promise { +export function execute(command: string, { stdout, stderr, ...options }: ExecuteOptions = {}): Promise { return new Promise((resolve, reject) => { const child = child_process.exec(command, options, (error, stdout, stderr) => { if (error) return reject(error.code ? new Error(stderr) : error); @@ -61,3 +63,18 @@ export function execute(command: string, {stdout, stderr, ...options}: ExecuteOp if (child.stderr && stderr) child.stderr.pipe(stderr); }); } + +export function issueHttpsCertificate() { + const certbotIniPath = path.resolve(rootDir, 'certbot.ini'); + const childProcess = spawn('certbot', ['certonly', '--non-interactive', '--agree-tos', '--config', certbotIniPath]); + childProcess.stdout.pipe(process.stdout); + childProcess.stderr.pipe(process.stderr); + childProcess.on('error', console.error); + childProcess.on('exit', code => { + if (code === 0) { + process.exit(0); + } else { + console.error(new Error(`certbot failed with exit code ${code}.`)); + } + }); +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy