diff --git a/src/lib/permissions.ts b/src/lib/permissions.ts index c7a49c6..f87051a 100644 --- a/src/lib/permissions.ts +++ b/src/lib/permissions.ts @@ -1,8 +1,12 @@ export enum Permissions { ALL = "*", - VIEW_PROFILE = "view_profile", + VIEW = "view", ADD_PROFILE = "add_profile", - MANAGE_PERMISSIONS = "manage_permissions" + REMOVE_PROFILE = "remove_profile", + VIEW_USERS = "view_users", + ADD_USER = "add_user", + EDIT_USER = "edit_user", + REMOVE_USER = "remove_user" } /** diff --git a/src/server.ts b/src/server.ts index c68e49a..1d6a7bf 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,10 +8,17 @@ import { hash } from "bcrypt"; import { log } from "./logger"; import { Permissions } from "./lib/permissions"; -const { PORT, NODE_ENV, DB_USERNAME, DB_PASSWORD, DB_URL, DB_NAME, API_KEY } = - process.env; +export const { + PORT, + NODE_ENV, + DB_USERNAME, + DB_PASSWORD, + DB_URL, + DB_NAME, + API_KEY +} = process.env; const dev = NODE_ENV === "development"; -const db = arangojs({ +export const db = arangojs({ auth: { username: DB_USERNAME || "root", password: DB_PASSWORD @@ -19,34 +26,83 @@ const db = arangojs({ url: DB_URL || "http://127.0.0.1:8529", databaseName: DB_NAME || "sbdatatracker" }); -const saltRounds = 10; +export const saltRounds = 9; +export const accessTokenExpire = 1000 * 60 * 20; +export const refreshTokenExpire = 1000 * 60 * 60 * 24 * 7; const delay = 3 * 60 * 1000; const intervalFunc = async (db: Database) => { const cnf = db.collection("config"); const users = db.collection("users"); + const sessions = db.collection("sessions"); if (!(await cnf.exists())) { - await cnf.create(); + await cnf.create({ + schema: { + rule: { + properties: { + type: { type: "string" }, + data: { type: "object" } + }, + required: ["type", "data"] + } + } + }); } if (!(await users.exists())) { - await users.create(); + await users.create({ + schema: { + rule: { + properties: { + username: { type: "string" }, + password: { type: "string" }, + permissions: { + type: "array", + items: { type: "string" } + } + }, + required: ["username", "permissions"] + } + } + }); await users.save({ - username: DB_USERNAME, + username: DB_USERNAME || "root", password: await hash(DB_PASSWORD || "SBDataTracker", saltRounds), - forceChangePassword: true, permissions: [Permissions.ALL] }); await users.save({ username: "_guest", - permissions: [Permissions.VIEW_PROFILE] + permissions: [Permissions.VIEW] }); } + if (!(await sessions.exists())) { + await sessions.create({ + schema: { + rule: { + properties: { + token: { type: "string" }, + exp: { type: "number" }, + type: { type: "string" }, + user: { type: "string" } + }, + required: ["token", "exp", "type", "user"] + } + } + }); + } + + // Delete expired sessions + const now = Date.now(); + await db.query(aql` + FOR doc in ${sessions} + FILTER doc.exp <= ${now} + REMOVE doc in ${sessions} + `); const cursor = await db.query( aql` FOR doc IN ${cnf} FILTER doc.type == "tracker" - RETURN doc + RETURN { _key: doc._key } `, { count: true @@ -65,28 +121,29 @@ const intervalFunc = async (db: Database) => { let counter = 0; let interval: NodeJS.Timeout; const iterate = async () => { - if (++counter >= (cursor.count as number)) clearInterval(interval); + try { + if (++counter >= cursor.count!) clearInterval(interval); - const { _key, profile } = await cursor.next(); - if (profile) { - const col = db.collection(`c${profile}`); - if (!(await col.exists())) col.create(); - - await col.save(await log(API_KEY || "", profile)); - } else { - console.warn( - `Configuration entry '${_key}' with type 'tracker' has no "profile" value` - ); + const { _key: profile } = await cursor.next(); + if (profile) { + const col = db.collection(`c${profile}`); + if (!(await col.exists())) col.create(); + console.log(`${new Date()}\tLogging '${profile}'`); + await col.save(await log(API_KEY || "", profile)); + } else { + console.warn( + `Configuration entry '${profile}' with type 'tracker' has no "profile" value` + ); + } + } catch (e) { + console.error(e); } }; // Separated into setInterval and a setTimeout so when the script is started, // immediately at least one profile is logged. This is useful for debugging // since you don't have to wait for up to 3 minutes to pass. - if ((cursor.count as number) > 1) - interval = setInterval( - iterate, - delay / ((cursor.count as number) - 1) - ); + if (cursor.count! > 1) + interval = setInterval(iterate, delay / (cursor.count! - 1)); setTimeout(iterate); } };