Optimizing for Docker Container

This commit is contained in:
Fabian Stamm 2019-12-16 14:02:51 +01:00
parent 11f460406b
commit f8dfceb300
12 changed files with 3306 additions and 282 deletions

View File

@ -1,8 +1,22 @@
pipeline: kind: pipeline
core: type: docker
image: node name: default
commands:
- node --version && npm --version steps:
- npm install - name: Build with node
- cd views && npm install && cd .. image: node:12
- npm run build commands:
- npm install
- cd views && npm install && cd ..
- npm run build
- name: Publish to docker
image: plugins/docker
settings:
username:
from_secret: docker_username
password:
from_secret: docker_password
auto_tag: true
repo: hibas123.azurecr.io/authserver
registry: hibas123.azurecr.io
debug: true

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
FROM node:12
LABEL maintainer="Fabian Stamm <dev@fabianstamm.de>"
# RUN apt-get update
# # for https
# RUN apt-get install -yyq ca-certificates
# # install libraries
# RUN apt-get install -yyq libappindicator1 libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6
# # tools
# RUN apt-get install -yyq gconf-service lsb-release wget xdg-utils
# # and fonts
# RUN apt-get install -yyq fonts-liberation
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json", "tsconfig.json", "/usr/src/app/"]
ENV NODE_ENV=production
RUN npm install
COPY lib/ /usr/src/app/lib
COPY views/out /usr/src/app/views/out/
VOLUME [ "/usr/src/app/logs"]
EXPOSE 3004/tcp
CMD ["npm", "run", "start"]

