Compare commits

..

98 Commits

Author SHA1 Message Date
dependabot[bot]
4397f57a51 Bump @eslint/plugin-kit from 0.3.2 to 0.3.5 in /test
Bumps [@eslint/plugin-kit](https://github.com/eslint/rewrite/tree/HEAD/packages/plugin-kit) from 0.3.2 to 0.3.5.
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/packages/plugin-kit/CHANGELOG.md)
- [Commits](https://github.com/eslint/rewrite/commits/plugin-kit-v0.3.5/packages/plugin-kit)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-version: 0.3.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-22 02:38:28 +00:00
jc21
5039738aa3 Merge pull request #4696 from NginxProxyManager/dependabot/npm_and_yarn/test/tmp-0.2.4
Bump tmp from 0.2.3 to 0.2.4 in /test
2025-08-22 12:34:03 +10:00
jc21
4451be8f1c Merge pull request #4722 from NginxProxyManager/dependabot/npm_and_yarn/frontend/cipher-base-1.0.6
Bump cipher-base from 1.0.4 to 1.0.6 in /frontend
2025-08-22 12:22:49 +10:00
jc21
bee2fd1978 Merge pull request #4723 from NginxProxyManager/dependabot/npm_and_yarn/frontend/sha.js-2.4.12
Bump sha.js from 2.4.11 to 2.4.12 in /frontend
2025-08-22 12:22:39 +10:00
dependabot[bot]
c8adbdfc15 Bump sha.js from 2.4.11 to 2.4.12 in /frontend
Bumps [sha.js](https://github.com/crypto-browserify/sha.js) from 2.4.11 to 2.4.12.
- [Changelog](https://github.com/browserify/sha.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/sha.js/compare/v2.4.11...v2.4.12)

---
updated-dependencies:
- dependency-name: sha.js
  dependency-version: 2.4.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 15:45:37 +00:00
dependabot[bot]
aff4182ab8 Bump cipher-base from 1.0.4 to 1.0.6 in /frontend
Bumps [cipher-base](https://github.com/crypto-browserify/cipher-base) from 1.0.4 to 1.0.6.
- [Changelog](https://github.com/browserify/cipher-base/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/cipher-base/compare/v1.0.4...v1.0.6)

---
updated-dependencies:
- dependency-name: cipher-base
  dependency-version: 1.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 15:13:31 +00:00
Jamie Curnow
8c9d2745e2 Fix remote execution bug where email address can contain malicious code
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
also convert almost all cmd execs for certificates to properly escape arguments
2025-08-20 10:57:24 +10:00
dependabot[bot]
076d14b5e4 Bump tmp from 0.2.3 to 0.2.4 in /test
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.3 to 0.2.4.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.4)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-06 17:12:10 +00:00
Jamie Curnow
54d463ac36 Safer and flexible boolean env vars 2025-07-09 21:27:50 +10:00
Jamie Curnow
a23dc24021 Tweak ownership output 2025-07-09 21:01:21 +10:00
Jamie Curnow
4f9df893c8 Ownership script shakeup
- Don't touch a file to determine if we need to run
- Instead, check ownership of each location and skip it if we are happy
- Keeping SKIP_CERTBOT_OWNERSHIP flag
- More vebose logging of outcomes
2025-07-09 20:30:27 +10:00
Jamie Curnow
304b38e82b Fix ownership if statement 2025-07-09 18:19:50 +10:00
jc21
1b0929ade6 Merge branch 'master' into develop 2025-07-09 16:36:26 +10:00
Jamie Curnow
ddbafb62a6 bump version 2025-07-09 16:33:50 +10:00
Jamie Curnow
9a0383bc73 Move SKIP_CERTBOT_OWNERSHIP check around the entire certbot code 2025-07-09 16:30:45 +10:00
jc21
307cb94e84 Merge pull request #4651 from NginxProxyManager/develop
v2.12.5
2025-07-09 14:22:26 +10:00
jc21
63ae924fbc Merge branch 'master' into develop 2025-07-09 13:16:38 +10:00
Jamie Curnow
1710a263c0 Bump version 2025-07-09 13:15:15 +10:00
Jamie Curnow
1357774f21 Add SKIP_CERTBOT_OWNERSHIP env var support to skip certbot folder ownership 2025-07-09 13:14:27 +10:00
Jamie Curnow
5f54490d86 Set SETUPTOOLS_USE_DISTUTILS for all plugin installs, seems like they all need it. 2025-07-09 12:35:20 +10:00
Jamie Curnow
c97b8a339d Some auto formatting changes suggested by ide 2025-07-09 11:34:57 +10:00
Jamie Curnow
ed1d90ee7f Fix powerdns dns plugin install, deps are outrageously old ;(
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
2025-07-09 11:34:19 +10:00
Jamie Curnow
70894e55b8 Remove cloudflare dep for certbot plugin, tested 2025-07-09 09:36:57 +10:00
Jamie Curnow
817021a43d Update s6 overlay
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
2025-07-08 17:32:23 +10:00
Jamie Curnow
36e3449a56 Update cloudflare dependency 2025-07-08 17:14:20 +10:00
Jamie Curnow
db9f25638f Update PR comments to highlight verification requirements 2025-07-08 17:08:31 +10:00
jc21
ddd3355d95 Merge pull request #4645 from NginxProxyManager/revert-4574-develop
Revert "Update 'global/certbot-dns-plugins.json' to apply SSL certs for CloudFlare."
2025-07-08 11:19:53 +10:00
jc21
aade8b42fc Revert "Update 'global/certbot-dns-plugins.json' to apply SSL certs for CloudFlare." 2025-07-08 10:26:46 +10:00
Jamie Curnow
3735f3c11d Formating for ownership script 2025-07-08 09:44:10 +10:00
jc21
b84762b5b9 Merge pull request #4605 from NginxProxyManager/develop
v2.12.4
2025-07-01 11:12:08 +10:00
jc21
953faeac15 Merge branch 'master' into develop 2025-07-01 07:33:33 +10:00
Jamie Curnow
c58f3f3ec9 Bump version 2025-07-01 07:32:39 +10:00
jc21
0ee4d04d5f Merge pull request #4491 from addievo/fix-certbot-startup-time
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
fix: optimize certbot ownership script to reduce container startup time
2025-06-30 15:31:09 +10:00
jc21
94f6756250 Merge pull request #4557 from 1ukastesar/patch-1
fix(modal): make textarea font actually monospace
2025-06-30 15:19:05 +10:00
jc21
27e3f73854 Merge pull request #4353 from mordyovits/patch-1
Update frontend copyright year to 2025
2025-06-30 14:57:07 +10:00
jc21
d98f4b43dc Merge pull request #4398 from cg-zhou/feature/add-ip-ranges-env-var
Added IP_RANGES_FETCH_ENABLED environment variable
2025-06-30 14:54:40 +10:00
jc21
ff3116a626 Merge pull request #4604 from NginxProxyManager/dependabot/npm_and_yarn/backend/brace-expansion-1.1.12
Bump brace-expansion from 1.1.11 to 1.1.12 in /backend
2025-06-30 14:47:58 +10:00
jc21
7047750b04 Merge pull request #4358 from pustekuchen91/update-cpanel-certbot-plugin
use latest certbot-dns-cpanel version
2025-06-30 14:43:48 +10:00
cg-zhou
0792fc0768 Remove unnecessary Promise.resolve() calls 2025-06-30 12:31:23 +08:00
dependabot[bot]
9758c12ca3 Bump brace-expansion from 1.1.11 to 1.1.12 in /backend
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 1.1.12.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 03:55:09 +00:00
jc21
ccd69c8867 Update certbot-dns-plugins.json 2025-06-30 13:52:07 +10:00
jc21
23fd1fec6c Merge branch 'develop' into update-cpanel-certbot-plugin 2025-06-30 13:51:19 +10:00
jc21
6f04543744 Merge pull request #4368 from wisewtf/patch-1
Fixed error in sqlite installation compose file
2025-06-30 13:49:40 +10:00
jc21
cbb1fe44ca Merge pull request #4381 from ZeroDeng01/ZeroDeng01-patch-1
Fixed an issue with the 500 error code on the Stream list page
2025-06-30 13:45:05 +10:00
jc21
4c23f22d5b Merge pull request #4601 from NginxProxyManager/dependabot/npm_and_yarn/test/axios-1.10.0
Bump axios from 1.7.7 to 1.10.0 in /test
2025-06-30 13:13:02 +10:00
jc21
af5d3eccd6 Merge pull request #4602 from NginxProxyManager/dependabot/npm_and_yarn/docs/vite-5.4.19
Bump vite from 5.4.14 to 5.4.19 in /docs
2025-06-30 13:12:51 +10:00
jc21
a87283b030 Merge pull request #4603 from NginxProxyManager/dependabot/npm_and_yarn/frontend/elliptic-6.6.1
Bump elliptic from 6.6.0 to 6.6.1 in /frontend
2025-06-30 13:12:42 +10:00
Jamie Curnow
97dbbdd60f Fix incorrect swagger for streams list 2025-06-30 13:00:25 +10:00
Jamie Curnow
ec81f2489a Add cypress test to list streams 2025-06-30 11:10:45 +10:00
dependabot[bot]
d0ec8e89aa Bump elliptic from 6.6.0 to 6.6.1 in /frontend
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.6.0 to 6.6.1.
- [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-version: 6.6.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 00:56:57 +00:00
dependabot[bot]
9a96fbb5f4 Bump vite from 5.4.14 to 5.4.19 in /docs
---
updated-dependencies:
- dependency-name: vite
  dependency-version: 5.4.19
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 00:56:15 +00:00
dependabot[bot]
a573450bb8 Bump axios from 1.7.7 to 1.10.0 in /test
Bumps [axios](https://github.com/axios/axios) from 1.7.7 to 1.10.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.7...v1.10.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.10.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 00:54:38 +00:00
jc21
60a25ffbd5 Merge pull request #4560 from spions/patch-1
Added Selectel v2  DNS provider
2025-06-30 10:49:40 +10:00
jc21
7d2369b380 Merge pull request #4576 from NginxProxyManager/dependabot/npm_and_yarn/test/brace-expansion-1.1.12
Bump brace-expansion from 1.1.11 to 1.1.12 in /test
2025-06-30 10:49:20 +10:00
jc21
64f00e8dba Merge pull request #4577 from h33n0k/develop
Fix Incorrect Api status codes
2025-06-30 10:49:09 +10:00
jc21
c99143f548 Merge pull request #4596 from NginxProxyManager/dependabot/npm_and_yarn/frontend/pbkdf2-3.1.3
Bump pbkdf2 from 3.1.1 to 3.1.3 in /frontend
2025-06-30 10:48:57 +10:00
jc21
cc4ee6919a Merge pull request #4597 from aitor422/develop
All checks were successful
Close stale issues and PRs / stale (push) Successful in 1m0s
added CDMon DNS provider
2025-06-30 08:49:03 +10:00
jc21
8a69c65b40 Merge pull request #4551 from MinhPho/feature/update-strato-dns-plugin
Update strato dns plugin from 0.2.1 to 0.2.2
2025-06-30 08:09:39 +10:00
jc21
95ee5ca958 Merge pull request #4553 from gustavfroding/develop
Added spaceship DNS provider
2025-06-30 08:09:17 +10:00
jc21
40f22d30c4 Merge pull request #4574 from tom-kst/develop
Update 'global/certbot-dns-plugins.json' to apply SSL certs for CloudFlare.
2025-06-30 08:08:18 +10:00
aitor422
30dfa9e3de added CDMon DNS provider 2025-06-25 13:32:14 +02:00
dependabot[bot]
b873499feb Bump pbkdf2 from 3.1.1 to 3.1.3 in /frontend
Bumps [pbkdf2](https://github.com/crypto-browserify/pbkdf2) from 3.1.1 to 3.1.3.
- [Changelog](https://github.com/browserify/pbkdf2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/pbkdf2/compare/v3.1.1...v3.1.3)

---
updated-dependencies:
- dependency-name: pbkdf2
  dependency-version: 3.1.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 09:20:21 +00:00
h33n0k
ef69be2036 Fix Incorrect Api status codes
Update Incorrect status code based off the api schema
2025-06-12 08:58:17 +02:00
dependabot[bot]
7580e65dd4 Bump brace-expansion from 1.1.11 to 1.1.12 in /test
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 1.1.12.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 21:02:35 +00:00
Tom.KST
f11dc5d7c1 Update certbot-dns-plugins.json 2025-06-11 17:36:21 +08:00
Tom.KST
77061a7bd6 Update certbot-dns-plugins.json
I've tried multi times failed, and I found that show be a 'space break' ahead & after the equal mark...
So the correct script should be "dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567", instead of "dns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567"
2025-06-11 17:33:44 +08:00
Oleg
b6afc19135 Added selectel v2 DNS provider 2025-05-28 18:10:21 +03:00
Lukáš Tesař
09ba400d09 fix(modal): make textarea font actually monospace
Modal `textarea` element has this class `text-monospace`, but there is actually no CSS definition that sets the monospace font for it (neither in custom SCSS files, nor in included libs). This commit fixes the issue by setting `monospace` `font-family` for the `textarea`, greatly enhancing UX of configuration editing in UI.
2025-05-26 19:40:08 +02:00
gustavfroding
0291cfc270 Added spaceship DNS provider 2025-05-23 13:18:07 +02:00
jelly_moon
34267e0af9 Update strato dns plugin from 0.2.1 to 0.2.2 2025-05-23 04:43:52 +02:00
jc21
f327c1e825 Merge pull request #4406 from chindocaine/fix_domainoffensive_certbot
All checks were successful
Close stale issues and PRs / stale (push) Successful in 1m28s
Fix DomainOffensive certbot plugin
2025-05-21 20:56:12 +10:00
jc21
6f539979ec Merge pull request #4411 from henmohr/develop
Update cloudflare dns plugin from 2.19.4 to 4.0.*
2025-05-21 20:52:50 +10:00
jc21
3d8079a137 Merge pull request #4426 from foxtrotcz/develop
Updates Active24 plugin to API v2
2025-05-21 20:50:55 +10:00
jc21
6d6d83c0d0 Merge pull request #4435 from amateescu/update-gandi-plugin
Update the Gandi plugin.
2025-05-21 20:50:36 +10:00
jc21
100a4888d0 Merge pull request #4481 from godsgood33/patch-1
Update certbot-dns-plugins.json
2025-05-21 20:50:14 +10:00
jc21
34a46bd733 Merge pull request #4534 from chenghaopeng/develop
add Baidu as DNS provider
2025-05-21 20:48:11 +10:00
jc21
7f8adc7e50 Merge pull request #4538 from astamminger/add_dns_ddnss_plugin
Add DDNSS to the list of supported Providers for DNS-01 Challenges
2025-05-21 20:47:29 +10:00
jc21
98d118cb74 Merge pull request #4540 from hatharry/develop
Add First Domains DNS Provider
2025-05-21 20:47:02 +10:00
jc21
4fb93542c3 Merge pull request #4547 from vzagorovskiy/develop
Added nic.ru DNS provider
2025-05-21 20:46:39 +10:00
vzagorovskiy
4fe305520a Added nic.ru dns provider 2025-05-19 13:18:58 +03:00
A. Stamminger
76be31cf76 Update certbot-dns-plugins.json with dns-ddns plugin
This commit extends the global plugin list with the configuration for
certbot-dns-ddnss (https://pypi.org/project/certbot-dns-ddnss/),
a new plugin providing DNS-01 challenges for ddnss.de
2025-05-12 15:54:10 +02:00
鹏鹏
55dadb2004 Merge pull request #1 from chenghaopeng/dns-baidu
add Baidu as DNS provider
2025-05-11 12:46:27 +08:00
鹏鹏
d9cdb3dc2c add Baidu as DNS provider 2025-05-11 12:45:13 +08:00
Aditya
0cab720f23 fix: optimize certbot ownership script to reduce container startup time
Replace inefficient find/execdir implementation that was causing 3+ minute
startup delays with a more efficient approach that:

1. Uses a flag file to skip redundant operations on container restarts
2. Processes site-packages directories with bulk chown operations instead
   of individual file checks and changes
3. Maintains the same functionality while dramatically improving performance

This change should significantly reduce container startup time while ensuring
all necessary file permissions are still properly set.
2025-04-20 20:38:54 +10:00
Ryan P
f5879dff6c Update certbot-dns-plugins.json
Fix for bug #4429 add cpanel_api_token entry to credentials check. Will still need to update the documentation that the user will need to retrieve the api token from their cPanel.
2025-04-10 19:56:06 -04:00
Jamie Curnow
5e66d677f1 Adds test for dashboard endpoints
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
2025-03-24 14:34:45 +10:00
Andrei Mateescu
18830f81b0 Update the Gandi plugin. 2025-03-13 23:47:31 +02:00
FoxtrotCZ
341ac65587 Updates Active24 plugin to API v2 2025-03-09 19:54:11 +01:00
henmohr
078baa255a Update certbot-dns-plugins.json 2025-03-03 16:40:38 -03:00
Michael Heilig
bf9d9bd43b Fix DomainOffensive certbot plugin
In https://github.com/NginxProxyManager/nginx-proxy-manager/pull/4235 the certbot plugin for do.de (Domain Offensive) was updated to use the more
official version. One necessary line modification was missed, resulting in an error when creating a new certificate.
2025-02-28 21:00:36 +01:00
cg-zhou
a394b25e61 fix eslint error 2025-02-26 19:45:49 +08:00
cg-zhou
1c47fc2ba4 feat: Add IP_RANGES_FETCH_ENABLED environment variable
This change adds a new environment variable to control whether IP ranges
are fetched during application startup. When set to 'false', the initial
fetch will be skipped, which can:

1. Speed up application startup
2. Avoid connectivity issues in environments with restricted internet access
3. Prevent startup failures when CloudFront or CloudFlare services are unreachable
2025-02-26 19:25:50 +08:00
ZeroDeng
312e2ab80c [fix]Stream List error code 500
Fix stream list page error code 500。
2025-02-21 14:56:00 +08:00
Wise
d147ccd88d Fixed error in sqlite installation compose file
If people copy and paste the sqlite installation without commenting environment docker compose will throw an error because environment will be null.
2025-02-14 14:44:54 +01:00
Marc
03fd292c61 use latest certbot-dns-cpanel version
this allows to use token for authentication
2025-02-09 11:41:30 +01:00
Mordy Ovits
b09147eca8 Update frontend copyright year to 2025 2025-02-06 19:40:23 -05:00
jc21
c5a319cb20 Merge pull request #4347 from NginxProxyManager/develop
v2.12.3
2025-02-06 20:25:09 +10:00
hatharry
2cee211fb0 add First Domains plugin 2024-11-13 16:31:59 +13:00
41 changed files with 1327 additions and 1079 deletions

View File

@@ -1 +1 @@
2.12.3
2.12.6

15
Jenkinsfile vendored
View File

@@ -241,12 +241,17 @@ pipeline {
}
steps {
script {
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on
[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev)
as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev):
```
nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}
```
**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
**Note:** this is a different docker image namespace than the official image
> [!NOTE]
> Ensure you backup your NPM instance before testing this image! Especially if there are database changes.
> This is a different docker image namespace than the official image.
> [!WARNING]
> Changes and additions to DNS Providers require verification by at least 2 members of the community!
""", true)
}
}

View File

@@ -1,7 +1,7 @@
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.12.3-green.svg?style=for-the-badge">
<img src="https://img.shields.io/badge/version-2.12.6-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>

View File

@@ -3,6 +3,8 @@
const schema = require('./schema');
const logger = require('./logger').global;
const IP_RANGES_FETCH_ENABLED = process.env.IP_RANGES_FETCH_ENABLED !== 'false';
async function appStart () {
const migrate = require('./migrate');
const setup = require('./setup');
@@ -13,7 +15,16 @@ async function appStart () {
return migrate.latest()
.then(setup)
.then(schema.getCompiledSchema)
.then(internalIpRanges.fetch)
.then(() => {
if (IP_RANGES_FETCH_ENABLED) {
logger.info('IP Ranges fetch is enabled');
return internalIpRanges.fetch().catch((err) => {
logger.error('IP Ranges fetch failed, continuing anyway:', err.message);
});
} else {
logger.info('IP Ranges fetch is disabled by environment variable');
}
})
.then(() => {
internalCertificate.initTimer();
internalIpRanges.initTimer();

View File

@@ -1,5 +1,5 @@
const _ = require('lodash');
const fs = require('fs');
const fs = require('node:fs');
const batchflow = require('batchflow');
const logger = require('../logger').access;
const error = require('../lib/error');
@@ -38,7 +38,7 @@ const internalAccessList = {
.then((row) => {
data.id = row.id;
let promises = [];
const promises = [];
// Now add the items
data.items.map((item) => {
@@ -116,7 +116,7 @@ const internalAccessList = {
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Access List could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
throw new error.InternalValidationError(`Access List could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
}
})
.then(() => {
@@ -135,10 +135,10 @@ const internalAccessList = {
.then(() => {
// Check for items and add/update/remove them
if (typeof data.items !== 'undefined' && data.items) {
let promises = [];
let items_to_keep = [];
const promises = [];
const items_to_keep = [];
data.items.map(function (item) {
data.items.map((item) => {
if (item.password) {
promises.push(accessListAuthModel
.query()
@@ -154,7 +154,7 @@ const internalAccessList = {
}
});
let query = accessListAuthModel
const query = accessListAuthModel
.query()
.delete()
.where('access_list_id', data.id);
@@ -175,9 +175,9 @@ const internalAccessList = {
.then(() => {
// Check for clients and add/update/remove them
if (typeof data.clients !== 'undefined' && data.clients) {
let promises = [];
const promises = [];
data.clients.map(function (client) {
data.clients.map((client) => {
if (client.address) {
promises.push(accessListClientModel
.query()
@@ -190,7 +190,7 @@ const internalAccessList = {
}
});
let query = accessListClientModel
const query = accessListClientModel
.query()
.delete()
.where('access_list_id', data.id);
@@ -249,7 +249,7 @@ const internalAccessList = {
return access.can('access_lists:get', data.id)
.then((access_data) => {
let query = accessListModel
const query = accessListModel
.query()
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
.leftJoin('proxy_host', function() {
@@ -267,7 +267,7 @@ const internalAccessList = {
}
if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.withGraphFetched('[' + data.expand.join(', ') + ']');
query.withGraphFetched(`[${data.expand.join(', ')}]`);
}
return query.then(utils.omitRow(omissions()));
@@ -327,7 +327,7 @@ const internalAccessList = {
// 3. reconfigure those hosts, then reload nginx
// set the access_list_id to zero for these items
row.proxy_hosts.map(function (val, idx) {
row.proxy_hosts.map((_val, idx) => {
row.proxy_hosts[idx].access_list_id = 0;
});
@@ -340,11 +340,11 @@ const internalAccessList = {
})
.then(() => {
// delete the htpasswd file
let htpasswd_file = internalAccessList.getFilename(row);
const htpasswd_file = internalAccessList.getFilename(row);
try {
fs.unlinkSync(htpasswd_file);
} catch (err) {
} catch (_err) {
// do nothing
}
})
@@ -374,7 +374,7 @@ const internalAccessList = {
getAll: (access, expand, search_query) => {
return access.can('access_lists:list')
.then((access_data) => {
let query = accessListModel
const query = accessListModel
.query()
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
.leftJoin('proxy_host', function() {
@@ -393,19 +393,19 @@ const internalAccessList = {
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('name', 'like', '%' + search_query + '%');
this.where('name', 'like', `%${search_query}%`);
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.withGraphFetched('[' + expand.join(', ') + ']');
query.withGraphFetched(`[${expand.join(', ')}]`);
}
return query.then(utils.omitRows(omissions()));
})
.then((rows) => {
if (rows) {
rows.map(function (row, idx) {
rows.map((row, idx) => {
if (typeof row.items !== 'undefined' && row.items) {
rows[idx] = internalAccessList.maskItems(row);
}
@@ -424,7 +424,7 @@ const internalAccessList = {
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = accessListModel
const query = accessListModel
.query()
.count('id as count')
.where('is_deleted', 0);
@@ -445,7 +445,7 @@ const internalAccessList = {
*/
maskItems: (list) => {
if (list && typeof list.items !== 'undefined') {
list.items.map(function (val, idx) {
list.items.map((val, idx) => {
let repeat_for = 8;
let first_char = '*';
@@ -468,7 +468,7 @@ const internalAccessList = {
* @returns {String}
*/
getFilename: (list) => {
return '/data/access/' + list.id;
return `/data/access/${list.id}`;
},
/**
@@ -479,15 +479,15 @@ const internalAccessList = {
* @returns {Promise}
*/
build: (list) => {
logger.info('Building Access file #' + list.id + ' for: ' + list.name);
logger.info(`Building Access file #${list.id} for: ${list.name}`);
return new Promise((resolve, reject) => {
let htpasswd_file = internalAccessList.getFilename(list);
const htpasswd_file = internalAccessList.getFilename(list);
// 1. remove any existing access file
try {
fs.unlinkSync(htpasswd_file);
} catch (err) {
} catch (_err) {
// do nothing
}
@@ -504,14 +504,14 @@ const internalAccessList = {
if (list.items.length) {
return new Promise((resolve, reject) => {
batchflow(list.items).sequential()
.each((i, item, next) => {
.each((_i, item, next) => {
if (typeof item.password !== 'undefined' && item.password.length) {
logger.info('Adding: ' + item.username);
logger.info(`Adding: ${item.username}`);
utils.execFile('openssl', ['passwd', '-apr1', item.password])
.then((res) => {
try {
fs.appendFileSync(htpasswd_file, item.username + ':' + res + '\n', {encoding: 'utf8'});
fs.appendFileSync(htpasswd_file, `${item.username}:${res}\n`, {encoding: 'utf8'});
} catch (err) {
reject(err);
}
@@ -528,7 +528,7 @@ const internalAccessList = {
reject(err);
})
.end((results) => {
logger.success('Built Access file #' + list.id + ' for: ' + list.name);
logger.success(`Built Access file #${list.id} for: ${list.name}`);
resolve(results);
});
});

View File

@@ -1,6 +1,6 @@
const _ = require('lodash');
const fs = require('fs');
const https = require('https');
const fs = require('node:fs');
const https = require('node:https');
const tempWrite = require('temp-write');
const moment = require('moment');
const archiver = require('archiver');
@@ -49,7 +49,7 @@ const internalCertificate = {
processExpiringHosts: () => {
if (!internalCertificate.intervalProcessing) {
internalCertificate.intervalProcessing = true;
logger.info('Renewing SSL certs expiring within ' + internalCertificate.renewBeforeExpirationBy[0] + ' ' + internalCertificate.renewBeforeExpirationBy[1] + ' ...');
logger.info(`Renewing SSL certs expiring within ${internalCertificate.renewBeforeExpirationBy[0]} ${internalCertificate.renewBeforeExpirationBy[1]} ...`);
const expirationThreshold = moment().add(internalCertificate.renewBeforeExpirationBy[0], internalCertificate.renewBeforeExpirationBy[1]).format('YYYY-MM-DD HH:mm:ss');
@@ -70,7 +70,7 @@ const internalCertificate = {
*/
let sequence = Promise.resolve();
certificates.forEach(function (certificate) {
certificates.forEach((certificate) => {
sequence = sequence.then(() =>
internalCertificate
.renew(
@@ -202,7 +202,7 @@ const internalCertificate = {
.then(() => {
// At this point, the letsencrypt cert should exist on disk.
// Lets get the expiry date from the file and update the row silently
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`)
.then((cert_info) => {
return certificateModel
.query()
@@ -263,7 +263,7 @@ const internalCertificate = {
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Certificate could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
throw new error.InternalValidationError(`Certificate could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
}
return certificateModel
@@ -308,7 +308,7 @@ const internalCertificate = {
return access.can('certificates:get', data.id)
.then((access_data) => {
let query = certificateModel
const query = certificateModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
@@ -323,7 +323,7 @@ const internalCertificate = {
}
if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.withGraphFetched('[' + data.expand.join(', ') + ']');
query.withGraphFetched(`[${data.expand.join(', ')}]`);
}
return query.then(utils.omitRow(omissions()));
@@ -354,17 +354,17 @@ const internalCertificate = {
})
.then((certificate) => {
if (certificate.provider === 'letsencrypt') {
const zipDirectory = '/etc/letsencrypt/live/npm-' + data.id;
const zipDirectory = internalCertificate.getLiveCertPath(data.id);
if (!fs.existsSync(zipDirectory)) {
throw new error.ItemNotFoundError('Certificate ' + certificate.nice_name + ' does not exists');
throw new error.ItemNotFoundError(`Certificate ${certificate.nice_name} does not exists`);
}
let certFiles = fs.readdirSync(zipDirectory)
const certFiles = fs.readdirSync(zipDirectory)
.filter((fn) => fn.endsWith('.pem'))
.map((fn) => fs.realpathSync(path.join(zipDirectory, fn)));
const downloadName = 'npm-' + data.id + '-' + `${Date.now()}.zip`;
const opName = '/tmp/' + downloadName;
const downloadName = `npm-${data.id}-${Date.now()}.zip`;
const opName = `/tmp/${downloadName}`;
internalCertificate.zipFiles(certFiles, opName)
.then(() => {
logger.debug('zip completed : ', opName);
@@ -392,7 +392,7 @@ const internalCertificate = {
return new Promise((resolve, reject) => {
source
.map((fl) => {
let fileName = path.basename(fl);
const fileName = path.basename(fl);
logger.debug(fl, 'added to certificate zip');
archive.file(fl, { name: fileName });
});
@@ -462,7 +462,7 @@ const internalCertificate = {
getAll: (access, expand, search_query) => {
return access.can('certificates:list')
.then((access_data) => {
let query = certificateModel
const query = certificateModel
.query()
.where('is_deleted', 0)
.groupBy('id')
@@ -479,12 +479,12 @@ const internalCertificate = {
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('nice_name', 'like', '%' + search_query + '%');
this.where('nice_name', 'like', `%${search_query}%`);
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.withGraphFetched('[' + expand.join(', ') + ']');
query.withGraphFetched(`[${expand.join(', ')}]`);
}
return query.then(utils.omitRows(omissions()));
@@ -499,7 +499,7 @@ const internalCertificate = {
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = certificateModel
const query = certificateModel
.query()
.count('id as count')
.where('is_deleted', 0);
@@ -521,7 +521,7 @@ const internalCertificate = {
writeCustomCert: (certificate) => {
logger.info('Writing Custom Certificate:', certificate);
const dir = '/data/custom_ssl/npm-' + certificate.id;
const dir = `/data/custom_ssl/npm-${certificate.id}`;
return new Promise((resolve, reject) => {
if (certificate.provider === 'letsencrypt') {
@@ -531,7 +531,7 @@ const internalCertificate = {
let certData = certificate.meta.certificate;
if (typeof certificate.meta.intermediate_certificate !== 'undefined') {
certData = certData + '\n' + certificate.meta.intermediate_certificate;
certData = `${certData}\n${certificate.meta.intermediate_certificate}`;
}
try {
@@ -543,7 +543,7 @@ const internalCertificate = {
return;
}
fs.writeFile(dir + '/fullchain.pem', certData, function (err) {
fs.writeFile(`${dir}/fullchain.pem`, certData, (err) => {
if (err) {
reject(err);
} else {
@@ -553,7 +553,7 @@ const internalCertificate = {
})
.then(() => {
return new Promise((resolve, reject) => {
fs.writeFile(dir + '/privkey.pem', certificate.meta.certificate_key, function (err) {
fs.writeFile(`${dir}/privkey.pem`, certificate.meta.certificate_key, (err) => {
if (err) {
reject(err);
} else {
@@ -591,7 +591,7 @@ const internalCertificate = {
validate: (data) => {
return new Promise((resolve) => {
// Put file contents into an object
let files = {};
const files = {};
_.map(data.files, (file, name) => {
if (internalCertificate.allowedSslFiles.indexOf(name) !== -1) {
files[name] = file.data.toString();
@@ -603,7 +603,7 @@ const internalCertificate = {
.then((files) => {
// For each file, create a temp file and write the contents to it
// Then test it depending on the file type
let promises = [];
const promises = [];
_.map(files, (content, type) => {
promises.push(new Promise((resolve) => {
if (type === 'certificate_key') {
@@ -688,11 +688,11 @@ const internalCertificate = {
reject(new error.ValidationError('Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.'));
}, 10000);
utils
.exec('openssl pkey -in ' + filepath + ' -check -noout 2>&1 ')
.exec(`openssl pkey -in ${filepath} -check -noout 2>&1 `)
.then((result) => {
clearTimeout(failTimeout);
if (!result.toLowerCase().includes('key is valid')) {
reject(new error.ValidationError('Result Validation Error: ' + result));
reject(new error.ValidationError(`Result Validation Error: ${result}`));
}
fs.unlinkSync(filepath);
resolve(true);
@@ -700,7 +700,7 @@ const internalCertificate = {
.catch((err) => {
clearTimeout(failTimeout);
fs.unlinkSync(filepath);
reject(new error.ValidationError('Certificate Key is not valid (' + err.message + ')', err));
reject(new error.ValidationError(`Certificate Key is not valid (${err.message})`, err));
});
});
});
@@ -735,9 +735,9 @@ const internalCertificate = {
* @param {Boolean} [throw_expired] Throw when the certificate is out of date
*/
getCertificateInfoFromFile: (certificate_file, throw_expired) => {
let certData = {};
const certData = {};
return utils.exec('openssl x509 -in ' + certificate_file + ' -subject -noout')
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-subject', '-noout'])
.then((result) => {
// Examples:
// subject=CN = *.jc21.com
@@ -745,11 +745,11 @@ const internalCertificate = {
const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
const match = regex.exec(result);
if (match && typeof match[1] !== 'undefined') {
certData['cn'] = match[1];
certData.cn = match[1];
}
})
.then(() => {
return utils.exec('openssl x509 -in ' + certificate_file + ' -issuer -noout');
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-issuer', '-noout']);
})
.then((result) => {
@@ -760,11 +760,11 @@ const internalCertificate = {
const regex = /^(?:issuer=)?(.*)$/gim;
const match = regex.exec(result);
if (match && typeof match[1] !== 'undefined') {
certData['issuer'] = match[1];
certData.issuer = match[1];
}
})
.then(() => {
return utils.exec('openssl x509 -in ' + certificate_file + ' -dates -noout');
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-dates', '-noout']);
})
.then((result) => {
// notBefore=Jul 14 04:04:29 2018 GMT
@@ -773,7 +773,7 @@ const internalCertificate = {
let validTo = null;
const lines = result.split('\n');
lines.map(function (str) {
lines.map((str) => {
const regex = /^(\S+)=(.*)$/gim;
const match = regex.exec(str.trim());
@@ -789,21 +789,21 @@ const internalCertificate = {
});
if (!validFrom || !validTo) {
throw new error.ValidationError('Could not determine dates from certificate: ' + result);
throw new error.ValidationError(`Could not determine dates from certificate: ${result}`);
}
if (throw_expired && validTo < parseInt(moment().format('X'), 10)) {
throw new error.ValidationError('Certificate has expired');
}
certData['dates'] = {
certData.dates = {
from: validFrom,
to: validTo
};
return certData;
}).catch((err) => {
throw new error.ValidationError('Certificate is not valid (' + err.message + ')', err);
throw new error.ValidationError(`Certificate is not valid (${err.message})`, err);
});
},
@@ -814,7 +814,7 @@ const internalCertificate = {
* @param {Boolean} [remove]
* @returns {Object}
*/
cleanMeta: function (meta, remove) {
cleanMeta: (meta, remove) => {
internalCertificate.allowedSslFiles.map((key) => {
if (typeof meta[key] !== 'undefined' && meta[key]) {
if (remove) {
@@ -834,24 +834,35 @@ const internalCertificate = {
* @returns {Promise}
*/
requestLetsEncryptSsl: (certificate) => {
logger.info('Requesting Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
logger.info(`Requesting LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const cmd = `${certbotCommand} certonly ` +
`--config '${letsencryptConfig}' ` +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
`--cert-name "npm-${certificate.id}" ` +
'--agree-tos ' +
'--authenticator webroot ' +
`--email '${certificate.meta.letsencrypt_email}' ` +
'--preferred-challenges "dns,http" ' +
`--domains "${certificate.domain_names.join(',')}" ` +
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
const args = [
'certonly',
'--config',
letsencryptConfig,
'--work-dir',
'/tmp/letsencrypt-lib',
'--logs-dir',
'/tmp/letsencrypt-log',
'--cert-name',
`npm-${certificate.id}`,
'--agree-tos',
'--authenticator',
'webroot',
'--email',
certificate.meta.letsencrypt_email,
'--preferred-challenges',
'dns,http',
'--domains',
certificate.domain_names.join(','),
];
logger.info('Command:', cmd);
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
args.push(...adds.args);
return utils.exec(cmd)
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
return utils.execFile(certbotCommand, args, adds.opts)
.then((result) => {
logger.success(result);
return result;
@@ -868,50 +879,48 @@ const internalCertificate = {
requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
await certbot.installPlugin(certificate.meta.dns_provider);
const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
logger.info(`Requesting LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentialsLocation = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
// Whether the plugin has a --<name>-credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
let mainCmd = certbotCommand + ' certonly ' +
`--config '${letsencryptConfig}' ` +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
`--cert-name 'npm-${certificate.id}' ` +
'--agree-tos ' +
`--email '${certificate.meta.letsencrypt_email}' ` +
`--domains '${certificate.domain_names.join(',')}' ` +
`--authenticator '${dnsPlugin.full_plugin_name}' ` +
(
hasConfigArg
? `--${dnsPlugin.full_plugin_name}-credentials '${credentialsLocation}' `
: ''
) +
(
certificate.meta.propagation_seconds !== undefined
? `--${dnsPlugin.full_plugin_name}-propagation-seconds '${certificate.meta.propagation_seconds}' `
: ''
) +
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
const args = [
'certonly',
'--config',
letsencryptConfig,
'--work-dir',
'/tmp/letsencrypt-lib',
'--logs-dir',
'/tmp/letsencrypt-log',
'--cert-name',
`npm-${certificate.id}`,
'--agree-tos',
'--email',
certificate.meta.letsencrypt_email,
'--domains',
certificate.domain_names.join(','),
'--authenticator',
dnsPlugin.full_plugin_name,
];
// Prepend the path to the credentials file as an environment variable
if (certificate.meta.dns_provider === 'route53') {
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
if (hasConfigArg) {
args.push(`--${dnsPlugin.full_plugin_name}-credentials`, credentialsLocation);
}
if (certificate.meta.propagation_seconds !== undefined) {
args.push(`--${dnsPlugin.full_plugin_name}-propagation-seconds`, certificate.meta.propagation_seconds.toString());
}
if (certificate.meta.dns_provider === 'duckdns') {
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
}
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
args.push(...adds.args);
logger.info('Command:', mainCmd);
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
try {
const result = await utils.exec(mainCmd);
const result = await utils.execFile(certbotCommand, args, adds.opts);
logger.info(result);
return result;
} catch (err) {
@@ -939,7 +948,7 @@ const internalCertificate = {
return renewMethod(certificate)
.then(() => {
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem');
return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`);
})
.then((cert_info) => {
return certificateModel
@@ -971,22 +980,31 @@ const internalCertificate = {
* @returns {Promise}
*/
renewLetsEncryptSsl: (certificate) => {
logger.info('Renewing Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
logger.info(`Renewing LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const cmd = certbotCommand + ' renew --force-renewal ' +
`--config '${letsencryptConfig}' ` +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
`--cert-name 'npm-${certificate.id}' ` +
'--preferred-challenges "dns,http" ' +
'--no-random-sleep-on-renew ' +
'--disable-hook-validation ' +
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
const args = [
'renew',
'--force-renewal',
'--config',
letsencryptConfig,
'--work-dir',
'/tmp/letsencrypt-lib',
'--logs-dir',
'/tmp/letsencrypt-log',
'--cert-name',
`npm-${certificate.id}`,
'--preferred-challenges',
'dns,http',
'--no-random-sleep-on-renew',
'--disable-hook-validation',
];
logger.info('Command:', cmd);
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
args.push(...adds.args);
return utils.exec(cmd)
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
return utils.execFile(certbotCommand, args, adds.opts)
.then((result) => {
logger.info(result);
return result;
@@ -1004,27 +1022,29 @@ const internalCertificate = {
throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
}
logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
logger.info(`Renewing LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
let mainCmd = certbotCommand + ' renew --force-renewal ' +
`--config "${letsencryptConfig}" ` +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
`--cert-name 'npm-${certificate.id}' ` +
'--disable-hook-validation ' +
'--no-random-sleep-on-renew ' +
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
const args = [
'renew',
'--force-renewal',
'--config',
letsencryptConfig,
'--work-dir',
'/tmp/letsencrypt-lib',
'--logs-dir',
'/tmp/letsencrypt-log',
'--cert-name',
`npm-${certificate.id}`,
'--disable-hook-validation',
'--no-random-sleep-on-renew',
];
// Prepend the path to the credentials file as an environment variable
if (certificate.meta.dns_provider === 'route53') {
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
}
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
args.push(...adds.args);
logger.info('Command:', mainCmd);
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
return utils.exec(mainCmd)
return utils.execFile(certbotCommand, args, adds.opts)
.then(async (result) => {
logger.info(result);
return result;
@@ -1037,25 +1057,29 @@ const internalCertificate = {
* @returns {Promise}
*/
revokeLetsEncryptSsl: (certificate, throw_errors) => {
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
logger.info(`Revoking LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const mainCmd = certbotCommand + ' revoke ' +
`--config '${letsencryptConfig}' ` +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
`--cert-path '/etc/letsencrypt/live/npm-${certificate.id}/fullchain.pem' ` +
'--delete-after-revoke ' +
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
const args = [
'revoke',
'--config',
letsencryptConfig,
'--work-dir',
'/tmp/letsencrypt-lib',
'--logs-dir',
'/tmp/letsencrypt-log',
'--cert-path',
`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`,
'--delete-after-revoke',
];
// Don't fail command if file does not exist
const delete_credentialsCmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
args.push(...adds.args);
logger.info('Command:', mainCmd + '; ' + delete_credentialsCmd);
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
return utils.exec(mainCmd)
return utils.execFile(certbotCommand, args, adds.opts)
.then(async (result) => {
await utils.exec(delete_credentialsCmd);
await utils.exec(`rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`);
logger.info(result);
return result;
})
@@ -1073,9 +1097,8 @@ const internalCertificate = {
* @returns {Boolean}
*/
hasLetsEncryptSslCerts: (certificate) => {
const letsencryptPath = '/etc/letsencrypt/live/npm-' + certificate.id;
return fs.existsSync(letsencryptPath + '/fullchain.pem') && fs.existsSync(letsencryptPath + '/privkey.pem');
const letsencryptPath = internalCertificate.getLiveCertPath(certificate.id);
return fs.existsSync(`${letsencryptPath}/fullchain.pem`) && fs.existsSync(`${letsencryptPath}/privkey.pem`);
},
/**
@@ -1087,7 +1110,7 @@ const internalCertificate = {
*/
disableInUseHosts: (in_use_result) => {
if (in_use_result.total_count) {
let promises = [];
const promises = [];
if (in_use_result.proxy_hosts.length) {
promises.push(internalNginx.bulkDeleteConfigs('proxy_host', in_use_result.proxy_hosts));
@@ -1117,7 +1140,7 @@ const internalCertificate = {
*/
enableInUseHosts: (in_use_result) => {
if (in_use_result.total_count) {
let promises = [];
const promises = [];
if (in_use_result.proxy_hosts.length) {
promises.push(internalNginx.bulkGenerateConfigs('proxy_host', in_use_result.proxy_hosts));
@@ -1150,12 +1173,12 @@ const internalCertificate = {
// Create a test challenge file
const testChallengeDir = '/data/letsencrypt-acme-challenge/.well-known/acme-challenge';
const testChallengeFile = testChallengeDir + '/test-challenge';
const testChallengeFile = `${testChallengeDir}/test-challenge`;
fs.mkdirSync(testChallengeDir, {recursive: true});
fs.writeFileSync(testChallengeFile, 'Success', {encoding: 'utf8'});
async function performTestForDomain (domain) {
logger.info('Testing http challenge for ' + domain);
logger.info(`Testing http challenge for ${domain}`);
const url = `http://${domain}/.well-known/acme-challenge/test-challenge`;
const formBody = `method=G&url=${encodeURI(url)}&bodytype=T&requestbody=&headername=User-Agent&headervalue=None&locationid=1&ch=false&cc=false`;
const options = {
@@ -1169,13 +1192,16 @@ const internalCertificate = {
const result = await new Promise((resolve) => {
const req = https.request('https://www.site24x7.com/tools/restapi-tester', options, function (res) {
const req = https.request('https://www.site24x7.com/tools/restapi-tester', options, (res) => {
let responseBody = '';
res.on('data', (chunk) => responseBody = responseBody + chunk);
res.on('end', function () {
res.on('data', (chunk) => {
responseBody = responseBody + chunk;
});
res.on('end', () => {
try {
const parsedBody = JSON.parse(responseBody + '');
const parsedBody = JSON.parse(`${responseBody}`);
if (res.statusCode !== 200) {
logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned: ${parsedBody.message}`);
resolve(undefined);
@@ -1196,7 +1222,7 @@ const internalCertificate = {
// Make sure to write the request body.
req.write(formBody);
req.end();
req.on('error', function (e) { logger.warn(`Failed to test HTTP challenge for domain ${domain}`, e);
req.on('error', (e) => { logger.warn(`Failed to test HTTP challenge for domain ${domain}`, e);
resolve(undefined); });
});
@@ -1238,6 +1264,34 @@ const internalCertificate = {
fs.unlinkSync(testChallengeFile);
return results;
},
getAdditionalCertbotArgs: (certificate_id, dns_provider) => {
const args = [];
if (letsencryptServer !== null) {
args.push('--server', letsencryptServer);
}
if (letsencryptStaging && letsencryptServer === null) {
args.push('--staging');
}
// For route53, add the credentials file as an environment variable,
// inheriting the process env
const opts = {};
if (certificate_id && dns_provider === 'route53') {
opts.env = process.env;
opts.env.AWS_CONFIG_FILE = `/etc/letsencrypt/credentials/credentials-${certificate_id}`;
}
if (dns_provider === 'duckdns') {
args.push('--dns-duckdns-no-txt-restore');
}
return {args: args, opts: opts};
},
getLiveCertPath: (certificate_id) => {
return `/etc/letsencrypt/live/npm-${certificate_id}`;
}
};

View File

@@ -1,5 +1,5 @@
const _ = require('lodash');
const fs = require('fs');
const fs = require('node:fs');
const logger = require('../logger').nginx;
const config = require('../lib/config');
const utils = require('../lib/utils');
@@ -57,9 +57,9 @@ const internalNginx = {
// It will always look like this:
// nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (6: No such device or address)
let valid_lines = [];
let err_lines = err.message.split('\n');
err_lines.map(function (line) {
const valid_lines = [];
const err_lines = err.message.split('\n');
err_lines.map((line) => {
if (line.indexOf('/var/log/nginx/error.log') === -1) {
valid_lines.push(line);
}
@@ -105,7 +105,7 @@ const internalNginx = {
logger.info('Testing Nginx configuration');
}
return utils.exec('/usr/sbin/nginx -t -g "error_log off;"');
return utils.execFile('/usr/sbin/nginx', ['-t', '-g', 'error_log off;']);
},
/**
@@ -115,7 +115,7 @@ const internalNginx = {
return internalNginx.test()
.then(() => {
logger.info('Reloading Nginx');
return utils.exec('/usr/sbin/nginx -s reload');
return utils.execFile('/usr/sbin/nginx', ['-s', 'reload']);
});
},
@@ -128,7 +128,7 @@ const internalNginx = {
if (host_type === 'default') {
return '/data/nginx/default_host/site.conf';
}
return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf';
return `/data/nginx/${internalNginx.getFileFriendlyHostType(host_type)}/${host_id}.conf`;
},
/**
@@ -141,7 +141,7 @@ const internalNginx = {
let template;
try {
template = fs.readFileSync(__dirname + '/../templates/_location.conf', {encoding: 'utf8'});
template = fs.readFileSync(`${__dirname}/../templates/_location.conf`, {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
@@ -152,7 +152,7 @@ const internalNginx = {
const locationRendering = async () => {
for (let i = 0; i < host.locations.length; i++) {
let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
const locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
{ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
{allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
@@ -183,21 +183,21 @@ const internalNginx = {
*/
generateConfig: (host_type, host_row) => {
// Prevent modifying the original object:
let host = JSON.parse(JSON.stringify(host_row));
const host = JSON.parse(JSON.stringify(host_row));
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
if (config.debug()) {
logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
logger.info(`Generating ${nice_host_type} Config:`, JSON.stringify(host, null, 2));
}
const renderEngine = utils.getRenderEngine();
return new Promise((resolve, reject) => {
let template = null;
let filename = internalNginx.getConfigName(nice_host_type, host.id);
let template = null;
const filename = internalNginx.getConfigName(nice_host_type, host.id);
try {
template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', {encoding: 'utf8'});
template = fs.readFileSync(`${__dirname}/../templates/${nice_host_type}.conf`, {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
@@ -252,7 +252,7 @@ const internalNginx = {
})
.catch((err) => {
if (config.debug()) {
logger.warn('Could not write ' + filename + ':', err.message);
logger.warn(`Could not write ${filename}:`, err.message);
}
reject(new error.ConfigurationError(err.message));
@@ -277,11 +277,11 @@ const internalNginx = {
const renderEngine = utils.getRenderEngine();
return new Promise((resolve, reject) => {
let template = null;
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
let template = null;
const filename = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
try {
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
template = fs.readFileSync(`${__dirname}/../templates/letsencrypt-request.conf`, {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
@@ -302,7 +302,7 @@ const internalNginx = {
})
.catch((err) => {
if (config.debug()) {
logger.warn('Could not write ' + filename + ':', err.message);
logger.warn(`Could not write ${filename}:`, err.message);
}
reject(new error.ConfigurationError(err.message));
@@ -316,7 +316,7 @@ const internalNginx = {
* @param {String} filename
*/
deleteFile: (filename) => {
logger.debug('Deleting file: ' + filename);
logger.debug(`Deleting file: ${filename}`);
try {
fs.unlinkSync(filename);
} catch (err) {
@@ -330,7 +330,7 @@ const internalNginx = {
* @returns String
*/
getFileFriendlyHostType: (host_type) => {
return host_type.replace(new RegExp('-', 'g'), '_');
return host_type.replace(/-/g, '_');
},
/**
@@ -340,7 +340,7 @@ const internalNginx = {
* @returns {Promise}
*/
deleteLetsEncryptRequestConfig: (certificate) => {
const config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
const config_file = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
return new Promise((resolve/*, reject*/) => {
internalNginx.deleteFile(config_file);
resolve();
@@ -355,7 +355,7 @@ const internalNginx = {
*/
deleteConfig: (host_type, host, delete_err_file) => {
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
const config_file_err = config_file + '.err';
const config_file_err = `${config_file}.err`;
return new Promise((resolve/*, reject*/) => {
internalNginx.deleteFile(config_file);
@@ -373,7 +373,7 @@ const internalNginx = {
*/
renameConfigAsError: (host_type, host) => {
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
const config_file_err = config_file + '.err';
const config_file_err = `${config_file}.err`;
return new Promise((resolve/*, reject*/) => {
fs.unlink(config_file, () => {
@@ -392,8 +392,8 @@ const internalNginx = {
* @returns {Promise}
*/
bulkGenerateConfigs: (host_type, hosts) => {
let promises = [];
hosts.map(function (host) {
const promises = [];
hosts.map((host) => {
promises.push(internalNginx.generateConfig(host_type, host));
});
@@ -406,8 +406,8 @@ const internalNginx = {
* @returns {Promise}
*/
bulkDeleteConfigs: (host_type, hosts) => {
let promises = [];
hosts.map(function (host) {
const promises = [];
hosts.map((host) => {
promises.push(internalNginx.deleteConfig(host_type, host, true));
});
@@ -418,14 +418,12 @@ const internalNginx = {
* @param {string} config
* @returns {boolean}
*/
advancedConfigHasDefaultLocation: function (cfg) {
return !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
},
advancedConfigHasDefaultLocation: (cfg) => !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im),
/**
* @returns {boolean}
*/
ipv6Enabled: function () {
ipv6Enabled: () => {
if (typeof process.env.DISABLE_IPV6 !== 'undefined') {
const disabled = process.env.DISABLE_IPV6.toLowerCase();
return !(disabled === 'on' || disabled === 'true' || disabled === '1' || disabled === 'yes');

View File

@@ -369,7 +369,7 @@ const internalStream = {
.where('is_deleted', 0)
.groupBy('id')
.allowGraph('[owner,certificate]')
.orderByRaw('CAST(incoming_port AS INTEGER) ASC');
.orderBy('incoming_port', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1));

View File

@@ -11,7 +11,7 @@ const certbot = {
/**
* @param {array} pluginKeys
*/
installPlugins: async function (pluginKeys) {
installPlugins: async (pluginKeys) => {
let hasErrors = false;
return new Promise((resolve, reject) => {
@@ -21,7 +21,7 @@ const certbot = {
}
batchflow(pluginKeys).sequential()
.each((i, pluginKey, next) => {
.each((_i, pluginKey, next) => {
certbot.installPlugin(pluginKey)
.then(() => {
next();
@@ -51,7 +51,7 @@ const certbot = {
* @param {string} pluginKey
* @returns {Object}
*/
installPlugin: async function (pluginKey) {
installPlugin: async (pluginKey) => {
if (typeof dnsPlugins[pluginKey] === 'undefined') {
// throw Error(`Certbot plugin ${pluginKey} not found`);
throw new error.ItemNotFoundError(pluginKey);
@@ -63,8 +63,15 @@ const certbot = {
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate';
return utils.exec(cmd)
// SETUPTOOLS_USE_DISTUTILS is required for certbot plugins to install correctly
// in new versions of Python
let env = Object.assign({}, process.env, {SETUPTOOLS_USE_DISTUTILS: 'stdlib'});
if (typeof plugin.env === 'object') {
env = Object.assign(env, plugin.env);
}
const cmd = `. /opt/certbot/bin/activate && pip install --no-cache-dir ${plugin.dependencies} ${plugin.package_name}${plugin.version} && deactivate`;
return utils.exec(cmd, {env})
.then((result) => {
logger.complete(`Installed ${pluginKey}`);
return result;

View File

@@ -1,13 +1,13 @@
const _ = require('lodash');
const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const exec = require('node:child_process').exec;
const execFile = require('node:child_process').execFile;
const { Liquid } = require('liquidjs');
const logger = require('../logger').global;
const error = require('./error');
module.exports = {
exec: async function(cmd, options = {}) {
exec: async (cmd, options = {}) => {
logger.debug('CMD:', cmd);
const { stdout, stderr } = await new Promise((resolve, reject) => {
@@ -29,15 +29,19 @@ module.exports = {
/**
* @param {String} cmd
* @param {Array} args
* @param {Object|undefined} options
* @returns {Promise}
*/
execFile: function (cmd, args) {
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
execFile: (cmd, args, options) => {
logger.debug(`CMD: ${cmd} ${args ? args.join(' ') : ''}`);
if (typeof options === 'undefined') {
options = {};
}
return new Promise((resolve, reject) => {
execFile(cmd, args, function (err, stdout, /*stderr*/) {
execFile(cmd, args, options, (err, stdout, stderr) => {
if (err && typeof err === 'object') {
reject(err);
reject(new error.CommandError(stderr, 1, err));
} else {
resolve(stdout.trim());
}
@@ -51,7 +55,7 @@ module.exports = {
* @param {Array} omissions
* @returns {Function}
*/
omitRow: function (omissions) {
omitRow: (omissions) => {
/**
* @param {Object} row
* @returns {Object}
@@ -67,7 +71,7 @@ module.exports = {
* @param {Array} omissions
* @returns {Function}
*/
omitRows: function (omissions) {
omitRows: (omissions) => {
/**
* @param {Array} rows
* @returns {Object}
@@ -83,9 +87,9 @@ module.exports = {
/**
* @returns {Object} Liquid render engine
*/
getRenderEngine: function () {
getRenderEngine: () => {
const renderEngine = new Liquid({
root: __dirname + '/../templates/'
root: `${__dirname}/../templates/`
});
/**

View File

@@ -6,7 +6,7 @@ const apiValidator = require('../../lib/validator/api');
const internalCertificate = require('../../internal/certificate');
const schema = require('../../schema');
let router = express.Router({
const router = express.Router({
caseSensitive: true,
strict: true,
mergeParams: true
@@ -231,7 +231,7 @@ router
*/
router
.route('/:certificate_id/download')
.options((req, res) => {
.options((_req, res) => {
res.sendStatus(204);
})
.all(jwtdecode())

View File

@@ -181,7 +181,7 @@ router
return internalUser.setPassword(res.locals.access, payload);
})
.then((result) => {
res.status(201)
res.status(200)
.send(result);
})
.catch(next);
@@ -212,7 +212,7 @@ router
return internalUser.setPermissions(res.locals.access, payload);
})
.then((result) => {
res.status(201)
res.status(200)
.send(result);
})
.catch(next);
@@ -238,7 +238,7 @@ router
.post((req, res, next) => {
internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
.then((result) => {
res.status(201)
res.status(200)
.send(result);
})
.catch(next);

View File

@@ -110,6 +110,11 @@
"caching_enabled": {
"description": "Should we cache assets",
"type": "boolean"
},
"email": {
"description": "Email address",
"type": "string",
"pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
}
}
}

View File

@@ -69,7 +69,7 @@
"type": "object"
},
"letsencrypt_email": {
"type": "string"
"$ref": "../common.json#/properties/email"
},
"propagation_seconds": {
"type": "integer",

View File

@@ -1,7 +1,7 @@
{
"type": "array",
"description": "Proxy Hosts list",
"description": "Streams list",
"items": {
"$ref": "./proxy-host-object.json"
"$ref": "./stream-object.json"
}
}

View File

@@ -24,7 +24,7 @@ const setupDefaultUser = () => {
const email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
const password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
logger.info('Creating a new user: ' + email + ' with password: ' + password);
logger.info(`Creating a new user: ${email} with password: ${password}`);
const data = {
is_deleted: 0,
@@ -113,20 +113,20 @@ const setupCertbotPlugins = () => {
.andWhere('provider', 'letsencrypt')
.then((certificates) => {
if (certificates && certificates.length) {
let plugins = [];
let promises = [];
const plugins = [];
const promises = [];
certificates.map(function (certificate) {
certificates.map((certificate) => {
if (certificate.meta && certificate.meta.dns_challenge === true) {
if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
plugins.push(certificate.meta.dns_provider);
}
// Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
// Escape single quotes and backslashes
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
const credentials_cmd = `[ -f '${credentials_loc}' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo '${escapedCredentials}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'; }`;
promises.push(utils.exec(credentials_cmd));
}
});
@@ -136,7 +136,7 @@ const setupCertbotPlugins = () => {
if (promises.length) {
return Promise.all(promises)
.then(() => {
logger.info('Added Certbot plugins ' + plugins.join(', '));
logger.info(`Added Certbot plugins ${plugins.join(', ')}`);
});
}
});
@@ -165,9 +165,7 @@ const setupLogrotation = () => {
return runLogrotate();
};
module.exports = function () {
return setupDefaultUser()
.then(setupDefaultSettings)
.then(setupCertbotPlugins)
.then(setupLogrotation);
};
module.exports = () => setupDefaultUser()
.then(setupDefaultSettings)
.then(setupCertbotPlugins)
.then(setupLogrotation);

View File

@@ -492,9 +492,9 @@ boxen@^4.2.0:
widest-line "^3.1.0"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
version "1.1.12"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"

View File

@@ -18,6 +18,7 @@ services:
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npmpass'
MARIADB_AUTO_UPGRADE: '1'
volumes:
- mysql_vol:/var/lib/mysql
networks:

View File

@@ -8,21 +8,53 @@ log_info 'Setting ownership ...'
# root
chown root /tmp/nginx
# npm user and group
chown -R "$PUID:$PGID" /data
chown -R "$PUID:$PGID" /etc/letsencrypt
chown -R "$PUID:$PGID" /run/nginx
chown -R "$PUID:$PGID" /tmp/nginx
chown -R "$PUID:$PGID" /var/cache/nginx
chown -R "$PUID:$PGID" /var/lib/logrotate
chown -R "$PUID:$PGID" /var/lib/nginx
chown -R "$PUID:$PGID" /var/log/nginx
locations=(
"/data"
"/etc/letsencrypt"
"/run/nginx"
"/tmp/nginx"
"/var/cache/nginx"
"/var/lib/logrotate"
"/var/lib/nginx"
"/var/log/nginx"
"/etc/nginx/nginx"
"/etc/nginx/nginx.conf"
"/etc/nginx/conf.d"
)
# Don't chown entire /etc/nginx folder as this causes crashes on some systems
chown -R "$PUID:$PGID" /etc/nginx/nginx
chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
chown -R "$PUID:$PGID" /etc/nginx/conf.d
chownit() {
local dir="$1"
local recursive="${2:-true}"
# Prevents errors when installing python certbot plugins when non-root
chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
find /opt/certbot/lib/python*/site-packages -not -user "$PUID" -execdir chown "$PUID:$PGID" {} \+
local have
have="$(stat -c '%u:%g' "$dir")"
echo "- $dir ... "
if [ "$have" != "$PUID:$PGID" ]; then
if [ "$recursive" = 'true' ] && [ -d "$dir" ]; then
chown -R "$PUID:$PGID" "$dir"
else
chown "$PUID:$PGID" "$dir"
fi
echo " DONE"
else
echo " SKIPPED"
fi
}
for loc in "${locations[@]}"; do
chownit "$loc"
done
if [ "$(is_true "${SKIP_CERTBOT_OWNERSHIP:-}")" = '1' ]; then
log_info 'Skipping ownership change of certbot directories'
else
log_info 'Changing ownership of certbot directories, this may take some time ...'
chownit "/opt/certbot" false
chownit "/opt/certbot/bin" false
# Handle all site-packages directories efficiently
find /opt/certbot/lib -type d -name "site-packages" | while read -r SITE_PACKAGES_DIR; do
chownit "$SITE_PACKAGES_DIR"
done
fi

View File

@@ -5,12 +5,9 @@ set -e
log_info 'Dynamic resolvers ...'
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
# thanks @tfmm
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ];
then
if [ "$(is_true "$DISABLE_IPV6")" = '1' ]; then
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
else
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf

View File

@@ -8,14 +8,11 @@ set -e
log_info 'IPv6 ...'
# Lowercase
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
process_folder () {
FILES=$(find "$1" -type f -name "*.conf")
SED_REGEX=
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ]; then
if [ "$(is_true "$DISABLE_IPV6")" = '1' ]; then
# IPV6 is disabled
echo "Disabling IPV6 in hosts in: $1"
SED_REGEX='s/^([^#]*)listen \[::\]/\1#listen [::]/g'

View File

@@ -56,3 +56,13 @@ get_group_id () {
getent group "$1" | cut -d: -f3
fi
}
# param $1: value
is_true () {
VAL=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')
if [ "$VAL" == 'true' ] || [ "$VAL" == 'on' ] || [ "$VAL" == '1' ] || [ "$VAL" == 'yes' ]; then
echo '1'
else
echo '0'
fi
}

View File

@@ -8,7 +8,7 @@ BLUE='\E[1;34m'
GREEN='\E[1;32m'
RESET='\E[0m'
S6_OVERLAY_VERSION=3.2.0.2
S6_OVERLAY_VERSION=3.2.1.0
TARGETPLATFORM=${1:-linux/amd64}
# Determine the correct binary file for the architecture given

View File

@@ -161,6 +161,14 @@ The easy fix is to add a Docker environment variable to the Nginx Proxy Manager
DISABLE_IPV6: 'true'
```
## Disabling IP Ranges Fetch
By default, NPM fetches IP ranges from CloudFront and Cloudflare during application startup. In environments with limited internet access or to speed up container startup, this fetch can be disabled:
```yml
environment:
IP_RANGES_FETCH_ENABLED: 'false'
```
## Custom Nginx Configurations

View File

@@ -21,7 +21,7 @@ services:
# Add any other Stream port you want to expose
# - '21:21' # FTP
environment:
#environment:
# Uncomment this if you want to change the location of
# the SQLite DB file within the container
# DB_SQLITE_FILE: "/data/database.sqlite"

View File

@@ -1065,9 +1065,9 @@ vfile@^6.0.0:
vfile-message "^4.0.0"
vite@^5.4.8:
version "5.4.14"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.14.tgz#ff8255edb02134df180dcfca1916c37a6abe8408"
integrity sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==
version "5.4.19"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.19.tgz#20efd060410044b3ed555049418a5e7d1998f959"
integrity sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==
dependencies:
esbuild "^0.21.3"
postcss "^8.4.43"

View File

@@ -60,7 +60,7 @@
},
"footer": {
"fork-me": "Fork me on Github",
"copy": "&copy; 2024 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
"copy": "&copy; 2025 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
},
"dashboard": {
@@ -297,297 +297,5 @@
"default-site-html": "Custom Page",
"default-site-redirect": "Redirect"
}
},
"es": {
"str": {
"email-address": "Dirección de correo electrónico",
"username": "Nombre de usuario",
"password": "Contraseña",
"sign-in": "Registrarse",
"sign-out": "Cerrar sesión",
"try-again": "Intentar otra vez",
"name": "Nombre",
"email": "Correo electrónico",
"roles": "Roles",
"created-on": "Creado: {date}",
"save": "Guardar",
"cancel": "Cancelar",
"close": "Cerrar",
"enable": "Habilitar",
"disable": "Inhabilitar",
"sure": "Si, estoy seguro",
"disabled": "Inhabilitado",
"choose-file": "Elija el archivo",
"source": "Fuente",
"destination": "Destino",
"ssl": "SSL",
"access": "Acceso",
"public": "Público",
"edit": "Editar",
"delete": "Borrar",
"logs": "Registros",
"status": "Estatus",
"online": "En línea",
"offline": "Desconectado",
"unknown": "Desconocido",
"expires": "Caduca",
"value": "Valor",
"please-wait": "Por favor, espere...",
"all": "Todo",
"any": "Ninguno"
},
"login": {
"title": "Ingrese a su cuenta"
},
"main": {
"app": "Nginx Proxy Manager",
"version": "v{version}",
"welcome": "Bienvenidos a Nginx Proxy Manager",
"logged-in": "Has iniciado sesión como {name}",
"unknown-error": "Error al cargar cosas. Vuelva a cargar la aplicación.",
"unknown-user": "Usuario desconocido",
"sign-in-as": "Vuelve a iniciar sesión como {name}"
},
"roles": {
"title": "Roles",
"admin": "Administrador",
"user": "Helicóptero Apache"
},
"menu": {
"dashboard": "Panel",
"hosts": "Servidores"
},
"footer": {
"fork-me": "Bifurcame en Github",
"copy": "&copy; 2022 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
"theme": "Tema por <a href=\"{url}\" target=\"_blank\">Tabler</a>"
},
"dashboard": {
"title": "Hola {name}"
},
"all-hosts": {
"empty-subtitle": "{manage, select, true{¿Por qué no creas uno?} other{Y no tienes permiso para crear uno.}}",
"details": "Detalles",
"enable-ssl": "Habilitar SSL",
"force-ssl": "Forzar SSL",
"http2-support": "Soporte HTTP/2",
"domain-names": "Nombres de Dominios",
"cert-provider": "Proveedor de certificados",
"block-exploits": "Bloquear exploits comunes",
"caching-enabled": "Caché de Activos",
"ssl-certificate": "Certificado SSL",
"none": "Ninguno",
"new-cert": "Solicitar un nuevo Certificado SSL",
"with-le": "con Let's Encrypt",
"no-ssl": "Este servidor no usará HTTPS",
"advanced": "Avanzado",
"advanced-warning": "¡Ingrese su configuración Nginx personalizada aquí bajo su propio riesgo!",
"advanced-config": "Configuración Nginx personalizada",
"advanced-config-var-headline": "Estos detalles del proxy están disponibles como variables Nginx:",
"advanced-config-header-info": "Tenga en cuenta que cualquier directiva add_header o set_header agregada aquí no será utilizada por Nginx. Deberá agregar una ubicación personalizada '/' y agregar el encabezado en la configuración personalizada allí.",
"hsts-enabled": "HSTS habilitado",
"hsts-subdomains": "Subdominios HSTS",
"locations": "Ubicaciones personalizadas"
},
"locations": {
"new_location": "Agregar ubicación",
"path": "/ruta",
"location_label": "Definir ubicación",
"delete": "Borrar"
},
"ssl": {
"letsencrypt": "Let's Encrypt",
"other": "Personalizada",
"none": "solo HTTP",
"letsencrypt-email": "Dirección de correo electrónico para Let's Encrypt",
"letsencrypt-agree": "Acepto los <a href=\"{url}\" target=\"_blank\">Términos de servicio de Let's Encrypt</a>",
"delete-ssl": "Los certificados SSL adjuntos NO se eliminarán, deberán eliminarse manualmente.",
"hosts-warning": "Estos dominios ya deben estar configurados para apuntar a esta instalación",
"no-wildcard-without-dns": "No se puede solicitar el certificado de Let's Encrypt para dominios comodín cuando no se usa el desafío de DNS",
"dns-challenge": "Utilice un desafío de DNS",
"certbot-warning": "Esta sección requiere algunos conocimientos sobre Certbot y sus complementos de DNS. Consulte la documentación de los complementos respectivos.",
"dns-provider": "Proveedor de DNS",
"please-choose": "Por favor, elige...",
"credentials-file-content": "Contenido del archivo de credenciales",
"credentials-file-content-info": "Este complemento requiere un archivo de configuración que contenga un token API u otras credenciales para su proveedor",
"stored-as-plaintext-info": "¡Estos datos se almacenarán como texto sin formato en la base de datos y en un archivo!",
"propagation-seconds": "Segundos de propagación",
"propagation-seconds-info": "Deje vacío para usar el valor predeterminado de los complementos. Número de segundos de espera para la propagación de DNS.",
"processing-info": "Procesando... Esto puede tardar unos minutos.",
"passphrase-protection-support-info": "Los archivos clave protegidos con una frase de contraseña no son compatibles."
},
"proxy-hosts": {
"title": "Servidores proxy",
"empty": "No hay Servidores proxy",
"add": "Agregar Servidor proxy",
"form-title": "{id, select, undefined{Nuevo} other{Editar}} Servidor proxy",
"forward-scheme": "Esquema",
"forward-host": "Reenviar nombre de servidor / IP",
"forward-port": "Reenviar Puerto",
"delete": "Borrar Servidor Proxy",
"delete-confirm": "¿Está seguro de que desea eliminar el Servidor Proxy para: <strong>{domains}</strong>?",
"help-title": "¿Qué es un Servidor proxy?",
"help-content": "Un servidor proxy es el punto final entrante para un servicio web que desea reenviar.\nProporciona una terminación SSL opcional para su servicio que podría no tener soporte SSL integrado.\nLos servidores proxy son el uso más común para Nginx Proxy Manager.",
"access-list": "Lista de acceso",
"allow-websocket-upgrade": "Soporte WebSockets",
"ignore-invalid-upstream-ssl": "Ignorar SSL no válido",
"custom-forward-host-help": "Agregue una ruta para el reenvío de subcarpetas.\nEjemplo: 203.0.113.25/ruta",
"search": "Buscar Servidor..."
},
"redirection-hosts": {
"title": "Servidores de redirección",
"empty": "No hay Servidores de redirección",
"add": "Agregar Servidor de redirección",
"form-title": "{id, select, undefined{Nuevo} other{Editar}} Servidor de redirección",
"forward-scheme": "Esquema",
"forward-http-status-code": "Código HTTP",
"forward-domain": "Reenviar dominio",
"preserve-path": "Conservar ruta",
"delete": "Borrar Servidor de redirección",
"delete-confirm": "¿Está seguro de que desea eliminar el servidor de redirección para: <strong>{domains}</strong>?",
"help-title": "¿Qué es un Servidor de redirección?",
"help-content": "Un servidor de redirección redirigirá las solicitudes del dominio entrante y empujará al espectador a otro dominio.\nLa razón más común para usar este tipo de servidor es cuando su sitio web cambia de dominio pero aún tiene un motor de búsqueda o enlaces de referencia que apuntan al dominio anterior.",
"search": "Buscar Servidor..."
},
"dead-hosts": {
"title": "",
"empty": "No hay Servidores 404",
"add": "Agregar Servidor 404",
"form-title": "{id, select, undefined{Nuevo} other{Editar}} Servidor 404",
"delete": "Borrar Servidor 404",
"delete-confirm": "¿Está seguro de que desea eliminar este Servidor 404?",
"help-title": "¿Qué es un Servidor 404?",
"help-content": "Un servidor 404 es simplemente una configuración de servidor que muestra una página 404.\nEsto puede ser útil cuando su dominio aparece en los motores de búsqueda y desea proporcionar una página de error más agradable o específicamente para decirles a los indexadores de búsqueda que las páginas del dominio ya no existen.\nOtro beneficio de tener este servidor es rastrear los registros de visitas y ver las referencias.",
"search": "Buscar Servidor..."
},
"streams": {
"title": "Streams",
"empty": "No hay Streams",
"add": "Agregar Stream",
"form-title": "{id, select, undefined{Nuevo} other{Editar}} Stream",
"incoming-port": "Puerto entrante",
"forwarding-host": "Servidor de reenvío",
"forwarding-port": "Puerto de reenvío",
"tcp-forwarding": "Reenvío TCP",
"udp-forwarding": "Reenvío UDP",
"forward-type-error": "Al menos un tipo de protocolo debe estar habilitado",
"protocol": "Protocol",
"tcp": "TCP",
"udp": "UDP",
"delete": "Borrar Stream",
"delete-confirm": "¿Está seguro de que desea eliminar esta Stream?",
"help-title": "¿Qué es un Stream?",
"help-content": "Una característica relativamente nueva para Nginx, un Stream servirá para reenviar el tráfico TCP/UDP directamente a otra computadora en la red.\nSi está ejecutando servidores de juegos, servidores FTP o SSH, esto puede ser útil.",
"search": "Buscar Puerto entrante..."
},
"certificates": {
"title": "Certificados SSL",
"empty": "No hay Certificados SSL",
"add": "Agregar Certificado SSL",
"form-title": "Agregar {provider, select, letsencrypt Certificado {Let's Encrypt} other{personalizado}}",
"delete": "Borrar Certificado SSL",
"delete-confirm": "¿Está seguro de que desea eliminar este certificado SSL? Cualquier servidor que lo use deberá actualizarse más tarde.",
"help-title": "Certificados SSL",
"help-content": "Los certificados SSL (correctamente conocidos como Certificados TLS) son una forma de clave de encriptación que permite que su sitio sea encriptado para el usuario final.\nNginx Proxy Manager usa un servicio llamado Let's Encrypt para emitir certificados SSL gratis.\nSi tiene algún tipo de información personal, contraseñas o datos confidenciales detrás de Nginx Proxy Manager, probablemente sea una buena idea usar un certificado.\nNginx Proxy Manager también es compatible con la autenticación DNS si no está ejecutando su sitio frente a Internet, o si solo desea un certificado comodín.",
"other-certificate": "Certificado",
"other-certificate-key": "Clave de Certificado",
"other-intermediate-certificate": "Certificado Intermedio",
"force-renew": "Renovar Ahora",
"test-reachability": "Accesibilidad del servidor de prueba",
"reachability-title": "Accesibilidad del servidor de prueba",
"reachability-info": "Pruebe si se puede acceder a los dominios desde la Internet pública utilizando Site24x7. Esto no es necesario cuando se utiliza el Desafío DNS.",
"reachability-failed-to-reach-api": "La comunicación con la API falló, ¿Nginx Proxy Manager se está ejecutando correctamente?",
"reachability-failed-to-check": "No se pudo verificar la accesibilidad debido a un error de comunicación con site24x7.com.",
"reachability-ok": "Su servidor es accesible y la creación de certificados debería ser posible.",
"reachability-404": "Hay un servidor encontrado en este dominio, pero no parece ser Nginx Proxy Manager. Asegúrese de que su dominio apunte a la IP donde se ejecuta su instancia de Nginx Proxy Manager.",
"reachability-not-resolved": "No hay servidor disponible en este dominio. Asegúrese de que su dominio exista y apunte a la IP donde se ejecuta su instancia de Nginx Proxy Manager y, si es necesario, se reenvía el puerto 80 en su enrutador.",
"reachability-wrong-data": "Se encontró un servidor en este dominio pero devolvió datos inesperados. ¿Es el servidor Nginx Proxy Manager? Asegúrese de que su dominio apunte a la IP donde se ejecuta su instancia de Nginx Proxy Manager.",
"reachability-other": "Se encontró un servidor en este dominio pero devolvió un código de estado inesperado {code}. ¿Es el servidor Nginx Proxy Manager? Asegúrese de que su dominio apunte a la IP donde se ejecuta su instancia de Nginx Proxy Manager.",
"download": "Descargar",
"renew-title": "Renovar Certificado Let's Encrypt",
"search": "Buscar Certificado..."
},
"access-lists": {
"title": "Listas de acceso",
"empty": "No hay Listas de acceso",
"add": "Agregar Listas de acceso",
"form-title": "{id, select, undefined{Nueva} other{Editar}} Lista de acceso",
"delete": "Borrar Lista de acceso",
"delete-confirm": "¿Está seguro de que desea eliminar esta lista de acceso?",
"public": "Públicamente Accesible",
"public-sub": "Sin restricciones de acceso",
"help-title": "¿Qué es una lista de acceso?",
"help-content": "Las listas de acceso proporcionan una lista negra o una lista blanca de direcciones IP de clientes específicos junto con la autenticación para los servidores proxy a través de la autenticación HTTP básica.\nPuede configurar varias reglas de cliente, nombres de usuario y contraseñas para una sola lista de acceso y luego aplicarla a un servidor proxy.\nEsto es más útil para los servicios web reenviados que no tienen mecanismos de autenticación integrados o que desea proteger del acceso de clientes desconocidos.",
"item-count": "{count} {count, select, 1{Usuario} other{Usuarios}}",
"client-count": "{count} {count, select, 1{Regla} other{Reglas}}",
"proxy-host-count": "{count} {count, select, 1{Servidor Proxy} other{Servidores Proxy}}",
"delete-has-hosts": "Esta lista de acceso está asociada con {count} Servidores Proxy. Estarán disponibles públicamente al eliminarlos.",
"details": "Detalles",
"authorization": "Autorización",
"access": "Acceso",
"satisfy": "Satisfacer",
"satisfy-any": "Satisfacer cualquiera",
"pass-auth": "Pasar autenticación al servidor",
"access-add": "Agregar",
"auth-add": "Agregar",
"search": "Buscar Acceso..."
},
"users": {
"title": "Usuarios",
"default_error": "Se debe cambiar la dirección de correo electrónico predeterminada",
"add": "Agregar Usuario",
"nickname": "Apodo",
"full-name": "Nombre completo",
"edit-details": "Editar Detalles",
"change-password": "Cambia contraseña",
"edit-permissions": "Editar Permisos",
"sign-in-as": "Iniciar sesión como usuario",
"form-title": "{id, select, undefined{Nuevo} other{Editar}} Usuario",
"delete": "Borrar {name, select, undefined{Usuario} other{{name}}}",
"delete-confirm": "¿Está seguro de que desea eliminar <strong>{name}</strong>?",
"password-title": "Cambia la contraseña{self, select, false{ for {name}} other{}}",
"current-password": "Contraseña actual",
"new-password": "Nueva contraseña",
"confirm-password": "Confirmar contraseña",
"permissions-title": "Permisos para {name}",
"admin-perms": "Este usuario es un administrador y algunos elementos no se pueden modificar",
"perms-visibility": "Visibilidad del elemento",
"perms-visibility-user": "Solo elementos creados",
"perms-visibility-all": "Todos los elementos",
"perm-manage": "Administrar",
"perm-view": "Sólo vista",
"perm-hidden": "Oculto",
"search": "Buscar Usuario..."
},
"audit-log": {
"title": "Registro de Auditoría",
"empty": "No hay Registros.",
"empty-subtitle": "Tan pronto como usted u otro usuario cambien algo, el historial de esos eventos aparecerá aquí.",
"proxy-host": "Servidor Proxy",
"redirection-host": "Servidor de redirección",
"dead-host": "Servidor 404",
"stream": "Stream",
"user": "Usuario",
"certificate": "Certificado",
"access-list": "Lista de acceso",
"created": "Creado {name}",
"updated": "Actualizado {name}",
"deleted": "Eliminado {name}",
"enabled": "Activado {name}",
"disabled": "Desactivado {name}",
"renewed": "Renovado {name}",
"meta-title": "Detalles del evento",
"view-meta": "Ver Detalles",
"date": "Fecha",
"search": "Buscar Registro..."
},
"settings": {
"title": "Ajustes",
"default-site": "Sitio por defecto",
"default-site-congratulations": "Página de felicitaciones",
"default-site-404": "Página de 404",
"default-site-html": "Pagina personalizada",
"default-site-redirect": "Redirigir"
}
}
}

View File

@@ -167,4 +167,5 @@ $pink: #f66d9b;
textarea.form-control.text-monospace {
font-size: 12px;
font-family: monospace;
}

View File

@@ -907,6 +907,13 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
available-typed-arrays@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
dependencies:
possible-typed-array-names "^1.0.0"
babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -1790,6 +1797,32 @@ cacheable-request@^6.0.0:
normalize-url "^4.1.0"
responselike "^1.0.2"
call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
call-bind@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
dependencies:
call-bind-apply-helpers "^1.0.0"
es-define-property "^1.0.0"
get-intrinsic "^1.2.4"
set-function-length "^1.2.2"
call-bound@^1.0.3, call-bound@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
dependencies:
call-bind-apply-helpers "^1.0.2"
get-intrinsic "^1.3.0"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -1949,12 +1982,12 @@ ci-info@^2.0.0:
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
version "1.0.6"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7"
integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
inherits "^2.0.4"
safe-buffer "^5.2.1"
class-utils@^0.3.5:
version "0.3.6"
@@ -2232,7 +2265,7 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0"
elliptic "^6.5.3"
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
create-hash@^1.1.0, create-hash@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
@@ -2243,7 +2276,17 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
ripemd160 "^2.0.1"
sha.js "^2.4.0"
create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
create-hash@~1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==
dependencies:
cipher-base "^1.0.1"
inherits "^2.0.1"
ripemd160 "^2.0.0"
sha.js "^2.4.0"
create-hmac@^1.1.0, create-hmac@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
@@ -2414,6 +2457,15 @@ defer-to-connect@^1.0.1:
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -2579,6 +2631,15 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
dunder-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
dependencies:
call-bind-apply-helpers "^1.0.1"
es-errors "^1.3.0"
gopd "^1.2.0"
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
@@ -2648,9 +2709,9 @@ electron-to-chromium@^1.3.47:
integrity sha512-67V62Z4CFOiAtox+o+tosGfVk0QX4DJgH609tjT8QymbJZVAI/jWnAthnr8c5hnRNziIRwkc9EMQYejiVz3/9Q==
elliptic@^6.5.3, elliptic@^6.5.4:
version "6.6.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
version "6.6.1"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06"
integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
@@ -2762,6 +2823,23 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-define-property@^1.0.0, es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
dependencies:
es-errors "^1.3.0"
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@@ -3131,6 +3209,13 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
for-each@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47"
integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==
dependencies:
is-callable "^1.2.7"
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -3191,6 +3276,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@@ -3227,6 +3317,30 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.2.4, get-intrinsic@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
dependencies:
call-bind-apply-helpers "^1.0.2"
es-define-property "^1.0.1"
es-errors "^1.3.0"
es-object-atoms "^1.1.1"
function-bind "^1.1.2"
get-proto "^1.0.1"
gopd "^1.2.0"
has-symbols "^1.1.0"
hasown "^2.0.2"
math-intrinsics "^1.1.0"
get-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
dependencies:
dunder-proto "^1.0.1"
es-object-atoms "^1.0.0"
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@@ -3393,6 +3507,11 @@ globule@^1.0.0:
lodash "~4.17.10"
minimatch "~3.0.2"
gopd@^1.0.1, gopd@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
@@ -3442,11 +3561,30 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-symbols@^1.0.0, has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
has-symbols@^1.0.3, has-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
has-tostringtag@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
dependencies:
has-symbols "^1.0.3"
has-unicode@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -3495,6 +3633,13 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hash-base@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==
dependencies:
inherits "^2.0.1"
hash-base@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
@@ -3512,6 +3657,13 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hasown@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
he@1.2.x, he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -3856,6 +4008,11 @@ is-callable@^1.1.4, is-callable@^1.2.0:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
is-ci@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
@@ -4019,6 +4176,13 @@ is-symbol@^1.0.2:
dependencies:
has-symbols "^1.0.1"
is-typed-array@^1.1.14:
version "1.1.15"
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b"
integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==
dependencies:
which-typed-array "^1.1.16"
is-typedarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@@ -4044,6 +4208,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isarray@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -4436,6 +4605,11 @@ marionette.templatecache@^1.0.0:
dependencies:
backbone.marionette "^4.0.0, 4.0.0-beta.1"
math-intrinsics@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -5289,15 +5463,16 @@ path-type@^4.0.0:
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
pbkdf2@^3.0.3:
version "3.1.1"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==
version "3.1.3"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b"
integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==
dependencies:
create-hash "^1.1.2"
create-hmac "^1.1.4"
ripemd160 "^2.0.1"
safe-buffer "^5.0.1"
sha.js "^2.4.8"
create-hash "~1.1.3"
create-hmac "^1.1.7"
ripemd160 "=2.0.1"
safe-buffer "^5.2.1"
sha.js "^2.4.11"
to-buffer "^1.2.0"
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
@@ -5326,6 +5501,11 @@ posix-character-classes@^0.1.0:
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
possible-typed-array-names@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae"
integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==
postcss-modules-extract-imports@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
@@ -5886,6 +6066,14 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
ripemd160@=2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==
dependencies:
hash-base "^2.0.0"
inherits "^2.0.1"
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -6037,6 +6225,18 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
set-function-length@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -6052,13 +6252,14 @@ setimmediate@^1.0.4:
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
sha.js@^2.4.0, sha.js@^2.4.8:
version "2.4.11"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
version "2.4.12"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.12.tgz#eb8b568bf383dfd1867a32c3f2b74eb52bdbf23f"
integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
inherits "^2.0.4"
safe-buffer "^5.2.1"
to-buffer "^1.2.0"
shebang-command@^1.2.0:
version "1.2.0"
@@ -6592,6 +6793,15 @@ to-arraybuffer@^1.0.0:
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
to-buffer@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0"
integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==
dependencies:
isarray "^2.0.5"
safe-buffer "^5.2.1"
typed-array-buffer "^1.0.3"
to-fast-properties@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
@@ -6698,6 +6908,15 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
typed-array-buffer@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536"
integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==
dependencies:
call-bound "^1.0.3"
es-errors "^1.3.0"
is-typed-array "^1.1.14"
typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
@@ -7024,6 +7243,19 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which-typed-array@^1.1.16:
version "1.1.19"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956"
integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==
dependencies:
available-typed-arrays "^1.0.7"
call-bind "^1.0.8"
call-bound "^1.0.4"
for-each "^0.3.5"
get-proto "^1.0.1"
gopd "^1.2.0"
has-tostringtag "^1.0.2"
which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"

View File

@@ -10,9 +10,9 @@
"active24": {
"name": "Active24",
"package_name": "certbot-dns-active24",
"version": "~=1.5.1",
"version": "~=2.0.0",
"dependencies": "",
"credentials": "dns_active24_token=\"TOKEN\"",
"credentials": "dns_active24_api_key = <identifier>\ndns_active24_secret = <secret>",
"full_plugin_name": "dns-active24"
},
"aliyun": {
@@ -31,6 +31,14 @@
"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",
"full_plugin_name": "dns-azure"
},
"baidu": {
"name": "baidu",
"package_name": "certbot-dns-baidu",
"version": "~=0.1.1",
"dependencies": "",
"credentials": "dns_baidu_access_key = 12345678\ndns_baidu_secret_key = 1234567890abcdef1234567890abcdef",
"full_plugin_name": "dns-baidu"
},
"beget": {
"name":"Beget",
"package_name": "certbot-beget-plugin",
@@ -47,11 +55,19 @@
"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
"full_plugin_name": "dns-bunny"
},
"cdmon": {
"name": "cdmon",
"package_name": "certbot-dns-cdmon",
"version": "~=0.4.1",
"dependencies": "",
"credentials": "dns_cdmon_api_key=your-cdmon-api-token\ndns_cdmon_domain=your_domain_is_optional",
"full_plugin_name": "dns-cdmon"
},
"cloudflare": {
"name": "Cloudflare",
"package_name": "certbot-dns-cloudflare",
"version": "=={{certbot-version}}",
"dependencies": "cloudflare==2.19.* acme=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567",
"full_plugin_name": "dns-cloudflare"
},
@@ -90,11 +106,19 @@
"cpanel": {
"name": "cPanel",
"package_name": "certbot-dns-cpanel",
"version": "~=0.2.2",
"version": "~=0.4.0",
"dependencies": "",
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = user\ncpanel_password = hunter2",
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = your_username\ncpanel_password = your_password\ncpanel_token = your_api_token",
"full_plugin_name": "cpanel"
},
"ddnss": {
"name": "DDNSS",
"package_name": "certbot-dns-ddnss",
"version": "~=1.1.0",
"dependencies": "",
"credentials": "dns_ddnss_token = YOUR_DDNSS_API_TOKEN",
"full_plugin_name": "dns-ddnss"
},
"desec": {
"name": "deSEC",
"package_name": "certbot-dns-desec",
@@ -164,7 +188,7 @@
"package_name": "certbot-dns-domainoffensive",
"version": "~=2.0.0",
"dependencies": "",
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
"credentials": "dns_domainoffensive_api_token = YOUR_DO_DE_AUTH_TOKEN",
"full_plugin_name": "dns-domainoffensive"
},
"domeneshop": {
@@ -199,6 +223,14 @@
"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
"full_plugin_name": "dns-eurodns"
},
"firstdomains": {
"name": "First Domains",
"package_name": "certbot-dns-firstdomains",
"version": ">=1.0",
"dependencies": "",
"credentials": "dns_firstdomains_username = myremoteuser\ndns_firstdomains_password = verysecureremoteuserpassword",
"full_plugin_name": "dns-firstdomains"
},
"freedns": {
"name": "FreeDNS",
"package_name": "certbot-dns-freedns",
@@ -209,8 +241,8 @@
},
"gandi": {
"name": "Gandi Live DNS",
"package_name": "certbot_plugin_gandi",
"version": "~=1.5.0",
"package_name": "certbot-dns-gandi",
"version": "~=1.6.1",
"dependencies": "",
"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
"full_plugin_name": "dns-gandi"
@@ -383,6 +415,14 @@
"credentials": "dns_netcup_customer_id = 123456\ndns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
"full_plugin_name": "dns-netcup"
},
"nicru": {
"name": "nic.ru",
"package_name": "certbot-dns-nicru",
"version": "~=1.0.3",
"dependencies": "",
"credentials": "dns_nicru_client_id = application-id\ndns_nicru_client_secret = application-token\ndns_nicru_username = 0001110/NIC-D\ndns_nicru_password = password\ndns_nicru_scope = .+:.+/zones/example.com(/.+)?\ndns_nicru_service = DNS_SERVICE_NAME\ndns_nicru_zone = example.com",
"full_plugin_name": "dns-nicru"
},
"njalla": {
"name": "Njalla",
"package_name": "certbot-dns-njalla",
@@ -471,14 +511,30 @@
"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"full_plugin_name": "dns-route53"
},
"spaceship": {
"name": "Spaceship",
"package_name": "certbot-dns-spaceship",
"version": "~=1.0.4",
"dependencies": "",
"credentials": "[spaceship]\napi_key=your_api_key\napi_secret=your_api_secret",
"full_plugin_name": "dns-spaceship"
},
"strato": {
"name": "Strato",
"package_name": "certbot-dns-strato",
"version": "~=0.2.1",
"version": "~=0.2.2",
"dependencies": "",
"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
"full_plugin_name": "dns-strato"
},
"selectelv2": {
"name": "Selectel api v2",
"package_name": "certbot-dns-selectel-api-v2",
"version": "~=0.3.0",
"dependencies": "",
"credentials": "dns_selectel_api_v2_account_id = your_account_id\ndns_selectel_api_v2_project_name = your_project\ndns_selectel_api_v2_username = your_username\ndns_selectel_api_v2_password = your_password",
"full_plugin_name": "dns-selectel-api-v2"
},
"timeweb": {
"name": "Timeweb Cloud",
"package_name": "certbot-dns-timeweb",

View File

@@ -10,7 +10,7 @@ describe('Certificates endpoints', () => {
});
});
it('Validate custom certificate', function() {
it('Validate custom certificate', () => {
cy.task('backendApiPostFiles', {
token: token,
path: '/api/nginx/certificates/validate',
@@ -25,7 +25,7 @@ describe('Certificates endpoints', () => {
});
});
it('Custom certificate lifecycle', function() {
it('Custom certificate lifecycle', () => {
// Create custom cert
cy.task('backendApiPost', {
token: token,
@@ -73,7 +73,7 @@ describe('Certificates endpoints', () => {
});
});
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/certificates',
@@ -96,4 +96,28 @@ describe('Certificates endpoints', () => {
expect(data.error.message).to.contain('data/domain_names/0 must match pattern');
});
});
it('Request Certificate - LE Email Escaped', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/certificates',
data: {
domain_names: ['test.com"||echo hello-world||\\\\n test.com"'],
meta: {
dns_challenge: false,
letsencrypt_agree: true,
letsencrypt_email: "admin@example.com' --version;echo hello-world",
},
provider: 'letsencrypt',
},
returnOnError: true,
}).then((data) => {
cy.validateSwaggerSchema('post', 400, '/nginx/certificates', data);
expect(data).to.have.property('error');
expect(data.error).to.have.property('message');
expect(data.error).to.have.property('code');
expect(data.error.code).to.equal(400);
expect(data.error.message).to.contain('data/meta/letsencrypt_email must match pattern');
});
});
});

View File

@@ -0,0 +1,25 @@
/// <reference types="cypress" />
describe('Dashboard endpoints', () => {
let token;
before(() => {
cy.getToken().then((tok) => {
token = tok;
});
});
it('Should be able to get host counts', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/reports/hosts'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/reports/hosts', data);
expect(data).to.have.property('dead');
expect(data).to.have.property('proxy');
expect(data).to.have.property('redirection');
expect(data).to.have.property('stream');
});
});
});

View File

@@ -9,7 +9,7 @@ describe('Full Certificate Provisions', () => {
});
});
it('Should be able to create new http certificate', function() {
it('Should be able to create new http certificate', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/certificates',
@@ -32,7 +32,7 @@ describe('Full Certificate Provisions', () => {
});
});
it('Should be able to create new DNS certificate with Powerdns', function() {
it('Should be able to create new DNS certificate with Powerdns', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/certificates',

View File

@@ -1,7 +1,7 @@
/// <reference types="cypress" />
describe('Basic API checks', () => {
it('Should return a valid health payload', function () {
it('Should return a valid health payload', () => {
cy.task('backendApiGet', {
path: '/api/',
}).then((data) => {
@@ -10,9 +10,9 @@ describe('Basic API checks', () => {
});
});
it('Should return a valid schema payload', function () {
it('Should return a valid schema payload', () => {
cy.task('backendApiGet', {
path: '/api/schema?ts=' + Date.now(),
path: `/api/schema?ts=${Date.now()}`,
}).then((data) => {
expect(data.openapi).to.be.equal('3.1.0');
});

View File

@@ -1,12 +1,12 @@
/// <reference types="cypress" />
describe('LDAP with Authentik', () => {
let token;
let _token;
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
before(() => {
cy.getToken().then((tok) => {
token = tok;
_token = tok;
// cy.task('backendApiPut', {
// token: token,
@@ -45,7 +45,7 @@ describe('LDAP with Authentik', () => {
});
});
it.skip('Should log in with LDAP', function() {
it.skip('Should log in with LDAP', () => {
// cy.task('backendApiPost', {
// token: token,
// path: '/api/auth',

View File

@@ -1,12 +1,12 @@
/// <reference types="cypress" />
describe('OAuth with Authentik', () => {
let token;
let _token;
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
before(() => {
cy.getToken().then((tok) => {
token = tok;
_token = tok;
// cy.task('backendApiPut', {
// token: token,
@@ -47,7 +47,7 @@ describe('OAuth with Authentik', () => {
});
});
it.skip('Should log in with OAuth', function() {
it.skip('Should log in with OAuth', () => {
// cy.task('backendApiGet', {
// path: '/oauth/login?redirect_base=' + encodeURI(Cypress.config('baseUrl')),
// }).then((data) => {

View File

@@ -9,7 +9,7 @@ describe('Proxy Hosts endpoints', () => {
});
});
it('Should be able to create a http host', function() {
it('Should be able to create a http host', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/proxy-hosts',

View File

@@ -9,7 +9,7 @@ describe('Settings endpoints', () => {
});
});
it('Get all settings', function() {
it('Get all settings', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/settings',
@@ -19,7 +19,7 @@ describe('Settings endpoints', () => {
});
});
it('Get default-site setting', function() {
it('Get default-site setting', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/settings/default-site',
@@ -30,7 +30,7 @@ describe('Settings endpoints', () => {
});
});
it('Default Site congratulations', function() {
it('Default Site congratulations', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/settings/default-site',
@@ -46,7 +46,7 @@ describe('Settings endpoints', () => {
});
});
it('Default Site 404', function() {
it('Default Site 404', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/settings/default-site',
@@ -62,7 +62,7 @@ describe('Settings endpoints', () => {
});
});
it('Default Site 444', function() {
it('Default Site 444', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/settings/default-site',
@@ -78,7 +78,7 @@ describe('Settings endpoints', () => {
});
});
it('Default Site redirect', function() {
it('Default Site redirect', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/settings/default-site',
@@ -100,7 +100,7 @@ describe('Settings endpoints', () => {
});
});
it('Default Site html', function() {
it('Default Site html', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/settings/default-site',

View File

@@ -33,7 +33,7 @@ describe('Streams', () => {
cy.exec('rm -f /test/results/testssl.json');
});
it('Should be able to create TCP Stream', function() {
it('Should be able to create TCP Stream', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/streams',
@@ -65,7 +65,7 @@ describe('Streams', () => {
});
});
it('Should be able to create UDP Stream', function() {
it('Should be able to create UDP Stream', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/streams',
@@ -92,7 +92,7 @@ describe('Streams', () => {
});
});
it('Should be able to create TCP/UDP Stream', function() {
it('Should be able to create TCP/UDP Stream', () => {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/streams',
@@ -124,7 +124,7 @@ describe('Streams', () => {
});
});
it('Should be able to create SSL TCP Stream', function() {
it('Should be able to create SSL TCP Stream', () => {
let certID = 0;
// Create custom cert
@@ -184,7 +184,7 @@ describe('Streams', () => {
cy.exec('/testssl/testssl.sh --quiet --add-ca="$(/bin/mkcert -CAROOT)/rootCA.pem" --jsonfile=/test/results/testssl.json website1.example.com:1503', {
timeout: 120000, // 2 minutes
}).then((result) => {
cy.task('log', '[testssl.sh] ' + result.stdout);
cy.task('log', `[testssl.sh] ${result.stdout}`);
const allowedSeverities = ["INFO", "OK", "LOW", "MEDIUM"];
const ignoredIDs = [
@@ -210,4 +210,16 @@ describe('Streams', () => {
});
});
it('Should be able to List Streams', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/nginx/streams?expand=owner,certificate',
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/nginx/streams', data);
expect(data.length).to.be.greaterThan(0);
expect(data[0]).to.have.property('id');
expect(data[0]).to.have.property('enabled');
});
});
});

View File

@@ -9,7 +9,7 @@ describe('Users endpoints', () => {
});
});
it('Should be able to get yourself', function() {
it('Should be able to get yourself', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/users/me'
@@ -20,7 +20,7 @@ describe('Users endpoints', () => {
});
});
it('Should be able to get all users', function() {
it('Should be able to get all users', () => {
cy.task('backendApiGet', {
token: token,
path: '/api/users'
@@ -30,7 +30,7 @@ describe('Users endpoints', () => {
});
});
it('Should be able to update yourself', function() {
it('Should be able to update yourself', () => {
cy.task('backendApiPut', {
token: token,
path: '/api/users/me',

File diff suppressed because it is too large Load Diff