mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2026-09-24 11:40:38 +01:00
Updated backend packages
This commit is contained in:
+72
-89
@@ -1,91 +1,74 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.5.10/schema.json",
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
"useIgnoreFile": true
|
"useIgnoreFile": true
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": false,
|
"ignoreUnknown": false,
|
||||||
"includes": [
|
"includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "!**/dist/**/*"]
|
||||||
"**/*.ts",
|
},
|
||||||
"**/*.tsx",
|
"formatter": {
|
||||||
"**/*.js",
|
"enabled": true,
|
||||||
"**/*.jsx",
|
"indentStyle": "tab",
|
||||||
"!**/dist/**/*"
|
"indentWidth": 4,
|
||||||
]
|
"lineWidth": 120,
|
||||||
},
|
"formatWithErrors": true
|
||||||
"formatter": {
|
},
|
||||||
"enabled": true,
|
"assist": {
|
||||||
"indentStyle": "tab",
|
"actions": {
|
||||||
"indentWidth": 4,
|
"source": {
|
||||||
"lineWidth": 120,
|
"organizeImports": {
|
||||||
"formatWithErrors": true
|
"level": "on",
|
||||||
},
|
"options": {
|
||||||
"assist": {
|
"groups": [
|
||||||
"actions": {
|
":BUN:",
|
||||||
"source": {
|
":NODE:",
|
||||||
"organizeImports": {
|
["npm:*", "npm:*/**"],
|
||||||
"level": "on",
|
":PACKAGE_WITH_PROTOCOL:",
|
||||||
"options": {
|
":URL:",
|
||||||
"groups": [
|
":PACKAGE:",
|
||||||
":BUN:",
|
["/src/*", "/src/**"],
|
||||||
":NODE:",
|
["/**"],
|
||||||
[
|
["#*", "#*/**"],
|
||||||
"npm:*",
|
":PATH:"
|
||||||
"npm:*/**"
|
]
|
||||||
],
|
}
|
||||||
":PACKAGE_WITH_PROTOCOL:",
|
}
|
||||||
":URL:",
|
}
|
||||||
":PACKAGE:",
|
}
|
||||||
[
|
},
|
||||||
"/src/*",
|
"linter": {
|
||||||
"/src/**"
|
"enabled": true,
|
||||||
],
|
"rules": {
|
||||||
[
|
"preset": "recommended",
|
||||||
"/**"
|
"correctness": {
|
||||||
],
|
"useUniqueElementIds": "off"
|
||||||
[
|
},
|
||||||
"#*",
|
"suspicious": {
|
||||||
"#*/**"
|
"noExplicitAny": "off"
|
||||||
],
|
},
|
||||||
":PATH:"
|
"performance": {
|
||||||
]
|
"noDelete": "off"
|
||||||
}
|
},
|
||||||
}
|
"nursery": "off",
|
||||||
}
|
"a11y": {
|
||||||
}
|
"useSemanticElements": "off",
|
||||||
},
|
"useValidAnchor": "off"
|
||||||
"linter": {
|
},
|
||||||
"enabled": true,
|
"style": {
|
||||||
"rules": {
|
"noParameterAssign": "error",
|
||||||
"recommended": true,
|
"useAsConstAssertion": "error",
|
||||||
"correctness": {
|
"useDefaultParameterLast": "error",
|
||||||
"useUniqueElementIds": "off"
|
"useEnumInitializers": "error",
|
||||||
},
|
"useSelfClosingElements": "error",
|
||||||
"suspicious": {
|
"useSingleVarDeclarator": "error",
|
||||||
"noExplicitAny": "off"
|
"noUnusedTemplateLiteral": "error",
|
||||||
},
|
"useNumberNamespace": "error",
|
||||||
"performance": {
|
"noInferrableTypes": "error",
|
||||||
"noDelete": "off"
|
"noUselessElse": "error"
|
||||||
},
|
}
|
||||||
"nursery": "off",
|
}
|
||||||
"a11y": {
|
}
|
||||||
"useSemanticElements": "off",
|
|
||||||
"useValidAnchor": "off"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"noParameterAssign": "error",
|
|
||||||
"useAsConstAssertion": "error",
|
|
||||||
"useDefaultParameterLast": "error",
|
|
||||||
"useEnumInitializers": "error",
|
|
||||||
"useSelfClosingElements": "error",
|
|
||||||
"useSingleVarDeclarator": "error",
|
|
||||||
"noUnusedTemplateLiteral": "error",
|
|
||||||
"useNumberNamespace": "error",
|
|
||||||
"noInferrableTypes": "error",
|
|
||||||
"noUselessElse": "error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
import knex from "knex";
|
import knex from "knex";
|
||||||
import {configGet, configHas} from "./lib/config.js";
|
import { configGet, configHas } from "./lib/config.js";
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ const generateDbConfig = () => {
|
|||||||
user: cfg.user,
|
user: cfg.user,
|
||||||
password: cfg.password,
|
password: cfg.password,
|
||||||
database: cfg.name,
|
database: cfg.name,
|
||||||
port: cfg.port,
|
port: cfg.port,
|
||||||
...(cfg.ssl ? { ssl: cfg.ssl } : {})
|
...(cfg.ssl ? { ssl: cfg.ssl } : {}),
|
||||||
},
|
},
|
||||||
migrations: {
|
migrations: {
|
||||||
tableName: "migrations",
|
tableName: "migrations",
|
||||||
@@ -37,6 +37,6 @@ const getInstance = () => {
|
|||||||
instance = knex(generateDbConfig());
|
instance = knex(generateDbConfig());
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default getInstance;
|
export default getInstance;
|
||||||
|
|||||||
+7
-11
@@ -161,12 +161,12 @@ const internal2fa = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await verify({
|
const result = await verify({
|
||||||
token: code,
|
token: code,
|
||||||
secret: auth.meta.totp_secret,
|
secret: auth.meta.totp_secret,
|
||||||
guardrails: createGuardrails({
|
guardrails: createGuardrails({
|
||||||
MIN_SECRET_BYTES: 10,
|
MIN_SECRET_BYTES: 10,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
throw new errs.AuthError("Invalid verification code");
|
throw new errs.AuthError("Invalid verification code");
|
||||||
@@ -288,11 +288,7 @@ const internal2fa = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getUserPasswordAuth: async (userId) => {
|
getUserPasswordAuth: async (userId) => {
|
||||||
const auth = await authModel
|
const auth = await authModel.query().where("user_id", userId).andWhere("type", "password").first();
|
||||||
.query()
|
|
||||||
.where("user_id", userId)
|
|
||||||
.andWhere("type", "password")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
throw new errs.ItemNotFoundError("Auth not found");
|
throw new errs.ItemNotFoundError("Auth not found");
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ const internalAccessList = {
|
|||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ["owner", "items", "clients", "proxy_hosts.access_list.[clients,items]"],
|
expand: ["owner", "items", "clients", "proxy_hosts.access_list.[clients,items]"],
|
||||||
},
|
},
|
||||||
true // skip masking
|
true, // skip masking
|
||||||
);
|
);
|
||||||
|
|
||||||
// Audit log
|
// Audit log
|
||||||
@@ -180,10 +180,10 @@ const internalAccessList = {
|
|||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ["owner", "items", "clients", "proxy_hosts.[certificate,access_list.[clients,items]]"],
|
expand: ["owner", "items", "clients", "proxy_hosts.[certificate,access_list.[clients,items]]"],
|
||||||
},
|
},
|
||||||
true // skip masking
|
true, // skip masking
|
||||||
);
|
);
|
||||||
|
|
||||||
await internalAccessList.build(freshRow)
|
await internalAccessList.build(freshRow);
|
||||||
if (Number.parseInt(freshRow.proxy_host_count, 10)) {
|
if (Number.parseInt(freshRow.proxy_host_count, 10)) {
|
||||||
await internalNginx.bulkGenerateConfigs("proxy_host", freshRow.proxy_hosts);
|
await internalNginx.bulkGenerateConfigs("proxy_host", freshRow.proxy_hosts);
|
||||||
}
|
}
|
||||||
@@ -202,17 +202,13 @@ const internalAccessList = {
|
|||||||
*/
|
*/
|
||||||
get: async (access, data, skipMasking) => {
|
get: async (access, data, skipMasking) => {
|
||||||
const thisData = data || {};
|
const thisData = data || {};
|
||||||
const accessData = await access.can("access_lists:get", thisData.id)
|
const accessData = await access.can("access_lists:get", thisData.id);
|
||||||
|
|
||||||
const query = accessListModel
|
const query = accessListModel
|
||||||
.query()
|
.query()
|
||||||
.select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count"))
|
.select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count"))
|
||||||
.leftJoin("proxy_host", function () {
|
.leftJoin("proxy_host", function () {
|
||||||
this.on("proxy_host.access_list_id", "=", "access_list.id").andOn(
|
this.on("proxy_host.access_list_id", "=", "access_list.id").andOn("proxy_host.is_deleted", "=", 0);
|
||||||
"proxy_host.is_deleted",
|
|
||||||
"=",
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.where("access_list.is_deleted", 0)
|
.where("access_list.is_deleted", 0)
|
||||||
.andWhere("access_list.id", thisData.id)
|
.andWhere("access_list.id", thisData.id)
|
||||||
@@ -267,19 +263,13 @@ const internalAccessList = {
|
|||||||
// 4. audit log
|
// 4. audit log
|
||||||
|
|
||||||
// 1. update row to be deleted
|
// 1. update row to be deleted
|
||||||
await accessListModel
|
await accessListModel.query().where("id", row.id).patch({
|
||||||
.query()
|
is_deleted: 1,
|
||||||
.where("id", row.id)
|
});
|
||||||
.patch({
|
|
||||||
is_deleted: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. update any proxy hosts that were using it (ignoring permissions)
|
// 2. update any proxy hosts that were using it (ignoring permissions)
|
||||||
if (row.proxy_hosts) {
|
if (row.proxy_hosts) {
|
||||||
await proxyHostModel
|
await proxyHostModel.query().where("access_list_id", "=", row.id).patch({ access_list_id: 0 });
|
||||||
.query()
|
|
||||||
.where("access_list_id", "=", row.id)
|
|
||||||
.patch({ access_list_id: 0 });
|
|
||||||
|
|
||||||
// 3. reconfigure those hosts, then reload nginx
|
// 3. reconfigure those hosts, then reload nginx
|
||||||
// set the access_list_id to zero for these items
|
// set the access_list_id to zero for these items
|
||||||
@@ -325,11 +315,7 @@ const internalAccessList = {
|
|||||||
.query()
|
.query()
|
||||||
.select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count"))
|
.select("access_list.*", accessListModel.raw("COUNT(proxy_host.id) as proxy_host_count"))
|
||||||
.leftJoin("proxy_host", function () {
|
.leftJoin("proxy_host", function () {
|
||||||
this.on("proxy_host.access_list_id", "=", "access_list.id").andOn(
|
this.on("proxy_host.access_list_id", "=", "access_list.id").andOn("proxy_host.is_deleted", "=", 0);
|
||||||
"proxy_host.is_deleted",
|
|
||||||
"=",
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.where("access_list.is_deleted", 0)
|
.where("access_list.is_deleted", 0)
|
||||||
.groupBy("access_list.id")
|
.groupBy("access_list.id")
|
||||||
@@ -371,10 +357,7 @@ const internalAccessList = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getCount: async (userId, visibility) => {
|
getCount: async (userId, visibility) => {
|
||||||
const query = accessListModel
|
const query = accessListModel.query().count("id as count").where("is_deleted", 0);
|
||||||
.query()
|
|
||||||
.count("id as count")
|
|
||||||
.where("is_deleted", 0);
|
|
||||||
|
|
||||||
if (visibility !== "all") {
|
if (visibility !== "all") {
|
||||||
query.andWhere("owner_user_id", userId);
|
query.andWhere("owner_user_id", userId);
|
||||||
@@ -436,20 +419,24 @@ const internalAccessList = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. create empty access file
|
// 2. create empty access file
|
||||||
fs.writeFileSync(htpasswdFile, '', {encoding: 'utf8'});
|
fs.writeFileSync(htpasswdFile, "", { encoding: "utf8" });
|
||||||
|
|
||||||
// 3. generate password for each user
|
// 3. generate password for each user
|
||||||
if (list.items.length) {
|
if (list.items.length) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
batchflow(list.items).sequential()
|
batchflow(list.items)
|
||||||
|
.sequential()
|
||||||
.each((_i, item, next) => {
|
.each((_i, item, next) => {
|
||||||
if (item.password?.length) {
|
if (item.password?.length) {
|
||||||
logger.info(`Adding: ${item.username}`);
|
logger.info(`Adding: ${item.username}`);
|
||||||
|
|
||||||
utils.execFile('openssl', ['passwd', '-apr1', item.password])
|
utils
|
||||||
|
.execFile("openssl", ["passwd", "-apr1", item.password])
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
try {
|
try {
|
||||||
fs.appendFileSync(htpasswdFile, `${item.username}:${res}\n`, {encoding: 'utf8'});
|
fs.appendFileSync(htpasswdFile, `${item.username}:${res}\n`, {
|
||||||
|
encoding: "utf8",
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
@@ -471,7 +458,7 @@ const internalAccessList = {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default internalAccessList;
|
export default internalAccessList;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { castJsonIfNeed } from "../lib/helpers.js";
|
|||||||
import auditLogModel from "../models/audit-log.js";
|
import auditLogModel from "../models/audit-log.js";
|
||||||
|
|
||||||
const internalAuditLog = {
|
const internalAuditLog = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All logs
|
* All logs
|
||||||
*
|
*
|
||||||
@@ -46,11 +45,7 @@ const internalAuditLog = {
|
|||||||
get: async (access, data) => {
|
get: async (access, data) => {
|
||||||
await access.can("auditlog:list");
|
await access.can("auditlog:list");
|
||||||
|
|
||||||
const query = auditLogModel
|
const query = auditLogModel.query().andWhere("id", data.id).allowGraph("[user]").first();
|
||||||
.query()
|
|
||||||
.andWhere("id", data.id)
|
|
||||||
.allowGraph("[user]")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (typeof data.expand !== "undefined" && data.expand !== null) {
|
if (typeof data.expand !== "undefined" && data.expand !== null) {
|
||||||
query.withGraphFetched(`[${data.expand.join(", ")}]`);
|
query.withGraphFetched(`[${data.expand.join(", ")}]`);
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ const internalDeadHost = {
|
|||||||
thisData.advanced_config = "";
|
thisData.advanced_config = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const row = await deadHostModel.query()
|
const row = await deadHostModel.query().insertAndFetch(thisData).then(utils.omitRow(omissions()));
|
||||||
.insertAndFetch(thisData)
|
|
||||||
.then(utils.omitRow(omissions()));
|
|
||||||
|
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
await internalAuditLog.add(access, {
|
await internalAuditLog.add(access, {
|
||||||
@@ -153,12 +151,8 @@ const internalDeadHost = {
|
|||||||
|
|
||||||
thisData = internalHost.cleanSslHstsData(thisData, row);
|
thisData = internalHost.cleanSslHstsData(thisData, row);
|
||||||
|
|
||||||
|
|
||||||
// do the row update
|
// do the row update
|
||||||
await deadHostModel
|
await deadHostModel.query().where({ id: data.id }).patch(data);
|
||||||
.query()
|
|
||||||
.where({id: data.id})
|
|
||||||
.patch(data);
|
|
||||||
|
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
await internalAuditLog.add(access, {
|
await internalAuditLog.add(access, {
|
||||||
@@ -168,11 +162,10 @@ const internalDeadHost = {
|
|||||||
meta: thisData,
|
meta: thisData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const thisRow = await internalDeadHost
|
const thisRow = await internalDeadHost.get(access, {
|
||||||
.get(access, {
|
id: thisData.id,
|
||||||
id: thisData.id,
|
expand: ["owner", "certificate"],
|
||||||
expand: ["owner", "certificate"],
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Configure nginx
|
// Configure nginx
|
||||||
const newMeta = await internalNginx.configure(deadHostModel, "dead_host", row);
|
const newMeta = await internalNginx.configure(deadHostModel, "dead_host", row);
|
||||||
@@ -224,18 +217,15 @@ const internalDeadHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
delete: async (access, data) => {
|
delete: async (access, data) => {
|
||||||
await access.can("dead_hosts:delete", data.id)
|
await access.can("dead_hosts:delete", data.id);
|
||||||
const row = await internalDeadHost.get(access, { id: data.id });
|
const row = await internalDeadHost.get(access, { id: data.id });
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
throw new errs.ItemNotFoundError(data.id);
|
throw new errs.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
await deadHostModel
|
await deadHostModel.query().where("id", row.id).patch({
|
||||||
.query()
|
is_deleted: 1,
|
||||||
.where("id", row.id)
|
});
|
||||||
.patch({
|
|
||||||
is_deleted: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete Nginx Config
|
// Delete Nginx Config
|
||||||
await internalNginx.deleteConfig("dead_host", row);
|
await internalNginx.deleteConfig("dead_host", row);
|
||||||
@@ -259,7 +249,7 @@ const internalDeadHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
enable: async (access, data) => {
|
enable: async (access, data) => {
|
||||||
await access.can("dead_hosts:update", data.id)
|
await access.can("dead_hosts:update", data.id);
|
||||||
const row = await internalDeadHost.get(access, {
|
const row = await internalDeadHost.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ["certificate", "owner"],
|
expand: ["certificate", "owner"],
|
||||||
@@ -273,12 +263,9 @@ const internalDeadHost = {
|
|||||||
|
|
||||||
row.enabled = 1;
|
row.enabled = 1;
|
||||||
|
|
||||||
await deadHostModel
|
await deadHostModel.query().where("id", row.id).patch({
|
||||||
.query()
|
enabled: 1,
|
||||||
.where("id", row.id)
|
});
|
||||||
.patch({
|
|
||||||
enabled: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Configure nginx
|
// Configure nginx
|
||||||
await internalNginx.configure(deadHostModel, "dead_host", row);
|
await internalNginx.configure(deadHostModel, "dead_host", row);
|
||||||
@@ -301,7 +288,7 @@ const internalDeadHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
disable: async (access, data) => {
|
disable: async (access, data) => {
|
||||||
await access.can("dead_hosts:update", data.id)
|
await access.can("dead_hosts:update", data.id);
|
||||||
const row = await internalDeadHost.get(access, { id: data.id });
|
const row = await internalDeadHost.get(access, { id: data.id });
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
throw new errs.ItemNotFoundError(data.id);
|
throw new errs.ItemNotFoundError(data.id);
|
||||||
@@ -312,12 +299,9 @@ const internalDeadHost = {
|
|||||||
|
|
||||||
row.enabled = 0;
|
row.enabled = 0;
|
||||||
|
|
||||||
await deadHostModel
|
await deadHostModel.query().where("id", row.id).patch({
|
||||||
.query()
|
enabled: 0,
|
||||||
.where("id", row.id)
|
});
|
||||||
.patch({
|
|
||||||
enabled: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete Nginx Config
|
// Delete Nginx Config
|
||||||
await internalNginx.deleteConfig("dead_host", row);
|
await internalNginx.deleteConfig("dead_host", row);
|
||||||
@@ -342,7 +326,7 @@ const internalDeadHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getAll: async (access, expand, searchQuery) => {
|
getAll: async (access, expand, searchQuery) => {
|
||||||
const accessData = await access.can("dead_hosts:list")
|
const accessData = await access.can("dead_hosts:list");
|
||||||
const query = deadHostModel
|
const query = deadHostModel
|
||||||
.query()
|
.query()
|
||||||
.where("is_deleted", 0)
|
.where("is_deleted", 0)
|
||||||
|
|||||||
@@ -217,7 +217,10 @@ const internalNginx = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For redirection hosts, if the scheme is not http or https, set it to $scheme
|
// For redirection hosts, if the scheme is not http or https, set it to $scheme
|
||||||
if (nice_host_type === "redirection_host" && ['http', 'https'].indexOf(host.forward_scheme.toLowerCase()) === -1) {
|
if (
|
||||||
|
nice_host_type === "redirection_host" &&
|
||||||
|
["http", "https"].indexOf(host.forward_scheme.toLowerCase()) === -1
|
||||||
|
) {
|
||||||
host.forward_scheme = "$scheme";
|
host.forward_scheme = "$scheme";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,7 @@ export default {
|
|||||||
throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth = await authModel
|
const auth = await authModel.query().where("user_id", "=", user.id).where("type", "=", "password").first();
|
||||||
.query()
|
|
||||||
.where("user_id", "=", user.id)
|
|
||||||
.where("type", "=", "password")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
||||||
@@ -50,10 +46,7 @@ export default {
|
|||||||
|
|
||||||
const valid = await auth.verifyPassword(data.secret);
|
const valid = await auth.verifyPassword(data.secret);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new errs.AuthError(
|
throw new errs.AuthError(ERROR_MESSAGE_INVALID_AUTH, ERROR_MESSAGE_INVALID_AUTH_I18N);
|
||||||
ERROR_MESSAGE_INVALID_AUTH,
|
|
||||||
ERROR_MESSAGE_INVALID_AUTH_I18N,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.scope !== "user" && _.indexOf(user.roles, data.scope) === -1) {
|
if (data.scope !== "user" && _.indexOf(user.roles, data.scope) === -1) {
|
||||||
@@ -171,7 +164,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check scope
|
// Check scope
|
||||||
if (!tokenData.scope || tokenData.scope[0] !== "2fa-challenge") {
|
if (tokenData.scope?.[0] !== "2fa-challenge") {
|
||||||
throw new errs.AuthError("Invalid challenge token");
|
throw new errs.AuthError("Invalid challenge token");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,10 +176,7 @@ export default {
|
|||||||
// Verify 2FA code
|
// Verify 2FA code
|
||||||
const valid = await twoFactor.verifyForLogin(userId, code);
|
const valid = await twoFactor.verifyForLogin(userId, code);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new errs.AuthError(
|
throw new errs.AuthError(ERROR_MESSAGE_INVALID_2FA, ERROR_MESSAGE_INVALID_2FA_I18N);
|
||||||
ERROR_MESSAGE_INVALID_2FA,
|
|
||||||
ERROR_MESSAGE_INVALID_2FA_I18N,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create full token
|
// Create full token
|
||||||
|
|||||||
@@ -257,11 +257,9 @@ const internalUser = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
deleteAll: async () => {
|
deleteAll: async () => {
|
||||||
await userModel
|
await userModel.query().patch({
|
||||||
.query()
|
is_deleted: 1,
|
||||||
.patch({
|
});
|
||||||
is_deleted: 1,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+11
-11
@@ -1,19 +1,19 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
development: {
|
development: {
|
||||||
client: 'mysql2',
|
client: "mysql2",
|
||||||
migrations: {
|
migrations: {
|
||||||
tableName: 'migrations',
|
tableName: "migrations",
|
||||||
stub: 'lib/migrate_template.js',
|
stub: "lib/migrate_template.js",
|
||||||
directory: 'migrations'
|
directory: "migrations",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
production: {
|
production: {
|
||||||
client: 'mysql2',
|
client: "mysql2",
|
||||||
migrations: {
|
migrations: {
|
||||||
tableName: 'migrations',
|
tableName: "migrations",
|
||||||
stub: 'lib/migrate_template.js',
|
stub: "lib/migrate_template.js",
|
||||||
directory: 'migrations'
|
directory: "migrations",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,10 +119,7 @@ export default function (tokenString) {
|
|||||||
|
|
||||||
// Proxy Hosts
|
// Proxy Hosts
|
||||||
case "proxy_hosts": {
|
case "proxy_hosts": {
|
||||||
const query = proxyHostModel
|
const query = proxyHostModel.query().select("id").andWhere("is_deleted", 0);
|
||||||
.query()
|
|
||||||
.select("id")
|
|
||||||
.andWhere("is_deleted", 0);
|
|
||||||
|
|
||||||
if (permissions.visibility === "user") {
|
if (permissions.visibility === "user") {
|
||||||
query.andWhere("owner_user_id", tokenUserId);
|
query.andWhere("owner_user_id", tokenUserId);
|
||||||
|
|||||||
+36
-16
@@ -2,13 +2,13 @@ import fs from "node:fs";
|
|||||||
import NodeRSA from "node-rsa";
|
import NodeRSA from "node-rsa";
|
||||||
import { global as logger } from "../logger.js";
|
import { global as logger } from "../logger.js";
|
||||||
|
|
||||||
const keysFile = '/data/keys.json';
|
const keysFile = "/data/keys.json";
|
||||||
const mysqlEngine = 'mysql2';
|
const mysqlEngine = "mysql2";
|
||||||
const postgresEngine = 'pg';
|
const postgresEngine = "pg";
|
||||||
const sqliteClientName = 'better-sqlite3';
|
const sqliteClientName = "better-sqlite3";
|
||||||
|
|
||||||
// Not used for new setups anymore but may exist in legacy setups
|
// Not used for new setups anymore but may exist in legacy setups
|
||||||
const legacySqliteClientName = 'sqlite3';
|
const legacySqliteClientName = "sqlite3";
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
@@ -40,14 +40,20 @@ const configure = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toBool = (v) => /^(1|true|yes|on)$/i.test((v || '').trim());
|
const toBool = (v) => /^(1|true|yes|on)$/i.test((v || "").trim());
|
||||||
|
|
||||||
const envMysqlHost = process.env.DB_MYSQL_HOST || null;
|
const envMysqlHost = process.env.DB_MYSQL_HOST || null;
|
||||||
const envMysqlUser = process.env.DB_MYSQL_USER || null;
|
const envMysqlUser = process.env.DB_MYSQL_USER || null;
|
||||||
const envMysqlName = process.env.DB_MYSQL_NAME || null;
|
const envMysqlName = process.env.DB_MYSQL_NAME || null;
|
||||||
const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL);
|
const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL);
|
||||||
const envMysqlSSLRejectUnauthorized = process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined ? true : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED);
|
const envMysqlSSLRejectUnauthorized =
|
||||||
const envMysqlSSLVerifyIdentity = process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined ? true : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY);
|
process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined
|
||||||
|
? true
|
||||||
|
: toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED);
|
||||||
|
const envMysqlSSLVerifyIdentity =
|
||||||
|
process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined
|
||||||
|
? true
|
||||||
|
: toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY);
|
||||||
if (envMysqlHost && envMysqlUser && envMysqlName) {
|
if (envMysqlHost && envMysqlUser && envMysqlName) {
|
||||||
// we have enough mysql creds to go with mysql
|
// we have enough mysql creds to go with mysql
|
||||||
logger.info("Using MySQL configuration");
|
logger.info("Using MySQL configuration");
|
||||||
@@ -58,8 +64,10 @@ const configure = () => {
|
|||||||
port: process.env.DB_MYSQL_PORT || 3306,
|
port: process.env.DB_MYSQL_PORT || 3306,
|
||||||
user: envMysqlUser,
|
user: envMysqlUser,
|
||||||
password: process.env.DB_MYSQL_PASSWORD,
|
password: process.env.DB_MYSQL_PASSWORD,
|
||||||
name: envMysqlName,
|
name: envMysqlName,
|
||||||
ssl: envMysqlSSL ? { rejectUnauthorized: envMysqlSSLRejectUnauthorized, verifyIdentity: envMysqlSSLVerifyIdentity } : false,
|
ssl: envMysqlSSL
|
||||||
|
? { rejectUnauthorized: envMysqlSSLRejectUnauthorized, verifyIdentity: envMysqlSSLVerifyIdentity }
|
||||||
|
: false,
|
||||||
},
|
},
|
||||||
keys: getKeys(),
|
keys: getKeys(),
|
||||||
};
|
};
|
||||||
@@ -222,7 +230,7 @@ const isDebugMode = () => !!process.env.DEBUG;
|
|||||||
*
|
*
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
const isCI = () => process.env.CI === 'true' && process.env.DEBUG === 'true';
|
const isCI = () => process.env.CI === "true" && process.env.DEBUG === "true";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a public key
|
* Returns a public key
|
||||||
@@ -259,4 +267,16 @@ const useLetsencryptServer = () => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { isCI, configHas, configGet, isSqlite, isMysql, isPostgres, isDebugMode, getPrivateKey, getPublicKey, useLetsencryptStaging, useLetsencryptServer };
|
export {
|
||||||
|
isCI,
|
||||||
|
configHas,
|
||||||
|
configGet,
|
||||||
|
isSqlite,
|
||||||
|
isMysql,
|
||||||
|
isPostgres,
|
||||||
|
isDebugMode,
|
||||||
|
getPrivateKey,
|
||||||
|
getPublicKey,
|
||||||
|
useLetsencryptStaging,
|
||||||
|
useLetsencryptServer,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
|
||||||
export default (default_sort, default_offset, default_limit, max_limit) => {
|
export default (default_sort, default_offset, default_limit, max_limit) => {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export default (req, res, next) => {
|
export default (req, res, next) => {
|
||||||
if (req.params.user_id === 'me' && res.locals.access) {
|
if (req.params.user_id === "me" && res.locals.access) {
|
||||||
req.params.user_id = res.locals.access.token.get('attrs').id;
|
req.params.user_id = res.locals.access.token.get("attrs").id;
|
||||||
} else {
|
} else {
|
||||||
req.params.user_id = Number.parseInt(req.params.user_id, 10);
|
req.params.user_id = Number.parseInt(req.params.user_id, 10);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,21 +24,17 @@ const apiValidator = async (schema, payload /*, description*/) => {
|
|||||||
throw new errs.ValidationError("Payload is undefined");
|
throw new errs.ValidationError("Payload is undefined");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const validate = ajv.compile(schema);
|
const validate = ajv.compile(schema);
|
||||||
|
|
||||||
const valid = validate(payload);
|
const valid = validate(payload);
|
||||||
|
|
||||||
|
|
||||||
if (valid && !validate.errors) {
|
if (valid && !validate.errors) {
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const message = ajv.errorsText(validate.errors);
|
const message = ajv.errorsText(validate.errors);
|
||||||
const err = new errs.ValidationError(message);
|
const err = new errs.ValidationError(message);
|
||||||
err.debug = {validationErrors: validate.errors, payload};
|
err.debug = { validationErrors: validate.errors, payload };
|
||||||
throw err;
|
throw err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Ajv from 'ajv/dist/2020.js';
|
import Ajv from "ajv/dist/2020.js";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import commonDefinitions from "../../schema/common.json" with { type: "json" };
|
import commonDefinitions from "../../schema/common.json" with { type: "json" };
|
||||||
import errs from "../error.js";
|
import errs from "../error.js";
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ const migrateName = "settings";
|
|||||||
const up = (knex) => {
|
const up = (knex) => {
|
||||||
logger.info(`[${migrateName}] Migrating Up...`);
|
logger.info(`[${migrateName}] Migrating Up...`);
|
||||||
|
|
||||||
return knex.schema.createTable('setting', (table) => {
|
return knex.schema
|
||||||
table.string('id').notNull().primary();
|
.createTable("setting", (table) => {
|
||||||
table.string('name', 100).notNull();
|
table.string("id").notNull().primary();
|
||||||
table.string('description', 255).notNull();
|
table.string("name", 100).notNull();
|
||||||
table.string('value', 255).notNull();
|
table.string("description", 255).notNull();
|
||||||
table.json('meta').notNull();
|
table.string("value", 255).notNull();
|
||||||
})
|
table.json("meta").notNull();
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`[${migrateName}] setting Table created`);
|
logger.info(`[${migrateName}] setting Table created`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ const up = (knex) => {
|
|||||||
.table("redirection_host", async (table) => {
|
.table("redirection_host", async (table) => {
|
||||||
// change the column default from $scheme to auto
|
// change the column default from $scheme to auto
|
||||||
await table.string("forward_scheme").notNull().defaultTo("auto").alter();
|
await table.string("forward_scheme").notNull().defaultTo("auto").alter();
|
||||||
await knex('redirection_host')
|
await knex("redirection_host").where("forward_scheme", "$scheme").update({ forward_scheme: "auto" });
|
||||||
.where('forward_scheme', '$scheme')
|
|
||||||
.update({ forward_scheme: 'auto' });
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`[${migrateName}] redirection_host Table altered`);
|
logger.info(`[${migrateName}] redirection_host Table altered`);
|
||||||
@@ -38,9 +36,7 @@ const down = (knex) => {
|
|||||||
return knex.schema
|
return knex.schema
|
||||||
.table("redirection_host", async (table) => {
|
.table("redirection_host", async (table) => {
|
||||||
await table.string("forward_scheme").notNull().defaultTo("$scheme").alter();
|
await table.string("forward_scheme").notNull().defaultTo("$scheme").alter();
|
||||||
await knex('redirection_host')
|
await knex("redirection_host").where("forward_scheme", "auto").update({ forward_scheme: "$scheme" });
|
||||||
.where('forward_scheme', 'auto')
|
|
||||||
.update({ forward_scheme: '$scheme' });
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`[${migrateName}] redirection_host Table altered`);
|
logger.info(`[${migrateName}] redirection_host Table altered`);
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ const migrateName = "trust_forwarded_proto";
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const up = (knex) => {
|
const up = (knex) => {
|
||||||
logger.info(`[${migrateName}] Migrating Up...`);
|
logger.info(`[${migrateName}] Migrating Up...`);
|
||||||
|
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.alterTable('proxy_host', (table) => {
|
.alterTable("proxy_host", (table) => {
|
||||||
table.tinyint('trust_forwarded_proto').notNullable().defaultTo(0);
|
table.tinyint("trust_forwarded_proto").notNullable().defaultTo(0);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`[${migrateName}] proxy_host Table altered`);
|
logger.info(`[${migrateName}] proxy_host Table altered`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,15 +29,15 @@ const up = (knex) => {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const down = (knex) => {
|
const down = (knex) => {
|
||||||
logger.info(`[${migrateName}] Migrating Down...`);
|
logger.info(`[${migrateName}] Migrating Down...`);
|
||||||
|
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.alterTable('proxy_host', (table) => {
|
.alterTable("proxy_host", (table) => {
|
||||||
table.dropColumn('trust_forwarded_proto');
|
table.dropColumn("trust_forwarded_proto");
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`[${migrateName}] proxy_host Table altered`);
|
logger.info(`[${migrateName}] proxy_host Table altered`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export { up, down };
|
export { up, down };
|
||||||
|
|||||||
@@ -7,23 +7,23 @@ import db from "../db.js";
|
|||||||
Model.knex(db());
|
Model.knex(db());
|
||||||
|
|
||||||
class Setting extends Model {
|
class Setting extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert() {
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === "undefined") {
|
||||||
this.meta = {};
|
this.meta = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name() {
|
||||||
return 'Setting';
|
return "Setting";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get tableName () {
|
static get tableName() {
|
||||||
return 'setting';
|
return "setting";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get jsonAttributes () {
|
static get jsonAttributes() {
|
||||||
return ['meta'];
|
return ["meta"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ import now from "./now_helper.js";
|
|||||||
Model.knex(db());
|
Model.knex(db());
|
||||||
|
|
||||||
class UserPermission extends Model {
|
class UserPermission extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert() {
|
||||||
this.created_on = now();
|
this.created_on = now();
|
||||||
this.modified_on = now();
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate() {
|
||||||
this.modified_on = now();
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name() {
|
||||||
return 'UserPermission';
|
return "UserPermission";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get tableName () {
|
static get tableName() {
|
||||||
return 'user_permission';
|
return "user_permission";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -13,37 +13,37 @@
|
|||||||
"regenerate-config": "node scripts/regenerate-config"
|
"regenerate-config": "node scripts/regenerate-config"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apidevtools/json-schema-ref-parser": "^15.3.5",
|
"@apidevtools/json-schema-ref-parser": "^16.0.0",
|
||||||
"ajv": "^8.20.0",
|
"ajv": "^8.20.0",
|
||||||
"archiver": "^8.0.0",
|
"archiver": "^8.0.0",
|
||||||
"batchflow": "^0.4.0",
|
"batchflow": "^0.4.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"better-sqlite3": "^12.10.0",
|
"better-sqlite3": "^13.0.3",
|
||||||
"body-parser": "^2.2.2",
|
"body-parser": "^2.3.0",
|
||||||
"chalk": "5.6.2",
|
"chalk": "5.6.2",
|
||||||
"compression": "^1.8.1",
|
"compression": "^1.8.1",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"express-fileupload": "^1.5.2",
|
"express-fileupload": "^1.5.2",
|
||||||
"gravatar": "^1.8.2",
|
"gravatar": "^1.8.2",
|
||||||
"jsonwebtoken": "^9.0.3",
|
"jsonwebtoken": "^9.0.3",
|
||||||
"knex": "3.2.10",
|
"knex": "3.3.0",
|
||||||
"liquidjs": "10.27.0",
|
"liquidjs": "10.29.0",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mysql2": "^3.22.3",
|
"mysql2": "^3.23.4",
|
||||||
"node-rsa": "^2.0.0",
|
"node-rsa": "^2.0.0",
|
||||||
"objection": "3.1.5",
|
"objection": "3.1.5",
|
||||||
"otplib": "^13.4.0",
|
"otplib": "^13.5.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"pg": "^8.21.0",
|
"pg": "^8.23.0",
|
||||||
"proxy-agent": "^8.0.1",
|
"proxy-agent": "^8.0.2",
|
||||||
"signale": "1.4.0",
|
"signale": "1.4.0",
|
||||||
"sqlite3": "^6.0.1",
|
"sqlite3": "^6.0.1",
|
||||||
"temp-write": "^6.0.1"
|
"temp-write": "^6.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@apidevtools/swagger-parser": "^12.1.0",
|
"@apidevtools/swagger-parser": "^12.1.0",
|
||||||
"@biomejs/biome": "^2.4.15",
|
"@biomejs/biome": "^2.5.10",
|
||||||
"nodemon": "^3.1.14"
|
"nodemon": "^3.1.14"
|
||||||
},
|
},
|
||||||
"signale": {
|
"signale": {
|
||||||
|
|||||||
@@ -86,10 +86,7 @@ router
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
event_id: req.params.event_id,
|
event_id: req.params.event_id,
|
||||||
expand:
|
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
|
||||||
typeof req.query.expand === "string"
|
|
||||||
? req.query.expand.split(",")
|
|
||||||
: null,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -44,18 +44,11 @@ router
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expand:
|
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
|
||||||
typeof req.query.expand === "string"
|
|
||||||
? req.query.expand.split(",")
|
|
||||||
: null,
|
|
||||||
query: typeof req.query.query === "string" ? req.query.query : null,
|
query: typeof req.query.query === "string" ? req.query.query : null,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const rows = await internalCertificate.getAll(
|
const rows = await internalCertificate.getAll(res.locals.access, data.expand, data.query);
|
||||||
res.locals.access,
|
|
||||||
data.expand,
|
|
||||||
data.query,
|
|
||||||
);
|
|
||||||
res.status(200).send(rows);
|
res.status(200).send(rows);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -70,15 +63,9 @@ router
|
|||||||
*/
|
*/
|
||||||
.post(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/nginx/certificates", "post"), req.body);
|
||||||
getValidationSchema("/nginx/certificates", "post"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
req.setTimeout(900000); // 15 minutes timeout
|
req.setTimeout(900000); // 15 minutes timeout
|
||||||
const result = await internalCertificate.create(
|
const result = await internalCertificate.create(res.locals.access, payload);
|
||||||
res.locals.access,
|
|
||||||
payload,
|
|
||||||
);
|
|
||||||
res.status(201).send(result);
|
res.status(201).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -139,16 +126,10 @@ router
|
|||||||
*/
|
*/
|
||||||
.post(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/nginx/certificates/test-http", "post"), req.body);
|
||||||
getValidationSchema("/nginx/certificates/test-http", "post"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
req.setTimeout(60000); // 1 minute timeout
|
req.setTimeout(60000); // 1 minute timeout
|
||||||
|
|
||||||
const result = await internalCertificate.testHttpsChallenge(
|
const result = await internalCertificate.testHttpsChallenge(res.locals.access, payload);
|
||||||
res.locals.access,
|
|
||||||
payload,
|
|
||||||
);
|
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -224,10 +205,7 @@ router
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
certificate_id: req.params.certificate_id,
|
certificate_id: req.params.certificate_id,
|
||||||
expand:
|
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
|
||||||
typeof req.query.expand === "string"
|
|
||||||
? req.query.expand.split(",")
|
|
||||||
: null,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const row = await internalCertificate.get(res.locals.access, {
|
const row = await internalCertificate.get(res.locals.access, {
|
||||||
|
|||||||
+10
-41
@@ -48,18 +48,11 @@ router
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expand:
|
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
|
||||||
typeof req.query.expand === "string"
|
|
||||||
? req.query.expand.split(",")
|
|
||||||
: null,
|
|
||||||
query: typeof req.query.query === "string" ? req.query.query : null,
|
query: typeof req.query.query === "string" ? req.query.query : null,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const users = await internalUser.getAll(
|
const users = await internalUser.getAll(res.locals.access, data.expand, data.query);
|
||||||
res.locals.access,
|
|
||||||
data.expand,
|
|
||||||
data.query,
|
|
||||||
);
|
|
||||||
res.status(200).send(users);
|
res.status(200).send(users);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -95,10 +88,7 @@ router
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/users", "post"), body);
|
||||||
getValidationSchema("/users", "post"),
|
|
||||||
body,
|
|
||||||
);
|
|
||||||
const user = await internalUser.create(res.locals.access, payload);
|
const user = await internalUser.create(res.locals.access, payload);
|
||||||
res.status(201).send(user);
|
res.status(201).send(user);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -169,20 +159,14 @@ router
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
user_id: req.params.user_id,
|
user_id: req.params.user_id,
|
||||||
expand:
|
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
|
||||||
typeof req.query.expand === "string"
|
|
||||||
? req.query.expand.split(",")
|
|
||||||
: null,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const user = await internalUser.get(res.locals.access, {
|
const user = await internalUser.get(res.locals.access, {
|
||||||
id: data.user_id,
|
id: data.user_id,
|
||||||
expand: data.expand,
|
expand: data.expand,
|
||||||
omit: internalUser.getUserOmisionsByAccess(
|
omit: internalUser.getUserOmisionsByAccess(res.locals.access, data.user_id),
|
||||||
res.locals.access,
|
|
||||||
data.user_id,
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
res.status(200).send(user);
|
res.status(200).send(user);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -198,10 +182,7 @@ router
|
|||||||
*/
|
*/
|
||||||
.put(async (req, res, next) => {
|
.put(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/users/{userID}", "put"), req.body);
|
||||||
getValidationSchema("/users/{userID}", "put"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
payload.id = req.params.user_id;
|
payload.id = req.params.user_id;
|
||||||
const result = await internalUser.update(res.locals.access, payload);
|
const result = await internalUser.update(res.locals.access, payload);
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
@@ -248,10 +229,7 @@ router
|
|||||||
*/
|
*/
|
||||||
.put(async (req, res, next) => {
|
.put(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/users/{userID}/auth", "put"), req.body);
|
||||||
getValidationSchema("/users/{userID}/auth", "put"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
payload.id = req.params.user_id;
|
payload.id = req.params.user_id;
|
||||||
const result = await internalUser.setPassword(res.locals.access, payload);
|
const result = await internalUser.setPassword(res.locals.access, payload);
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
@@ -281,15 +259,9 @@ router
|
|||||||
*/
|
*/
|
||||||
.put(async (req, res, next) => {
|
.put(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const payload = await apiValidator(
|
const payload = await apiValidator(getValidationSchema("/users/{userID}/permissions", "put"), req.body);
|
||||||
getValidationSchema("/users/{userID}/permissions", "put"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
payload.id = req.params.user_id;
|
payload.id = req.params.user_id;
|
||||||
const result = await internalUser.setPermissions(
|
const result = await internalUser.setPermissions(res.locals.access, payload);
|
||||||
res.locals.access,
|
|
||||||
payload,
|
|
||||||
);
|
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -408,10 +380,7 @@ router
|
|||||||
*/
|
*/
|
||||||
.post(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { code } = await apiValidator(
|
const { code } = await apiValidator(getValidationSchema("/users/{userID}/2fa/enable", "post"), req.body);
|
||||||
getValidationSchema("/users/{userID}/2fa/enable", "post"),
|
|
||||||
req.body,
|
|
||||||
);
|
|
||||||
const result = await internal2FA.enable(res.locals.access, req.params.user_id, code);
|
const result = await internal2FA.enable(res.locals.access, req.params.user_id, code);
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
+32
-35
@@ -1,3 +1,4 @@
|
|||||||
|
import fs from "node:fs/promises";
|
||||||
import { installPlugins } from "./lib/certbot.js";
|
import { installPlugins } from "./lib/certbot.js";
|
||||||
import utils from "./lib/utils.js";
|
import utils from "./lib/utils.js";
|
||||||
import { setup as logger } from "./logger.js";
|
import { setup as logger } from "./logger.js";
|
||||||
@@ -6,12 +7,11 @@ import certificateModel from "./models/certificate.js";
|
|||||||
import settingModel from "./models/setting.js";
|
import settingModel from "./models/setting.js";
|
||||||
import userModel from "./models/user.js";
|
import userModel from "./models/user.js";
|
||||||
import userPermissionModel from "./models/user_permission.js";
|
import userPermissionModel from "./models/user_permission.js";
|
||||||
import fs from "fs/promises";
|
|
||||||
|
|
||||||
export const isSetup = async () => {
|
export const isSetup = async () => {
|
||||||
const row = await userModel.query().select("id").where("is_deleted", 0).first();
|
const row = await userModel.query().select("id").where("is_deleted", 0).first();
|
||||||
return row?.id > 0;
|
return row?.id > 0;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a default admin users if one doesn't already exist in the database
|
* Creates a default admin users if one doesn't already exist in the database
|
||||||
@@ -45,18 +45,14 @@ const setupDefaultUser = async () => {
|
|||||||
roles: ["admin"],
|
roles: ["admin"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const user = await userModel
|
const user = await userModel.query().insertAndFetch(data);
|
||||||
.query()
|
|
||||||
.insertAndFetch(data);
|
|
||||||
|
|
||||||
await authModel
|
await authModel.query().insert({
|
||||||
.query()
|
user_id: user.id,
|
||||||
.insert({
|
type: "password",
|
||||||
user_id: user.id,
|
secret: initialAdminPassword,
|
||||||
type: "password",
|
meta: {},
|
||||||
secret: initialAdminPassword,
|
});
|
||||||
meta: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
await userPermissionModel.query().insert({
|
await userPermissionModel.query().insert({
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
@@ -78,22 +74,16 @@ const setupDefaultUser = async () => {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const setupDefaultSettings = async () => {
|
const setupDefaultSettings = async () => {
|
||||||
const row = await settingModel
|
const row = await settingModel.query().select("id").where({ id: "default-site" }).first();
|
||||||
.query()
|
|
||||||
.select("id")
|
|
||||||
.where({ id: "default-site" })
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!row?.id) {
|
if (!row?.id) {
|
||||||
await settingModel
|
await settingModel.query().insert({
|
||||||
.query()
|
id: "default-site",
|
||||||
.insert({
|
name: "Default Site",
|
||||||
id: "default-site",
|
description: "What to show when Nginx is hit with an unknown Host",
|
||||||
name: "Default Site",
|
value: "congratulations",
|
||||||
description: "What to show when Nginx is hit with an unknown Host",
|
meta: {},
|
||||||
value: "congratulations",
|
});
|
||||||
meta: {},
|
|
||||||
});
|
|
||||||
logger.info("Default settings added");
|
logger.info("Default settings added");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -104,10 +94,7 @@ const setupDefaultSettings = async () => {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const setupCertbotPlugins = async () => {
|
const setupCertbotPlugins = async () => {
|
||||||
const certificates = await certificateModel
|
const certificates = await certificateModel.query().where("is_deleted", 0).andWhere("provider", "letsencrypt");
|
||||||
.query()
|
|
||||||
.where("is_deleted", 0)
|
|
||||||
.andWhere("provider", "letsencrypt");
|
|
||||||
|
|
||||||
if (certificates?.length) {
|
if (certificates?.length) {
|
||||||
const plugins = [];
|
const plugins = [];
|
||||||
@@ -122,14 +109,24 @@ const setupCertbotPlugins = async () => {
|
|||||||
// Make sure credentials file exists
|
// Make sure credentials file exists
|
||||||
const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
|
const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
|
||||||
if (typeof certificate.meta.dns_provider_credentials === "string") {
|
if (typeof certificate.meta.dns_provider_credentials === "string") {
|
||||||
promises.push(fs.mkdir("/etc/letsencrypt/credentials", { recursive: true })
|
promises.push(
|
||||||
.then(() => fs.writeFile(credentials_loc, certificate.meta.dns_provider_credentials, { mode: 0o600, flag: "wx" }))
|
fs
|
||||||
.catch((err) => { if (err.code !== "EEXIST") throw err; }));
|
.mkdir("/etc/letsencrypt/credentials", { recursive: true })
|
||||||
|
.then(() =>
|
||||||
|
fs.writeFile(credentials_loc, certificate.meta.dns_provider_credentials, {
|
||||||
|
mode: 0o600,
|
||||||
|
flag: "wx",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.code !== "EEXIST") throw err;
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
await installPlugins(plugins);
|
await installPlugins(plugins);
|
||||||
|
|
||||||
if (promises.length) {
|
if (promises.length) {
|
||||||
|
|||||||
+386
-339
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user