-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
1,069 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
.vscode | ||
/node_modules/ | ||
node_modules | ||
|
||
/data/ | ||
/out/ | ||
/local-stuff/ | ||
data | ||
out | ||
local-stuff | ||
tsconfig.json | ||
*.bat | ||
*.example.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build/ | ||
dist/ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.vscode | ||
node_modules | ||
|
||
data | ||
out | ||
local-stuff | ||
tsconfig.json | ||
*.bat | ||
*.example.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM node:lts-alpine | ||
|
||
WORKDIR /usr/src/app | ||
COPY . /usr/src/app | ||
|
||
ENV NODE_ENV=production | ||
RUN npm ci --omit=dev | ||
|
||
CMD [ "npm", "run", "production" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# MIREA Schedule System | ||
|
||
## Panel | ||
|
||
Panel for changing MSS params, runs behind NGINX, uses Keycloak to validate user. | ||
|
||
## Commands | ||
|
||
1. Install all dependencies `npm ci --only=prod` | ||
2. Run backend `npm run production` | ||
|
||
## Some other files | ||
|
||
`panel.config.json` – Config file with ports, DB, logging, Keycloak, etc. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import fetch from "node-fetch"; | ||
import ReadConfig from "../util/read-config.js"; | ||
|
||
const PANEL_CONFIG = ReadConfig(); | ||
|
||
/** | ||
* @param {string} code | ||
* @returns {Promise<string>} | ||
*/ | ||
export default function ExchangeCodeToToken(code) { | ||
if (!code) return Promise.reject(new Error("No code was passed")); | ||
|
||
return fetch(`${PANEL_CONFIG.KEYCLOAK_ORIGIN}/realms/${PANEL_CONFIG.KEYCLOAK_REALM}/protocol/openid-connect/token`, { | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json", | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
"User-Agent": "MSS-Panel/1.0.0" | ||
}, | ||
body: `client_id=${encodeURIComponent(PANEL_CONFIG.KEYCLOAK_CLIENT_ID)}&client_secret=${encodeURIComponent( | ||
PANEL_CONFIG.KEYCLOAK_CLIENT_SECRET | ||
)}&grant_type=authorization_code&scope=${encodeURIComponent( | ||
["openid", "profile"].join(" ") | ||
)}&code=${encodeURIComponent(code)}&redirect_uri=${encodeURIComponent(PANEL_CONFIG.PANEL_ORIGIN)}` | ||
}) | ||
.then((res) => { | ||
if (!res.ok) | ||
return res.text().then( | ||
(text) => Promise.reject(new Error(`Keycloak returned ${res.status} ${res.statusText} – ${text}`)), | ||
() => () => Promise.reject(new Error(`Keycloak returned ${res.status} ${res.statusText}`)) | ||
); | ||
|
||
return res.json(); | ||
}) | ||
.then( | ||
/** @param {import('../types').TokenResponse} tokenResponse */ (tokenResponse) => | ||
Promise.resolve(tokenResponse.access_token) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import fetch from "node-fetch"; | ||
import ReadConfig from "../util/read-config.js"; | ||
|
||
const PANEL_CONFIG = ReadConfig(); | ||
|
||
/** | ||
* @param {string} token | ||
* @returns {Promise<void>} | ||
*/ | ||
export default function ValidateAccessToken(token) { | ||
if (!token) return Promise.reject(new Error("No token was passed")); | ||
|
||
return fetch( | ||
`${PANEL_CONFIG.KEYCLOAK_ORIGIN}/realms/${PANEL_CONFIG.KEYCLOAK_REALM}/protocol/openid-connect/userinfo`, | ||
{ | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json", | ||
"User-Agent": "MSS-Panel/1.0.0", | ||
Authorization: `Bearer ${token}` | ||
} | ||
} | ||
) | ||
.then((res) => { | ||
if (!res.ok) | ||
return res.text().then( | ||
(text) => Promise.reject(new Error(`Keycloak returned ${res.status} ${res.statusText} – ${text}`)), | ||
() => () => Promise.reject(new Error(`Keycloak returned ${res.status} ${res.statusText}`)) | ||
); | ||
|
||
return res.json(); | ||
}) | ||
.then( | ||
/** @param {import('../types').UserInfo} userInfo */ (userInfo) => | ||
userInfo.email_verified && userInfo.email === PANEL_CONFIG.PANEL_USER_EMAIL | ||
? Promise.resolve() | ||
: Promise.reject(new Error("Email validation failed")) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { MongoClient } from "mongodb"; | ||
import ReadConfig from "../util/read-config.js"; | ||
import Logging from "../util/logging.js"; | ||
|
||
const MONGO_CONNECTION_URL = ReadConfig().DATABASE_CONNECTION_URI || "mongodb://127.0.0.1:27017/"; | ||
|
||
/** | ||
* @callback MongoDispatcherCallback | ||
* @param {import("mongodb").Db} db | ||
* @returns {void} | ||
*/ | ||
|
||
/** | ||
* @class | ||
* @classdesc Various events and callbacks for DB | ||
*/ | ||
export default class MongoDispatcher { | ||
/** | ||
* @param {string} dbName | ||
*/ | ||
constructor(dbName) { | ||
/** | ||
* @private | ||
* @type {DB} | ||
*/ | ||
this.DB = null; | ||
|
||
/** | ||
* @private | ||
* @type {{[eventName: string]: MongoDispatcherCallback[]}} | ||
*/ | ||
this.events = {}; | ||
|
||
MongoClient.connect(MONGO_CONNECTION_URL, {}) | ||
.then((connectedClient) => { | ||
this.DB = connectedClient.db(dbName); | ||
|
||
this.on("close", () => { | ||
this.DB = null; | ||
connectedClient.close(); | ||
}); | ||
}) | ||
.catch((e) => { | ||
Logging("Error with connection to MongoDB on start-up", mongoError); | ||
}); | ||
} | ||
|
||
/** | ||
* @param {string} eventName | ||
* @param {MongoDispatcherCallback} eventHandler | ||
* @returns {void} | ||
*/ | ||
on(eventName, eventHandler) { | ||
if (!this.events[eventName] || !(this.events[eventName] instanceof Array)) this.events[eventName] = []; | ||
|
||
this.events[eventName].push(eventHandler); | ||
} | ||
|
||
/** | ||
* @param {string} eventName | ||
* @returns {void} | ||
*/ | ||
off(eventName) { | ||
delete this.events[eventName]; | ||
} | ||
|
||
/** | ||
* @param {string} eventName | ||
* @returns {void} | ||
*/ | ||
dispatchEvent(eventName) { | ||
if (this.events[eventName] && this.events[eventName] instanceof Array) | ||
this.events[eventName].forEach((eventHandler) => { | ||
if (typeof eventHandler == "function") eventHandler(this.DB); | ||
}); | ||
} | ||
|
||
/** | ||
* @returns {void} | ||
*/ | ||
closeConnection() { | ||
this.dispatchEvent("close"); | ||
} | ||
|
||
/** | ||
* @returns {Promise<import('mongodb').Db>} | ||
*/ | ||
callDB() { | ||
return new Promise((resolve) => { | ||
if (this.DB) return resolve(this.DB); | ||
|
||
const waitingInterval = setInterval(() => { | ||
if (this.DB) { | ||
clearInterval(waitingInterval); | ||
resolve(this.DB); | ||
} | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import ReadConfig from "../util/read-config.js"; | ||
import MongoDispatcher from "./dispatcher.js"; | ||
|
||
const mongoDispatcher = new MongoDispatcher(ReadConfig().DATABASE_NAME); | ||
|
||
const DB_METHODS = { | ||
listAllParams() { | ||
return mongoDispatcher | ||
.callDB() | ||
.then((db) => db.collection("params").find({}).project({ name: true, value: true, _id: false }).toArray()); | ||
}, | ||
|
||
/** | ||
* @param {{ name: string, value: any }} [payload] | ||
*/ | ||
setParam(payload) { | ||
if (typeof payload !== "object") return Promise.reject(new Error("Malformed payload")); | ||
if (!("name" in payload)) return Promise.reject(new Error("Missing name")); | ||
if (!("value" in payload)) return Promise.reject(new Error("Missing value")); | ||
if (typeof payload.name !== "string") return Promise.reject(new Error("Malformed name")); | ||
|
||
const trueParamValue = | ||
payload.name === "start_of_weeks" | ||
? parseInt(payload.value) | ||
: payload.name === "scrapper_updated_date" | ||
? new Date(payload.value) | ||
: payload.name === "scrapper_interval_seconds" | ||
? parseInt(payload.value) | ||
: payload.value; | ||
|
||
return mongoDispatcher | ||
.callDB() | ||
.then((db) => | ||
db.collection("params").updateOne({ name: payload.name }, { $set: { value: trueParamValue } }, { upsert: true }) | ||
) | ||
.then((updateResult) => Promise.resolve(updateResult.modifiedCount)); | ||
} | ||
}; | ||
|
||
export default DB_METHODS; |
Oops, something went wrong.