Compare commits

..

289 Commits

Author SHA1 Message Date
824c837a38 Merge pull request #2906 from NginxProxyManager/develop
Fix certbot plugins install when using PUID/PGID
2023-05-10 14:40:15 +10:00
2a06384a4a Merge branch 'master' into develop 2023-05-10 14:40:06 +10:00
05307aa253 Fix certbot plugins install when using PUID/PGID 2023-05-10 14:39:08 +10:00
3d2406ac3d Merge pull request #2905 from NginxProxyManager/develop
v2.10.3
2023-05-10 14:09:04 +10:00
0127dc7f03 Bump version 2023-05-10 11:32:22 +10:00
4349d42636 Merge pull request #2904 from NginxProxyManager/s6-verbose
Fixes for s6 timeout at startup
2023-05-10 11:31:17 +10:00
4b6f9d9419 Remove s6 service timeout 2023-05-10 09:57:24 +10:00
c3f019c911 Test ipv6 disabled in ci 2023-05-09 08:19:09 +10:00
ecf0290203 Update s6-overlay 2023-05-09 08:15:44 +10:00
4f41fe0c95 Update s6-overlay 2023-05-05 08:46:54 +10:00
c3735fdbbb Missed a file that was explicit verbose 2023-05-04 12:30:27 +10:00
c432c34fb3 Small refactor of user/groups and add checks during startup. Only use -x in bash scripts when DEBUG=true set in env vars 2023-05-04 10:03:06 +10:00
a1245bc161 Split up ownership to indentify point of failure 2023-05-04 08:27:38 +10:00
db4ab1d548 Verbose debugging of s6 scripts 2023-05-03 16:01:27 +10:00
86ddd9c83c Merge pull request #2784 from NginxProxyManager/develop
v2.10.2
2023-03-31 09:37:08 +10:00
67208e43cc Merge branch 'master' into develop 2023-03-31 08:27:00 +10:00
ddf80302c6 Bump version 2023-03-31 08:25:45 +10:00
5f2576946d Merge pull request #2783 from NginxProxyManager/uidgid
Make PUID and PGID optional
2023-03-31 08:25:07 +10:00
9fe07fa6c3 Update documentation 2023-03-30 15:37:59 +10:00
d9b9af543e Fix text replacement whoops 2023-03-30 15:03:57 +10:00
eb2e2e0478 Throw in a docker restart during testing phase 2023-03-30 14:44:15 +10:00
9225d5d442 Tweak test 2023-03-30 13:00:22 +10:00
308a7149ed Tweak test 2023-03-30 12:55:20 +10:00
8a4a7d0caf Allow 201 as success in test result 2023-03-30 12:51:26 +10:00
5d03ede100 Add test for creating a host 2023-03-30 12:44:28 +10:00
4a86bb42cc Different approach, always create npmuser
even if the user id is zero, and then we'll always use it
2023-03-30 11:19:16 +10:00
dad8561ea1 Use numbers for permissions in case npmuser doesn't exist 2023-03-30 10:20:20 +10:00
56a92e5c0e Run as root by default
Optionally run as another user/group only if
the env vars are specified. Should give flexibility
to those who need to run processes as root and open ports
without having to request additional priveleges
2023-03-30 09:04:37 +10:00
9d672f5813 Own this nginx folder too 2023-03-29 14:04:48 +10:00
d5ed70dbb6 Own this nginx folder too 2023-03-29 14:03:58 +10:00
c197e66d62 Merge pull request #2764 from NginxProxyManager/develop
v2.10.1
2023-03-29 08:54:30 +10:00
91cf3c8873 Tweaks to docker compose ci after updates 2023-03-29 08:24:28 +10:00
7f5e0414ac Bump version 2023-03-29 07:22:15 +10:00
d179887c15 Another fix for #2734, only chown parts of /etc/nginx 2023-03-28 10:39:26 +10:00
35abb4d7ae Execute permissions missing on script 2023-03-28 09:33:30 +10:00
61b290e220 Chown each folder on separately
Really not sure why this fixes #2734 however it does actually
help the ownership script succeed specifically on arm7/raspbian
2023-03-28 08:50:10 +10:00
e1bcef6e5c Merge pull request #2749 from NginxProxyManager/develop
v2.10.0
2023-03-27 12:17:07 +10:00
81f51f9e2d Merge branch 'master' into develop 2023-03-27 08:29:08 +10:00
661953db25 Bump version 2023-03-27 08:26:42 +10:00
065c2dac42 Merge pull request #2721 from NginxProxyManager/docker-user-group
Docker users and groups, refactor configuration
2023-03-27 08:19:57 +10:00
2926844cbe Merge pull request #2738 from NginxProxyManager/develop
v2.9.22
2023-03-24 08:48:45 +10:00
c1960f3793 Merge branch 'master' into develop 2023-03-24 08:19:54 +10:00
11a29a8b67 Bump version 2023-03-24 08:15:27 +10:00
c40e48e678 Fix docker restart because user already exists 2023-03-23 10:21:34 +10:00
124cb18e17 Fix renewing certs because of permission errors 2023-03-22 13:40:36 +10:00
5ac9dc0758 Attempt to set HOME for npmuser backend 2023-03-22 13:00:26 +10:00
9a799d51ce Optimize docker image a bit 2023-03-22 09:42:16 +10:00
77eb618758 Fix pip installs running as non-root user 2023-03-22 09:41:59 +10:00
79fedfcea4 Use consistent docker-compose file version in docs 2023-03-22 09:41:19 +10:00
8fdb8ac853 Update docs 2023-03-21 18:26:28 +10:00
4fdc80be01 Fix logical error with keys and mysql config 2023-03-21 17:59:27 +10:00
f8e6c8d018 Fix mistake with debug output 2023-03-21 17:49:39 +10:00
c3469de61b Linting fixes 2023-03-21 17:11:16 +10:00
ea61b15a40 don't zip log files anymore 2023-03-21 16:59:36 +10:00
60175e6d8c Updates for ci stack 2023-03-21 16:56:45 +10:00
2a07445005 Refactor configuration
- No longer use config npm package
- Prefer config from env vars, though still has support for config file
- No longer writes a config file for database config
- Writes keys to a new file in /data folder
- Removes a lot of cruft and improves config understanding
2023-03-21 16:53:39 +10:00
dad3e1da7c Adds support to run processes as a user/group, defined
with PUID and PGID environment variables

- Detects if image is run with a user in docker command and fails if so
- Adds s6 prepare scripts for adding a 'npmuser'
- Split up and refactor the s6 prepare scripts
- Runs nginx and backend node as 'npmuser'
- Changes ownership of files required at startup
2023-03-20 16:56:52 +10:00
82d9452001 Move some older s6-overlay over to new format, fixes #2705 2023-03-18 17:45:31 +10:00
095bc8f676 Merge pull request #2703 from NginxProxyManager/develop
v2.9.21
2023-03-18 16:10:27 +10:00
8c15340b83 Merge branch 'master' into develop 2023-03-18 14:20:42 +10:00
a13f7c3792 Merge pull request #2702 from dormancygrace/patch-3
update reg.ru template
2023-03-18 14:17:41 +10:00
6748985669 bump version 2023-03-18 14:15:37 +10:00
e2957f070b update reg.ru template
this small fix make it work again with certbot >=2.1.0
2023-03-18 03:37:23 +02:00
fccbde1371 fix linting 2023-03-17 14:23:12 +10:00
fec36834f7 - Updated objection, knex, liquidjs, signale and sqlite3 packages
- Changes for objection migration
- Moved common access template code to an include
- Fixed access rules configuration generation
2023-03-17 14:18:51 +10:00
00aeef75b6 Refactor nginx config functions, some don't need to report errors, save error'd config files as .err for debugging later 2023-03-17 11:34:27 +10:00
5b7682f13c Update s6-overlay and move processes to new format 2023-03-17 08:50:32 +10:00
b30fcb50c8 Args weren't being passed to htpasswd command, fixes #2692 2023-03-17 08:49:18 +10:00
100c56ad10 Merge pull request #2686 from NginxProxyManager/develop
v2.9.20
2023-03-16 09:42:28 +10:00
44bebf366a Bump version 2023-03-16 08:55:16 +10:00
6a28701242 Moved base images docker repo back to jc21, as docker is sunsetting free teams and this open source project isn't prepared to pay 300 shmackaroos for a nicer image url 2023-03-15 16:03:00 +10:00
09d1d3744c Merge pull request #2530 from jmerdich/jmerdich/fix-acl-edit-ssl 2023-03-08 21:08:52 +10:00
84e0b30f8d Merge pull request #2411 from plantysnake/fix-certbot-plugins
Bugfix: Fix certbot plugin installation issues
2023-03-08 20:40:15 +10:00
546ce8d4bc Merge pull request #2444 from BitsOfAByte/develop
Load events configuration from custom file
2023-03-08 16:32:46 +10:00
9b40bb288d Improvements to CI: comment on PR when syntax checking fails 2023-03-08 16:22:07 +10:00
c812b674b6 Update cypress 2023-03-08 09:20:15 +10:00
86e63197f6 Merge pull request #2507 from LEDfan/update-desec
Update certbot desec plugin fixes #2485
2023-03-08 08:43:44 +10:00
c371b2e953 Merge pull request #2527 from gromez/certbot-dns-online
Add Online (online.net) DNS provider
2023-03-08 08:39:46 +10:00
2142e25029 Merge pull request #2582 from TheBeeZee/ssl_reject_handshake
Use ssl_reject_handshake to reject requests to default https site
2023-03-08 08:30:02 +10:00
30076a0e66 Merge pull request #2635 from skarlcf/security/CVE-2023-23596
Mitigate CVE-2023-23596
2023-03-08 08:25:38 +10:00
42bd39163a Merge pull request #2638 from jlesage/case-insensitive-email-login
Make sure to lowercase email address entered by the user during login.
2023-03-08 08:25:09 +10:00
cc4891d9ec Merge pull request #2647 from ttocsr/google_domains_dns
Add Google Domains DNS provider
2023-03-08 08:20:07 +10:00
40c26839f5 Merge pull request #2655 from campingwoelfe/campingwoelfe-patch-1
Update certbot-dns-ionos plugin
2023-03-08 08:19:38 +10:00
2ff66ee238 Add style required by linter 2023-03-07 17:15:03 +01:00
9d60b4a756 Add Google Domains DNS provider
Add DNS provider for Google Domains DNS.

dns_google_domains_access_token = abcdef
dns_google_domains_zone = "example.com"
2023-03-07 07:01:50 -07:00
d2becc0681 Merge pull request #2469 from NginxProxyManager/dependabot/npm_and_yarn/frontend/qs-6.5.3
Bump qs from 6.5.2 to 6.5.3 in /frontend
2023-03-07 22:36:15 +10:00
579c32a724 Bump qs from 6.5.2 to 6.5.3 in /frontend
Bumps [qs](https://github.com/ljharb/qs) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.5.2...v6.5.3)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 11:41:12 +00:00
b08ef17894 Merge pull request #2453 from NginxProxyManager/dependabot/npm_and_yarn/frontend/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2 in /frontend
2023-03-07 21:40:54 +10:00
589ab8757e Merge pull request #1933 from NginxProxyManager/dependabot/npm_and_yarn/docs/postcss-8.2.13
Bump postcss from 8.2.10 to 8.2.13 in /docs
2023-03-07 21:40:39 +10:00
abdaac8584 Merge pull request #2470 from NginxProxyManager/dependabot/npm_and_yarn/backend/express-4.17.3
Bump express from 4.17.1 to 4.17.3 in /backend
2023-03-07 21:40:20 +10:00
d5c950a231 Merge pull request #2659 from NginxProxyManager/dependabot/npm_and_yarn/docs/qs-6.10.3
Bump qs from 6.9.7 to 6.10.3 in /docs
2023-03-07 21:40:09 +10:00
d9a1701927 Bump qs from 6.9.7 to 6.10.3 in /docs
Bumps [qs](https://github.com/ljharb/qs) from 6.9.7 to 6.10.3.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.9.7...v6.10.3)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 10:51:49 +00:00
6e500c35dc Merge pull request #1958 from NginxProxyManager/dependabot/npm_and_yarn/docs/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6 in /docs
2023-03-07 20:51:45 +10:00
a06e96061f Merge pull request #1947 from NginxProxyManager/dependabot/npm_and_yarn/docs/node-forge-1.3.0
Bump node-forge from 1.0.0 to 1.3.0 in /docs
2023-03-07 20:51:32 +10:00
f0513d34f9 Merge pull request #1851 from NginxProxyManager/dependabot/npm_and_yarn/test/ajv-6.12.6
Bump ajv from 6.10.2 to 6.12.6 in /test
2023-03-07 20:50:56 +10:00
09349efbbe Merge pull request #1934 from NginxProxyManager/dependabot/npm_and_yarn/docs/ansi-html-0.0.8
Bump ansi-html from 0.0.7 to 0.0.8 in /docs
2023-03-07 20:50:38 +10:00
06453e9668 Bump decode-uri-component from 0.2.0 to 0.2.2 in /frontend
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 10:50:16 +00:00
b1e904df84 Merge pull request #2031 from NginxProxyManager/dependabot/npm_and_yarn/docs/async-3.2.2
Bump async from 3.2.0 to 3.2.2 in /docs
2023-03-07 20:50:16 +10:00
5f435b6325 Merge pull request #2454 from NginxProxyManager/dependabot/npm_and_yarn/docs/decode-uri-component-0.2.1
Bump decode-uri-component from 0.2.0 to 0.2.1 in /docs
2023-03-07 20:49:48 +10:00
7b48488c29 Bump express from 4.17.1 to 4.17.3 in /backend
Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.17.3.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.17.3)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 10:49:22 +00:00
3f6ad0d807 Merge pull request #2471 from NginxProxyManager/dependabot/npm_and_yarn/docs/express-4.17.3
Bump express from 4.17.1 to 4.17.3 in /docs
2023-03-07 20:48:55 +10:00
edba369ae8 Merge pull request #2497 from NginxProxyManager/dependabot/npm_and_yarn/backend/jsonwebtoken-9.0.0
Bump jsonwebtoken from 8.5.1 to 9.0.0 in /backend
2023-03-07 20:48:45 +10:00
b77d916bdd Merge pull request #2498 from NginxProxyManager/dependabot/npm_and_yarn/backend/liquidjs-10.0.0
Bump liquidjs from 9.15.0 to 10.0.0 in /backend
2023-03-07 20:48:36 +10:00
2706454635 Bump minimist from 1.2.5 to 1.2.6 in /docs
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 09:23:06 +00:00
32a3bb1d6d Bump ajv from 6.10.2 to 6.12.6 in /test
Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.10.2 to 6.12.6.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.10.2...v6.12.6)

