mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-27 16:54:04 +00:00
Add JSDoc to server/*
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
This commit is contained in:
parent
45f44b183d
commit
03b2d8d521
14 changed files with 380 additions and 60 deletions
|
@ -1,8 +1,12 @@
|
||||||
const { checkLogin } = require("./util-server");
|
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
class TwoFA {
|
class TwoFA {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable 2FA for specified user
|
||||||
|
* @param {number} userID ID of user to disable
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
static async disable2FA(userID) {
|
static async disable2FA(userID) {
|
||||||
return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [
|
return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [
|
||||||
userID,
|
userID,
|
||||||
|
|
|
@ -6,10 +6,10 @@ const { debug } = require("../src/util");
|
||||||
const { loginRateLimiter } = require("./rate-limiter");
|
const { loginRateLimiter } = require("./rate-limiter");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Login to web app
|
||||||
* @param username : string
|
* @param {string} username
|
||||||
* @param password : string
|
* @param {string} password
|
||||||
* @returns {Promise<Bean|null>}
|
* @returns {Promise<(Bean|null)>}
|
||||||
*/
|
*/
|
||||||
exports.login = async function (username, password) {
|
exports.login = async function (username, password) {
|
||||||
let user = await R.findOne("user", " username = ? AND active = 1 ", [
|
let user = await R.findOne("user", " username = ? AND active = 1 ", [
|
||||||
|
@ -30,6 +30,19 @@ exports.login = async function (username, password) {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for myAuthorizer
|
||||||
|
* @callback myAuthorizerCB
|
||||||
|
* @param {any} err Any error encountered
|
||||||
|
* @param {boolean} authorized Is the client authorized?
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom authorizer for express-basic-auth
|
||||||
|
* @param {string} username
|
||||||
|
* @param {string} password
|
||||||
|
* @param {myAuthorizerCB} callback
|
||||||
|
*/
|
||||||
function myAuthorizer(username, password, callback) {
|
function myAuthorizer(username, password, callback) {
|
||||||
setting("disableAuth").then((result) => {
|
setting("disableAuth").then((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ exports.latestVersion = null;
|
||||||
|
|
||||||
let interval;
|
let interval;
|
||||||
|
|
||||||
|
/** Start 48 hour check interval */
|
||||||
exports.startInterval = () => {
|
exports.startInterval = () => {
|
||||||
let check = async () => {
|
let check = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -28,6 +29,11 @@ exports.startInterval = () => {
|
||||||
interval = setInterval(check, 3600 * 1000 * 48);
|
interval = setInterval(check, 3600 * 1000 * 48);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the check update feature
|
||||||
|
* @param {boolean} value Should the check update feature be enabled?
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
exports.enableCheckUpdate = async (value) => {
|
exports.enableCheckUpdate = async (value) => {
|
||||||
await setSetting("checkUpdate", value);
|
await setSetting("checkUpdate", value);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,11 @@ const { io } = require("./server");
|
||||||
const { setting } = require("./util-server");
|
const { setting } = require("./util-server");
|
||||||
const checkVersion = require("./check-version");
|
const checkVersion = require("./check-version");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send list of notification providers to client
|
||||||
|
* @param {Socket} socket Socket.io socket instance
|
||||||
|
* @returns {Promise<Bean[]>}
|
||||||
|
*/
|
||||||
async function sendNotificationList(socket) {
|
async function sendNotificationList(socket) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
@ -28,8 +33,11 @@ async function sendNotificationList(socket) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send Heartbeat History list to socket
|
* Send Heartbeat History list to socket
|
||||||
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
* @param {Socket} socket Socket.io instance
|
||||||
* @param overwrite Overwrite client-side's heartbeat list
|
* @param {number} monitorID ID of monitor to send heartbeat history
|
||||||
|
* @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
|
* @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
@ -56,10 +64,11 @@ async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite =
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Important Heart beat list (aka event list)
|
* Important Heart beat list (aka event list)
|
||||||
* @param socket
|
* @param {Socket} socket Socket.io instance
|
||||||
* @param monitorID
|
* @param {number} monitorID ID of monitor to send heartbeat history
|
||||||
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
* @param {boolean} [toUser=false] True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
* @param overwrite Overwrite client-side's heartbeat list
|
* @param {boolean} [overwrite=false] Overwrite client-side's heartbeat list
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
@ -83,6 +92,11 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send application info
|
||||||
|
* @param {Socket} socket Socket.io socket instance
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function sendInfo(socket) {
|
async function sendInfo(socket) {
|
||||||
socket.emit("info", {
|
socket.emit("info", {
|
||||||
version: checkVersion.version,
|
version: checkVersion.version,
|
||||||
|
|
|
@ -63,6 +63,10 @@ class Database {
|
||||||
|
|
||||||
static noReject = true;
|
static noReject = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the database
|
||||||
|
* @param {Object} args Arguments to initialize DB with
|
||||||
|
*/
|
||||||
static init(args) {
|
static init(args) {
|
||||||
// Data Directory (must be end with "/")
|
// Data Directory (must be end with "/")
|
||||||
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
|
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
|
||||||
|
@ -80,6 +84,12 @@ class Database {
|
||||||
console.log(`Data Dir: ${Database.dataDir}`);
|
console.log(`Data Dir: ${Database.dataDir}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the database
|
||||||
|
* @param {boolean} [testMode=false] Should the connection be
|
||||||
|
* started in test mode?
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
static async connect(testMode = false) {
|
static async connect(testMode = false) {
|
||||||
const acquireConnectionTimeout = 120 * 1000;
|
const acquireConnectionTimeout = 120 * 1000;
|
||||||
|
|
||||||
|
@ -129,6 +139,7 @@ class Database {
|
||||||
console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()"));
|
console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Patch the database */
|
||||||
static async patch() {
|
static async patch() {
|
||||||
let version = parseInt(await setting("database_version"));
|
let version = parseInt(await setting("database_version"));
|
||||||
|
|
||||||
|
@ -173,7 +184,9 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Patch DB using new process
|
||||||
* Call it from patch() only
|
* Call it from patch() only
|
||||||
|
* @private
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async patch2() {
|
static async patch2() {
|
||||||
|
@ -212,9 +225,12 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Patch database using new patching process
|
||||||
* Used it patch2() only
|
* Used it patch2() only
|
||||||
|
* @private
|
||||||
* @param sqlFilename
|
* @param sqlFilename
|
||||||
* @param databasePatchedFiles
|
* @param databasePatchedFiles
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
|
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
|
||||||
let value = this.patchList[sqlFilename];
|
let value = this.patchList[sqlFilename];
|
||||||
|
@ -249,12 +265,12 @@ class Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself
|
* Load an SQL file and execute it
|
||||||
* @param filename
|
* @param filename Filename of SQL file to import
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async importSQLFile(filename) {
|
static async importSQLFile(filename) {
|
||||||
|
// Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself
|
||||||
await R.getCell("SELECT 1");
|
await R.getCell("SELECT 1");
|
||||||
|
|
||||||
let text = fs.readFileSync(filename).toString();
|
let text = fs.readFileSync(filename).toString();
|
||||||
|
@ -282,6 +298,10 @@ class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aquire a direct connection to database
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
static getBetterSQLite3Database() {
|
static getBetterSQLite3Database() {
|
||||||
return R.knex.client.acquireConnection();
|
return R.knex.client.acquireConnection();
|
||||||
}
|
}
|
||||||
|
@ -317,7 +337,7 @@ class Database {
|
||||||
/**
|
/**
|
||||||
* One backup one time in this process.
|
* One backup one time in this process.
|
||||||
* Reset this.backupPath if you want to backup again
|
* Reset this.backupPath if you want to backup again
|
||||||
* @param version
|
* @param {string} version Version code of backup
|
||||||
*/
|
*/
|
||||||
static backup(version) {
|
static backup(version) {
|
||||||
if (! this.backupPath) {
|
if (! this.backupPath) {
|
||||||
|
@ -339,9 +359,7 @@ class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Restore from most recent backup */
|
||||||
*
|
|
||||||
*/
|
|
||||||
static restore() {
|
static restore() {
|
||||||
if (this.backupPath) {
|
if (this.backupPath) {
|
||||||
console.error("Patching the database failed!!! Restoring the backup");
|
console.error("Patching the database failed!!! Restoring the backup");
|
||||||
|
@ -383,6 +401,7 @@ class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the size of the database */
|
||||||
static getSize() {
|
static getSize() {
|
||||||
debug("Database.getSize()");
|
debug("Database.getSize()");
|
||||||
let stats = fs.statSync(Database.path);
|
let stats = fs.statSync(Database.path);
|
||||||
|
@ -390,6 +409,10 @@ class Database {
|
||||||
return stats.size;
|
return stats.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shrink the database
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
static async shrink() {
|
static async shrink() {
|
||||||
await R.exec("VACUUM");
|
await R.exec("VACUUM");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ let fs = require("fs");
|
||||||
|
|
||||||
let ImageDataURI = (() => {
|
let ImageDataURI = (() => {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the data:image/ URI
|
||||||
|
* @param {string} dataURI data:image/ URI to decode
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
function decode(dataURI) {
|
function decode(dataURI) {
|
||||||
if (!/data:image\//.test(dataURI)) {
|
if (!/data:image\//.test(dataURI)) {
|
||||||
console.log("ImageDataURI :: Error :: It seems that it is not an Image Data URI. Couldn't match \"data:image/\"");
|
console.log("ImageDataURI :: Error :: It seems that it is not an Image Data URI. Couldn't match \"data:image/\"");
|
||||||
|
@ -20,6 +25,12 @@ let ImageDataURI = (() => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endcode an image into data:image/ URI
|
||||||
|
* @param {(Buffer|string)} data Data to encode
|
||||||
|
* @param {string} mediaType Media type of data
|
||||||
|
* @returns {(string|null)}
|
||||||
|
*/
|
||||||
function encode(data, mediaType) {
|
function encode(data, mediaType) {
|
||||||
if (!data || !mediaType) {
|
if (!data || !mediaType) {
|
||||||
console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType ");
|
console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType ");
|
||||||
|
@ -33,6 +44,12 @@ let ImageDataURI = (() => {
|
||||||
return dataImgBase64;
|
return dataImgBase64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data URI to file
|
||||||
|
* @param {string} dataURI data:image/ URI
|
||||||
|
* @param {string} filePath Path to write file to
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
function outputFile(dataURI, filePath) {
|
function outputFile(dataURI, filePath) {
|
||||||
filePath = filePath || "./";
|
filePath = filePath || "./";
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
@ -9,6 +9,11 @@ const jobs = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize background jobs
|
||||||
|
* @param {Object} args Arguments to pass to workers
|
||||||
|
* @returns {Bree}
|
||||||
|
*/
|
||||||
const initBackgroundJobs = function (args) {
|
const initBackgroundJobs = function (args) {
|
||||||
const bree = new Bree({
|
const bree = new Bree({
|
||||||
root: path.resolve("server", "jobs"),
|
root: path.resolve("server", "jobs"),
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Notification {
|
||||||
|
|
||||||
providerList = {};
|
providerList = {};
|
||||||
|
|
||||||
|
/** Initialize the notification providers */
|
||||||
static init() {
|
static init() {
|
||||||
console.log("Prepare Notification Providers");
|
console.log("Prepare Notification Providers");
|
||||||
|
|
||||||
|
@ -81,13 +82,13 @@ class Notification {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Send a notification
|
||||||
* @param notification : BeanModel
|
* @param {BeanModel} notification
|
||||||
* @param msg : string General Message
|
* @param {string} msg General Message
|
||||||
* @param monitorJSON : object Monitor details (For Up/Down only)
|
* @param {Object} monitorJSON Monitor details (For Up/Down only)
|
||||||
* @param heartbeatJSON : object Heartbeat details (For Up/Down only)
|
* @param {Object} heartbeatJSON Heartbeat details (For Up/Down only)
|
||||||
* @returns {Promise<string>} Successful msg
|
* @returns {Promise<string>} Successful msg
|
||||||
* Throw Error with fail msg
|
* @throws Error with fail msg
|
||||||
*/
|
*/
|
||||||
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
if (this.providerList[notification.type]) {
|
if (this.providerList[notification.type]) {
|
||||||
|
@ -97,28 +98,35 @@ class Notification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a notification
|
||||||
|
* @param {Object} notification Notification to save
|
||||||
|
* @param {?number} notificationID ID of notification to update
|
||||||
|
* @param {number} userID ID of user who adds notification
|
||||||
|
* @returns {Promise<Bean>}
|
||||||
|
*/
|
||||||
static async save(notification, notificationID, userID) {
|
static async save(notification, notificationID, userID) {
|
||||||
let bean
|
let bean;
|
||||||
|
|
||||||
if (notificationID) {
|
if (notificationID) {
|
||||||
bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
||||||
notificationID,
|
notificationID,
|
||||||
userID,
|
userID,
|
||||||
])
|
]);
|
||||||
|
|
||||||
if (! bean) {
|
if (! bean) {
|
||||||
throw new Error("notification not found")
|
throw new Error("notification not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bean = R.dispense("notification")
|
bean = R.dispense("notification");
|
||||||
}
|
}
|
||||||
|
|
||||||
bean.name = notification.name;
|
bean.name = notification.name;
|
||||||
bean.user_id = userID;
|
bean.user_id = userID;
|
||||||
bean.config = JSON.stringify(notification);
|
bean.config = JSON.stringify(notification);
|
||||||
bean.is_default = notification.isDefault || false;
|
bean.is_default = notification.isDefault || false;
|
||||||
await R.store(bean)
|
await R.store(bean);
|
||||||
|
|
||||||
if (notification.applyExisting) {
|
if (notification.applyExisting) {
|
||||||
await applyNotificationEveryMonitor(bean.id, userID);
|
await applyNotificationEveryMonitor(bean.id, userID);
|
||||||
|
@ -127,19 +135,29 @@ class Notification {
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a notification
|
||||||
|
* @param {number} notificationID ID of notification to delete
|
||||||
|
* @param {number} userID ID of user who created notification
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
static async delete(notificationID, userID) {
|
static async delete(notificationID, userID) {
|
||||||
let bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
let bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
|
||||||
notificationID,
|
notificationID,
|
||||||
userID,
|
userID,
|
||||||
])
|
]);
|
||||||
|
|
||||||
if (! bean) {
|
if (! bean) {
|
||||||
throw new Error("notification not found")
|
throw new Error("notification not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
await R.trash(bean)
|
await R.trash(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if apprise exists
|
||||||
|
* @returns {boolean} Does the command apprise exist?
|
||||||
|
*/
|
||||||
static checkApprise() {
|
static checkApprise() {
|
||||||
let commandExistsSync = require("command-exists").sync;
|
let commandExistsSync = require("command-exists").sync;
|
||||||
let exists = commandExistsSync("apprise");
|
let exists = commandExistsSync("apprise");
|
||||||
|
@ -148,6 +166,12 @@ class Notification {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the notification to every monitor
|
||||||
|
* @param {number} notificationID ID of notification to apply
|
||||||
|
* @param {number} userID ID of user who created notification
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function applyNotificationEveryMonitor(notificationID, userID) {
|
async function applyNotificationEveryMonitor(notificationID, userID) {
|
||||||
let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [
|
let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [
|
||||||
userID
|
userID
|
||||||
|
@ -157,17 +181,17 @@ async function applyNotificationEveryMonitor(notificationID, userID) {
|
||||||
let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [
|
let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [
|
||||||
monitors[i].id,
|
monitors[i].id,
|
||||||
notificationID,
|
notificationID,
|
||||||
])
|
]);
|
||||||
|
|
||||||
if (! checkNotification) {
|
if (! checkNotification) {
|
||||||
let relation = R.dispense("monitor_notification");
|
let relation = R.dispense("monitor_notification");
|
||||||
relation.monitor_id = monitors[i].id;
|
relation.monitor_id = monitors[i].id;
|
||||||
relation.notification_id = notificationID;
|
relation.notification_id = notificationID;
|
||||||
await R.store(relation)
|
await R.store(relation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Notification,
|
Notification,
|
||||||
}
|
};
|
||||||
|
|
|
@ -2,22 +2,42 @@ const passwordHashOld = require("password-hash");
|
||||||
const bcrypt = require("bcryptjs");
|
const bcrypt = require("bcryptjs");
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash a password
|
||||||
|
* @param {string} password
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
exports.generate = function (password) {
|
exports.generate = function (password) {
|
||||||
return bcrypt.hashSync(password, saltRounds);
|
return bcrypt.hashSync(password, saltRounds);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a password against a hash
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} hash
|
||||||
|
* @returns {boolean} Does the password match the hash?
|
||||||
|
*/
|
||||||
exports.verify = function (password, hash) {
|
exports.verify = function (password, hash) {
|
||||||
if (isSHA1(hash)) {
|
if (isSHA1(hash)) {
|
||||||
return passwordHashOld.verify(password, hash)
|
return passwordHashOld.verify(password, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bcrypt.compareSync(password, hash);
|
return bcrypt.compareSync(password, hash);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the hash a SHA1 hash
|
||||||
|
* @param {string} hash
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
function isSHA1(hash) {
|
function isSHA1(hash) {
|
||||||
return (typeof hash === "string" && hash.startsWith("sha1"))
|
return (typeof hash === "string" && hash.startsWith("sha1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the hash need to be rehashed?
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
exports.needRehash = function (hash) {
|
exports.needRehash = function (hash) {
|
||||||
return isSHA1(hash);
|
return isSHA1(hash);
|
||||||
}
|
};
|
||||||
|
|
|
@ -8,6 +8,11 @@ const util = require("./util-server");
|
||||||
|
|
||||||
module.exports = Ping;
|
module.exports = Ping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for ping class
|
||||||
|
* @param {string} host Host to ping
|
||||||
|
* @param {string} options Command line options for ping
|
||||||
|
*/
|
||||||
function Ping(host, options) {
|
function Ping(host, options) {
|
||||||
if (!host) {
|
if (!host) {
|
||||||
throw new Error("You must specify a host to ping!");
|
throw new Error("You must specify a host to ping!");
|
||||||
|
@ -75,8 +80,17 @@ function Ping(host, options) {
|
||||||
|
|
||||||
Ping.prototype.__proto__ = events.EventEmitter.prototype;
|
Ping.prototype.__proto__ = events.EventEmitter.prototype;
|
||||||
|
|
||||||
// SEND A PING
|
/**
|
||||||
// ===========
|
* Callback for send
|
||||||
|
* @callback pingCB
|
||||||
|
* @param {any} err Any error encountered
|
||||||
|
* @param {number} ms Ping time in ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a ping
|
||||||
|
* @param {pingCB} callback Callback to call with results
|
||||||
|
*/
|
||||||
Ping.prototype.send = function (callback) {
|
Ping.prototype.send = function (callback) {
|
||||||
let self = this;
|
let self = this;
|
||||||
callback = callback || function (err, ms) {
|
callback = callback || function (err, ms) {
|
||||||
|
@ -145,8 +159,10 @@ Ping.prototype.send = function (callback) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// CALL Ping#send(callback) ON A TIMER
|
/**
|
||||||
// ===================================
|
* Ping every interval
|
||||||
|
* @param {pingCB} callback Callback to call with results
|
||||||
|
*/
|
||||||
Ping.prototype.start = function (callback) {
|
Ping.prototype.start = function (callback) {
|
||||||
let self = this;
|
let self = this;
|
||||||
this._i = setInterval(function () {
|
this._i = setInterval(function () {
|
||||||
|
@ -155,8 +171,7 @@ Ping.prototype.start = function (callback) {
|
||||||
self.send(callback);
|
self.send(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
// STOP SENDING PINGS
|
/** Stop sending pings */
|
||||||
// ==================
|
|
||||||
Ping.prototype.stop = function () {
|
Ping.prototype.stop = function () {
|
||||||
clearInterval(this._i);
|
clearInterval(this._i);
|
||||||
};
|
};
|
||||||
|
@ -165,7 +180,7 @@ Ping.prototype.stop = function () {
|
||||||
* Try to convert to UTF-8 for Windows, as the ping's output on Windows is not UTF-8 and could be in other languages
|
* Try to convert to UTF-8 for Windows, as the ping's output on Windows is not UTF-8 and could be in other languages
|
||||||
* Thank @pemassi
|
* Thank @pemassi
|
||||||
* https://github.com/louislam/uptime-kuma/issues/570#issuecomment-941984094
|
* https://github.com/louislam/uptime-kuma/issues/570#issuecomment-941984094
|
||||||
* @param data
|
* @param {any} data
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function convertOutput(data) {
|
function convertOutput(data) {
|
||||||
|
|
|
@ -34,6 +34,9 @@ const monitor_status = new PrometheusClient.Gauge({
|
||||||
class Prometheus {
|
class Prometheus {
|
||||||
monitorLabelValues = {}
|
monitorLabelValues = {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} monitor Monitor object to monitor
|
||||||
|
*/
|
||||||
constructor(monitor) {
|
constructor(monitor) {
|
||||||
this.monitorLabelValues = {
|
this.monitorLabelValues = {
|
||||||
monitor_name: monitor.name,
|
monitor_name: monitor.name,
|
||||||
|
@ -44,6 +47,11 @@ class Prometheus {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the metrics page
|
||||||
|
* @param {Object} heartbeat Heartbeat details
|
||||||
|
* @param {Object} tlsInfo TLS details
|
||||||
|
*/
|
||||||
update(heartbeat, tlsInfo) {
|
update(heartbeat, tlsInfo) {
|
||||||
|
|
||||||
if (typeof tlsInfo !== "undefined") {
|
if (typeof tlsInfo !== "undefined") {
|
||||||
|
|
|
@ -2,11 +2,26 @@ const { RateLimiter } = require("limiter");
|
||||||
const { debug } = require("../src/util");
|
const { debug } = require("../src/util");
|
||||||
|
|
||||||
class KumaRateLimiter {
|
class KumaRateLimiter {
|
||||||
|
/**
|
||||||
|
* @param {Object} config Rate limiter configuration object
|
||||||
|
*/
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.errorMessage = config.errorMessage;
|
this.errorMessage = config.errorMessage;
|
||||||
this.rateLimiter = new RateLimiter(config);
|
this.rateLimiter = new RateLimiter(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for pass
|
||||||
|
* @callback passCB
|
||||||
|
* @param {Object} err Too many requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should the request be passed through
|
||||||
|
* @param {passCB} callback
|
||||||
|
* @param {number} [num=1] Number of tokens to remove
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
async pass(callback, num = 1) {
|
async pass(callback, num = 1) {
|
||||||
const remainingRequests = await this.removeTokens(num);
|
const remainingRequests = await this.removeTokens(num);
|
||||||
debug("Rate Limit (remainingRequests):" + remainingRequests);
|
debug("Rate Limit (remainingRequests):" + remainingRequests);
|
||||||
|
@ -22,6 +37,11 @@ class KumaRateLimiter {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given number of tokens
|
||||||
|
* @param {number} [num=1] Number of tokens to remove
|
||||||
|
* @returns {Promise<number>}
|
||||||
|
*/
|
||||||
async removeTokens(num = 1) {
|
async removeTokens(num = 1) {
|
||||||
return await this.rateLimiter.removeTokens(num);
|
return await this.rateLimiter.removeTokens(num);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1362,6 +1362,13 @@ exports.entryPage = "dashboard";
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update notifications for a given monitor
|
||||||
|
* @param {number} monitorID ID of monitor to update
|
||||||
|
* @param {Array<number>} notificationIDList List of new notification
|
||||||
|
* providers to add
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function updateMonitorNotification(monitorID, notificationIDList) {
|
async function updateMonitorNotification(monitorID, notificationIDList) {
|
||||||
await R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [
|
await R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [
|
||||||
monitorID,
|
monitorID,
|
||||||
|
@ -1377,6 +1384,13 @@ async function updateMonitorNotification(monitorID, notificationIDList) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given user owns a specific monitor
|
||||||
|
* @param {number} userID
|
||||||
|
* @param {number} monitorID
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @throws {Error} The specified user does not own the monitor
|
||||||
|
*/
|
||||||
async function checkOwner(userID, monitorID) {
|
async function checkOwner(userID, monitorID) {
|
||||||
let row = await R.getRow("SELECT id FROM monitor WHERE id = ? AND user_id = ? ", [
|
let row = await R.getRow("SELECT id FROM monitor WHERE id = ? AND user_id = ? ", [
|
||||||
monitorID,
|
monitorID,
|
||||||
|
@ -1388,12 +1402,23 @@ async function checkOwner(userID, monitorID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the monitor list to clients
|
||||||
|
* @param {Socket} socket Socket.io instance
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
async function sendMonitorList(socket) {
|
async function sendMonitorList(socket) {
|
||||||
let list = await getMonitorJSONList(socket.userID);
|
let list = await getMonitorJSONList(socket.userID);
|
||||||
io.to(socket.userID).emit("monitorList", list);
|
io.to(socket.userID).emit("monitorList", list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called after user login
|
||||||
|
* @param {Socket} socket Socket.io instance
|
||||||
|
* @param {Object} user User object
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function afterLogin(socket, user) {
|
async function afterLogin(socket, user) {
|
||||||
socket.userID = user.id;
|
socket.userID = user.id;
|
||||||
socket.join(user.id);
|
socket.join(user.id);
|
||||||
|
@ -1416,6 +1441,11 @@ async function afterLogin(socket, user) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a JSON representation of monitor list
|
||||||
|
* @param {number} userID
|
||||||
|
* @returns {Promise<Object>}
|
||||||
|
*/
|
||||||
async function getMonitorJSONList(userID) {
|
async function getMonitorJSONList(userID) {
|
||||||
let result = {};
|
let result = {};
|
||||||
|
|
||||||
|
@ -1430,6 +1460,12 @@ async function getMonitorJSONList(userID) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the database
|
||||||
|
* @param {boolean} [testMode=false] Should the connection be
|
||||||
|
* started in test mode?
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function initDatabase(testMode = false) {
|
async function initDatabase(testMode = false) {
|
||||||
if (! fs.existsSync(Database.path)) {
|
if (! fs.existsSync(Database.path)) {
|
||||||
console.log("Copying Database");
|
console.log("Copying Database");
|
||||||
|
@ -1464,6 +1500,12 @@ async function initDatabase(testMode = false) {
|
||||||
jwtSecret = jwtSecretBean.value;
|
jwtSecret = jwtSecretBean.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the specified monitor
|
||||||
|
* @param {number} userID ID of user who owns monitor
|
||||||
|
* @param {number} monitorID ID of monitor to start
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function startMonitor(userID, monitorID) {
|
async function startMonitor(userID, monitorID) {
|
||||||
await checkOwner(userID, monitorID);
|
await checkOwner(userID, monitorID);
|
||||||
|
|
||||||
|
@ -1486,10 +1528,22 @@ async function startMonitor(userID, monitorID) {
|
||||||
monitor.start(io);
|
monitor.start(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart a given monitor
|
||||||
|
* @param {number} userID ID of user who owns monitor
|
||||||
|
* @param {number} monitorID ID of monitor to start
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function restartMonitor(userID, monitorID) {
|
async function restartMonitor(userID, monitorID) {
|
||||||
return await startMonitor(userID, monitorID);
|
return await startMonitor(userID, monitorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause a given monitor
|
||||||
|
* @param {number} userID ID of user who owns monitor
|
||||||
|
* @param {number} monitorID ID of monitor to start
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function pauseMonitor(userID, monitorID) {
|
async function pauseMonitor(userID, monitorID) {
|
||||||
await checkOwner(userID, monitorID);
|
await checkOwner(userID, monitorID);
|
||||||
|
|
||||||
|
@ -1505,9 +1559,7 @@ async function pauseMonitor(userID, monitorID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Resume active monitors */
|
||||||
* Resume active monitors
|
|
||||||
*/
|
|
||||||
async function startMonitors() {
|
async function startMonitors() {
|
||||||
let list = await R.find("monitor", " active = 1 ");
|
let list = await R.find("monitor", " active = 1 ");
|
||||||
|
|
||||||
|
@ -1522,6 +1574,11 @@ async function startMonitors() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the application
|
||||||
|
* @param {string} signal Shutdown signal
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
async function shutdownFunction(signal) {
|
async function shutdownFunction(signal) {
|
||||||
console.log("Shutdown requested");
|
console.log("Shutdown requested");
|
||||||
console.log("Called signal: " + signal);
|
console.log("Called signal: " + signal);
|
||||||
|
@ -1535,6 +1592,7 @@ async function shutdownFunction(signal) {
|
||||||
await Database.close();
|
await Database.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Final function called before application exits */
|
||||||
function finalFunction() {
|
function finalFunction() {
|
||||||
console.log("Graceful shutdown successful!");
|
console.log("Graceful shutdown successful!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,12 @@ exports.initJWTSecret = async () => {
|
||||||
return jwtSecretBean;
|
return jwtSecretBean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send TCP request to specified hostname and port
|
||||||
|
* @param {string} hostname Hostname / address of machine
|
||||||
|
* @param {number} port TCP port to test
|
||||||
|
* @returns {Promise<number>} Maximum time in ms rounded to nearest integer
|
||||||
|
*/
|
||||||
exports.tcping = function (hostname, port) {
|
exports.tcping = function (hostname, port) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
tcpp.ping({
|
tcpp.ping({
|
||||||
|
@ -58,6 +64,11 @@ exports.tcping = function (hostname, port) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ping the specified machine
|
||||||
|
* @param {string} hostname Hostname / address of machine
|
||||||
|
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
|
||||||
|
*/
|
||||||
exports.ping = async (hostname) => {
|
exports.ping = async (hostname) => {
|
||||||
try {
|
try {
|
||||||
return await exports.pingAsync(hostname);
|
return await exports.pingAsync(hostname);
|
||||||
|
@ -71,6 +82,12 @@ exports.ping = async (hostname) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ping the specified machine
|
||||||
|
* @param {string} hostname Hostname / address of machine to ping
|
||||||
|
* @param {boolean} ipv6 Should IPv6 be used?
|
||||||
|
* @returns {Promise<number>} Time for ping in ms rounded to nearest integer
|
||||||
|
*/
|
||||||
exports.pingAsync = function (hostname, ipv6 = false) {
|
exports.pingAsync = function (hostname, ipv6 = false) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const ping = new Ping(hostname, {
|
const ping = new Ping(hostname, {
|
||||||
|
@ -89,6 +106,14 @@ exports.pingAsync = function (hostname, ipv6 = false) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// `string[]`, `Object[]` and `Object`.
|
||||||
|
/**
|
||||||
|
* Resolves a given record using the specified DNS server
|
||||||
|
* @param {string} hostname The hostname of the record to lookup
|
||||||
|
* @param {string} resolver_server The DNS server to use
|
||||||
|
* @param {string} rrtype The type of record to request
|
||||||
|
* @returns {Promise<(string[]|Object[]|Object)>}
|
||||||
|
*/
|
||||||
exports.dnsResolve = function (hostname, resolver_server, rrtype) {
|
exports.dnsResolve = function (hostname, resolver_server, rrtype) {
|
||||||
const resolver = new Resolver();
|
const resolver = new Resolver();
|
||||||
resolver.setServers([resolver_server]);
|
resolver.setServers([resolver_server]);
|
||||||
|
@ -113,6 +138,11 @@ exports.dnsResolve = function (hostname, resolver_server, rrtype) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve value of setting based on key
|
||||||
|
* @param {string} key Key of setting to retrieve
|
||||||
|
* @returns {Promise<Object>} Object representation of setting
|
||||||
|
*/
|
||||||
exports.setting = async function (key) {
|
exports.setting = async function (key) {
|
||||||
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
||||||
key,
|
key,
|
||||||
|
@ -127,6 +157,13 @@ exports.setting = async function (key) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the specified setting to specifed value
|
||||||
|
* @param {string} key Key of setting to set
|
||||||
|
* @param {any} value Value to set to
|
||||||
|
* @param {?string} type Type of setting
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
exports.setSetting = async function (key, value, type = null) {
|
exports.setSetting = async function (key, value, type = null) {
|
||||||
let bean = await R.findOne("setting", " `key` = ? ", [
|
let bean = await R.findOne("setting", " `key` = ? ", [
|
||||||
key,
|
key,
|
||||||
|
@ -140,6 +177,11 @@ exports.setSetting = async function (key, value, type = null) {
|
||||||
await R.store(bean);
|
await R.store(bean);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get settings based on type
|
||||||
|
* @param {?string} type The type of setting
|
||||||
|
* @returns {Promise<Bean>}
|
||||||
|
*/
|
||||||
exports.getSettings = async function (type) {
|
exports.getSettings = async function (type) {
|
||||||
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
|
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
|
||||||
type,
|
type,
|
||||||
|
@ -158,6 +200,12 @@ exports.getSettings = async function (type) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set settings based on type
|
||||||
|
* @param {?string} type Type of settings to set
|
||||||
|
* @param {Object} data Values of settings
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
exports.setSettings = async function (type, data) {
|
exports.setSettings = async function (type, data) {
|
||||||
let keyList = Object.keys(data);
|
let keyList = Object.keys(data);
|
||||||
|
|
||||||
|
@ -184,12 +232,23 @@ exports.setSettings = async function (type, data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// ssl-checker by @dyaa
|
// ssl-checker by @dyaa
|
||||||
// param: res - response object from axios
|
//https://github.com/dyaa/ssl-checker/blob/master/src/index.ts
|
||||||
// return an object containing the certificate information
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of days between two dates
|
||||||
|
* @param {Date} validFrom Start date
|
||||||
|
* @param {Date} validTo End date
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
const getDaysBetween = (validFrom, validTo) =>
|
const getDaysBetween = (validFrom, validTo) =>
|
||||||
Math.round(Math.abs(+validFrom - +validTo) / 8.64e7);
|
Math.round(Math.abs(+validFrom - +validTo) / 8.64e7);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get days remaining from a time range
|
||||||
|
* @param {Date} validFrom Start date
|
||||||
|
* @param {Date} validTo End date
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
const getDaysRemaining = (validFrom, validTo) => {
|
const getDaysRemaining = (validFrom, validTo) => {
|
||||||
const daysRemaining = getDaysBetween(validFrom, validTo);
|
const daysRemaining = getDaysBetween(validFrom, validTo);
|
||||||
if (new Date(validTo).getTime() < new Date().getTime()) {
|
if (new Date(validTo).getTime() < new Date().getTime()) {
|
||||||
|
@ -198,8 +257,11 @@ const getDaysRemaining = (validFrom, validTo) => {
|
||||||
return daysRemaining;
|
return daysRemaining;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fix certificate Info for display
|
/**
|
||||||
// param: info - the chain obtained from getPeerCertificate()
|
* Fix certificate info for display
|
||||||
|
* @param {Object} info The chain obtained from getPeerCertificate()
|
||||||
|
* @returns {Object} An object representing certificate information
|
||||||
|
*/
|
||||||
const parseCertificateInfo = function (info) {
|
const parseCertificateInfo = function (info) {
|
||||||
let link = info;
|
let link = info;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
@ -239,6 +301,11 @@ const parseCertificateInfo = function (info) {
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if certificate is valid
|
||||||
|
* @param {Object} res Response object from axios
|
||||||
|
* @returns {Object} Object containing certificate information
|
||||||
|
*/
|
||||||
exports.checkCertificate = function (res) {
|
exports.checkCertificate = function (res) {
|
||||||
const info = res.request.res.socket.getPeerCertificate(true);
|
const info = res.request.res.socket.getPeerCertificate(true);
|
||||||
const valid = res.request.res.socket.authorized || false;
|
const valid = res.request.res.socket.authorized || false;
|
||||||
|
@ -252,12 +319,13 @@ exports.checkCertificate = function (res) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the provided status code is within the accepted ranges
|
/**
|
||||||
// Param: status - the status code to check
|
* Check if the provided status code is within the accepted ranges
|
||||||
// Param: accepted_codes - an array of accepted status codes
|
* @param {string} status The status code to check
|
||||||
// Return: true if the status code is within the accepted ranges, false otherwise
|
* @param {Array<string>} accepted_codes An array of accepted status codes
|
||||||
// Will throw an error if the provided status code is not a valid range string or code string
|
* @returns {boolean} True if status code within range, false otherwise
|
||||||
|
* @throws {Error} Will throw an error if the provided status code is not a valid range string or code string
|
||||||
|
*/
|
||||||
exports.checkStatusCode = function (status, accepted_codes) {
|
exports.checkStatusCode = function (status, accepted_codes) {
|
||||||
if (accepted_codes == null || accepted_codes.length === 0) {
|
if (accepted_codes == null || accepted_codes.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -281,6 +349,12 @@ exports.checkStatusCode = function (status, accepted_codes) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total number of clients in room
|
||||||
|
* @param {Server} io Socket server instance
|
||||||
|
* @param {string} roomName Name of room to check
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
exports.getTotalClientInRoom = (io, roomName) => {
|
exports.getTotalClientInRoom = (io, roomName) => {
|
||||||
|
|
||||||
const sockets = io.sockets;
|
const sockets = io.sockets;
|
||||||
|
@ -304,23 +378,36 @@ exports.getTotalClientInRoom = (io, roomName) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow CORS all origins if development
|
||||||
|
* @param {Object} res Response object from axios
|
||||||
|
*/
|
||||||
exports.allowDevAllOrigin = (res) => {
|
exports.allowDevAllOrigin = (res) => {
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
exports.allowAllOrigin(res);
|
exports.allowAllOrigin(res);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow CORS all origins
|
||||||
|
* @param {Object} res Response object from axios
|
||||||
|
*/
|
||||||
exports.allowAllOrigin = (res) => {
|
exports.allowAllOrigin = (res) => {
|
||||||
res.header("Access-Control-Allow-Origin", "*");
|
res.header("Access-Control-Allow-Origin", "*");
|
||||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a user is logged in
|
||||||
|
* @param {Socket} socket Socket instance
|
||||||
|
*/
|
||||||
exports.checkLogin = (socket) => {
|
exports.checkLogin = (socket) => {
|
||||||
if (! socket.userID) {
|
if (! socket.userID) {
|
||||||
throw new Error("You are not logged in.");
|
throw new Error("You are not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Start Unit tests */
|
||||||
exports.startUnitTest = async () => {
|
exports.startUnitTest = async () => {
|
||||||
console.log("Starting unit test...");
|
console.log("Starting unit test...");
|
||||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||||
|
@ -341,7 +428,8 @@ exports.startUnitTest = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param body : Buffer
|
* Convert unknown string to UTF8
|
||||||
|
* @param {Uint8Array} body Buffer
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
exports.convertToUTF8 = (body) => {
|
exports.convertToUTF8 = (body) => {
|
||||||
|
@ -359,6 +447,11 @@ try {
|
||||||
});
|
});
|
||||||
} catch (_) { }
|
} catch (_) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write error to log file
|
||||||
|
* @param {any} error The error to write
|
||||||
|
* @param {boolean} outputToConsole Should the error also be output to console?
|
||||||
|
*/
|
||||||
exports.errorLog = (error, outputToConsole = true) => {
|
exports.errorLog = (error, outputToConsole = true) => {
|
||||||
try {
|
try {
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
|
|
Loading…
Reference in a new issue