Skip to content

Commit 847c58b

Browse files
authored
Merge pull request #4956 from NginxProxyManager/develop
v2.13.5
2 parents f02145c + 89b8b74 commit 847c58b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+2857
-1989
lines changed

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.13.4
1+
2.13.5

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<p align="center">
22
<img src="https://nginxproxymanager.com/github.png">
33
<br><br>
4-
<img src="https://img.shields.io/badge/version-2.13.4-green.svg?style=for-the-badge">
4+
<img src="https://img.shields.io/badge/version-2.13.5-green.svg?style=for-the-badge">
55
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
66
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
77
</a>

backend/certbot/dns-plugins.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
"azure": {
2727
"name": "Azure",
2828
"package_name": "certbot-dns-azure",
29-
"version": "~=1.2.0",
30-
"dependencies": "",
29+
"version": "~=2.6.1",
30+
"dependencies": "azure-mgmt-dns==8.2.0",
3131
"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
3232
"full_plugin_name": "dns-azure"
3333
},
@@ -482,7 +482,7 @@
482482
"porkbun": {
483483
"name": "Porkbun",
484484
"package_name": "certbot-dns-porkbun",
485-
"version": "~=0.9",
485+
"version": "~=0.11.0",
486486
"dependencies": "",
487487
"credentials": "dns_porkbun_key=your-porkbun-api-key\ndns_porkbun_secret=your-porkbun-api-secret",
488488
"full_plugin_name": "dns-porkbun"

backend/internal/remote-version.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import https from "node:https";
2+
import { ProxyAgent } from "proxy-agent";
3+
import { debug, remoteVersion as logger } from "../logger.js";
4+
import pjson from "../package.json" with { type: "json" };
5+
6+
const VERSION_URL = "https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest";
7+
8+
const internalRemoteVersion = {
9+
cache_timeout: 1000 * 60 * 15, // 15 minutes
10+
last_result: null,
11+
last_fetch_time: null,
12+
13+
/**
14+
* Fetch the latest version info, using a cached result if within the cache timeout period.
15+
* @return {Promise<{current: string, latest: string, update_available: boolean}>} Version info
16+
*/
17+
get: async () => {
18+
if (
19+
!internalRemoteVersion.last_result ||
20+
!internalRemoteVersion.last_fetch_time ||
21+
Date.now() - internalRemoteVersion.last_fetch_time > internalRemoteVersion.cache_timeout
22+
) {
23+
const raw = await internalRemoteVersion.fetchUrl(VERSION_URL);
24+
const data = JSON.parse(raw);
25+
internalRemoteVersion.last_result = data;
26+
internalRemoteVersion.last_fetch_time = Date.now();
27+
} else {
28+
debug(logger, "Using cached remote version result");
29+
}
30+
31+
const latestVersion = internalRemoteVersion.last_result.tag_name;
32+
const version = pjson.version.split("-").shift().split(".");
33+
const currentVersion = `v${version[0]}.${version[1]}.${version[2]}`;
34+
return {
35+
current: currentVersion,
36+
latest: latestVersion,
37+
update_available: internalRemoteVersion.compareVersions(currentVersion, latestVersion),
38+
};
39+
},
40+
41+
fetchUrl: (url) => {
42+
const agent = new ProxyAgent();
43+
const headers = {
44+
"User-Agent": `NginxProxyManager v${pjson.version}`,
45+
};
46+
47+
return new Promise((resolve, reject) => {
48+
logger.info(`Fetching ${url}`);
49+
return https
50+
.get(url, { agent, headers }, (res) => {
51+
res.setEncoding("utf8");
52+
let raw_data = "";
53+
res.on("data", (chunk) => {
54+
raw_data += chunk;
55+
});
56+
res.on("end", () => {
57+
resolve(raw_data);
58+
});
59+
})
60+
.on("error", (err) => {
61+
reject(err);
62+
});
63+
});
64+
},
65+
66+
compareVersions: (current, latest) => {
67+
const cleanCurrent = current.replace(/^v/, "");
68+
const cleanLatest = latest.replace(/^v/, "");
69+
70+
const currentParts = cleanCurrent.split(".").map(Number);
71+
const latestParts = cleanLatest.split(".").map(Number);
72+
73+
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
74+
const curr = currentParts[i] || 0;
75+
const lat = latestParts[i] || 0;
76+
77+
if (lat > curr) return true;
78+
if (lat < curr) return false;
79+
}
80+
return false;
81+
},
82+
};
83+
84+
export default internalRemoteVersion;

