From 0597b36ef3740fb0032a13f1d5ff02889c5d2a0b Mon Sep 17 00:00:00 2001 From: Sebastian Seedorf Date: Mon, 16 Nov 2020 13:14:05 +0100 Subject: [PATCH] Moved utils to another repository --- docker-compose.debug.yml | 2 +- package-lock.json | 34 ++++++-- package.json | 5 +- src/app.ts | 4 +- src/healthcheck.ts | 2 +- src/index.ts | 2 +- src/types/extend-request.d.ts | 28 +++++++ src/utils/auth-proxy.ts | 40 --------- src/utils/auto-reload.ts | 62 -------------- src/utils/config.ts | 44 ---------- src/utils/helpers/resolvable.ts | 79 ------------------ src/utils/helpers/urlJoin.ts | 3 - src/utils/index.ts | 10 --- src/utils/logging.ts | 55 ------------ src/utils/permissions.ts | 92 --------------------- src/utils/polyfill-worker.ts | 25 ------ src/utils/polyfill.ts | 38 --------- src/utils/redis.ts | 70 ---------------- src/utils/session.ts | 28 ------- src/utils/types/userinfo.d.ts | 10 --- {src/utils/types => types}/auth-proxy.d.ts | 2 +- {src/utils/types => types}/json-prune.d.ts | 0 {src/utils/types => types}/logging.d.ts | 0 {src/utils/types => types}/permissions.d.ts | 0 {src/utils/types => types}/polyfill.d.ts | 0 25 files changed, 64 insertions(+), 571 deletions(-) create mode 100644 src/types/extend-request.d.ts delete mode 100644 src/utils/auth-proxy.ts delete mode 100644 src/utils/auto-reload.ts delete mode 100644 src/utils/config.ts delete mode 100644 src/utils/helpers/resolvable.ts delete mode 100644 src/utils/helpers/urlJoin.ts delete mode 100644 src/utils/index.ts delete mode 100644 src/utils/logging.ts delete mode 100644 src/utils/permissions.ts delete mode 100644 src/utils/polyfill-worker.ts delete mode 100644 src/utils/polyfill.ts delete mode 100644 src/utils/redis.ts delete mode 100644 src/utils/session.ts delete mode 100644 src/utils/types/userinfo.d.ts rename {src/utils/types => types}/auth-proxy.d.ts (58%) rename {src/utils/types => types}/json-prune.d.ts (100%) rename {src/utils/types => types}/logging.d.ts (100%) rename {src/utils/types => types}/permissions.d.ts (100%) rename {src/utils/types => types}/polyfill.d.ts (100%) diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml index b8074f2..e22ef43 100644 --- a/docker-compose.debug.yml +++ b/docker-compose.debug.yml @@ -25,7 +25,7 @@ services: - "CLIENT_SCOPE=openid email profile roles groups" - "NODE_ENV=debug" - "SSL_VERIFY=false" - - "EXT_RESOURCE_URI=http://localhost" + - "EXT_RESOURCE_URI=http://localhost:3001" - "REDIS_URL=redis://redis:6379" - "NO_PROXY=redis:6379" ports: diff --git a/package-lock.json b/package-lock.json index 5421eb0..1aa25e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3173,6 +3173,29 @@ "pinkie": "^2.0.0" } }, + "pkg-express-utils": { + "version": "git+https://git.biotronik.int/scm/coe-bs-website/node-pkg-express-utils.git#99527fdb494c464c9351626548bf446b39c155f4", + "from": "git+https://git.biotronik.int/scm/coe-bs-website/node-pkg-express-utils.git", + "requires": { + "@10xjs/polyfill-analyzer": "^0.1.0", + "connect-redis": "^5.0.0", + "cookie-parser": "~1.4.4", + "env-var": "^6.3.0", + "express": "~4.16.1", + "express-session": "^1.17.1", + "json-prune": "^1.1.0", + "node-fetch": "^2.6.1", + "polyfill-library": "^3.97.0", + "proper-url-join": "^2.1.1", + "redis": "^3.0.2", + "role-acl": "^4.5.4", + "run-script-os": "^1.1.3", + "threads": "^1.6.3", + "tiny-worker": "^2.3.0", + "uuid": "^8.3.1", + "winston": "^3.3.3" + } + }, "polyfill-library": { "version": "3.97.0", "resolved": "https://registry.npmjs.org/polyfill-library/-/polyfill-library-3.97.0.tgz", @@ -3643,6 +3666,11 @@ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==" }, + "run-script-os": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.3.tgz", + "integrity": "sha512-xPlzE6533nvWVea5z7e5J7+JAIepfpxTu/HLGxcjJYlemVukOCWJBaRCod/DWXJFRIWEFOgSGbjd2m1QWTJi5w==" + }, "rxjs": { "version": "6.6.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", @@ -4606,12 +4634,6 @@ "mkdirp": "^0.5.1" } }, - "ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==", - "dev": true - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/package.json b/package.json index 4b0c223..c9af3a2 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "scripts": { "lint": "eslint . --ext .ts", "lint-fix": "eslint . --ext .ts --fix", - "update-client-hash": "node -e \"require('fs').writeFileSync('public/misc/hash.txt', require('randomstring').generate())\"", "debug-client": "tsc-watch --project ./public/js-source", "debug-server": "tsc-watch --project . --onSuccess \"node --enable-source-maps --use-openssl-ca --unhandled-rejections=strict ./out/index\"", "debug": "concurrently npm:debug-*", @@ -27,6 +26,7 @@ "json-prune": "^1.1.0", "node-fetch": "^2.6.1", "node-sass-middleware": "0.11.0", + "pkg-express-utils": "git+https://git.biotronik.int/scm/coe-bs-website/node-pkg-express-utils.git", "polyfill-library": "^3.97.0", "proper-url-join": "^2.1.1", "pug": "^3.0.0", @@ -57,7 +57,6 @@ "eslint-plugin-promise": "^4.2.1", "node-watch": "^0.7.0", "tsc-watch": "^4.2.9", - "typescript": "^4.0.5", - "ws": "^7.4.0" + "typescript": "^4.0.5" } } diff --git a/src/app.ts b/src/app.ts index 01bcf70..d87899f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as sassMiddleware from 'node-sass-middleware'; import * as compression from 'compression'; import indexRouter from './routes'; -import {AuthProxy, AutoReloader, DefaultConfig, HttpLogger, Polyfill} from './utils'; +import {AuthProxy, AutoReloader, DefaultConfig, HttpLogger, Polyfill, Permissions} from 'pkg-express-utils'; export const app = express(); @@ -36,7 +36,7 @@ router.use(AutoReloader.router); //router.use(Session.getRouter()); // static config -router.use("/js/polyfill.js", Polyfill.router); +router.use("/js/polyfill.js", Polyfill.getRouter('./public/js/bundle.js')); router.use(sassMiddleware({ src: path.join(__dirname, '../public'), dest: path.join(__dirname, '../public'), diff --git a/src/healthcheck.ts b/src/healthcheck.ts index ddb1f95..d880f40 100644 --- a/src/healthcheck.ts +++ b/src/healthcheck.ts @@ -1,7 +1,7 @@ /* eslint-disable no-process-exit,no-console */ import * as http from "http"; import urlJoin from 'proper-url-join'; -import {DefaultConfig} from './utils'; +import {DefaultConfig} from 'pkg-express-utils'; const options = { host: DefaultConfig.HOSTNAME, diff --git a/src/index.ts b/src/index.ts index ce5c2e3..760c133 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import * as http from 'http'; import {app} from './app'; import {HttpError} from 'http-errors'; -import {DefaultConfig, Logger} from './utils'; +import {DefaultConfig, Logger} from 'pkg-express-utils'; app.set('port', DefaultConfig.PORT); const server = http.createServer(app); diff --git a/src/types/extend-request.d.ts b/src/types/extend-request.d.ts new file mode 100644 index 0000000..4b557a2 --- /dev/null +++ b/src/types/extend-request.d.ts @@ -0,0 +1,28 @@ +// extend-request.d.ts + +declare global { + namespace Express { + interface UserInfo { + email: string, + email_verified: boolean, + family_name: string, + given_name: string, + groups: string[], + name: string, + preferred_username: string, + sub: string, + } + + interface Request { + getUserInfo(): Promise; + noLogging: boolean|undefined; + permissionDetails?: import('role-acl').Permission; + } + + interface Response { + initLogout(): boolean; + } + } +} + +export {}; diff --git a/src/utils/auth-proxy.ts b/src/utils/auth-proxy.ts deleted file mode 100644 index 8fe6272..0000000 --- a/src/utils/auth-proxy.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Request, RequestHandler} from 'express'; -import {DefaultConfig, Logger, Resolvable, urlJoin} from '.'; -import fetch from 'node-fetch'; - -const router: RequestHandler = (req: Request, res, next) => { - const resolvable = new Resolvable(async () => { - if (!DefaultConfig.USERINFO_HEADER) { - return undefined; - } - const token = req.header(DefaultConfig.USERINFO_HEADER); - const url = DefaultConfig.AUTH_PROXY_USERINFO_URL || - DefaultConfig.AUTH_PROXY_URL && urlJoin(DefaultConfig.AUTH_PROXY_URL, "userinfo"); - if (token === undefined || url === undefined) { - return undefined; - } - try { - const res = await fetch(url, {headers: [[DefaultConfig.USERINFO_HEADER, token]]}); - return await res.json() as UserInfo; - } catch (e) { - Logger.warn(e); - return undefined; - } - }); - - req.getUserInfo = () => resolvable.resolve(); - res.initLogout = function() { - const url = DefaultConfig.AUTH_PROXY_INIT_LOGOUT_URL || - DefaultConfig.AUTH_PROXY_URL && urlJoin(DefaultConfig.AUTH_PROXY_URL, "init-logout"); - if (url === undefined) { - return false; - } - this.redirect(307, url); - return true; - }; - next(); -}; - -export const AuthProxy = { - router, -}; diff --git a/src/utils/auto-reload.ts b/src/utils/auto-reload.ts deleted file mode 100644 index c3d014e..0000000 --- a/src/utils/auto-reload.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {Router} from 'express'; -import {DefaultConfig, Logger, urlJoin} from '.'; -import {v4} from 'uuid'; -import Timeout = NodeJS.Timeout; - -const router = Router(); -if (!DefaultConfig.isProduction) { - let uuid = v4(); - let updateTimeout: Timeout|undefined = undefined; - import("node-watch").then((watch) => { - watch.default('public', {recursive: true}, () => { - if (updateTimeout !== undefined) clearTimeout(updateTimeout); - updateTimeout = setTimeout(() => { - uuid = v4(); - }, 200); - }); - }).catch((err) => { Logger.error(err); }); - - router.get("/auto-reload/client.js", (req, res) => { - Logger.debug(req.url, req.originalUrl, req.baseUrl); - res.setHeader('Content-Type', "application/javascript"); - // language=JavaScript - res.send(` - const loc = window.location; - const url = loc.protocol+'//'+loc.host+'${urlJoin(req.baseUrl, "/auto-reload")}'; - // const parse = async res => (await res.json()).uuid; - const parse = function(res) { - return res.json() - .then(function(json) {return json.uuid;}) } - let hash = undefined; - let hadError = false; - setInterval(function() { - try { - fetch(url) - .then(function(res) { return parse(res) }) - .then(function(data) { - if (data) { - hash = hash === undefined ? data : hash; - if (hash !== data) { - window.location.reload(); - } - } - }); - } catch (e) { - if (hadError === false) { - console.log(e); - hadError = true; - } - } - }, 3000); - `.replace(/\t/g, "")); - }); - - router.get("/auto-reload", (req, res) => { - req.noLogging = true; - res.json({uuid}); - }); -} - -export const AutoReloader = { - router, -}; diff --git a/src/utils/config.ts b/src/utils/config.ts deleted file mode 100644 index 13db449..0000000 --- a/src/utils/config.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as env from 'env-var'; -import {urlJoin} from '.'; - -const NODE_ENV = env.get('NODE_ENV').default("development").asString(); -const isProduction = NODE_ENV === 'production'; - -const envs = { - NODE_ENV, - // port of the server - PORT: env.get('PORT').default('3000').asPortNumber(), - // hostname of the server ('0.0.0.0' listens on all network interfaces) - HOSTNAME: env.get('HOSTNAME').default('0.0.0.0').asString(), - // base path - BASE_PATH: env.get('BASE_PATH').default('/').asString(), - // external base url - EXTERNAL_BASE_URL: env.get('EXTERNAL_BASE_URL').asString(), - - // url of redis session store (required in production using InMemory) - REDIS_URL: env.get('REDIS_URL').asString() || undefined, - // cookie secret for the session id (required in production using Session) - SESSION_SECRET: env.get('SESSION_SECRET').asString() || undefined, - - // header where user info token is stored to request auth proxy - USERINFO_HEADER: env.get('USERINFO_HEADER').asString() || undefined, - // base url to init a logout or request user info - AUTH_PROXY_URL: env.get('AUTH_PROXY_URL').asString() || undefined, - // override base url to request user info - AUTH_PROXY_USERINFO_URL: env.get('AUTH_PROXY_USERINFO_URL').asString() || undefined, - // override base url to init a logout - AUTH_PROXY_INIT_LOGOUT_URL: env.get('AUTH_PROXY_INIT_LOGOUT_URL').asString() || undefined, -}; - -function requireEnv(name: string, onlyInProduction = false): void { - env.get(name).required(!onlyInProduction || isProduction).asString(); -} - -export const DefaultConfig = { - ...envs, - EXTERNAL_BASE_URL: - envs.EXTERNAL_BASE_URL || - urlJoin(`http://${envs.HOSTNAME}${envs.PORT !== 80 ? `:${envs.PORT}` : ""}`, envs.BASE_PATH), - isProduction, - requireEnv, -}; diff --git a/src/utils/helpers/resolvable.ts b/src/utils/helpers/resolvable.ts deleted file mode 100644 index 679703f..0000000 --- a/src/utils/helpers/resolvable.ts +++ /dev/null @@ -1,79 +0,0 @@ -enum ResolvableState { - WAITING, - PENDING, - ERROR, - DONE -} - -class FetchOnce> { - protected data: T|undefined; - protected error: unknown|undefined; - protected state: ResolvableState = ResolvableState.WAITING; - protected pendings: [(res: Promise|T) => void, (reason: unknown) => void][] = []; - - constructor(protected fetchMethod?: (...args: U) => Promise) { } - - public resolve(...args: U): Promise { - // eslint-disable-next-line promise/avoid-new - return new Promise((resolve, reject) => { - switch (this.state) { - case ResolvableState.WAITING: - this.state = ResolvableState.PENDING; - this.pendings.push([resolve, reject]); - if (this.fetchMethod) this.parsePromise(this.fetchMethod(...args)); - break; - case ResolvableState.PENDING: - this.pendings.push([resolve, reject]); - break; - case ResolvableState.DONE: - resolve(this.data); - break; - case ResolvableState.ERROR: - reject(this.error); - break; - } - }); - } - - protected isFinished(): boolean { - return this.state === ResolvableState.DONE || this.state === ResolvableState.ERROR; - } - - protected parsePromise(promise: Promise): void { - promise.then((data) => { - this.data = data; - this.state = ResolvableState.DONE; - this.pendings.forEach(pending => pending[0](data)); - }).catch(err => { - this.error = err; - this.state = ResolvableState.ERROR; - this.pendings.forEach(pending => pending[1](err)); - }); - } -} - -export class Resolvable> extends FetchOnce { - constructor(fetchMethod: (...args: U) => Promise) { - super(fetchMethod); - } -} - -export class WaitForSync extends FetchOnce { - protected state: ResolvableState = ResolvableState.PENDING; - - constructor() { - super(undefined); - } - - public setData(data: T): void { - if (!this.isFinished()) { - this.parsePromise((async () => data)()); - } - } - - public setError(error: unknown): void { - if (!this.isFinished()) { - this.parsePromise((async () => { throw error; })()); - } - } -} diff --git a/src/utils/helpers/urlJoin.ts b/src/utils/helpers/urlJoin.ts deleted file mode 100644 index 457fc35..0000000 --- a/src/utils/helpers/urlJoin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as properUrlJoin from 'proper-url-join'; - -export const urlJoin = properUrlJoin as unknown as properUrlJoin.default; diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index 2867882..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export {DefaultConfig} from './config'; -export {Redis} from './redis'; -export {Logger, HttpLogger} from './logging'; -export {AuthProxy} from './auth-proxy'; -export {Resolvable, WaitForSync} from './helpers/resolvable'; -export {urlJoin} from './helpers/urlJoin'; -export {AutoReloader} from './auto-reload'; -export {Polyfill} from './polyfill'; -export {Session} from './session'; -export {Permissions} from './permissions'; diff --git a/src/utils/logging.ts b/src/utils/logging.ts deleted file mode 100644 index 1225d69..0000000 --- a/src/utils/logging.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as winston from 'winston'; -import {LeveledLogMethod} from 'winston'; -import {RequestHandler} from 'express'; -import * as colors from 'colors'; -import {DefaultConfig} from '.'; -import prune = require('json-prune'); - - -const logger = winston.createLogger({ - level: DefaultConfig.isProduction ? "info" : "silly", - format: winston.format.json(), - transports: [ - new winston.transports.Console({ - format: winston.format.simple(), - }), - ], -}); - -const levels = ["error", "warn", "info", "http", "verbose", "debug", "silly"] as const; -type LogLevels = typeof levels[number]|"log"; -const wrapper = (original: LeveledLogMethod) => { - return (...args: unknown[]) => { - return original(args.map((obj) => typeof obj === "string" ? obj : prune(obj)).join(" ")); - }; -}; - -export const Logger = { -} as {[level in LogLevels]: ReturnType}; - -for (const level of levels) { - Logger[level] = wrapper(logger[level]); -} -Logger.log = wrapper(logger["silly"]); - -export const HttpLogger: RequestHandler = (req, res, next) => { - const start = Date.now(); - const path = req.path; - type Callback = (() => void)|undefined; - const end = res.end; - res.end = function(...args: [Callback] & [unknown, Callback] & [unknown, BufferEncoding, Callback]) { - const statusCode = res.statusCode; - const colorFunction = statusCode >= 500 ? colors.red - : statusCode >= 400 ? colors.yellow - : statusCode >= 300 ? colors.cyan - : statusCode >= 200 ? colors.green - : colors.gray; - const status = colorFunction(res.statusCode.toString(10)); - const method = req.method.toUpperCase().padEnd(6, " "); - const responseTime = (Date.now()-start).toString(10).padStart(3, " "); - if (!req.noLogging) - Logger.http(`${status} ${method} ${responseTime}ms ${path}`); - end.apply(res, args); - }; - next(); -}; diff --git a/src/utils/permissions.ts b/src/utils/permissions.ts deleted file mode 100644 index ae42301..0000000 --- a/src/utils/permissions.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {AccessControl, AccessControlError, IQueryInfo, Permission} from 'role-acl'; -import {Query} from 'role-acl/lib/src/core/Query'; -import {Request, RequestHandler} from 'express'; - -// see https://www.npmjs.com/package/role-acl -class PermissionManager extends AccessControl { - public can(roleOrRequest: Request|string|string[]|IQueryInfo): PermQuery { - return new PermQuery(this.getGrants(), roleOrRequest); - } - - public getRouter(resource: string, opts: Partial): RequestHandler { - return async (req: Request, res, next) => { - let query = this.can(req); - if (opts.context) - query = query.context(opts.context); - if (opts.action) - query = query.execute(opts.action); - if (opts.skipConditions) - query = query.skipConditions(opts.skipConditions); - const permission = await query.on(resource); - if (permission.granted) { - req.permissionDetails = permission; - next(); - } else { - res.sendStatus(403); - } - }; - } -} - -export type RermRouterOpts = { - context: unknown, - action: string, - skipConditions: boolean -} - -export class PermQuery extends Query { - protected resolveRequest: Request|undefined; - - constructor(grants: unknown, roleOrRequest: Request|string|string[]|IQueryInfo) { - function isRequest(obj: unknown): obj is Request { - // eslint-disable-next-line no-prototype-builtins - return typeof obj === 'object' && obj && obj.hasOwnProperty('path') || false; - } - if (isRequest(roleOrRequest)) { - super(grants, []); - this.resolveRequest = roleOrRequest; - } else { - super(grants, roleOrRequest); - } - } - - public async on(resource: string, skipConditions?: boolean): Promise { - if (this.resolveRequest) { - const userInfo = await this.resolveRequest.getUserInfo(); - this.role(userInfo?.groups ?? []); - } - if ( - typeof this._.role === 'object' && this._.role.includes('noaccess') || - typeof this._.role === 'string' && this._.role === 'noaccess' - ) { - this.role([]); - } - return super.on(resource, skipConditions); - } - - public context(context: unknown): PermQuery { - super.context(context); - return this; - } - - public skipConditions(value: boolean): PermQuery { - super.skipConditions(value); - return this; - } - - public with(context: unknown): PermQuery { - super.with(context); - return this; - } - - public execute(action: string): PermQuery { - super.execute(action); - return this; - } - - public sync(): PermQuery { - throw new AccessControlError("Sync method is not allowed on PermissionManager!"); - } -} - -export const Permissions = new PermissionManager(); diff --git a/src/utils/polyfill-worker.ts b/src/utils/polyfill-worker.ts deleted file mode 100644 index 77ddc29..0000000 --- a/src/utils/polyfill-worker.ts +++ /dev/null @@ -1,25 +0,0 @@ -// workers/add.js -import {expose} from "threads/worker"; -import * as fs from "fs"; -import {analyze} from '@10xjs/polyfill-analyzer'; -import allPolyfills from '@10xjs/polyfill-analyzer/dist/polyfills'; -import {PolyfillFeatureList} from "polyfill-library"; - -expose(() => { - const exclude = [ - "console.markTimeline", - "console.timeline", - "console.timelineEnd", - ]; - const featureList = analyze({ - source: fs.readFileSync('./public/js/bundle.js', 'utf-8'), - include: allPolyfills.filter(x => !exclude.includes(x)), - // Not all features listed by polyfillLibrary.listAllPolyfills()` can be detected. - unsupportedPolyfill: 'ignore', - }); - const feats: PolyfillFeatureList = {}; - for (const feature of featureList) { - feats[feature] = {}; - } - return feats; -}); diff --git a/src/utils/polyfill.ts b/src/utils/polyfill.ts deleted file mode 100644 index 2a68457..0000000 --- a/src/utils/polyfill.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {RequestHandler} from 'express'; -import * as polyfillLibrary from 'polyfill-library'; -import {PolyfillFeatureList} from 'polyfill-library'; -import {DefaultConfig, Logger, WaitForSync} from '.'; -import {spawn, Thread, Worker} from 'threads'; -import {WorkerFunction} from 'threads/dist/types/worker'; - -const features = new WaitForSync(); - -(async () => { - const worker = await spawn(new Worker("./polyfill-worker")); - const feats = await worker() as PolyfillFeatureList; - await Thread.terminate(worker); - return feats; -})() - .then(feats => { - feats["fetch"] = {}; - Logger.debug("Polyfill analysed:", Object.keys(feats)); - features.setData(feats); - }) - .catch(err => features.setError(err)); - - -const router: RequestHandler = async (req, res) => { - const polyfillBundle = await polyfillLibrary.getPolyfillString({ - uaString: req.header("user-agent"), - features: await features.resolve(), - minify: DefaultConfig.isProduction, - unknown: "polyfill", - stream: false, - }); - res.setHeader('Content-Type', 'text/javascript'); - res.send(polyfillBundle); -}; - -export const Polyfill = { - router: router, -}; diff --git a/src/utils/redis.ts b/src/utils/redis.ts deleted file mode 100644 index 2b8f0bf..0000000 --- a/src/utils/redis.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as redis from 'redis'; -import {DefaultConfig} from '.'; -import {promisify} from 'util'; - -interface RedisType { - client: redis.RedisClient | undefined; - get(key: string): Promise; - set(key: string, value: string): Promise; - del(...keys: string[]): Promise; -} - -class RealRedis implements RedisType { - private _client: redis.RedisClient|undefined; - private _promGet: ((key: string) => Promise)|undefined; - private _promSet: RedisType["set"]|undefined; - private _promDel: RedisType["del"]|undefined; - - get client(): redis.RedisClient { - if (this._client !== undefined) return this._client; - DefaultConfig.requireEnv('REDIS_URL'); - this._client = redis.createClient({url: DefaultConfig.REDIS_URL}); - return this._client; - } - - async get(key: string): Promise { - if (!this._promGet) this._promGet = promisify(this.client.get); - const value = await this._promGet(key); - // eslint-disable-next-line no-null/no-null - return value === null ? undefined : value; - } - - async set(key: string, value: string): Promise { - if (!this._promSet) this._promSet = promisify(this.client.set); - await this._promSet(key, value); - } - - async del(...keys: string[]): Promise { - if (!this._promDel) this._promDel = promisify(this.client.del); - return await this._promDel(...keys); - } -} - -class MockRedis implements RedisType { - private inMemory: {[key: string]: string} = {}; - - get client(): undefined { - return undefined; - } - - async get(key: string): Promise { - return this.inMemory[key] || undefined; - } - - async set(key: string, value: string): Promise { - this.inMemory[key] = value; - } - - async del(...keys: string[]): Promise { - for (const key of keys) { - delete this.inMemory[key]; - } - return keys.length; - } -} - -export const Redis: RedisType = - DefaultConfig.REDIS_URL || DefaultConfig.isProduction - ? new RealRedis() - : new MockRedis(); - diff --git a/src/utils/session.ts b/src/utils/session.ts deleted file mode 100644 index 7e93aee..0000000 --- a/src/utils/session.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as session from 'express-session'; -import {Store} from 'express-session'; -import {DefaultConfig, Redis} from '.'; -import * as redisStore from "connect-redis"; -import {RequestHandler} from 'express'; - - -let sessionStore: Store|undefined = undefined; - -function getRouter(options?: Partial): RequestHandler { - DefaultConfig.requireEnv('SESSION_SECRET', true); - if (Redis.client && sessionStore !== undefined) { - const RedisStore = redisStore(session); - sessionStore = new RedisStore({client: Redis.client}); - } - return session({ - store: sessionStore, - secret: DefaultConfig.SESSION_SECRET || 'keyboard cat', - resave: false, - saveUninitialized: true, - cookie: {secure: false}, - ...options, - }); -} - -export const Session = { - getRouter, -}; diff --git a/src/utils/types/userinfo.d.ts b/src/utils/types/userinfo.d.ts deleted file mode 100644 index c11e154..0000000 --- a/src/utils/types/userinfo.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -type UserInfo = { - email: string, - email_verified: boolean, - family_name: string, - given_name: string, - groups: string[], - name: string, - preferred_username: string, - sub: string, -}; diff --git a/src/utils/types/auth-proxy.d.ts b/types/auth-proxy.d.ts similarity index 58% rename from src/utils/types/auth-proxy.d.ts rename to types/auth-proxy.d.ts index 93b5b22..1fe0e51 100644 --- a/src/utils/types/auth-proxy.d.ts +++ b/types/auth-proxy.d.ts @@ -1,6 +1,6 @@ declare namespace Express { interface Request { - getUserInfo(): Promise; + getUserInfo(): Promise; } interface Response { diff --git a/src/utils/types/json-prune.d.ts b/types/json-prune.d.ts similarity index 100% rename from src/utils/types/json-prune.d.ts rename to types/json-prune.d.ts diff --git a/src/utils/types/logging.d.ts b/types/logging.d.ts similarity index 100% rename from src/utils/types/logging.d.ts rename to types/logging.d.ts diff --git a/src/utils/types/permissions.d.ts b/types/permissions.d.ts similarity index 100% rename from src/utils/types/permissions.d.ts rename to types/permissions.d.ts diff --git a/src/utils/types/polyfill.d.ts b/types/polyfill.d.ts similarity index 100% rename from src/utils/types/polyfill.d.ts rename to types/polyfill.d.ts