2950
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -37,8 +37,10 @@
"typescript": "^3.5.3" "typescript": "^3.5.3"
}, },
"dependencies": { "dependencies": {
"@hibas123/config": "^1.0.2",
"@hibas123/nodelogging": "^2.1.0", "@hibas123/nodelogging": "^2.1.0",
"@hibas123/nodeloggingserver_client": "^1.1.2", "@hibas123/nodeloggingserver_client": "^1.1.2",
"@hibas123/openauth-views": "file:../Views",
"@hibas123/safe_mongo": "^1.6.1", "@hibas123/safe_mongo": "^1.6.1",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"compression": "^1.7.4", "compression": "^1.7.4",

View File

@ -1,44 +1,70 @@
export interface DatabaseConfig { import { parse } from "@hibas123/config";
host: string import { Logging } from "@hibas123/nodelogging";
database: string import * as dotenv from "dotenv";
} import { readFileSync } from "fs";
import * as ini from "ini";
export interface WebConfig {
port: string dotenv.config();
secure: "true" | "false" | undefined
} export interface DatabaseConfig {
host: string
export interface CoreConfig { database: string
name: string }
url: string
dev: string export interface WebConfig {
} port: string
secure: "true" | "false" | undefined
export interface Config { }
core: CoreConfig
database: DatabaseConfig export interface CoreConfig {
web: WebConfig name: string
dev: boolean url: string
logging: { dev: boolean
server: string; }
appid: string;
token: string; export interface Config {
} | undefined core: CoreConfig
} database: DatabaseConfig
web: WebConfig
import * as ini from "ini"; }
import { readFileSync } from "fs";
const config = parse({
import * as dotenv from "dotenv"; core: {
import { Logging } from "@hibas123/nodelogging"; dev: {
dotenv.config(); default: false,
type: Boolean
const config = ini.parse(readFileSync("./config.ini").toString()) as Config; },
name: {
if (config.core.dev) config.dev = Boolean(config.core.dev); type: String,
if (process.env.DEV === "true") default: "Open Auth"
config.dev = true; },
if (config.dev) url: String
Logging.warning("DEV mode active. This can cause major performance issues, data loss and vulnerabilities! ") },
database: {
database: {
type: String,
default: "openauth"
},
host: {
type: String,
default: "localhost"
}
},
web: {
port: {
type: Number,
default: 3004
},
secure: {
type: Boolean,
default: false
}
}
}, "config.ini") as any as Config;
if (process.env.DEV === "true")
config.core.dev = true;
if (config.core.dev)
Logging.warning("DEV mode active. This can cause major performance issues, data loss and vulnerabilities! ")
export default config; export default config;

View File

@ -1,11 +1,11 @@
import SafeMongo from "@hibas123/safe_mongo"; import SafeMongo from "@hibas123/safe_mongo";
import Config from "./config" import Config from "./config"
let dbname = "openauth" let dbname = "openauth"
let host = "localhost" let host = "localhost"
if (Config.database) { if (Config.database) {
if (Config.database.database) dbname = Config.database.database; if (Config.database.database) dbname = Config.database.database;
if (Config.database.host) host = Config.database.host; if (Config.database.host) host = Config.database.host;
} }
if (Config.dev) dbname += "_dev"; if (Config.core.dev) dbname += "_dev";
const DB = new SafeMongo("mongodb://" + host, dbname); const DB = new SafeMongo("mongodb://" + host, dbname);
export default DB; export default DB;

View File

@ -1,11 +1,11 @@
import Logging from "@hibas123/nodelogging"; import Logging from "@hibas123/nodelogging";
import config from "./config"; import config from "./config";
import NLS from "@hibas123/nodeloggingserver_client"; // import NLS from "@hibas123/nodeloggingserver_client";
if (config.logging) { // if (config.logging) {
let s = NLS(Logging, config.logging.server, config.logging.appid, config.logging.token); // let s = NLS(Logging, config.logging.server, config.logging.appid, config.logging.token);
s.send(`[${new Date().toLocaleTimeString()}] Starting application`); // s.send(`[${new Date().toLocaleTimeString()}] Starting application`);
} // }
// if (!config.database) { // if (!config.database) {
// Logging.error("No database config set. Terminating.") // Logging.error("No database config set. Terminating.")
@ -28,12 +28,12 @@ import TestData from "./testdata";
import DB from "./database"; import DB from "./database";
Logging.log("Connecting to Database") Logging.log("Connecting to Database")
if (config.dev) { if (config.core.dev) {
Logging.warning("Running in dev mode! Database will be cleared!") Logging.warning("Running in dev mode! Database will be cleared!")
} }
DB.connect().then(async () => { DB.connect().then(async () => {
Logging.log("Database connected") Logging.log("Database connected")
if (config.dev) if (config.core.dev)
await TestData() await TestData()
let web = new Web(config.web) let web = new Web(config.web)
web.listen() web.listen()

View File

@ -1,21 +1,21 @@
import * as handlebars from "handlebars" import * as handlebars from "handlebars"
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { __ as i__ } from "i18n" import { __ as i__ } from "i18n"
import config from "../config"; import config from "../config";
let template: handlebars.TemplateDelegate<any>; let template: handlebars.TemplateDelegate<any>;
function loadStatic() { function loadStatic() {
let html = readFileSync("./views/out/admin/admin.html").toString(); let html = readFileSync("./views/out/admin/admin.html").toString();
template = handlebars.compile(html); template = handlebars.compile(html);
} }
export default function GetAdminPage(__: typeof i__): string { export default function GetAdminPage(__: typeof i__): string {
if (config.dev) { if (config.core.dev) {
loadStatic() loadStatic()
} }
let data = {} let data = {}
return template(data, { helpers: { "i18n": __ } }) return template(data, { helpers: { "i18n": __ } })
} }
loadStatic() loadStatic()

View File

@ -1,26 +1,26 @@
import { compile, TemplateDelegate } from "handlebars" import { compile, TemplateDelegate } from "handlebars"
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { __ as i__ } from "i18n" import { __ as i__ } from "i18n"
import config from "../config"; import config from "../config";
let template: TemplateDelegate<any>; let template: TemplateDelegate<any>;
function loadStatic() { function loadStatic() {
let html = readFileSync("./views/out/authorize/authorize.html").toString(); let html = readFileSync("./views/out/authorize/authorize.html").toString();
template = compile(html) template = compile(html)
} }
export default function GetAuthPage(__: typeof i__, appname: string, scopes: { name: string, description: string, logo: string }[]): string { export default function GetAuthPage(__: typeof i__, appname: string, scopes: { name: string, description: string, logo: string }[]): string {
if (config.dev) { if (config.core.dev) {
loadStatic() loadStatic()
} }
return template({ return template({
title: __("Authorize %s", appname), title: __("Authorize %s", appname),
information: __("By clicking on ALLOW, you allow this app to access the requested recources."), information: __("By clicking on ALLOW, you allow this app to access the requested recources."),
scopes: scopes, scopes: scopes,
// request: request // request: request
}, { helpers: { "i18n": __ } }); }, { helpers: { "i18n": __ } });
} }
loadStatic() loadStatic()

View File

@ -1,39 +1,39 @@
import * as handlebars from "handlebars" import * as handlebars from "handlebars"
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { __ as i__ } from "i18n" import { __ as i__ } from "i18n"
import config from "../config"; import config from "../config";
let template: handlebars.TemplateDelegate<any>; let template: handlebars.TemplateDelegate<any>;
function loadStatic() { function loadStatic() {
let html = readFileSync("./views/out/login/login.html").toString(); let html = readFileSync("./views/out/login/login.html").toString();
template = handlebars.compile(html); template = handlebars.compile(html);
} }
/** /**
* Benchmarks (5000, 500 cuncurrent) * Benchmarks (5000, 500 cuncurrent)
* Plain: * Plain:
* - dev 10sec * - dev 10sec
* - prod 6sec * - prod 6sec
* Mustache: * Mustache:
* - dev : 15sec * - dev : 15sec
* - prod: 12sec * - prod: 12sec
* *
* Handlebars: * Handlebars:
* Compile + Render * Compile + Render
* - dev 13sec * - dev 13sec
* - prod 9sec * - prod 9sec
* Compile on load + Render * Compile on load + Render
* - dev 13sec * - dev 13sec
* - prod 6sec * - prod 6sec
*/ */
export default function GetLoginPage(__: typeof i__): string { export default function GetLoginPage(__: typeof i__): string {
if (config.dev) { if (config.core.dev) {
loadStatic() loadStatic()
} }
let data = {} let data = {}
return template(data, { helpers: { "i18n": __ } }); return template(data, { helpers: { "i18n": __ } });
} }
loadStatic() loadStatic()

View File

@ -1,21 +1,21 @@
import * as handlebars from "handlebars" import * as handlebars from "handlebars"
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { __ as i__ } from "i18n" import { __ as i__ } from "i18n"
import config from "../config"; import config from "../config";
let template: handlebars.TemplateDelegate<any>; let template: handlebars.TemplateDelegate<any>;
function loadStatic() { function loadStatic() {
let html = readFileSync("./views/out/register/register.html").toString(); let html = readFileSync("./views/out/register/register.html").toString();
template = handlebars.compile(html); template = handlebars.compile(html);
} }
export default function GetRegistrationPage(__: typeof i__): string { export default function GetRegistrationPage(__: typeof i__): string {
if (config.dev) { if (config.core.dev) {
loadStatic() loadStatic()
} }
let data = {} let data = {}
return template(data, { helpers: { "i18n": __ } }) return template(data, { helpers: { "i18n": __ } })
} }
loadStatic() loadStatic()

View File

@ -1,111 +1,111 @@
import { Router, IRouter, Request } from "express" import { Router, IRouter, Request } from "express"
import GetLoginPage from "./login"; import GetLoginPage from "./login";
import GetAuthPage from "./authorize"; import GetAuthPage from "./authorize";
import promiseMiddleware from "../helper/promiseMiddleware"; import promiseMiddleware from "../helper/promiseMiddleware";
import config from "../config"; import config from "../config";
import * as Handlebars from "handlebars"; import * as Handlebars from "handlebars";
import GetRegistrationPage from "./register"; import GetRegistrationPage from "./register";
import GetAdminPage from "./admin"; import GetAdminPage from "./admin";
import { HttpStatusCode } from "../helper/request_error"; import { HttpStatusCode } from "../helper/request_error";
import * as moment from "moment"; import * as moment from "moment";
import Permission, { IPermission } from "../models/permissions"; import Permission, { IPermission } from "../models/permissions";
import Client from "../models/client"; import Client from "../models/client";
import { Logging } from "@hibas123/nodelogging"; import { Logging } from "@hibas123/nodelogging";
import Stacker from "../api/middlewares/stacker"; import Stacker from "../api/middlewares/stacker";
import { UserMiddleware, GetUserMiddleware } from "../api/middlewares/user"; import { UserMiddleware, GetUserMiddleware } from "../api/middlewares/user";
// import GetUserPage from "./user"; // import GetUserPage from "./user";
Handlebars.registerHelper("appname", () => config.core.name); Handlebars.registerHelper("appname", () => config.core.name);
const cacheTime = config.dev ? moment.duration(1, "month").asSeconds() : 10; const cacheTime = config.core.dev ? moment.duration(1, "month").asSeconds() : 10;
const ViewRouter: IRouter<void> = Router(); const ViewRouter: IRouter<void> = Router();
ViewRouter.get("/", UserMiddleware, (req, res) => { ViewRouter.get("/", UserMiddleware, (req, res) => {
res.send("This is the main page") res.send("This is the main page")
}) })
ViewRouter.get("/register", (req, res) => { ViewRouter.get("/register", (req, res) => {
res.setHeader("Cache-Control", "public, max-age=" + cacheTime); res.setHeader("Cache-Control", "public, max-age=" + cacheTime);
res.send(GetRegistrationPage(req.__)); res.send(GetRegistrationPage(req.__));
}) })
ViewRouter.get("/login", (req, res) => { ViewRouter.get("/login", (req, res) => {
res.setHeader("Cache-Control", "public, max-age=" + cacheTime); res.setHeader("Cache-Control", "public, max-age=" + cacheTime);
res.send(GetLoginPage(req.__)) res.send(GetLoginPage(req.__))
}) })
ViewRouter.get("/admin", GetUserMiddleware(false, true), (req: Request, res, next) => { ViewRouter.get("/admin", GetUserMiddleware(false, true), (req: Request, res, next) => {
if (!req.isAdmin) res.sendStatus(HttpStatusCode.FORBIDDEN) if (!req.isAdmin) res.sendStatus(HttpStatusCode.FORBIDDEN)
else next() else next()
}, (req, res) => { }, (req, res) => {
res.send(GetAdminPage(req.__)) res.send(GetAdminPage(req.__))
}) })
// ViewRouter.get("/user", Stacker(GetUserMiddleware(false, true), (req, res) => { // ViewRouter.get("/user", Stacker(GetUserMiddleware(false, true), (req, res) => {
// res.setHeader("Cache-Control", "public, max-age=" + cacheTime); // res.setHeader("Cache-Control", "public, max-age=" + cacheTime);
// res.send(GetUserPage(req.__)); // res.send(GetUserPage(req.__));
// })); // }));
ViewRouter.get("/auth", Stacker(GetUserMiddleware(false, true), async (req, res) => { ViewRouter.get("/auth", Stacker(GetUserMiddleware(false, true), async (req, res) => {
let { scope, redirect_uri, state, client_id }: { [key: string]: string } = req.query; let { scope, redirect_uri, state, client_id }: { [key: string]: string } = req.query;
const sendError = (type) => { const sendError = (type) => {
res.redirect(redirect_uri += `?error=${type}&state=${state}`); res.redirect(redirect_uri += `?error=${type}&state=${state}`);
} }
let client = await Client.findOne({ client_id: client_id }) let client = await Client.findOne({ client_id: client_id })
if (!client) { if (!client) {
return sendError("unauthorized_client") return sendError("unauthorized_client")
} }
let permissions: IPermission[] = []; let permissions: IPermission[] = [];
let proms: PromiseLike<void>[] = []; let proms: PromiseLike<void>[] = [];
if (scope) { if (scope) {
for (let perm of scope.split(";").filter(e => e !== "read_user")) { for (let perm of scope.split(";").filter(e => e !== "read_user")) {
proms.push(Permission.findById(perm).then(p => { proms.push(Permission.findById(perm).then(p => {
if (!p) return Promise.reject(new Error()); if (!p) return Promise.reject(new Error());
permissions.push(p); permissions.push(p);
})); }));
} }
} }
let err = false; let err = false;
await Promise.all(proms).catch(e => { await Promise.all(proms).catch(e => {
err = true; err = true;
}) })
Logging.debug(err); Logging.debug(err);
if (err) { if (err) {
return sendError("invalid_scope") return sendError("invalid_scope")
} }
let scopes = await Promise.all(permissions.map(async perm => { let scopes = await Promise.all(permissions.map(async perm => {
let client = await Client.findById(perm.client); let client = await Client.findById(perm.client);
return { return {
name: perm.name, name: perm.name,
description: perm.description, description: perm.description,
logo: client.logo logo: client.logo
} }
})) }))
res.send(GetAuthPage(req.__, client.name, scopes)); res.send(GetAuthPage(req.__, client.name, scopes));
})); }));
if (config.dev) { if (config.core.dev) {
const logo = "data:image/png;base64,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" const logo = "data:image/png;base64,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"
ViewRouter.get("/devauth", (req, res) => { ViewRouter.get("/devauth", (req, res) => {
res.send(GetAuthPage(req.__, "Test 05265", [ res.send(GetAuthPage(req.__, "Test 05265", [
{ {
name: "Access Profile", name: "Access Profile",
description: "It allows the application to know who you are. Required for all applications. And a lot of more Text, because why not? This will not stop, till it is multiple lines long and maybe kill the layout, so keep reading as long as you like, but I promise it will get boring after some time. So this should be enougth.", description: "It allows the application to know who you are. Required for all applications. And a lot of more Text, because why not? This will not stop, till it is multiple lines long and maybe kill the layout, so keep reading as long as you like, but I promise it will get boring after some time. So this should be enougth.",
logo: logo logo: logo
}, },
{ {
name: "Test 1", name: "Test 1",
description: "This is not an real permission. This is used just to verify the layout", description: "This is not an real permission. This is used just to verify the layout",
logo: logo logo: logo
}, },
{ {
name: "Test 2", name: "Test 2",
description: "This is not an real permission. This is used just to verify the layout", description: "This is not an real permission. This is used just to verify the layout",
logo: logo logo: logo
} }
])) ]))
}) })
} }
export default ViewRouter; export default ViewRouter;