---
updated-dependencies:
- dependency-name: ajv
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 09:22:54 +00:00
95665ca378 Merge pull request #2513 from NginxProxyManager/dependabot/npm_and_yarn/docs/json5-2.2.2
Bump json5 from 2.1.3 to 2.2.2 in /docs
2023-03-07 19:22:26 +10:00
09d6cf7c48 Merge pull request #2648 from NginxProxyManager/dependabot/npm_and_yarn/backend/minimist-1.2.8
Bump minimist from 1.2.5 to 1.2.8 in /backend
2023-03-07 19:22:17 +10:00
2addc48a9b Merge pull request #2649 from NginxProxyManager/dependabot/npm_and_yarn/frontend/minimist-1.2.8
Bump minimist from 1.2.5 to 1.2.8 in /frontend
2023-03-07 19:22:07 +10:00
ebf07a7912 Bump json5 from 2.1.3 to 2.2.2 in /docs
Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:52:21 +00:00
abe6493244 Bump express from 4.17.1 to 4.17.3 in /docs
Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.17.3.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.17.3)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:40 +00:00
9f192ab275 Bump decode-uri-component from 0.2.0 to 0.2.1 in /docs
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.1)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:33 +00:00
52e013d289 Merge pull request #2410 from NginxProxyManager/dependabot/npm_and_yarn/docs/loader-utils-2.0.4
Bump loader-utils from 2.0.3 to 2.0.4 in /docs
2023-03-07 16:51:30 +10:00
331da3841e Bump minimist from 1.2.5 to 1.2.8 in /frontend
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.8.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.8)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:11 +00:00
e227f4177b Bump minimist from 1.2.5 to 1.2.8 in /backend
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.8.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.8)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:09 +00:00
88fa7cdfff Bump liquidjs from 9.15.0 to 10.0.0 in /backend
Bumps [liquidjs](https://github.com/harttle/liquidjs) from 9.15.0 to 10.0.0.
- [Release notes](https://github.com/harttle/liquidjs/releases)
- [Changelog](https://github.com/harttle/liquidjs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harttle/liquidjs/compare/v9.15.0...v10.0.0)

---
updated-dependencies:
- dependency-name: liquidjs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:08 +00:00
f3b3072711 Bump async from 3.2.0 to 3.2.2 in /docs
Bumps [async](https://github.com/caolan/async) from 3.2.0 to 3.2.2.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/master/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v3.2.0...v3.2.2)

---
updated-dependencies:
- dependency-name: async
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:51:02 +00:00
cf6cc7dcc5 Bump jsonwebtoken from 8.5.1 to 9.0.0 in /backend
Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 8.5.1 to 9.0.0.
- [Release notes](https://github.com/auth0/node-jsonwebtoken/releases)
- [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v8.5.1...v9.0.0)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 06:50:55 +00:00
448c8a2dd5 Merge pull request #2523 from NginxProxyManager/dependabot/npm_and_yarn/backend/json5-2.2.3
Bump json5 from 2.1.3 to 2.2.3 in /backend
2023-03-07 16:50:37 +10:00
634cfe13f1 Merge pull request #2534 from NginxProxyManager/dependabot/npm_and_yarn/backend/knex-2.4.0
Bump knex from 0.20.15 to 2.4.0 in /backend
2023-03-07 16:50:30 +10:00
7597515c20 Merge pull request #2564 from NginxProxyManager/dependabot/npm_and_yarn/frontend/ua-parser-js-0.7.33
Bump ua-parser-js from 0.7.28 to 0.7.33 in /frontend
2023-03-07 16:50:18 +10:00
93f57aece5 Merge pull request #2583 from NginxProxyManager/dependabot/npm_and_yarn/docs/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1 in /docs
2023-03-07 16:49:58 +10:00
ef6da1bbe1 Merge pull request #2584 from NginxProxyManager/dependabot/npm_and_yarn/backend/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1 in /backend
2023-03-07 16:49:50 +10:00
4ad9e68886 Merge pull request #2585 from NginxProxyManager/dependabot/npm_and_yarn/frontend/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1 in /frontend
2023-03-07 16:49:44 +10:00
9b35e7c188 Merge pull request #2644 from NginxProxyManager/dependabot/npm_and_yarn/docs/dns-packet-5.4.0
Bump dns-packet from 5.2.2 to 5.4.0 in /docs
2023-03-07 16:49:28 +10:00
2aa6e55d6b Update certbot-dns-ionos plugin 2023-03-06 15:31:39 +01:00
1ac28410ff Bump dns-packet from 5.2.2 to 5.4.0 in /docs
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 5.2.2 to 5.4.0.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v5.2.2...5.4.0)

---
updated-dependencies:
- dependency-name: dns-packet
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-02 21:13:16 +00:00
b0fd976b97 Make sure to lowercase email address entered by the user during login. 2023-02-26 22:24:58 -05:00
7fe7e94fbd Mitigate CVE-2023-23596 by changing child_process.exec to child_process.execFile 2023-02-26 20:10:25 +01:00
8864960eb4 Bump http-cache-semantics from 4.1.0 to 4.1.1 in /frontend
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-03 12:12:27 +00:00
23326895b2 Bump http-cache-semantics from 4.1.0 to 4.1.1 in /backend
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-03 12:12:01 +00:00
d2f707b76d Bump http-cache-semantics from 4.1.0 to 4.1.1 in /docs
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-03 05:19:25 +00:00
a7f0c3b730 Use ssl_reject_handshake to reject requests to default https site
Instead of creating a dummy certificate, we can return an SSL protocol error, which will generate a descriptive error message in the browser.
2023-02-02 19:19:37 -08:00
a9e84f1750 Bump ua-parser-js from 0.7.28 to 0.7.33 in /frontend
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.28 to 0.7.33.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.28...0.7.33)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-27 04:36:34 +00:00
7ca3a9e7a6 Bump knex from 0.20.15 to 2.4.0 in /backend
Bumps [knex](https://github.com/knex/knex) from 0.20.15 to 2.4.0.
- [Release notes](https://github.com/knex/knex/releases)
- [Changelog](https://github.com/knex/knex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/knex/knex/compare/0.20.15...2.4.0)

---
updated-dependencies:
- dependency-name: knex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-11 02:35:51 +00:00
c80d099193 ACL changes should not blow away cert config
When editing an access list, all affected sites get their config updated without certificates, functionally breaking https on those sites until they get a manual config change that rewrites the config properly. Properly fetch the certificate from the DB before `bulkGenerateConfigs` so it gets updated right.

I am not certain whether there are similar bugs in other places that use `bulkGenerateConfigs`.

Should fix #2254
2023-01-10 01:59:04 -05:00
35aba13122 Add Online (online.net) DNS provider 2023-01-09 09:19:08 +01:00
b69e493c54 Bump json5 from 2.1.3 to 2.2.3 in /backend
Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-06 02:33:27 +00:00
99d73a2da8 Update certbot desec plugin fixes #2485 2022-12-28 11:26:33 +01:00
3c23aa935e Load events configuration from custom file 2022-12-02 21:32:04 +00:00
8dee139810 Fix linter issues 2022-11-21 01:46:42 +03:00
6349cb6094 Fix cerbot plugin installation issues 2022-11-18 15:06:19 +03:00
452838b04a Bump loader-utils from 2.0.3 to 2.0.4 in /docs
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 00:00:12 +00:00
fd30cfe98b Fix linting 2022-11-15 07:54:48 +10:00
6f281fef42 Workaround for cloudflare plugin install (#2381) 2022-11-15 07:48:57 +10:00
5920b0cf5e Merge pull request #2380 from NginxProxyManager/develop
v2.9.19
2022-11-08 14:26:06 +10:00
41bbfcf165 Merge branch 'master' into develop 2022-11-08 13:32:32 +10:00
80a93e17fa Bump version 2022-11-08 13:31:27 +10:00
4a1eebc54b Linked to contributors instead of managing for every release 2022-11-08 13:30:41 +10:00
264ba71462 Merge pull request #2230 from wnhrt/add-autofocus-to-login
Added autofocus to email input on login screen
2022-11-08 13:12:45 +10:00
e229fa89f8 Merge pull request #2222 from mantoufan/add-webp-to-assets.conf-for-cache-assets
Add webp format to assets.conf for Cache Assets
2022-11-08 13:12:13 +10:00
d3b72ae07d Fix tabs after web-resolved change 2022-11-08 11:53:13 +10:00
b62b6b5112 Merge pull request #2373 from lakkeri/develop
Possible multiple X-Forwarded-For headers
2022-11-08 11:48:05 +10:00
c44f8c6155 Merge pull request #2312 from knoxell/knoxell#add-namecheap
Added Namecheap certbot dns plugin
2022-11-08 11:45:41 +10:00
0dfa3d9ca3 Merge pull request #2379 from NginxProxyManager/dependabot/npm_and_yarn/docs/loader-utils-2.0.3
Bump loader-utils from 2.0.0 to 2.0.3 in /docs
2022-11-08 11:44:55 +10:00
8c7c84906b Merge pull request #2327 from DFS-90/develop
added DomainOffensive (do.de) certbot dns plugin (update certbot-dns-plugins.js)
2022-11-08 11:44:30 +10:00
662143cf21 Merge branch 'develop' into develop 2022-11-08 11:44:22 +10:00
c60fc7926e Merge pull request #2298 from ATCUSA/develop
Update for docker-compose-plugin command
2022-11-08 11:41:57 +10:00
cfbdc6c340 Merge pull request #2294 from oleban/add-domeneshop-plugin
Added Domeneshop certbot dns plugin
2022-11-08 11:41:34 +10:00
2f6d8257ec Merge pull request #2259 from cuishuang/develop
all: fix some typos
2022-11-08 11:40:42 +10:00
b9a6b5d4f5 Merge pull request #2355 from rovast/patch-1
Update README.md
2022-11-08 11:01:10 +10:00
32f77dbcee Bump loader-utils from 2.0.0 to 2.0.3 in /docs
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.0 to 2.0.3.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.3/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v2.0.0...v2.0.3)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-08 00:53:09 +00:00
052cb8f12d Possible multiple X-Forwarded-For headers
NMP behind another reverse proxy can multiply X-Forwarded-For headers. $proxy_add_x_forwarded_for equals to $remote_addr if this header not present in client request 
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#var_proxy_add_x_forwarded_for
2022-11-05 16:24:12 +03:00
03b544023b Update README.md
Fix docker compose up warning message 

```
WARN[0000] network default: network.external.name is deprecated in favor of network.name
```
2022-11-02 10:26:01 +08:00
5070499cfd Merge pull request #2335 from Czocher/fix-disable-ipv6
Fix DISABLE_IPV6 flag handling
2022-10-21 08:57:08 +10:00
e77b13d36e Fix DISABLE_IPV6 flag handling
The DISABLE_IPV6 flag did not turn off ipv6 DNS requests performed by
nginx. This commit changes it and makes nginx-proxy-manager more
compatible with podman.
2022-10-20 07:55:08 +02:00
4bb237d7c2 Update certbot-dns-plugins.js
added DomainOffensive (do.de) certbot dns plugin
2022-10-16 00:24:18 +02:00
aa5a7faa94 Added Namecheap 2022-10-08 21:53:34 +02:00
837f4dcbd4 Update for docker-compose-plugin command 2022-10-02 05:05:46 +00:00
d73a246b66 Added Domeneshop certbot dns plugin 2022-09-28 11:48:31 +02:00
f85e82973d all: fix some typos
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-09-10 21:08:16 +08:00
84afec567c Added autofocus to email input on login screen 2022-08-28 19:54:50 +02:00
e1525e5d56 Add webp format to assets.conf for Cache Assets 2022-08-26 03:47:06 +08:00
d2688cf08c CI - don't remove all other images, causing errors in new docker-compose 2022-08-24 07:15:28 +10:00
7372319568 Merge pull request #2051 from Nobody84/develop
update certbot-dns-duckdns to 0.9
2022-08-23 20:59:16 +10:00
60ffec5c64 Merge pull request #2072 from NginxProxyManager/dependabot/npm_and_yarn/docs/eventsource-2.0.2
Bump eventsource from 1.0.7 to 2.0.2 in /docs
2022-08-23 20:57:21 +10:00
23c88f6955 Merge pull request #2090 from swazynski/patch-1
Add trailing slash to example
2022-08-23 20:57:04 +10:00
dd14207b63 Merge pull request #2110 from cfoellmann/footer-blank
open footer link "Fork me" in new tab/windows (_blank)
2022-08-23 20:44:56 +10:00
103adfbb57 Merge pull request #2125 from NginxProxyManager/dependabot/npm_and_yarn/test/async-3.2.4
Bump async from 3.2.0 to 3.2.4 in /test
2022-08-23 20:44:32 +10:00
b673ebe2ca Merge pull request #2126 from NginxProxyManager/dependabot/npm_and_yarn/backend/async-3.2.4
Bump async from 3.2.1 to 3.2.4 in /backend
2022-08-23 20:44:21 +10:00
0e0c3df0cd Merge pull request #2142 from NginxProxyManager/dependabot/npm_and_yarn/frontend/moment-2.29.4
Bump moment from 2.27.0 to 2.29.4 in /frontend
2022-08-23 20:44:08 +10:00
8dbd482e08 Merge pull request #2143 from NginxProxyManager/dependabot/npm_and_yarn/test/moment-2.29.4
Bump moment from 2.27.0 to 2.29.4 in /test
2022-08-23 20:43:44 +10:00
ab5f7c0f26 Merge pull request #2144 from NginxProxyManager/dependabot/npm_and_yarn/backend/moment-2.29.4
Bump moment from 2.27.0 to 2.29.4 in /backend
2022-08-23 20:43:35 +10:00
191f493eb9 Merge pull request #2162 from NginxProxyManager/dependabot/npm_and_yarn/docs/terser-5.14.2
Bump terser from 5.0.0 to 5.14.2 in /docs
2022-08-23 20:43:24 +10:00
d1f4640a9c Merge pull request #2164 from NginxProxyManager/dependabot/npm_and_yarn/frontend/terser-4.8.1
Bump terser from 4.8.0 to 4.8.1 in /frontend
2022-08-23 20:43:15 +10:00
3d97f4578d Merge pull request #2206 from phulstaert/patch-1
fix typo
2022-08-23 20:42:59 +10:00
fb0ef08fd8 fix typo 2022-08-18 09:25:45 +02:00
0de78205b5 Bump terser from 4.8.0 to 4.8.1 in /frontend
Bumps [terser](https://github.com/terser/terser) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-20 21:35:47 +00:00
e0821bd927 Bump terser from 5.0.0 to 5.14.2 in /docs
Bumps [terser](https://github.com/terser/terser) from 5.0.0 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-20 01:39:09 +00:00
e5966b54a8 Bump moment from 2.27.0 to 2.29.4 in /backend
Bumps [moment](https://github.com/moment/moment) from 2.27.0 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.27.0...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-07 16:43:24 +00:00
d2f6b09901 Bump moment from 2.27.0 to 2.29.4 in /test
Bumps [moment](https://github.com/moment/moment) from 2.27.0 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.27.0...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-07 16:43:16 +00:00
5c8aa8517b Bump moment from 2.27.0 to 2.29.4 in /frontend
Bumps [moment](https://github.com/moment/moment) from 2.27.0 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.27.0...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-07 16:43:13 +00:00
1e5916db28 Bump async from 3.2.1 to 3.2.4 in /backend
Bumps [async](https://github.com/caolan/async) from 3.2.1 to 3.2.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/master/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v3.2.1...v3.2.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 17:38:17 +00:00
a3ae6956e2 Bump async from 3.2.0 to 3.2.4 in /test
Bumps [async](https://github.com/caolan/async) from 3.2.0 to 3.2.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/master/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v3.2.0...v3.2.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 16:50:18 +00:00
518b84b38b open footer link "Fork me" in new tab/windows (_blank) 2022-06-15 12:20:54 +02:00
932dc4bf02 Add trailing slash to example 2022-06-03 15:20:26 +02:00
bdc3a555b6 Bump eventsource from 1.0.7 to 2.0.2 in /docs
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.0.7 to 2.0.2.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.0.7...v2.0.2)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 06:36:19 +00:00
d4dcb61ee6 update certbot-dns-duckdns to 0.9 2022-05-14 00:30:18 +02:00
cce73beb2d Merge pull request #1967 from NginxProxyManager/develop
v2.9.18
2022-03-31 15:40:49 +10:00
4db34f5894 Bump version, to trigger rebuild with updated base images 2022-03-31 14:43:41 +10:00
063ac4619f Merge pull request #1966 from NginxProxyManager/develop
v2.9.17
2022-03-31 11:32:05 +10:00
d1a338107b Merge branch 'master' into develop 2022-03-31 10:21:19 +10:00
0d0b7e117f Bump version 2022-03-31 10:20:27 +10:00
3538f9719f Merge pull request #1951 from NginxProxyManager/test-html-encode
Fix #1950 attempt to encode hdomain values before render
2022-03-25 09:03:30 +10:00
feaafdc559 Fix #1950 attempt to encode hdomain values before render 2022-03-25 08:31:28 +10:00
edf369a3d4 Bump node-forge from 1.0.0 to 1.3.0 in /docs
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.0.0 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.0.0...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-23 17:18:07 +00:00
eb148eb8f0 Merge pull request #1904 from NginxProxyManager/dependabot/npm_and_yarn/docs/url-parse-1.5.9
Bump url-parse from 1.5.2 to 1.5.9 in /docs
2022-03-15 07:38:11 +10:00
4251157ffa Bump ansi-html from 0.0.7 to 0.0.8 in /docs
Bumps [ansi-html](https://github.com/Tjatse/ansi-html) from 0.0.7 to 0.0.8.
- [Release notes](https://github.com/Tjatse/ansi-html/releases)
- [Commits](https://github.com/Tjatse/ansi-html/commits)

---
updated-dependencies:
- dependency-name: ansi-html
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 21:21:19 +00:00
9866eec21c Bump postcss from 8.2.10 to 8.2.13 in /docs
Bumps [postcss](https://github.com/postcss/postcss) from 8.2.10 to 8.2.13.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.2.10...8.2.13)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-14 21:20:37 +00:00
e879d41ee4 Merge pull request #1892 from NginxProxyManager/dependabot/npm_and_yarn/docs/prismjs-1.27.0
Bump prismjs from 1.25.0 to 1.27.0 in /docs
2022-03-15 07:18:23 +10:00
bb26f5b2c7 Merge pull request #1863 from omercnet/patch-1
Update resolvers.conf to break dns cache
2022-03-15 07:17:24 +10:00
8e61d3eadf Bump url-parse from 1.5.2 to 1.5.9 in /docs
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.2 to 1.5.9.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.2...1.5.9)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-02 18:35:56 +00:00
749ab36b1a Bump prismjs from 1.25.0 to 1.27.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.25.0 to 1.27.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.25.0...v1.27.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-26 01:52:17 +00:00
c68874743d Merge pull request #1864 from NginxProxyManager/develop
v2.9.16
2022-02-19 21:47:15 +10:00
1a76f4ebfc Merge branch 'master' into develop 2022-02-17 13:20:44 +10:00
59238d1dc1 Bump version 2022-02-17 13:18:06 +10:00
661f3d6899 Update repo path in docs 2022-02-17 13:15:15 +10:00
14b889a85f Merge pull request #1822 from ivankristianto/add-search-feature-redirection
Add Search Feature To Backend Administration
2022-02-17 13:14:35 +10:00
ac25171420 Update resolvers.conf to break dns cache
By default, nginx caches answers using the TTL value of a response.
In a dynamic environment containers can get recreated with new IPs,
reducing the validity of the cache allows refreshing these IPs

https://nginx.org/en/docs/http/ngx_http_core_module.html#resolver
2022-02-16 09:31:56 +02:00
7281ed5968 Merge pull request #1830 from lug-gh/lug-gh-patch-1
Update current year for footer
2022-02-13 20:20:32 +10:00
dc541b2c72 Merge pull request #1850 from NginxProxyManager/dependabot/npm_and_yarn/docs/follow-redirects-1.14.8
Bump follow-redirects from 1.14.7 to 1.14.8 in /docs
2022-02-13 20:18:47 +10:00
9a854fd8fe Bump follow-redirects from 1.14.7 to 1.14.8 in /docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-13 08:02:46 +00:00
8eb44c404d Add translation for search text 2022-02-12 13:28:16 +07:00
61b25e1213 Add search feature to Audit Logs 2022-02-12 13:10:23 +07:00
d3a5a3d0d6 Add search feature to Users 2022-02-12 12:52:22 +07:00
366fcf0bed Fix nginx/certificates search query 2022-02-12 12:46:06 +07:00
29c0fcbad6 Add search feature to SSL Certificates 2022-02-12 12:45:29 +07:00
de84d5d463 Add search feature to Access Lists 2022-02-12 12:17:45 +07:00
078114ee67 Fix search query for proxy 2022-02-12 11:52:47 +07:00
49f350fb00 Add search feature to 404 hosts 2022-02-12 11:48:47 +07:00
e141b5ff20 Add search feature to stream 2022-02-12 11:36:59 +07:00
181f163cb5 Move render showEmpty into function 2022-02-12 10:40:37 +07:00
30a9d3ae8d Add search feature to proxy host 2022-02-12 10:38:15 +07:00
83e09ad5a7 Update current year for footer
Update current year for footer
2022-02-05 20:59:21 +01:00
8e5255a275 Merge pull request #1767 from NginxProxyManager/dependabot/npm_and_yarn/docs/json-schema-0.4.0
Bump json-schema from 0.2.5 to 0.4.0 in /docs
2022-01-31 09:03:11 +10:00
e4f06368bb Merge pull request #1768 from NginxProxyManager/dependabot/npm_and_yarn/docs/is-svg-4.3.0
Bump is-svg from 4.2.2 to 4.3.0 in /docs
2022-01-31 09:02:59 +10:00
0edd87324c Merge pull request #1773 from NginxProxyManager/certbot-dns-transip-update
Update certbot-dns-transip plugin
2022-01-31 09:02:48 +10:00
96e034aa75 Add search function for redirection 2022-01-30 22:47:42 +07:00
821432263a Update certbot-dns-transip plugin 2022-01-19 07:36:49 +10:00
5edb16f36e Fix failing pip installs, downgrade setuptools 2022-01-17 21:46:26 +10:00
a233bc0045 Merge pull request #1766 from NginxProxyManager/develop
v2.9.15
2022-01-17 12:08:45 +10:00
eed40d095e Bump is-svg from 4.2.2 to 4.3.0 in /docs
Bumps [is-svg](https://github.com/sindresorhus/is-svg) from 4.2.2 to 4.3.0.
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.2.2...v4.3.0)

---
updated-dependencies:
- dependency-name: is-svg
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-17 01:22:20 +00:00
0d0e5295f4 Bump json-schema from 0.2.5 to 0.4.0 in /docs
Bumps [json-schema](https://github.com/kriszyp/json-schema) from 0.2.5 to 0.4.0.
- [Release notes](https://github.com/kriszyp/json-schema/releases)
- [Commits](https://github.com/kriszyp/json-schema/compare/v0.2.5...v0.4.0)

---
updated-dependencies:
- dependency-name: json-schema
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-17 01:21:03 +00:00
51ac4bc688 Merge branch 'master' into develop 2022-01-17 10:53:03 +10:00
4f97592965 Bump version 2022-01-17 10:48:57 +10:00
be5a763d39 Merge pull request #1758 from NginxProxyManager/dependabot/npm_and_yarn/docs/markdown-it-12.3.2
Bump markdown-it from 11.0.0 to 12.3.2 in /docs
2022-01-17 10:46:00 +10:00
c435ce0224 Merge pull request #1760 from NginxProxyManager/dependabot/npm_and_yarn/docs/follow-redirects-1.14.7
Bump follow-redirects from 1.12.1 to 1.14.7 in /docs
2022-01-17 10:45:49 +10:00
67d8ede247 Merge pull request #1763 from NginxProxyManager/dependabot/npm_and_yarn/docs/node-forge-1.0.0
Bump node-forge from 0.10.0 to 1.0.0 in /docs
2022-01-17 10:45:28 +10:00
5e98ce32b7 Merge pull request #1764 from troykelly/troykelly#add-constellix
Added Constellix as DNS auth method
2022-01-17 10:45:02 +10:00
a2c01655f0 Added Constellix 2022-01-15 09:48:04 +00:00
3a71281937 Bump node-forge from 0.10.0 to 1.0.0 in /docs
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 0.10.0 to 1.0.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/0.10.0...v1.0.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-14 21:13:50 +00:00
f235ec8b5a Bump follow-redirects from 1.12.1 to 1.14.7 in /docs
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.12.1 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.12.1...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-14 05:54:23 +00:00
fa7df05b92 Bump markdown-it from 11.0.0 to 12.3.2 in /docs
Bumps [markdown-it](https://github.com/markdown-it/markdown-it) from 11.0.0 to 12.3.2.
- [Release notes](https://github.com/markdown-it/markdown-it/releases)
- [Changelog](https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/markdown-it/compare/11.0.0...12.3.2)

---
updated-dependencies:
- dependency-name: markdown-it
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-12 23:02:03 +00:00
1f3ac7a9ec And update the docker org too 2022-01-11 11:52:25 +10:00
5bd002a568 Forgot to update this docker base image 2022-01-11 11:28:01 +10:00
5fb0cc5fab No need to symlink python, done in base image now 2022-01-11 11:17:19 +10:00
818b9595aa Use renamed nginx-full docker images 2022-01-11 08:57:24 +10:00
c78f641e85 Revert #1614
as it breaks some existing services
2022-01-11 08:54:40 +10:00
081380c8d5 Merge pull request #1716 from jc21/develop
v2.9.14
2022-01-02 22:31:12 +10:00
7e451bce0b Merge pull request #1688 from jlesage/resolvers-fix
Fixed generation of resolvers.conf.
2022-01-02 22:05:32 +10:00
a082ec0604 Merge pull request #1600 from jc21/updates-dnspod-dns-challenge
Fixes dnspod credentials template
2022-01-02 22:05:15 +10:00
973a10a9d1 Bump version 2022-01-02 21:33:16 +10:00
1ec95096d5 Ensure backend build is pulling node:latest first 2022-01-02 21:24:16 +10:00
e81cc45405 Updates dnspod challenge credentials 2022-01-02 11:49:18 +01:00
b9ef11e8bf Merge pull request #1614 from the1ts/feature/proxy-header-additions
Feature: Add two new headers to proxy.conf
2022-01-02 16:11:50 +10:00
0d8dd03c3d Merge pull request #1687 from jlesage/fallback-access-fix
Fixed the access log path to match the HTTP one.
2022-01-02 16:10:25 +10:00
74d610d9ad Merge pull request #1697 from jc21/official-dns-version-requirement
Sets certbot official dns plugin version requirement to match certbot version
2022-01-02 16:09:27 +10:00
9146ca6c63 Merge pull request #1698 from jc21/adds-faq-acl-with-login
Adds FAQ entry for acl plus login
2022-01-02 15:39:04 +10:00
d7e0ae0fa0 Merge pull request #1701 from jc21/escape-credential-backslashes
Correctly escape backslashes in dns plugin credentials
2022-01-02 15:29:31 +10:00
29ee48530c Merge pull request #1703 from luoweihua7/develop
fetch cloudflare ipv4/ipv6 fail #1405
2022-01-02 15:28:58 +10:00
abe53a4bdd Merge pull request #1704 from jc21/letsencrypt-cert-request-delay
Adds delay after reloading nginx before requesting ssl certificate using http challenge
2022-01-02 15:27:39 +10:00
2d23bedf12 Merge pull request #1713 from jc21/adds-tencentcloud-dns-challenge
Adds tencent cloud as dns challenge provider
2022-01-02 15:26:25 +10:00
4e17fb476b Adds tencent cloud as dns challenge provider 2022-01-01 17:57:17 +01:00
c803ec7e26 Adds delay after reloading nginx before requesting ssl certificate using http challenge 2021-12-30 13:21:21 +01:00
7e67f33766 fetch cloudflare ipv4/ipv6 fail #1405 2021-12-30 11:50:21 +08:00
9dd5644183 Correctly escape backslashes in dns plugin credentials 2021-12-29 16:30:49 +01:00
5a8028a72d Adds FAQ entry for acl plus login 2021-12-29 11:35:59 +01:00
747de511d4 Sets certbot official dns plugin version requirement to match certbot version 2021-12-29 09:54:59 +01:00
7800938fd2 Update default.conf 2021-12-28 18:58:22 +00:00
ab80fe13e9 Fixes custom certificate upload modal 2021-12-28 18:58:22 +00:00
5d106c4064 Bump version 2021-12-28 18:58:22 +00:00
2ac1026e4b Hack for python binary in newer node images 2021-12-28 18:58:22 +00:00
b78c7e1c53 Fixes dnspod credentials template 2021-12-27 21:13:27 +01:00
849bdcda7b Fixed generation of resolvers.conf.
This fixes scenarios where `resolv.conf` generated by dhcpcd has a nameserver with `%interface` appended to its IPv6 address.
For example, a line like this must be properly handled:
nameserver fe80::7747:4aff:fe9a:8cb1%br0
2021-12-26 21:49:55 -05:00
5aae8cd0e3 Fixed the access log path to match the HTTP one. This also fixes its handling by logrotate. 2021-12-26 20:56:42 -05:00
adc5a2020a Merge pull request #1666 from TobiasKneidl/patch-1
Update default.conf to follow the default site setting also for ipv6
2021-12-27 11:03:14 +10:00
40b1521f72 Merge pull request #1677 from jc21/fixes-custom-certificate-modal
Fixes custom certificate upload modal
2021-12-27 11:02:16 +10:00
ac23c66659 Fixes custom certificate upload modal 2021-12-23 12:23:30 +01:00
bb422d4454 Update default.conf 2021-12-22 00:24:05 +01:00
3dfe23836c Add two new headers to proxy.conf
Fixes #1609. Adding both  X-Forwarded-Host  and X-Forwarded-Port, this is vital for some services behind a proxy (used to allow creation of absolute links in html). I've had to include at least the Host version in the past for jenkins and nexus.
Been running locally for 24 hours, does not appear to break any of my 15+ services currently running behind NPM would allow people to host those services without the need for advanced configuration
2021-11-29 13:48:39 +00:00
132 changed files with 4196 additions and 4014 deletions

View File

@ -1 +1 @@
2.9.13 2.10.3

113
Jenkinsfile vendored
View File

@ -1,3 +1,9 @@
import groovy.transform.Field
@Field
def shOutput = ""
def buildxPushTags = ""
pipeline { pipeline {
agent { agent {
label 'docker-multiarch' label 'docker-multiarch'
@ -8,14 +14,16 @@ pipeline {
ansiColor('xterm') ansiColor('xterm')
} }
environment { environment {
IMAGE = "nginx-proxy-manager" IMAGE = 'nginx-proxy-manager'
BUILD_VERSION = getVersion() BUILD_VERSION = getVersion()
MAJOR_VERSION = "2" MAJOR_VERSION = '2'
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}" BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}"
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}" COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_FILE = 'docker/docker-compose.ci.yml' COMPOSE_FILE = 'docker/docker-compose.ci.yml'
COMPOSE_INTERACTIVE_NO_CLI = 1 COMPOSE_INTERACTIVE_NO_CLI = 1
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}" BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
DOCS_BUCKET = 'jc21-npm-site'
DOCS_CDN = 'EN1G6DEWZUTDT'
} }
stages { stages {
stage('Environment') { stage('Environment') {
@ -26,7 +34,7 @@ pipeline {
} }
steps { steps {
script { script {
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest" buildxPushTags = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest"
} }
} }
} }
@ -39,7 +47,7 @@ pipeline {
steps { steps {
script { script {
// Defaults to the Branch name, which is applies to all branches AND pr's // Defaults to the Branch name, which is applies to all branches AND pr's
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}" buildxPushTags = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
} }
} }
} }
@ -54,54 +62,52 @@ pipeline {
} }
} }
} }
stage('Frontend') { stage('Build and Test') {
steps { steps {
sh './scripts/frontend-build' script {
// Frontend and Backend
def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
set -e
./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
''')
shOutput = readFile "${env.WORKSPACE}/tmp-sh-build"
if (shStatusCode != 0) {
error "${shOutput}"
}
}
} }
} post {
stage('Backend') { always {
steps { sh 'rm -f ${WORKSPACE}/tmp-sh-build'
echo 'Checking Syntax ...' }
// See: https://github.com/yarnpkg/yarn/issues/3254 failure {
sh '''docker run --rm \\ npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
-v "$(pwd)/backend:/app" \\ }
-v "$(pwd)/global:/app/global" \\
-w /app \\
node:latest \\
sh -c "ln -s /usr/bin/python3 /usr/bin/python && yarn install && yarn eslint . && rm -rf node_modules"
'''
echo 'Docker Build ...'
sh '''docker build --pull --no-cache --squash --compress \\
-t "${IMAGE}:ci-${BUILD_NUMBER}" \\
-f docker/Dockerfile \\
--build-arg TARGETPLATFORM=linux/amd64 \\
--build-arg BUILDPLATFORM=linux/amd64 \\
--build-arg BUILD_VERSION="${BUILD_VERSION}" \\
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
.
'''
} }
} }
stage('Integration Tests Sqlite') { stage('Integration Tests Sqlite') {
steps { steps {
// Bring up a stack // Bring up a stack
sh 'docker-compose up -d fullstack-sqlite' sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120' sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
// Stop and Start it, as this will test it's ability to restart with existing data
sh 'docker-compose stop fullstack-sqlite'
sh 'docker-compose start fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
// Run tests // Run tests
sh 'rm -rf test/results' sh 'rm -rf test/results'
sh 'docker-compose up cypress-sqlite' sh 'docker-compose up cypress-sqlite'
// Get results // Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/' sh 'docker cp -L "$(docker-compose ps --all -q cypress-sqlite):/test/results" test/'
} }
post { post {
always { always {
// Dumps to analyze later // Dumps to analyze later
sh 'mkdir -p debug' sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz' sh 'docker-compose logs fullstack-sqlite > debug/docker_fullstack_sqlite.log'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz' sh 'docker-compose logs db > debug/docker_db.log'
// Cypress videos and screenshot artifacts // Cypress videos and screenshot artifacts
dir(path: 'test/results') { dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml' archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
@ -114,20 +120,20 @@ pipeline {
steps { steps {
// Bring up a stack // Bring up a stack
sh 'docker-compose up -d fullstack-mysql' sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120' sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-mysql) 120'
// Run tests // Run tests
sh 'rm -rf test/results' sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql' sh 'docker-compose up cypress-mysql'
// Get results // Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/' sh 'docker cp -L "$(docker-compose ps --all -q cypress-mysql):/test/results" test/'
} }
post { post {
always { always {
// Dumps to analyze later // Dumps to analyze later
sh 'mkdir -p debug' sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz' sh 'docker-compose logs fullstack-mysql > debug/docker_fullstack_mysql.log'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz' sh 'docker-compose logs db > debug/docker_db.log'
// Cypress videos and screenshot artifacts // Cypress videos and screenshot artifacts
dir(path: 'test/results') { dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml' archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
@ -163,10 +169,8 @@ pipeline {
} }
steps { steps {
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
// Docker Login sh 'docker login -u "${duser}" -p "${dpass}"'
sh "docker login -u '${duser}' -p '${dpass}'" sh "./scripts/buildx --push ${buildxPushTags}"
// Buildx with push from cache
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
} }
} }
} }
@ -180,26 +184,7 @@ pipeline {
} }
} }
steps { steps {
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'npm-s3-docs', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) { npmDocsRelease("$DOCS_BUCKET", "$DOCS_CDN")
sh """docker run --rm \\
--name \${COMPOSE_PROJECT_NAME}-docs-upload \\
-e S3_BUCKET=jc21-npm-site \\
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
-v \$(pwd):/app \\
-w /app \\
jc21/ci-tools \\
scripts/docs-upload /app/docs/.vuepress/dist/
"""
sh """docker run --rm \\
--name \${COMPOSE_PROJECT_NAME}-docs-invalidate \\
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
jc21/ci-tools \\
aws cloudfront create-invalidation --distribution-id EN1G6DEWZUTDT --paths '/*'
"""
}
} }
} }
stage('PR Comment') { stage('PR Comment') {
@ -213,14 +198,14 @@ pipeline {
} }
steps { steps {
script { script {
def comment = pullRequest.comment("This is an automated message from CI:\n\nDocker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.") npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
} }
} }
} }
} }
post { post {
always { always {
sh 'docker-compose down --rmi all --remove-orphans --volumes -t 30' sh 'docker-compose down --remove-orphans --volumes -t 30'
sh 'echo Reverting ownership' sh 'echo Reverting ownership'
sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data' sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
} }

418
README.md
View File

@ -1,22 +1,13 @@
<p align="center"> <p align="center">
<img src="https://nginxproxymanager.com/github.png"> <img src="https://nginxproxymanager.com/github.png">
<br><br> <br><br>
<img src="https://img.shields.io/badge/version-2.9.13-green.svg?style=for-the-badge"> <img src="https://img.shields.io/badge/version-2.10.3-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager"> <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"> <img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a> </a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager"> <a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge"> <img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a> </a>
<a href="https://ci.nginxproxymanager.com/blue/organizations/jenkins/nginx-proxy-manager/branches/">
<img src="https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fci.nginxproxymanager.com%2Fjob%2Fnginx-proxy-manager%2Fjob%2Fmaster&style=for-the-badge">
</a>
<a href="https://gitter.im/nginx-proxy-manager/community">
<img alt="Gitter" src="https://img.shields.io/gitter/room/nginx-proxy-manager/community?style=for-the-badge">
</a>
<a href="https://reddit.com/r/nginxproxymanager">
<img alt="Reddit" src="https://img.shields.io/reddit/subreddit-subscribers/nginxproxymanager?label=Reddit%20Community&style=for-the-badge">
</a>
</p> </p>
This project comes as a pre-built docker image that enables you to easily forward to your websites This project comes as a pre-built docker image that enables you to easily forward to your websites
@ -65,7 +56,7 @@ I won't go in to too much detail here but here are the basics for someone new to
2. Create a docker-compose.yml file similar to this: 2. Create a docker-compose.yml file similar to this:
```yml ```yml
version: '3' version: '3.8'
services: services:
app: app:
image: 'jc21/nginx-proxy-manager:latest' image: 'jc21/nginx-proxy-manager:latest'
@ -79,10 +70,16 @@ services:
- ./letsencrypt:/etc/letsencrypt - ./letsencrypt:/etc/letsencrypt
``` ```
This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
3. Bring up your stack by running 3. Bring up your stack by running
```bash ```bash
docker-compose up -d docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
``` ```
4. Log in to the Admin UI 4. Log in to the Admin UI
@ -103,395 +100,12 @@ Immediately after logging in with this default user you will be asked to modify
## Contributors ## Contributors
Special thanks to the following contributors: Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
<!-- prettier-ignore-start -->
<!-- markdownlint-disable --> ## Getting Support
<table>
<tr> 1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
<td align="center"> 2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
<a href="https://github.com/Subv"> 3. [Development Gitter](https://gitter.im/nginx-proxy-manager/community)
<img src="https://avatars1.githubusercontent.com/u/357072?s=460&u=d8adcdc91d749ae53e177973ed9b6bb6c4c894a3&v=4" width="80" alt=""/> 4. [Reddit](https://reddit.com/r/nginxproxymanager)
<br /><sub><b>Sebastian Valle</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Indemnity83">
<img src="https://avatars3.githubusercontent.com/u/35218?s=460&u=7082004ff35138157c868d7d9c683ccebfce5968&v=4" width="80" alt=""/>
<br /><sub><b>Kyle Klaus</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/theraw">
<img src="https://avatars1.githubusercontent.com/u/32969774?s=460&u=6b359971e15685fb0359e6a8c065a399b40dc228&v=4" width="80" alt=""/>
<br /><sub><b>ƬHE ЯAW</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/spalger">
<img src="https://avatars2.githubusercontent.com/u/1329312?s=400&u=565223e38f1c052afb4c5dcca3fcf1c63ba17ae7&v=4" width="80" alt=""/>
<br /><sub><b>Spencer</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Xantios">
<img src="https://avatars3.githubusercontent.com/u/1507836?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Xantios Krugor</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dpanesso">
<img src="https://avatars2.githubusercontent.com/u/2687121?s=460&v=4" width="80" alt=""/>
<br /><sub><b>David Panesso</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/IronTooch">
<img src="https://avatars3.githubusercontent.com/u/27360514?s=460&u=69bf854a6647c55725f62ecb8d39249c6c0b2602&v=4" width="80" alt=""/>
<br /><sub><b>IronTooch</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/damianog">
<img src="https://avatars1.githubusercontent.com/u/2786682?s=460&u=76c6136fae797abb76b951cd8a246dcaecaf21af&v=4" width="80" alt=""/>
<br /><sub><b>Damiano</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/tfmm">
<img src="https://avatars3.githubusercontent.com/u/6880538?s=460&u=ce0160821cc4aa802df8395200f2d4956a5bc541&v=4" width="80" alt=""/>
<br /><sub><b>Russ</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/margaale">
<img src="https://avatars3.githubusercontent.com/u/20794934?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Marcelo Castagna</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Steven-Harris">
<img src="https://avatars2.githubusercontent.com/u/7720242?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Steven Harris</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jlesage">
<img src="https://avatars0.githubusercontent.com/u/1791123?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Jocelyn Le Sage</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/cmer">
<img src="https://avatars0.githubusercontent.com/u/412?s=460&u=67dd8b2e3661bfd6f68ec1eaa5b9821bd8a321cd&v=4" width="80" alt=""/>
<br /><sub><b>Carl Mercier</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/the1ts">
<img src="https://avatars1.githubusercontent.com/u/84956?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Paul Mansfield</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/OhHeyAlan">
<img src="https://avatars0.githubusercontent.com/u/11955126?s=460&u=fbaa5a1a4f73ef8960132c703349bfd037fe2630&v=4" width="80" alt=""/>
<br /><sub><b>OhHeyAlan</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dogmatic69">
<img src="https://avatars2.githubusercontent.com/u/94674?s=460&u=ca7647de53145c6283b6373ade5dc94ba99347db&v=4" width="80" alt=""/>
<br /><sub><b>Carl Sutton</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/tg44">
<img src="https://avatars0.githubusercontent.com/u/31839?s=460&u=ad32f4cadfef5e5fb09cdfa4b7b7b36a99ba6811&v=4" width="80" alt=""/>
<br /><sub><b>Gergő Törcsvári</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/vrenjith">
<img src="https://avatars3.githubusercontent.com/u/2093241?s=460&u=96ce93a9bebabdd0a60a2dc96cd093a41d5edaba&v=4" width="80" alt=""/>
<br /><sub><b>vrenjith</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/duhruh">
<img src="https://avatars2.githubusercontent.com/u/1133969?s=460&u=c0691e6131ec6d516416c1c6fcedb5034f877bbe&v=4" width="80" alt=""/>
<br /><sub><b>David Rivera</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jipjan">
<img src="https://avatars2.githubusercontent.com/u/1384618?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Jaap-Jan de Wit</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jmwebslave">
<img src="https://avatars2.githubusercontent.com/u/6118262?s=460&u=7db409c47135b1e141c366bbb03ed9fae6ac2638&v=4" width="80" alt=""/>
<br /><sub><b>James Morgan</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/chaptergy">
<img src="https://avatars2.githubusercontent.com/u/26956711?s=460&u=7d9adebabb6b4e7af7cb05d98d751087a372304b&v=4" width="80" alt=""/>
<br /><sub><b>chaptergy</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Philip-Mooney">
<img src="https://avatars0.githubusercontent.com/u/48624631?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Philip Mooney</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/WaterCalm">
<img src="https://avatars1.githubusercontent.com/u/23502129?s=400&v=4" width="80" alt=""/>
<br /><sub><b>WaterCalm</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/lebrou34">
<img src="https://avatars1.githubusercontent.com/u/16373103?s=460&v=4" width="80" alt=""/>
<br /><sub><b>lebrou34</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/lightglitch">
<img src="https://avatars0.githubusercontent.com/u/196953?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Mário Franco</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/klutchell">
<img src="https://avatars3.githubusercontent.com/u/20458272?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Kyle Harding</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ahgraber">
<img src="https://avatars.githubusercontent.com/u/24922003?s=460&u=8376c9f00af9b6057ba4d2fb03b4f1b20a75277f&v=4" width="80" alt=""/>
<br /><sub><b>Alex Graber</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/MooBaloo">
<img src="https://avatars.githubusercontent.com/u/9493496?s=460&v=4" width="80" alt=""/>
<br /><sub><b>MooBaloo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Shuro">
<img src="https://avatars.githubusercontent.com/u/944030?s=460&v=4" width="80" alt=""/>
<br /><sub><b>Shuro</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/lorisbergeron">
<img src="https://avatars.githubusercontent.com/u/51918567?s=460&u=778e4ff284b7d7304450f98421c99f79298371fb&v=4" width="80" alt=""/>
<br /><sub><b>Loris Bergeron</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/hepelayo">
<img src="https://avatars.githubusercontent.com/u/8243119?v=4" width="80" alt=""/>
<br /><sub><b>hepelayo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jonasled">
<img src="https://avatars.githubusercontent.com/u/46790650?v=4" width="80" alt=""/>
<br /><sub><b>Jonas Leder</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/stegmannb">
<img src="https://avatars.githubusercontent.com/u/12850482?v=4" width="80" alt=""/>
<br /><sub><b>Bastian Stegmann</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Stealthii">
<img src="https://avatars.githubusercontent.com/u/998920?v=4" width="80" alt=""/>
<br /><sub><b>Stealthii</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/thegamingninja">
<img src="https://avatars.githubusercontent.com/u/8020534?v=4" width="80" alt=""/>
<br /><sub><b>THEGamingninja</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/italobb">
<img src="https://avatars.githubusercontent.com/u/1801687?v=4" width="80" alt=""/>
<br /><sub><b>Italo Borssatto</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/GurjinderSingh">
<img src="https://avatars.githubusercontent.com/u/3470709?v=4" width="80" alt=""/>
<br /><sub><b>Gurjinder Singh</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/phantomski77">
<img src="https://avatars.githubusercontent.com/u/69464125?v=4" width="80" alt=""/>
<br /><sub><b>David Dosoudil</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ijaron">
<img src="https://avatars.githubusercontent.com/u/5156472?v=4" width="80" alt=""/>
<br /><sub><b>ijaron</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/nielscil">
<img src="https://avatars.githubusercontent.com/u/9073152?v=4" width="80" alt=""/>
<br /><sub><b>Niels Bouma</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ogarai">
<img src="https://avatars.githubusercontent.com/u/2949572?v=4" width="80" alt=""/>
<br /><sub><b>Orko Garai</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/baruffaldi">
<img src="https://avatars.githubusercontent.com/u/36949?v=4" width="80" alt=""/>
<br /><sub><b>Filippo Baruffaldi</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/bikram990">
<img src="https://avatars.githubusercontent.com/u/6782131?v=4" width="80" alt=""/>
<br /><sub><b>Bikramjeet Singh</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/razvanstoica89">
<img src="https://avatars.githubusercontent.com/u/28236583?v=4" width="80" alt=""/>
<br /><sub><b>Razvan Stoica</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/psharma04">
<img src="https://avatars.githubusercontent.com/u/22587474?v=4" width="80" alt=""/>
<br /><sub><b>RBXII3</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/demize">
<img src="https://avatars.githubusercontent.com/u/264914?v=4" width="80" alt=""/>
<br /><sub><b>demize</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/PUP-Loki">
<img src="https://avatars.githubusercontent.com/u/75944209?v=4" width="80" alt=""/>
<br /><sub><b>PUP-Loki</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/DSorlov">
<img src="https://avatars.githubusercontent.com/u/8133650?v=4" width="80" alt=""/>
<br /><sub><b>Daniel Sörlöv</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/Theyooo">
<img src="https://avatars.githubusercontent.com/u/58510131?v=4" width="80" alt=""/>
<br /><sub><b>Theyooo</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mrdink">
<img src="https://avatars.githubusercontent.com/u/514751?v=4" width="80" alt=""/>
<br /><sub><b>Justin Peacock</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ChrisTracy">
<img src="https://avatars.githubusercontent.com/u/58871574?v=4" width="80" alt=""/>
<br /><sub><b>Chris Tracy</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Fuechslein">
<img src="https://avatars.githubusercontent.com/u/15112818?v=4" width="80" alt=""/>
<br /><sub><b>Fuechslein</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/nightah">
<img src="https://avatars.githubusercontent.com/u/3339418?v=4" width="80" alt=""/>
<br /><sub><b>Amir Zarrinkafsh</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/gabbe">
<img src="https://avatars.githubusercontent.com/u/156397?v=4" width="80" alt=""/>
<br /><sub><b>gabbe</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/bmbvenom">
<img src="https://avatars.githubusercontent.com/u/20530371?v=4" width="80" alt=""/>
<br /><sub><b>bmbvenom</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/FMeinicke">
<img src="https://avatars.githubusercontent.com/u/42121639?v=4" width="80" alt=""/>
<br /><sub><b>Florian Meinicke</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/ssrahul96">
<img src="https://avatars.githubusercontent.com/u/15570570?v=4" width="80" alt=""/>
<br /><sub><b>Rahul Somasundaram</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/BjoernAkAManf">
<img src="https://avatars.githubusercontent.com/u/833043?v=4" width="80" alt=""/>
<br /><sub><b>Björn Heinrichs</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/realJoshByrnes">
<img src="https://avatars.githubusercontent.com/u/204185?v=4" width="80" alt=""/>
<br /><sub><b>Josh Byrnes</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/bergi9">
<img src="https://avatars.githubusercontent.com/u/5556750?v=4" width="80" alt=""/>
<br /><sub><b>bergi9</b></sub>
</a>
</td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

View File

@ -2,6 +2,7 @@ const express = require('express');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload'); const fileUpload = require('express-fileupload');
const compression = require('compression'); const compression = require('compression');
const config = require('./lib/config');
const log = require('./logger').express; const log = require('./logger').express;
/** /**
@ -24,7 +25,7 @@ app.enable('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
app.enable('strict routing'); app.enable('strict routing');
// pretty print JSON when not live // pretty print JSON when not live
if (process.env.NODE_ENV !== 'production') { if (config.debug()) {
app.set('json spaces', 2); app.set('json spaces', 2);
} }
@ -65,7 +66,7 @@ app.use(function (err, req, res, next) {
} }
}; };
if (process.env.NODE_ENV === 'development' || (req.baseUrl + req.path).includes('nginx/certificates')) { if (config.debug() || (req.baseUrl + req.path).includes('nginx/certificates')) {
payload.debug = { payload.debug = {
stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null, stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null,
previous: err.previous previous: err.previous
@ -74,7 +75,7 @@ app.use(function (err, req, res, next) {
// Not every error is worth logging - but this is good for now until it gets annoying. // Not every error is worth logging - but this is good for now until it gets annoying.
if (typeof err.stack !== 'undefined' && err.stack) { if (typeof err.stack !== 'undefined' && err.stack) {
if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { if (config.debug()) {
log.debug(err.stack); log.debug(err.stack);
} else if (typeof err.public == 'undefined' || !err.public) { } else if (typeof err.public == 'undefined' || !err.public) {
log.warn(err.message); log.warn(err.message);

View File

@ -1,33 +1,27 @@
const config = require('config'); const config = require('./lib/config');
if (!config.has('database')) { if (!config.has('database')) {
throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md'); throw new Error('Database config does not exist! Please read the instructions: https://nginxproxymanager.com/setup/');
} }
function generateDbConfig() { function generateDbConfig() {
if (config.database.engine === 'knex-native') { const cfg = config.get('database');
return config.database.knex; if (cfg.engine === 'knex-native') {
} else return cfg.knex;
return { }
client: config.database.engine, return {
connection: { client: cfg.engine,
host: config.database.host, connection: {
user: config.database.user, host: cfg.host,
password: config.database.password, user: cfg.user,
database: config.database.name, password: cfg.password,
port: config.database.port database: cfg.name,
}, port: cfg.port
migrations: { },
tableName: 'migrations' migrations: {
} tableName: 'migrations'
}; }
};
} }
module.exports = require('knex')(generateDbConfig());
let data = generateDbConfig();
if (typeof config.database.version !== 'undefined') {
data.version = config.database.version;
}
module.exports = require('knex')(data);

View File

@ -40,6 +40,210 @@
} }
} }
}, },
"/nginx/proxy-hosts": {
"get": {
"operationId": "getProxyHosts",
"summary": "Get all proxy hosts",
"tags": ["Proxy Hosts"],
"security": [
{
"BearerAuth": ["users"]
}
],
"parameters": [
{
"in": "query",
"name": "expand",
"description": "Expansions",
"schema": {
"type": "string",
"enum": ["access_list", "owner", "certificate"]
}
}
],
"responses": {
"200": {
"description": "200 response",
"content": {
"application/json": {
"examples": {
"default": {
"value": [
{
"id": 1,
"created_on": "2023-03-30T01:12:23.000Z",
"modified_on": "2023-03-30T02:15:40.000Z",
"owner_user_id": 1,
"domain_names": ["aasdasdad"],
"forward_host": "asdasd",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "sdfsdfsdf",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false,
"nginx_online": false,
"nginx_err": "Command failed: /usr/sbin/nginx -t -g \"error_log off;\"\nnginx: [emerg] unknown directive \"sdfsdfsdf\" in /data/nginx/proxy_host/1.conf:37\nnginx: configuration file /etc/nginx/nginx.conf test failed\n"
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"certificate": null
},
{
"id": 2,
"created_on": "2023-03-30T02:11:49.000Z",
"modified_on": "2023-03-30T02:11:49.000Z",
"owner_user_id": 1,
"domain_names": ["test.example.com"],
"forward_host": "1.1.1.1",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false,
"nginx_online": true,
"nginx_err": null
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"certificate": null
}
]
}
},
"schema": {
"$ref": "#/components/schemas/ProxyHostsList"
}
}
}
}
}
},
"post": {
"operationId": "createProxyHost",
"summary": "Create a Proxy Host",
"tags": ["Proxy Hosts"],
"security": [
{
"BearerAuth": ["users"]
}
],
"parameters": [
{
"in": "body",
"name": "proxyhost",
"description": "Proxy Host Payload",
"required": true,
"schema": {
"$ref": "#/components/schemas/ProxyHostObject"
}
}
],
"responses": {
"201": {
"description": "201 response",
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"id": 3,
"created_on": "2023-03-30T02:31:27.000Z",
"modified_on": "2023-03-30T02:31:27.000Z",
"owner_user_id": 1,
"domain_names": ["test2.example.com"],
"forward_host": "1.1.1.1",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"certificate": null,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"use_default_location": true,
"ipv6": true
}
}
},
"schema": {
"$ref": "#/components/schemas/ProxyHostObject"
}
}
}
}
}
}
},
"/schema": { "/schema": {
"get": { "get": {
"operationId": "schema", "operationId": "schema",
@ -55,14 +259,10 @@
"get": { "get": {
"operationId": "refreshToken", "operationId": "refreshToken",
"summary": "Refresh your access token", "summary": "Refresh your access token",
"tags": [ "tags": ["Tokens"],
"Tokens"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["tokens"]
"tokens"
]
} }
], ],
"responses": { "responses": {
@ -104,19 +304,14 @@
"scope": { "scope": {
"minLength": 1, "minLength": 1,
"type": "string", "type": "string",
"enum": [ "enum": ["user"]
"user"
]
}, },
"secret": { "secret": {
"minLength": 1, "minLength": 1,
"type": "string" "type": "string"
} }
}, },
"required": [ "required": ["identity", "secret"],
"identity",
"secret"
],
"type": "object" "type": "object"
} }
} }
@ -144,23 +339,17 @@
} }
}, },
"summary": "Request a new access token from credentials", "summary": "Request a new access token from credentials",
"tags": [ "tags": ["Tokens"]
"Tokens"
]
} }
}, },
"/settings": { "/settings": {
"get": { "get": {
"operationId": "getSettings", "operationId": "getSettings",
"summary": "Get all settings", "summary": "Get all settings",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"responses": { "responses": {
@ -194,14 +383,10 @@
"get": { "get": {
"operationId": "getSetting", "operationId": "getSetting",
"summary": "Get a setting", "summary": "Get a setting",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"parameters": [ "parameters": [
@ -244,14 +429,10 @@
"put": { "put": {
"operationId": "updateSetting", "operationId": "updateSetting",
"summary": "Update a setting", "summary": "Update a setting",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"parameters": [ "parameters": [
@ -305,14 +486,10 @@
"get": { "get": {
"operationId": "getUsers", "operationId": "getUsers",
"summary": "Get all users", "summary": "Get all users",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -322,9 +499,7 @@
"description": "Expansions", "description": "Expansions",
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["permissions"]
"permissions"
]
} }
} }
], ],
@ -345,9 +520,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
] ]
}, },
@ -362,9 +535,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"],
"admin"
],
"permissions": { "permissions": {
"visibility": "all", "visibility": "all",
"proxy_hosts": "manage", "proxy_hosts": "manage",
@ -389,14 +560,10 @@
"post": { "post": {
"operationId": "createUser", "operationId": "createUser",
"summary": "Create a User", "summary": "Create a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -426,9 +593,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"],
"admin"
],
"permissions": { "permissions": {
"visibility": "all", "visibility": "all",
"proxy_hosts": "manage", "proxy_hosts": "manage",
@ -454,14 +619,10 @@
"get": { "get": {
"operationId": "getUser", "operationId": "getUser",
"summary": "Get a user", "summary": "Get a user",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -501,9 +662,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
}, },
@ -518,14 +677,10 @@
"put": { "put": {
"operationId": "updateUser", "operationId": "updateUser",
"summary": "Update a User", "summary": "Update a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -574,9 +729,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
}, },
@ -591,14 +744,10 @@
"delete": { "delete": {
"operationId": "deleteUser", "operationId": "deleteUser",
"summary": "Delete a User", "summary": "Delete a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -637,14 +786,10 @@
"put": { "put": {
"operationId": "updateUserAuth", "operationId": "updateUserAuth",
"summary": "Update a User's Authentication", "summary": "Update a User's Authentication",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -700,14 +845,10 @@
"put": { "put": {
"operationId": "updateUserPermissions", "operationId": "updateUserPermissions",
"summary": "Update a User's Permissions", "summary": "Update a User's Permissions",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -755,14 +896,10 @@
"put": { "put": {
"operationId": "loginAsUser", "operationId": "loginAsUser",
"summary": "Login as this user", "summary": "Login as this user",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -797,9 +934,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm", "avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
} }
@ -807,11 +942,7 @@
"schema": { "schema": {
"type": "object", "type": "object",
"description": "Login object", "description": "Login object",
"required": [ "required": ["expires", "token", "user"],
"expires",
"token",
"user"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"expires": { "expires": {
@ -840,14 +971,10 @@
"get": { "get": {
"operationId": "reportsHosts", "operationId": "reportsHosts",
"summary": "Report on Host Statistics", "summary": "Report on Host Statistics",
"tags": [ "tags": ["Reports"],
"Reports"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["reports"]
"reports"
]
} }
], ],
"responses": { "responses": {
@ -878,14 +1005,10 @@
"get": { "get": {
"operationId": "getAuditLog", "operationId": "getAuditLog",
"summary": "Get Audit Log", "summary": "Get Audit Log",
"tags": [ "tags": ["Audit Log"],
"Audit Log"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["audit-log"]
"audit-log"
]
} }
], ],
"responses": { "responses": {
@ -925,10 +1048,7 @@
"type": "object", "type": "object",
"description": "Health object", "description": "Health object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": ["status", "version"],
"status",
"version"
],
"properties": { "properties": {
"status": { "status": {
"type": "string", "type": "string",
@ -944,11 +1064,7 @@
"revision": 0 "revision": 0
}, },
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": ["major", "minor", "revision"],
"major",
"minor",
"revision"
],
"properties": { "properties": {
"major": { "major": {
"type": "integer", "type": "integer",
@ -969,10 +1085,7 @@
"TokenObject": { "TokenObject": {
"type": "object", "type": "object",
"description": "Token object", "description": "Token object",
"required": [ "required": ["expires", "token"],
"expires",
"token"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"expires": { "expires": {
@ -988,16 +1101,147 @@
} }
} }
}, },
"ProxyHostObject": {
"type": "object",
"description": "Proxy Host object",
"required": [
"id",
"created_on",
"modified_on",
"owner_user_id",
"domain_names",
"forward_host",
"forward_port",
"access_list_id",
"certificate_id",
"ssl_forced",
"caching_enabled",
"block_exploits",
"advanced_config",
"meta",
"allow_websocket_upgrade",
"http2_support",
"forward_scheme",
"enabled",
"locations",
"hsts_enabled",
"hsts_subdomains",
"certificate",
"use_default_location",
"ipv6"
],
"additionalProperties": false,
"properties": {
"id": {
"type": "integer",
"description": "Proxy Host ID",
"minimum": 1,
"example": 1
},
"created_on": {
"type": "string",
"description": "Created Date",
"example": "2020-01-30T09:36:08.000Z"
},
"modified_on": {
"type": "string",
"description": "Modified Date",
"example": "2020-01-30T09:41:04.000Z"
},
"owner_user_id": {
"type": "integer",
"minimum": 1,
"example": 1
},
"domain_names": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"minLength": 1
}
},
"forward_host": {
"type": "string",
"minLength": 1
},
"forward_port": {
"type": "integer",
"minimum": 1
},
"access_list_id": {
"type": "integer"
},
"certificate_id": {
"type": "integer"
},
"ssl_forced": {
"type": "integer"
},
"caching_enabled": {
"type": "integer"
},
"block_exploits": {
"type": "integer"
},
"advanced_config": {
"type": "string"
},
"meta": {
"type": "object"
},
"allow_websocket_upgrade": {
"type": "integer"
},
"http2_support": {
"type": "integer"
},
"forward_scheme": {
"type": "string"
},
"enabled": {
"type": "integer"
},
"locations": {
"type": "array"
},
"hsts_enabled": {
"type": "integer"
},
"hsts_subdomains": {
"type": "integer"
},
"certificate": {
"type": "object",
"nullable": true
},
"owner": {
"type": "object",
"nullable": true
},
"access_list": {
"type": "object",
"nullable": true
},
"use_default_location": {
"type": "boolean"
},
"ipv6": {
"type": "boolean"
}
}
},
"ProxyHostsList": {
"type": "array",
"description": "Proxyn Hosts list",
"items": {
"$ref": "#/components/schemas/ProxyHostObject"
}
},
"SettingObject": { "SettingObject": {
"type": "object", "type": "object",
"description": "Setting object", "description": "Setting object",
"required": [ "required": ["id", "name", "description", "value", "meta"],
"id",
"name",
"description",
"value",
"meta"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"id": { "id": {
@ -1057,17 +1301,7 @@
"UserObject": { "UserObject": {
"type": "object", "type": "object",
"description": "User object", "description": "User object",
"required": [ "required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"],
"id",
"created_on",
"modified_on",
"is_disabled",
"email",
"name",
"nickname",
"avatar",
"roles"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"id": { "id": {
@ -1117,9 +1351,7 @@
}, },
"roles": { "roles": {
"description": "Roles applied", "description": "Roles applied",
"example": [ "example": ["admin"],
"admin"
],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
@ -1137,10 +1369,7 @@
"AuthObject": { "AuthObject": {
"type": "object", "type": "object",
"description": "Authentication Object", "description": "Authentication Object",
"required": [ "required": ["type", "secret"],
"type",
"secret"
],
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
@ -1167,64 +1396,37 @@
"visibility": { "visibility": {
"type": "string", "type": "string",
"description": "Visibility Type", "description": "Visibility Type",
"enum": [ "enum": ["all", "user"]
"all",
"user"
]
}, },
"access_lists": { "access_lists": {
"type": "string", "type": "string",
"description": "Access Lists Permissions", "description": "Access Lists Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"dead_hosts": { "dead_hosts": {
"type": "string", "type": "string",
"description": "404 Hosts Permissions", "description": "404 Hosts Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"proxy_hosts": { "proxy_hosts": {
"type": "string", "type": "string",
"description": "Proxy Hosts Permissions", "description": "Proxy Hosts Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"redirection_hosts": { "redirection_hosts": {
"type": "string", "type": "string",
"description": "Redirection Permissions", "description": "Redirection Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"streams": { "streams": {
"type": "string", "type": "string",
"description": "Streams Permissions", "description": "Streams Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"certificates": { "certificates": {
"type": "string", "type": "string",
"description": "Certificates Permissions", "description": "Certificates Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
} }
} }
}, },

View File

@ -3,9 +3,6 @@
const logger = require('./logger').global; const logger = require('./logger').global;
async function appStart () { async function appStart () {
// Create config file db settings if environment variables have been set
await createDbConfigFromEnvironment();
const migrate = require('./migrate'); const migrate = require('./migrate');
const setup = require('./setup'); const setup = require('./setup');
const app = require('./app'); const app = require('./app');
@ -42,90 +39,6 @@ async function appStart () {
}); });
} }
async function createDbConfigFromEnvironment() {
return new Promise((resolve, reject) => {
const envMysqlHost = process.env.DB_MYSQL_HOST || null;
const envMysqlPort = process.env.DB_MYSQL_PORT || null;
const envMysqlUser = process.env.DB_MYSQL_USER || null;
const envMysqlName = process.env.DB_MYSQL_NAME || null;
let envSqliteFile = process.env.DB_SQLITE_FILE || null;
const fs = require('fs');
const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
let configData = {};
try {
configData = require(filename);
} catch (err) {
// do nothing
}
if (configData.database && configData.database.engine && !configData.database.fromEnv) {
logger.info('Manual db configuration already exists, skipping config creation from environment variables');
resolve();
return;
}
if ((!envMysqlHost || !envMysqlPort || !envMysqlUser || !envMysqlName) && !envSqliteFile){
envSqliteFile = '/data/database.sqlite';
logger.info(`No valid environment variables for database provided, using default SQLite file '${envSqliteFile}'`);
}
if (envMysqlHost && envMysqlPort && envMysqlUser && envMysqlName) {
const newConfig = {
fromEnv: true,
engine: 'mysql',
host: envMysqlHost,
port: envMysqlPort,
user: envMysqlUser,
password: process.env.DB_MYSQL_PASSWORD,
name: envMysqlName,
};
if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) {
// Config is unchanged, skip overwrite
resolve();
return;
}
logger.info('Generating MySQL knex configuration from environment variables');
configData.database = newConfig;
} else {
const newConfig = {
fromEnv: true,
engine: 'knex-native',
knex: {
client: 'sqlite3',
connection: {
filename: envSqliteFile
},
useNullAsDefault: true
}
};
if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) {
// Config is unchanged, skip overwrite
resolve();
return;
}
logger.info('Generating SQLite knex configuration');
configData.database = newConfig;
}
// Write config
fs.writeFile(filename, JSON.stringify(configData, null, 2), (err) => {
if (err) {
logger.error('Could not write db config to config file: ' + filename);
reject(err);
} else {
logger.debug('Wrote db configuration to config file: ' + filename);
resolve();
}
});
});
}
try { try {
appStart(); appStart();
} catch (err) { } catch (err) {

View File

@ -3,13 +3,13 @@ const fs = require('fs');
const batchflow = require('batchflow'); const batchflow = require('batchflow');
const logger = require('../logger').access; const logger = require('../logger').access;
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const accessListModel = require('../models/access_list'); const accessListModel = require('../models/access_list');
const accessListAuthModel = require('../models/access_list_auth'); const accessListAuthModel = require('../models/access_list_auth');
const accessListClientModel = require('../models/access_list_client'); const accessListClientModel = require('../models/access_list_client');
const proxyHostModel = require('../models/proxy_host'); const proxyHostModel = require('../models/proxy_host');
const internalAuditLog = require('./audit-log'); const internalAuditLog = require('./audit-log');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
const utils = require('../lib/utils');
function omissions () { function omissions () {
return ['is_deleted']; return ['is_deleted'];
@ -27,13 +27,13 @@ const internalAccessList = {
.then((/*access_data*/) => { .then((/*access_data*/) => {
return accessListModel return accessListModel
.query() .query()
.omit(omissions())
.insertAndFetch({ .insertAndFetch({
name: data.name, name: data.name,
satisfy_any: data.satisfy_any, satisfy_any: data.satisfy_any,
pass_auth: data.pass_auth, pass_auth: data.pass_auth,
owner_user_id: access.token.getUserId(1) owner_user_id: access.token.getUserId(1)
}); })
.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
data.id = row.id; data.id = row.id;
@ -218,7 +218,7 @@ const internalAccessList = {
// re-fetch with expansions // re-fetch with expansions
return internalAccessList.get(access, { return internalAccessList.get(access, {
id: data.id, id: data.id,
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]'] expand: ['owner', 'items', 'clients', 'proxy_hosts.[certificate,access_list.[clients,items]]']
}, true /* <- skip masking */); }, true /* <- skip masking */);
}) })
.then((row) => { .then((row) => {
@ -256,35 +256,31 @@ const internalAccessList = {
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0') .joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
.where('access_list.is_deleted', 0) .where('access_list.is_deleted', 0)
.andWhere('access_list.id', data.id) .andWhere('access_list.id', data.id)
.allowEager('[owner,items,clients,proxy_hosts.[*, access_list.[clients,items]]]') .allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
.omit(['access_list.is_deleted'])
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('access_list.owner_user_id', access.token.getUserId(1)); query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
row = internalAccessList.maskItems(row);
}
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
row = internalAccessList.maskItems(row);
}
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -381,8 +377,7 @@ const internalAccessList = {
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0') .joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
.where('access_list.is_deleted', 0) .where('access_list.is_deleted', 0)
.groupBy('access_list.id') .groupBy('access_list.id')
.omit(['access_list.is_deleted']) .allowGraph('[owner,items,clients]')
.allowEager('[owner,items,clients]')
.orderBy('access_list.name', 'ASC'); .orderBy('access_list.name', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -397,10 +392,10 @@ const internalAccessList = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}) })
.then((rows) => { .then((rows) => {
if (rows) { if (rows) {
@ -507,7 +502,7 @@ const internalAccessList = {
if (typeof item.password !== 'undefined' && item.password.length) { if (typeof item.password !== 'undefined' && item.password.length) {
logger.info('Adding: ' + item.username); logger.info('Adding: ' + item.username);
utils.exec('/usr/bin/htpasswd -b "' + htpasswd_file + '" "' + item.username + '" "' + item.password + '"') utils.execFile('/usr/bin/htpasswd', ['-b', htpasswd_file, item.username, item.password])
.then((/*result*/) => { .then((/*result*/) => {
next(); next();
}) })

View File

@ -19,7 +19,7 @@ const internalAuditLog = {
.orderBy('created_on', 'DESC') .orderBy('created_on', 'DESC')
.orderBy('id', 'DESC') .orderBy('id', 'DESC')
.limit(100) .limit(100)
.allowEager('[user]'); .allowGraph('[user]');
// Query is used for searching // Query is used for searching
if (typeof search_query === 'string') { if (typeof search_query === 'string') {
@ -29,7 +29,7 @@ const internalAuditLog = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query;

View File

@ -1,22 +1,24 @@
const _ = require('lodash'); const _ = require('lodash');
const fs = require('fs'); const fs = require('fs');
const https = require('https'); const https = require('https');
const tempWrite = require('temp-write'); const tempWrite = require('temp-write');
const moment = require('moment'); const moment = require('moment');
const logger = require('../logger').ssl; const logger = require('../logger').ssl;
const error = require('../lib/error'); const config = require('../lib/config');
const utils = require('../lib/utils'); const error = require('../lib/error');
const certificateModel = require('../models/certificate'); const utils = require('../lib/utils');
const dnsPlugins = require('../global/certbot-dns-plugins'); const certificateModel = require('../models/certificate');
const internalAuditLog = require('./audit-log'); const dnsPlugins = require('../global/certbot-dns-plugins');
const internalNginx = require('./nginx'); const internalAuditLog = require('./audit-log');
const internalHost = require('./host'); const internalNginx = require('./nginx');
const letsencryptStaging = process.env.NODE_ENV !== 'production'; const internalHost = require('./host');
const archiver = require('archiver');
const path = require('path');
const { isArray } = require('lodash');
const letsencryptStaging = config.useLetsencryptStaging();
const letsencryptConfig = '/etc/letsencrypt.ini'; const letsencryptConfig = '/etc/letsencrypt.ini';
const certbotCommand = 'certbot'; const certbotCommand = 'certbot';
const archiver = require('archiver');
const path = require('path');
const { isArray } = require('lodash');
function omissions() { function omissions() {
return ['is_deleted']; return ['is_deleted'];
@ -46,6 +48,8 @@ const internalCertificate = {
const cmd = certbotCommand + ' renew --non-interactive --quiet ' + const cmd = certbotCommand + ' renew --non-interactive --quiet ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--preferred-challenges "dns,http" ' + '--preferred-challenges "dns,http" ' +
'--disable-hook-validation ' + '--disable-hook-validation ' +
(letsencryptStaging ? '--staging' : ''); (letsencryptStaging ? '--staging' : '');
@ -121,8 +125,8 @@ const internalCertificate = {
return certificateModel return certificateModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((certificate) => { .then((certificate) => {
if (certificate.provider === 'letsencrypt') { if (certificate.provider === 'letsencrypt') {
@ -171,6 +175,7 @@ const internalCertificate = {
// 3. Generate the LE config // 3. Generate the LE config
return internalNginx.generateLetsEncryptRequestConfig(certificate) return internalNginx.generateLetsEncryptRequestConfig(certificate)
.then(internalNginx.reload) .then(internalNginx.reload)
.then(async() => await new Promise((r) => setTimeout(r, 5000)))
.then(() => { .then(() => {
// 4. Request cert // 4. Request cert
return internalCertificate.requestLetsEncryptSsl(certificate); return internalCertificate.requestLetsEncryptSsl(certificate);
@ -268,8 +273,8 @@ const internalCertificate = {
return certificateModel return certificateModel
.query() .query()
.omit(omissions())
.patchAndFetchById(row.id, data) .patchAndFetchById(row.id, data)
.then(utils.omitRow(omissions()))
.then((saved_row) => { .then((saved_row) => {
saved_row.meta = internalCertificate.cleanMeta(saved_row.meta); saved_row.meta = internalCertificate.cleanMeta(saved_row.meta);
data.meta = internalCertificate.cleanMeta(data.meta); data.meta = internalCertificate.cleanMeta(data.meta);
@ -287,7 +292,7 @@ const internalCertificate = {
meta: _.omit(data, ['expires_on']) // this prevents json circular reference because expires_on might be raw meta: _.omit(data, ['expires_on']) // this prevents json circular reference because expires_on might be raw
}) })
.then(() => { .then(() => {
return _.omit(saved_row, omissions()); return saved_row;
}); });
}); });
}); });
@ -312,30 +317,28 @@ const internalCertificate = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[owner]') .allowGraph('[owner]')
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1)); query.andWhere('owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -465,8 +468,7 @@ const internalCertificate = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[owner]')
.allowEager('[owner]')
.orderBy('nice_name', 'ASC'); .orderBy('nice_name', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -476,15 +478,15 @@ const internalCertificate = {
// Query is used for searching // Query is used for searching
if (typeof search_query === 'string') { if (typeof search_query === 'string') {
query.where(function () { query.where(function () {
this.where('name', 'like', '%' + search_query + '%'); this.where('nice_name', 'like', '%' + search_query + '%');
}); });
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}); });
}, },
@ -661,7 +663,6 @@ const internalCertificate = {
meta: _.clone(row.meta) // Prevent the update method from changing this value that we'll use later meta: _.clone(row.meta) // Prevent the update method from changing this value that we'll use later
}) })
.then((certificate) => { .then((certificate) => {
console.log('ROWMETA:', row.meta);
certificate.meta = row.meta; certificate.meta = row.meta;
return internalCertificate.writeCustomCert(certificate); return internalCertificate.writeCustomCert(certificate);
}); });
@ -836,6 +837,8 @@ const internalCertificate = {
const cmd = certbotCommand + ' certonly ' + const cmd = certbotCommand + ' certonly ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-name "npm-' + certificate.id + '" ' + '--cert-name "npm-' + certificate.id + '" ' +
'--agree-tos ' + '--agree-tos ' +
'--authenticator webroot ' + '--authenticator webroot ' +
@ -870,14 +873,19 @@ const internalCertificate = {
logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_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;
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\''; // Escape single quotes and backslashes
const prepareCmd = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies; const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
// we call `. /opt/certbot/bin/activate` (`.` is alternative to `source` in dash) to access certbot venv
const prepareCmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir --user ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies + ' && deactivate';
// Whether the plugin has a --<name>-credentials argument // Whether the plugin has a --<name>-credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53'; const hasConfigArg = certificate.meta.dns_provider !== 'route53';
let mainCmd = certbotCommand + ' certonly ' + let mainCmd = certbotCommand + ' certonly ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-name "npm-' + certificate.id + '" ' + '--cert-name "npm-' + certificate.id + '" ' +
'--agree-tos ' + '--agree-tos ' +
'--email "' + certificate.meta.letsencrypt_email + '" ' + '--email "' + certificate.meta.letsencrypt_email + '" ' +
@ -974,6 +982,8 @@ const internalCertificate = {
const cmd = certbotCommand + ' renew --force-renewal ' + const cmd = certbotCommand + ' renew --force-renewal ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-name "npm-' + certificate.id + '" ' + '--cert-name "npm-' + certificate.id + '" ' +
'--preferred-challenges "dns,http" ' + '--preferred-challenges "dns,http" ' +
'--no-random-sleep-on-renew ' + '--no-random-sleep-on-renew ' +
@ -1004,6 +1014,8 @@ const internalCertificate = {
let mainCmd = certbotCommand + ' renew ' + let mainCmd = certbotCommand + ' renew ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-name "npm-' + certificate.id + '" ' + '--cert-name "npm-' + certificate.id + '" ' +
'--disable-hook-validation ' + '--disable-hook-validation ' +
'--no-random-sleep-on-renew ' + '--no-random-sleep-on-renew ' +

View File

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const deadHostModel = require('../models/dead_host'); const deadHostModel = require('../models/dead_host');
const internalHost = require('./host'); const internalHost = require('./host');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
@ -49,8 +50,8 @@ const internalDeadHost = {
return deadHostModel return deadHostModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (create_certificate) { if (create_certificate) {
@ -218,31 +219,28 @@ const internalDeadHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[owner,certificate]') .allowGraph('[owner,certificate]')
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1)); query.andWhere('owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -404,8 +402,7 @@ const internalDeadHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[owner,certificate]')
.allowEager('[owner,certificate]')
.orderBy('domain_names', 'ASC'); .orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -420,10 +417,10 @@ const internalDeadHost = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}) })
.then((rows) => { .then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) { if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {

View File

@ -2,13 +2,16 @@ const https = require('https');
const fs = require('fs'); const fs = require('fs');
const logger = require('../logger').ip_ranges; const logger = require('../logger').ip_ranges;
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
const { Liquid } = require('liquidjs');
const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json'; const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4'; const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6'; const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
const regIpV4 = /^(\d+\.?){4}\/\d+/;
const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
const internalIpRanges = { const internalIpRanges = {
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
@ -74,14 +77,14 @@ const internalIpRanges = {
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL); return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
}) })
.then((cloudfare_data) => { .then((cloudfare_data) => {
let items = cloudfare_data.split('\n'); let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
ip_ranges = [... ip_ranges, ... items]; ip_ranges = [... ip_ranges, ... items];
}) })
.then(() => { .then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL); return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
}) })
.then((cloudfare_data) => { .then((cloudfare_data) => {
let items = cloudfare_data.split('\n'); let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
ip_ranges = [... ip_ranges, ... items]; ip_ranges = [... ip_ranges, ... items];
}) })
.then(() => { .then(() => {
@ -116,10 +119,7 @@ const internalIpRanges = {
* @returns {Promise} * @returns {Promise}
*/ */
generateConfig: (ip_ranges) => { generateConfig: (ip_ranges) => {
let renderEngine = new Liquid({ const renderEngine = utils.getRenderEngine();
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let template = null; let template = null;
let filename = '/etc/nginx/conf.d/include/ip_ranges.conf'; let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';

View File

@ -1,10 +1,9 @@
const _ = require('lodash'); const _ = require('lodash');
const fs = require('fs'); const fs = require('fs');
const logger = require('../logger').nginx; const logger = require('../logger').nginx;
const utils = require('../lib/utils'); const config = require('../lib/config');
const error = require('../lib/error'); const utils = require('../lib/utils');
const { Liquid } = require('liquidjs'); const error = require('../lib/error');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
const internalNginx = { const internalNginx = {
@ -29,7 +28,9 @@ const internalNginx = {
.then(() => { .then(() => {
// Nginx is OK // Nginx is OK
// We're deleting this config regardless. // We're deleting this config regardless.
return internalNginx.deleteConfig(host_type, host); // Don't throw errors, as the file may not exist at all // Don't throw errors, as the file may not exist at all
// Delete the .err file too
return internalNginx.deleteConfig(host_type, host, false, true);
}) })
.then(() => { .then(() => {
return internalNginx.generateConfig(host_type, host); return internalNginx.generateConfig(host_type, host);
@ -64,7 +65,7 @@ const internalNginx = {
} }
}); });
if (debug_mode) { if (config.debug()) {
logger.error('Nginx test failed:', valid_lines.join('\n')); logger.error('Nginx test failed:', valid_lines.join('\n'));
} }
@ -80,6 +81,9 @@ const internalNginx = {
.patch({ .patch({
meta: combined_meta meta: combined_meta
}) })
.then(() => {
internalNginx.renameConfigAsError(host_type, host);
})
.then(() => { .then(() => {
return internalNginx.deleteConfig(host_type, host, true); return internalNginx.deleteConfig(host_type, host, true);
}); });
@ -97,7 +101,7 @@ const internalNginx = {
* @returns {Promise} * @returns {Promise}
*/ */
test: () => { test: () => {
if (debug_mode) { if (config.debug()) {
logger.info('Testing Nginx configuration'); logger.info('Testing Nginx configuration');
} }
@ -121,13 +125,10 @@ const internalNginx = {
* @returns {String} * @returns {String}
*/ */
getConfigName: (host_type, host_id) => { getConfigName: (host_type, host_id) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_');
if (host_type === 'default') { if (host_type === 'default') {
return '/data/nginx/default_host/site.conf'; return '/data/nginx/default_host/site.conf';
} }
return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf';
return '/data/nginx/' + host_type + '/' + host_id + '.conf';
}, },
/** /**
@ -136,8 +137,6 @@ const internalNginx = {
* @returns {Promise} * @returns {Promise}
*/ */
renderLocations: (host) => { renderLocations: (host) => {
//logger.info('host = ' + JSON.stringify(host, null, 2));
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let template; let template;
@ -148,9 +147,7 @@ const internalNginx = {
return; return;
} }
let renderer = new Liquid({ const renderEngine = utils.getRenderEngine();
root: __dirname + '/../templates/'
});
let renderedLocations = ''; let renderedLocations = '';
const locationRendering = async () => { const locationRendering = async () => {
@ -168,10 +165,8 @@ const internalNginx = {
locationCopy.forward_path = `/${splitted.join('/')}`; locationCopy.forward_path = `/${splitted.join('/')}`;
} }
//logger.info('locationCopy = ' + JSON.stringify(locationCopy, null, 2));
// eslint-disable-next-line // eslint-disable-next-line
renderedLocations += await renderer.parseAndRender(template, locationCopy); renderedLocations += await renderEngine.parseAndRender(template, locationCopy);
} }
}; };
@ -187,24 +182,20 @@ const internalNginx = {
* @returns {Promise} * @returns {Promise}
*/ */
generateConfig: (host_type, host) => { generateConfig: (host_type, host) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_'); const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
if (debug_mode) { if (config.debug()) {
logger.info('Generating ' + host_type + ' Config:', host); logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
} }
// logger.info('host = ' + JSON.stringify(host, null, 2)); const renderEngine = utils.getRenderEngine();
let renderEngine = new Liquid({
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let template = null; let template = null;
let filename = internalNginx.getConfigName(host_type, host.id); let filename = internalNginx.getConfigName(nice_host_type, host.id);
try { try {
template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'}); template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', {encoding: 'utf8'});
} catch (err) { } catch (err) {
reject(new error.ConfigurationError(err.message)); reject(new error.ConfigurationError(err.message));
return; return;
@ -214,7 +205,7 @@ const internalNginx = {
let origLocations; let origLocations;
// Manipulate the data a bit before sending it to the template // Manipulate the data a bit before sending it to the template
if (host_type !== 'default') { if (nice_host_type !== 'default') {
host.use_default_location = true; host.use_default_location = true;
if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
@ -248,7 +239,7 @@ const internalNginx = {
.then((config_text) => { .then((config_text) => {
fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
if (debug_mode) { if (config.debug()) {
logger.success('Wrote config:', filename, config_text); logger.success('Wrote config:', filename, config_text);
} }
@ -258,7 +249,7 @@ const internalNginx = {
resolve(true); resolve(true);
}) })
.catch((err) => { .catch((err) => {
if (debug_mode) { if (config.debug()) {
logger.warn('Could not write ' + filename + ':', err.message); logger.warn('Could not write ' + filename + ':', err.message);
} }
@ -277,13 +268,11 @@ const internalNginx = {
* @returns {Promise} * @returns {Promise}
*/ */
generateLetsEncryptRequestConfig: (certificate) => { generateLetsEncryptRequestConfig: (certificate) => {
if (debug_mode) { if (config.debug()) {
logger.info('Generating LetsEncrypt Request Config:', certificate); logger.info('Generating LetsEncrypt Request Config:', certificate);
} }
let renderEngine = new Liquid({ const renderEngine = utils.getRenderEngine();
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let template = null; let template = null;
@ -303,14 +292,14 @@ const internalNginx = {
.then((config_text) => { .then((config_text) => {
fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
if (debug_mode) { if (config.debug()) {
logger.success('Wrote config:', filename, config_text); logger.success('Wrote config:', filename, config_text);
} }
resolve(true); resolve(true);
}) })
.catch((err) => { .catch((err) => {
if (debug_mode) { if (config.debug()) {
logger.warn('Could not write ' + filename + ':', err.message); logger.warn('Could not write ' + filename + ':', err.message);
} }
@ -319,33 +308,39 @@ const internalNginx = {
}); });
}, },
/**
* A simple wrapper around unlinkSync that writes to the logger
*
* @param {String} filename
*/
deleteFile: (filename) => {
logger.debug('Deleting file: ' + filename);
try {
fs.unlinkSync(filename);
} catch (err) {
logger.debug('Could not delete file:', JSON.stringify(err, null, 2));
}
},
/**
*
* @param {String} host_type
* @returns String
*/
getFileFriendlyHostType: (host_type) => {
return host_type.replace(new RegExp('-', 'g'), '_');
},
/** /**
* This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig` * This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
* *
* @param {Object} certificate * @param {Object} certificate
* @param {Boolean} [throw_errors]
* @returns {Promise} * @returns {Promise}
*/ */
deleteLetsEncryptRequestConfig: (certificate, throw_errors) => { deleteLetsEncryptRequestConfig: (certificate) => {
return new Promise((resolve, reject) => { const config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
try { return new Promise((resolve/*, reject*/) => {
let config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf'; internalNginx.deleteFile(config_file);
if (debug_mode) {
logger.warn('Deleting nginx config: ' + config_file);
}
fs.unlinkSync(config_file);
} catch (err) {
if (debug_mode) {
logger.warn('Could not delete config:', err.message);
}
if (throw_errors) {
reject(err);
}
}
resolve(); resolve();
}); });
}, },
@ -353,35 +348,42 @@ const internalNginx = {
/** /**
* @param {String} host_type * @param {String} host_type
* @param {Object} [host] * @param {Object} [host]
* @param {Boolean} [throw_errors] * @param {Boolean} [delete_err_file]
* @returns {Promise} * @returns {Promise}
*/ */
deleteConfig: (host_type, host, throw_errors) => { deleteConfig: (host_type, host, delete_err_file) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_'); const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
const config_file_err = config_file + '.err';
return new Promise((resolve, reject) => { return new Promise((resolve/*, reject*/) => {
try { internalNginx.deleteFile(config_file);
let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id); if (delete_err_file) {
internalNginx.deleteFile(config_file_err);
if (debug_mode) {
logger.warn('Deleting nginx config: ' + config_file);
}
fs.unlinkSync(config_file);
} catch (err) {
if (debug_mode) {
logger.warn('Could not delete config:', err.message);
}
if (throw_errors) {
reject(err);
}
} }
resolve(); resolve();
}); });
}, },
/**
* @param {String} host_type
* @param {Object} [host]
* @returns {Promise}
*/
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';
return new Promise((resolve/*, reject*/) => {
fs.unlink(config_file, () => {
// ignore result, continue
fs.rename(config_file, config_file_err, () => {
// also ignore result, as this is a debugging informative file anyway
resolve();
});
});
});
},
/** /**
* @param {String} host_type * @param {String} host_type
* @param {Array} hosts * @param {Array} hosts
@ -399,13 +401,12 @@ const internalNginx = {
/** /**
* @param {String} host_type * @param {String} host_type
* @param {Array} hosts * @param {Array} hosts
* @param {Boolean} [throw_errors]
* @returns {Promise} * @returns {Promise}
*/ */
bulkDeleteConfigs: (host_type, hosts, throw_errors) => { bulkDeleteConfigs: (host_type, hosts) => {
let promises = []; let promises = [];
hosts.map(function (host) { hosts.map(function (host) {
promises.push(internalNginx.deleteConfig(host_type, host, throw_errors)); promises.push(internalNginx.deleteConfig(host_type, host, true));
}); });
return Promise.all(promises); return Promise.all(promises);
@ -415,8 +416,8 @@ const internalNginx = {
* @param {string} config * @param {string} config
* @returns {boolean} * @returns {boolean}
*/ */
advancedConfigHasDefaultLocation: function (config) { advancedConfigHasDefaultLocation: function (cfg) {
return !!config.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im); return !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
}, },
/** /**

View File

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const proxyHostModel = require('../models/proxy_host'); const proxyHostModel = require('../models/proxy_host');
const internalHost = require('./host'); const internalHost = require('./host');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
@ -49,8 +50,8 @@ const internalProxyHost = {
return proxyHostModel return proxyHostModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (create_certificate) { if (create_certificate) {
@ -170,6 +171,7 @@ const internalProxyHost = {
.query() .query()
.where({id: data.id}) .where({id: data.id})
.patch(data) .patch(data)
.then(utils.omitRow(omissions()))
.then((saved_row) => { .then((saved_row) => {
// Add to audit log // Add to audit log
return internalAuditLog.add(access, { return internalAuditLog.add(access, {
@ -179,7 +181,7 @@ const internalProxyHost = {
meta: data meta: data
}) })
.then(() => { .then(() => {
return _.omit(saved_row, omissions()); return saved_row;
}); });
}); });
}) })
@ -223,31 +225,29 @@ const internalProxyHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[owner,access_list,access_list.[clients,items],certificate]') .allowGraph('[owner,access_list,access_list.[clients,items],certificate]')
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1)); query.andWhere('owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
row = internalHost.cleanRowCertificateMeta(row);
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -409,8 +409,7 @@ const internalProxyHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[owner,access_list,certificate]')
.allowEager('[owner,access_list,certificate]')
.orderBy('domain_names', 'ASC'); .orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -425,10 +424,10 @@ const internalProxyHost = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}) })
.then((rows) => { .then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) { if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {

View File

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const redirectionHostModel = require('../models/redirection_host'); const redirectionHostModel = require('../models/redirection_host');
const internalHost = require('./host'); const internalHost = require('./host');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
@ -49,8 +50,8 @@ const internalRedirectionHost = {
return redirectionHostModel return redirectionHostModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (create_certificate) { if (create_certificate) {
@ -65,9 +66,8 @@ const internalRedirectionHost = {
.then(() => { .then(() => {
return row; return row;
}); });
} else {
return row;
} }
return row;
}) })
.then((row) => { .then((row) => {
// re-fetch with cert // re-fetch with cert
@ -218,31 +218,29 @@ const internalRedirectionHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[owner,certificate]') .allowGraph('[owner,certificate]')
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1)); query.andWhere('owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
row = internalHost.cleanRowCertificateMeta(row);
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -404,8 +402,7 @@ const internalRedirectionHost = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[owner,certificate]')
.allowEager('[owner,certificate]')
.orderBy('domain_names', 'ASC'); .orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -420,10 +417,10 @@ const internalRedirectionHost = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}) })
.then((rows) => { .then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) { if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {

View File

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const streamModel = require('../models/stream'); const streamModel = require('../models/stream');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
const internalAuditLog = require('./audit-log'); const internalAuditLog = require('./audit-log');
@ -27,8 +28,8 @@ const internalStream = {
return streamModel return streamModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
// Configure nginx // Configure nginx
@ -71,8 +72,8 @@ const internalStream = {
return streamModel return streamModel
.query() .query()
.omit(omissions())
.patchAndFetchById(row.id, data) .patchAndFetchById(row.id, data)
.then(utils.omitRow(omissions()))
.then((saved_row) => { .then((saved_row) => {
return internalNginx.configure(streamModel, 'stream', saved_row) return internalNginx.configure(streamModel, 'stream', saved_row)
.then(() => { .then(() => {
@ -88,7 +89,7 @@ const internalStream = {
meta: data meta: data
}) })
.then(() => { .then(() => {
return _.omit(saved_row, omissions()); return saved_row;
}); });
}); });
}); });
@ -113,30 +114,28 @@ const internalStream = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[owner]') .allowGraph('[owner]')
.first(); .first();
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1)); query.andWhere('owner_user_id', access.token.getUserId(1));
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -298,8 +297,7 @@ const internalStream = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[owner]')
.allowEager('[owner]')
.orderBy('incoming_port', 'ASC'); .orderBy('incoming_port', 'ASC');
if (access_data.permission_visibility !== 'all') { if (access_data.permission_visibility !== 'all') {
@ -314,10 +312,10 @@ const internalStream = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}); });
}, },

View File

@ -24,7 +24,7 @@ module.exports = {
return userModel return userModel
.query() .query()
.where('email', data.identity) .where('email', data.identity.toLowerCase().trim())
.andWhere('is_deleted', 0) .andWhere('is_deleted', 0)
.andWhere('is_disabled', 0) .andWhere('is_disabled', 0)
.first() .first()

View File

@ -1,5 +1,6 @@
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils');
const userModel = require('../models/user'); const userModel = require('../models/user');
const userPermissionModel = require('../models/user_permission'); const userPermissionModel = require('../models/user_permission');
const authModel = require('../models/auth'); const authModel = require('../models/auth');
@ -35,8 +36,8 @@ const internalUser = {
return userModel return userModel
.query() .query()
.omit(omissions()) .insertAndFetch(data)
.insertAndFetch(data); .then(utils.omitRow(omissions()));
}) })
.then((user) => { .then((user) => {
if (auth) { if (auth) {
@ -140,11 +141,8 @@ const internalUser = {
return userModel return userModel
.query() .query()
.omit(omissions())
.patchAndFetchById(user.id, data) .patchAndFetchById(user.id, data)
.then((saved_user) => { .then(utils.omitRow(omissions()));
return _.omit(saved_user, omissions());
});
}) })
.then(() => { .then(() => {
return internalUser.get(access, {id: data.id}); return internalUser.get(access, {id: data.id});
@ -186,26 +184,24 @@ const internalUser = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.andWhere('id', data.id) .andWhere('id', data.id)
.allowEager('[permissions]') .allowGraph('[permissions]')
.first(); .first();
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) { if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']'); query.withGraphFetched('[' + data.expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRow(omissions()));
}) })
.then((row) => { .then((row) => {
if (row) { if (!row) {
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id); throw new error.ItemNotFoundError(data.id);
} }
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
row = _.omit(row, data.omit);
}
return row;
}); });
}, },
@ -322,8 +318,7 @@ const internalUser = {
.query() .query()
.where('is_deleted', 0) .where('is_deleted', 0)
.groupBy('id') .groupBy('id')
.omit(['is_deleted']) .allowGraph('[permissions]')
.allowEager('[permissions]')
.orderBy('name', 'ASC'); .orderBy('name', 'ASC');
// Query is used for searching // Query is used for searching
@ -335,10 +330,10 @@ const internalUser = {
} }
if (typeof expand !== 'undefined' && expand !== null) { if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']'); query.withGraphFetched('[' + expand.join(', ') + ']');
} }
return query; return query.then(utils.omitRows(omissions()));
}); });
}, },

View File

@ -55,8 +55,8 @@ module.exports = function (token_string) {
.where('id', token_data.attrs.id) .where('id', token_data.attrs.id)
.andWhere('is_deleted', 0) .andWhere('is_deleted', 0)
.andWhere('is_disabled', 0) .andWhere('is_disabled', 0)
.allowEager('[permissions]') .allowGraph('[permissions]')
.eager('[permissions]') .withGraphFetched('[permissions]')
.first() .first()
.then((user) => { .then((user) => {
if (user) { if (user) {

184
backend/lib/config.js Normal file
View File

@ -0,0 +1,184 @@
const fs = require('fs');
const NodeRSA = require('node-rsa');
const logger = require('../logger').global;
const keysFile = '/data/keys.json';
let instance = null;
// 1. Load from config file first (not recommended anymore)
// 2. Use config env variables next
const configure = () => {
const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
if (fs.existsSync(filename)) {
let configData;
try {
configData = require(filename);
} catch (err) {
// do nothing
}
if (configData && configData.database) {
logger.info(`Using configuration from file: ${filename}`);
instance = configData;
instance.keys = getKeys();
return;
}
}
const envMysqlHost = process.env.DB_MYSQL_HOST || null;
const envMysqlUser = process.env.DB_MYSQL_USER || null;
const envMysqlName = process.env.DB_MYSQL_NAME || null;
if (envMysqlHost && envMysqlUser && envMysqlName) {
// we have enough mysql creds to go with mysql
logger.info('Using MySQL configuration');
instance = {
database: {
engine: 'mysql',
host: envMysqlHost,
port: process.env.DB_MYSQL_PORT || 3306,
user: envMysqlUser,
password: process.env.DB_MYSQL_PASSWORD,
name: envMysqlName,
},
keys: getKeys(),
};
return;
}
const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
logger.info(`Using Sqlite: ${envSqliteFile}`);
instance = {
database: {
engine: 'knex-native',
knex: {
client: 'sqlite3',
connection: {
filename: envSqliteFile
},
useNullAsDefault: true
}
},
keys: getKeys(),
};
};
const getKeys = () => {
// Get keys from file
if (!fs.existsSync(keysFile)) {
generateKeys();
} else if (process.env.DEBUG) {
logger.info('Keys file exists OK');
}
try {
return require(keysFile);
} catch (err) {
logger.error('Could not read JWT key pair from config file: ' + keysFile, err);
process.exit(1);
}
};
const generateKeys = () => {
logger.info('Creating a new JWT key pair...');
// Now create the keys and save them in the config.
const key = new NodeRSA({ b: 2048 });
key.generateKeyPair();
const keys = {
key: key.exportKey('private').toString(),
pub: key.exportKey('public').toString(),
};
// Write keys config
try {
fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
} catch (err) {
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message);
process.exit(1);
}
logger.info('Wrote JWT key pair to config file: ' + keysFile);
};
module.exports = {
/**
*
* @param {string} key ie: 'database' or 'database.engine'
* @returns {boolean}
*/
has: function(key) {
instance === null && configure();
const keys = key.split('.');
let level = instance;
let has = true;
keys.forEach((keyItem) =>{
if (typeof level[keyItem] === 'undefined') {
has = false;
} else {
level = level[keyItem];
}
});
return has;
},
/**
* Gets a specific key from the top level
*
* @param {string} key
* @returns {*}
*/
get: function (key) {
instance === null && configure();
if (key && typeof instance[key] !== 'undefined') {
return instance[key];
}
return instance;
},
/**
* Is this a sqlite configuration?
*
* @returns {boolean}
*/
isSqlite: function () {
instance === null && configure();
return instance.database.knex && instance.database.knex.client === 'sqlite3';
},
/**
* Are we running in debug mdoe?
*
* @returns {boolean}
*/
debug: function () {
return !!process.env.DEBUG;
},
/**
* Returns a public key
*
* @returns {string}
*/
getPublicKey: function () {
instance === null && configure();
return instance.keys.pub;
},
/**
* Returns a private key
*
* @returns {string}
*/
getPrivateKey: function () {
instance === null && configure();
return instance.keys.key;
},
/**
* @returns {boolean}
*/
useLetsencryptStaging: function () {
return !!process.env.LE_STAGING;
}
};

View File

@ -1,4 +1,8 @@
const exec = require('child_process').exec; const _ = require('lodash');
const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const { Liquid } = require('liquidjs');
const logger = require('../logger').global;
module.exports = { module.exports = {
@ -16,5 +20,82 @@ module.exports = {
} }
}); });
}); });
},
/**
* @param {String} cmd
* @param {Array} args
* @returns {Promise}
*/
execFile: function (cmd, args) {
logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
return new Promise((resolve, reject) => {
execFile(cmd, args, function (err, stdout, /*stderr*/) {
if (err && typeof err === 'object') {
reject(err);
} else {
resolve(stdout.trim());
}
});
});
},
/**
* Used in objection query builder
*
* @param {Array} omissions
* @returns {Function}
*/
omitRow: function (omissions) {
/**
* @param {Object} row
* @returns {Object}
*/
return (row) => {
return _.omit(row, omissions);
};
},
/**
* Used in objection query builder
*
* @param {Array} omissions
* @returns {Function}
*/
omitRows: function (omissions) {
/**
* @param {Array} rows
* @returns {Object}
*/
return (rows) => {
rows.forEach((row, idx) => {
rows[idx] = _.omit(row, omissions);
});
return rows;
};
},
/**
* @returns {Object} Liquid render engine
*/
getRenderEngine: function () {
const renderEngine = new Liquid({
root: __dirname + '/../templates/'
});
/**
* nginxAccessRule expects the object given to have 2 properties:
*
* directive string
* address string
*/
renderEngine.registerFilter('nginxAccessRule', (v) => {
if (typeof v.directive !== 'undefined' && typeof v.address !== 'undefined' && v.directive && v.address) {
return `${v.directive} ${v.address};`;
}
return '';
});
return renderEngine;
} }
}; };

View File

@ -5,7 +5,7 @@ const definitions = require('../../schema/definitions.json');
RegExp.prototype.toJSON = RegExp.prototype.toString; RegExp.prototype.toJSON = RegExp.prototype.toString;
const ajv = require('ajv')({ const ajv = require('ajv')({
verbose: true, //process.env.NODE_ENV === 'development', verbose: true,
allErrors: true, allErrors: true,
format: 'full', // strict regexes for format checks format: 'full', // strict regexes for format checks
coerceTypes: true, coerceTypes: true,

View File

@ -50,7 +50,6 @@ class AccessList extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
}, },
items: { items: {
@ -59,9 +58,6 @@ class AccessList extends Model {
join: { join: {
from: 'access_list.id', from: 'access_list.id',
to: 'access_list_auth.access_list_id' to: 'access_list_auth.access_list_id'
},
modify: function (qb) {
qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
} }
}, },
clients: { clients: {
@ -70,9 +66,6 @@ class AccessList extends Model {
join: { join: {
from: 'access_list.id', from: 'access_list.id',
to: 'access_list_client.access_list_id' to: 'access_list_client.access_list_id'
},
modify: function (qb) {
qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
} }
}, },
proxy_hosts: { proxy_hosts: {
@ -84,19 +77,10 @@ class AccessList extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('proxy_host.is_deleted', 0); qb.where('proxy_host.is_deleted', 0);
qb.omit(['is_deleted', 'meta']);
} }
} }
}; };
} }
get satisfy() {
return this.satisfy_any ? 'satisfy any' : 'satisfy all';
}
get passauth() {
return this.pass_auth ? '' : 'proxy_set_header Authorization "";';
}
} }
module.exports = AccessList; module.exports = AccessList;

View File

@ -45,7 +45,6 @@ class AccessListAuth extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('access_list.is_deleted', 0); qb.where('access_list.is_deleted', 0);
qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
} }
} }
}; };

View File

@ -45,15 +45,10 @@ class AccessListClient extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('access_list.is_deleted', 0); qb.where('access_list.is_deleted', 0);
qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
} }
} }
}; };
} }
get rule() {
return `${this.directive} ${this.address}`;
}
} }
module.exports = AccessListClient; module.exports = AccessListClient;

View File

@ -43,9 +43,6 @@ class AuditLog extends Model {
join: { join: {
from: 'audit_log.user_id', from: 'audit_log.user_id',
to: 'user.id' to: 'user.id'
},
modify: function (qb) {
qb.omit(['id', 'created_on', 'modified_on', 'roles']);
} }
} }
}; };

View File

@ -74,9 +74,6 @@ class Auth extends Model {
}, },
filter: { filter: {
is_deleted: 0 is_deleted: 0
},
modify: function (qb) {
qb.omit(['is_deleted']);
} }
} }
}; };

View File

@ -63,7 +63,6 @@ class Certificate extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
} }
}; };

View File

@ -59,7 +59,6 @@ class DeadHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
}, },
certificate: { certificate: {
@ -71,7 +70,6 @@ class DeadHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('certificate.is_deleted', 0); qb.where('certificate.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
} }
} }
}; };

View File

@ -1,13 +1,13 @@
const db = require('../db'); const db = require('../db');
const config = require('config'); const config = require('../lib/config');
const Model = require('objection').Model; const Model = require('objection').Model;
Model.knex(db); Model.knex(db);
module.exports = function () { module.exports = function () {
if (config.database.knex && config.database.knex.client === 'sqlite3') { if (config.isSqlite()) {
return Model.raw('datetime(\'now\',\'localtime\')'); // eslint-disable-next-line
} else { return Model.raw("datetime('now','localtime')");
return Model.raw('NOW()');
} }
return Model.raw('NOW()');
}; };

View File

@ -60,7 +60,6 @@ class ProxyHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
}, },
access_list: { access_list: {
@ -72,7 +71,6 @@ class ProxyHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('access_list.is_deleted', 0); qb.where('access_list.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
} }
}, },
certificate: { certificate: {
@ -84,7 +82,6 @@ class ProxyHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('certificate.is_deleted', 0); qb.where('certificate.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
} }
} }
}; };

View File

@ -1,3 +1,4 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
@ -59,7 +60,6 @@ class RedirectionHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
}, },
certificate: { certificate: {
@ -71,7 +71,6 @@ class RedirectionHost extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('certificate.is_deleted', 0); qb.where('certificate.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
} }
} }
}; };

View File

@ -46,7 +46,6 @@ class Stream extends Model {
}, },
modify: function (qb) { modify: function (qb) {
qb.where('user.is_deleted', 0); qb.where('user.is_deleted', 0);
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
} }
} }
}; };

View File

@ -6,44 +6,36 @@
const _ = require('lodash'); const _ = require('lodash');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const crypto = require('crypto'); const crypto = require('crypto');
const config = require('../lib/config');
const error = require('../lib/error'); const error = require('../lib/error');
const logger = require('../logger').global;
const ALGO = 'RS256'; const ALGO = 'RS256';
let public_key = null;
let private_key = null;
function checkJWTKeyPair() {
if (!public_key || !private_key) {
let config = require('config');
public_key = config.get('jwt.pub');
private_key = config.get('jwt.key');
}
}
module.exports = function () { module.exports = function () {
let token_data = {}; let token_data = {};
let self = { const self = {
/** /**
* @param {Object} payload * @param {Object} payload
* @returns {Promise} * @returns {Promise}
*/ */
create: (payload) => { create: (payload) => {
if (!config.getPrivateKey()) {
logger.error('Private key is empty!');
}
// sign with RSA SHA256 // sign with RSA SHA256
let options = { const options = {
algorithm: ALGO, algorithm: ALGO,
expiresIn: payload.expiresIn || '1d' expiresIn: payload.expiresIn || '1d'
}; };
payload.jti = crypto.randomBytes(12) payload.jti = crypto.randomBytes(12)
.toString('base64') .toString('base64')
.substr(-8); .substring(-8);
checkJWTKeyPair();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
jwt.sign(payload, private_key, options, (err, token) => { jwt.sign(payload, config.getPrivateKey(), options, (err, token) => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
@ -62,13 +54,15 @@ module.exports = function () {
* @returns {Promise} * @returns {Promise}
*/ */
load: function (token) { load: function (token) {
if (!config.getPublicKey()) {
logger.error('Public key is empty!');
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
checkJWTKeyPair();
try { try {
if (!token || token === null || token === 'null') { if (!token || token === null || token === 'null') {
reject(new error.AuthError('Empty token')); reject(new error.AuthError('Empty token'));
} else { } else {
jwt.verify(token, public_key, {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => { jwt.verify(token, config.getPublicKey(), {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
if (err) { if (err) {
if (err.name === 'TokenExpiredError') { if (err.name === 'TokenExpiredError') {
@ -83,8 +77,6 @@ module.exports = function () {
// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'. // Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
// For 30 days at least, we need to replace 'all' with user. // For 30 days at least, we need to replace 'all' with user.
if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) { if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
//console.log('Warning! Replacing "all" scope with "user"');
token_data.scope = ['user']; token_data.scope = ['user'];
} }
@ -134,7 +126,7 @@ module.exports = function () {
* @returns {Integer} * @returns {Integer}
*/ */
getUserId: (default_value) => { getUserId: (default_value) => {
let attrs = self.get('attrs'); const attrs = self.get('attrs');
if (attrs && typeof attrs.id !== 'undefined' && attrs.id) { if (attrs && typeof attrs.id !== 'undefined' && attrs.id) {
return attrs.id; return attrs.id;
} }

View File

@ -43,9 +43,6 @@ class User extends Model {
join: { join: {
from: 'user.id', from: 'user.id',
to: 'user_permission.user_id' to: 'user_permission.user_id'
},
modify: function (qb) {
qb.omit(['id', 'created_on', 'modified_on', 'user_id']);
} }
} }
}; };

View File

@ -10,23 +10,21 @@
"bcrypt": "^5.0.0", "bcrypt": "^5.0.0",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"compression": "^1.7.4", "compression": "^1.7.4",
"config": "^3.3.1", "express": "^4.17.3",
"express": "^4.17.1",
"express-fileupload": "^1.1.9", "express-fileupload": "^1.1.9",
"gravatar": "^1.8.0", "gravatar": "^1.8.0",
"json-schema-ref-parser": "^8.0.0", "json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"knex": "^0.20.13", "knex": "2.4.2",
"liquidjs": "^9.11.10", "liquidjs": "10.6.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.24.0", "moment": "^2.29.4",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-rsa": "^1.0.8", "node-rsa": "^1.0.8",
"nodemon": "^2.0.2", "objection": "3.0.1",
"objection": "^2.2.16",
"path": "^0.12.7", "path": "^0.12.7",
"signale": "^1.4.0", "signale": "1.4.0",
"sqlite3": "^4.1.1", "sqlite3": "5.1.6",
"temp-write": "^4.0.0" "temp-write": "^4.0.0"
}, },
"signale": { "signale": {
@ -36,8 +34,9 @@
"author": "Jamie Curnow <jc@jc21.com>", "author": "Jamie Curnow <jc@jc21.com>",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"eslint": "^6.8.0", "eslint": "^8.36.0",
"eslint-plugin-align-assignments": "^1.1.2", "eslint-plugin-align-assignments": "^1.1.2",
"nodemon": "^2.0.2",
"prettier": "^2.0.4" "prettier": "^2.0.4"
} }
} }

View File

@ -1,6 +1,4 @@
const fs = require('fs'); const config = require('./lib/config');
const NodeRSA = require('node-rsa');
const config = require('config');
const logger = require('./logger').setup; const logger = require('./logger').setup;
const certificateModel = require('./models/certificate'); const certificateModel = require('./models/certificate');
const userModel = require('./models/user'); const userModel = require('./models/user');
@ -9,62 +7,6 @@ const utils = require('./lib/utils');
const authModel = require('./models/auth'); const authModel = require('./models/auth');
const settingModel = require('./models/setting'); const settingModel = require('./models/setting');
const dns_plugins = require('./global/certbot-dns-plugins'); const dns_plugins = require('./global/certbot-dns-plugins');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
/**
* Creates a new JWT RSA Keypair if not alread set on the config
*
* @returns {Promise}
*/
const setupJwt = () => {
return new Promise((resolve, reject) => {
// Now go and check if the jwt gpg keys have been created and if not, create them
if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) {
logger.info('Creating a new JWT key pair...');
// jwt keys are not configured properly
const filename = config.util.getEnv('NODE_CONFIG_DIR') + '/' + (config.util.getEnv('NODE_ENV') || 'default') + '.json';
let config_data = {};
try {
config_data = require(filename);
} catch (err) {
// do nothing
if (debug_mode) {
logger.debug(filename + ' config file could not be required');
}
}
// Now create the keys and save them in the config.
let key = new NodeRSA({ b: 2048 });
key.generateKeyPair();
config_data.jwt = {
key: key.exportKey('private').toString(),
pub: key.exportKey('public').toString(),
};
// Write config
fs.writeFile(filename, JSON.stringify(config_data, null, 2), (err) => {
if (err) {
logger.error('Could not write JWT key pair to config file: ' + filename);
reject(err);
} else {
logger.info('Wrote JWT key pair to config file: ' + filename);
delete require.cache[require.resolve('config')];
resolve();
}
});
} else {
// JWT key pair exists
if (debug_mode) {
logger.debug('JWT Keypair already exists');
}
resolve();
}
});
};
/** /**
* Creates a default admin users if one doesn't already exist in the database * Creates a default admin users if one doesn't already exist in the database
@ -119,8 +61,8 @@ const setupDefaultUser = () => {
.then(() => { .then(() => {
logger.info('Initial admin setup completed'); logger.info('Initial admin setup completed');
}); });
} else if (debug_mode) { } else if (config.debug()) {
logger.debug('Admin user setup not required'); logger.info('Admin user setup not required');
} }
}); });
}; };
@ -151,8 +93,8 @@ const setupDefaultSettings = () => {
logger.info('Default settings added'); logger.info('Default settings added');
}); });
} }
if (debug_mode) { if (config.debug()) {
logger.debug('Default setting setup not required'); logger.info('Default setting setup not required');
} }
}); });
}; };
@ -174,20 +116,22 @@ const setupCertbotPlugins = () => {
certificates.map(function (certificate) { certificates.map(function (certificate) {
if (certificate.meta && certificate.meta.dns_challenge === true) { if (certificate.meta && certificate.meta.dns_challenge === true) {
const dns_plugin = dns_plugins[certificate.meta.dns_provider]; const dns_plugin = dns_plugins[certificate.meta.dns_provider];
const packages_to_install = `${dns_plugin.package_name}${dns_plugin.version_requirement || ''} ${dns_plugin.dependencies}`;
const packages_to_install = `${dns_plugin.package_name}${dns_plugin.version_requirement || ''} ${dns_plugin.dependencies}`;
if (plugins.indexOf(packages_to_install) === -1) plugins.push(packages_to_install); if (plugins.indexOf(packages_to_install) === -1) plugins.push(packages_to_install);
// Make sure credentials file exists // Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id; const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }'; // 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 + '\'; }';
promises.push(utils.exec(credentials_cmd)); promises.push(utils.exec(credentials_cmd));
} }
}); });
if (plugins.length) { if (plugins.length) {
const install_cmd = 'pip install ' + plugins.join(' '); const install_cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugins.join(' ') + ' && deactivate';
promises.push(utils.exec(install_cmd)); promises.push(utils.exec(install_cmd));
} }
@ -223,8 +167,7 @@ const setupLogrotation = () => {
}; };
module.exports = function () { module.exports = function () {
return setupJwt() return setupDefaultUser()
.then(setupDefaultUser)
.then(setupDefaultSettings) .then(setupDefaultSettings)
.then(setupCertbotPlugins) .then(setupCertbotPlugins)
.then(setupLogrotation); .then(setupLogrotation);

View File

@ -0,0 +1,25 @@
{% if access_list_id > 0 %}
{% if access_list.items.length > 0 %}
# Authorization
auth_basic "Authorization required";
auth_basic_user_file /data/access/{{ access_list_id }};
{% if access_list.pass_auth == 0 %}
proxy_set_header Authorization "";
{% endif %}
{% endif %}
# Access Rules: {{ access_list.clients | size }} total
{% for client in access_list.clients %}
{{client | nginxAccessRule}}
{% endfor %}
deny all;
# Access checks must...
{% if access_list.satisfy_any == 1 %}
satisfy any;
{% else %}
satisfy all;
{% endif %}
{% endif %}

View File

@ -6,30 +6,9 @@
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }}; proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
{% if access_list_id > 0 %} {% include "_access.conf" %}
{% if access_list.items.length > 0 %}
# Authorization
auth_basic "Authorization required";
auth_basic_user_file /data/access/{{ access_list_id }};
{{ access_list.passauth }}
{% endif %}
# Access Rules
{% for client in access_list.clients %}
{{- client.rule -}};
{% endfor %}deny all;
# Access checks must...
{% if access_list.satisfy %}
{{ access_list.satisfy }};
{% endif %}
{% endif %}
{% include "_assets.conf" %} {% include "_assets.conf" %}
{% include "_exploits.conf" %} {% include "_exploits.conf" %}
{% include "_forced_ssl.conf" %} {% include "_forced_ssl.conf" %}
{% include "_hsts.conf" %} {% include "_hsts.conf" %}

View File

@ -7,9 +7,9 @@
server { server {
listen 80 default; listen 80 default;
{% if ipv6 -%} {% if ipv6 -%}
listen [::]:80; listen [::]:80 default;
{% else -%} {% else -%}
#listen [::]:80; #listen [::]:80 default;
{% endif %} {% endif %}
server_name default-host.localhost; server_name default-host.localhost;
access_log /data/logs/default-host_access.log combined; access_log /data/logs/default-host_access.log combined;

View File

@ -30,27 +30,7 @@ proxy_http_version 1.1;
location / { location / {
{% if access_list_id > 0 %} {% include "_access.conf" %}
{% if access_list.items.length > 0 %}
# Authorization
auth_basic "Authorization required";
auth_basic_user_file /data/access/{{ access_list_id }};
{{ access_list.passauth }}
{% endif %}
# Access Rules
{% for client in access_list.clients %}
{{- client.rule -}};
{% endfor %}deny all;
# Access checks must...
{% if access_list.satisfy %}
{{ access_list.satisfy }};
{% endif %}
{% endif %}
{% include "_hsts.conf" %} {% include "_hsts.conf" %}
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %} {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,20 @@
# This file assumes that the frontend has been built using ./scripts/frontend-build # This file assumes that the frontend has been built using ./scripts/frontend-build
FROM nginxproxymanager/nginx-full:node FROM jc21/nginx-full:certbot-node
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG BUILD_VERSION ARG BUILD_VERSION
ARG BUILD_COMMIT ARG BUILD_COMMIT
ARG BUILD_DATE ARG BUILD_DATE
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
ENV SUPPRESS_NO_CONFIG_WARNING=1 \ ENV SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \ S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_KILL_FINISH_MAXTIME=10000 \
S6_VERBOSITY=1 \
NODE_ENV=production \ NODE_ENV=production \
NPM_BUILD_VERSION="${BUILD_VERSION}" \ NPM_BUILD_VERSION="${BUILD_VERSION}" \
NPM_BUILD_COMMIT="${BUILD_COMMIT}" \ NPM_BUILD_COMMIT="${BUILD_COMMIT}" \
@ -25,7 +29,7 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# s6 overlay # s6 overlay
COPY scripts/install-s6 /tmp/install-s6 COPY docker/scripts/install-s6 /tmp/install-s6
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6 RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
EXPOSE 80 81 443 EXPOSE 80 81 443
@ -35,16 +39,17 @@ COPY frontend/dist /app/frontend
COPY global /app/global COPY global /app/global
WORKDIR /app WORKDIR /app
RUN yarn install RUN yarn install \
&& yarn cache clean
# add late to limit cache-busting by modifications # add late to limit cache-busting by modifications
COPY docker/rootfs / COPY docker/rootfs /
# Remove frontend service not required for prod, dev nginx config as well # Remove frontend service not required for prod, dev nginx config as well
RUN rm -rf /etc/services.d/frontend /etc/nginx/conf.d/dev.conf RUN rm -rf /etc/services.d/frontend /etc/nginx/conf.d/dev.conf \
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager \
# Change permission of logrotate config file && pip uninstall --yes setuptools \
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager && pip install --no-cache-dir "setuptools==58.0.0"
VOLUME [ "/data", "/etc/letsencrypt" ] VOLUME [ "/data", "/etc/letsencrypt" ]
ENTRYPOINT [ "/init" ] ENTRYPOINT [ "/init" ]

View File

@ -1,13 +1,17 @@
FROM nginxproxymanager/nginx-full:node FROM jc21/nginx-full:certbot-node
LABEL maintainer="Jamie Curnow <jc@jc21.com>" LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV S6_LOGGING=0 \ # See: https://github.com/just-containers/s6-overlay/blob/master/README.md
SUPPRESS_NO_CONFIG_WARNING=1 \ ENV SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1 S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_KILL_FINISH_MAXTIME=10000 \
S6_VERBOSITY=2
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \ && apt-get update \
&& apt-get install -y certbot jq python3-pip logrotate \ && apt-get install -y jq python3-pip logrotate \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
@ -21,9 +25,8 @@ RUN rm -f /etc/nginx/conf.d/production.conf
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
# s6 overlay # s6 overlay
RUN curl -L -o /tmp/s6-overlay-amd64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz" \ COPY scripts/install-s6 /tmp/install-s6
&& tar -xzf /tmp/s6-overlay-amd64.tar.gz -C / RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
EXPOSE 80 81 443 EXPOSE 80 81 443
ENTRYPOINT [ "/init" ] ENTRYPOINT [ "/init" ]

View File

@ -1,17 +1,18 @@
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production. # WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
version: "3" version: '3.8'
services: services:
fullstack-mysql: fullstack-mysql:
image: ${IMAGE}:ci-${BUILD_NUMBER} image: "${IMAGE}:ci-${BUILD_NUMBER}"
environment: environment:
NODE_ENV: "development" DEBUG: 'true'
LE_STAGING: 'true'
FORCE_COLOR: 1 FORCE_COLOR: 1
DB_MYSQL_HOST: "db" DB_MYSQL_HOST: 'db'
DB_MYSQL_PORT: 3306 DB_MYSQL_PORT: '3306'
DB_MYSQL_USER: "npm" DB_MYSQL_USER: 'npm'
DB_MYSQL_PASSWORD: "npm" DB_MYSQL_PASSWORD: 'npm'
DB_MYSQL_NAME: "npm" DB_MYSQL_NAME: 'npm'
volumes: volumes:
- npm_data:/data - npm_data:/data
expose: expose:
@ -26,11 +27,15 @@ services:
timeout: 3s timeout: 3s
fullstack-sqlite: fullstack-sqlite:
image: ${IMAGE}:ci-${BUILD_NUMBER} image: "${IMAGE}:ci-${BUILD_NUMBER}"
environment: environment:
NODE_ENV: "development" DEBUG: 'true'
LE_STAGING: 'true'
FORCE_COLOR: 1 FORCE_COLOR: 1
DB_SQLITE_FILE: "/data/database.sqlite" DB_SQLITE_FILE: '/data/mydb.sqlite'
PUID: 1000
PGID: 1000
DISABLE_IPV6: 'true'
volumes: volumes:
- npm_data:/data - npm_data:/data
expose: expose:
@ -45,26 +50,26 @@ services:
db: db:
image: jc21/mariadb-aria image: jc21/mariadb-aria
environment: environment:
MYSQL_ROOT_PASSWORD: "npm" MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: "npm" MYSQL_DATABASE: 'npm'
MYSQL_USER: "npm" MYSQL_USER: 'npm'
MYSQL_PASSWORD: "npm" MYSQL_PASSWORD: 'npm'
volumes: volumes:
- db_data:/var/lib/mysql - db_data:/var/lib/mysql
cypress-mysql: cypress-mysql:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER} image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
build: build:
context: ../test/ context: ../test/
dockerfile: cypress/Dockerfile dockerfile: cypress/Dockerfile
environment: environment:
CYPRESS_baseUrl: "http://fullstack-mysql:81" CYPRESS_baseUrl: 'http://fullstack-mysql:81'
volumes: volumes:
- cypress-logs:/results - cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json} command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite: cypress-sqlite:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER} image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
build: build:
context: ../test/ context: ../test/
dockerfile: cypress/Dockerfile dockerfile: cypress/Dockerfile

View File

@ -1,6 +1,7 @@
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production. # WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
version: "3.5" version: '3.8'
services: services:
npm: npm:
image: nginxproxymanager:dev image: nginxproxymanager:dev
container_name: npm_core container_name: npm_core
@ -14,14 +15,19 @@ services:
networks: networks:
- nginx_proxy_manager - nginx_proxy_manager
environment: environment:
NODE_ENV: "development" PUID: 1000
PGID: 1000
FORCE_COLOR: 1 FORCE_COLOR: 1
DEVELOPMENT: "true" # specifically for dev:
DB_MYSQL_HOST: "db" DEBUG: 'true'
DB_MYSQL_PORT: 3306 DEVELOPMENT: 'true'
DB_MYSQL_USER: "npm" LE_STAGING: 'true'
DB_MYSQL_PASSWORD: "npm" # db:
DB_MYSQL_NAME: "npm" DB_MYSQL_HOST: 'db'
DB_MYSQL_PORT: '3306'
DB_MYSQL_USER: 'npm'
DB_MYSQL_PASSWORD: 'npm'
DB_MYSQL_NAME: 'npm'
# DB_SQLITE_FILE: "/data/database.sqlite" # DB_SQLITE_FILE: "/data/database.sqlite"
# DISABLE_IPV6: "true" # DISABLE_IPV6: "true"
volumes: volumes:
@ -42,10 +48,10 @@ services:
networks: networks:
- nginx_proxy_manager - nginx_proxy_manager
environment: environment:
MYSQL_ROOT_PASSWORD: "npm" MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: "npm" MYSQL_DATABASE: 'npm'
MYSQL_USER: "npm" MYSQL_USER: 'npm'
MYSQL_PASSWORD: "npm" MYSQL_PASSWORD: 'npm'
volumes: volumes:
- db_data:/var/lib/mysql - db_data:/var/lib/mysql

View File

@ -0,0 +1,54 @@
#!/bin/bash
set -e
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
export CYAN BLUE YELLOW RED RESET
PUID=${PUID:-0}
PGID=${PGID:-0}
NPMUSER=npm
NPMGROUP=npm
NPMHOME=/tmp/npmuserhome
export NPMUSER NPMGROUP NPMHOME
if [[ "$PUID" -ne '0' ]] && [ "$PGID" = '0' ]; then
# set group id to same as user id,
# the user probably forgot to specify the group id and
# it would be rediculous to intentionally use the root group
# for a non-root user
PGID=$PUID
fi
export PUID PGID
log_info () {
echo -e "${BLUE} ${CYAN}$1${RESET}"
}
log_error () {
echo -e "${RED} $1${RESET}"
}
# The `run` file will only execute 1 line so this helps keep things
# logically separated
log_fatal () {
echo -e "${RED}--------------------------------------${RESET}"
echo -e "${RED}ERROR: $1${RESET}"
echo -e "${RED}--------------------------------------${RESET}"
/run/s6/basedir/bin/halt
exit 1
}
# param $1: group_name
get_group_id () {
if [ "${1:-}" != '' ]; then
getent group "$1" | cut -d: -f3
fi
}

View File

@ -1,46 +0,0 @@
#!/bin/bash
# This command reads the `DISABLE_IPV6` env var and will either enable
# or disable ipv6 in all nginx configs based on this setting.
# Lowercase
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
FOLDER=$1
if [ "$FOLDER" == "" ]; then
echo -e "${RED} $0 requires a absolute folder path as the first argument!${RESET}"
echo -e "${YELLOW} ie: $0 /data/nginx${RESET}"
exit 1
fi
FILES=$(find "$FOLDER" -type f -name "*.conf")
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ]; then
# IPV6 is disabled
echo "Disabling IPV6 in hosts"
echo -e "${BLUE} ${CYAN}Disabling IPV6 in hosts: ${YELLOW}${FOLDER}${RESET}"
# Iterate over configs and run the regex
for FILE in $FILES
do
echo -e " ${BLUE} ${YELLOW}${FILE}${RESET}"
sed -E -i 's/^([^#]*)listen \[::\]/\1#listen [::]/g' "$FILE"
done
else
# IPV6 is enabled
echo -e "${BLUE} ${CYAN}Enabling IPV6 in hosts: ${YELLOW}${FOLDER}${RESET}"
# Iterate over configs and run the regex
for FILE in $FILES
do
echo -e " ${BLUE} ${YELLOW}${FILE}${RESET}"
sed -E -i 's/^(\s*)#listen \[::\]/\1listen [::]/g' "$FILE"
done
fi

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -1,3 +0,0 @@
*
!.gitignore
!*.sh

View File

@ -1,7 +0,0 @@
#!/usr/bin/with-contenv bash
set -e
mkdir -p /data/logs
echo "Changing ownership of /data/logs to $(id -u):$(id -g)"
chown -R "$(id -u):$(id -g)" /data/logs

View File

@ -1,29 +0,0 @@
#!/usr/bin/with-contenv bash
# ref: https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/cont-init.d/01-envfile
# in s6, environmental variables are written as text files for s6 to monitor
# seach through full-path filenames for files ending in "__FILE"
for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do
echo "[secret-init] Evaluating ${FILENAME##*/} ..."
# set SECRETFILE to the contents of the full-path textfile
SECRETFILE=$(cat ${FILENAME})
# SECRETFILE=${FILENAME}
# echo "[secret-init] Set SECRETFILE to ${SECRETFILE}" # DEBUG - rm for prod!
# if SECRETFILE exists / is not null
if [[ -f ${SECRETFILE} ]]; then
# strip the appended "__FILE" from environmental variable name ...
STRIPFILE=$(echo ${FILENAME} | sed "s/__FILE//g")
# echo "[secret-init] Set STRIPFILE to ${STRIPFILE}" # DEBUG - rm for prod!
# ... and set value to contents of secretfile
# since s6 uses text files, this is effectively "export ..."
printf $(cat ${SECRETFILE}) > ${STRIPFILE}
# echo "[secret-init] Set ${STRIPFILE##*/} to $(cat ${STRIPFILE})" # DEBUG - rm for prod!"
echo "[secret-init] Success! ${STRIPFILE##*/} set from ${FILENAME##*/}"
else
echo "[secret-init] cannot find secret in ${FILENAME}"
fi
done

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -30,11 +30,9 @@ server {
set $port "443"; set $port "443";
server_name localhost; server_name localhost;
access_log /data/logs/fallback-access.log standard; access_log /data/logs/fallback_access.log standard;
error_log /dev/null crit; error_log /dev/null crit;
ssl_certificate /data/nginx/dummycert.pem; ssl_reject_handshake on;
ssl_certificate_key /data/nginx/dummykey.pem;
include conf.d/include/ssl-ciphers.conf;
return 444; return 444;
} }

View File

@ -1,4 +1,4 @@
location ~* ^.*\.(css|js|jpe?g|gif|png|woff|eot|ttf|svg|ico|css\.map|js\.map)$ { location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
if_modified_since off; if_modified_since off;
# use the public cache # use the public cache

View File

@ -2,7 +2,7 @@ add_header X-Served-By $host;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port$request_uri; proxy_pass $forward_scheme://$server:$port$request_uri;

View File

@ -1,7 +1,7 @@
# run nginx in foreground # run nginx in foreground
daemon off; daemon off;
pid /run/nginx/nginx.pid;
user root; user npm;
# Set number of worker processes automatically based on number of CPU cores. # Set number of worker processes automatically based on number of CPU cores.
worker_processes auto; worker_processes auto;
@ -15,7 +15,7 @@ error_log /data/logs/fallback_error.log warn;
include /etc/nginx/modules/*.conf; include /etc/nginx/modules/*.conf;
events { events {
worker_connections 1024; include /data/nginx/custom/events[.]conf;
} }
http { http {

View File

@ -0,0 +1,21 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
. /bin/common.sh
cd /app || exit 1
log_info 'Starting backend ...'
if [ "${DEVELOPMENT:-}" = 'true' ]; then
s6-setuidgid "$PUID:$PGID" yarn install
exec s6-setuidgid "$PUID:$PGID" bash -c "export HOME=$NPMHOME;node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js"
else
while :
do
s6-setuidgid "$PUID:$PGID" bash -c "export HOME=$NPMHOME;node --abort_on_uncaught_exception --max_old_space_size=250 index.js"
sleep 1
done
fi

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,21 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
# This service is DEVELOPMENT only.
if [ "$DEVELOPMENT" = 'true' ]; then
. /bin/common.sh
cd /app/frontend || exit 1
HOME=$NPMHOME
export HOME
mkdir -p /app/frontend/dist
chown -R "$PUID:$PGID" /app/frontend/dist
log_info 'Starting frontend ...'
s6-setuidgid "$PUID:$PGID" yarn install
exec s6-setuidgid "$PUID:$PGID" yarn watch
else
exit 0
fi

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,9 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
. /bin/common.sh
log_info 'Starting nginx ...'
exec s6-setuidgid "$PUID:$PGID" nginx

View File

@ -0,0 +1 @@
longrun

View File

@ -0,0 +1,22 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
. /bin/common.sh
if [ "$(id -u)" != "0" ]; then
log_fatal "This docker container must be run as root, do not specify a user.\nYou can specify PUID and PGID env vars to run processes as that user and group after initialization."
fi
if [ "$DEBUG" = "true" ]; then
set -x
fi
. /etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh
. /etc/s6-overlay/s6-rc.d/prepare/20-paths.sh
. /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh
. /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh
. /etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh
. /etc/s6-overlay/s6-rc.d/prepare/60-secrets.sh
. /etc/s6-overlay/s6-rc.d/prepare/90-banner.sh

View File

@ -0,0 +1,40 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
log_info "Configuring $NPMUSER user ..."
if id -u "$NPMUSER" 2>/dev/null; then
# user already exists
usermod -u "$PUID" "$NPMUSER"
else
# Add user
useradd -o -u "$PUID" -U -d "$NPMHOME" -s /bin/false "$NPMUSER"
fi
log_info "Configuring $NPMGROUP group ..."
if [ "$(get_group_id "$NPMGROUP")" = '' ]; then
# Add group. This will not set the id properly if it's already taken
groupadd -f -g "$PGID" "$NPMGROUP"
else
groupmod -o -g "$PGID" "$NPMGROUP"
fi
# Set the group ID and check it
groupmod -o -g "$PGID" "$NPMGROUP"
if [ "$(get_group_id "$NPMGROUP")" != "$PGID" ]; then
echo "ERROR: Unable to set group id properly"
exit 1
fi
# Set the group against the user and check it
usermod -G "$PGID" "$NPMGROUP"
if [ "$(id -g "$NPMUSER")" != "$PGID" ] ; then
echo "ERROR: Unable to set group against the user properly"
exit 1
fi
# Home for user
mkdir -p "$NPMHOME"
chown -R "$PUID:$PGID" "$NPMHOME"

View File

@ -0,0 +1,41 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
log_info 'Checking paths ...'
# Ensure /data is mounted
if [ ! -d '/data' ]; then
log_fatal '/data is not mounted! Check your docker configuration.'
fi
# Ensure /etc/letsencrypt is mounted
if [ ! -d '/etc/letsencrypt' ]; then
log_fatal '/etc/letsencrypt is not mounted! Check your docker configuration.'
fi
# Create required folders
mkdir -p \
/data/nginx \
/data/custom_ssl \
/data/logs \
/data/access \
/data/nginx/default_host \
/data/nginx/default_www \
/data/nginx/proxy_host \
/data/nginx/redirection_host \
/data/nginx/stream \
/data/nginx/dead_host \
/data/nginx/temp \
/data/letsencrypt-acme-challenge \
/run/nginx \
/tmp/nginx/body \
/var/log/nginx \
/var/lib/nginx/cache/public \
/var/lib/nginx/cache/private \
/var/cache/nginx/proxy_temp
touch /var/log/nginx/error.log || true
chmod 777 /var/log/nginx/error.log || true
chmod -R 777 /var/cache/nginx || true
chmod 644 /etc/logrotate.d/nginx-proxy-manager

View File

@ -0,0 +1,27 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
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
# 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
# Prevents errors when installing python certbot plugins when non-root
chown -R "$PUID:$PGID" /opt/certbot

View File

@ -0,0 +1,17 @@
#!/command/with-contenv bash
# shellcheck shell=bash
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
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
fi

View File

@ -0,0 +1,39 @@
#!/command/with-contenv bash
# shellcheck shell=bash
# This command reads the `DISABLE_IPV6` env var and will either enable
# or disable ipv6 in all nginx configs based on this setting.
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
# IPV6 is disabled
echo "Disabling IPV6 in hosts in: $1"
SED_REGEX='s/^([^#]*)listen \[::\]/\1#listen [::]/g'
else
# IPV6 is enabled
echo "Enabling IPV6 in hosts in: $1"
SED_REGEX='s/^(\s*)#listen \[::\]/\1listen [::]/g'
fi
for FILE in $FILES
do
echo "- ${FILE}"
sed -E -i "$SED_REGEX" "$FILE"
done
# ensure the files are still owned by the npm user
chown -R "$PUID:$PGID" "$1"
}
process_folder /etc/nginx/conf.d
process_folder /data/nginx

View File

@ -0,0 +1,30 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
# in s6, environmental variables are written as text files for s6 to monitor
# search through full-path filenames for files ending in "__FILE"
log_info 'Docker secrets ...'
for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do
echo "[secret-init] Evaluating ${FILENAME##*/} ..."
# set SECRETFILE to the contents of the full-path textfile
SECRETFILE=$(cat "${FILENAME}")
# if SECRETFILE exists / is not null
if [[ -f "${SECRETFILE}" ]]; then
# strip the appended "__FILE" from environmental variable name ...
STRIPFILE=$(echo "${FILENAME}" | sed "s/__FILE//g")
# echo "[secret-init] Set STRIPFILE to ${STRIPFILE}" # DEBUG - rm for prod!
# ... and set value to contents of secretfile
# since s6 uses text files, this is effectively "export ..."
printf $(cat "${SECRETFILE}") > "${STRIPFILE}"
# echo "[secret-init] Set ${STRIPFILE##*/} to $(cat ${STRIPFILE})" # DEBUG - rm for prod!"
echo "Success: ${STRIPFILE##*/} set from ${FILENAME##*/}"
else
echo "Cannot find secret in ${FILENAME}"
fi
done

View File

@ -0,0 +1,18 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
set +x
echo "
-------------------------------------
_ _ ____ __ __
| \ | | _ \| \/ |
| \| | |_) | |\/| |
| |\ | __/| | | |
|_| \_|_| |_| |_|
-------------------------------------
User: $NPMUSER PUID:$PUID ID:$(id -u "$NPMUSER") GROUP:$(id -g "$NPMUSER")
Group: $NPMGROUP PGID:$PGID ID:$(get_group_id "$NPMGROUP")
-------------------------------------
"

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1,2 @@
# shellcheck shell=bash
/etc/s6-overlay/s6-rc.d/prepare/00-all.sh

View File

@ -1,6 +0,0 @@
#!/usr/bin/execlineb -S1
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@ -1,12 +0,0 @@
#!/usr/bin/with-contenv bash
# This service is DEVELOPMENT only.
if [ "$DEVELOPMENT" == "true" ]; then
cd /app/frontend || exit 1
# If yarn install fails: add --verbose --network-concurrency 1
yarn install
yarn watch
else
exit 0
fi

View File

@ -1,3 +0,0 @@
#!/usr/bin/with-contenv bash
s6-svscanctl -t /var/run/s6/services

View File

@ -1,19 +0,0 @@
#!/usr/bin/with-contenv bash
mkdir -p /data/letsencrypt-acme-challenge
cd /app || echo
if [ "$DEVELOPMENT" == "true" ]; then
cd /app || exit 1
# If yarn install fails: add --verbose --network-concurrency 1
yarn install
node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js
else
cd /app || exit 1
while :
do
node --abort_on_uncaught_exception --max_old_space_size=250 index.js
sleep 1
done
fi

View File

@ -1 +0,0 @@
/bin/true

View File

@ -1,49 +0,0 @@
#!/usr/bin/with-contenv bash
# Create required folders
mkdir -p /tmp/nginx/body \
/run/nginx \
/var/log/nginx \
/data/nginx \
/data/custom_ssl \
/data/logs \
/data/access \
/data/nginx/default_host \
/data/nginx/default_www \
/data/nginx/proxy_host \
/data/nginx/redirection_host \
/data/nginx/stream \
/data/nginx/dead_host \
/data/nginx/temp \
/var/lib/nginx/cache/public \
/var/lib/nginx/cache/private \
/var/cache/nginx/proxy_temp
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
chown root /tmp/nginx
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
# thanks @tfmm
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
# Generate dummy self-signed certificate.
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]
then
echo "Generating dummy SSL certificate..."
openssl req \
-new \
-newkey rsa:2048 \
-days 3650 \
-nodes \
-x509 \
-subj '/O=localhost/OU=localhost/CN=localhost' \
-keyout /data/nginx/dummykey.pem \
-out /data/nginx/dummycert.pem
echo "Complete"
fi
# Handle IPV6 settings
/bin/handle-ipv6-setting /etc/nginx/conf.d
/bin/handle-ipv6-setting /data/nginx
exec nginx

View File

@ -8,8 +8,8 @@ BLUE='\E[1;34m'
GREEN='\E[1;32m' GREEN='\E[1;32m'
RESET='\E[0m' RESET='\E[0m'
S6_OVERLAY_VERSION=1.22.1.0 S6_OVERLAY_VERSION=3.1.5.0
TARGETPLATFORM=$1 TARGETPLATFORM=${1:unspecified}
# Determine the correct binary file for the architecture given # Determine the correct binary file for the architecture given
case $TARGETPLATFORM in case $TARGETPLATFORM in
@ -22,13 +22,17 @@ case $TARGETPLATFORM in
;; ;;
*) *)
S6_ARCH=amd64 S6_ARCH=x86_64
;; ;;
esac esac
echo -e "${BLUE} ${CYAN}Installing S6-overlay v${S6_OVERLAY_VERSION} for ${YELLOW}${TARGETPLATFORM} (${S6_ARCH})${RESET}" echo -e "${BLUE} ${CYAN}Installing S6-overlay v${S6_OVERLAY_VERSION} for ${YELLOW}${TARGETPLATFORM} (${S6_ARCH})${RESET}"
curl -L -o "/tmp/s6-overlay-${S6_ARCH}.tar.gz" "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.gz" \ curl -L -o '/tmp/s6-overlay-noarch.tar.xz' "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz"
&& tar -xzf "/tmp/s6-overlay-${S6_ARCH}.tar.gz" -C / curl -L -o "/tmp/s6-overlay-${S6_ARCH}.tar.xz" "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz"
tar -C / -Jxpf '/tmp/s6-overlay-noarch.tar.xz'
tar -C / -Jxpf "/tmp/s6-overlay-${S6_ARCH}.tar.xz"
rm -rf "/tmp/s6-overlay-${S6_ARCH}.tar.xz"
echo -e "${BLUE} ${GREEN}S6-overlay install Complete${RESET}" echo -e "${BLUE} ${GREEN}S6-overlay install Complete${RESET}"

View File

@ -1,5 +1,26 @@
# Advanced Configuration # Advanced Configuration
## Running processes as a user/group
By default, the services (nginx etc) will run as `root` user inside the docker container.
You can change this behaviour by setting the following environment variables.
Not only will they run the services as this user/group, they will change the ownership
on the `data` and `letsencrypt` folders at startup.
```yml
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
environment:
PUID: 1000
PGID: 1000
# ...
```
This may have the side effect of a failed container start due to permission denied trying
to open port 80 on some systems. The only course to fix that is to remove the variables
and run as the default root user.
## Best Practice: Use a Docker network ## Best Practice: Use a Docker network
For those who have a few of their upstream services running in Docker on the same Docker For those who have a few of their upstream services running in Docker on the same Docker
@ -18,14 +39,14 @@ services running on this Docker host:
```yml ```yml
networks: networks:
default: default:
external: external: true
name: scoobydoo name: scoobydoo
``` ```
Let's look at a Portainer example: Let's look at a Portainer example:
```yml ```yml
version: '3' version: '3.8'
services: services:
portainer: portainer:
@ -38,8 +59,8 @@ services:
networks: networks:
default: default:
external: external: true
name: scoobydoo name: scoobydoo
``` ```
Now in the NPM UI you can create a proxy host with `portainer` as the hostname, Now in the NPM UI you can create a proxy host with `portainer` as the hostname,
@ -60,14 +81,14 @@ healthcheck:
timeout: 3s timeout: 3s
``` ```
## Docker Secrets ## Docker File Secrets
This image supports the use of Docker secrets to import from file and keep sensitive usernames or passwords from being passed or preserved in plaintext. This image supports the use of Docker secrets to import from files and keep sensitive usernames or passwords from being passed or preserved in plaintext.
You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name. You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name.
```yml ```yml
version: "3.7" version: '3.8'
secrets: secrets:
# Secrets are single-line text files where the sole content is the secret # Secrets are single-line text files where the sole content is the secret
@ -96,9 +117,7 @@ services:
# DB_MYSQL_PASSWORD: "npm" # use secret instead # DB_MYSQL_PASSWORD: "npm" # use secret instead
DB_MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD DB_MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
DB_MYSQL_NAME: "npm" DB_MYSQL_NAME: "npm"
# If you would rather use Sqlite uncomment this # If you would rather use Sqlite, remove all DB_MYSQL_* lines above
# and remove all DB_MYSQL_* lines above
# DB_SQLITE_FILE: "/data/database.sqlite"
# Uncomment this if IPv6 is not enabled on your host # Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true' # DISABLE_IPV6: 'true'
volumes: volumes:
@ -108,6 +127,7 @@ services:
- MYSQL_PWD - MYSQL_PWD
depends_on: depends_on:
- db - db
db: db:
image: jc21/mariadb-aria image: jc21/mariadb-aria
restart: unless-stopped restart: unless-stopped
@ -151,6 +171,7 @@ You can add your custom configuration snippet files at `/data/nginx/custom` as f
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf - `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block - `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
- `/data/nginx/custom/http.conf`: Included at the end of the main http block - `/data/nginx/custom/http.conf`: Included at the end of the main http block
- `/data/nginx/custom/events.conf`: Included at the end of the events block
- `/data/nginx/custom/stream.conf`: Included at the end of the main stream block - `/data/nginx/custom/stream.conf`: Included at the end of the main stream block
- `/data/nginx/custom/server_proxy.conf`: Included at the end of every proxy server block - `/data/nginx/custom/server_proxy.conf`: Included at the end of every proxy server block
- `/data/nginx/custom/server_redirect.conf`: Included at the end of every redirection server block - `/data/nginx/custom/server_redirect.conf`: Included at the end of every redirection server block

View File

@ -21,3 +21,6 @@ Your best bet is to ask the [Reddit community for support](https://www.reddit.co
Gitter is best left for anyone contributing to the project to ask for help about internals, code reviews etc. Gitter is best left for anyone contributing to the project to ask for help about internals, code reviews etc.
## When adding username and password access control to a proxy host, I can no longer login into the app.
Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the `Authorization` header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the `Authorization` header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the [internet standard](https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2) and almost all apps do not support multiple values in the `Authorization` header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.

View File

@ -16,7 +16,7 @@
"alphanum-sort": "^1.0.2", "alphanum-sort": "^1.0.2",
"ansi-colors": "^4.1.1", "ansi-colors": "^4.1.1",
"ansi-escapes": "^4.3.1", "ansi-escapes": "^4.3.1",
"ansi-html": "^0.0.7", "ansi-html": "^0.0.8",
"ansi-regex": "^5.0.0", "ansi-regex": "^5.0.0",
"ansi-styles": "^4.2.1", "ansi-styles": "^4.2.1",
"anymatch": "^3.1.1", "anymatch": "^3.1.1",
@ -213,7 +213,7 @@
"etag": "^1.8.1", "etag": "^1.8.1",
"eventemitter3": "^4.0.4", "eventemitter3": "^4.0.4",
"events": "^3.2.0", "events": "^3.2.0",
"eventsource": "^1.0.7", "eventsource": "^2.0.2",
"evp_bytestokey": "^1.0.3", "evp_bytestokey": "^1.0.3",
"execa": "^4.0.3", "execa": "^4.0.3",
"expand-brackets": "^4.0.0", "expand-brackets": "^4.0.0",
@ -357,7 +357,7 @@
"jsbn": "^1.1.0", "jsbn": "^1.1.0",
"jsesc": "^3.0.1", "jsesc": "^3.0.1",
"json-parse-better-errors": "^1.0.2", "json-parse-better-errors": "^1.0.2",
"json-schema": "^0.2.5", "json-schema": "^0.4.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"json-stringify-safe": "^5.0.1", "json-stringify-safe": "^5.0.1",
"json3": "^3.3.3", "json3": "^3.3.3",
@ -394,7 +394,7 @@
"map-age-cleaner": "^0.1.3", "map-age-cleaner": "^0.1.3",
"map-cache": "^0.2.2", "map-cache": "^0.2.2",
"map-visit": "^1.0.0", "map-visit": "^1.0.0",
"markdown-it": "^11.0.0", "markdown-it": "^12.3.2",
"markdown-it-anchor": "^5.3.0", "markdown-it-anchor": "^5.3.0",
"markdown-it-chain": "^1.3.0", "markdown-it-chain": "^1.3.0",
"markdown-it-container": "^3.0.0", "markdown-it-container": "^3.0.0",
@ -434,7 +434,7 @@
"neo-async": "^2.6.2", "neo-async": "^2.6.2",
"nice-try": "^2.0.1", "nice-try": "^2.0.1",
"no-case": "^3.0.3", "no-case": "^3.0.3",
"node-forge": "^0.10.0", "node-forge": "^1.0.0",
"node-libs-browser": "^2.2.1", "node-libs-browser": "^2.2.1",
"node-releases": "^1.1.60", "node-releases": "^1.1.60",
"nopt": "^4.0.3", "nopt": "^4.0.3",

View File

@ -5,7 +5,7 @@
Create a `docker-compose.yml` file: Create a `docker-compose.yml` file:
```yml ```yml
version: "3" version: '3.8'
services: services:
app: app:
image: 'jc21/nginx-proxy-manager:latest' image: 'jc21/nginx-proxy-manager:latest'
@ -51,7 +51,7 @@ are going to use.
Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container: Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container:
```yml ```yml
version: "3" version: '3.8'
services: services:
app: app:
image: 'jc21/nginx-proxy-manager:latest' image: 'jc21/nginx-proxy-manager:latest'
@ -64,6 +64,7 @@ services:
# Add any other Stream port you want to expose # Add any other Stream port you want to expose
# - '21:21' # FTP # - '21:21' # FTP
environment: environment:
# Mysql/Maria connection parameters:
DB_MYSQL_HOST: "db" DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306 DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm" DB_MYSQL_USER: "npm"
@ -86,7 +87,7 @@ services:
MYSQL_USER: 'npm' MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm' MYSQL_PASSWORD: 'npm'
volumes: volumes:
- ./data/mysql:/var/lib/mysql - ./mysql:/var/lib/mysql
``` ```
::: warning ::: warning
@ -107,7 +108,7 @@ you don't have to worry about doing anything special and you can follow the comm
Check out the [dockerhub tags](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags) Check out the [dockerhub tags](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags)
for a list of supported architectures and if you want one that doesn't exist, for a list of supported architectures and if you want one that doesn't exist,
[create a feature request](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=). [create a feature request](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
Also, if you don't know how to already, follow [this guide to install docker and docker-compose](https://manre-universe.net/how-to-run-docker-and-docker-compose-on-raspbian/) Also, if you don't know how to already, follow [this guide to install docker and docker-compose](https://manre-universe.net/how-to-run-docker-and-docker-compose-on-raspbian/)
on Raspbian. on Raspbian.
@ -118,13 +119,12 @@ Please note that the `jc21/mariadb-aria:latest` image might have some problems o
After the app is running for the first time, the following will happen: After the app is running for the first time, the following will happen:
1. The database will initialize with table structures 1. GPG keys will be generated and saved in the data folder
2. GPG keys will be generated and saved in the configuration file 2. The database will initialize with table structures
3. A default admin user will be created 3. A default admin user will be created
This process can take a couple of minutes depending on your machine. This process can take a couple of minutes depending on your machine.
## Default Administrator User ## Default Administrator User
``` ```
@ -134,49 +134,3 @@ Password: changeme
Immediately after logging in with this default user you will be asked to modify your details and change your password. Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Configuration File
::: warning
This section is meant for advanced users
:::
If you would like more control over the database settings you can define a custom config JSON file.
Here's an example for `sqlite` configuration as it is generated from the environment variables:
```json
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
},
"useNullAsDefault": true
}
}
}
```
You can modify the `knex` object with your custom configuration, but note that not all knex clients might be installed in the image.
Once you've created your configuration file you can mount it to `/app/config/production.json` inside you container using:
```
[...]
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
[...]
volumes:
- ./config.json:/app/config/production.json
[...]
[...]
```
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation.
These keys affect the login and session management of the application. If these keys change for any reason, all users will be logged out.

View File

@ -1,6 +1,6 @@
# Third Party # Third Party
As this software gains popularity it's common to see it integrated with other platforms. Please be aware that unless specifically mentioned in the documenation of those As this software gains popularity it's common to see it integrated with other platforms. Please be aware that unless specifically mentioned in the documentation of those
integrations, they are *not supported* by me. integrations, they are *not supported* by me.
Known integrations: Known integrations:

View File

@ -9,3 +9,4 @@ This project will automatically update any databases or other requirements so yo
any crazy instructions. These steps above will pull the latest updates and recreate the docker any crazy instructions. These steps above will pull the latest updates and recreate the docker
containers. containers.
See the [list of releases](https://github.com/NginxProxyManager/nginx-proxy-manager/releases) for any upgrade steps specific to each release.

View File

@ -967,6 +967,51 @@
lodash "^4.17.19" lodash "^4.17.19"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@leichtgewicht/ip-codec@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
"@mrmlnc/readdir-enhanced@^2.2.1": "@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@ -1478,13 +1523,13 @@ abbrev@1, abbrev@^1.1.1:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8:
version "1.3.7" version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
dependencies: dependencies:
mime-types "~2.1.24" mime-types "~2.1.34"
negotiator "0.6.2" negotiator "0.6.3"
acorn@^6.4.1: acorn@^6.4.1:
version "6.4.1" version "6.4.1"
@ -1496,6 +1541,11 @@ acorn@^7.4.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c"
integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==
acorn@^8.5.0:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
agentkeepalive@^2.2.0: agentkeepalive@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-2.2.0.tgz#c5d1bd4b129008f1163f236f86e5faea2026e2ef"
@ -1608,11 +1658,16 @@ ansi-escapes@^4.1.0, ansi-escapes@^4.2.1, ansi-escapes@^4.3.1:
dependencies: dependencies:
type-fest "^0.11.0" type-fest "^0.11.0"
ansi-html@0.0.7, ansi-html@^0.0.7: ansi-html@0.0.7:
version "0.0.7" version "0.0.7"
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4=
ansi-html@^0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.8.tgz#e969db193b12bcdfa6727b29ffd8882dc13cc501"
integrity sha512-QROYz1I1Kj+8bTYgx0IlMBpRSCIU+7GjbE0oH+KF7QKc+qSF8YAlIutN59Db17tXN70Ono9upT9Ht0iG93W7ug==
ansi-regex@^2.0.0: ansi-regex@^2.0.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@ -1686,6 +1741,11 @@ argparse@^1.0.10, argparse@^1.0.7:
dependencies: dependencies:
sprintf-js "~1.0.2" sprintf-js "~1.0.2"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
arr-diff@^4.0.0: arr-diff@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
@ -1830,9 +1890,9 @@ async@^2.6.2:
lodash "^4.17.14" lodash "^4.17.14"
async@^3.2.0: async@^3.2.0:
version "3.2.0" version "3.2.2"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd"
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
@ -2010,21 +2070,21 @@ bn.js@^5.1.1, bn.js@^5.1.2:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA== integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
body-parser@1.19.0, body-parser@^1.19.0: body-parser@1.19.2, body-parser@^1.19.0:
version "1.19.0" version "1.19.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
dependencies: dependencies:
bytes "3.1.0" bytes "3.1.2"
content-type "~1.0.4" content-type "~1.0.4"
debug "2.6.9" debug "2.6.9"
depd "~1.1.2" depd "~1.1.2"
http-errors "1.7.2" http-errors "1.8.1"
iconv-lite "0.4.24" iconv-lite "0.4.24"
on-finished "~2.3.0" on-finished "~2.3.0"
qs "6.7.0" qs "6.9.7"
raw-body "2.4.0" raw-body "2.4.3"
type-is "~1.6.17" type-is "~1.6.18"
bonjour@^3.5.0: bonjour@^3.5.0:
version "3.5.0" version "3.5.0"
@ -2224,6 +2284,11 @@ bytes@3.1.0, bytes@^3.1.0:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
bytes@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
cac@^6.5.6, cac@^6.6.1: cac@^6.5.6, cac@^6.6.1:
version "6.6.1" version "6.6.1"
resolved "https://registry.yarnpkg.com/cac/-/cac-6.6.1.tgz#3dde3f6943f45d42a56729ea3573c08b3e7b6a6d" resolved "https://registry.yarnpkg.com/cac/-/cac-6.6.1.tgz#3dde3f6943f45d42a56729ea3573c08b3e7b6a6d"
@ -2339,6 +2404,14 @@ cacheable-request@^6.0.0:
normalize-url "^4.1.0" normalize-url "^4.1.0"
responselike "^1.0.2" responselike "^1.0.2"
call-bind@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
dependencies:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
call-me-maybe@^1.0.1: call-me-maybe@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
@ -2791,12 +2864,12 @@ constants-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
content-disposition@0.5.3, content-disposition@^0.5.3: content-disposition@0.5.4, content-disposition@^0.5.3:
version "0.5.3" version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
dependencies: dependencies:
safe-buffer "5.1.2" safe-buffer "5.2.1"
content-type@^1.0.4, content-type@~1.0.4: content-type@^1.0.4, content-type@~1.0.4:
version "1.0.4" version "1.0.4"
@ -2820,15 +2893,10 @@ cookie-signature@^1.1.0:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.1.0.tgz#cc94974f91fb9a9c1bb485e95fc2b7f4b120aff2" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.1.0.tgz#cc94974f91fb9a9c1bb485e95fc2b7f4b120aff2"
integrity sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A== integrity sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==
cookie@0.4.0: cookie@0.4.2, cookie@^0.4.1:
version "0.4.0" version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookie@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
copy-concurrently@^1.0.0, copy-concurrently@^1.0.5: copy-concurrently@^1.0.0, copy-concurrently@^1.0.5:
version "1.0.5" version "1.0.5"
@ -3279,9 +3347,9 @@ decamelize@^4.0.0:
integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
decode-uri-component@^0.2.0: decode-uri-component@^0.2.0:
version "0.2.0" version "0.2.1"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.1.tgz#e9d7afd716fc1a7ec6ae7cc0aa3e540a1eac2e9d"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= integrity sha512-XZHyaFJ6QMWhYmlz+UcmtaLeecNiXwkTGzCqG5WByt+1P1HnU6Siwf0TeP3OsZmlnGqQRSEMIxue0LLCaGY3dw==
decompress-response@^3.3.0: decompress-response@^3.3.0:
version "3.3.0" version "3.3.0"
@ -3501,11 +3569,11 @@ dns-packet@^4.0.0:
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
dns-packet@^5.2.1: dns-packet@^5.2.1:
version "5.2.2" version "5.4.0"
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.2.2.tgz#e4c7d12974cc320b0c0d4b9bbbf68ac151cfe81e" resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b"
integrity sha512-sQN+vLwC3PvOXiCH/oHcdzML2opFeIdVh8gjjMZrM45n4dR80QF6o3AzInQy6F9Eoc0VJYog4JpQTilt4RFLYQ== integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==
dependencies: dependencies:
ip "^1.1.5" "@leichtgewicht/ip-codec" "^2.0.1"
dns-txt@^2.0.2: dns-txt@^2.0.2:
version "2.0.2" version "2.0.2"
@ -3744,10 +3812,10 @@ entities@^1.1.1, entities@~1.1.1:
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
entities@^2.0.0, entities@^2.0.3, entities@~2.0.0: entities@^2.0.0, entities@^2.0.3, entities@~2.1.0:
version "2.0.3" version "2.1.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
envify@^4.0.0, envify@^4.1.0: envify@^4.0.0, envify@^4.1.0:
version "4.1.0" version "4.1.0"
@ -3925,6 +3993,11 @@ eventsource@^1.0.7:
dependencies: dependencies:
original "^1.0.0" original "^1.0.0"
eventsource@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508"
integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==
evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
@ -3985,16 +4058,16 @@ expand-brackets@^4.0.0:
to-regex "^3.0.1" to-regex "^3.0.1"
express@^4.17.1: express@^4.17.1:
version "4.17.1" version "4.17.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
dependencies: dependencies:
accepts "~1.3.7" accepts "~1.3.8"
array-flatten "1.1.1" array-flatten "1.1.1"
body-parser "1.19.0" body-parser "1.19.2"
content-disposition "0.5.3" content-disposition "0.5.4"
content-type "~1.0.4" content-type "~1.0.4"
cookie "0.4.0" cookie "0.4.2"
cookie-signature "1.0.6" cookie-signature "1.0.6"
debug "2.6.9" debug "2.6.9"
depd "~1.1.2" depd "~1.1.2"
@ -4008,13 +4081,13 @@ express@^4.17.1:
on-finished "~2.3.0" on-finished "~2.3.0"
parseurl "~1.3.3" parseurl "~1.3.3"
path-to-regexp "0.1.7" path-to-regexp "0.1.7"
proxy-addr "~2.0.5" proxy-addr "~2.0.7"
qs "6.7.0" qs "6.9.7"
range-parser "~1.2.1" range-parser "~1.2.1"
safe-buffer "5.1.2" safe-buffer "5.2.1"
send "0.17.1" send "0.17.2"
serve-static "1.14.1" serve-static "1.14.2"
setprototypeof "1.1.1" setprototypeof "1.2.0"
statuses "~1.5.0" statuses "~1.5.0"
type-is "~1.6.18" type-is "~1.6.18"
utils-merge "1.0.1" utils-merge "1.0.1"
@ -4112,6 +4185,13 @@ fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-xml-parser@^3.19.0:
version "3.21.1"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz#152a1d51d445380f7046b304672dd55d15c9e736"
integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==
dependencies:
strnum "^1.0.4"
fastq@^1.6.0: fastq@^1.6.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"
@ -4254,9 +4334,9 @@ flush-write-stream@^2.0.0:
readable-stream "^3.1.1" readable-stream "^3.1.1"
follow-redirects@^1.0.0, follow-redirects@^1.12.1: follow-redirects@^1.0.0, follow-redirects@^1.12.1:
version "1.12.1" version "1.14.8"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg== integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
for-in@^1.0.2: for-in@^1.0.2:
version "1.0.2" version "1.0.2"
@ -4291,7 +4371,12 @@ form-data@~2.3.2:
combined-stream "^1.0.6" combined-stream "^1.0.6"
mime-types "^2.1.12" mime-types "^2.1.12"
forwarded@^0.1.2, forwarded@~0.1.2: forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
forwarded@^0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
@ -4385,6 +4470,15 @@ 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" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.3"
get-stream@^4.0.0, get-stream@^4.1.0: get-stream@^4.0.0, get-stream@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
@ -4638,6 +4732,11 @@ has-symbols@^1.0.0, has-symbols@^1.0.1:
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-value@^0.3.1: has-value@^0.3.1:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@ -4839,27 +4938,16 @@ htmlparser2@^4.1.0:
entities "^2.0.0" entities "^2.0.0"
http-cache-semantics@^4.0.0: http-cache-semantics@^4.0.0:
version "4.1.0" version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
http-deceiver@^1.2.7: http-deceiver@^1.2.7:
version "1.2.7" version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
http-errors@1.7.2: http-errors@1.7.3:
version "1.7.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-errors@1.7.3, http-errors@~1.7.2:
version "1.7.3" version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
@ -4870,6 +4958,17 @@ http-errors@1.7.3, http-errors@~1.7.2:
statuses ">= 1.5.0 < 2" statuses ">= 1.5.0 < 2"
toidentifier "1.0.0" toidentifier "1.0.0"
http-errors@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.1"
http-errors@^1.8.0: http-errors@^1.8.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507"
@ -5530,11 +5629,11 @@ is-svg@^3.0.0:
html-comment-regex "^1.1.0" html-comment-regex "^1.1.0"
is-svg@^4.2.1: is-svg@^4.2.1:
version "4.2.2" version "4.3.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.2.2.tgz#a4ea0f3f78dada7085db88f1e85b6f845626cfae" resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.3.0.tgz#3e46a45dcdb2780e42a3c8538154d7f7bfc07216"
integrity sha512-JlA7Mc7mfWjdxxTkJ094oUK9amGD7gQaj5xA/NCY0vlVvZ1stmj4VX+bRuwOMN93IHRZ2ctpPH/0FO6DqvQ5Rw== integrity sha512-Np3TOGLVr0J27VDaS/gVE7bT45ZcSmX4pMmMTsPjqO8JY383fuPIcWmZr3QsHVWhqhZWxSdmW+tkkl3PWOB0Nw==
dependencies: dependencies:
html-comment-regex "^1.1.2" fast-xml-parser "^3.19.0"
is-symbol@^1.0.2, is-symbol@^1.0.3: is-symbol@^1.0.2, is-symbol@^1.0.3:
version "1.0.3" version "1.0.3"
@ -5714,10 +5813,10 @@ json-schema@0.2.3:
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-schema@^0.2.5: json-schema@^0.4.0:
version "0.2.5" version "0.4.0"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.5.tgz#97997f50972dd0500214e208c407efa4b5d7063b" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
integrity sha512-gWJOWYFrhQ8j7pVm0EM8Slr+EPVq1Phf6lvzvD/WCeqkrx/f2xBI0xOsRRS9xCn3I4vKtP519dvs3TP09r24wQ== integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"
@ -5742,11 +5841,9 @@ json5@^1.0.1:
minimist "^1.2.0" minimist "^1.2.0"
json5@^2.1.2, json5@^2.1.3: json5@^2.1.2, json5@^2.1.3:
version "2.1.3" version "2.2.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab"
integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==
dependencies:
minimist "^1.2.5"
jsonfile@^4.0.0: jsonfile@^4.0.0:
version "4.0.0" version "4.0.0"
@ -5915,9 +6012,9 @@ loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4
json5 "^1.0.1" json5 "^1.0.1"
loader-utils@^2.0.0: loader-utils@^2.0.0:
version "2.0.0" version "2.0.4"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
dependencies: dependencies:
big.js "^5.2.2" big.js "^5.2.2"
emojis-list "^3.0.0" emojis-list "^3.0.0"
@ -6135,13 +6232,13 @@ markdown-it-table-of-contents@^0.4.0, markdown-it-table-of-contents@^0.4.4:
resolved "https://registry.yarnpkg.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz#3dc7ce8b8fc17e5981c77cc398d1782319f37fbc" resolved "https://registry.yarnpkg.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz#3dc7ce8b8fc17e5981c77cc398d1782319f37fbc"
integrity sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw== integrity sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==
markdown-it@^11.0.0: markdown-it@^12.3.2:
version "11.0.0" version "12.3.2"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-11.0.0.tgz#dbfc30363e43d756ebc52c38586b91b90046b876" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90"
integrity sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg== integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==
dependencies: dependencies:
argparse "^1.0.7" argparse "^2.0.1"
entities "~2.0.0" entities "~2.1.0"
linkify-it "^3.0.1" linkify-it "^3.0.1"
mdurl "^1.0.1" mdurl "^1.0.1"
uc.micro "^1.0.5" uc.micro "^1.0.5"
@ -6296,6 +6393,11 @@ mime-db@1.44.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.44.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12, mime-types@^2.1.26, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: mime-types@^2.1.12, mime-types@^2.1.26, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.27" version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@ -6303,6 +6405,13 @@ mime-types@^2.1.12, mime-types@^2.1.26, mime-types@^2.1.27, mime-types@~2.1.17,
dependencies: dependencies:
mime-db "1.44.0" mime-db "1.44.0"
mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@1.6.0: mime@1.6.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@ -6373,9 +6482,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5: minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5" version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
minipass-collect@^1.0.2: minipass-collect@^1.0.2:
version "1.0.2" version "1.0.2"
@ -6492,10 +6601,10 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.1: ms@2.1.3:
version "2.1.1" version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: ms@^2.0.0, ms@^2.1.1, ms@^2.1.2:
version "2.1.2" version "2.1.2"
@ -6555,7 +6664,12 @@ nanomatch@^1.2.13, nanomatch@^1.2.9:
snapdragon "^0.8.1" snapdragon "^0.8.1"
to-regex "^3.0.1" to-regex "^3.0.1"
negotiator@0.6.2, negotiator@^0.6.2: negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
negotiator@^0.6.2:
version "0.6.2" version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
@ -6595,10 +6709,10 @@ node-forge@0.9.0:
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==
node-forge@^0.10.0: node-forge@^1.0.0:
version "0.10.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.0.tgz#37a874ea723855f37db091e6c186e5b67a01d4b2"
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== integrity sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==
node-libs-browser@^2.2.1: node-libs-browser@^2.2.1:
version "2.2.1" version "2.2.1"
@ -6776,6 +6890,11 @@ object-inspect@^1.7.0, object-inspect@^1.8.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
object-inspect@^1.9.0:
version "1.12.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
object-is@^1.0.1, object-is@^1.1.2: object-is@^1.0.1, object-is@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
@ -7659,9 +7778,9 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.2
supports-color "^6.1.0" supports-color "^6.1.0"
postcss@^8.2.10: postcss@^8.2.10:
version "8.2.10" version "8.2.13"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.13.tgz#dbe043e26e3c068e45113b1ed6375d2d37e2129f"
integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw== integrity sha512-FCE5xLH+hjbzRdpbRb1IMCvPv9yZx2QnDarBEYSN0N0HYk+TcXsEhwdFcFb+SRWOKzKGErhIEbBK2ogyLdTtfQ==
dependencies: dependencies:
colorette "^1.2.2" colorette "^1.2.2"
nanoid "^3.1.22" nanoid "^3.1.22"
@ -7706,9 +7825,9 @@ pretty-time@^1.1.0:
integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==
prismjs@^1.13.0, prismjs@^1.20.0: prismjs@^1.13.0, prismjs@^1.20.0:
version "1.25.0" version "1.27.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057"
integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==
private@^0.1.8: private@^0.1.8:
version "0.1.8" version "0.1.8"
@ -7730,12 +7849,12 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
proxy-addr@^2.0.6, proxy-addr@~2.0.5: proxy-addr@^2.0.6, proxy-addr@~2.0.7:
version "2.0.6" version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
dependencies: dependencies:
forwarded "~0.1.2" forwarded "0.2.0"
ipaddr.js "1.9.1" ipaddr.js "1.9.1"
prr@^1.0.1, prr@~1.0.1: prr@^1.0.1, prr@~1.0.1:
@ -7826,15 +7945,17 @@ q@^1.1.2, q@^1.5.1:
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
qs@6.7.0: qs@6.9.7:
version "6.7.0" version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
qs@^6.9.4: qs@^6.9.4:
version "6.9.4" version "6.10.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
dependencies:
side-channel "^1.0.4"
qs@~6.5.2: qs@~6.5.2:
version "6.5.2" version "6.5.2"
@ -7902,13 +8023,13 @@ range-parser@^1.2.1, range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.4.0: raw-body@2.4.3:
version "2.4.0" version "2.4.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
dependencies: dependencies:
bytes "3.1.0" bytes "3.1.2"
http-errors "1.7.2" http-errors "1.8.1"
iconv-lite "0.4.24" iconv-lite "0.4.24"
unpipe "1.0.0" unpipe "1.0.0"
@ -8261,7 +8382,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
version "5.2.1" version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@ -8360,10 +8481,10 @@ semver@^7.3.2:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
send@0.17.1, send@^0.17.1: send@0.17.2, send@^0.17.1:
version "0.17.1" version "0.17.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==
dependencies: dependencies:
debug "2.6.9" debug "2.6.9"
depd "~1.1.2" depd "~1.1.2"
@ -8372,9 +8493,9 @@ send@0.17.1, send@^0.17.1:
escape-html "~1.0.3" escape-html "~1.0.3"
etag "~1.8.1" etag "~1.8.1"
fresh "0.5.2" fresh "0.5.2"
http-errors "~1.7.2" http-errors "1.8.1"
mime "1.6.0" mime "1.6.0"
ms "2.1.1" ms "2.1.3"
on-finished "~2.3.0" on-finished "~2.3.0"
range-parser "~1.2.1" range-parser "~1.2.1"
statuses "~1.5.0" statuses "~1.5.0"
@ -8411,15 +8532,15 @@ serve-index@^1.9.1:
mime-types "~2.1.17" mime-types "~2.1.17"
parseurl "~1.3.2" parseurl "~1.3.2"
serve-static@1.14.1, serve-static@^1.14.1: serve-static@1.14.2, serve-static@^1.14.1:
version "1.14.1" version "1.14.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa"
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==
dependencies: dependencies:
encodeurl "~1.0.2" encodeurl "~1.0.2"
escape-html "~1.0.3" escape-html "~1.0.3"
parseurl "~1.3.3" parseurl "~1.3.3"
send "0.17.1" send "0.17.2"
set-blocking@^2.0.0: set-blocking@^2.0.0:
version "2.0.0" version "2.0.0"
@ -8516,13 +8637,14 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
side-channel@^1.0.2: side-channel@^1.0.2, side-channel@^1.0.4:
version "1.0.2" version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA== integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies: dependencies:
es-abstract "^1.17.0-next.1" call-bind "^1.0.0"
object-inspect "^1.7.0" get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.3" version "3.0.3"
@ -8754,10 +8876,10 @@ source-map-resolve@^0.6.0:
atob "^2.1.2" atob "^2.1.2"
decode-uri-component "^0.2.0" decode-uri-component "^0.2.0"
source-map-support@^0.5.19, source-map-support@~0.5.12: source-map-support@^0.5.19, source-map-support@~0.5.12, source-map-support@~0.5.20:
version "0.5.19" version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies: dependencies:
buffer-from "^1.0.0" buffer-from "^1.0.0"
source-map "^0.6.0" source-map "^0.6.0"
@ -9080,6 +9202,11 @@ strip-json-comments@~2.0.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
strnum@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
stylehacks@^4.0.0, stylehacks@^4.0.3: stylehacks@^4.0.0, stylehacks@^4.0.3:
version "4.0.3" version "4.0.3"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
@ -9224,13 +9351,14 @@ terser@^4.1.2:
source-map-support "~0.5.12" source-map-support "~0.5.12"
terser@^5.0.0: terser@^5.0.0:
version "5.0.0" version "5.14.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.0.0.tgz#269640e4e92f15d628de1e5f01c4c61e1ba3d765" resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
integrity sha512-olH2DwGINoSuEpSGd+BsPuAQaA3OrHnHnFL/rDB2TVNc3srUbz/rq/j2BlF4zDXI+JqAvGr86bIm1R2cJgZ3FA== integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
dependencies: dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
commander "^2.20.0" commander "^2.20.0"
source-map "~0.6.1" source-map-support "~0.5.20"
source-map-support "~0.5.12"
text-table@^0.2.0: text-table@^0.2.0:
version "0.2.0" version "0.2.0"
@ -9349,6 +9477,11 @@ toidentifier@1.0.0, toidentifier@^1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
toidentifier@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
toml@^3.0.0: toml@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
@ -9447,7 +9580,7 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-is@^1.6.18, type-is@~1.6.17, type-is@~1.6.18: type-is@^1.6.18, type-is@~1.6.18:
version "1.6.18" version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
@ -9664,9 +9797,9 @@ url-parse-lax@^3.0.0:
prepend-http "^2.0.0" prepend-http "^2.0.0"
url-parse@^1.4.3, url-parse@^1.4.7: url-parse@^1.4.3, url-parse@^1.4.7:
version "1.5.2" version "1.5.9"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.2.tgz#a4eff6fd5ff9fe6ab98ac1f79641819d13247cda" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.9.tgz#05ff26484a0b5e4040ac64dcee4177223d74675e"
integrity sha512-6bTUPERy1muxxYClbzoRo5qtQuyoGEbzbQvi0SW4/8U8UyVkAQhWFBlnigqJkRm4su4x1zDQfNbEzWkt+vchcg== integrity sha512-HpOvhKBvre8wYez+QhHcYiVvVmeF6DVnuSOOPhe3cTum3BnqHhvKaZm8FU5yTiOu/Jut2ZpB2rA/SbBA1JIGlQ==
dependencies: dependencies:
querystringify "^2.1.1" querystringify "^2.1.1"
requires-port "^1.0.0" requires-port "^1.0.0"

View File

@ -2,6 +2,16 @@
<div class="card-status bg-teal"></div> <div class="card-status bg-teal"></div>
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('audit-log', 'title') %></h3> <h3 class="card-title"><%- i18n('audit-log', 'title') %></h3>
<div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('audit-log', 'search') %>" aria-label="<%- i18n('audit-log', 'search') %>">
</div>
</form>
</div>
</div> </div>
<div class="card-body no-padding min-100"> <div class="card-body no-padding min-100">
<div class="dimmer active"> <div class="dimmer active">

View File

@ -12,39 +12,68 @@ module.exports = Mn.View.extend({
ui: { ui: {
list_region: '.list-region', list_region: '.list-region',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.AuditLog.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new AuditLogModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showAuditLog();
}
}));
console.error(err);
},
showEmpty: function() {
this.showChildView('list_region', new EmptyView({
title: App.i18n('audit-log', 'empty'),
subtitle: App.i18n('audit-log', 'empty-subtitle')
}));
}, },
regions: { regions: {
list_region: '@ui.list_region' list_region: '@ui.list_region'
}, },
events: {
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['user'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
}
},
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.AuditLog.getAll(['user']) view.fetch(['user'])
.then(response => { .then(response => {
if (!view.isDestroyed() && response && response.length) { if (!view.isDestroyed() && response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new AuditLogModel.Collection(response)
}));
} else { } else {
view.showChildView('list_region', new EmptyView({ view.showEmpty();
title: App.i18n('audit-log', 'empty'),
subtitle: App.i18n('audit-log', 'empty-subtitle')
}));
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showAuditLog();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('access-lists', 'title') %></h3> <h3 class="card-title"><%- i18n('access-lists', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('access-lists', 'search') %>" aria-label="<%- i18n('access-lists', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('access-lists', 'add') %></a> <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('access-lists', 'add') %></a>

View File

@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.AccessLists.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new AccessListModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxAccess();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('access_lists');
this.showChildView('list_region', new EmptyView({
title: App.i18n('access-lists', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('access-lists', 'add') : null,
btn_color: 'teal',
permission: 'access_lists',
action: function () {
App.Controller.showNginxAccessListForm();
}
}));
}, },
regions: { regions: {
@ -30,6 +67,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('access-lists', 'help-title'), App.i18n('access-lists', 'help-content')); App.Controller.showHelp(App.i18n('access-lists', 'help-title'), App.i18n('access-lists', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner', 'items', 'clients'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@ -40,39 +88,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.AccessLists.getAll(['owner', 'items', 'clients']) view.fetch(['owner', 'items', 'clients'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new AccessListModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('access_lists'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('access-lists', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('access-lists', 'add') : null,
btn_color: 'teal',
permission: 'access_lists',
action: function () {
App.Controller.showNginxAccessListForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxAccess();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@ -278,9 +278,11 @@ module.exports = Mn.View.extend({
this.ui.credentials_file_content.hide(); this.ui.credentials_file_content.hide();
this.ui.loader_content.hide(); this.ui.loader_content.hide();
this.ui.le_error_info.hide(); this.ui.le_error_info.hide();
const domainNames = this.ui.domain_names[0].value.split(','); if (this.ui.domain_names[0]) {
if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) { const domainNames = this.ui.domain_names[0].value.split(',');
this.ui.test_domains_button.prop('disabled', true); if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) {
this.ui.test_domains_button.prop('disabled', true);
}
} }
}, },

Some files were not shown because too many files have changed in this diff Show More