1
0
Fork 0
mirror of https://github.com/louislam/uptime-kuma.git synced 2025-03-15 04:30:29 +03:00

Refactor modules for improved readability and consistency

Reformatted code across multiple modules, standardizing string quotes, indentation, and spacing. Improved readability by restructuring blocks and aligning object properties consistently. These changes ensure better code maintainability and follow standard conventions.

Signed-off-by: Toby Liddicoat <toby@codesure.co.uk>
This commit is contained in:
Toby Liddicoat 2025-02-27 19:58:07 +00:00
parent 200f179b5f
commit 9081025c4a
35 changed files with 699 additions and 369 deletions

View file

@ -3,7 +3,10 @@ const passwordHash = require("./password-hash");
const { R } = require("redbean-node");
const { setting } = require("./util-server");
const { log } = require("../src/util");
const { loginRateLimiter, apiRateLimiter } = require("./rate-limiter");
const {
loginRateLimiter,
apiRateLimiter,
} = require("./rate-limiter");
const { Settings } = require("./settings");
const dayjs = require("dayjs");

View file

@ -47,10 +47,11 @@ async function sendNotificationList(socket) {
*/
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
let list = await R.getAll(`
SELECT * FROM heartbeat
SELECT *
FROM heartbeat
WHERE monitor_id = ?
ORDER BY time DESC
LIMIT 100
LIMIT 100
`, [
monitorID,
]);

View file

@ -1,7 +1,13 @@
const fs = require("fs");
const { R } = require("redbean-node");
const { setSetting, setting } = require("./util-server");
const { log, sleep } = require("../src/util");
const {
setSetting,
setting,
} = require("./util-server");
const {
log,
sleep,
} = require("../src/util");
const knex = require("knex");
const path = require("path");
const { EmbeddedMariaDB } = require("./embedded-mariadb");
@ -136,24 +142,24 @@ class Database {
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
Database.sqlitePath = path.join(Database.dataDir, "kuma.db");
if (! fs.existsSync(Database.dataDir)) {
if (!fs.existsSync(Database.dataDir)) {
fs.mkdirSync(Database.dataDir, { recursive: true });
}
Database.uploadDir = path.join(Database.dataDir, "upload/");
if (! fs.existsSync(Database.uploadDir)) {
if (!fs.existsSync(Database.uploadDir)) {
fs.mkdirSync(Database.uploadDir, { recursive: true });
}
// Create screenshot dir
Database.screenshotDir = path.join(Database.dataDir, "screenshots/");
if (! fs.existsSync(Database.screenshotDir)) {
if (!fs.existsSync(Database.screenshotDir)) {
fs.mkdirSync(Database.screenshotDir, { recursive: true });
}
Database.dockerTLSDir = path.join(Database.dataDir, "docker-tls/");
if (! fs.existsSync(Database.dockerTLSDir)) {
if (!fs.existsSync(Database.dockerTLSDir)) {
fs.mkdirSync(Database.dockerTLSDir, { recursive: true });
}
@ -231,7 +237,7 @@ class Database {
if (dbConfig.type === "sqlite") {
if (! fs.existsSync(Database.sqlitePath)) {
if (!fs.existsSync(Database.sqlitePath)) {
log.info("server", "Copying Database");
fs.copyFileSync(Database.templatePath, Database.sqlitePath);
}
@ -252,7 +258,7 @@ class Database {
idleTimeoutMillis: 120 * 1000,
propagateCreateError: false,
acquireTimeoutMillis: acquireConnectionTimeout,
}
},
};
} else if (dbConfig.type === "mariadb") {
if (!/^\w+$/.test(dbConfig.dbName)) {
@ -451,7 +457,7 @@ class Database {
static async patchSqlite() {
let version = parseInt(await setting("database_version"));
if (! version) {
if (!version) {
version = 0;
}
@ -502,7 +508,7 @@ class Database {
log.debug("db", "Database Patch 2.0 Process");
let databasePatchedFiles = await setting("databasePatchedFiles");
if (! databasePatchedFiles) {
if (!databasePatchedFiles) {
databasePatchedFiles = {};
}
@ -579,11 +585,11 @@ class Database {
let id = await R.store(statusPage);
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [
id
id,
]);
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [
id
id,
]);
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
@ -611,13 +617,13 @@ class Database {
static async patch2Recursion(sqlFilename, databasePatchedFiles) {
let value = this.patchList[sqlFilename];
if (! value) {
if (!value) {
log.info("db", sqlFilename + " skip");
return;
}
// Check if patched
if (! databasePatchedFiles[sqlFilename]) {
if (!databasePatchedFiles[sqlFilename]) {
log.info("db", sqlFilename + " is not patched");
if (value.parents) {
@ -652,7 +658,7 @@ class Database {
// Remove all comments (--)
let lines = text.split("\n");
lines = lines.filter((line) => {
return ! line.startsWith("--");
return !line.startsWith("--");
});
// Split statements by semicolon
@ -797,7 +803,8 @@ class Database {
// Stop if stat_* tables are not empty
for (let table of [ "stat_minutely", "stat_hourly", "stat_daily" ]) {
let countResult = await R.getRow(`SELECT COUNT(*) AS count FROM ${table}`);
let countResult = await R.getRow(`SELECT COUNT(*) AS count
FROM ${table}`);
let count = countResult.count;
if (count > 0) {
log.warn("db", `Aggregate table ${table} is not empty, migration will not be started (Maybe you were using 2.0.0-dev?)`);
@ -814,12 +821,12 @@ class Database {
for (let monitor of monitors) {
// Get a list of unique dates from the heartbeat table, using raw sql
let dates = await R.getAll(`
SELECT DISTINCT DATE(time) AS date
SELECT DISTINCT DATE (time) AS date
FROM heartbeat
WHERE monitor_id = ?
ORDER BY date ASC
`, [
monitor.monitor_id
monitor.monitor_id,
]);
for (let date of dates) {
@ -833,7 +840,7 @@ class Database {
SELECT status, ping, time
FROM heartbeat
WHERE monitor_id = ?
AND DATE(time) = ?
AND DATE (time) = ?
ORDER BY time ASC
`, [ monitor.monitor_id, date.date ]);
@ -887,19 +894,21 @@ class Database {
log.info("db", "Deleting non-important heartbeats for monitor " + monitor.id);
}
await R.exec(`
DELETE FROM heartbeat
DELETE
FROM heartbeat
WHERE monitor_id = ?
AND important = 0
AND time < ${sqlHourOffset}
AND id NOT IN (
AND important = 0
AND time
< ${sqlHourOffset}
AND id NOT IN (
SELECT id FROM ( -- written this way for Maria's support
SELECT id
FROM heartbeat
WHERE monitor_id = ?
ORDER BY time DESC
LIMIT ?
) AS limited_ids
)
SELECT id
FROM heartbeat
WHERE monitor_id = ?
ORDER BY time DESC
LIMIT ?
) AS limited_ids
)
`, [
monitor.id,
-24,

View file

@ -146,7 +146,7 @@ class DockerHost {
static getHttpsAgentOptions(dockerType, url) {
let baseOptions = {
maxCachedSessions: 0,
rejectUnauthorized: true
rejectUnauthorized: true,
};
let certOptions = {};
@ -163,13 +163,13 @@ class DockerHost {
certOptions = {
ca,
key,
cert
cert,
};
}
return {
...baseOptions,
...certOptions
...certOptions,
};
}
}

View file

@ -15,7 +15,7 @@ const jobs = [
interval: "*/5 * * * *",
jobFunc: incrementalVacuum,
croner: null,
}
},
];
/**
@ -54,5 +54,5 @@ const stopBackgroundJobs = function () {
module.exports = {
initBackgroundJobs,
stopBackgroundJobs
stopBackgroundJobs,
};

View file

@ -1,5 +1,9 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const { parseTimeObject, parseTimeFromTimeObject, log } = require("../../src/util");
const {
parseTimeObject,
parseTimeFromTimeObject,
log,
} = require("../../src/util");
const { R } = require("redbean-node");
const dayjs = require("dayjs");
const Cron = require("croner");
@ -192,7 +196,8 @@ class Maintenance extends BeanModel {
* @returns {void}
*/
static validateCron(cron) {
let job = new Cron(cron, () => {});
let job = new Cron(cron, () => {
});
job.stop();
}

View file

@ -1,11 +1,37 @@
const dayjs = require("dayjs");
const axios = require("axios");
const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
SQL_DATETIME_FORMAT, evaluateJsonQuery
const {
log,
UP,
DOWN,
PENDING,
MAINTENANCE,
flipStatus,
MAX_INTERVAL_SECOND,
MIN_INTERVAL_SECOND,
SQL_DATETIME_FORMAT,
evaluateJsonQuery,
} = require("../../src/util");
const { tcping, ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery,
redisPingAsync, kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal
const {
tcping,
ping,
checkCertificate,
checkStatusCode,
getTotalClientInRoom,
setting,
mssqlQuery,
postgresQuery,
mysqlQuery,
setSetting,
httpNtlm,
radius,
grpcQuery,
redisPingAsync,
kafkaProducerAsync,
getOidcTokenClientCredentials,
rootCertificatesFingerprints,
axiosAbortSignal,
} = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
@ -61,7 +87,10 @@ class Monitor extends BeanModel {
}
if (certExpiry && (this.type === "http" || this.type === "keyword" || this.type === "json-query") && this.getURLProtocol() === "https:") {
const { certExpiryDaysRemaining, validCert } = await this.getCertExpiry(this.id);
const {
certExpiryDaysRemaining,
validCert,
} = await this.getCertExpiry(this.id);
obj.certExpiryDaysRemaining = certExpiryDaysRemaining;
obj.validCert = validCert;
}
@ -218,13 +247,13 @@ class Monitor extends BeanModel {
if (tlsInfo?.valid && tlsInfo?.certInfo?.daysRemaining) {
return {
certExpiryDaysRemaining: tlsInfo.certInfo.daysRemaining,
validCert: true
validCert: true,
};
}
}
return {
certExpiryDaysRemaining: "",
validCert: false
validCert: false,
};
}
@ -334,7 +363,7 @@ class Monitor extends BeanModel {
let beatInterval = this.interval;
if (! beatInterval) {
if (!beatInterval) {
beatInterval = 1;
}
@ -479,7 +508,7 @@ class Monitor extends BeanModel {
...(contentType ? { "Content-Type": contentType } : {}),
...(basicAuthHeader),
...(oauth2AuthHeader),
...(this.headers ? JSON.parse(this.headers) : {})
...(this.headers ? JSON.parse(this.headers) : {}),
},
maxRedirects: this.maxredirects,
validateStatus: (status) => {
@ -504,7 +533,10 @@ class Monitor extends BeanModel {
const proxy = await R.load("proxy", this.proxy_id);
if (proxy && proxy.active) {
const { httpAgent, httpsAgent } = Proxy.createAgents(proxy, {
const {
httpAgent,
httpsAgent,
} = Proxy.createAgents(proxy, {
httpsAgentOptions: httpsAgentOptions,
});
@ -518,7 +550,7 @@ class Monitor extends BeanModel {
let jar = new CookieJar();
let httpsCookieAgentOptions = {
...httpsAgentOptions,
cookies: { jar }
cookies: { jar },
};
options.httpsAgent = new HttpsCookieAgent(httpsCookieAgentOptions);
}
@ -600,7 +632,10 @@ class Monitor extends BeanModel {
} else if (this.type === "json-query") {
let data = res.data;
const { status, response } = await evaluateJsonQuery(data, this.jsonPath, this.jsonPathOperator, this.expectedValue);
const {
status,
response,
} = await evaluateJsonQuery(data, this.jsonPath, this.jsonPathOperator, this.expectedValue);
if (status) {
bean.status = UP;
@ -681,7 +716,7 @@ class Monitor extends BeanModel {
params: {
filter: filter,
key: steamAPIKey,
}
},
});
if (res.data.response && res.data.response.servers && res.data.response.servers.length > 0) {
@ -690,7 +725,8 @@ class Monitor extends BeanModel {
try {
bean.ping = await ping(this.hostname, this.packetSize);
} catch (_) { }
} catch (_) {
}
} else {
throw new Error("Server not found on Steam");
}
@ -739,7 +775,7 @@ class Monitor extends BeanModel {
} else if (dockerHost._dockerType === "tcp") {
options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon);
options.httpsAgent = new https.Agent(
DockerHost.getHttpsAgentOptions(dockerHost._dockerType, options.baseURL)
DockerHost.getHttpsAgentOptions(dockerHost._dockerType, options.baseURL),
);
}
@ -984,12 +1020,12 @@ class Monitor extends BeanModel {
previousBeat = bean;
if (! this.isStop) {
if (!this.isStop) {
log.debug("monitor", `[${this.name}] SetTimeout for next check.`);
let intervalRemainingMs = Math.max(
1,
beatInterval * 1000 - dayjs().diff(dayjs.utc(bean.time))
beatInterval * 1000 - dayjs().diff(dayjs.utc(bean.time)),
);
log.debug("monitor", `[${this.name}] Next heartbeat in: ${intervalRemainingMs}ms`);
@ -1013,7 +1049,7 @@ class Monitor extends BeanModel {
UptimeKumaServer.errorLog(e, false);
log.error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues");
if (! this.isStop) {
if (!this.isStop) {
log.info("monitor", "Try to restart the monitor");
this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000);
}
@ -1047,7 +1083,7 @@ class Monitor extends BeanModel {
username: this.basic_auth_user,
password: this.basic_auth_pass,
domain: this.authDomain,
workstation: this.authWorkstation ? this.authWorkstation : undefined
workstation: this.authWorkstation ? this.authWorkstation : undefined,
});
} else {
res = await axios.request(options);
@ -1065,8 +1101,9 @@ class Monitor extends BeanModel {
let oauth2AuthHeader = {
"Authorization": this.oauthAccessToken.token_type + " " + this.oauthAccessToken.access_token,
};
options.headers = { ...(options.headers),
...(oauth2AuthHeader)
options.headers = {
...(options.headers),
...(oauth2AuthHeader),
};
return this.makeAxiosRequest(options, true);
@ -1158,7 +1195,7 @@ class Monitor extends BeanModel {
if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) {
log.debug("monitor", "Resetting sent_history");
await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [
this.id
this.id,
]);
} else {
log.debug("monitor", "No need to reset sent_history");
@ -1168,7 +1205,8 @@ class Monitor extends BeanModel {
} else {
log.debug("monitor", "Not valid object");
}
} catch (e) { }
} catch (e) {
}
}
@ -1326,8 +1364,9 @@ class Monitor extends BeanModel {
for (let notification of notificationList) {
try {
const heartbeatJSON = bean.toJSON();
const monitorData = [{ id: monitor.id,
active: monitor.active
const monitorData = [ {
id: monitor.id,
active: monitor.active,
}];
const preloadData = await Monitor.preparePreloadData(monitorData);
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
@ -1370,7 +1409,7 @@ class Monitor extends BeanModel {
if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) {
const notificationList = await Monitor.getNotificationList(this);
if (! notificationList.length > 0) {
if (!notificationList.length > 0) {
// fail fast. If no notification is set, all the following checks can be skipped.
log.debug("monitor", "No notification, no need to send cert notification");
return;
@ -1458,7 +1497,7 @@ class Monitor extends BeanModel {
*/
static async getPreviousHeartbeat(monitorID) {
return await R.findOne("heartbeat", " id = (select MAX(id) from heartbeat where monitor_id = ?)", [
monitorID
monitorID,
]);
}
@ -1570,7 +1609,7 @@ class Monitor extends BeanModel {
monitor_id: row.monitor_id,
value: row.value,
name: row.name,
color: row.color
color: row.color,
});
});
@ -1687,7 +1726,7 @@ class Monitor extends BeanModel {
*/
static async unlinkAllChildren(groupID) {
return await R.exec("UPDATE `monitor` SET parent = ? WHERE parent = ? ", [
null, groupID
null, groupID,
]);
}

View file

@ -8,7 +8,15 @@ const { marked } = require("marked");
const { Feed } = require("feed");
const config = require("../config");
const { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_MAINTENANCE, STATUS_PAGE_PARTIAL_DOWN, UP, MAINTENANCE, DOWN } = require("../../src/util");
const {
STATUS_PAGE_ALL_DOWN,
STATUS_PAGE_ALL_UP,
STATUS_PAGE_MAINTENANCE,
STATUS_PAGE_PARTIAL_DOWN,
UP,
MAINTENANCE,
DOWN,
} = require("../../src/util");
class StatusPage extends BeanModel {
@ -16,7 +24,7 @@ class StatusPage extends BeanModel {
* Like this: { "test-uptime.kuma.pet": "default" }
* @type {{}}
*/
static domainMappingList = { };
static domainMappingList = {};
/**
* Handle responses to RSS pages
@ -26,7 +34,7 @@ class StatusPage extends BeanModel {
*/
static async handleStatusPageRSSResponse(response, slug) {
let statusPage = await R.findOne("status_page", " slug = ? ", [
slug
slug,
]);
if (statusPage) {
@ -51,7 +59,7 @@ class StatusPage extends BeanModel {
}
let statusPage = await R.findOne("status_page", " slug = ? ", [
slug
slug,
]);
if (statusPage) {
@ -68,7 +76,10 @@ class StatusPage extends BeanModel {
* @returns {Promise<string>} the rendered html
*/
static async renderRSS(statusPage, slug) {
const { heartbeats, statusDescription } = await StatusPage.getRSSPageData(statusPage);
const {
heartbeats,
statusDescription,
} = await StatusPage.getRSSPageData(statusPage);
let proto = config.isSSL ? "https" : "http";
let host = `${proto}://${config.hostname || "localhost"}:${config.port}/status/${slug}`;
@ -135,7 +146,7 @@ class StatusPage extends BeanModel {
// Preload data
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
const escapedJSONObject = jsesc(await StatusPage.getStatusPageData(statusPage), {
"isScriptContext": true
"isScriptContext": true,
});
const script = $(`
@ -174,7 +185,7 @@ class StatusPage extends BeanModel {
}
}
if (! hasUp) {
if (!hasUp) {
status = STATUS_PAGE_ALL_DOWN;
}
@ -223,7 +234,7 @@ class StatusPage extends BeanModel {
const showTags = !!statusPage.show_tags;
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
statusPage.id
statusPage.id,
]);
let heartbeats = [];
@ -236,7 +247,7 @@ class StatusPage extends BeanModel {
heartbeats.push({
...monitor,
status: heartbeat.status,
time: heartbeat.time
time: heartbeat.time,
});
}
}
@ -251,7 +262,7 @@ class StatusPage extends BeanModel {
return {
heartbeats,
statusDescription
statusDescription,
};
}
@ -279,7 +290,7 @@ class StatusPage extends BeanModel {
const showTags = !!statusPage.show_tags;
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
statusPage.id
statusPage.id,
]);
for (let groupBean of list) {
@ -442,7 +453,7 @@ class StatusPage extends BeanModel {
*/
static async slugToID(slug) {
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
slug
slug,
]);
}

View file

@ -2,7 +2,10 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
const passwordHash = require("../password-hash");
const { R } = require("redbean-node");
const jwt = require("jsonwebtoken");
const { shake256, SHAKE256_LENGTH } = require("../util-server");
const {
shake256,
SHAKE256_LENGTH,
} = require("../util-server");
class User extends BeanModel {
/**
@ -15,7 +18,7 @@ class User extends BeanModel {
static async resetPassword(userID, newPassword) {
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
passwordHash.generate(newPassword),
userID
userID,
]);
}
@ -29,7 +32,7 @@ class User extends BeanModel {
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
hashedPassword,
this.id
this.id,
]);
this.password = hashedPassword;

View file

@ -100,7 +100,7 @@ function ApiCache() {
* Generated by Trelent
*/
function debug(a, b, c, d) {
let arr = ["\x1b[36m[apicache]\x1b[0m", a, b, c, d].filter(function (arg) {
let arr = [ "\x1b[36m[apicache]\x1b[0m", a, b, c, d ].filter(function (arg) {
return arg !== undefined;
});
let debugEnv = process.env.DEBUG && process.env.DEBUG.split(",").indexOf("apicache") !== -1;
@ -210,7 +210,8 @@ function ApiCache() {
try {
redis.hset(key, "response", JSON.stringify(value));
redis.hset(key, "duration", duration);
redis.expire(key, duration / 1000, expireCallback || function () {});
redis.expire(key, duration / 1000, expireCallback || function () {
});
} catch (err) {
debug("[apicache] error in redis.hset()");
}
@ -247,8 +248,8 @@ function ApiCache() {
}
res._apicache.content = Buffer.concat(
[oldContent, content],
oldContent.length + content.length
[ oldContent, content ],
oldContent.length + content.length,
);
} else {
res._apicache.content = content;
@ -268,7 +269,7 @@ function ApiCache() {
* @param {function(Object, Object):boolean} toggle
*/
function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) {
// monkeypatch res.end to create cache object
// monkeypatch res.end to create cache object
res._apicache = {
write: res.write,
writeHead: res.writeHead,
@ -314,7 +315,7 @@ function ApiCache() {
res.statusCode,
headers,
res._apicache.content,
encoding
encoding,
);
cacheResponse(key, cacheObject, duration);
@ -367,7 +368,7 @@ function ApiCache() {
let data = cacheObject.data;
if (data && data.type === "Buffer") {
data =
typeof data.data === "number" ? new Buffer.alloc(data.data) : new Buffer.from(data.data);
typeof data.data === "number" ? new Buffer.alloc(data.data) : new Buffer.from(data.data);
}
// test Etag against If-None-Match for 304
@ -511,15 +512,15 @@ function ApiCache() {
};
/**
* Return cache performance statistics (hit rate). Suitable for
* putting into a route:
* <code>
* app.get('/api/cache/performance', (req, res) => {
* res.json(apicache.getPerformance())
* })
* </code>
* @returns {any[]}
*/
* Return cache performance statistics (hit rate). Suitable for
* putting into a route:
* <code>
* app.get('/api/cache/performance', (req, res) => {
* res.json(apicache.getPerformance())
* })
* </code>
* @returns {any[]}
*/
this.getPerformance = function () {
return performanceArray.map(function (p) {
return p.report();
@ -528,7 +529,7 @@ function ApiCache() {
/**
* Get index of a group
* @param {string} group
* @param {string} group
* @returns {number}
*/
this.getIndex = function (group) {
@ -543,9 +544,9 @@ function ApiCache() {
* Express middleware
* @param {(string|number)} strDuration Duration to cache responses
* for.
* @param {function(Object, Object):boolean} middlewareToggle
* @param {function(Object, Object):boolean} middlewareToggle
* @param {Object} localOptions Options for APICache
* @returns
* @returns
*/
this.middleware = function cache(strDuration, middlewareToggle, localOptions) {
let duration = instance.getDuration(strDuration);
@ -573,7 +574,8 @@ function ApiCache() {
* A Function for non tracking performance
*/
function NOOPCachePerformance() {
this.report = this.hit = this.miss = function () {}; // noop;
this.report = this.hit = this.miss = function () {
}; // noop;
}
/**
@ -762,8 +764,8 @@ function ApiCache() {
}
if (
req.headers["x-apicache-bypass"] ||
req.headers["x-apicache-force-fetch"] ||
(opt.respectCacheControl && req.headers["cache-control"] == "no-cache")
req.headers["x-apicache-force-fetch"] ||
(opt.respectCacheControl && req.headers["cache-control"] == "no-cache")
) {
return bypass();
}
@ -826,7 +828,7 @@ function ApiCache() {
JSON.parse(obj.response),
middlewareToggle,
next,
duration
duration,
);
} else {
perf.miss(key);
@ -837,7 +839,7 @@ function ApiCache() {
key,
duration,
strDuration,
middlewareToggle
middlewareToggle,
);
}
});
@ -859,7 +861,7 @@ function ApiCache() {
/**
* Process options
* @param {Object} options
* @param {Object} options
* @returns {Object}
*/
this.options = function (options) {

View file

@ -2,7 +2,7 @@ const apicache = require("./apicache");
apicache.options({
headerBlacklist: [
"cache-control"
"cache-control",
],
headers: {
// Disable client side cache, only server side cache.

View file

@ -4,7 +4,7 @@ function MemoryCache() {
}
/**
*
*
* @param {string} key Key to store cache as
* @param {any} value Value to store
* @param {number} time Time to store for
@ -22,7 +22,7 @@ MemoryCache.prototype.add = function (key, value, time, timeoutCallback) {
timeout: setTimeout(function () {
instance.delete(key);
return timeoutCallback && typeof timeoutCallback === "function" && timeoutCallback(value, key);
}, time)
}, time),
};
this.cache[key] = entry;
@ -52,7 +52,7 @@ MemoryCache.prototype.delete = function (key) {
/**
* Get value of key
* @param {string} key
* @param {string} key
* @returns {Object}
*/
MemoryCache.prototype.get = function (key) {
@ -63,7 +63,7 @@ MemoryCache.prototype.get = function (key) {
/**
* Get value of cache entry
* @param {string} key
* @param {string} key
* @returns {any}
*/
MemoryCache.prototype.getValue = function (key) {

View file

@ -1,4 +1,4 @@
'use strict';
"use strict";
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/flags.js
module.exports.NTLMFLAG_NEGOTIATE_UNICODE = 1 << 0;
/* Indicates that Unicode strings are supported for use in security buffer
@ -74,4 +74,4 @@ module.exports.NTLMFLAG_NEGOTIATE_KEY_EXCHANGE = 1 << 30;
/* Indicates that the client will provide an encrypted master key in
the "Session Key" field of the Type 3 message. */
module.exports.NTLMFLAG_NEGOTIATE_56 = 1 << 31;
//# sourceMappingURL=flags.js.map
//# sourceMappingURL=flags.js.map

View file

@ -1,6 +1,7 @@
'use strict';
"use strict";
// Original source at https://github.com/elasticio/node-ntlm-client/blob/master/lib/hash.js
var crypto = require('crypto');
var crypto = require("crypto");
function createLMResponse(challenge, lmhash) {
var buf = new Buffer.alloc(24), pwBuffer = new Buffer.alloc(21).fill(0);
lmhash.copy(pwBuffer);
@ -9,19 +10,21 @@ function createLMResponse(challenge, lmhash) {
calculateDES(pwBuffer.slice(14), challenge).copy(buf, 16);
return buf;
}
function createLMHash(password) {
var buf = new Buffer.alloc(16), pwBuffer = new Buffer.alloc(14), magicKey = new Buffer.from('KGS!@#$%', 'ascii');
var buf = new Buffer.alloc(16), pwBuffer = new Buffer.alloc(14), magicKey = new Buffer.from("KGS!@#$%", "ascii");
if (password.length > 14) {
buf.fill(0);
return buf;
}
pwBuffer.fill(0);
pwBuffer.write(password.toUpperCase(), 0, 'ascii');
pwBuffer.write(password.toUpperCase(), 0, "ascii");
return Buffer.concat([
calculateDES(pwBuffer.slice(0, 7), magicKey),
calculateDES(pwBuffer.slice(7), magicKey)
calculateDES(pwBuffer.slice(7), magicKey),
]);
}
function calculateDES(key, message) {
var desKey = new Buffer.alloc(8);
desKey[0] = key[0] & 0xFE;
@ -39,9 +42,10 @@ function calculateDES(key, message) {
}
desKey[i] |= (parity % 2) === 0 ? 1 : 0;
}
var des = crypto.createCipheriv('DES-ECB', desKey, '');
var des = crypto.createCipheriv("DES-ECB", desKey, "");
return des.update(message);
}
function createNTLMResponse(challenge, ntlmhash) {
var buf = new Buffer.alloc(24), ntlmBuffer = new Buffer.alloc(21).fill(0);
ntlmhash.copy(ntlmBuffer);
@ -50,30 +54,36 @@ function createNTLMResponse(challenge, ntlmhash) {
calculateDES(ntlmBuffer.slice(14), challenge).copy(buf, 16);
return buf;
}
function createNTLMHash(password) {
var md4sum = crypto.createHash('md4');
md4sum.update(new Buffer.from(password, 'ucs2'));
var md4sum = crypto.createHash("md4");
md4sum.update(new Buffer.from(password, "ucs2"));
return md4sum.digest();
}
function createNTLMv2Hash(ntlmhash, username, authTargetName) {
var hmac = crypto.createHmac('md5', ntlmhash);
hmac.update(new Buffer.from(username.toUpperCase() + authTargetName, 'ucs2'));
var hmac = crypto.createHmac("md5", ntlmhash);
hmac.update(new Buffer.from(username.toUpperCase() + authTargetName, "ucs2"));
return hmac.digest();
}
function createLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
var buf = new Buffer.alloc(24), ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName), hmac = crypto.createHmac('md5', ntlm2hash);
var buf = new Buffer.alloc(24), ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName),
hmac = crypto.createHmac("md5", ntlm2hash);
//server challenge
type2message.challenge.copy(buf, 8);
//client nonce
buf.write(nonce || createPseudoRandomValue(16), 16, 'hex');
buf.write(nonce || createPseudoRandomValue(16), 16, "hex");
//create hash
hmac.update(buf.slice(8));
var hashedBuffer = hmac.digest();
hashedBuffer.copy(buf);
return buf;
}
function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetName) {
var buf = new Buffer.alloc(48 + type2message.targetInfo.buffer.length), ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName), hmac = crypto.createHmac('md5', ntlm2hash);
var buf = new Buffer.alloc(48 + type2message.targetInfo.buffer.length),
ntlm2hash = createNTLMv2Hash(ntlmhash, username, targetName), hmac = crypto.createHmac("md5", ntlm2hash);
//the first 8 bytes are spare to store the hashed value before the blob
//server challenge
type2message.challenge.copy(buf, 8);
@ -86,12 +96,12 @@ function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetNam
// maybe think about a different solution here
// 11644473600000 = diff between 1970 and 1601
var timestamp = ((Date.now() + 11644473600000) * 10000).toString(16);
var timestampLow = Number('0x' + timestamp.substring(Math.max(0, timestamp.length - 8)));
var timestampHigh = Number('0x' + timestamp.substring(0, Math.max(0, timestamp.length - 8)));
var timestampLow = Number("0x" + timestamp.substring(Math.max(0, timestamp.length - 8)));
var timestampHigh = Number("0x" + timestamp.substring(0, Math.max(0, timestamp.length - 8)));
buf.writeUInt32LE(timestampLow, 24, false);
buf.writeUInt32LE(timestampHigh, 28, false);
//random client nonce
buf.write(nonce || createPseudoRandomValue(16), 32, 'hex');
buf.write(nonce || createPseudoRandomValue(16), 32, "hex");
//zero
buf.writeUInt32LE(0, 40);
//complete target information block from type 2 message
@ -103,13 +113,15 @@ function createNTLMv2Response(type2message, username, ntlmhash, nonce, targetNam
hashedBuffer.copy(buf);
return buf;
}
function createPseudoRandomValue(length) {
var str = '';
var str = "";
while (str.length < length) {
str += Math.floor(Math.random() * 16).toString(16);
}
return str;
}
module.exports = {
createLMHash: createLMHash,
createNTLMHash: createNTLMHash,
@ -117,6 +129,6 @@ module.exports = {
createNTLMResponse: createNTLMResponse,
createLMv2Response: createLMv2Response,
createNTLMv2Response: createNTLMv2Response,
createPseudoRandomValue: createPseudoRandomValue
createPseudoRandomValue: createPseudoRandomValue,
};
//# sourceMappingURL=hash.js.map
//# sourceMappingURL=hash.js.map

View file

@ -1,13 +1,14 @@
'use strict';
"use strict";
// Original file https://raw.githubusercontent.com/elasticio/node-ntlm-client/master/lib/ntlm.js
var os = require('os'), flags = require('./flags'), hash = require('./hash');
var os = require("os"), flags = require("./flags"), hash = require("./hash");
var NTLMSIGNATURE = "NTLMSSP\0";
function createType1Message(workstation, target) {
var dataPos = 32, pos = 0, buf = new Buffer.alloc(1024);
workstation = workstation === undefined ? os.hostname() : workstation;
target = target === undefined ? '' : target;
target = target === undefined ? "" : target;
//signature
buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, 'ascii');
buf.write(NTLMSIGNATURE, pos, NTLMSIGNATURE.length, "ascii");
pos += NTLMSIGNATURE.length;
//message type
buf.writeUInt32LE(1, pos);
@ -27,7 +28,7 @@ function createType1Message(workstation, target) {
buf.writeUInt32LE(target.length === 0 ? 0 : dataPos, pos);
pos += 4;
if (target.length > 0) {
dataPos += buf.write(target, dataPos, 'ascii');
dataPos += buf.write(target, dataPos, "ascii");
}
//workstation security buffer
buf.writeUInt16LE(workstation.length, pos);
@ -37,39 +38,39 @@ function createType1Message(workstation, target) {
buf.writeUInt32LE(workstation.length === 0 ? 0 : dataPos, pos);
pos += 4;
if (workstation.length > 0) {
dataPos += buf.write(workstation, dataPos, 'ascii');
dataPos += buf.write(workstation, dataPos, "ascii");
}
return 'NTLM ' + buf.toString('base64', 0, dataPos);
return "NTLM " + buf.toString("base64", 0, dataPos);
}
function decodeType2Message(str) {
if (str === undefined) {
throw new Error('Invalid argument');
throw new Error("Invalid argument");
}
//convenience
if (Object.prototype.toString.call(str) !== '[object String]') {
if (str.hasOwnProperty('headers') && str.headers.hasOwnProperty('www-authenticate')) {
str = str.headers['www-authenticate'];
}
else {
throw new Error('Invalid argument');
if (Object.prototype.toString.call(str) !== "[object String]") {
if (str.hasOwnProperty("headers") && str.headers.hasOwnProperty("www-authenticate")) {
str = str.headers["www-authenticate"];
} else {
throw new Error("Invalid argument");
}
}
var ntlmMatch = /^NTLM ([^,\s]+)/.exec(str);
if (ntlmMatch) {
str = ntlmMatch[1];
}
var buf = new Buffer.from(str, 'base64'), obj = {};
var buf = new Buffer.from(str, "base64"), obj = {};
//check signature
if (buf.toString('ascii', 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
throw new Error('Invalid message signature: ' + str);
if (buf.toString("ascii", 0, NTLMSIGNATURE.length) !== NTLMSIGNATURE) {
throw new Error("Invalid message signature: " + str);
}
//check message type
if (buf.readUInt32LE(NTLMSIGNATURE.length) !== 2) {
throw new Error('Invalid message type (no type 2)');
throw new Error("Invalid message type (no type 2)");
}
//read flags
obj.flags = buf.readUInt32LE(20);
obj.encoding = (obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM) ? 'ascii' : 'ucs2';
obj.encoding = (obj.flags & flags.NTLMFLAG_NEGOTIATE_OEM) ? "ascii" : "ucs2";
obj.version = (obj.flags & flags.NTLMFLAG_NEGOTIATE_NTLM2_KEY) ? 2 : 1;
obj.challenge = buf.slice(24, 32);
//read target name
@ -78,10 +79,10 @@ function decodeType2Message(str) {
//skipping allocated space
var offset = buf.readUInt32LE(16);
if (length === 0) {
return '';
return "";
}
if ((offset + length) > buf.length || offset < 32) {
throw new Error('Bad type 2 message');
throw new Error("Bad type 2 message");
}
return buf.toString(obj.encoding, offset, offset + length);
})();
@ -98,7 +99,7 @@ function decodeType2Message(str) {
return info;
}
if ((offset + length) > buf.length || offset < 32) {
throw new Error('Bad type 2 message');
throw new Error("Bad type 2 message");
}
var pos = offset;
while (pos < (offset + length)) {
@ -113,37 +114,38 @@ function decodeType2Message(str) {
var blockTypeStr = void 0;
switch (blockType) {
case 1:
blockTypeStr = 'SERVER';
blockTypeStr = "SERVER";
break;
case 2:
blockTypeStr = 'DOMAIN';
blockTypeStr = "DOMAIN";
break;
case 3:
blockTypeStr = 'FQDN';
blockTypeStr = "FQDN";
break;
case 4:
blockTypeStr = 'DNS';
blockTypeStr = "DNS";
break;
case 5:
blockTypeStr = 'PARENT_DNS';
blockTypeStr = "PARENT_DNS";
break;
default:
blockTypeStr = '';
blockTypeStr = "";
break;
}
if (blockTypeStr) {
info[blockTypeStr] = buf.toString('ucs2', pos, pos + blockLength);
info[blockTypeStr] = buf.toString("ucs2", pos, pos + blockLength);
}
pos += blockLength;
}
return {
parsed: info,
buffer: targetInfoBuffer
buffer: targetInfoBuffer,
};
})();
}
return obj;
}
function createType3Message(type2Message, username, password, workstation, target) {
var dataPos = 52, buf = new Buffer.alloc(1024);
if (workstation === undefined) {
@ -153,12 +155,14 @@ function createType3Message(type2Message, username, password, workstation, targe
target = type2Message.targetName;
}
//signature
buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, 'ascii');
buf.write(NTLMSIGNATURE, 0, NTLMSIGNATURE.length, "ascii");
//message type
buf.writeUInt32LE(3, 8);
if (type2Message.version === 2) {
dataPos = 64;
var ntlmHash = hash.createNTLMHash(password), nonce = hash.createPseudoRandomValue(16), lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target), ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
var ntlmHash = hash.createNTLMHash(password), nonce = hash.createPseudoRandomValue(16),
lmv2 = hash.createLMv2Response(type2Message, username, ntlmHash, nonce, target),
ntlmv2 = hash.createNTLMv2Response(type2Message, username, ntlmHash, nonce, target);
//lmv2 security buffer
buf.writeUInt16LE(lmv2.length, 12);
buf.writeUInt16LE(lmv2.length, 14);
@ -171,9 +175,10 @@ function createType3Message(type2Message, username, password, workstation, targe
buf.writeUInt32LE(dataPos, 24);
ntlmv2.copy(buf, dataPos);
dataPos += ntlmv2.length;
}
else {
var lmHash = hash.createLMHash(password), ntlmHash = hash.createNTLMHash(password), lm = hash.createLMResponse(type2Message.challenge, lmHash), ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
} else {
var lmHash = hash.createLMHash(password), ntlmHash = hash.createNTLMHash(password),
lm = hash.createLMResponse(type2Message.challenge, lmHash),
ntlm = hash.createNTLMResponse(type2Message.challenge, ntlmHash);
//lm security buffer
buf.writeUInt16LE(lm.length, 12);
buf.writeUInt16LE(lm.length, 14);
@ -188,18 +193,18 @@ function createType3Message(type2Message, username, password, workstation, targe
dataPos += ntlm.length;
}
//target name security buffer
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 28);
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? target.length : target.length * 2, 30);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? target.length : target.length * 2, 28);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? target.length : target.length * 2, 30);
buf.writeUInt32LE(dataPos, 32);
dataPos += buf.write(target, dataPos, type2Message.encoding);
//user name security buffer
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 36);
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? username.length : username.length * 2, 38);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? username.length : username.length * 2, 36);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? username.length : username.length * 2, 38);
buf.writeUInt32LE(dataPos, 40);
dataPos += buf.write(username, dataPos, type2Message.encoding);
//workstation name security buffer
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 44);
buf.writeUInt16LE(type2Message.encoding === 'ascii' ? workstation.length : workstation.length * 2, 46);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? workstation.length : workstation.length * 2, 44);
buf.writeUInt16LE(type2Message.encoding === "ascii" ? workstation.length : workstation.length * 2, 46);
buf.writeUInt32LE(dataPos, 48);
dataPos += buf.write(workstation, dataPos, type2Message.encoding);
if (type2Message.version === 2) {
@ -210,11 +215,12 @@ function createType3Message(type2Message, username, password, workstation, targe
//flags
buf.writeUInt32LE(type2Message.flags, 60);
}
return 'NTLM ' + buf.toString('base64', 0, dataPos);
return "NTLM " + buf.toString("base64", 0, dataPos);
}
module.exports = {
createType1Message: createType1Message,
decodeType2Message: decodeType2Message,
createType3Message: createType3Message
createType3Message: createType3Message,
};
//# sourceMappingURL=ntlm.js.map
//# sourceMappingURL=ntlm.js.map

View file

@ -1,57 +1,172 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function (o, m, k, k2) {
if (k2 === undefined) {
k2 = k;
}
Object.defineProperty(o, k2, {
enumerable: true,
get: function () {
return m[k];
},
});
}) : (function (o, m, k, k2) {
if (k2 === undefined) {
k2 = k;
}
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function (o, v) {
Object.defineProperty(o, "default", {
enumerable: true,
value: v,
});
}) : function (o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
if (mod && mod.__esModule) {
return mod;
}
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
if (mod != null) {
for (var k in mod) {
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) {
__createBinding(result, mod, k);
}
}
}
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
var _ = {
label: 0,
sent: function () {
if (t[0] & 1) {
throw t[1];
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
return t[1];
},
trys: [],
ops: [],
}, f, y, t, g;
return g = {
next: verb(0),
"throw": verb(1),
"return": verb(2),
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
return this;
}), g;
function verb(n) {
return function (v) {
return step([ n, v ]);
};
}
function step(op) {
if (f) {
throw new TypeError("Generator is already executing.");
}
while (_) {
try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) {
return t;
}
if (y = 0, t) {
op = [ op[0] & 2, t.value ];
}
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return {
value: op[1],
done: false,
};
case 5:
_.label++;
y = op[1];
op = [ 0 ];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2]) {
_.ops.pop();
}
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
} catch (e) {
op = [ 6, e ];
y = 0;
} finally {
f = t = 0;
}
}
if (op[0] & 5) {
throw op[1];
}
return {
value: op[0] ? op[1] : void 0,
done: true,
};
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
@ -64,12 +179,13 @@ var ntlm = __importStar(require("./ntlm"));
var https = __importStar(require("https"));
var http = __importStar(require("http"));
var dev_null_1 = __importDefault(require("dev-null"));
/**
* @param credentials An NtlmCredentials object containing the username and password
* @param AxiosConfig The Axios config for the instance you wish to create
*
* @returns This function returns an axios instance configured to use the provided credentials
*/
* @param credentials An NtlmCredentials object containing the username and password
* @param AxiosConfig The Axios config for the instance you wish to create
*
* @returns This function returns an axios instance configured to use the provided credentials
*/
function NtlmClient(credentials, AxiosConfig) {
var _this = this;
var config = AxiosConfig !== null && AxiosConfig !== void 0 ? AxiosConfig : {};
@ -82,46 +198,56 @@ function NtlmClient(credentials, AxiosConfig) {
var client = axios_1.default.create(config);
client.interceptors.response.use(function (response) {
return response;
}, function (err) { return __awaiter(_this, void 0, void 0, function () {
var error, t1Msg, t2Msg, t3Msg, stream_1;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
error = err.response;
if (!(error && error.status === 401
&& error.headers['www-authenticate']
&& error.headers['www-authenticate'].includes('NTLM'))) return [3 /*break*/, 3];
// This length check is a hack because SharePoint is awkward and will
// include the Negotiate option when responding with the T2 message
// There is nore we could do to ensure we are processing correctly,
// but this is the easiest option for now
if (error.headers['www-authenticate'].length < 50) {
t1Msg = ntlm.createType1Message(credentials.workstation, credentials.domain);
error.config.headers["Authorization"] = t1Msg;
}
else {
t2Msg = ntlm.decodeType2Message((error.headers['www-authenticate'].match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1]);
t3Msg = ntlm.createType3Message(t2Msg, credentials.username, credentials.password, credentials.workstation, credentials.domain);
error.config.headers["X-retry"] = "false";
error.config.headers["Authorization"] = t3Msg;
}
if (!(error.config.responseType === "stream")) return [3 /*break*/, 2];
stream_1 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data;
if (!(stream_1 && !stream_1.readableEnded)) return [3 /*break*/, 2];
return [4 /*yield*/, new Promise(function (resolve) {
}, function (err) {
return __awaiter(_this, void 0, void 0, function () {
var error, t1Msg, t2Msg, t3Msg, stream_1;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
error = err.response;
if (!(error && error.status === 401
&& error.headers["www-authenticate"]
&& error.headers["www-authenticate"].includes("NTLM"))) {
return [ 3 /*break*/, 3 ];
}
// This length check is a hack because SharePoint is awkward and will
// include the Negotiate option when responding with the T2 message
// There is nore we could do to ensure we are processing correctly,
// but this is the easiest option for now
if (error.headers["www-authenticate"].length < 50) {
t1Msg = ntlm.createType1Message(credentials.workstation, credentials.domain);
error.config.headers["Authorization"] = t1Msg;
} else {
t2Msg = ntlm.decodeType2Message((error.headers["www-authenticate"].match(/^NTLM\s+(.+?)(,|\s+|$)/) || [])[1]);
t3Msg = ntlm.createType3Message(t2Msg, credentials.username, credentials.password, credentials.workstation, credentials.domain);
error.config.headers["X-retry"] = "false";
error.config.headers["Authorization"] = t3Msg;
}
if (!(error.config.responseType === "stream")) {
return [ 3 /*break*/, 2 ];
}
stream_1 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data;
if (!(stream_1 && !stream_1.readableEnded)) {
return [ 3 /*break*/, 2 ];
}
return [ 4 /*yield*/, new Promise(function (resolve) {
stream_1.pipe((0, dev_null_1.default)());
stream_1.once('close', resolve);
})];
case 1:
_b.sent();
_b.label = 2;
case 2: return [2 /*return*/, client(error.config)];
case 3: throw err;
}
}) ];
case 1:
_b.sent();
_b.label = 2;
case 2:
return [ 2 /*return*/, client(error.config) ];
case 3:
throw err;
}
});
});
}); });
});
return client;
}
exports.NtlmClient = NtlmClient;
//# sourceMappingURL=ntlmClient.js.map
//# sourceMappingURL=ntlmClient.js.map

View file

@ -1,20 +1,24 @@
import { PluginFunc, ConfigType } from 'dayjs'
import { PluginFunc, ConfigType } from "dayjs";
declare const plugin: PluginFunc
declare const plugin: PluginFunc;
export = plugin
declare module 'dayjs' {
interface Dayjs {
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
offsetName(type?: 'short' | 'long'): string | undefined
}
declare module "dayjs" {
interface Dayjs {
tz(timezone?: string, keepLocalTime?: boolean): Dayjs;
interface DayjsTimezone {
(date: ConfigType, timezone?: string): Dayjs
(date: ConfigType, format: string, timezone?: string): Dayjs
guess(): string
setDefault(timezone?: string): void
}
offsetName(type?: "short" | "long"): string | undefined;
}
const tz: DayjsTimezone
interface DayjsTimezone {
(date: ConfigType, timezone?: string): Dayjs;
(date: ConfigType, format: string, timezone?: string): Dayjs;
guess(): string;
setDefault(timezone?: string): void;
}
const tz: DayjsTimezone;
}

View file

@ -15,7 +15,7 @@
day: 2,
hour: 3,
minute: 4,
second: 5
second: 5,
};
let e = {};
return function (n, i, o) {
@ -37,7 +37,7 @@
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZoneName: i
timeZoneName: i,
}), e[o] = r), r;
}(n, i);
return r.formatToParts(o);

View file

@ -1,5 +1,8 @@
const { MonitorType } = require("./monitor-type");
const { UP, DOWN } = require("../../src/util");
const {
UP,
DOWN,
} = require("../../src/util");
const dayjs = require("dayjs");
const { dnsResolve } = require("../util-server");
const { R } = require("redbean-node");
@ -14,7 +17,7 @@ class DnsMonitorType extends MonitorType {
supportsConditions = true;
conditionVariables = [
new ConditionVariable("record", defaultStringOperators ),
new ConditionVariable("record", defaultStringOperators),
];
/**

View file

@ -1,5 +1,8 @@
const { MonitorType } = require("./monitor-type");
const { log, UP } = require("../../src/util");
const {
log,
UP,
} = require("../../src/util");
const mqtt = require("mqtt");
const jsonata = require("jsonata");
@ -57,7 +60,12 @@ class MqttMonitorType extends MonitorType {
*/
mqttAsync(hostname, topic, options = {}) {
return new Promise((resolve, reject) => {
const { port, username, password, interval = 20 } = options;
const {
port,
username,
password,
interval = 20,
} = options;
// Adds MQTT protocol to the hostname if not already present
if (!/^(?:http|mqtt|ws)s?:\/\//.test(hostname)) {
@ -77,7 +85,7 @@ class MqttMonitorType extends MonitorType {
let client = mqtt.connect(mqttUrl, {
username,
password,
clientId: "uptime-kuma_" + Math.random().toString(16).substr(2, 8)
clientId: "uptime-kuma_" + Math.random().toString(16).substr(2, 8),
});
client.on("connect", () => {

View file

@ -1,5 +1,9 @@
const { MonitorType } = require("./monitor-type");
const { log, UP, DOWN } = require("../../src/util");
const {
log,
UP,
DOWN,
} = require("../../src/util");
const { axiosAbortSignal } = require("../util-server");
const axios = require("axios");
@ -21,7 +25,7 @@ class RabbitMqMonitorType extends MonitorType {
for (let baseUrl of baseUrls) {
try {
// Without a trailing slash, path in baseUrl will be removed. https://example.com/api -> https://example.com
if ( !baseUrl.endsWith("/") ) {
if (!baseUrl.endsWith("/")) {
baseUrl += "/";
}
const options = {

View file

@ -1,6 +1,9 @@
const { MonitorType } = require("./monitor-type");
const { chromium } = require("playwright-core");
const { UP, log } = require("../../src/util");
const {
UP,
log,
} = require("../../src/util");
const { Settings } = require("../settings");
const commandExistsSync = require("command-exists").sync;
const childProcess = require("child_process");
@ -122,7 +125,7 @@ async function prepareChromeExecutable(executablePath) {
executablePath = "/usr/bin/chromium";
// Install chromium in container via apt install
if ( !commandExistsSync(executablePath)) {
if (!commandExistsSync(executablePath)) {
await new Promise((resolve, reject) => {
log.info("Chromium", "Installing Chromium...");
let child = childProcess.exec("apt update && apt --yes --no-install-recommends install chromium fonts-indic fonts-noto fonts-noto-cjk");
@ -213,6 +216,7 @@ async function testChrome(executablePath) {
throw new Error(e.message);
}
}
// test remote browser
/**
* @param {string} remoteBrowserURL Remote Browser URL
@ -228,6 +232,7 @@ async function testRemoteBrowser(remoteBrowserURL) {
throw new Error(e.message);
}
}
class RealBrowserMonitorType extends MonitorType {
name = "real-browser";

View file

@ -1,5 +1,9 @@
const { MonitorType } = require("./monitor-type");
const { UP, log, evaluateJsonQuery } = require("../../src/util");
const {
UP,
log,
evaluateJsonQuery,
} = require("../../src/util");
const snmp = require("net-snmp");
class SNMPMonitorType extends MonitorType {
@ -42,7 +46,10 @@ class SNMPMonitorType extends MonitorType {
// We restrict querying to one OID per monitor, therefore `varbinds[0]` will always contain the value we're interested in.
const value = varbinds[0].value;
const { status, response } = await evaluateJsonQuery(value, monitor.jsonPath, monitor.jsonPathOperator, monitor.expectedValue);
const {
status,
response,
} = await evaluateJsonQuery(value, monitor.jsonPath, monitor.jsonPathOperator, monitor.expectedValue);
if (status) {
heartbeat.status = UP;

View file

@ -5,6 +5,15 @@ const NotifyClient = require("notifications-node-client").NotifyClient;
class GovNotify extends NotificationProvider {
name = "GovNotify";
/**
* Sends notifications via email and SMS using the GOV.UK Notify service.
* @param {object} notification The notification object containing configuration such as API key, email recipients, SMS recipients, message template, and template IDs for email and SMS.
* @param {string} msg The message content to send if no message template is provided in the notification object.
* @param {object | null} monitorJSON Optional parameter containing monitoring-related data.
* @param {object | null} heartbeatJSON Optional parameter containing heartbeat-related data, used to determine notification subject (e.g., status up or down).
* @returns {Promise<string>} A promise that resolves to a success message after sending notifications or rejects with an error if the sending fails.
* @throws {Error} Throws an error if notification sending fails.
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
const apiKey = notification.apiKey;

View file

@ -20,19 +20,21 @@ class HomeAssistant extends NotificationProvider {
{
title: "Uptime Kuma",
message: msg,
...(notificationService !== "persistent_notification" && { data: {
name: monitorJSON?.name,
status: heartbeatJSON?.status,
channel: "Uptime Kuma",
icon_url: "https://github.com/louislam/uptime-kuma/blob/master/public/icon.png?raw=true",
} }),
...(notificationService !== "persistent_notification" && {
data: {
name: monitorJSON?.name,
status: heartbeatJSON?.status,
channel: "Uptime Kuma",
icon_url: "https://github.com/louislam/uptime-kuma/blob/master/public/icon.png?raw=true",
},
}),
},
{
headers: {
Authorization: `Bearer ${notification.longLivedAccessToken}`,
"Content-Type": "application/json",
},
}
},
);
return okMsg;

View file

@ -159,7 +159,7 @@ class Notification {
new GovNotify(),
];
for (let item of list) {
if (! item.name) {
if (!item.name) {
throw new Error("Notification provider without name");
}
@ -203,7 +203,7 @@ class Notification {
userID,
]);
if (! bean) {
if (!bean) {
throw new Error("notification not found");
}
@ -236,7 +236,7 @@ class Notification {
userID,
]);
if (! bean) {
if (!bean) {
throw new Error("notification not found");
}
@ -263,7 +263,7 @@ class Notification {
*/
async function applyNotificationEveryMonitor(notificationID, userID) {
let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [
userID
userID,
]);
for (let i = 0; i < monitors.length; i++) {
@ -272,7 +272,7 @@ async function applyNotificationEveryMonitor(notificationID, userID) {
notificationID,
]);
if (! checkNotification) {
if (!checkNotification) {
let relation = R.dispense("monitor_notification");
relation.monitor_id = monitors[i].id;
relation.notification_id = notificationID;

View file

@ -12,24 +12,24 @@ const commonLabels = [
const monitorCertDaysRemaining = new PrometheusClient.Gauge({
name: "monitor_cert_days_remaining",
help: "The number of days remaining until the certificate expires",
labelNames: commonLabels
labelNames: commonLabels,
});
const monitorCertIsValid = new PrometheusClient.Gauge({
name: "monitor_cert_is_valid",
help: "Is the certificate still valid? (1 = Yes, 0= No)",
labelNames: commonLabels
labelNames: commonLabels,
});
const monitorResponseTime = new PrometheusClient.Gauge({
name: "monitor_response_time",
help: "Monitor Response Time (ms)",
labelNames: commonLabels
labelNames: commonLabels,
});
const monitorStatus = new PrometheusClient.Gauge({
name: "monitor_status",
help: "Monitor Status (1 = UP, 0= DOWN, 2= PENDING, 3= MAINTENANCE)",
labelNames: commonLabels
labelNames: commonLabels,
});
class Prometheus {
@ -44,7 +44,7 @@ class Prometheus {
monitor_type: monitor.type,
monitor_url: monitor.url,
monitor_hostname: monitor.hostname,
monitor_port: monitor.port
monitor_port: monitor.port,
};
}
@ -119,5 +119,5 @@ class Prometheus {
}
module.exports = {
Prometheus
Prometheus,
};

View file

@ -36,7 +36,7 @@ class Proxy {
if (!this.SUPPORTED_PROXY_PROTOCOLS.includes(proxy.protocol)) {
throw new Error(`
Unsupported proxy protocol "${proxy.protocol}.
Supported protocols are ${this.SUPPORTED_PROXY_PROTOCOLS.join(", ")}."`
Supported protocols are ${this.SUPPORTED_PROXY_PROTOCOLS.join(", ")}."`,
);
}
@ -92,7 +92,10 @@ class Proxy {
* @throws Proxy protocol is unsupported
*/
static createAgents(proxy, options) {
const { httpAgentOptions, httpsAgentOptions } = options || {};
const {
httpAgentOptions,
httpsAgentOptions,
} = options || {};
let agent;
let httpAgent;
let httpsAgent;
@ -150,12 +153,13 @@ class Proxy {
httpsAgent = agent;
break;
default: throw new Error(`Unsupported proxy protocol provided. ${proxy.protocol}`);
default:
throw new Error(`Unsupported proxy protocol provided. ${proxy.protocol}`);
}
return {
httpAgent,
httpsAgent
httpsAgent,
};
}

View file

@ -11,7 +11,15 @@ const { R } = require("redbean-node");
const apicache = require("../modules/apicache");
const Monitor = require("../model/monitor");
const dayjs = require("dayjs");
const { UP, MAINTENANCE, DOWN, PENDING, flipStatus, log, badgeConstants } = require("../../src/util");
const {
UP,
MAINTENANCE,
DOWN,
PENDING,
flipStatus,
log,
badgeConstants,
} = require("../../src/util");
const StatusPage = require("../model/status_page");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const { makeBadge } = require("badge-maker");
@ -28,7 +36,7 @@ let io = server.io;
router.get("/api/entry-page", async (request, response) => {
allowDevAllOrigin(response);
let result = { };
let result = {};
let hostname = request.hostname;
if ((await setting("trustProxy")) && request.headers["x-forwarded-host"]) {
hostname = request.headers["x-forwarded-host"];
@ -53,10 +61,10 @@ router.all("/api/push/:pushToken", async (request, response) => {
let status = (statusString === "up") ? UP : DOWN;
let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [
pushToken
pushToken,
]);
if (! monitor) {
if (!monitor) {
throw new Error("Monitor not found or not active.");
}
@ -127,7 +135,7 @@ router.all("/api/push/:pushToken", async (request, response) => {
} catch (e) {
response.status(404).json({
ok: false,
msg: e.message
msg: e.message,
});
}
});
@ -159,7 +167,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
[ requestedMonitorId ],
);
const badgeValues = { style };
@ -242,7 +250,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
[ requestedMonitorId ],
);
const badgeValues = { style };
@ -362,7 +370,7 @@ router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (
request.params.duration
? parseInt(request.params.duration, 10)
: 24,
720
720,
);
const overrideValue = value && parseFloat(value);
@ -376,7 +384,7 @@ router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (
AND public = 1
AND heartbeat.monitor_id = ?
`,
[ -requestedDuration, requestedMonitorId ]
[ -requestedDuration, requestedMonitorId ],
));
const badgeValues = { style };
@ -443,7 +451,7 @@ router.get("/api/badge/:id/cert-exp", cache("5 minutes"), async (request, respon
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
[ requestedMonitorId ],
);
const badgeValues = { style };
@ -528,7 +536,7 @@ router.get("/api/badge/:id/response", cache("5 minutes"), async (request, respon
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
[ requestedMonitorId ],
);
const badgeValues = { style };
@ -540,7 +548,7 @@ router.get("/api/badge/:id/response", cache("5 minutes"), async (request, respon
badgeValues.color = badgeConstants.naColor;
} else {
const heartbeat = await Monitor.getPreviousHeartbeat(
requestedMonitorId
requestedMonitorId,
);
if (!heartbeat.ping) {

View file

@ -2,7 +2,10 @@ let express = require("express");
const apicache = require("../modules/apicache");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const StatusPage = require("../model/status_page");
const { allowDevAllOrigin, sendHttpError } = require("../util-server");
const {
allowDevAllOrigin,
sendHttpError,
} = require("../util-server");
const { R } = require("redbean-node");
const { badgeConstants } = require("../../src/util");
const { makeBadge } = require("badge-maker");
@ -44,7 +47,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons
try {
// Get Status Page
let statusPage = await R.findOne("status_page", " slug = ? ", [
slug
slug,
]);
if (!statusPage) {
@ -81,7 +84,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
AND public = 1
AND \`group\`.status_page_id = ?
`, [
statusPageID
statusPageID,
]);
for (let monitorID of monitorIDList) {
@ -103,7 +106,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
response.json({
heartbeatList,
uptimeList
uptimeList,
});
} catch (error) {
@ -120,7 +123,7 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
try {
// Get Status Page
let statusPage = await R.findOne("status_page", " slug = ? ", [
slug
slug,
]);
if (!statusPage) {
@ -137,9 +140,9 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
{
"src": statusPage.icon,
"sizes": "128x128",
"type": "image/png"
}
]
"type": "image/png",
},
],
});
} catch (error) {
@ -159,7 +162,7 @@ router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, r
downColor = badgeConstants.defaultDownColor,
partialColor = "#F6BE00",
maintenanceColor = "#808080",
style = badgeConstants.defaultStyle
style = badgeConstants.defaultStyle,
} = request.query;
try {
@ -169,7 +172,7 @@ router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, r
AND public = 1
AND \`group\`.status_page_id = ?
`, [
statusPageID
statusPageID,
]);
let hasUp = false;

View file

@ -37,13 +37,19 @@ if (!semver.satisfies(nodeVersion, requiredNodeVersions)) {
}
const args = require("args-parser")(process.argv);
const { sleep, log, getRandomInt, genSecret, isDev } = require("../src/util");
const {
sleep,
log,
getRandomInt,
genSecret,
isDev,
} = require("../src/util");
const config = require("./config");
log.debug("server", "Arguments");
log.debug("server", args);
if (! process.env.NODE_ENV) {
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = "production";
}
@ -90,7 +96,16 @@ const Monitor = require("./model/monitor");
const User = require("./model/user");
log.debug("server", "Importing Settings");
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, doubleCheckPassword, shake256, SHAKE256_LENGTH, allowDevAllOrigin,
const {
getSettings,
setSettings,
setting,
initJWTSecret,
checkLogin,
doubleCheckPassword,
shake256,
SHAKE256_LENGTH,
allowDevAllOrigin,
} = require("./util-server");
log.debug("server", "Importing Notification");
@ -101,8 +116,14 @@ log.debug("server", "Importing Database");
const Database = require("./database");
log.debug("server", "Importing Background Jobs");
const { initBackgroundJobs, stopBackgroundJobs } = require("./jobs");
const { loginRateLimiter, twoFaRateLimiter } = require("./rate-limiter");
const {
initBackgroundJobs,
stopBackgroundJobs,
} = require("./jobs");
const {
loginRateLimiter,
twoFaRateLimiter,
} = require("./rate-limiter");
const { apiAuth } = require("./auth");
const { login } = require("./auth");
@ -122,7 +143,7 @@ const cloudflaredToken = args["cloudflared-token"] || process.env.UPTIME_KUMA_CL
// 2FA / notp verification defaults
const twoFAVerifyOptions = {
"window": 1,
"time": 30
"time": 30,
};
/**
@ -132,13 +153,26 @@ const twoFAVerifyOptions = {
const testMode = !!args["test"] || false;
// Must be after io instantiation
const { sendNotificationList, sendHeartbeatList, sendInfo, sendProxyList, sendDockerHostList, sendAPIKeyList, sendRemoteBrowserList, sendMonitorTypeList } = require("./client");
const {
sendNotificationList,
sendHeartbeatList,
sendInfo,
sendProxyList,
sendDockerHostList,
sendAPIKeyList,
sendRemoteBrowserList,
sendMonitorTypeList,
} = require("./client");
const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler");
const { databaseSocketHandler } = require("./socket-handlers/database-socket-handler");
const { remoteBrowserSocketHandler } = require("./socket-handlers/remote-browser-socket-handler");
const TwoFA = require("./2fa");
const StatusPage = require("./model/status_page");
const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler");
const {
cloudflaredSocketHandler,
autoStart: cloudflaredAutoStart,
stop: cloudflaredStop,
} = require("./socket-handlers/cloudflared-socket-handler");
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler");
const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler");
@ -933,8 +967,9 @@ let needSetup = false;
monitorID,
socket.userID,
]);
const monitorData = [{ id: monitor.id,
active: monitor.active
const monitorData = [ {
id: monitor.id,
active: monitor.active,
}];
const preloadData = await Monitor.preparePreloadData(monitorData);
callback({
@ -966,7 +1001,8 @@ let needSetup = false;
SELECT *
FROM heartbeat
WHERE monitor_id = ?
AND time > ${sqlHourOffset}
AND time
> ${sqlHourOffset}
ORDER BY time ASC
`, [
monitorID,
@ -1519,7 +1555,7 @@ let needSetup = false;
log.info("manage", `Clear Heartbeats Monitor: ${monitorID} User ID: ${socket.userID}`);
await R.exec("DELETE FROM heartbeat WHERE monitor_id = ?", [
monitorID
monitorID,
]);
await sendHeartbeatList(socket, monitorID, true, true);
@ -1658,7 +1694,7 @@ async function checkOwner(userID, monitorID) {
userID,
]);
if (! row) {
if (!row) {
throw new Error("You do not own this monitor.");
}
}
@ -1698,7 +1734,7 @@ async function afterLogin(socket, user) {
// Set server timezone from client browser if not set
// It should be run once only
if (! await Settings.get("initServerTimezone")) {
if (!await Settings.get("initServerTimezone")) {
log.debug("server", "emit initServerTimezone");
socket.emit("initServerTimezone");
}
@ -1722,7 +1758,7 @@ async function initDatabase(testMode = false) {
"jwtSecret",
]);
if (! jwtSecretBean) {
if (!jwtSecretBean) {
log.info("server", "JWT secret is not found, generate one.");
jwtSecretBean = await initJWTSecret();
log.info("server", "Stored JWT secret into database");

View file

@ -17,9 +17,7 @@ class Settings {
* }
* @type {{}}
*/
static cacheList = {
};
static cacheList = {};
static cacheCleaner = null;
@ -61,7 +59,7 @@ class Settings {
Settings.cacheList[key] = {
value: v,
timestamp: Date.now()
timestamp: Date.now(),
};
return v;
@ -129,7 +127,7 @@ class Settings {
for (let key of keyList) {
let bean = await R.findOne("setting", " `key` = ? ", [
key
key,
]);
if (bean == null) {

View file

@ -1,7 +1,11 @@
const tcpp = require("tcp-ping");
const ping = require("@louislam/ping");
const { R } = require("redbean-node");
const { log, genSecret, badgeConstants } = require("../src/util");
const {
log,
genSecret,
badgeConstants,
} = require("../src/util");
const passwordHash = require("./password-hash");
const { Resolver } = require("dns");
const iconv = require("iconv-lite");
@ -22,14 +26,20 @@ const tls = require("tls");
const {
dictionaries: {
rfc2865: { file, attributes },
rfc2865: {
file,
attributes,
},
},
} = require("node-radius-utils");
const dayjs = require("dayjs");
// SASLOptions used in JSDoc
// eslint-disable-next-line no-unused-vars
const { Kafka, SASLOptions } = require("kafkajs");
const {
Kafka,
SASLOptions,
} = require("kafkajs");
const crypto = require("crypto");
const isWindows = process.platform === /^win/.test(process.platform);
@ -75,7 +85,7 @@ exports.getOidcTokenClientCredentials = async (tokenEndpoint, clientId, clientSe
let client = new oauthProvider.Client({
client_id: clientId,
client_secret: clientSecret,
token_endpoint_auth_method: authMethod
token_endpoint_auth_method: authMethod,
});
// Increase default timeout and clock tolerance
@ -185,7 +195,12 @@ exports.pingAsync = function (hostname, ipv6 = false, size = 56) {
*/
exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, saslOptions = {}) {
return new Promise((resolve, reject) => {
const { interval = 20, allowAutoTopicCreation = false, ssl = false, clientId = "Uptime-Kuma" } = options;
const {
interval = 20,
allowAutoTopicCreation = false,
ssl = false,
clientId = "Uptime-Kuma",
} = options;
let connectedToKafka = false;
@ -213,7 +228,7 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
allowAutoTopicCreation: allowAutoTopicCreation,
retry: {
retries: 0,
}
},
});
producer.connect().then(
@ -234,14 +249,14 @@ exports.kafkaProducerAsync = function (brokers, topic, message, options = {}, sa
connectedToKafka = true;
clearTimeout(timeoutID);
});
}
},
).catch(
(e) => {
connectedToKafka = true;
producer.disconnect();
clearTimeout(timeoutID);
reject(new Error("Error in producer connection: " + e.message));
}
},
);
producer.on("producer.network.request_timeout", (_) => {
@ -409,7 +424,7 @@ exports.mysqlQuery = function (connectionString, query, password = undefined) {
return new Promise((resolve, reject) => {
const connection = mysql.createConnection({
uri: connectionString,
password
password,
});
connection.on("error", (err) => {
@ -494,8 +509,8 @@ exports.redisPingAsync = function (dsn, rejectUnauthorized) {
const client = redis.createClient({
url: dsn,
socket: {
rejectUnauthorized
}
rejectUnauthorized,
},
});
client.on("error", (err) => {
if (client.isOpen) {
@ -661,7 +676,7 @@ exports.checkCertificate = function (socket) {
return {
valid: valid,
certInfo: parsedInfo
certInfo: parsedInfo,
};
};
@ -693,7 +708,7 @@ exports.checkStatusCode = function (status, acceptedCodes) {
}
} else {
log.error("monitor", `${codeRange} is not a valid status code range`);
continue;
}
}
@ -925,14 +940,21 @@ module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
* @returns {Promise<object>} Result of gRPC query
*/
module.exports.grpcQuery = async (options) => {
const { grpcUrl, grpcProtobufData, grpcServiceName, grpcEnableTls, grpcMethod, grpcBody } = options;
const {
grpcUrl,
grpcProtobufData,
grpcServiceName,
grpcEnableTls,
grpcMethod,
grpcBody,
} = options;
const protocObject = protojs.parse(grpcProtobufData);
const protoServiceObject = protocObject.root.lookupService(grpcServiceName);
const Client = grpc.makeGenericClientConstructor({});
const credentials = grpcEnableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure();
const client = new Client(
grpcUrl,
credentials
credentials,
);
const grpcService = protoServiceObject.create(function (method, requestData, cb) {
const fullServiceName = method.fullName;
@ -955,14 +977,14 @@ module.exports.grpcQuery = async (options) => {
return resolve({
code: err.code,
errorMessage: err.details,
data: ""
data: "",
});
} else {
log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
return resolve({
code: 1,
errorMessage: "",
data: responseData
data: responseData,
});
}
});
@ -970,7 +992,7 @@ module.exports.grpcQuery = async (options) => {
return resolve({
code: -1,
errorMessage: `Error ${err}. Please review your gRPC configuration option. The service name must not include package name value, and the method name must follow camelCase format`,
data: ""
data: "",
});
}

View file

@ -81,5 +81,5 @@ class ArrayWithKey {
}
module.exports = {
ArrayWithKey
ArrayWithKey,
};

View file

@ -44,5 +44,5 @@ class LimitQueue extends ArrayWithKey {
}
module.exports = {
LimitQueue
LimitQueue,
};