Adding Dockerfile and build script
This commit is contained in:
parent
65588f4b98
commit
405e589328
32
Dockerfile
Normal file
32
Dockerfile
Normal 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 /usr/src/app
|
||||||
|
COPY package-lock.json /usr/src/app
|
||||||
|
COPY lib/ /usr/src/app
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
VOLUME [ "/usr/src/app/databases", "/usr/src/app/logs" ]
|
||||||
|
|
||||||
|
EXPOSE 5000/tcp
|
||||||
|
|
||||||
|
CMD ["npm", "run", "start"]
|
@ -1,5 +0,0 @@
|
|||||||
[general]
|
|
||||||
dev=true
|
|
||||||
port=5013
|
|
||||||
admin=admin
|
|
||||||
access_log=true
|
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@hibas123/realtime-db",
|
"name": "@hibas123/realtimedb",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
@ -76,6 +76,15 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/dotenv": {
|
||||||
|
"version": "6.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz",
|
||||||
|
"integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/events": {
|
"@types/events": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||||
@ -930,6 +939,11 @@
|
|||||||
"is-obj": "^1.0.0"
|
"is-obj": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dotenv": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA=="
|
||||||
|
},
|
||||||
"duplexer3": {
|
"duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
"watch-ts": "tsc -w",
|
"watch-ts": "tsc -w",
|
||||||
"watch-node": "nodemon --ignore *.ts lib/index.js",
|
"watch-node": "nodemon --ignore *.ts lib/index.js",
|
||||||
"watch": "concurrently \"npm:watch-*\"",
|
"watch": "concurrently \"npm:watch-*\"",
|
||||||
|
"build-docker": "npm run build && docker build -t realtimedb .",
|
||||||
"prepublishOnly": "tsc"
|
"prepublishOnly": "tsc"
|
||||||
},
|
},
|
||||||
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/dotenv": "^6.1.1",
|
||||||
"@types/ini": "^1.3.30",
|
"@types/ini": "^1.3.30",
|
||||||
"@types/leveldown": "^4.0.0",
|
"@types/leveldown": "^4.0.0",
|
||||||
"@types/levelup": "^3.1.1",
|
"@types/levelup": "^3.1.1",
|
||||||
@ -30,6 +32,7 @@
|
|||||||
"@hibas123/utils": "^2.1.1",
|
"@hibas123/utils": "^2.1.1",
|
||||||
"@types/koa": "^2.0.49",
|
"@types/koa": "^2.0.49",
|
||||||
"@types/koa-router": "^7.0.42",
|
"@types/koa-router": "^7.0.42",
|
||||||
|
"dotenv": "^8.1.0",
|
||||||
"handlebars": "^4.2.0",
|
"handlebars": "^4.2.0",
|
||||||
"ini": "^1.3.5",
|
"ini": "^1.3.5",
|
||||||
"koa": "^2.8.1",
|
"koa": "^2.8.1",
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
import * as ini from "ini";
|
|
||||||
import * as fs from "fs";
|
|
||||||
import Logging from "@hibas123/nodelogging";
|
import Logging from "@hibas123/nodelogging";
|
||||||
|
import * as dotenv from "dotenv";
|
||||||
|
|
||||||
interface IConfig {
|
interface IConfig {
|
||||||
general: {
|
port: number;
|
||||||
port: string;
|
admin: string;
|
||||||
admin: string;
|
access_log: boolean;
|
||||||
access_log: boolean;
|
dev: boolean
|
||||||
dev: boolean
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = ini.parse(fs.readFileSync("config.ini").toString()) as IConfig;
|
const config: IConfig = {
|
||||||
Logging.debug("Config:", config);
|
port: Number(process.env.PORT),
|
||||||
|
access_log: (process.env.ACCESS_LOG || "").toLowerCase() === "true",
|
||||||
|
admin: process.env.ADMIN_KEY,
|
||||||
|
dev: (process.env.DEV || "").toLowerCase() === "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
dotenv.config()
|
||||||
|
|
||||||
export default config;
|
export default config;
|
@ -13,7 +13,7 @@ export class DatabaseManager {
|
|||||||
let databases = await Settings.getDatabases();
|
let databases = await Settings.getDatabases();
|
||||||
|
|
||||||
databases.forEach(dbconfig => {
|
databases.forEach(dbconfig => {
|
||||||
let db = new Database(dbconfig.name, dbconfig.accesskey, dbconfig.rules, dbconfig.publickey);
|
let db = new Database(dbconfig.name, dbconfig.accesskey, dbconfig.rules, dbconfig.publickey, dbconfig.rootkey);
|
||||||
this.databases.set(dbconfig.name, db);
|
this.databases.set(dbconfig.name, db);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ export class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(public name: string, public accesskey?: string, rawRules?: string, public publickey?: string) {
|
constructor(public name: string, public accesskey?: string, rawRules?: string, public publickey?: string, public rootkey?: string) {
|
||||||
if (rawRules)
|
if (rawRules)
|
||||||
this.rules = new Rules(rawRules);
|
this.rules = new Rules(rawRules);
|
||||||
}
|
}
|
||||||
@ -84,11 +84,17 @@ export class Database {
|
|||||||
this.accesskey = key;
|
this.accesskey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setRootKey(key: string) {
|
||||||
|
await Settings.setDatabaseAccessKey(this.name, key);
|
||||||
|
this.accesskey = key;
|
||||||
|
}
|
||||||
|
|
||||||
async setPublicKey(key: string) {
|
async setPublicKey(key: string) {
|
||||||
await Settings.setDatabasePublicKey(this.name, key);
|
await Settings.setDatabasePublicKey(this.name, key);
|
||||||
this.publickey = key;
|
this.publickey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getQuery(path: string[]) {
|
getQuery(path: string[]) {
|
||||||
return new Query(this, path);
|
return new Query(this, path);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import Logging from "@hibas123/nodelogging";
|
import Logging from "@hibas123/nodelogging";
|
||||||
// import getLevelDB from "./storage";
|
|
||||||
// import Settings from "./settings";
|
|
||||||
import Web from "./web";
|
import Web from "./web";
|
||||||
import config from "./config";
|
import config from "./config";
|
||||||
import { DatabaseManager } from "./database/database";
|
import { DatabaseManager } from "./database/database";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
import { ConnectionManager } from "./connection";
|
import { ConnectionManager } from "./connection";
|
||||||
|
|
||||||
// Logging.debug(getLevelDB("system"));
|
|
||||||
|
|
||||||
DatabaseManager.init().then(() => {
|
DatabaseManager.init().then(() => {
|
||||||
const http = createServer(Web.callback());
|
const http = createServer(Web.callback());
|
||||||
ConnectionManager.bind(http);
|
ConnectionManager.bind(http);
|
||||||
const port = Number(config.general.port) || 5013;
|
const port = config.port || 5000;
|
||||||
http.listen(port, () => Logging.log("Listening on port:", port))
|
http.listen(port, () => Logging.log("Listening on port:", port))
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
Logging.error(err);
|
Logging.error(err);
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import getLevelDB, { resNull } from "./storage";
|
import getLevelDB, { resNull } from "./storage";
|
||||||
|
|
||||||
import Encoder, { DataTypes } from "@hibas123/binary-encoder";
|
|
||||||
import Logging from "@hibas123/nodelogging";
|
|
||||||
import { Lock } from "@hibas123/utils";
|
import { Lock } from "@hibas123/utils";
|
||||||
|
|
||||||
interface IDatabaseConfig {
|
interface IDatabaseConfig {
|
||||||
@ -9,19 +6,9 @@ interface IDatabaseConfig {
|
|||||||
publickey?: string;
|
publickey?: string;
|
||||||
rules?: string;
|
rules?: string;
|
||||||
accesskey?: string;
|
accesskey?: string;
|
||||||
|
rootkey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const DatabaseEncoder = new Encoder<IDatabaseConfig>({
|
|
||||||
// publickey: {
|
|
||||||
// index: 1,
|
|
||||||
// type: DataTypes.STRING,
|
|
||||||
// allowNull: true
|
|
||||||
// },
|
|
||||||
// rules: {
|
|
||||||
// index: 2,
|
|
||||||
// type: DataTypes.STRING
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
class SettingComponent {
|
class SettingComponent {
|
||||||
db = getLevelDB("_server");
|
db = getLevelDB("_server");
|
||||||
@ -54,7 +41,8 @@ class SettingComponent {
|
|||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.getField(database, "publickey").then(r => res.publickey = r),
|
this.getField(database, "publickey").then(r => res.publickey = r),
|
||||||
this.getField(database, "rules").then(r => res.rules = r),
|
this.getField(database, "rules").then(r => res.rules = r),
|
||||||
this.getField(database, "accesskey").then(r => res.accesskey = r)
|
this.getField(database, "accesskey").then(r => res.accesskey = r),
|
||||||
|
this.getField(database, "rootkey").then(r => res.rootkey = r)
|
||||||
])
|
])
|
||||||
return res;
|
return res;
|
||||||
})))
|
})))
|
||||||
@ -107,6 +95,14 @@ class SettingComponent {
|
|||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setDatabaseRootKey(name: string, accesskey: string) {
|
||||||
|
const lock = await this.databaseLock.getLock();
|
||||||
|
|
||||||
|
await this.setField(name, "rootkey", accesskey);
|
||||||
|
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
async deleteDatabase(name: string) {
|
async deleteDatabase(name: string) {
|
||||||
const lock = await this.databaseLock.getLock();
|
const lock = await this.databaseLock.getLock();
|
||||||
|
|
||||||
@ -119,6 +115,7 @@ class SettingComponent {
|
|||||||
.del(pref + ":publickey")
|
.del(pref + ":publickey")
|
||||||
.del(pref + ":rules")
|
.del(pref + ":rules")
|
||||||
.del(pref + ":accesskey")
|
.del(pref + ":accesskey")
|
||||||
|
.del(pref + ":rootkey")
|
||||||
.write();
|
.write();
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
|
@ -42,7 +42,7 @@ const cache = new Map<string, Handlebars.TemplateDelegate>();
|
|||||||
|
|
||||||
export default function getTemplate(name: string) {
|
export default function getTemplate(name: string) {
|
||||||
let tl: Handlebars.TemplateDelegate;
|
let tl: Handlebars.TemplateDelegate;
|
||||||
if (!config.general.dev)
|
if (!config.dev)
|
||||||
tl = cache.get(name);
|
tl = cache.get(name);
|
||||||
|
|
||||||
if (!tl) {
|
if (!tl) {
|
||||||
|
@ -2,9 +2,9 @@ import { LoggingBase } from "@hibas123/nodelogging";
|
|||||||
import { Context } from "koa";
|
import { Context } from "koa";
|
||||||
import config from "../../config";
|
import config from "../../config";
|
||||||
|
|
||||||
const route_logging = new LoggingBase({ name: "access", files: { errorfile: null }, console: config.general.dev })
|
const route_logging = new LoggingBase({ name: "access", files: { errorfile: null }, console: config.dev })
|
||||||
const RequestLog = async (ctx: Context, next) => {
|
const RequestLog = async (ctx: Context, next) => {
|
||||||
if (!config.general.access_log) return next();
|
if (!config.access_log) return next();
|
||||||
let start = process.hrtime()
|
let start = process.hrtime()
|
||||||
let to = false
|
let to = false
|
||||||
let print = () => {
|
let print = () => {
|
||||||
|
@ -13,7 +13,7 @@ const AdminRoute = new Router();
|
|||||||
|
|
||||||
AdminRoute.use(async (ctx, next) => {
|
AdminRoute.use(async (ctx, next) => {
|
||||||
const { key } = ctx.query;
|
const { key } = ctx.query;
|
||||||
if (key !== config.general.admin)
|
if (key !== config.admin)
|
||||||
throw new NoPermissionError("No permission!");
|
throw new NoPermissionError("No permission!");
|
||||||
return next();
|
return next();
|
||||||
})
|
})
|
||||||
@ -87,7 +87,7 @@ AdminRoute
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.post("/database", async ctx => {
|
.post("/database", async ctx => {
|
||||||
const { name, rules, publickey, accesskey } = ctx.request.body;
|
const { name, rules, publickey, accesskey, rootkey } = ctx.request.body;
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
throw new BadRequestError("Name must be set!");
|
throw new BadRequestError("Name must be set!");
|
||||||
@ -101,16 +101,22 @@ AdminRoute
|
|||||||
|
|
||||||
if (rules)
|
if (rules)
|
||||||
await db.setRules(rules);
|
await db.setRules(rules);
|
||||||
db
|
|
||||||
if (accesskey)
|
if (accesskey)
|
||||||
await db.setAccessKey(accesskey);
|
await db.setAccessKey(accesskey);
|
||||||
|
|
||||||
|
|
||||||
|
if (rootkey)
|
||||||
|
await db.setRootKey(rootkey);
|
||||||
|
|
||||||
|
|
||||||
ctx.body = "Success";
|
ctx.body = "Success";
|
||||||
})
|
})
|
||||||
|
|
||||||
AdminRoute.get("/database/new", getForm("/v1/admin/database", "New/Change Database", {
|
AdminRoute.get("/database/new", getForm("/v1/admin/database", "New/Change Database", {
|
||||||
name: { label: "Name", type: "text", },
|
name: { label: "Name", type: "text", },
|
||||||
accesskey: { label: "Access Key", type: "text" },
|
accesskey: { label: "Access Key", type: "text" },
|
||||||
|
rootkey: { label: "Root access key", type: "text" },
|
||||||
rules: { label: "Rules", type: "textarea", value: `{\n ".write": true, \n ".read": true \n}` },
|
rules: { label: "Rules", type: "textarea", value: `{\n ".write": true, \n ".read": true \n}` },
|
||||||
publickey: { label: "Public Key", type: "textarea" }
|
publickey: { label: "Public Key", type: "textarea" }
|
||||||
}))
|
}))
|
||||||
|
Reference in New Issue
Block a user