backend/logger.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ const certbot = new signale.Signale({ scope: "Certbot ", ...opts });
1515
const importer = new signale.Signale({ scope: "Importer ", ...opts });
1616
const setup = new signale.Signale({ scope: "Setup ", ...opts });
1717
const ipRanges = new signale.Signale({ scope: "IP Ranges", ...opts });
18+
const remoteVersion = new signale.Signale({ scope: "Remote Version", ...opts });
1819

1920
const debug = (logger, ...args) => {
2021
if (isDebugMode()) {
2122
logger.debug(...args);
2223
}
2324
};
2425

25-
export { debug, global, migrate, express, access, nginx, ssl, certbot, importer, setup, ipRanges };
26+
export { debug, global, migrate, express, access, nginx, ssl, certbot, importer, setup, ipRanges, remoteVersion };

backend/routes/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import schemaRoutes from "./schema.js";
1414
import settingsRoutes from "./settings.js";
1515
import tokensRoutes from "./tokens.js";
1616
import usersRoutes from "./users.js";
17+
import versionRoutes from "./version.js";
1718

1819
const router = express.Router({
1920
caseSensitive: true,
@@ -46,6 +47,7 @@ router.use("/users", usersRoutes);
4647
router.use("/audit-log", auditLogRoutes);
4748
router.use("/reports", reportsRoutes);
4849
router.use("/settings", settingsRoutes);
50+
router.use("/version", versionRoutes);
4951
router.use("/nginx/proxy-hosts", proxyHostsRoutes);
5052
router.use("/nginx/redirection-hosts", redirectionHostsRoutes);
5153
router.use("/nginx/dead-hosts", deadHostsRoutes);

backend/routes/version.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import express from "express";
2+
import internalRemoteVersion from "../internal/remote-version.js";
3+
import { debug, express as logger } from "../logger.js";
4+
5+
const router = express.Router({
6+
caseSensitive: true,
7+
strict: true,
8+
mergeParams: true,
9+
});
10+
11+
/**
12+
* /api/version/check
13+
*/
14+
router
15+
.route("/check")
16+
.options((_, res) => {
17+
res.sendStatus(204);
18+
})
19+
20+
/**
21+
* GET /api/version/check
22+
*
23+
* Check for available updates
24+
*/
25+
.get(async (req, res, _next) => {
26+
try {
27+
const data = await internalRemoteVersion.get();
28+
res.status(200).send(data);
29+
} catch (error) {
30+
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${error}`);
31+
// Send 200 even though there's an error to avoid triggering update checks repeatedly
32+
res.status(200).send({
33+
current: null,
34+
latest: null,
35+
update_available: false,
36+
});
37+
}
38+
});
39+
40+
export default router;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"type": "object",
3+
"description": "Check Version object",
4+
"additionalProperties": false,
5+
"required": ["current", "latest", "update_available"],
6+
"properties": {
7+
"current": {
8+
"type": ["string", "null"],
9+
"description": "Current version string",
10+
"example": "v2.10.1"
11+
},
12+
"latest": {
13+
"type": ["string", "null"],
14+
"description": "Latest version string",
15+
"example": "v2.13.4"
16+
},
17+
"update_available": {
18+
"type": "boolean",
19+
"description": "Whether there's an update available",
20+
"example": true
21+
}
22+
}
23+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"operationId": "checkVersion",
3+
"summary": "Returns any new version data from github",
4+
"tags": ["public"],
5+
"responses": {
6+
"200": {
7+
"description": "200 response",
8+
"content": {
9+
"application/json": {
10+
"examples": {
11+
"default": {
12+
"value": {
13+
"current": "v2.12.0",
14+
"latest": "v2.13.4",
15+
"update_available": true
16+
}
17+
}
18+
},
19+
"schema": {
20+
"$ref": "../../../components/check-version-object.json"
21+
}
22+
}
23+
}
24+
}
25+
}
26+
}

backend/schema/swagger.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@
293293
"$ref": "./paths/tokens/post.json"
294294
}
295295
},
296+
"/version/check": {
297+
"get": {
298+
"$ref": "./paths/version/check/get.json"
299+
}
300+
},
296301
"/users": {
297302
"get": {
298303
"$ref": "./paths/users/get.json"

0 commit comments

Comments
 (0)