Compare commits

...

872 Commits

Author SHA1 Message Date
Jamie Curnow
fd30cfe98b Fix linting
Some checks reported errors
bastion/nginx-proxy-manager/pipeline/head Something is wrong with the build of this commit
2022-11-15 07:54:48 +10:00
Jamie Curnow
6f281fef42 Workaround for cloudflare plugin install (#2381) 2022-11-15 07:48:57 +10:00
jc21
41bbfcf165
Merge branch 'master' into develop 2022-11-08 13:32:32 +10:00
Jamie Curnow
80a93e17fa Bump version 2022-11-08 13:31:27 +10:00
Jamie Curnow
4a1eebc54b Linked to contributors instead of managing for every release 2022-11-08 13:30:41 +10:00
jc21
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
jc21
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
Jamie Curnow
d3b72ae07d Fix tabs after web-resolved change 2022-11-08 11:53:13 +10:00
jc21
b62b6b5112
Merge pull request #2373 from lakkeri/develop
Possible multiple X-Forwarded-For headers
2022-11-08 11:48:05 +10:00
jc21
c44f8c6155
Merge pull request #2312 from knoxell/knoxell#add-namecheap
Added Namecheap certbot dns plugin
2022-11-08 11:45:41 +10:00
jc21
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
jc21
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
jc21
662143cf21
Merge branch 'develop' into develop 2022-11-08 11:44:22 +10:00
jc21
c60fc7926e
Merge pull request #2298 from ATCUSA/develop
Update for docker-compose-plugin command
2022-11-08 11:41:57 +10:00
jc21
cfbdc6c340
Merge pull request #2294 from oleban/add-domeneshop-plugin
Added Domeneshop certbot dns plugin
2022-11-08 11:41:34 +10:00
jc21
2f6d8257ec
Merge pull request #2259 from cuishuang/develop
all: fix some typos
2022-11-08 11:40:42 +10:00
jc21
b9a6b5d4f5
Merge pull request #2355 from rovast/patch-1
Update README.md
2022-11-08 11:01:10 +10:00
dependabot[bot]
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
lakkeri
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
ROVAST
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
jc21
5070499cfd
Merge pull request #2335 from Czocher/fix-disable-ipv6
Fix DISABLE_IPV6 flag handling
2022-10-21 08:57:08 +10:00
Paweł Jan Czochański
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
DFS-90
4bb237d7c2
Update certbot-dns-plugins.js
added DomainOffensive (do.de) certbot dns plugin
2022-10-16 00:24:18 +02:00
knoxell
aa5a7faa94 Added Namecheap 2022-10-08 21:53:34 +02:00
Austin
837f4dcbd4 Update for docker-compose-plugin command 2022-10-02 05:05:46 +00:00
Ole Bøe Andreassen
d73a246b66
Added Domeneshop certbot dns plugin 2022-09-28 11:48:31 +02:00
cui fliter
f85e82973d all: fix some typos
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-09-10 21:08:16 +08:00
Niklas Weinhart
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
Jamie Curnow
d2688cf08c CI - don't remove all other images, causing errors in new docker-compose 2022-08-24 07:15:28 +10:00
jc21
7372319568
Merge pull request #2051 from Nobody84/develop
update certbot-dns-duckdns to 0.9
2022-08-23 20:59:16 +10:00
jc21
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
jc21
23c88f6955
Merge pull request #2090 from swazynski/patch-1
Add trailing slash to example
2022-08-23 20:57:04 +10:00
jc21
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
jc21
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
jc21
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
jc21
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
jc21
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
jc21
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
jc21
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
jc21
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
jc21
3d97f4578d
Merge pull request #2206 from phulstaert/patch-1
fix typo
2022-08-23 20:42:59 +10:00
Peter Hulstaert
fb0ef08fd8
fix typo 2022-08-18 09:25:45 +02:00
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
Christian Foellmann
518b84b38b open footer link "Fork me" in new tab/windows (_blank) 2022-06-15 12:20:54 +02:00
swazynski
932dc4bf02
Add trailing slash to example 2022-06-03 15:20:26 +02:00
dependabot[bot]
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
Nobody84
d4dcb61ee6
update certbot-dns-duckdns to 0.9 2022-05-14 00:30:18 +02:00
jc21
cce73beb2d
Merge pull request #1967 from NginxProxyManager/develop
v2.9.18
2022-03-31 15:40:49 +10:00
Jamie Curnow
4db34f5894 Bump version, to trigger rebuild with updated base images 2022-03-31 14:43:41 +10:00
jc21
063ac4619f
Merge pull request #1966 from NginxProxyManager/develop
v2.9.17
2022-03-31 11:32:05 +10:00
jc21
d1a338107b
Merge branch 'master' into develop 2022-03-31 10:21:19 +10:00
Jamie Curnow
0d0b7e117f Bump version 2022-03-31 10:20:27 +10:00
jc21
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
Jamie Curnow
feaafdc559 Fix #1950 attempt to encode hdomain values before render 2022-03-25 08:31:28 +10:00
jc21
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
jc21
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
jc21
bb26f5b2c7
Merge pull request #1863 from omercnet/patch-1
Update resolvers.conf to break dns cache
2022-03-15 07:17:24 +10:00
dependabot[bot]
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
dependabot[bot]
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
jc21
c68874743d
Merge pull request #1864 from NginxProxyManager/develop
v2.9.16
2022-02-19 21:47:15 +10:00
jc21
1a76f4ebfc
Merge branch 'master' into develop 2022-02-17 13:20:44 +10:00
Jamie Curnow
59238d1dc1 Bump version 2022-02-17 13:18:06 +10:00
Jamie Curnow
661f3d6899 Update repo path in docs 2022-02-17 13:15:15 +10:00
jc21
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
Omer Cohen
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
jc21
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
jc21
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
dependabot[bot]
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
Ivan Kristianto
8eb44c404d Add translation for search text 2022-02-12 13:28:16 +07:00
Ivan Kristianto
61b25e1213 Add search feature to Audit Logs 2022-02-12 13:10:23 +07:00
Ivan Kristianto
d3a5a3d0d6 Add search feature to Users 2022-02-12 12:52:22 +07:00
Ivan Kristianto
366fcf0bed Fix nginx/certificates search query 2022-02-12 12:46:06 +07:00
Ivan Kristianto
29c0fcbad6 Add search feature to SSL Certificates 2022-02-12 12:45:29 +07:00
Ivan Kristianto
de84d5d463 Add search feature to Access Lists 2022-02-12 12:17:45 +07:00
Ivan Kristianto
078114ee67 Fix search query for proxy 2022-02-12 11:52:47 +07:00
Ivan Kristianto
49f350fb00 Add search feature to 404 hosts 2022-02-12 11:48:47 +07:00
Ivan Kristianto
e141b5ff20 Add search feature to stream 2022-02-12 11:36:59 +07:00
Ivan Kristianto
181f163cb5 Move render showEmpty into function 2022-02-12 10:40:37 +07:00
Ivan Kristianto
30a9d3ae8d Add search feature to proxy host 2022-02-12 10:38:15 +07:00
lug-gh
83e09ad5a7
Update current year for footer
Update current year for footer
2022-02-05 20:59:21 +01:00
jc21
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
jc21
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
jc21
0edd87324c
Merge pull request #1773 from NginxProxyManager/certbot-dns-transip-update
Update certbot-dns-transip plugin
2022-01-31 09:02:48 +10:00
Ivan Kristianto
96e034aa75 Add search function for redirection 2022-01-30 22:47:42 +07:00
Jamie Curnow
821432263a Update certbot-dns-transip plugin 2022-01-19 07:36:49 +10:00
Jamie Curnow
5edb16f36e Fix failing pip installs, downgrade setuptools 2022-01-17 21:46:26 +10:00
jc21
a233bc0045
Merge pull request #1766 from NginxProxyManager/develop
v2.9.15
2022-01-17 12:08:45 +10:00
dependabot[bot]
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
dependabot[bot]
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
jc21
51ac4bc688
Merge branch 'master' into develop 2022-01-17 10:53:03 +10:00
Jamie Curnow
4f97592965 Bump version 2022-01-17 10:48:57 +10:00
jc21
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
jc21
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
jc21
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
jc21
5e98ce32b7
Merge pull request #1764 from troykelly/troykelly#add-constellix
Added Constellix as DNS auth method
2022-01-17 10:45:02 +10:00
Troy Kelly
a2c01655f0 Added Constellix 2022-01-15 09:48:04 +00:00
dependabot[bot]
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
dependabot[bot]
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
dependabot[bot]
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
Jamie Curnow
1f3ac7a9ec And update the docker org too 2022-01-11 11:52:25 +10:00
Jamie Curnow
5bd002a568 Forgot to update this docker base image 2022-01-11 11:28:01 +10:00
Jamie Curnow
5fb0cc5fab No need to symlink python, done in base image now 2022-01-11 11:17:19 +10:00
Jamie Curnow
818b9595aa Use renamed nginx-full docker images 2022-01-11 08:57:24 +10:00
Jamie Curnow
c78f641e85 Revert #1614
as it breaks some existing services
2022-01-11 08:54:40 +10:00
jc21
081380c8d5
Merge pull request #1716 from jc21/develop
v2.9.14
2022-01-02 22:31:12 +10:00
jc21
7e451bce0b
Merge pull request #1688 from jlesage/resolvers-fix
Fixed generation of resolvers.conf.
2022-01-02 22:05:32 +10:00
jc21
a082ec0604
Merge pull request #1600 from jc21/updates-dnspod-dns-challenge
Fixes dnspod credentials template
2022-01-02 22:05:15 +10:00
Jamie Curnow
973a10a9d1 Bump version 2022-01-02 21:33:16 +10:00
Jamie Curnow
1ec95096d5 Ensure backend build is pulling node:latest first 2022-01-02 21:24:16 +10:00
chaptergy
e81cc45405 Updates dnspod challenge credentials 2022-01-02 11:49:18 +01:00
jc21
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
jc21
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
jc21
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
jc21
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
jc21
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
jc21
29ee48530c
Merge pull request #1703 from luoweihua7/develop
fetch cloudflare ipv4/ipv6 fail #1405
2022-01-02 15:28:58 +10:00
jc21
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
jc21
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
chaptergy
4e17fb476b Adds tencent cloud as dns challenge provider 2022-01-01 17:57:17 +01:00
chaptergy
c803ec7e26 Adds delay after reloading nginx before requesting ssl certificate using http challenge 2021-12-30 13:21:21 +01:00
Larify
7e67f33766 fetch cloudflare ipv4/ipv6 fail #1405 2021-12-30 11:50:21 +08:00
chaptergy
9dd5644183 Correctly escape backslashes in dns plugin credentials 2021-12-29 16:30:49 +01:00
chaptergy
5a8028a72d Adds FAQ entry for acl plus login 2021-12-29 11:35:59 +01:00
chaptergy
747de511d4 Sets certbot official dns plugin version requirement to match certbot version 2021-12-29 09:54:59 +01:00
Tobias Kneidl
7800938fd2 Update default.conf 2021-12-28 18:58:22 +00:00
chaptergy
ab80fe13e9 Fixes custom certificate upload modal 2021-12-28 18:58:22 +00:00
Jamie Curnow
5d106c4064 Bump version 2021-12-28 18:58:22 +00:00
Jamie Curnow
2ac1026e4b Hack for python binary in newer node images 2021-12-28 18:58:22 +00:00
chaptergy
b78c7e1c53 Fixes dnspod credentials template 2021-12-27 21:13:27 +01:00
Jocelyn Le Sage
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
Jocelyn Le Sage
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
jc21
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
jc21
40b1521f72
Merge pull request #1677 from jc21/fixes-custom-certificate-modal
Fixes custom certificate upload modal
2021-12-27 11:02:16 +10:00
chaptergy
ac23c66659 Fixes custom certificate upload modal 2021-12-23 12:23:30 +01:00
jc21
84bc33db8a
Merge pull request #1667 from jc21/develop
v2.9.13
2021-12-22 11:53:02 +10:00
jc21
6392df36c3
Merge branch 'master' into develop 2021-12-22 11:52:27 +10:00
Jamie Curnow
c82843279c Bump version 2021-12-22 11:51:32 +10:00
Jamie Curnow
b394eb8e55 Hack for python binary in newer node images 2021-12-22 11:05:57 +10:00
Tobias Kneidl
bb422d4454
Update default.conf 2021-12-22 00:24:05 +01:00
Paul Mansfield
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
jc21
d45f39aae3
Merge pull request #1538 from jc21/adds-http-challenge-test
Adds buttons to test availability of server from public internet
2021-11-10 09:15:26 +10:00
jc21
cb091040a8
Merge pull request #1578 from jc21/undo-switch-to-variables
Reverts back to proxy_pass without variables
2021-11-10 09:13:02 +10:00
chaptergy
ddd538944a Skip migration if setting does not exist 2021-11-09 14:03:39 +01:00
chaptergy
1f879f67a9 Reverts back to proxy_pass without variables 2021-11-09 13:57:39 +01:00
Chaptergy
ee89dedd0f Adds migration to regenerate default host 2021-11-08 23:11:56 +01:00
jc21
9ab5333652
Merge pull request #1574 from jc21/develop
v2.9.12
2021-11-08 14:34:31 +10:00
Jamie Curnow
3bd97ae1b0 Version bump 2021-11-08 13:37:44 +10:00
jc21
432062e0f4
Merge pull request #1559 from jc21/variable-fix-custom-locations
Fixes custom location with capture groups
2021-11-08 12:29:43 +10:00
jc21
0c8bbb4bc2
Merge pull request #1561 from jc21/header-warning-for-advanced-config
Adds advanced config header warning
2021-11-08 12:28:34 +10:00
jc21
48e96c46d5
Merge pull request #1565 from jc21/removes-hsts-from-admin-ui
Removes HSTS from admin ui
2021-11-08 12:27:36 +10:00
jc21
25e9acf618
Merge pull request #1566 from jc21/cleans-dependencies
Removes unused dependencies
2021-11-08 12:27:04 +10:00
jc21
a517e80236
Merge pull request #1567 from jc21/removes-renew-delay
Removes random delay when renewing certificates with the renew now button
2021-11-08 12:26:34 +10:00
jc21
3d4d3bc73b
Merge pull request #1572 from jc21/letsencrypt-config-file
Uses letsencrypt config file everywhere
2021-11-08 12:25:48 +10:00
Julian Reinhardt
cf4d1f73fa Uses letsencrypt config file everywhere 2021-11-06 22:31:13 +01:00
Julian Reinhardt
c203d1a0d8 Requires ~() in location to remove $request_uri and removes $request_uri if it is just a slash 2021-11-06 13:38:02 +01:00
Julian Reinhardt
5f29f6b039 Removes random delay when renewing certificates with the renew now button 2021-11-05 14:20:12 +01:00
Julian Reinhardt
f75b5b867b Fixes formatting 2021-11-05 14:01:50 +01:00
Julian Reinhardt
67463ca136 Removes unused dependencies 2021-11-05 13:59:19 +01:00
Julian Reinhardt
8db541f37f Removes HSTS from admin ui 2021-11-05 00:09:05 +01:00
Julian Reinhardt
a5229d0e92 Adds advanced config header warning and replaces variable info with translation 2021-11-04 12:01:01 +01:00
Julian Reinhardt
38ec0f9f95 Adds logs to backend when testing http challenge 2021-11-04 11:16:23 +01:00
Julian Reinhardt
3d80759a21 Renames the $upstream variables and does not append $request_ui if capture group exists in location 2021-11-04 10:08:15 +01:00
jc21
d95cd36b3e
Merge pull request #1544 from piuswalter/patch-1
Fixed typo in i18n translation file
2021-11-03 09:42:49 +10:00
jc21
4c6b96ad5d
Merge pull request #1546 from jc21/removes-swagger-containter
Removes swagger container
2021-11-03 09:41:41 +10:00
jc21
c3bef2867e
Merge pull request #1547 from jc21/makes-sqlite-default
Changes documentation to make SQLite the default db
2021-11-03 09:41:02 +10:00
Julian Reinhardt
efc5bff2e1 Makes SQLite the default database in documentation 2021-11-02 12:24:23 +01:00
Julian Reinhardt
ffe3db8c08 Falls back to SQLite if no environment variables are provided 2021-11-02 12:22:39 +01:00
Julian Reinhardt
4ada0feae3 Removes swagger container and adds exposed port for DB in dev env 2021-11-02 11:33:22 +01:00
Pius Walter
e17de6058e Fixed typo 2021-11-01 17:43:46 +01:00
Julian Reinhardt
9efe6cfb39 Minor fixes 2021-10-31 13:41:29 +01:00
Julian Reinhardt
c86a1a50bd Fixes formatting 2021-10-31 00:28:43 +02:00
Julian Reinhardt
c55476b196 Adds buttons to test availability of server from public internet 2021-10-31 00:19:18 +02:00
jc21
3b47decbb0
Merge pull request #1528 from jc21/develop
v2.9.11
2021-10-27 22:11:55 +10:00
Jamie Curnow
d0bfa082e0 Bump version 2021-10-27 21:43:07 +10:00
jc21
6b7a8b009e
Merge pull request #1519 from jc21/fixes-incorrect-proxy-path
Updates proxy paths
2021-10-27 21:42:18 +10:00
Julian Reinhardt
ca59e585d8 Uses variable in proxy_pass for normal proxy hosts 2021-10-25 14:58:02 +02:00
Julian Reinhardt
bbde7a108a Use variable with full uri in proxy pass 2021-10-25 14:48:22 +02:00
Julian Reinhardt
87731a8b5c Revert "Utilise variable for custom locations proxy_pass"
This reverts commit 6c1ae77a2a40283c5444c2f7e0a7c8227aeecbd2.
2021-10-25 14:27:37 +02:00
jc21
29d4bd4ccf
Merge pull request #1517 from jc21/develop
v2.9.10
2021-10-25 15:48:43 +10:00
jc21
925ad90f91
Merge branch 'master' into develop 2021-10-25 14:26:47 +10:00
Jamie Curnow
650ae61c43 Version bump 2021-10-25 11:35:44 +10:00
jc21
02f3f9704f
Merge pull request #1480 from jc21/prefer-isrg-cert-chain
Sets the cert chain to prefer ISRG Root X1
2021-10-25 08:42:31 +10:00
jc21
da7c3057b4
Merge pull request #1481 from jc21/certificate-no-domain-sorting
Removes sorting of domain names when creating a certificate
2021-10-25 08:40:19 +10:00
jc21
040b45cafa
Merge pull request #1496 from jc21/fixes-cache-busting
Adds cache busting to js bundles as well
2021-10-25 08:30:15 +10:00
jc21
8ece310b9f
Merge pull request #1514 from jc21/adds-dns-websupportsk-challenge
Adds Webbsupport.sk dns plugin
2021-10-25 08:26:20 +10:00
jc21
96959db3c2
Merge pull request #1504 from jc21/removes-certbot-plugin-prefixes
Removes certbot plugin prefixes
2021-10-25 08:26:03 +10:00
Julian Reinhardt
6360100611 Adds Webbsupport.sk dns plugin 2021-10-24 22:14:59 +02:00
Julian Reinhardt
b833044cea Fixes formatting 2021-10-20 18:38:21 +02:00
Julian Reinhardt
97909830f5 Removes dns plugin prefixes 2021-10-20 18:16:54 +02:00
Julian Reinhardt
8ae2de2f49 Updates certbot-dns-ionos to newest version 2021-10-20 18:08:11 +02:00
chaptergy
bf7b659e89 Adds cache busting to js bundles as well 2021-10-17 19:15:35 +02:00
chaptergy
4e3c7749af Removes sorting of domain names when creating a certificate 2021-10-12 16:18:11 +02:00
chaptergy
f63441921f Sets the cert chain to prefer ISRG Root X1 2021-10-12 16:11:47 +02:00
jc21
725ba83606
Merge pull request #1443 from jc21/dependabot/npm_and_yarn/docs/ansi-regex-5.0.1
Bump ansi-regex from 5.0.0 to 5.0.1 in /docs
2021-10-12 10:36:48 +10:00
jc21
281906c0b5
Merge pull request #1476 from jc21/dependabot/npm_and_yarn/backend/objection-2.2.16
Bump objection from 2.2.2 to 2.2.16 in /backend
2021-10-12 10:36:34 +10:00
dependabot[bot]
8ed121f43d
Bump ansi-regex from 5.0.0 to 5.0.1 in /docs
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 01:57:51 +00:00
jc21
81a9cab2b3
Merge pull request #1464 from jc21/fixes-navigation-on-mobile
Adds toggle to header to display menu on mobile
2021-10-11 11:55:37 +10:00
jc21
8d98a417c5
Merge pull request #1469 from jc21/certbot-plugin-updates
Certbot plugin updates
2021-10-11 11:54:51 +10:00
dependabot[bot]
6fa81b179b
Bump objection from 2.2.2 to 2.2.16 in /backend
Bumps [objection](https://github.com/vincit/objection.js) from 2.2.2 to 2.2.16.
- [Release notes](https://github.com/vincit/objection.js/releases)
- [Commits](https://github.com/vincit/objection.js/commits/2.2.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 01:53:33 +00:00
jc21
9e169fbb42
Merge pull request #1474 from Djelibeybi/add-oci-dns
Add DNS provider for Oracle Cloud Infrastructure (OCI) DNS
2021-10-11 11:53:26 +10:00
Jamie Curnow
27f84f880a Updated node-sass and sass-loader 2021-10-11 11:11:46 +10:00
Avi Miller
0d9c941b4e
Add support for Oracle Cloud Infrastructure (OCI) DNS
Signed-off-by: Avi Miller <avi.miller@oracle.com>
2021-10-10 08:49:12 +11:00
chaptergy
8865aa9c8c Fixes formatting 2021-10-07 17:39:18 +02:00
chaptergy
6d8c4218f1 Replaces fixed certbot plugin version with optional version requirements 2021-10-07 17:13:48 +02:00
chaptergy
c134a43337 Updates DirectAdmin plugin to prevent certbot downgrade 2021-10-06 17:58:07 +02:00
chaptergy
780759dc27 Adds toggle to header to display menu on mobile 2021-10-05 21:00:10 +02:00
jc21
85128f08f3
Merge pull request #1409 from jc21/dependabot/npm_and_yarn/docs/set-value-4.0.1
Bump set-value from 3.0.2 to 4.0.1 in /docs
2021-09-30 13:16:28 +10:00
jc21
d2f8c1e5f1
Merge pull request #1412 from jc21/dependabot/npm_and_yarn/docs/prismjs-1.25.0
Bump prismjs from 1.24.0 to 1.25.0 in /docs
2021-09-30 13:16:20 +10:00
jc21
9c88b9c1e9
Merge pull request #1415 from jc21/dependabot/npm_and_yarn/docs/nth-check-2.0.1
Bump nth-check from 1.0.2 to 2.0.1 in /docs
2021-09-30 13:16:10 +10:00
dependabot[bot]
13fd2ce4e2
Bump nth-check from 1.0.2 to 2.0.1 in /docs
Bumps [nth-check](https://github.com/fb55/nth-check) from 1.0.2 to 2.0.1.
- [Release notes](https://github.com/fb55/nth-check/releases)
- [Commits](https://github.com/fb55/nth-check/compare/v1.0.2...v2.0.1)

---
updated-dependencies:
- dependency-name: nth-check
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-22 04:54:41 +00:00
dependabot[bot]
9979f516d6
Bump prismjs from 1.24.0 to 1.25.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.24.0 to 1.25.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.24.0...v1.25.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-20 21:48:33 +00:00
dependabot[bot]
39a5cd2d6e
Bump set-value from 3.0.2 to 4.0.1 in /docs
Bumps [set-value](https://github.com/jonschlinkert/set-value) from 3.0.2 to 4.0.1.
- [Release notes](https://github.com/jonschlinkert/set-value/releases)
- [Commits](https://github.com/jonschlinkert/set-value/compare/3.0.2...4.0.1)

---
updated-dependencies:
- dependency-name: set-value
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-16 04:26:17 +00:00
jc21
784516283f
Merge pull request #1399 from nikhen/i845
data.email should NOT be shorter than 8 characters #845
2021-09-13 11:03:22 +10:00
nikhen
ce503232c3 data.email should NOT be shorter than 8 characters #845 2021-09-12 15:01:55 +02:00
jc21
f2edf9130f
Merge pull request #1396 from nikhen/develop
1.1.1.1 used as a placeholder, despite being real external website/address #686
2021-09-12 20:42:51 +10:00
nikhen
413ab50fc4 Change example IP: 0.0.0.0 -> 203.0.113.25 2021-09-12 12:28:25 +02:00
nikhen
c1880bd3ff 1.1.1.1 used as a placeholder, despite being real external website/address #686 2021-09-11 17:21:32 +02:00
Jamie Curnow
0f0a672275 Added another contributor 2021-09-10 14:49:11 +10:00
jc21
06c5f991e7
Merge pull request #1390 from jc21/develop
v2.9.9
2021-09-10 13:50:47 +10:00
Jamie Curnow
babc5b7a38 Bumped version 2021-09-10 07:54:10 +10:00
Jamie Curnow
b96c996a45 Log more info for internal errors in debug mode 2021-09-09 08:46:09 +10:00
jc21
fb8f2c2f9a
Merge pull request #1384 from bergi9/patch-1
Add SSL and HTTP2 into IPv6 on listen.conf
2021-09-08 11:30:00 +10:00
jc21
6794937391
Merge pull request #1376 from realJoshByrnes/develop
Fixed some typos in Advanced Config readme
2021-09-08 10:52:25 +10:00
bergi9
f022e84979
Add SSL and HTTP2 into IPv6 on listen.conf
I can only server contents with IPv6 because I'm sitting behind CGN on IPv4. When enabling HTTP2 it still not serve contents with HTTP2 as there are missing arguments in the `listen`. But it still does the SSL encryption.
Previous to this commit it generates:
```
listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443;
```
Now it generates:
```
listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;
```
2021-09-07 22:50:49 +02:00
Josh Byrnes
fd5ac952cc Fixed some typos in Advanced Config readme 2021-09-05 05:47:14 +10:00
jc21
07f60e5c77
Merge pull request #1367 from jc21/dependabot/npm_and_yarn/docs/tar-6.1.11
Bump tar from 6.1.6 to 6.1.11 in /docs
2021-09-02 11:52:52 +10:00
jc21
628b8a7e1f
Merge pull request #1368 from jc21/dependabot/npm_and_yarn/backend/tar-4.4.19
Bump tar from 4.4.15 to 4.4.19 in /backend
2021-09-02 11:52:39 +10:00
dependabot[bot]
30a442807d
Bump tar from 4.4.15 to 4.4.19 in /backend
Bumps [tar](https://github.com/npm/node-tar) from 4.4.15 to 4.4.19.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v4.4.15...v4.4.19)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-02 00:11:00 +00:00
jc21
1626c8edd1
Merge pull request #1343 from ssrahul96/develop
Added support to download Let's Encrypt Certificate
2021-09-02 10:09:45 +10:00
Rahul Somasundaram
ca6561bf6c
updated debug statement 2021-09-01 11:50:51 +05:30
Rahul Somasundaram
273a81471d
Revert "updated debug statement"
This reverts commit 8b07a67133bf9d2ee80beeb40262d83d236b9e20.
2021-09-01 11:47:47 +05:30
Rahul Somasundaram
8b07a67133
updated debug statement 2021-09-01 11:46:10 +05:30
Rahul Somasundaram
32089ea272
deferenced symlinks and downloaded the certs from live directory 2021-09-01 11:41:27 +05:30
Rahul Somasundaram
658acd147c
updated certificate path 2021-09-01 07:38:11 +05:30
jc21
ca3370a6ac
Merge pull request #1366 from BjoernAkAManf/patch-1
Forwarding host should be anyOf not oneOf
2021-09-01 07:25:35 +10:00
dependabot[bot]
c4e2557de2
Bump tar from 6.1.6 to 6.1.11 in /docs
Bumps [tar](https://github.com/npm/node-tar) from 6.1.6 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.6...v6.1.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-31 19:03:35 +00:00
Björn Heinrichs
6f2b4fdf86
Forwarding host should be anyOf not oneOf
Should fix #1354
2021-08-31 19:27:43 +02:00
Rahul Somasundaram
f302ff71c9
corrected message 2021-08-30 16:36:13 +05:30
jc21
fee87a44d6
Merge pull request #1348 from jc21/develop
v2.9.8
2021-08-25 10:11:10 +10:00
Rahul Somasundaram
8944609b63
fixed linting 2021-08-24 07:28:17 +05:30
Rahul Somasundaram
be87c45f27
thrown exception for non LE certificates 2021-08-24 06:01:08 +05:30
Rahul Somasundaram
1b1807c79a removed debug lines 2021-08-23 18:03:47 +05:30
Rahul Somasundaram
a8f4699816 [frontend] certificate download changes 2021-08-23 15:47:03 +05:30
Rahul Somasundaram
ac3df6dd77
fixed comments 2021-08-23 09:29:33 +05:30
Jamie Curnow
5c67908460 Bump version, added contributors 2021-08-23 13:55:48 +10:00
Rahul Somasundaram
7b67ef3015
fixed linting 2021-08-23 09:17:42 +05:30
Rahul Somasundaram
e5a3b5ee2f
added endpoint to download certificates 2021-08-23 09:03:24 +05:30
Jamie Curnow
5e9ff4d2bf Add healthcheck back for ci containers 2021-08-23 09:29:11 +10:00
jc21
daa71764b6
Merge pull request #1338 from bmbvenom/patch-1
remove dummy cert references to Nginx Proxy Manager
2021-08-23 08:52:01 +10:00
Jamie Curnow
6a6c2ef192 Remove healthchecks and mention how to optin to them in docs 2021-08-23 08:50:07 +10:00
bmbvenom
320315956d
remove dummy cert references to Nginx Proxy Manager
Based on this issue: https://github.com/jc21/nginx-proxy-manager/issues/1024
2021-08-21 22:37:14 -07:00
Jamie Curnow
4f10d129c2 Reload nginx after access list change. Fixes #1328 2021-08-19 08:55:53 +10:00
Jamie Curnow
62eb3fcd85 Updated docker base image location 2021-08-17 11:28:30 +10:00
jc21
ab40e4e2cf
Merge pull request #1036 from BjoernAkAManf/master
Allows hostname instead of ip for streams
2021-08-16 13:40:40 +10:00
jc21
0bb9450642
Merge pull request #1323 from jc21/dependabot/npm_and_yarn/docs/url-parse-1.5.2
Bump url-parse from 1.5.0 to 1.5.2 in /docs
2021-08-16 13:38:16 +10:00
dependabot[bot]
a6e15532b9
Bump url-parse from 1.5.0 to 1.5.2 in /docs
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.0 to 1.5.2.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.0...1.5.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 03:37:58 +00:00
jc21
9a89a8a77e
Merge pull request #1209 from jc21/dependabot/npm_and_yarn/docs/prismjs-1.24.0
Bump prismjs from 1.23.0 to 1.24.0 in /docs
2021-08-16 13:37:56 +10:00
jc21
fe3675dc7a
Merge pull request #1210 from jc21/dependabot/npm_and_yarn/backend/normalize-url-4.5.1
Bump normalize-url from 4.5.0 to 4.5.1 in /backend
2021-08-16 13:37:47 +10:00
jc21
5c9acc2bff
Merge pull request #1309 from jc21/dependabot/npm_and_yarn/backend/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7 in /backend
2021-08-16 13:37:36 +10:00
jc21
c94e937a50
Merge pull request #1308 from jc21/dependabot/npm_and_yarn/frontend/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7 in /frontend
2021-08-16 13:37:26 +10:00
jc21
3e4e10e644
Merge pull request #1310 from jc21/dependabot/npm_and_yarn/docs/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7 in /docs
2021-08-16 13:37:15 +10:00
Björn Heinrichs
ba7bb57ca2
Incorporate feedback
- Empty function removed
- Placeholder and Maxlength restored
- Validation improved
- Typo fixed
2021-08-13 11:32:01 +02:00
dependabot[bot]
14c125150a
Bump path-parse from 1.0.6 to 1.0.7 in /docs
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 03:03:43 +00:00
dependabot[bot]
053701a702
Bump path-parse from 1.0.6 to 1.0.7 in /backend
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 00:57:11 +00:00
dependabot[bot]
3fc3e43042
Bump path-parse from 1.0.6 to 1.0.7 in /frontend
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 00:56:50 +00:00
jc21
b0dc68d7d4
Merge pull request #1300 from FMeinicke/develop
Add deSEC DNS provider
2021-08-09 15:30:53 +10:00
Florian Meinicke
e895baaeb4 Add deSEC DNS provider 2021-08-08 19:22:17 +02:00
jc21
c47f6fdb21
Merge pull request #1294 from jc21/develop
v2.9.7
2021-08-07 21:15:47 +10:00
jc21
9e188e441a
Merge branch 'master' into develop 2021-08-07 20:06:40 +10:00
Jamie Curnow
f6efcdf9f9 Bumped version 2021-08-07 20:05:53 +10:00
David Dosoudil
b1ceda3af4 Update letsencrypt.ini to support ECDSA keys
Since we have newer certbot available, it's time to support more modern and safer ECDSA keys instead of RSA.
2021-08-07 20:05:53 +10:00
jc21
cd3a0684d0
Merge pull request #1293 from jc21/dependabot/npm_and_yarn/docs/tar-6.1.6
Bump tar from 6.0.2 to 6.1.6 in /docs
2021-08-07 19:07:08 +10:00
jc21
f25e54c6cb
Merge pull request #1211 from gabbe/dns-loopia
Added Loopia dns provider
2021-08-07 13:04:11 +10:00
jc21
66f86cf497
Merge pull request #1258 from nightah/fix-location-proxy_pass
Utilise variable for custom locations proxy_pass
2021-08-07 13:03:33 +10:00
dependabot[bot]
d260edc547
Bump tar from 6.0.2 to 6.1.6 in /docs
Bumps [tar](https://github.com/npm/node-tar) from 6.0.2 to 6.1.6.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.0.2...v6.1.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-07 03:02:18 +00:00
jc21
ba1e6fa984
Merge pull request #1265 from phantomski77/master
Update letsencrypt.ini to support ECDSA keys
2021-08-07 13:01:14 +10:00
jc21
6b59f36213
Merge pull request #1287 from jc21/dependabot/npm_and_yarn/backend/tar-4.4.15
Bump tar from 4.4.13 to 4.4.15 in /backend
2021-08-07 13:00:55 +10:00
jc21
1894960762
Merge pull request #1286 from jc21/fixes-certificate-renewal
Fixes certificate renewal
2021-08-07 12:59:58 +10:00
chaptergy
83c5c55f32
Fixes creation of certificates using the http challenge 2021-08-06 10:56:06 +02:00
dependabot[bot]
fb8c0b9a48
Bump tar from 4.4.13 to 4.4.15 in /backend
Bumps [tar](https://github.com/npm/node-tar) from 4.4.13 to 4.4.15.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v4.4.13...v4.4.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-04 20:15:26 +00:00
chaptergy
d34691152c
Fixes renewal unused http certificates 2021-08-04 14:07:53 +02:00
chaptergy
cea80b482e
Fixes certificate renewal for dns challenges 2021-08-04 13:47:44 +02:00
David Dosoudil
c460a8fa5c
Update letsencrypt.ini to support ECDSA keys
Since we have newer certbot available, it's time to support more modern and safer ECDSA keys instead of RSA.
2021-07-28 11:25:24 +01:00
jc21
5f852437fe
Merge pull request #1261 from jc21/develop
v2.9.6
2021-07-25 23:19:35 +10:00
Jamie Curnow
8aded1a685 Bump version 2021-07-25 21:10:26 +10:00
Jamie Curnow
f2acb9e150 Tweaks to s6 scripts 2021-07-25 21:09:02 +10:00
jc21
6f3a00c9b8
Merge pull request #1255 from jc21/fixes-crash-when-logrotation-fails 2021-07-24 08:50:12 +10:00
chaptergy
fbae107c04
Changes owner of logs to root on every container start 2021-07-23 09:11:43 +02:00
Amir Zarrinkafsh
6c1ae77a2a
Utilise variable for custom locations proxy_pass
If a custom location is currently set to proxy to a DNS hostname this hostname is cached by nginx. When the underlying IP for the hostname changes this will be cached in nginx until it is restarted. This behaviour is somewhat undesirable if utilising containers.

This change sets the proxy_pass for custom locations into a variable and utilises said variable for routing to the upstream backend. This will ensure that nginx will utilise the resolver and resolve the hostname to the current IP instead of relying on the nginx cache.
2021-07-23 16:24:46 +10:00
chaptergy
67e8ca6714
Fixes crash when logrotate fails 2021-07-22 14:05:21 +02:00
jc21
a56d976947
Merge pull request #1248 from jc21/develop
v2.9.5
2021-07-19 22:10:23 +10:00
jc21
ac0bb6bee2
Merge branch 'master' into develop 2021-07-19 15:59:06 +10:00
Jamie Curnow
dee67dac75 Bumped version, added contributors 2021-07-19 15:58:15 +10:00
jc21
9458cfbd1a
Merge pull request #1229 from demize/auth_request-fix
Disable auth_request in letsencrypt-acme-challenge.conf
2021-07-18 21:54:59 +10:00
jc21
4b8bdd22b3
Merge pull request #1181 from Theyooo/fix-wildcard-domains-regex
Fix wildcard domain regex
2021-07-18 19:05:23 +10:00
jc21
a4c143e2d1
Merge pull request #1178 from mrdink/patch-1
Update messages.json
2021-07-12 07:54:36 +10:00
jc21
e91019feb9
Merge pull request #1140 from jc21/adds-logrotation
Adds logrotation
2021-07-12 07:54:02 +10:00
jc21
8a37ec72b7
Merge pull request #1212 from jc21/dependabot/npm_and_yarn/docs/color-string-1.5.5
Bump color-string from 1.5.3 to 1.5.5 in /docs
2021-07-12 07:52:49 +10:00
jc21
c263a33095
Merge pull request #1222 from PUP-Loki/patch-1
Added Joker dns provider
2021-07-12 07:52:34 +10:00
demize
4b2c0115db Add to letsencrypt-acme-challenge.conf to allow for ACME challenges on proxy hosts using auth_requests 2021-07-10 15:02:09 -04:00
chaptergy
673f40bd85
Removes force parameter from logrotate 2021-07-09 12:34:50 +02:00
PUP-Loki
b9f8108cd3
Added Joker dns provider 2021-07-07 08:49:30 +01:00
dependabot[bot]
a16ecf656b
Bump color-string from 1.5.3 to 1.5.5 in /docs
Bumps [color-string](https://github.com/Qix-/color-string) from 1.5.3 to 1.5.5.
- [Release notes](https://github.com/Qix-/color-string/releases)
- [Changelog](https://github.com/Qix-/color-string/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Qix-/color-string/commits/1.5.5)

---
updated-dependencies:
- dependency-name: color-string
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-30 23:58:23 +00:00
Jamie Curnow
842cff130b Re-add missing certbot force renewal flag
and cleaned up this horrible file a bit
2021-07-01 09:57:26 +10:00
gabbe
346b9b4b79 Added Loopia dns provider 2021-06-30 14:11:58 +02:00
chaptergy
56c317d223
All logs in single folder
nginx cannot create the folder structure for logs
2021-06-29 23:07:54 +02:00
chaptergy
b7b150a979
Run logrotation binary from program 2021-06-29 21:18:29 +02:00
chaptergy
fae848bd1b
Store host logs in subfolders 2021-06-29 20:40:36 +02:00
dependabot[bot]
a5b8087dc5
Bump normalize-url from 4.5.0 to 4.5.1 in /backend
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-29 11:59:33 +00:00
dependabot[bot]
7aa078e025
Bump prismjs from 1.23.0 to 1.24.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.23.0 to 1.24.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.23.0...v1.24.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-28 19:45:20 +00:00
jc21
4b6b276b64
Merge pull request #1195 from jc21/develop
v2.9.4
2021-06-22 09:41:47 +10:00
Jamie Curnow
0373daae5c Bump version 2021-06-22 08:55:37 +10:00
jc21
7f30dd0475
Merge pull request #1194 from jc21/dependabot/npm_and_yarn/docs/set-getter-0.1.1
Bump set-getter from 0.1.0 to 0.1.1 in /docs
2021-06-22 08:19:36 +10:00
dependabot[bot]
d2a77c2371
Bump set-getter from 0.1.0 to 0.1.1 in /docs
Bumps [set-getter](https://github.com/doowb/set-getter) from 0.1.0 to 0.1.1.
- [Release notes](https://github.com/doowb/set-getter/releases)
- [Commits](https://github.com/doowb/set-getter/commits/0.1.1)

---
updated-dependencies:
- dependency-name: set-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-21 21:26:26 +00:00
jc21
104f65b541
Merge pull request #1169 from jc21/dependabot/npm_and_yarn/test/glob-parent-5.1.2
Bump glob-parent from 5.1.0 to 5.1.2 in /test
2021-06-19 10:31:47 +10:00
jc21
d0fb4b6914
Merge pull request #1177 from jc21/dependabot/npm_and_yarn/frontend/postcss-7.0.36
Bump postcss from 7.0.32 to 7.0.36 in /frontend
2021-06-19 10:31:36 +10:00
jc21
42c3272def
Merge pull request #1182 from DSorlov/develop
Update ssl-ciphers.conf
2021-06-19 10:30:43 +10:00
jc21
2812889d61
Merge pull request #1186 from jc21/use-certbot-from-path
Use the certbot command from the PATH variable
2021-06-19 10:24:21 +10:00
chaptergy
bd3a13b2a5
Also rotate other logs 2021-06-18 10:43:56 +02:00
chaptergy
289d179142
Adds logrotate 2021-06-18 09:38:48 +02:00
chaptergy
deca493912
Splits access and error logs for each host 2021-06-18 09:38:48 +02:00
chaptergy
d16bf7d6c0
Adds explicit names to dev containers 2021-06-18 09:38:48 +02:00
chaptergy
3f1415dad1
Use the certbot command from the PATH variable 2021-06-18 09:22:42 +02:00
Daniel Sörlöv
3e744b6b2d Update ssl-ciphers.conf
Removing support (by default) for all the unsecure protocols. This should be the default and if needed additional support can be configured. As this is a security feature it should be aligned with a moderate policy. This is updated using the latest recomendation as found on https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&guideline=5.6
2021-06-17 15:17:13 +02:00
Théo Sallou
56c4f8a106 fix wildcard domains regex 2021-06-17 11:51:51 +02:00
Justin Peacock
99ef8bae4c
Update messages.json
small change but updated the year in the footer. maybe there's a better way to grab the date with a function?
2021-06-16 09:29:55 -04:00
dependabot[bot]
b7f0343730
Bump postcss from 7.0.32 to 7.0.36 in /frontend
Bumps [postcss](https://github.com/postcss/postcss) from 7.0.32 to 7.0.36.
- [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/7.0.32...7.0.36)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-16 10:16:48 +00:00
jc21
c807b59fb4
Merge pull request #1149 from Fuechslein/develop 2021-06-16 20:16:08 +10:00
jc21
60fc57431a
Merge pull request #1136 from jc21/dependabot/npm_and_yarn/docs/ws-7.4.6
Bump ws from 7.3.1 to 7.4.6 in /docs
2021-06-11 12:11:30 +10:00
dependabot[bot]
d988a3a307
Bump glob-parent from 5.1.0 to 5.1.2 in /test
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.0 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.0...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 01:26:02 +00:00
jc21
de763d3fa9
Merge pull request #1170 from jc21/dependabot/npm_and_yarn/docs/glob-parent-5.1.2
Bump glob-parent from 5.1.1 to 5.1.2 in /docs
2021-06-11 11:25:28 +10:00
jc21
21bfb61cc8
Merge pull request #1068 from jc21/dependabot/npm_and_yarn/frontend/underscore-1.12.1
Bump underscore from 1.10.2 to 1.12.1 in /frontend
2021-06-11 10:01:30 +10:00
dependabot[bot]
a79adeb280
Bump ws from 7.3.1 to 7.4.6 in /docs
Bumps [ws](https://github.com/websockets/ws) from 7.3.1 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.3.1...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-10 23:08:37 +00:00
jc21
9b7a019222
Merge pull request #1159 from jc21/changes-real_ip-ranges-to-local-network
Sets real_ip ranges to local network only
2021-06-11 09:07:57 +10:00
jc21
e65143d276
Merge pull request #1164 from jc21/dependabot/npm_and_yarn/docs/normalize-url-5.3.1
Bump normalize-url from 5.1.0 to 5.3.1 in /docs
2021-06-11 09:07:06 +10:00
dependabot[bot]
61bb183eda
Bump glob-parent from 5.1.1 to 5.1.2 in /docs
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-10 23:06:36 +00:00
jc21
f3d3a6db91
Merge pull request #1165 from jc21/dependabot/npm_and_yarn/docs/css-what-5.0.1
Bump css-what from 3.3.0 to 5.0.1 in /docs
2021-06-11 09:05:46 +10:00
dependabot[bot]
9ebb443cb7
Bump css-what from 3.3.0 to 5.0.1 in /docs
Bumps [css-what](https://github.com/fb55/css-what) from 3.3.0 to 5.0.1.
- [Release notes](https://github.com/fb55/css-what/releases)
- [Commits](https://github.com/fb55/css-what/compare/v3.3.0...v5.0.1)

---
updated-dependencies:
- dependency-name: css-what
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-09 19:18:07 +00:00
dependabot[bot]
fa4c4d0a8d
Bump normalize-url from 5.1.0 to 5.3.1 in /docs
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 5.1.0 to 5.3.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-09 00:57:18 +00:00
Jamie Curnow
3e1518fef6 Updated docs for docker restart policy 2021-06-08 08:48:26 +10:00
jc21
e59db84721
Merge pull request #1155 from ChrisTracy/patch-1
Adding "restart: always" to ReadMe
2021-06-08 08:45:28 +10:00
Chris Tracy
c281b31fc8
Update README.md 2021-06-07 09:38:45 -05:00
jc21
1c93ca9896
Merge pull request #1158 from jc21/fixes-duckdns-certbot 2021-06-07 18:33:25 +10:00
chaptergy
df5836e573
Sets real_ip ranges to local network only 2021-06-07 08:30:39 +02:00
chaptergy
41ef35f0d0
Fixes duckdns certbot 2021-06-07 08:27:01 +02:00
chaptergy
5e6ce8643f
Adds reddit badge to readme 2021-06-07 06:19:29 +00:00
jc21
f575400bc8
Merge pull request #1081 from vipergts450/vipergts450-custom_location-patch
Vipergts450 custom location patch
2021-06-07 12:46:23 +10:00
jc21
6d9a335b0e
Merge pull request #1129 from jc21/dependabot/npm_and_yarn/docs/dns-packet-5.2.2
Bump dns-packet from 5.2.1 to 5.2.2 in /docs
2021-06-07 12:44:26 +10:00
jc21
f94eb5f318
Merge pull request #1123 from jc21/dependabot/npm_and_yarn/docs/browserslist-4.16.5
Bump browserslist from 4.13.0 to 4.16.5 in /docs
2021-06-07 09:30:49 +10:00
Chris Tracy
245fa421a2
Adding "restart: always" to ReadMe
Adding "restart: always" to ReadMe. I had a hard time figuring out why once of my NPM containers would not start on reboot while the rest of them would.
2021-06-06 12:14:58 -05:00
Fuechslein
655094a816
Update certbot-dns-plugins.js 2021-06-06 16:44:44 +02:00
Yannik Roth
d544650b05
fix spacings. again. 2021-06-03 19:42:14 +02:00
Yannik Roth
d9d682585c
fix spaces/tabs 2021-06-03 19:35:30 +02:00
Fuechslein
44a202552e Restore default build script 2021-06-03 18:36:25 +02:00
Fuechslein
fd6673420b Added IONOS and Infomaniak certbot plugins 2021-06-03 18:33:33 +02:00
jc21
0e9cd5db9c
Merge pull request #1122 from jc21/fixes-some-database-issues
Fixes some database issues on raspberry pi
2021-05-31 08:43:28 +10:00
dependabot[bot]
6da6e6f145
Bump dns-packet from 5.2.1 to 5.2.2 in /docs
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 5.2.1 to 5.2.2.
- [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.1...v5.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-26 18:51:46 +00:00
dependabot[bot]
bdaa7460e4
Bump browserslist from 4.13.0 to 4.16.5 in /docs
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.13.0 to 4.16.5.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.13.0...4.16.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-26 04:04:42 +00:00
chaptergy
d6d1c1ac35
Updates raspberry pi docker compose in documentation 2021-05-25 14:18:51 +02:00
chaptergy
67958155fc
Updates generated sqlite config in documentation 2021-05-25 14:18:01 +02:00
chaptergy
198bd74ec6
Adds useNullAsDefault to default sqlite config 2021-05-25 14:16:46 +02:00
jc21
92eec95dad
Merge pull request #1111 from jc21/develop
v2.9.3
2021-05-21 08:59:01 +10:00
jc21
b73a034fca
Merge branch 'master' into develop 2021-05-20 13:34:43 +10:00
Jamie Curnow
11b508f021 Bump version, added contributors 2021-05-20 13:31:14 +10:00
jc21
c2b5be37f9
Merge pull request #966 from razvanstoica89/master
Add new details about how to run this image on a Raspberry Pi device.
2021-05-20 08:15:31 +10:00
jc21
1a04863a08
Merge pull request #972 from psharma04/master
Add info about SSL
2021-05-20 08:14:28 +10:00
jc21
077d3eb993
Merge pull request #1071 from jc21/dependabot/npm_and_yarn/frontend/ua-parser-js-0.7.28
Bump ua-parser-js from 0.7.21 to 0.7.28 in /frontend
2021-05-20 08:12:41 +10:00
jc21
ac38221bdf
Merge pull request #1094 from jc21/dependabot/npm_and_yarn/docs/postcss-8.2.10
Bump postcss from 7.0.32 to 8.2.10 in /docs
2021-05-20 08:12:25 +10:00
jc21
9f146b8fc3
Merge pull request #1099 from jc21/updates-dns-providers
Updates Porkbun, DuckDNS & Azure challenge providers
2021-05-20 08:12:12 +10:00
jc21
9a2d9659a7
Merge pull request #1100 from jc21/show-entity-ids-in-frontend
Displays entity id for each entry in frontend
2021-05-20 08:11:12 +10:00
jc21
6faae5350a
Merge pull request #1107 from jc21/improved-issue-templates
Updates issue templates
2021-05-20 08:10:01 +10:00
chaptergy
2616709e7f
Reactivates Azure dns challenge with new version 2021-05-19 21:07:56 +02:00
chaptergy
bed9ff084c
Adds dns challenge issue template 2021-05-18 20:44:06 +02:00
chaptergy
fb3082b0bb
Updates issue templates to prevent segment information to show up in issue 2021-05-18 20:10:50 +02:00
chaptergy
c8439b8429
Displays entity id for each entry in frontend
Displays this id inside the three-dot-menu on the right
2021-05-16 16:57:05 +02:00
chaptergy
4c3632d3e7
Automatically sort DNS challenge providers by display name on render 2021-05-15 19:16:28 +02:00
chaptergy
24d8cd57da
Updates DuckDNS to a working version 2021-05-15 18:35:49 +02:00
chaptergy
b7c0a8b0c2
Sorts providers alphabetically 2021-05-15 18:32:49 +02:00
chaptergy
d6d7b22b1e
Adds porkbun as dns provider 2021-05-15 18:31:33 +02:00
jc21
5269c957ce
Merge pull request #1085 from jc21/improved-new-password-error-messages
Improved new password error messages
2021-05-13 08:24:12 +10:00
RBXII3
bf8d2672c8
Typo (used \m instead of \n) 2021-05-13 08:24:08 +10:00
jc21
8461acab9b
Merge pull request #1088 from bikram990/develop
Added support for Dynu DNS Provider
2021-05-13 08:23:10 +10:00
jc21
731ae43fe8
Merge pull request #1095 from jc21/godaddy-dns
Adds GoDaddy DNS and temporarily disables Azure DNS
2021-05-13 08:22:37 +10:00
jc21
5354c85352
Merge pull request #1096 from jc21/serve-fonts-locally
Serves font locally
2021-05-13 08:22:00 +10:00
chaptergy
22a37bb923
Disables azure dns provider temporarily 2021-05-12 18:49:28 +02:00
chaptergy
07bbece704
Serves font locally 2021-05-12 18:03:10 +02:00
chaptergy
9af2f50d81
Adds GoDaddy DNS provider 2021-05-12 16:28:09 +02:00
dependabot[bot]
7b148f7970
Bump postcss from 7.0.32 to 8.2.10 in /docs
Bumps [postcss](https://github.com/postcss/postcss) from 7.0.32 to 8.2.10.
- [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/7.0.32...8.2.10)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-12 06:59:49 +00:00
Bikramjeet Singh
a1e52d919f Added support for Dynu DNS Provider 2021-05-11 20:24:52 +05:30
chaptergy
899b487daa
Puts backend errors into own error field 2021-05-10 19:58:28 +02:00
jc21
86eeb5fc44
Merge pull request #1084 from jc21/develop
v2.9.2
2021-05-10 09:10:13 +10:00
Jamie Curnow
62a708b416 Version bump 2021-05-10 08:18:19 +10:00
jc21
a7ce8704b3
Merge pull request #1069 from jc21/dependabot/npm_and_yarn/backend/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /backend
2021-05-10 08:15:22 +10:00
jc21
7319a13077
Merge pull request #1074 from jc21/dependabot/npm_and_yarn/frontend/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /frontend
2021-05-10 08:15:13 +10:00
jc21
95bd4d93c5
Merge pull request #1080 from jc21/dependabot/npm_and_yarn/frontend/hosted-git-info-2.8.9
Bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
2021-05-10 08:15:01 +10:00
jc21
69c33f0395
Merge pull request #1083 from chaptergy/adds-more-dns-challenges
Adds more dns challenges
2021-05-10 08:14:07 +10:00
chaptergy
cd4caea2dc
Adds coudns dns provider 2021-05-09 21:47:30 +02:00
chaptergy
c9daf19940
Reorders some providers alphabetically 2021-05-09 21:36:52 +02:00
chaptergy
7c2540b193
Adds Azure dns provider
Issue #864
2021-05-09 19:46:20 +02:00
chaptergy
3e600552dc
Adds regru dns provider
Issue #938
2021-05-09 19:45:42 +02:00
vipergts450
69ee6b1699
Update nginx.js 2021-05-07 23:38:32 -04:00
vipergts450
ca1ea042b2
Update nginx.js 2021-05-07 23:31:51 -04:00
vipergts450
f26df7d9bb
Update nginx.js 2021-05-07 22:43:22 -04:00
Jamie Curnow
ba45705571 Partial revert of 421934e
Keeping the server block of websocket definitions but also bringing back the
location block after discussions on #1067
2021-05-08 12:17:10 +10:00
dependabot[bot]
bf8ea71c77
Bump hosted-git-info from 2.8.8 to 2.8.9 in /frontend
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-08 02:12:03 +00:00
dependabot[bot]
7deb64a5de
Bump lodash from 4.17.19 to 4.17.21 in /backend
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-08 02:11:35 +00:00
dependabot[bot]
e283865d3d
Bump lodash from 4.17.19 to 4.17.21 in /frontend
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-08 02:11:13 +00:00
jc21
a32be3e96b
Merge pull request #1070 from jc21/dependabot/npm_and_yarn/docs/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /docs
2021-05-08 12:10:48 +10:00
jc21
0cfd6eab3f
Merge pull request #1072 from jc21/dependabot/npm_and_yarn/docs/url-parse-1.5.0
Bump url-parse from 1.4.7 to 1.5.0 in /docs
2021-05-08 12:10:40 +10:00
jc21
c2361f13e6
Merge pull request #1073 from jc21/dependabot/npm_and_yarn/test/lodash-4.17.21
Bump lodash from 4.17.19 to 4.17.21 in /test
2021-05-08 12:10:30 +10:00
jc21
bc81de54b9
Merge pull request #1078 from jc21/master 2021-05-08 00:21:17 +10:00
jc21
07884bc9b1
Merge pull request #1076 from jc21/develop
v2.9.1
2021-05-07 18:57:53 +10:00
dependabot[bot]
58c3204187
Bump lodash from 4.17.19 to 4.17.21 in /test
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 03:52:24 +00:00
dependabot[bot]
19d3deddd4
Bump url-parse from 1.4.7 to 1.5.0 in /docs
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.4.7 to 1.5.0.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.4.7...1.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 03:51:57 +00:00
dependabot[bot]
f0233b947e
Bump ua-parser-js from 0.7.21 to 0.7.28 in /frontend
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.21 to 0.7.28.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.21...0.7.28)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 03:51:51 +00:00
dependabot[bot]
c6a90a2fd0
Bump lodash from 4.17.19 to 4.17.21 in /docs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 03:51:51 +00:00
Jamie Curnow
3607c30d98 Bump version 2021-05-07 13:51:35 +10:00
Jamie Curnow
717105f243 Revert installing certbot. This is handled by base image jc21/nginx-full now
Update path of certbot, and use the pip instead
2021-05-07 13:49:31 +10:00
dependabot[bot]
2373e4a06d
Bump underscore from 1.10.2 to 1.12.1 in /frontend
Bumps [underscore](https://github.com/jashkenas/underscore) from 1.10.2 to 1.12.1.
- [Release notes](https://github.com/jashkenas/underscore/releases)
- [Commits](https://github.com/jashkenas/underscore/compare/1.10.2...1.12.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 03:05:13 +00:00
vipergts450
4c76803f13
Rearrange _location.conf template
Allow more of the main host parameters into the custom location configuration and reorder to make more sense.
2021-05-06 22:30:45 -04:00
vipergts450
6a46e88f8f
Fix renderLocations to accept more parameters from host
Amend renderLocations to pass more host parameters into the custom locations to match the requirements set for the default location. This will apply all parameters set in the UI to all custom locations.
2021-05-06 22:29:21 -04:00
vipergts450
e4e94d5be0
Update nginx.js
Adds ability for custom location templates to handle includes
2021-05-06 14:50:09 -04:00
vipergts450
a3b896fa70
Update _location.conf 2021-05-06 14:48:38 -04:00
vipergts450
60347a90e9
Update _location.conf 2021-05-06 11:40:40 -04:00
Jamie Curnow
a02d4ec46f Use certbot from pip instead of apt 2021-05-06 19:10:40 +10:00
jc21
485bae8f22
Merge pull request #1064 from jc21/develop
v2.9.0
2021-05-06 12:45:21 +10:00
Jamie Curnow
655477316b Version bump, contributors added, apt tweak 2021-05-06 11:32:54 +10:00
jc21
e22f87dee7
Merge pull request #975 from thegamingninja/feature/more-access-ips
Improved Access List Form
2021-05-06 11:06:08 +10:00
THEGamingninja
d3337322dd Add target _blank to href 2021-05-05 21:02:04 -04:00
jc21
6202f4f943
Merge pull request #1034 from jonasled/patch-2
don't fix the select height, to fix multiline select
2021-05-06 10:54:12 +10:00
jc21
b42cc9ed3e
Merge pull request #1050 from jc21/dependabot/npm_and_yarn/frontend/y18n-4.0.3
Bump y18n from 4.0.0 to 4.0.3 in /frontend
2021-04-30 07:16:06 +10:00
jc21
fbf72c0f61
Merge pull request #958 from italobb/patch-1
docker-compose Instructions for streams support
2021-04-29 21:49:13 +10:00
jc21
cbd0b0c070
Merge pull request #964 from jc21/dependabot/npm_and_yarn/docs/is-svg-4.2.2
Bump is-svg from 4.2.1 to 4.2.2 in /docs
2021-04-29 21:45:00 +10:00
jc21
874f049323
Merge pull request #965 from jc21/dependabot/npm_and_yarn/docs/ssri-8.0.1
Bump ssri from 8.0.0 to 8.0.1 in /docs
2021-04-29 21:44:39 +10:00
dependabot[bot]
42ab4020e2
Bump y18n from 4.0.0 to 4.0.3 in /frontend
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.3.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/y18n-v4.0.3/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/compare/v4.0.0...y18n-v4.0.3)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-29 11:44:15 +00:00
jc21
7ab9683b87
Merge pull request #987 from jc21/dependabot/npm_and_yarn/backend/y18n-4.0.1
Bump y18n from 4.0.0 to 4.0.1 in /backend
2021-04-29 21:43:59 +10:00
jc21
865facfd05
Merge pull request #988 from jc21/dependabot/npm_and_yarn/test/y18n-4.0.1
Bump y18n from 4.0.0 to 4.0.1 in /test
2021-04-29 21:43:37 +10:00
jc21
0951f4a202
Merge pull request #989 from jc21/dependabot/npm_and_yarn/docs/y18n-4.0.1
Bump y18n from 4.0.0 to 4.0.1 in /docs
2021-04-29 21:43:22 +10:00
jc21
882ec27969
Merge pull request #1017 from Stealthii/bugfix/config-application
Apply 'Force SSL' and 'Enable Websockets' to full host definition
2021-04-29 21:42:58 +10:00
jc21
a84158c1ff
Merge pull request #1020 from stegmannb/patch-1
Updated credentials for netcup dns challenge
2021-04-29 21:40:49 +10:00
dependabot[bot]
161d3ec817
Bump ssri from 8.0.0 to 8.0.1 in /docs
Bumps [ssri](https://github.com/npm/ssri) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-29 11:38:19 +00:00
jc21
5b15249689
Merge pull request #1042 from hepelayo/duckdnsCertbotPlugin
Add DuckDNS certbot plugin
2021-04-29 21:37:58 +10:00
jc21
602fce1c7e
Merge pull request #1046 from jc21/dependabot/npm_and_yarn/frontend/ssri-6.0.2
Bump ssri from 6.0.1 to 6.0.2 in /frontend
2021-04-29 21:36:55 +10:00
Jamie Curnow
f2f653e345 Remove platform specific determination 2021-04-29 11:19:59 +10:00
dependabot[bot]
b55738bd6e
Bump ssri from 6.0.1 to 6.0.2 in /frontend
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-28 23:39:48 +00:00
jc21
b39a59ce72
Merge pull request #1045 from jc21/nginx-full
Switch to nginx-full base
2021-04-29 09:29:46 +10:00
Jamie Curnow
9872daf29f Switch to nginx-full base 2021-04-29 08:28:40 +10:00
Héctor Pelayo
91044e730b Correct indentation 2021-04-26 22:35:52 +02:00
Héctor Pelayo
656a7dceef Correct spacing 2021-04-26 22:31:16 +02:00
Héctor Pelayo
d636502eaa Add DuckDNS certbot plugin
Uses https://github.com/infinityofspace/certbot_dns_duckdns certbot plugin to implement DuckDNS DNS challenge in order to obtain Wildcard certificates.

Requires that the user inserts his duckDNS token in "Credentials File Content" input box.
2021-04-26 20:25:24 +02:00
Björn Heinrichs
389fd158ad allows hostname instead of ip for streams 2021-04-24 01:09:01 +02:00
Jonas Leder
30fa63b379
don't fix the select height, to fix multiline select 2021-04-23 21:25:57 +02:00
Bastian Stegmann
691063545c
Updated credentials for netcup dns challange
The netcup DNS challenge currently fails because the credentials are not found.
2021-04-15 09:48:08 +02:00
Daniel Porter
421934efed Move 'Allow Websockets' definitions to host root configuration
This fixes issues with these settings not applying to custom locations
defined under hosts.
2021-04-13 20:04:35 +01:00
Daniel Porter
f056b9dc7f Move 'Force SSL' definitions to host root configuration
This fixes issues with these settings not applying to custom locations
defined under hosts.
2021-04-13 19:59:49 +01:00
dependabot[bot]
48d421ba28
Bump y18n from 4.0.0 to 4.0.1 in /docs
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-31 17:28:00 +00:00
dependabot[bot]
096b714117
Bump y18n from 4.0.0 to 4.0.1 in /test
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-31 14:28:11 +00:00
dependabot[bot]
0d25dc1aaa
Bump y18n from 4.0.0 to 4.0.1 in /backend
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-31 14:25:26 +00:00
THEGamingninja
63d3c2d06f Add More Access List Entries & Access List Help 2021-03-25 14:59:07 -04:00
RBXII3
5fc704ccad
Add info about SSL 2021-03-23 13:49:14 +11:00
Razvan Stoica
61d99561c1
Set ports to default value 2021-03-22 09:50:25 +02:00
Razvan Stoica
c26ce2083f Add new details about how to run this image on a Raspberry Pi device. 2021-03-21 18:02:53 +02:00
dependabot[bot]
847d71f72a
Bump is-svg from 4.2.1 to 4.2.2 in /docs
Bumps [is-svg](https://github.com/sindresorhus/is-svg) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.2.1...v4.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-21 00:12:10 +00:00
Italo Borssatto
3c35039445
docker-compose Instructions for streams support
A simple example to make the docker-compose configuration support stream configurations.
2021-03-18 01:20:47 -03:00
jc21
1a64d44857
Merge pull request #955 from jc21/develop
v2.8.1
2021-03-18 09:36:26 +10:00
Jamie Curnow
ba5f0c212c Bumped version 2021-03-17 14:56:22 +10:00
jc21
4eddb5d7f3
Merge pull request #769 from jc21/dependabot/npm_and_yarn/frontend/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8 in /frontend
2021-03-17 14:54:45 +10:00
Jamie Curnow
3b104710d5 Restrict redirect http code 2021-03-17 14:53:57 +10:00
jc21
74db0004bd
Merge pull request #883 from baruffaldi/master
Forward scheme and http code added for redirection hosts
2021-03-17 11:30:26 +10:00
jc21
6e67352a0f
Merge pull request #880 from jlesage/jwt-key-pair-no-restart
Removed the need to restart Nginx Proxy Manager after generating JWT key pair
2021-03-17 11:09:37 +10:00
Jamie Curnow
b127f02468 Added upgrade steps 2021-03-17 08:58:45 +10:00
jc21
c9c53d9670
Merge pull request #903 from ogarai/edit-disabled-host
Prevent activating nginx config after editing disabled proxy host
2021-03-17 08:32:14 +10:00
jc21
d36dbb868b
Merge pull request #942 from nielscil/develop-certbot-dns-transip
Added TransIP dns provider
2021-03-17 08:30:05 +10:00
jc21
b7fb2cfe92
Merge pull request #947 from phantomski77/patch-2
Update _hsts.conf template to increase HSTS max-age value
2021-03-17 08:29:46 +10:00
Niels Bouma
d0a0c77556
acmedns indentation fix 2021-03-16 13:36:17 +01:00
Niels Bouma
9469b9c78a
fixed closing brace 2021-03-16 12:57:26 +01:00
jc21
e4988f34c7
Merge pull request #943 from phantomski77/patch-1
Update README.md
2021-03-16 19:51:03 +10:00
jc21
1fe9e24f0a
Merge pull request #920 from jc21/dependabot/npm_and_yarn/docs/prismjs-1.23.0
Bump prismjs from 1.21.0 to 1.23.0 in /docs
2021-03-16 19:50:28 +10:00
jc21
9c39de3454
Merge pull request #935 from jc21/dependabot/npm_and_yarn/frontend/elliptic-6.5.4
Bump elliptic from 6.5.3 to 6.5.4 in /frontend
2021-03-16 19:50:14 +10:00
jc21
9bb68ad4eb
Merge pull request #937 from jc21/dependabot/npm_and_yarn/docs/elliptic-6.5.4
Bump elliptic from 6.5.3 to 6.5.4 in /docs
2021-03-16 19:49:59 +10:00
jc21
5bf774bee1
Merge branch 'develop' into develop-certbot-dns-transip 2021-03-16 19:49:27 +10:00
jc21
99514464fb
Merge pull request #946 from ijaron/dns-acme
Add ACME-DNS certbot plugin
2021-03-16 19:48:13 +10:00
jc21
3bf1c1e531
Merge pull request #948 from GurjinderSingh/patch-1
Update README.md
2021-03-16 13:59:04 +10:00
Jamie Curnow
e2e31094aa Fix CI, no var needed for this 2021-03-16 11:32:38 +10:00
Gurjinder Singh
f29ff15167
Update README.md
found it in config file was going to add option
	# Custom
	include /data/nginx/custom/http_top[.]conf;
 
b7b808d98d/docker/rootfs/etc/nginx/nginx.conf (L72)
2021-03-14 05:13:26 -04:00
David Dosoudil
1c64252015
Update _hsts.conf template
I propose the change to max-age value of HSTS from 1 year to 2 years.
2021-03-13 12:40:47 +00:00
ijaron
ead19915f3 Add ACME-DNS certbot plugin
uses https://github.com/pan-net-security/certbot-dns-acmedns in to implement ACME-DNS support.
Requires file in /data with following layout
# cat /data/acme-registration.json
{
  "something.acme.com": {
    "username": "6e14735c-2c6a-447e-b63d-a23ac4438bd7",
    "password": "dd6gnYS-IxrQfDLbdPRX3hrFhS_SLrwbS0kSl_i8",
    "fulldomain": "3b750a0e-c627-423f-9966-4799c6a9533b.auth.example.org",
    "subdomain": "3b750a0e-c627-423f-9966-4799c6a9533b",
    "allowfrom": []
  }
}
2021-03-12 14:24:56 -06:00
David Dosoudil
967e0dd98a
Update README.md
Secrets need both global and local per-service declaration, otherwise fails as "not found". Local configuration added for both app and db.
2021-03-11 21:59:26 +00:00
Niels Bouma
bd0324dba0
credentials property naming for transip
credentials property naming for transip
2021-03-11 15:44:20 +01:00
Niels Bouma
607fb83a1e
Added transIP certbot dns plugin 2021-03-11 13:33:42 +01:00
Jamie Curnow
bb5fc58f3a Revert "Fix CI, use docker for a yarn command"
This reverts commit afbec0aca96fd860bbaaed0bebf9e5294e6ea325.
2021-03-11 09:29:08 +10:00
Jamie Curnow
afbec0aca9 Fix CI, use docker for a yarn command 2021-03-11 08:41:10 +10:00
dependabot[bot]
1e5d9dfbff
Bump elliptic from 6.5.3 to 6.5.4 in /docs
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-10 10:39:22 +00:00
dependabot[bot]
cfcb657cde
Bump elliptic from 6.5.3 to 6.5.4 in /frontend
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-10 08:19:41 +00:00
dependabot[bot]
7f243e6f06
Bump prismjs from 1.21.0 to 1.23.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.21.0 to 1.23.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.21.0...v1.23.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-01 21:06:50 +00:00
Orko Garai
7e7032c051 Prevent activating nginx config after editing disabled proxy host 2021-02-18 23:05:30 +00:00
jc21
b7b808d98d
Merge pull request #899 from jc21/develop
Docs for a docker network
2021-02-17 20:56:10 +10:00
Jamie Curnow
a21289bf11 Docs for a docker network 2021-02-17 20:55:12 +10:00
jc21
4a8d01224a
Merge pull request #897 from jc21/develop
Update github templates and docs
2021-02-17 20:19:49 +10:00
Jamie Curnow
f0eebc43e3 Update github templates and docs 2021-02-17 20:18:12 +10:00
baruffaldi
49fbf031d1 $scheme is displayed as "auto" on hosts listing 2021-02-10 19:43:29 +01:00
baruffaldi
4060718e5c Hotfix: This group of assignments is not aligned 2021-02-10 18:26:19 +01:00
baruffaldi
49b0f11ae7 migrations 2021-02-10 18:13:12 +01:00
baruffaldi
9b83d35ef4 Migrations 2021-02-10 18:12:02 +01:00
baruffaldi
eb20add0c7 Migrations hotfix 2021-02-10 17:16:33 +01:00
baruffaldi
1f122e9145 Database migrations created 2021-02-10 15:57:28 +01:00
baruffaldi
329d0ecaed Added forward scheme to table columns 2021-02-10 15:27:11 +01:00
baruffaldi
77a2ee948a Updated list table
Added state code columns
Better form columns sizing
2021-02-10 15:25:19 +01:00
baruffaldi
ebeda6345e Globalization done
Ready to merge
2021-02-10 14:11:01 +01:00
baruffaldi
e35138ebed Added scheme to definitions 2021-02-10 10:42:34 +01:00
baruffaldi
8ba6c4f7e7 Added http_code definition 2021-02-10 09:55:41 +01:00
baruffaldi
6df7b72e08 Forward scheme and http code added for redirection hosts
You can now configure the forward_scheme and forward_http_code on user interface (section redirection hosts)
2021-02-09 11:23:15 +01:00
Jocelyn Le Sage
fe13b12f43 Removed the need to restart Nginx Proxy Manager after generating JWT key pair. 2021-02-08 17:36:58 -05:00
jc21
ea28da90b2
Merge pull request #876 from jc21/develop
v2.8.0
2021-02-08 15:01:31 +10:00
Jamie Curnow
b243324c65 Added contributors and bumped version 2021-02-08 12:23:52 +10:00
jc21
a2dde00f40
Merge pull request #868 from lorisbergeron/eurodns-as-provider
Add EuroDNS as a DNS provider
2021-02-08 12:22:33 +10:00
jc21
5ff07faa7e
Merge pull request #872 from ahgraber/master
Add Docker secrets
2021-02-08 11:59:23 +10:00
Jamie Curnow
272c652847 Updated docs to use latest mariadb-aria image 2021-02-08 11:56:21 +10:00
ahgraber
3964bbf3fe update advanced-config/readme with secrets 2021-02-07 19:12:20 -05:00
ahgraber
11175aaa5f revert docker/dev before PR 2021-02-07 09:52:37 -05:00
ahgraber
7fcc4a7ef0 cleanup 2021-02-06 20:05:40 -05:00
ahgraber
5abb9458c7 fix linebreaks in secrets 2021-02-05 23:47:30 -05:00
Loris Bergeron
0ca5587a6f EuroDNS fix key-spacing error 2021-02-05 23:40:31 +01:00
Loris Bergeron
d29650882b EuroDNS fix key-spacing error 2021-02-05 23:29:01 +01:00
Loris Bergeron
9c3a7b02ec Add EuroDNS as a DNS provider 2021-02-05 23:17:51 +01:00
Alex Graber
ef3a073af5 local builds & secrets 2021-02-05 16:52:24 -05:00
ahgraber
15c4857a4b fix /docker/dev/docker-compose.yaml 2021-02-04 14:03:17 -05:00
Alex Graber
63a71afbc8 beta s6 secrets 2021-02-04 11:25:26 -05:00
Alex Graber
64761ee9c6 beta secrets 2021-02-04 11:15:31 -05:00
ahgraber
d6c344b5ec add local docker-compose to build 2021-02-02 08:58:45 -05:00
jc21
d27826d10e
Merge pull request #850 from MooBaloo/master
Add new custom http.conf above includes for NPM-generated files
2021-02-01 12:10:31 +10:00
MooBaloo
4ac52a0e25
Add custom .conf above includes for NPM-generated files.
Added a new clause for custom http_top.conf above the include clauses for NPM-generated files. Allows for more flexibility with adding custom nginx .conf files to NPM

Use case: adding a configuration change needs to be present before other custom configuration files are called and reference configuration from the custom http_top.conf file.
Example: add a new log_format in http_top.conf, then referencing it in a access_log clause in server_proxy.conf.
2021-01-28 05:52:41 -05:00
jc21
efa841d75a
Merge pull request #842 from Shuro/patch-1
Use configured default page also for IPv6
2021-01-28 08:45:12 +10:00
Shuro
d1fac583ea
Use configured default page also for IPv6
Just a small check for the ipv6 variable, similar to _listen.conf,
so that the configured default page is also delivered on ipv6 requests.
2021-01-25 01:28:50 +01:00
jc21
8cb44c7b97
Merge pull request #830 from jc21/develop
Updated version fixes #823
2021-01-18 12:15:20 +10:00
jc21
f2293a9dda
Merge branch 'master' into develop 2021-01-18 12:15:04 +10:00
Jamie Curnow
da0d1d4a2f Updated version fixes #823 2021-01-18 12:14:13 +10:00
jc21
6a8d5e2166
Merge pull request #820 from jc21/develop
v2.7.3
2021-01-12 11:13:35 +10:00
jc21
d732665a23
Merge branch 'master' into develop 2021-01-12 09:06:34 +10:00
Jamie Curnow
e0748c9bc7 Bumped version 2021-01-12 09:05:27 +10:00
dependabot[bot]
23573543a3
Bump ini from 1.3.5 to 1.3.8 in /frontend
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-06 23:36:33 +00:00
jc21
bfb328238e
Merge pull request #806 from jc21/develop
v2.7.2
2021-01-07 09:35:35 +10:00
Jamie Curnow
64cc4f57d6 Version bump and acknowledgements 2021-01-06 21:48:10 +10:00
jc21
7a3c91c6a4
Merge pull request #804 from lebrou34/master
Add Gandi Live DNS to certbot-dns-plugins.js
2021-01-06 13:14:54 +10:00
lebrou34
508bc62852
Update certbot-dns-plugins.js 2021-01-05 18:47:22 +01:00
lebrou34
59e8446d47
Update certbot-dns-plugins.js 2021-01-05 18:41:26 +01:00
lebrou34
d13596d2f7
Update certbot-dns-plugins.js 2021-01-05 18:35:18 +01:00
lebrou34
9adccfa341
Update certbot-dns-plugins.js 2021-01-05 18:19:27 +01:00
lebrou34
5cc3b53378
Update certbot-dns-plugins.js 2021-01-05 18:11:10 +01:00
lebrou34
b62b0a2fb7
Update certbot-dns-plugins.js 2021-01-05 17:36:47 +01:00
jc21
1faac4edf2
Merge pull request #750 from klutchell/klutchell-patch-1
allow custom stream conf
2021-01-03 20:14:55 +10:00
jc21
4c60dce169
Merge pull request #796 from lightglitch/patch-1
Fix dead hosts verification count
2021-01-03 20:14:36 +10:00
jc21
771f31f44d
Merge pull request #770 from jc21/dependabot/npm_and_yarn/backend/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8 in /backend
2021-01-03 20:14:21 +10:00
jc21
8bedb95e1d
Merge pull request #771 from jc21/dependabot/npm_and_yarn/test/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8 in /test
2021-01-03 20:14:03 +10:00
jc21
ac4be08df2
Merge pull request #772 from jc21/dependabot/npm_and_yarn/docs/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8 in /docs
2021-01-03 20:13:49 +10:00
jc21
0d6e058e23
Merge pull request #774 from chaptergy/better-custom-certificate-handling
Better custom certificate handling
2021-01-03 12:09:55 +10:00
Mário Franco
bee2ceb667
Fix dead hosts verification count 2021-01-02 04:58:14 +00:00
chaptergy
6af13d4f40 Removes explicit privkeytype check and adds passphrase error 2020-12-14 12:08:39 +01:00
dependabot[bot]
9dd0ebd899
Bump ini from 1.3.5 to 1.3.8 in /docs
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-12 10:17:11 +00:00
dependabot[bot]
6e97bfa717
Bump ini from 1.3.5 to 1.3.8 in /test
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-12 08:23:59 +00:00
dependabot[bot]
07b69f41eb
Bump ini from 1.3.5 to 1.3.8 in /backend
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-12 08:23:45 +00:00
Kyle Harding
6bd2ac7d6d
Update README.md 2020-12-01 14:24:14 -05:00
Kyle Harding
528e5ef3bc
allow custom stream conf
Allow a top-level custom `stream` configuration file to be loaded.
2020-12-01 14:22:31 -05:00
Jamie Curnow
bc1c50ac92 Added contributor 2020-11-22 21:50:57 +10:00
jc21
8c2ab42b75
Merge pull request #738 from WaterCalm/master
add aliyun DNS plugin
2020-11-22 21:48:24 +10:00
WaterCalm
62053d15d4
add aliyun DNS plugin
add aliyun DNS plugin
2020-11-22 16:08:56 +08:00
Jamie Curnow
6fed642aba Cypress docker build should be faster and added mkcert for later 2020-11-22 16:57:12 +10:00
jc21
72ac549a58
Merge pull request #729 from jc21/develop
v2.7.1
2020-11-18 22:55:47 +10:00
jc21
9f38617135
Merge branch 'master' into develop 2020-11-18 22:55:37 +10:00
Jamie Curnow
94eec805df Version bump 2020-11-18 21:46:21 +10:00
Jamie Curnow
05a940e732 Fix instances where config file exists and env vars don't 2020-11-18 21:42:03 +10:00
jc21
1c43cc2181
Merge pull request #725 from jc21/develop
v2.7.0
2020-11-18 14:30:44 +10:00
jc21
657ee73ff1
Merge branch 'master' into develop 2020-11-18 12:22:34 +10:00
Jamie Curnow
4ee5d993cf Bumped version 2020-11-18 12:21:35 +10:00
jc21
70a445e2d7
Merge pull request #704 from chaptergy/allow-setup-without-config-file
Removes the need of a config file and allows db config via environment
2020-11-18 12:18:45 +10:00
jc21
2115da210d
Merge pull request #694 from chaptergy/visual-indicator-for-certificate-deletion
Adds visual indicator for certificate deletion
2020-11-09 10:10:55 +10:00
jc21
540554c4f6
Merge pull request #695 from chaptergy/failed-certificate-autoremove
Adds autoremove of failed certificate creations in DB
2020-11-09 10:10:00 +10:00
chaptergy
1337c50d28 Use latest tag in full setup instructions 2020-11-07 19:37:35 +01:00
chaptergy
c5ceb3b2b1 Removes obsolete file mount 2020-11-07 13:54:18 +01:00
chaptergy
57fc1d8f08 Removes the need of a config file and allows db config via environment 2020-11-07 13:24:01 +01:00
chaptergy
1518ecd1e9 Adds autoremove of failed certificate creations in DB 2020-11-06 12:29:38 +01:00
chaptergy
6be0343918 Adds visual indicator for certificate deletion 2020-11-06 11:51:42 +01:00
jc21
cf8812c932
Merge pull request #692 from jc21/develop
v2.6.2
2020-11-06 19:31:10 +10:00
Jamie Curnow
5bc3e474a9 Merge branch 'real_ip' of github.com:jc21/nginx-proxy-manager into develop 2020-11-06 13:21:37 +10:00
Jamie Curnow
13eaa346bc Use remote addr as real ip 2020-11-06 13:21:22 +10:00
Jamie Curnow
d7437cc4a7 Test for real-ip header 2020-11-06 13:17:30 +10:00
Jamie Curnow
ddb3c6590c Version bump 2020-11-06 13:06:15 +10:00
Jamie Curnow
89d6773bda Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into real_ip 2020-11-06 09:18:25 +10:00
Jamie Curnow
3651b9484f Fix for pip install error when there are no plugins to install 2020-11-06 09:17:52 +10:00
Jamie Curnow
2200c950b7 Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into real_ip 2020-11-06 09:12:35 +10:00
jc21
14f84f01b5
Merge pull request #687 from chaptergy/allow-additional-dns-challenge-dependencies
Allow additional dns challenge dependencies
2020-11-06 09:02:35 +10:00
chaptergy
cb014027bb Makes sure credentials folder exist every time before saving credentials 2020-11-04 19:31:40 +01:00
chaptergy
32e5155783 Fixes Linting errors 2020-11-03 22:38:09 +01:00
chaptergy
a3159ad59e Converts tabs to spaces 2020-11-03 22:24:03 +01:00
chaptergy
60a40197f1 Always install additional dependencies for dns plugins 2020-11-03 21:59:18 +01:00
chaptergy
7d693a4271 Expands and refactors dns plugin list 2020-11-03 21:28:50 +01:00
Jamie Curnow
f192748bf9 Use x-real-ip header for the real-ip module 2020-10-19 11:40:50 +10:00
jc21
96f401cba6
Merge pull request #664 from chaptergy/fixes-expiring-hosts-renewal
Adds certbot plugin installation check on startup
2020-10-19 08:50:44 +10:00
jc21
ffd2430160
Merge pull request #666 from MarceloLagos/master
Check key for RSA header otherwise use EC, and output fix.
2020-10-19 08:45:28 +10:00
MarceloLagos
190cd2d6bb
Update certificate.js 2020-10-17 23:46:18 -06:00
MarceloLagos
7ba58bdbd3
Update certificate.js 2020-10-17 23:27:12 -06:00
chaptergy
08ab62108f Fixes eslint errors 2020-10-17 12:54:38 +02:00
chaptergy
1028de8158 Adds certbot plugin installation check on startup 2020-10-17 12:13:08 +02:00
jc21
301499dc52
Merge pull request #659 from jc21/develop
v2.6.1
2020-10-16 15:53:56 +10:00
jc21
5c2f13ed8e
Merge branch 'master' into develop 2020-10-16 13:44:10 +10:00
Jamie Curnow
e30ad81f69 Updated version 2020-10-16 13:43:13 +10:00
Jamie Curnow
21f36f535f Don't spit out a ; if the preceeding value is empty 2020-10-16 13:41:08 +10:00
jc21
c14236823a
Merge pull request #656 from chaptergy/fixes-custom-certificate-upload
Fixes custom certificate upload
2020-10-16 08:33:51 +10:00
chaptergy
551a9fe1c6 Fixes custom certificate upload 2020-10-15 14:58:05 +02:00
jc21
e3399e1035
Merge pull request #654 from jc21/develop
2.6.0 Release
2020-10-15 15:14:57 +10:00
Jamie Curnow
c413b4af3f Added contributors 2020-10-15 14:06:21 +10:00
Jamie Curnow
dbf5dec23b Bump version 2020-10-15 10:40:01 +10:00
Jamie Curnow
10f0eb17d7 Fix linting errors 2020-10-15 10:33:51 +10:00
jc21
e3b680c351
Merge pull request #653 from jmwebslave/dont-pass-auth-header
Pass/Don't Pass Auth Header
2020-10-15 10:10:33 +10:00
James Morgan
0df0545777 Allows auth information from AccessList not to be passed to proxied hosts. Resolves issue #153.
Signed-off-by: James Morgan <jmorgan.au+github@gmail.com>
2020-10-15 10:23:09 +11:00
jc21
165bfc9f5f
Merge pull request #607 from jc21/dependabot/npm_and_yarn/docs/node-forge-0.10.0
Bump node-forge from 0.9.1 to 0.10.0 in /docs
2020-10-15 08:34:14 +10:00
jc21
5830bd73b9
Merge pull request #608 from Philip-Mooney/master
Fix for access list getAll when not granted all permissions
2020-10-15 08:33:58 +10:00
jc21
3c4ce839b9
Merge pull request #635 from chaptergy/allow-more-dns-challenges
Allow DNS challenges not just for cloudflare
2020-10-14 19:12:15 +10:00
chaptergy
ac9f052309 Fixes linting errors 2020-10-14 09:55:45 +02:00
chaptergy
049e424957 Adds special case for Route53 2020-10-14 09:20:52 +02:00
chaptergy
07e78aec48 Adds error stack information in prod environment for certificates 2020-10-08 15:30:13 +02:00
chaptergy
3fec135fe5 Fixes ESlint formatting errors 2020-10-08 14:38:19 +02:00
chaptergy
867fe1322b Unifies directory structure in dev and prod containers 2020-10-08 13:38:20 +02:00
chaptergy
95208a50a7 Increases timeouts in front- and backend 2020-10-08 13:21:17 +02:00
chaptergy
514b13fcc2 Fixes build issues due to globally used file 2020-10-06 16:12:12 +02:00
chaptergy
4cbc1f5bbe Minor refactoring 2020-10-06 15:37:51 +02:00
chaptergy
64de36cdf2 Adds more DNS plugins 2020-10-06 15:16:45 +02:00
chaptergy
093b48ad7b Implements backend changes to allow more dns challenges 2020-10-06 14:52:06 +02:00
chaptergy
05f6a55a0b Adds frontend improvements and fixes 2020-10-06 14:49:02 +02:00
chaptergy
2523424f68 Updates dockerfiles 2020-10-05 01:04:18 +02:00
chaptergy
b81325d7bf Implements dns challenge provider selection in frontend 2020-10-05 01:04:06 +02:00
Philip Mooney
3e10b7b2b1 Fix for access list getAll when not granted all permissions 2020-09-19 22:16:16 +01:00
dependabot[bot]
e5cb750015
Bump node-forge from 0.9.1 to 0.10.0 in /docs
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 0.9.1 to 0.10.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/master/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/0.9.1...0.10.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-17 23:42:28 +00:00
jc21
28f72086ec
Merge pull request #592 from jc21/develop
v2.5.0
2020-09-04 09:07:47 +10:00
Jamie Curnow
a6b9bd7b01 Version bump and contributors 2020-09-03 14:11:44 +10:00
Jamie Curnow
2c5eac9dad Merge branch 'master' of github.com:jc21/nginx-proxy-manager into develop 2020-09-03 14:03:43 +10:00
jc21
87f61b8527
Merge pull request #572 from jipjan/features/dns-cloudflare
Add DNS CloudFlare with wildcard support
2020-09-03 14:01:05 +10:00
jc21
74bfe490c6
Merge pull request #587 from duhruh/bug/custom-ssl-inputs
Allow inputs to update
2020-09-03 13:53:17 +10:00
David Rivera
015167f34d
Allow inputs to update 2020-08-29 20:24:51 -07:00
jc21
4bafc7ff1a
Merge pull request #546 from jc21/dependabot/npm_and_yarn/docs/prismjs-1.21.0
Bump prismjs from 1.20.0 to 1.21.0 in /docs
2020-08-25 10:51:11 +10:00
jc21
bf8beb50b4
Merge pull request #559 from jlesage/remove-webroot-certbot-arg
Removed the hardcoded `--webroot` certbot argument to better support DNS challenge
2020-08-25 08:44:00 +10:00
jc21
e5034a34f5
Merge pull request #570 from jc21/dependabot/npm_and_yarn/backend/bcrypt-5.0.0
Bump bcrypt from 4.0.1 to 5.0.0 in /backend
2020-08-25 08:31:48 +10:00
Jaap-Jan de Wit
a561605653 show in ssl certificates list that CloudFlare is used 2020-08-24 09:09:52 +00:00
Jaap-Jan de Wit
e8596c1554 cloudflare DNS also possible while adding proxy, redirection and 404 2020-08-24 09:00:00 +00:00
Jaap-Jan de Wit
ab67481e99 fix eslint errors 2020-08-23 18:56:25 +00:00
Jaap-Jan de Wit
1b611e67c8 Merge commit 'c5aa2b9f771cbd4c78c239ed0791aeb8d9e4d2e4' into features/dns-cloudflare 2020-08-23 18:30:07 +00:00
Jaap-Jan de Wit
c5aa2b9f77 add cloudflare renew and make revoke working for both by deleting unnecessary config command 2020-08-23 18:29:16 +00:00
Jaap-Jan de Wit
cff6c4d1f5 - prevent wildcard generation when not using Cloudflare dns
- fix cloudflare token required logic
2020-08-23 16:48:14 +00:00
Jaap-Jan de Wit
077cf75ef2 wildcard support 2020-08-23 13:24:20 +00:00
Jaap-Jan de Wit
ff1770204c request via cloudflare dns working 2020-08-23 12:50:41 +00:00
Jaap-Jan de Wit
b9a95840e0 add cloudflare dns option to letsencrypt via manual certificate 2020-08-23 11:40:41 +00:00
Jaap-Jan de Wit
2d7576c57e add cloudflare dns also to dev docker file 2020-08-23 10:54:36 +00:00
Jaap-Jan
251aac716a Add CloudFlare DNS plugin to certbot 2020-08-21 09:49:43 +02:00
jc21
6694a42270
Merge pull request #560 from jlesage/remove-from-unixtime
Removed usage of `FROM_UNIXTIME` mysql-specific function.
2020-08-21 14:21:40 +10:00
dependabot[bot]
f78a4c6ad1
Bump bcrypt from 4.0.1 to 5.0.0 in /backend
Bumps [bcrypt](https://github.com/kelektiv/node.bcrypt.js) from 4.0.1 to 5.0.0.
- [Release notes](https://github.com/kelektiv/node.bcrypt.js/releases)
- [Changelog](https://github.com/kelektiv/node.bcrypt.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kelektiv/node.bcrypt.js/compare/v4.0.1...v5.0.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-20 17:01:00 +00:00
Jocelyn Le Sage
83fad8bcda Removed usage of FROM_UNIXTIME mysql-specific function.
This provide better interoperability with different databases (e.g. sqlite).
Fixes #557
2020-08-14 19:31:05 -04:00
Jocelyn Le Sage
f539e813aa Removed the hardcoded --webroot certbot argument to better support DNS challenge. Also, this option is already set in the default letsencrypt.ini. 2020-08-14 14:28:03 -04:00
Jamie Curnow
5d65166777 Ignore local subnets for real IP determination 2020-08-12 09:32:40 +10:00
dependabot[bot]
70346138a7
Bump prismjs from 1.20.0 to 1.21.0 in /docs
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.20.0 to 1.21.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.20.0...v1.21.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-08 00:02:04 +00:00
jc21
d68656559c
Merge pull request #544 from jlesage/sqlite-now-helper-fix
Fixed now_helper for sqlite (time is missing)
2020-08-07 08:37:00 +10:00
Jocelyn Le Sage
01660b5b80 Fixed now_helper for sqlite: it should also returns the time. 2020-08-06 17:16:22 -04:00
jc21
74010acd85
Merge pull request #543 from jc21/develop
v2.4.0
2020-08-06 16:00:10 +10:00
Jamie Curnow
7c7d255172 Added another contributor 2020-08-06 14:46:19 +10:00
jc21
058f1e9835
Merge pull request #464 from vrenjith/patch-1
Update location-item.ejs - forward_host size increase to 200
2020-08-06 14:45:09 +10:00
Jamie Curnow
b4fc629ec0 Bumped version 2020-08-06 14:43:34 +10:00
Jamie Curnow
ae06b2da75 Updated deps and added contributor 2020-08-06 14:40:54 +10:00
Jamie Curnow
54d423a11f Updated doc for sqlite 2020-08-06 14:27:29 +10:00
Jamie Curnow
5da6c97a00 Pull cypress tests from correct location 2020-08-06 13:57:33 +10:00
Jamie Curnow
bf2f13443f Cypress fixes 2020-08-06 12:47:24 +10:00
Jamie Curnow
9ce4c3fe2f CI fix 2020-08-06 12:02:47 +10:00
Jamie Curnow
4a07bf666d Added users cypress tests 2020-08-06 11:57:31 +10:00
Jamie Curnow
5be46b4b20 Cypress fixes 2020-08-06 11:26:37 +10:00
Jamie Curnow
7fd825b76b Use development config file in CI 2020-08-06 10:59:25 +10:00
Jamie Curnow
b23d59dec7 Updated cypress to 4.12.1 2020-08-06 09:00:52 +10:00
Jamie Curnow
492d450d26 Sqlite Tweaks
- Added cypress testing in CI for sqlite
- Cleaned up promises in setup
- Ensure check for settings is strict
2020-08-06 08:58:20 +10:00
jc21
04412f3624
Merge pull request #510 from tg44/multidb-re
Multidb - sqlite support
2020-08-06 08:33:00 +10:00
Jamie Curnow
c41057b28a Revert builx push experiment 2020-07-31 09:28:45 +10:00
Jamie Curnow
8312bc0100 Use same tags for experiment 2020-07-30 14:00:59 +10:00
Jamie Curnow
85ac43bc5e Merge branch 'master' of github.com:jc21/nginx-proxy-manager into develop 2020-07-30 08:31:18 +10:00
Jamie Curnow
d1a0780c7a Attempt to circumvent docker login token timeouts 2020-07-30 08:30:26 +10:00
jc21
f9b8d76527
Merge pull request #513 from jc21/dependabot/npm_and_yarn/frontend/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19 in /frontend
2020-07-20 12:39:10 +10:00
jc21
26f00eeae4
Merge branch 'master' into dependabot/npm_and_yarn/frontend/lodash-4.17.19 2020-07-20 10:59:15 +10:00
jc21
1bc2df2178
Merge pull request #514 from jc21/dependabot/npm_and_yarn/docs/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19 in /docs
2020-07-20 10:58:36 +10:00
dependabot[bot]
8dfbcef198
Bump lodash from 4.17.15 to 4.17.19 in /docs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-19 20:33:49 +00:00
Gergo Torcsvari
6690b7735d sqlite3 and psql support 2020-07-19 20:04:29 +02:00
Gergo Torcsvari
a9e7222e5e introduced now_helper for multidb capabilities 2020-07-19 20:03:53 +02:00
Gergo Torcsvari
f8edeb2775 fixed migration and setup
more info: https://github.com/knex/knex/issues/2820
2020-07-19 20:02:20 +02:00
dependabot[bot]
d1786fe159
Bump lodash from 4.17.15 to 4.17.19 in /frontend
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-19 15:20:28 +00:00
vrenjith
157a12fb7c
Update location-item.ejs 2020-06-19 01:56:16 +05:30
jc21
3f723b1638
Merge pull request #454 from jc21/develop
v2.3.1
2020-06-09 09:47:31 +10:00
Jamie Curnow
e2e9835d01 Version bump 2020-06-09 09:17:25 +10:00
jc21
7599617b67
Merge pull request #452 from jc21/dependabot/npm_and_yarn/docs/websocket-extensions-0.1.4
Bump websocket-extensions from 0.1.3 to 0.1.4 in /docs
2020-06-08 11:14:20 +10:00
dependabot[bot]
18a5b11033
Bump websocket-extensions from 0.1.3 to 0.1.4 in /docs
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-06-07 23:36:47 +00:00
Jamie Curnow
fff31b0f34 Ensure we're using the latest node image 2020-06-03 10:30:29 +10:00
Jamie Curnow
c02e30663a Revert last 2020-06-02 20:21:27 +10:00
Jamie Curnow
4c6527cafc Ensure python2 is installed for frontend build 2020-06-02 20:09:27 +10:00
jc21
55bddb12e5
Merge pull request #435 from Subv/access_lists_ips
Don't use duplicate relations when eager-loading access list items and clients.
2020-06-02 19:42:27 +10:00
Subv
d95861e1fb Don't use duplicate relations when eager-loading access list items and clients.
This fixes an Objection warning: 'Duplicate relation "proxy_hosts" in a relation expression. You should use "a.[b, c]" instead of "[a.b, a.c]". This will cause an error in objection 2.0'.

It also fixes the access list clients not being properly eager-loaded when building the proxy host nginx configuration files. Closes #434
2020-05-29 20:29:34 -05:00
Jamie Curnow
94754a5cb3 Revert CI debug 2020-05-28 20:26:16 +10:00
jc21
546f862236
Merge pull request #429 from jc21/develop
v2.3.0
2020-05-28 17:06:19 +10:00
jc21
f105e29e56
Merge branch 'master' into develop 2020-05-28 15:38:38 +10:00
Jamie Curnow
5c15993d06 Contributors 7 wide 2020-05-28 13:31:41 +10:00
Jamie Curnow
a369ea1080 Bump version 2020-05-28 13:29:55 +10:00
Jamie Curnow
98068c0f57 Debug CI by leaving images alive 2020-05-28 13:26:36 +10:00
jc21
e0ef8683a2
Merge pull request #428 from jc21/openresty
Openresty base
2020-05-28 12:22:31 +10:00
Jamie Curnow
66412a75f9 Revert to node base now that base has openresty 2020-05-28 09:25:29 +10:00
jc21
84d8fb0899
Merge pull request #403 from Indemnity83/empty-auth
Don't ask for username/password if none are defined
2020-05-28 09:18:50 +10:00
Jamie Curnow
c631537dbe Don't wipe out nginx dir, keeps luajit 2020-05-27 10:38:00 +10:00
Jamie Curnow
8d2f49541c Use OpenResty base image 2020-05-26 14:38:41 +10:00
Jamie Curnow
55a28e3437 Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into develop 2020-05-25 14:53:46 +10:00
Jamie Curnow
67ea2d01c8 Added gitter, contributors 2020-05-25 14:53:35 +10:00
jc21
dab229e37c
Merge pull request #406 from theraw/patch-1
set proper timeout.
2020-05-25 14:37:06 +10:00
jc21
7084473330
Merge pull request #416 from jc21/develop
v2.2.4
2020-05-21 16:52:16 +10:00
Jamie Curnow
dd2e335fae Cypress 4.6.0 and tweaks to scripts 2020-05-21 16:11:19 +10:00
Jamie Curnow
1ff87bbc12 Version bump 2020-05-21 15:09:51 +10:00
Jamie Curnow
2ebfdcf0c9 Fix LE certs for IPv6 only domains Fixes 394 2020-05-20 22:21:26 +10:00
Jamie Curnow
8ab161a3ee Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into develop 2020-05-20 21:53:44 +10:00
Jamie Curnow
e74b9617be Added product support github template 2020-05-20 21:40:54 +10:00
jc21
c3d88c83e3
Merge pull request #402 from Indemnity83/patch-2
Fix address validation rule to allow 'all' keyword
2020-05-20 21:16:11 +10:00
Jamie Curnow
3e912a7474 Added FAQ to docs 2020-05-20 21:14:00 +10:00
jc21
0d726a1d83
Merge pull request #405 from Indemnity83/fix-satisfy
fix spelling of 'satisfy'
2020-05-20 20:44:38 +10:00
ƬHE ЯAW ☣
affabf065e
set proper timeout. 2020-05-11 00:24:02 +02:00
Kyle Klaus
e6ea77d263 fix spelling of 'satisfy'
Fixes #385
2020-05-09 18:01:43 -07:00
Kyle Klaus
df73c2a458 skip auth check if no users defined 2020-05-09 15:51:11 -07:00
Kyle Klaus
96c5c79aef
Fix address validation rule to allow 'all' keyword
The rule was looking for the keyword 'any' but should have been looking for 'all' 

http://nginx.org/en/docs/http/ngx_http_access_module.html
2020-05-09 09:31:58 -07:00
jc21
64922f07ff
Merge pull request #388 from jc21/dependabot/npm_and_yarn/frontend/jquery-3.5.0
Bump jquery from 3.4.1 to 3.5.0 in /frontend
2020-05-07 14:53:24 +10:00
jc21
bae21f3210
Merge pull request #397 from Indemnity83/patch-1
apply migration to correct table
2020-05-05 10:14:47 +10:00
Jamie Curnow
0702a4e58e Fix incorrect var 2020-05-05 10:00:41 +10:00
Kyle Klaus
31f1d304d6
apply migration to correct table 2020-05-04 16:56:26 -07:00
dependabot[bot]
291a74c295
Bump jquery from 3.4.1 to 3.5.0 in /frontend
Bumps [jquery](https://github.com/jquery/jquery) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.4.1...3.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-30 14:43:28 +00:00
Jamie Curnow
c0e9d1eb2f Fix satisy typo 2020-04-22 11:11:20 +10:00
jc21
a7cabdde3a
Merge pull request #376 from spalger/expand-forward-host-size
expand the maximum size of the forward_host
2020-04-17 08:59:55 +10:00
spalger
3af560c2d0 switch to 255 limit to match db 2020-04-16 15:14:49 -07:00
spalger
1d23d5c761 remove maxlength from html too 2020-04-16 15:13:28 -07:00
spalger
995db12f22 remove arbitrary length limit of forward_host 2020-04-16 14:00:22 -07:00
jc21
4c60bfb66b
Merge pull request #370 from jc21/develop
v2.2.3
2020-04-15 15:06:56 +10:00
jc21
1716747047
Merge branch 'master' into develop 2020-04-15 14:19:07 +10:00
Jamie Curnow
090b4d0388 Version bump 2020-04-15 14:18:27 +10:00
jc21
a9f068daa8
Merge pull request #360 from Indemnity83/ip-access-control
Client Access Lists
2020-04-15 08:29:40 +10:00
Kyle Klaus
f5ee91aeb3 write access list to proxy host config 2020-04-13 23:32:00 -07:00
Kyle Klaus
e2ee2cbf2d enforce a 'deny all' default rule
this ensures that an access list is 'secure by default' and requires the user to create exceptions or holes in the proection instead of building the wall entirely. This also means that we no longer require the user to input any username/passwords or client addressses and can avoid internal errors which generate unhelpful user errors.
2020-04-13 23:31:54 -07:00
jc21
dcf8364899
Merge pull request #368 from jc21/develop
Support ipv6 address as a origin header, hopefully fixes #149
2020-04-14 14:40:00 +10:00
Jamie Curnow
b783602786 Support ipv6 address as a origin header, hopefully fixes #149 2020-04-14 13:01:13 +10:00
Kyle Klaus
005e64eb9f valite auth/access rules in backend 2020-04-13 19:23:55 -07:00
Kyle Klaus
e9e5d293cc expand address format
now accepts CIDR notation, IPv6 or the string 'any'
2020-04-13 19:16:18 -07:00
jc21
a57255350f
Merge pull request #365 from jc21/develop
Develop
2020-04-14 09:10:45 +10:00
jc21
781442bf1e
Merge pull request #361 from Xantios/fix-bad-gateway
Fixes #310 Clarification on the docs
2020-04-14 09:09:39 +10:00
jc21
604bd2c576
Merge pull request #358 from dpanesso/dev-formatting
Documentation formatting
2020-04-14 08:37:23 +10:00
Xantios Krugor
d9e1e1bbb7 Fixes #310 Clarification on the docs 2020-04-11 13:03:15 +02:00
Kyle Klaus
907e9e182d remove testing cruft 2020-04-11 00:42:58 -07:00
Kyle Klaus
0f238a5021 add satisfy configuration to the ui 2020-04-11 00:26:54 -07:00
Kyle Klaus
8d432bd60a refine the UI labeling 2020-04-10 20:22:01 -07:00
Kyle Klaus
fd932c7678 fix bugs preventing client rules from being updated 2020-04-10 17:42:44 -07:00
Kyle Klaus
46a9f5cb96 add basic functionality to front end 2020-04-10 17:33:14 -07:00
Kyle Klaus
f990d3f674 add access list clients to back-end 2020-04-10 16:38:54 -07:00
David Panesso
4a6de8deee Documentation formatting on advanced configuration page 2020-04-10 00:57:45 -05:00
jc21
9a7a216b23
Merge pull request #352 from jc21/develop
Develop
2020-04-07 12:09:17 +10:00
jc21
fccaaaae4d
Merge branch 'master' into develop 2020-04-07 12:09:09 +10:00
Jamie Curnow
a882b0be82 Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into develop 2020-04-07 12:06:55 +10:00
Jamie Curnow
db7bbab768 Updated npm deps 2020-04-07 12:06:36 +10:00
jc21
030e553549
Merge pull request #351 from jc21/develop
v2.2.2 Release
2020-04-07 12:01:48 +10:00
jc21
8b0ca8e367
Merge branch 'master' into develop 2020-04-07 11:23:03 +10:00
Jamie Curnow
83b2b07200 Version bump 2020-04-07 10:45:45 +10:00
Jamie Curnow
bdb591af9e - Add ability to disable ipv6, fixes #312
- Added ipv6 listening to hosts when configured, fixes #236 and #149
- Added documentation about disabling ipv6
- Updated npm packages
2020-04-07 10:43:19 +10:00
jc21
2993a08777
Merge pull request #349 from jc21/develop
v2.2.1
2020-04-06 10:23:45 +10:00
Jamie Curnow
2a2d3d57ec Version bump 2020-04-06 09:13:40 +10:00
jc21
33c2c131c2
Merge pull request #345 from IronTooch/master
Documentation update
2020-04-06 08:33:02 +10:00
jc21
e4286c96a7
Merge pull request #342 from damianog/patch-1
Update proxy_host.conf
2020-04-06 08:32:48 +10:00
jc21
2d9486b6fd
Merge pull request #347 from jc21/dependabot/npm_and_yarn/test/acorn-7.1.1
Bump acorn from 7.1.0 to 7.1.1 in /test
2020-04-06 07:55:40 +10:00
jc21
632ee2d0bd
Merge pull request #348 from jc21/dependabot/npm_and_yarn/backend/acorn-7.1.1
Bump acorn from 7.1.0 to 7.1.1 in /backend
2020-04-06 07:36:16 +10:00
dependabot[bot]
b09f201819
Bump acorn from 7.1.0 to 7.1.1 in /backend
Bumps [acorn](https://github.com/acornjs/acorn) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/7.1.0...7.1.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-04 12:29:15 +00:00
dependabot[bot]
baaf39c23d
Bump acorn from 7.1.0 to 7.1.1 in /test
Bumps [acorn](https://github.com/acornjs/acorn) from 7.1.0 to 7.1.1.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/7.1.0...7.1.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-04 12:28:57 +00:00
IronTooch
b7467c10e8
Update README.md 2020-04-01 23:44:24 -04:00
IronTooch
701ef18606
Update README.md 2020-04-01 23:42:58 -04:00
Damiano
3e7d2b216b
Update proxy_host.conf
FIX as explained on #340
2020-03-27 19:01:21 +01:00
dependabot[bot]
41f16c20b6 Bump minimist from 1.2.0 to 1.2.2 in /docs
Bumps [minimist](https://github.com/substack/minimist) from 1.2.0 to 1.2.2.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.0...1.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-19 09:53:16 +10:00
Jamie Curnow
96bc0b53c3 Manually applying #296 - nickname required in ui 2020-03-12 08:46:18 +10:00
jc21
b80baa78ef
Updated readme (#323)
* Tweaks and backend vscode settings

* Version bump

* Updated Icon to be more vibrant

* New logo and new login screen layout, version bump

* New documentation!

* Use CI to update package versions

because I was sick of changing it everywhere

* Generate docs

* Docs upload

* Fix pipeline

* Fix pipeline

* Update readme version before generating docs

* Testing docs deploy

* Fix pipeline

* Updated CI link

* Fix docs upload

* Docs upload fixes

* Fix s3 upload grrr

* Docs tweaks

* Updated readme

* Updated screenshots

* Updated cdn id for docs

* Updated github image

* Nicer readme header

Co-authored-by: Jamie Curnow <jamiec@benon.com>
2020-03-12 08:43:50 +10:00
jc21
ce88e0745d
Updated cdn id for docs (#322)
* Tweaks and backend vscode settings

* Version bump

* Updated Icon to be more vibrant

* New logo and new login screen layout, version bump

* New documentation!

* Use CI to update package versions

because I was sick of changing it everywhere

* Generate docs

* Docs upload

* Fix pipeline

* Fix pipeline

* Update readme version before generating docs

* Testing docs deploy

* Fix pipeline

* Updated CI link

* Fix docs upload

* Docs upload fixes

* Fix s3 upload grrr

* Docs tweaks

* Updated readme

* Updated screenshots

* Updated cdn id for docs

Co-authored-by: Jamie Curnow <jamiec@benon.com>
2020-03-12 08:36:01 +10:00
jc21
256bd2336f
v2.2.0 New Brand (#319)
* Tweaks and backend vscode settings

* Version bump

* Updated Icon to be more vibrant

* New logo and new login screen layout, version bump

* New documentation!

* Use CI to update package versions

because I was sick of changing it everywhere

* Generate docs

* Docs upload

* Fix pipeline

* Fix pipeline

* Update readme version before generating docs

* Testing docs deploy

* Fix pipeline

* Updated CI link

* Fix docs upload

* Docs upload fixes

* Fix s3 upload grrr

* Docs tweaks

* Updated readme

* Updated screenshots

Co-authored-by: Jamie Curnow <jamiec@benon.com>
2020-03-11 16:54:10 +10:00
Jamie Curnow
1b6993ee70 Added better Build Badge 2020-03-10 09:59:34 +10:00
Jamie Curnow
af319b4729 Updated doc and example to use jc21/mariadb-aria now that it supports multiple arch 2020-03-09 15:22:24 +10:00
Jamie Curnow
1a15b4f18d Also archive db ci log 2020-03-06 13:21:13 +10:00
Jamie Curnow
3ddd3b49fd Re-order post testing steps 2020-03-06 13:11:04 +10:00
Jamie Curnow
e2c4b32311 Merge branch 'master' of github.com:jc21/nginx-proxy-manager 2020-03-06 12:54:15 +10:00
Jamie Curnow
8fb2821343 Get artifacts on build fail 2020-03-06 12:54:05 +10:00
jc21
93f29734b7
Version 2.1.2 (#317)
* Tweaks and backend vscode settings

* Version bump
2020-03-06 11:04:42 +10:00
Jamie Curnow
569d2b0dce Merge branch 'develop' of github.com:jc21/nginx-proxy-manager 2020-02-21 12:05:49 +10:00
Jamie Curnow
b7e1e4fd9e Use the corresponding s6 binary for the built arch - fixes #298 2020-02-21 10:52:43 +10:00
Jamie Curnow
a1cebb889c Use cypress 4.0.2 2020-02-20 12:58:47 +10:00
Jamie Curnow
f040de5788 Update backend packages
Liquid required some changes
Version bump
2020-02-20 09:17:45 +10:00
jc21
e869c76e63
Updated version in readme label (#295) 2020-02-19 17:48:49 +11:00
Jamie Curnow
6f298ada61 Updated version in readme label 2020-02-19 16:48:18 +10:00
dependabot[bot]
26a8e234fa
Bump knex from 0.15.2 to 0.19.5 in /backend (#294)
Bumps [knex](https://github.com/knex/knex) from 0.15.2 to 0.19.5.
- [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.15.2...0.19.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: jc21 <jc@jc21.com>
2020-02-19 17:32:19 +11:00
Jamie Curnow
43b5720532 Fix docker push for branches containing slashes, again 2020-02-19 16:11:52 +10:00
Jamie Curnow
a25f196ceb Push to latest for master branch as well 2020-02-19 15:49:32 +10:00
Jamie Curnow
f9e15a4470 Fix docker push for branches containing slashes 2020-02-19 15:46:52 +10:00
Jamie Curnow
447cf12629 Fix master docker pushes, hopefully 2020-02-19 15:28:27 +10:00
jc21
bb0f4bfa62
v2.1.0 (#293)
* Fix wrapping when too many hosts are shown (#207)

* Update npm packages, fixes CVE-2019-10757

* Revert some breaking packages

* Major overhaul

- Docker buildx support in CI
- Cypress API Testing in CI
- Restructured folder layout (insert clean face meme)
- Added Swagger documentation and validate API against that (to be completed)
- Use common base image for all supported archs, which includes updated nginx with ipv6 support
- Updated certbot and changes required for it
- Large amount of Hosts names will wrap in UI
- Updated packages for frontend
- Version bump 2.1.0

* Updated documentation

* Fix JWT expire time going crazy. Now set to 1day

* Backend JS formatting rules

* Remove v1 importer, I doubt anyone is using v1 anymore

* Added backend formatting rules and enforce them
in Jenkins builds

* Fix CI, doesn't need a tty

* Thanks bcrypt. Why can't you just be normal.

* Cleanup after syntax check

Co-authored-by: Marcelo Castagna <margaale@users.noreply.github.com>
2020-02-19 15:55:06 +11:00
Russ
bf036cbb88 fix ipv6 resolver setup for nginx (#246) 2020-01-06 08:48:43 +10:00
jc21
8a9495de18
Update README.md 2019-11-29 09:46:41 +10:00
jc21
3e9614879a
Update README.md 2019-11-29 09:43:03 +10:00
Jamie Curnow
0057c793ee Updated Readme 2019-11-29 09:30:34 +10:00
Jamie Curnow
ea5bdab374 Fix CI permissions, again and again 2019-10-10 09:50:46 +10:00
Jamie Curnow
0e96ad62bb Fix CI permissions, again 2019-10-10 09:41:50 +10:00
Jamie Curnow
aa26f3908b Fix CI permissions 2019-10-10 08:44:12 +10:00
Jamie Curnow
d3f90647f5 Merge branch 'develop' of github.com:jc21/nginx-proxy-manager 2019-09-05 08:25:52 +10:00
Jamie Curnow
7d6c6129f2 Updated readme versions 2019-09-05 08:25:30 +10:00
jc21
0bc12f3bdf
Merge from develop v2.0.14 release (#196)
* Selection of the ssl protocols/ciphers is done using the default server block. (#189)
* Fix wrap for tags (#195)
2019-09-04 14:51:24 +10:00
Jamie Curnow
13767d13d6 Version bump 2019-09-04 14:41:48 +10:00
Steven Harris
a215958cec Fix wrap for tags (#195) 2019-09-04 14:40:59 +10:00
Jocelyn Le Sage
288086c78d Selection of the ssl protocols/ciphers is done using the default server block. (#189) 2019-08-21 10:52:00 +10:00
Carl Mercier
31aa9c9644 Allow including custom nginx conf files (#178)
* Allow including custom nginx conf files

Give advanced users more flexibility by allowing them to include custom config files at differents locations in the nginx configuration.

`/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
`/data/nginx/custom/http.conf`: Included at the end of the main `http` 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_stream.conf`: Included at the end of every stream `server` block
`/data/nginx/custom/server_stream_tcp.conf`: Included at the end of every TCP stream `server` block
`/data/nginx/custom/server_stream_udp.conf`: Included at the end of every UDP stream `server` block

* Don't fail if file doesn't exist

* Advanced Nginx settings doc
2019-08-09 11:19:42 +10:00
Paul Mansfield
ddbfdf6f6e Open up lets Encrypt acme challenge config (#165)
Since Lets Encrypt don't publish IP ranges that their acme challenge service will be sourced from, we need to allow free access to this location special to override any IP ACLs added by Advanced Custom Nginx Configuration. Due to the way Nginx config is applied, this only applies to the regex and below, keeping the IP ACLs working for the rest of the website.
2019-07-05 08:32:41 +10:00
Lukas Meyer
43c7063538 Center username vertically (#163)
Center username/role container vertically within header
2019-06-25 15:25:45 +10:00
Jamie Curnow
3f089fb239 Updated documentation, installation instructions and examples 2019-05-10 15:31:25 +10:00
Jamie Curnow
2d0f7d5126 Updated documentation, installation instructions and examples 2019-05-10 15:26:12 +10:00
Jamie Curnow
06272d3d2c Use correct var when returning updated certificate 2019-05-09 10:03:41 +10:00
Jamie Curnow
3885c0ad6d Add cert renewals to audit log 2019-05-09 09:20:49 +10:00
Jamie Curnow
099ec00155 Don't use LE staging when debug mode is on in production 2019-05-09 08:58:10 +10:00
Jamie Curnow
92fcae9c54 Added missing dialog for renewing certs 2019-05-08 15:34:14 +10:00
Jamie Curnow
22e8961c80 Fixes #104 - allow using / location in custom location 2019-05-08 15:33:54 +10:00
Jamie Curnow
4d5adefa41 Added ability to force renew a LE cert, and also fix revoking certs 2019-05-08 15:25:48 +10:00
Jamie Curnow
feaa0e51bd Removed use strict 2019-05-08 15:24:57 +10:00
Jamie Curnow
af83cb57d0 Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into develop 2019-05-08 11:23:50 +10:00
Jamie Curnow
8b4f3507c3 Revert to previous tabler version to hopefully fix ui issues 2019-05-08 11:21:59 +10:00
Jamie Curnow
bda3dba369 Revert to previous tabler version to hopefully fix ui issues 2019-05-08 10:53:44 +10:00
Jamie Curnow
beb313af40 Merge branch 'master' of github.com:jc21/nginx-proxy-manager into develop 2019-05-08 10:11:32 +10:00
OhHeyAlan
4fad9d672f Correcting X-XSS-Protection Header (#136)
* Correcting X-XSS-Protection Header

X-XSS-Protection sets the configuration for the cross-site scripting filters built into most browsers. The best configuration is "X-XSS-Protection: 1; mode=block".

Was "0"
Now "1; mode=block"

* Update issue templates
2019-05-08 10:11:05 +10:00
Carl Sutton
0fca64929e Try DNS challenge in addition to http (#85) 2019-05-08 10:07:43 +10:00
OhHeyAlan
9e476e5b24 Only Secure TLS Ciphers & Protocols (#134)
Disable insecure SSL/TLS ciphers & protocols. Only TLS_1.2 and TLS_1.3 should be enabled.
2019-05-08 10:01:08 +10:00
Jamie Curnow
0819a265f5 Bumped version 2019-05-08 09:50:20 +10:00
jc21
ad8eac4f07 Update issue templates 2019-05-08 09:36:44 +10:00
Jamie Curnow
b49de0e23e Enable TLS 1.3 by default 2019-05-02 13:03:16 +10:00
Stephen Roberts
efbd024da9 Update copyright year (#121)
Updated the year in the copyright statement in the footer
2019-04-20 21:28:06 +10:00
Jocelyn Le Sage
e7ddcb91fc Fixed directory traversal vulnerability. (#114)
Awesome find!
2019-04-03 08:37:40 +10:00
Jamie Curnow
3095cff7d9 Forgot to change dockerfiles to match CI names 2019-03-19 07:01:12 +10:00
Jamie Curnow
6d8f5aa3a7 Version bump 2019-03-15 07:49:08 +10:00
Jamie Curnow
27a06850ff CI Docker manifest improvements 2019-03-15 07:49:08 +10:00
Jamie Curnow
dce6423c85 Fixes #103 - Allow for longer domain names 2019-03-15 07:49:08 +10:00
kolbii
d79fcbf447 This commit resolves #98 so custom location can forward to custom path. (#99)
Awesome work!
2019-03-11 13:52:09 +10:00
Jamie Curnow
631d9ae4eb CI Changes, docker image tag changes and manifests 2019-03-07 09:45:01 +10:00
Jamie Curnow
0ac349ba67 CI Changes, docker image tag changes and manifests 2019-03-07 09:45:01 +10:00
Jamie Curnow
1b0563a4a6 CI Changes, docker image tag changes and manifests 2019-03-07 09:45:01 +10:00
Jamie Curnow
1db2a29d49 CI Changes, docker image tag changes and manifests 2019-03-07 09:45:01 +10:00
Jamie Curnow
14e62a0830 CI Changes, docker image tag changes and manifests 2019-03-07 09:45:01 +10:00
Jamie Curnow
2280a61c2b CI Fix for arm64 2019-03-05 08:25:12 +10:00
Jamie Curnow
f3e6f64c0c Version Bump 2019-03-05 08:25:12 +10:00
Jamie Curnow
d04b7a0d88 Bug fixes 2019-03-05 08:25:12 +10:00
kolbii
71dfd5d8f8 Feature/custom locations (#74)
* New feature: custom locations

* Custom locations: exteding config generator

* Custom locations: refactoring

* Fixing proxy_host table on small screens

* Custom locations: translations

* Custom locations bugfix

* Custom locations bugfix

* PR #74 fixes
2019-03-05 08:21:02 +10:00
jc21
133d66c2fe
Default Site customisation and new Settings space (#91) 2019-03-04 21:19:36 +10:00
jc21
6f1d38a0e2
Fixes #88 - Allow specifying X-FRAME-OPTIONS with an environment variable (#89) 2019-03-04 10:16:46 +10:00
Jamie Curnow
aad9ecde6b CI: Prevent having to spin up resources when not Master branch 2019-03-01 20:12:49 +10:00
Jamie Curnow
ae9324295c Merge branch 'develop' of github.com:jc21/nginx-proxy-manager into develop 2019-03-01 13:48:30 +10:00
Jamie Curnow
0acec1105b CI: Prevent having to spin up resources when not Master branch 2019-03-01 20:12:49 +10:00
Jamie Curnow
5a9a716ca6 CI: Prevent having to spin up resources when not Master branch 2019-03-01 13:47:49 +10:00
Jamie Curnow
418899d425 Version bump 2019-02-27 17:52:30 +10:00
jc21
e7379e3683
Ignore default location when defined in advanced config (#79) 2019-02-25 10:42:16 +10:00
jc21
29bebcc73e
Ignore default location when defined in advanced config (#79) 2019-02-25 10:34:55 +10:00
Jamie Curnow
26064b20b8 Fix PR docker image pushing to wrong repo 2019-02-20 08:25:12 +10:00
jc21
3dc9b20543
CI Improvements (#77) 2019-02-20 14:35:10 +10:00
Jamie Curnow
444dbd5160 Added PR build steps to CI 2019-02-20 08:25:12 +10:00
Jamie Curnow
c2f99e253c Merge branch 'master' of github.com:jc21/nginx-proxy-manager 2019-02-20 10:04:16 +10:00
Jamie Curnow
5c7fb7b698 Added armv6 Dockerfile 2019-02-20 08:25:12 +10:00
jc21
733d7d9583
Update DOCKERHUB.md 2019-02-19 17:05:26 +10:00
612 changed files with 44799 additions and 13132 deletions

View File

@ -1,12 +0,0 @@
{
"presets": [
["env", {
"targets": {
"browsers": ["Chrome >= 65"]
},
"debug": false,
"modules": false,
"useBuiltIns": "usage"
}]
]
}

55
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,55 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
<!--
Are you in the right place?
- If you are looking for support on how to get your upstream server forwarding, please consider asking the community on Reddit.
- If you are writing code changes to contribute and need to ask about the internals of the software, Gitter is the best place to ask.
- If you think you found a bug with NPM (not Nginx, or your upstream server or MySql) then you are in the *right place.*
-->
**Checklist**
- Have you pulled and found the error with `jc21/nginx-proxy-manager:latest` docker image?
- Yes / No
- Are you sure you're not using someone else's docker image?
- Yes / No
- Have you searched for similar issues (both open and closed)?
- Yes / No
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**Nginx Proxy Manager Version**
<!-- What version of Nginx Proxy Manager is reported on the login page? -->
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Operating System**
<!-- Please specify if using a Rpi, Mac, orchestration tool or any other setups that might affect the reproduction of this error. -->
**Additional context**
<!-- Add any other context about the problem here, docker version, browser version, logs if applicable to the problem. Too much info is better than too little. -->

View File

@ -0,0 +1,18 @@
---
name: DNS challenge provider request
about: Suggest a new provider to be available for a certificate DNS challenge
title: ''
labels: dns provider request
assignees: ''
---
**What provider would you like to see added to NPM?**
<!-- What is this provider called? -->
**Have you checked if a certbot plugin exists?**
<!--
Currently NPM only supports DNS challenge providers for which a certbot plugin exists.
You can visit pypi.org, and search for a package with the name `certbot-dns-<privider>`.
-->

View File

@ -0,0 +1,32 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
<!--
Are you in the right place?
- If you are looking for support on how to get your upstream server forwarding, please consider asking the community on Reddit.
- If you are writing code changes to contribute and need to ask about the internals of the software, Gitter is the best place to ask.
- If you think you found a bug with NPM (not Nginx, or your upstream server or MySql) then you are in the *right place.*
-->
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

13
.gitignore vendored
View File

@ -1,14 +1,5 @@
.DS_Store
.idea
._*
node_modules
core*
config/development.json
dist
webpack_stats.html
data/*
yarn-error.log
yarn.lock
tmp
certbot.log
.vscode
certbot-help.txt

1
.version Normal file
View File

@ -0,0 +1 @@
2.9.19

View File

@ -1,39 +0,0 @@
FROM jc21/nginx-proxy-manager-base:latest
MAINTAINER Jamie Curnow <jc@jc21.com>
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV SUPPRESS_NO_CONFIG_WARNING=1
ENV S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
# Nginx, Node and required packages should already be installed from the base image
# root filesystem
COPY rootfs /
# s6 overlay
RUN curl -L -o /tmp/s6-overlay-amd64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.21.4.0/s6-overlay-amd64.tar.gz" \
&& tar xzf /tmp/s6-overlay-amd64.tar.gz -C /
# App
ENV NODE_ENV=production
ADD dist /app/dist
ADD node_modules /app/node_modules
ADD src/backend /app/src/backend
ADD package.json /app/package.json
ADD knexfile.js /app/knexfile.js
# Volumes
VOLUME [ "/data", "/etc/letsencrypt" ]
CMD [ "/init" ]
# Ports
EXPOSE 80
EXPOSE 81
EXPOSE 443
EXPOSE 9876
HEALTHCHECK --interval=15s --timeout=3s CMD curl -f http://localhost:9876/health || exit 1

View File

@ -1,38 +0,0 @@
FROM jc21/nginx-proxy-manager-base:arm64
MAINTAINER Jamie Curnow <jc@jc21.com>
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV SUPPRESS_NO_CONFIG_WARNING=1
ENV S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
# Nginx, Node and required packages should already be installed from the base image
# root filesystem
COPY rootfs /
# s6 overlay
RUN curl -L -o /tmp/s6-overlay-aarch64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-aarch64.tar.gz" \
&& tar xzf /tmp/s6-overlay-aarch64.tar.gz -C /
# App
ENV NODE_ENV=production
ADD dist /app/dist
ADD node_modules /app/node_modules
ADD src/backend /app/src/backend
ADD package.json /app/package.json
ADD knexfile.js /app/knexfile.js
# Volumes
VOLUME [ "/data", "/etc/letsencrypt" ]
CMD [ "/init" ]
# Ports
EXPOSE 80
EXPOSE 81
EXPOSE 443
EXPOSE 9876
HEALTHCHECK --interval=15s --timeout=3s CMD curl -f http://localhost:9876/health || exit 1

View File

@ -1,38 +0,0 @@
FROM jc21/nginx-proxy-manager-base:armhf
MAINTAINER Jamie Curnow <jc@jc21.com>
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV SUPPRESS_NO_CONFIG_WARNING=1
ENV S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
# Nginx, Node and required packages should already be installed from the base image
# root filesystem
COPY rootfs /
# s6 overlay
RUN curl -L -o /tmp/s6-overlay-armhf.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.21.4.0/s6-overlay-armhf.tar.gz" \
&& tar xzf /tmp/s6-overlay-armhf.tar.gz -C /
# App
ENV NODE_ENV=production
ADD dist /app/dist
ADD node_modules /app/node_modules
ADD src/backend /app/src/backend
ADD package.json /app/package.json
ADD knexfile.js /app/knexfile.js
# Volumes
VOLUME [ "/data", "/etc/letsencrypt" ]
CMD [ "/init" ]
# Ports
EXPOSE 80
EXPOSE 81
EXPOSE 443
EXPOSE 9876
HEALTHCHECK --interval=15s --timeout=3s CMD curl -f http://localhost:9876/health || exit 1

447
Jenkinsfile vendored
View File

@ -1,216 +1,253 @@
pipeline {
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
disableConcurrentBuilds()
}
agent any
environment {
IMAGE = "nginx-proxy-manager"
BASE_IMAGE = "jc21/nginx-proxy-manager-base"
TEMP_IMAGE = "nginx-proxy-manager-build_${BUILD_NUMBER}"
TEMP_IMAGE_ARM = "nginx-proxy-manager-arm-build_${BUILD_NUMBER}"
TEMP_IMAGE_ARM64 = "nginx-proxy-manager-arm64-build_${BUILD_NUMBER}"
TAG_VERSION = getPackageVersion()
MAJOR_VERSION = "2"
}
stages {
stage('Prepare') {
steps {
sh 'docker pull $DOCKER_CI_TOOLS'
}
}
stage('Build Develop') {
when {
branch 'develop'
}
steps {
ansiColor('xterm') {
// Codebase
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE yarn install'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE npm run-script build'
sh 'rm -rf node_modules'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE yarn install --prod'
sh 'docker run --rm -v $(pwd):/data $DOCKER_CI_TOOLS node-prune'
agent {
label 'docker-multiarch'
}
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
disableConcurrentBuilds()
ansiColor('xterm')
}
environment {
IMAGE = "nginx-proxy-manager"
BUILD_VERSION = getVersion()
MAJOR_VERSION = "2"
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}"
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_FILE = 'docker/docker-compose.ci.yml'
COMPOSE_INTERACTIVE_NO_CLI = 1
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
}
stages {
stage('Environment') {
parallel {
stage('Master') {
when {
branch 'master'
}
steps {
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"
}
}
}
stage('Other') {
when {
not {
branch 'master'
}
}
steps {
script {
// 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}"
}
}
}
stage('Versions') {
steps {
sh 'cat frontend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge frontend/package.json'
sh 'echo -e "\\E[1;36mFrontend Version is:\\E[1;33m $(cat frontend/package.json | jq -r .version)\\E[0m"'
sh 'cat backend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge backend/package.json'
sh 'echo -e "\\E[1;36mBackend Version is:\\E[1;33m $(cat backend/package.json | jq -r .version)\\E[0m"'
sh 'sed -i -E "s/(version-)[0-9]+\\.[0-9]+\\.[0-9]+(-green)/\\1${BUILD_VERSION}\\2/" README.md'
}
}
}
}
stage('Frontend') {
steps {
sh './scripts/frontend-build'
}
}
stage('Backend') {
steps {
echo 'Checking Syntax ...'
sh 'docker pull nginxproxymanager/nginx-full:certbot-node'
// See: https://github.com/yarnpkg/yarn/issues/3254
sh '''docker run --rm \\
-v "$(pwd)/backend:/app" \\
-v "$(pwd)/global:/app/global" \\
-w /app \\
nginxproxymanager/nginx-full:certbot-node \\
sh -c "yarn install && yarn eslint . && rm -rf node_modules"
'''
// Docker Build
sh 'docker build --pull --no-cache --squash --compress -t $TEMP_IMAGE .'
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') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
// Dockerhub
sh 'docker tag $TEMP_IMAGE docker.io/jc21/$IMAGE:develop'
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass'"
sh 'docker push docker.io/jc21/$IMAGE:develop'
}
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-sqlite'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Integration Tests Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
// Private Registry
sh 'docker tag $TEMP_IMAGE $DOCKER_PRIVATE_REGISTRY/$IMAGE:develop'
withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass' $DOCKER_PRIVATE_REGISTRY"
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:develop'
}
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Docs') {
when {
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
steps {
dir(path: 'docs') {
sh 'yarn install'
sh 'yarn build'
}
sh 'docker rmi $TEMP_IMAGE'
}
}
}
stage('Build Master') {
parallel {
stage('x86_64') {
when {
branch 'master'
}
steps {
ansiColor('xterm') {
// Codebase
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE yarn install'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE npm run-script build'
sh 'rm -rf node_modules'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE yarn install --prod'
sh 'docker run --rm -v $(pwd):/data $DOCKER_CI_TOOLS node-prune'
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
// Docker Build
sh 'docker build --pull --no-cache --squash --compress -t $TEMP_IMAGE .'
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
}
}
stage('MultiArch Build') {
when {
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
steps {
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
// Docker Login
sh "docker login -u '${duser}' -p '${dpass}'"
// Buildx with push from cache
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
}
}
}
stage('Docs Deploy') {
when {
allOf {
branch 'master'
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'npm-s3-docs', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
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/
"""
// Dockerhub
sh 'docker tag $TEMP_IMAGE docker.io/jc21/$IMAGE:$TAG_VERSION'
sh 'docker tag $TEMP_IMAGE docker.io/jc21/$IMAGE:$MAJOR_VERSION'
sh 'docker tag $TEMP_IMAGE docker.io/jc21/$IMAGE:latest'
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass'"
sh 'docker push docker.io/jc21/$IMAGE:$TAG_VERSION'
sh 'docker push docker.io/jc21/$IMAGE:$MAJOR_VERSION'
sh 'docker push docker.io/jc21/$IMAGE:latest'
}
// Private Registry
sh 'docker tag $TEMP_IMAGE $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION'
sh 'docker tag $TEMP_IMAGE $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION'
sh 'docker tag $TEMP_IMAGE $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest'
withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass' $DOCKER_PRIVATE_REGISTRY"
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest'
}
sh 'docker rmi $TEMP_IMAGE'
}
}
}
stage('armhf') {
when {
branch 'master'
}
agent {
label 'armhf'
}
steps {
ansiColor('xterm') {
// Codebase
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:armhf yarn install'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:armhf npm run-script build'
sh 'rm -rf node_modules'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:armhf yarn install --prod'
// Docker Build
sh 'docker build --pull --no-cache --squash --compress -t $TEMP_IMAGE_ARM -f Dockerfile.armhf .'
// Dockerhub
sh 'docker tag $TEMP_IMAGE_ARM docker.io/jc21/$IMAGE:$TAG_VERSION-armhf'
sh 'docker tag $TEMP_IMAGE_ARM docker.io/jc21/$IMAGE:$MAJOR_VERSION-armhf'
sh 'docker tag $TEMP_IMAGE_ARM docker.io/jc21/$IMAGE:latest-armhf'
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass'"
sh 'docker push docker.io/jc21/$IMAGE:$TAG_VERSION-armhf'
sh 'docker push docker.io/jc21/$IMAGE:$MAJOR_VERSION-armhf'
sh 'docker push docker.io/jc21/$IMAGE:latest-armhf'
}
// Private Registry
sh 'docker tag $TEMP_IMAGE_ARM $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION-armhf'
sh 'docker tag $TEMP_IMAGE_ARM $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION-armhf'
sh 'docker tag $TEMP_IMAGE_ARM $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest-armhf'
withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass' $DOCKER_PRIVATE_REGISTRY"
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION-armhf'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION-armhf'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest-armhf'
}
sh 'docker rmi $TEMP_IMAGE_ARM'
}
}
}
stage('arm64') {
when {
branch 'master'
}
agent {
label 'arm64'
}
steps {
ansiColor('xterm') {
// Codebase
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:arm64 yarn install'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:arm64 npm run-script build'
sh 'sudo rm -rf node_modules'
sh 'docker run --rm -v $(pwd):/app -w /app $BASE_IMAGE:arm64 yarn install --prod'
// Docker Build
sh 'docker build --pull --no-cache --squash --compress -t $TEMP_IMAGE_ARM64 -f Dockerfile.arm64 .'
// Dockerhub
sh 'docker tag $TEMP_IMAGE_ARM64 docker.io/jc21/$IMAGE:$TAG_VERSION-arm64'
sh 'docker tag $TEMP_IMAGE_ARM64 docker.io/jc21/$IMAGE:$MAJOR_VERSION-arm64'
sh 'docker tag $TEMP_IMAGE_ARM64 docker.io/jc21/$IMAGE:latest-arm64'
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass'"
sh 'docker push docker.io/jc21/$IMAGE:$TAG_VERSION-arm64'
sh 'docker push docker.io/jc21/$IMAGE:$MAJOR_VERSION-arm64'
sh 'docker push docker.io/jc21/$IMAGE:latest-arm64'
}
// Private Registry
sh 'docker tag $TEMP_IMAGE_ARM64 $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION-arm64'
sh 'docker tag $TEMP_IMAGE_ARM64 $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION-arm64'
sh 'docker tag $TEMP_IMAGE_ARM64 $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest-arm64'
withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '$dpass' $DOCKER_PRIVATE_REGISTRY"
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$TAG_VERSION-arm64'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:$MAJOR_VERSION-arm64'
sh 'docker push $DOCKER_PRIVATE_REGISTRY/$IMAGE:latest-arm64'
}
sh 'docker rmi $TEMP_IMAGE_ARM64'
// Hack to clean up ec2 instance for next build
sh 'sudo chown -R ec2-user:ec2-user *'
}
}
}
}
}
}
post {
success {
juxtapose event: 'success'
sh 'figlet "SUCCESS"'
}
failure {
juxtapose event: 'failure'
sh 'figlet "FAILURE"'
}
}
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') {
when {
allOf {
changeRequest()
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
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.")
}
}
}
}
post {
always {
sh 'docker-compose down --remove-orphans --volumes -t 30'
sh 'echo Reverting ownership'
sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
}
success {
juxtapose event: 'success'
sh 'figlet "SUCCESS"'
}
failure {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
juxtapose event: 'failure'
sh 'figlet "FAILURE"'
}
unstable {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
juxtapose event: 'unstable'
sh 'figlet "UNSTABLE"'
}
}
}
def getPackageVersion() {
ver = sh(script: 'docker run --rm -v $(pwd):/data $DOCKER_CI_TOOLS bash -c "cat /data/package.json|jq -r \'.version\'"', returnStdout: true)
return ver.trim()
def getVersion() {
ver = sh(script: 'cat .version', returnStdout: true)
return ver.trim()
}
def getCommit() {
ver = sh(script: 'git log -n 1 --format=%h', returnStdout: true)
return ver.trim()
}

158
README.md
View File

@ -1,15 +1,22 @@
![Nginx Proxy Manager](https://public.jc21.com/nginx-proxy-manager/github.png "Nginx Proxy Manager")
# Nginx Proxy Manager
![Version](https://img.shields.io/badge/version-2.0.9-green.svg?style=for-the-badge)
![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge)
![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge)
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.9.19-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<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">
</a>
</p>
This project comes as a pre-built docker image that enables you to easily forward to your websites
running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
- [Quick Setup](#quick-setup)
- [Full Setup](https://nginxproxymanager.com/setup/)
- [Screenshots](https://nginxproxymanager.com/screenshots/)
## Project Goal
I created this project to fill a personal need to provide users with a easy way to accomplish reverse
@ -17,89 +24,86 @@ proxying hosts with SSL termination and it had to be so easy that a monkey could
While there might be advanced options they are optional and the project should be as simple as possible
so that the barrier for entry here is low.
<a href="https://www.buymeacoffee.com/jc21" target="_blank"><img src="http://public.jc21.com/github/by-me-a-coffee.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
## Features
- Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io/)
- Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx
- Free SSL using Let's Encrypt or provide your own custom SSL certificates
- Free SSL using Let's Encrypt or provide your own custom SSL certificates
- Access Lists and basic HTTP Authentication for your hosts
- Advanced Nginx configuration available for super users
- User management, permissions and audit log
## Screenshots
[![Login](https://public.jc21.com/nginx-proxy-manager/v2/small/login.jpg "Login")](https://public.jc21.com/nginx-proxy-manager/v2/large/login.jpg)
[![Dashboard](https://public.jc21.com/nginx-proxy-manager/v2/small/dashboard.jpg "Dashboard")](https://public.jc21.com/nginx-proxy-manager/v2/large/dashboard.jpg)
[![Proxy Hosts](https://public.jc21.com/nginx-proxy-manager/v2/small/proxy-hosts.jpg "Proxy Hosts")](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts.jpg)
[![Proxy Host Settings](https://public.jc21.com/nginx-proxy-manager/v2/small/proxy-hosts-new1.jpg "Proxy Host Settings")](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts-new1.jpg)
[![Proxy Host SSL](https://public.jc21.com/nginx-proxy-manager/v2/small/proxy-hosts-new2.jpg "Proxy Host SSL")](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts-new2.jpg)
[![Redirection Hosts](https://public.jc21.com/nginx-proxy-manager/v2/small/redirection-hosts.jpg "Redirection Hosts")](https://public.jc21.com/nginx-proxy-manager/v2/large/redirection-hosts.jpg)
[![Redirection Host Settings](https://public.jc21.com/nginx-proxy-manager/v2/small/redirection-hosts-new1.jpg "Redirection Host Settings")](https://public.jc21.com/nginx-proxy-manager/v2/large/redirection-hosts-new1.jpg)
[![Streams](https://public.jc21.com/nginx-proxy-manager/v2/small/streams.jpg "Streams")](https://public.jc21.com/nginx-proxy-manager/v2/large/streams.jpg)
[![Stream Settings](https://public.jc21.com/nginx-proxy-manager/v2/small/streams-new1.jpg "Stream Settings")](https://public.jc21.com/nginx-proxy-manager/v2/large/streams-new1.jpg)
[![404 Hosts](https://public.jc21.com/nginx-proxy-manager/v2/small/dead-hosts.jpg "404 Hosts")](https://public.jc21.com/nginx-proxy-manager/v2/large/dead-hosts.jpg)
[![404 Host Settings](https://public.jc21.com/nginx-proxy-manager/v2/small/dead-hosts-new1.jpg "404 Host Settings")](https://public.jc21.com/nginx-proxy-manager/v2/large/dead-hosts-new1.jpg)
[![Certificates](https://public.jc21.com/nginx-proxy-manager/v2/small/certificates.jpg "Certificates")](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates.jpg)
[![Lets Encrypt Certificates](https://public.jc21.com/nginx-proxy-manager/v2/small/certificates-new1.jpg "Lets Encrypt Certificates")](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates-new1.jpg)
[![Custom Certificates](https://public.jc21.com/nginx-proxy-manager/v2/small/certificates-new2.jpg "Custom Certificates")](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates-new2.jpg)
[![Access Lists](https://public.jc21.com/nginx-proxy-manager/v2/small/access-lists.jpg "Access Lists")](https://public.jc21.com/nginx-proxy-manager/v2/large/access-lists.jpg)
[![Access List Users](https://public.jc21.com/nginx-proxy-manager/v2/small/access-lists-new1.jpg "Access List Users")](https://public.jc21.com/nginx-proxy-manager/v2/large/access-lists-new1.jpg)
[![Users](https://public.jc21.com/nginx-proxy-manager/v2/small/users.jpg "Users")](https://public.jc21.com/nginx-proxy-manager/v2/large/users.jpg)
[![User Permissions](https://public.jc21.com/nginx-proxy-manager/v2/small/users-permissions.jpg "User Permissions")](https://public.jc21.com/nginx-proxy-manager/v2/large/users-permissions.jpg)
[![Audit Log](https://public.jc21.com/nginx-proxy-manager/v2/small/audit-log.jpg "Audit Log")](https://public.jc21.com/nginx-proxy-manager/v2/large/audit-log.jpg)
## Getting started
Please consult the [installation instructions](doc/INSTALL.md) for a complete guide or
if you just want to get up and running in the quickest time possible, grab all the files in the `doc/example/` folder and run `docker-compose up -d`
## Importing from Version 1?
Here's a [guide for you to migrate your configuration](doc/IMPORTING.md). You should definitely read the [installation instructions](doc/INSTALL.md) first though.
**Why should I?**
Version 2 has the following improvements:
- Management security and multiple user access
- User permissions and visibility
- Custom SSL certificate support
- Audit log of changes
- Broken nginx config detection
- Multiple domains in Let's Encrypt certificates
- Wildcard domain name support (not available with a Let's Encrypt certificate though)
- It's super sexy
## Administration
When your docker container is running, connect to it on port `81` for the admin interface.
[http://localhost:81](http://localhost:81)
Note: Requesting SSL Certificates won't work until this project is accessible from the outside world, as explained below.
### Default Administrator User
```
Email: admin@example.com
Password: changeme
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Hosting your home network
I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
1. Your home router will have a Port Forwarding section somewhere. Log in and find it
2. Add port forwarding for port 80 and 443 to the server hosting this project
3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS
4. Use the Nginx Proxy Manager here as your gateway to forward to your other web based services
3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
## Quick Setup
1. Install Docker and Docker-Compose
- [Docker Install documentation](https://docs.docker.com/install/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
2. Create a docker-compose.yml file similar to this:
```yml
version: '3'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
```
3. Bring up your stack by running
```bash
docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
```
4. Log in to the Admin UI
When your docker container is running, connect to it on port `81` for the admin interface.
Sometimes this can take a little bit because of the entropy of keys.
[http://127.0.0.1:81](http://127.0.0.1:81)
Default Admin User:
```
Email: admin@example.com
Password: changeme
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Contributors
Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
## Getting Support
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
3. [Development Gitter](https://gitter.im/nginx-proxy-manager/community)
4. [Reddit](https://reddit.com/r/nginxproxymanager)

73
backend/.eslintrc.json Normal file
View File

@ -0,0 +1,73 @@
{
"env": {
"node": true,
"es6": true
},
"extends": [
"eslint:recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"align-assignments"
],
"rules": {
"arrow-parens": [
"error",
"always"
],
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"key-spacing": [
"error",
{
"align": "value"
}
],
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
"func-call-spacing": [
"error",
"never"
],
"keyword-spacing": [
"error",
{
"before": true
}
],
"no-irregular-whitespace": "error",
"no-unused-expressions": 0,
"align-assignments/align-assignments": [
2,
{
"requiresOnly": false
}
]
}
}

8
backend/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
config/development.json
data/*
yarn-error.log
tmp
certbot.log
node_modules
core.*

11
backend/.prettierrc Normal file
View File

@ -0,0 +1,11 @@
{
"printWidth": 320,
"tabWidth": 4,
"useTabs": true,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"jsxBracketSameLine": true,
"trailingComma": "all",
"proseWrap": "always"
}

8
backend/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"editor.insertSpaces": false,
"editor.formatOnSave": true,
"files.trimTrailingWhitespace": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}

89
backend/app.js Normal file
View File

@ -0,0 +1,89 @@
const express = require('express');
const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const compression = require('compression');
const log = require('./logger').express;
/**
* App
*/
const app = express();
app.use(fileUpload());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Gzip
app.use(compression());
/**
* General Logging, BEFORE routes
*/
app.disable('x-powered-by');
app.enable('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
app.enable('strict routing');
// pretty print JSON when not live
if (process.env.NODE_ENV !== 'production') {
app.set('json spaces', 2);
}
// CORS for everything
app.use(require('./lib/express/cors'));
// General security/cache related headers + server header
app.use(function (req, res, next) {
let x_frame_options = 'DENY';
if (typeof process.env.X_FRAME_OPTIONS !== 'undefined' && process.env.X_FRAME_OPTIONS) {
x_frame_options = process.env.X_FRAME_OPTIONS;
}
res.set({
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': x_frame_options,
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
Pragma: 'no-cache',
Expires: 0
});
next();
});
app.use(require('./lib/express/jwt')());
app.use('/', require('./routes/api/main'));
// production error handler
// no stacktraces leaked to user
// eslint-disable-next-line
app.use(function (err, req, res, next) {
let payload = {
error: {
code: err.status,
message: err.public ? err.message : 'Internal Error'
}
};
if (process.env.NODE_ENV === 'development' || (req.baseUrl + req.path).includes('nginx/certificates')) {
payload.debug = {
stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null,
previous: err.previous
};
}
// Not every error is worth logging - but this is good for now until it gets annoying.
if (typeof err.stack !== 'undefined' && err.stack) {
if (process.env.NODE_ENV === 'development' || process.env.DEBUG) {
log.debug(err.stack);
} else if (typeof err.public == 'undefined' || !err.public) {
log.warn(err.message);
}
}
res
.status(err.status || 500)
.send(payload);
});
module.exports = app;

View File

@ -0,0 +1,26 @@
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/app/config/mydb.sqlite"
},
"pool": {
"min": 0,
"max": 1,
"createTimeoutMillis": 3000,
"acquireTimeoutMillis": 30000,
"idleTimeoutMillis": 30000,
"reapIntervalMillis": 1000,
"createRetryIntervalMillis": 100,
"propagateCreateError": false
},
"migrations": {
"tableName": "migrations",
"stub": "src/backend/lib/migrate_template.js",
"directory": "src/backend/migrations"
}
}
}
}

33
backend/db.js Normal file
View File

@ -0,0 +1,33 @@
const config = require('config');
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');
}
function generateDbConfig() {
if (config.database.engine === 'knex-native') {
return config.database.knex;
} else
return {
client: config.database.engine,
connection: {
host: config.database.host,
user: config.database.user,
password: config.database.password,
database: config.database.name,
port: config.database.port
},
migrations: {
tableName: 'migrations'
}
};
}
let data = generateDbConfig();
if (typeof config.database.version !== 'undefined') {
data.version = config.database.version;
}
module.exports = require('knex')(data);

1254
backend/doc/api.swagger.json Normal file

File diff suppressed because it is too large Load Diff

135
backend/index.js Normal file
View File

@ -0,0 +1,135 @@
#!/usr/bin/env node
const logger = require('./logger').global;
async function appStart () {
// Create config file db settings if environment variables have been set
await createDbConfigFromEnvironment();
const migrate = require('./migrate');
const setup = require('./setup');
const app = require('./app');
const apiValidator = require('./lib/validator/api');
const internalCertificate = require('./internal/certificate');
const internalIpRanges = require('./internal/ip_ranges');
return migrate.latest()
.then(setup)
.then(() => {
return apiValidator.loadSchemas;
})
.then(internalIpRanges.fetch)
.then(() => {
internalCertificate.initTimer();
internalIpRanges.initTimer();
const server = app.listen(3000, () => {
logger.info('Backend PID ' + process.pid + ' listening on port 3000 ...');
process.on('SIGTERM', () => {
logger.info('PID ' + process.pid + ' received SIGTERM');
server.close(() => {
logger.info('Stopping.');
process.exit(0);
});
});
});
})
.catch((err) => {
logger.error(err.message);
setTimeout(appStart, 1000);
});
}
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 {
appStart();
} catch (err) {
logger.error(err.message, err);
process.exit(1);
}

View File

@ -0,0 +1,534 @@
const _ = require('lodash');
const fs = require('fs');
const batchflow = require('batchflow');
const logger = require('../logger').access;
const error = require('../lib/error');
const accessListModel = require('../models/access_list');
const accessListAuthModel = require('../models/access_list_auth');
const accessListClientModel = require('../models/access_list_client');
const proxyHostModel = require('../models/proxy_host');
const internalAuditLog = require('./audit-log');
const internalNginx = require('./nginx');
const utils = require('../lib/utils');
function omissions () {
return ['is_deleted'];
}
const internalAccessList = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
return access.can('access_lists:create', data)
.then((/*access_data*/) => {
return accessListModel
.query()
.omit(omissions())
.insertAndFetch({
name: data.name,
satisfy_any: data.satisfy_any,
pass_auth: data.pass_auth,
owner_user_id: access.token.getUserId(1)
});
})
.then((row) => {
data.id = row.id;
let promises = [];
// Now add the items
data.items.map((item) => {
promises.push(accessListAuthModel
.query()
.insert({
access_list_id: row.id,
username: item.username,
password: item.password
})
);
});
// Now add the clients
if (typeof data.clients !== 'undefined' && data.clients) {
data.clients.map((client) => {
promises.push(accessListClientModel
.query()
.insert({
access_list_id: row.id,
address: client.address,
directive: client.directive
})
);
});
}
return Promise.all(promises);
})
.then(() => {
// re-fetch with expansions
return internalAccessList.get(access, {
id: data.id,
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
}, true /* <- skip masking */);
})
.then((row) => {
// Audit log
data.meta = _.assign({}, data.meta || {}, row.meta);
return internalAccessList.build(row)
.then(() => {
if (row.proxy_host_count) {
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
}
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'access-list',
object_id: row.id,
meta: internalAccessList.maskItems(data)
});
})
.then(() => {
return internalAccessList.maskItems(row);
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {String} [data.name]
* @param {String} [data.items]
* @return {Promise}
*/
update: (access, data) => {
return access.can('access_lists:update', data.id)
.then((/*access_data*/) => {
return internalAccessList.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Access List could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
})
.then(() => {
// patch name if specified
if (typeof data.name !== 'undefined' && data.name) {
return accessListModel
.query()
.where({id: data.id})
.patch({
name: data.name,
satisfy_any: data.satisfy_any,
pass_auth: data.pass_auth,
});
}
})
.then(() => {
// Check for items and add/update/remove them
if (typeof data.items !== 'undefined' && data.items) {
let promises = [];
let items_to_keep = [];
data.items.map(function (item) {
if (item.password) {
promises.push(accessListAuthModel
.query()
.insert({
access_list_id: data.id,
username: item.username,
password: item.password
})
);
} else {
// This was supplied with an empty password, which means keep it but don't change the password
items_to_keep.push(item.username);
}
});
let query = accessListAuthModel
.query()
.delete()
.where('access_list_id', data.id);
if (items_to_keep.length) {
query.andWhere('username', 'NOT IN', items_to_keep);
}
return query
.then(() => {
// Add new items
if (promises.length) {
return Promise.all(promises);
}
});
}
})
.then(() => {
// Check for clients and add/update/remove them
if (typeof data.clients !== 'undefined' && data.clients) {
let promises = [];
data.clients.map(function (client) {
if (client.address) {
promises.push(accessListClientModel
.query()
.insert({
access_list_id: data.id,
address: client.address,
directive: client.directive
})
);
}
});
let query = accessListClientModel
.query()
.delete()
.where('access_list_id', data.id);
return query
.then(() => {
// Add new items
if (promises.length) {
return Promise.all(promises);
}
});
}
})
.then(internalNginx.reload)
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'access-list',
object_id: data.id,
meta: internalAccessList.maskItems(data)
});
})
.then(() => {
// re-fetch with expansions
return internalAccessList.get(access, {
id: data.id,
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
}, true /* <- skip masking */);
})
.then((row) => {
return internalAccessList.build(row)
.then(() => {
if (row.proxy_host_count) {
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
}
})
.then(() => {
return internalAccessList.maskItems(row);
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @param {Boolean} [skip_masking]
* @return {Promise}
*/
get: (access, data, skip_masking) => {
if (typeof data === 'undefined') {
data = {};
}
return access.can('access_lists:get', data.id)
.then((access_data) => {
let query = accessListModel
.query()
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
.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)
.andWhere('access_list.id', data.id)
.allowEager('[owner,items,clients,proxy_hosts.[*, access_list.[clients,items]]]')
.omit(['access_list.is_deleted'])
.first();
if (access_data.permission_visibility !== 'all') {
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) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((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);
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('access_lists:delete', data.id)
.then(() => {
return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
}
// 1. update row to be deleted
// 2. update any proxy hosts that were using it (ignoring permissions)
// 3. reconfigure those hosts
// 4. audit log
// 1. update row to be deleted
return accessListModel
.query()
.where('id', row.id)
.patch({
is_deleted: 1
})
.then(() => {
// 2. update any proxy hosts that were using it (ignoring permissions)
if (row.proxy_hosts) {
return proxyHostModel
.query()
.where('access_list_id', '=', row.id)
.patch({access_list_id: 0})
.then(() => {
// 3. reconfigure those hosts, then reload nginx
// set the access_list_id to zero for these items
row.proxy_hosts.map(function (val, idx) {
row.proxy_hosts[idx].access_list_id = 0;
});
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
})
.then(() => {
return internalNginx.reload();
});
}
})
.then(() => {
// delete the htpasswd file
let htpasswd_file = internalAccessList.getFilename(row);
try {
fs.unlinkSync(htpasswd_file);
} catch (err) {
// do nothing
}
})
.then(() => {
// 4. audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'access-list',
object_id: row.id,
meta: _.omit(internalAccessList.maskItems(row), ['is_deleted', 'proxy_hosts'])
});
});
})
.then(() => {
return true;
});
},
/**
* All Lists
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('access_lists:list')
.then((access_data) => {
let query = accessListModel
.query()
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
.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)
.groupBy('access_list.id')
.omit(['access_list.is_deleted'])
.allowEager('[owner,items,clients]')
.orderBy('access_list.name', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
}
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('name', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
})
.then((rows) => {
if (rows) {
rows.map(function (row, idx) {
if (typeof row.items !== 'undefined' && row.items) {
rows[idx] = internalAccessList.maskItems(row);
}
});
}
return rows;
});
},
/**
* Report use
*
* @param {Integer} user_id
* @param {String} visibility
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = accessListModel
.query()
.count('id as count')
.where('is_deleted', 0);
if (visibility !== 'all') {
query.andWhere('owner_user_id', user_id);
}
return query.first()
.then((row) => {
return parseInt(row.count, 10);
});
},
/**
* @param {Object} list
* @returns {Object}
*/
maskItems: (list) => {
if (list && typeof list.items !== 'undefined') {
list.items.map(function (val, idx) {
let repeat_for = 8;
let first_char = '*';
if (typeof val.password !== 'undefined' && val.password) {
repeat_for = val.password.length - 1;
first_char = val.password.charAt(0);
}
list.items[idx].hint = first_char + ('*').repeat(repeat_for);
list.items[idx].password = '';
});
}
return list;
},
/**
* @param {Object} list
* @param {Integer} list.id
* @returns {String}
*/
getFilename: (list) => {
return '/data/access/' + list.id;
},
/**
* @param {Object} list
* @param {Integer} list.id
* @param {String} list.name
* @param {Array} list.items
* @returns {Promise}
*/
build: (list) => {
logger.info('Building Access file #' + list.id + ' for: ' + list.name);
return new Promise((resolve, reject) => {
let htpasswd_file = internalAccessList.getFilename(list);
// 1. remove any existing access file
try {
fs.unlinkSync(htpasswd_file);
} catch (err) {
// do nothing
}
// 2. create empty access file
try {
fs.writeFileSync(htpasswd_file, '', {encoding: 'utf8'});
resolve(htpasswd_file);
} catch (err) {
reject(err);
}
})
.then((htpasswd_file) => {
// 3. generate password for each user
if (list.items.length) {
return new Promise((resolve, reject) => {
batchflow(list.items).sequential()
.each((i, item, next) => {
if (typeof item.password !== 'undefined' && item.password.length) {
logger.info('Adding: ' + item.username);
utils.exec('/usr/bin/htpasswd -b "' + htpasswd_file + '" "' + item.username + '" "' + item.password + '"')
.then((/*result*/) => {
next();
})
.catch((err) => {
logger.error(err);
next(err);
});
}
})
.error((err) => {
logger.error(err);
reject(err);
})
.end((results) => {
logger.success('Built Access file #' + list.id + ' for: ' + list.name);
resolve(results);
});
});
}
});
}
};
module.exports = internalAccessList;

View File

@ -0,0 +1,78 @@
const error = require('../lib/error');
const auditLogModel = require('../models/audit-log');
const internalAuditLog = {
/**
* All logs
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('auditlog:list')
.then(() => {
let query = auditLogModel
.query()
.orderBy('created_on', 'DESC')
.orderBy('id', 'DESC')
.limit(100)
.allowEager('[user]');
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('meta', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
});
},
/**
* This method should not be publicly used, it doesn't check certain things. It will be assumed
* that permission to add to audit log is already considered, however the access token is used for
* default user id determination.
*
* @param {Access} access
* @param {Object} data
* @param {String} data.action
* @param {Number} [data.user_id]
* @param {Number} [data.object_id]
* @param {Number} [data.object_type]
* @param {Object} [data.meta]
* @returns {Promise}
*/
add: (access, data) => {
return new Promise((resolve, reject) => {
// Default the user id
if (typeof data.user_id === 'undefined' || !data.user_id) {
data.user_id = access.token.getUserId(1);
}
if (typeof data.action === 'undefined' || !data.action) {
reject(new error.InternalValidationError('Audit log entry must contain an Action'));
} else {
// Make sure at least 1 of the IDs are set and action
resolve(auditLogModel
.query()
.insert({
user_id: data.user_id,
action: data.action,
object_type: data.object_type || '',
object_id: data.object_id || 0,
meta: data.meta || {}
}));
}
});
}
};
module.exports = internalAuditLog;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,461 @@
const _ = require('lodash');
const error = require('../lib/error');
const deadHostModel = require('../models/dead_host');
const internalHost = require('./host');
const internalNginx = require('./nginx');
const internalAuditLog = require('./audit-log');
const internalCertificate = require('./certificate');
function omissions () {
return ['is_deleted'];
}
const internalDeadHost = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('dead_hosts:create', data)
.then((/*access_data*/) => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
})
.then(() => {
// At this point the domains should have been checked
data.owner_user_id = access.token.getUserId(1);
data = internalHost.cleanSslHstsData(data);
return deadHostModel
.query()
.omit(omissions())
.insertAndFetch(data);
})
.then((row) => {
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, data)
.then((cert) => {
// update host with cert id
return internalDeadHost.update(access, {
id: row.id,
certificate_id: cert.id
});
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// re-fetch with cert
return internalDeadHost.get(access, {
id: row.id,
expand: ['certificate', 'owner']
});
})
.then((row) => {
// Configure nginx
return internalNginx.configure(deadHostModel, 'dead_host', row)
.then(() => {
return row;
});
})
.then((row) => {
data.meta = _.assign({}, data.meta || {}, row.meta);
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'dead-host',
object_id: row.id,
meta: data
})
.then(() => {
return row;
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @return {Promise}
*/
update: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('dead_hosts:update', data.id)
.then((/*access_data*/) => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
if (typeof data.domain_names !== 'undefined') {
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'dead', data.id));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
}
})
.then(() => {
return internalDeadHost.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('404 Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, {
domain_names: data.domain_names || row.domain_names,
meta: _.assign({}, row.meta, data.meta)
})
.then((cert) => {
// update host with cert id
data.certificate_id = cert.id;
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
data = _.assign({}, {
domain_names: row.domain_names
}, data);
data = internalHost.cleanSslHstsData(data, row);
return deadHostModel
.query()
.where({id: data.id})
.patch(data)
.then((saved_row) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'dead-host',
object_id: row.id,
meta: data
})
.then(() => {
return _.omit(saved_row, omissions());
});
});
})
.then(() => {
return internalDeadHost.get(access, {
id: data.id,
expand: ['owner', 'certificate']
})
.then((row) => {
// Configure nginx
return internalNginx.configure(deadHostModel, 'dead_host', row)
.then((new_meta) => {
row.meta = new_meta;
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
});
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @return {Promise}
*/
get: (access, data) => {
if (typeof data === 'undefined') {
data = {};
}
return access.can('dead_hosts:get', data.id)
.then((access_data) => {
let query = deadHostModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[owner,certificate]')
.first();
if (access_data.permission_visibility !== 'all') {
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) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((row) => {
if (row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('dead_hosts:delete', data.id)
.then(() => {
return internalDeadHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
}
return deadHostModel
.query()
.where('id', row.id)
.patch({
is_deleted: 1
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('dead_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'dead-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
enable: (access, data) => {
return access.can('dead_hosts:update', data.id)
.then(() => {
return internalDeadHost.get(access, {
id: data.id,
expand: ['certificate', 'owner']
});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (row.enabled) {
throw new error.ValidationError('Host is already enabled');
}
row.enabled = 1;
return deadHostModel
.query()
.where('id', row.id)
.patch({
enabled: 1
})
.then(() => {
// Configure nginx
return internalNginx.configure(deadHostModel, 'dead_host', row);
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'enabled',
object_type: 'dead-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
disable: (access, data) => {
return access.can('dead_hosts:update', data.id)
.then(() => {
return internalDeadHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (!row.enabled) {
throw new error.ValidationError('Host is already disabled');
}
row.enabled = 0;
return deadHostModel
.query()
.where('id', row.id)
.patch({
enabled: 0
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('dead_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'disabled',
object_type: 'dead-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* All Hosts
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('dead_hosts:list')
.then((access_data) => {
let query = deadHostModel
.query()
.where('is_deleted', 0)
.groupBy('id')
.omit(['is_deleted'])
.allowEager('[owner,certificate]')
.orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1));
}
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('domain_names', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
})
.then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
return internalHost.cleanAllRowsCertificateMeta(rows);
}
return rows;
});
},
/**
* Report use
*
* @param {Number} user_id
* @param {String} visibility
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = deadHostModel
.query()
.count('id as count')
.where('is_deleted', 0);
if (visibility !== 'all') {
query.andWhere('owner_user_id', user_id);
}
return query.first()
.then((row) => {
return parseInt(row.count, 10);
});
}
};
module.exports = internalDeadHost;

235
backend/internal/host.js Normal file
View File

@ -0,0 +1,235 @@
const _ = require('lodash');
const proxyHostModel = require('../models/proxy_host');
const redirectionHostModel = require('../models/redirection_host');
const deadHostModel = require('../models/dead_host');
const internalHost = {
/**
* Makes sure that the ssl_* and hsts_* fields play nicely together.
* ie: if there is no cert, then force_ssl is off.
* if force_ssl is off, then hsts_enabled is definitely off.
*
* @param {object} data
* @param {object} [existing_data]
* @returns {object}
*/
cleanSslHstsData: function (data, existing_data) {
existing_data = existing_data === undefined ? {} : existing_data;
let combined_data = _.assign({}, existing_data, data);
if (!combined_data.certificate_id) {
combined_data.ssl_forced = false;
combined_data.http2_support = false;
}
if (!combined_data.ssl_forced) {
combined_data.hsts_enabled = false;
}
if (!combined_data.hsts_enabled) {
combined_data.hsts_subdomains = false;
}
return combined_data;
},
/**
* used by the getAll functions of hosts, this removes the certificate meta if present
*
* @param {Array} rows
* @returns {Array}
*/
cleanAllRowsCertificateMeta: function (rows) {
rows.map(function (row, idx) {
if (typeof rows[idx].certificate !== 'undefined' && rows[idx].certificate) {
rows[idx].certificate.meta = {};
}
});
return rows;
},
/**
* used by the get/update functions of hosts, this removes the certificate meta if present
*
* @param {Object} row
* @returns {Object}
*/
cleanRowCertificateMeta: function (row) {
if (typeof row.certificate !== 'undefined' && row.certificate) {
row.certificate.meta = {};
}
return row;
},
/**
* This returns all the host types with any domain listed in the provided domain_names array.
* This is used by the certificates to temporarily disable any host that is using the domain
*
* @param {Array} domain_names
* @returns {Promise}
*/
getHostsWithDomains: function (domain_names) {
let promises = [
proxyHostModel
.query()
.where('is_deleted', 0),
redirectionHostModel
.query()
.where('is_deleted', 0),
deadHostModel
.query()
.where('is_deleted', 0)
];
return Promise.all(promises)
.then((promises_results) => {
let response_object = {
total_count: 0,
dead_hosts: [],
proxy_hosts: [],
redirection_hosts: []
};
if (promises_results[0]) {
// Proxy Hosts
response_object.proxy_hosts = internalHost._getHostsWithDomains(promises_results[0], domain_names);
response_object.total_count += response_object.proxy_hosts.length;
}
if (promises_results[1]) {
// Redirection Hosts
response_object.redirection_hosts = internalHost._getHostsWithDomains(promises_results[1], domain_names);
response_object.total_count += response_object.redirection_hosts.length;
}
if (promises_results[2]) {
// Dead Hosts
response_object.dead_hosts = internalHost._getHostsWithDomains(promises_results[2], domain_names);
response_object.total_count += response_object.dead_hosts.length;
}
return response_object;
});
},
/**
* Internal use only, checks to see if the domain is already taken by any other record
*
* @param {String} hostname
* @param {String} [ignore_type] 'proxy', 'redirection', 'dead'
* @param {Integer} [ignore_id] Must be supplied if type was also supplied
* @returns {Promise}
*/
isHostnameTaken: function (hostname, ignore_type, ignore_id) {
let promises = [
proxyHostModel
.query()
.where('is_deleted', 0)
.andWhere('domain_names', 'like', '%' + hostname + '%'),
redirectionHostModel
.query()
.where('is_deleted', 0)
.andWhere('domain_names', 'like', '%' + hostname + '%'),
deadHostModel
.query()
.where('is_deleted', 0)
.andWhere('domain_names', 'like', '%' + hostname + '%')
];
return Promise.all(promises)
.then((promises_results) => {
let is_taken = false;
if (promises_results[0]) {
// Proxy Hosts
if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[0], ignore_type === 'proxy' && ignore_id ? ignore_id : 0)) {
is_taken = true;
}
}
if (promises_results[1]) {
// Redirection Hosts
if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[1], ignore_type === 'redirection' && ignore_id ? ignore_id : 0)) {
is_taken = true;
}
}
if (promises_results[2]) {
// Dead Hosts
if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[2], ignore_type === 'dead' && ignore_id ? ignore_id : 0)) {
is_taken = true;
}
}
return {
hostname: hostname,
is_taken: is_taken
};
});
},
/**
* Private call only
*
* @param {String} hostname
* @param {Array} existing_rows
* @param {Integer} [ignore_id]
* @returns {Boolean}
*/
_checkHostnameRecordsTaken: function (hostname, existing_rows, ignore_id) {
let is_taken = false;
if (existing_rows && existing_rows.length) {
existing_rows.map(function (existing_row) {
existing_row.domain_names.map(function (existing_hostname) {
// Does this domain match?
if (existing_hostname.toLowerCase() === hostname.toLowerCase()) {
if (!ignore_id || ignore_id !== existing_row.id) {
is_taken = true;
}
}
});
});
}
return is_taken;
},
/**
* Private call only
*
* @param {Array} hosts
* @param {Array} domain_names
* @returns {Array}
*/
_getHostsWithDomains: function (hosts, domain_names) {
let response = [];
if (hosts && hosts.length) {
hosts.map(function (host) {
let host_matches = false;
domain_names.map(function (domain_name) {
host.domain_names.map(function (host_domain_name) {
if (domain_name.toLowerCase() === host_domain_name.toLowerCase()) {
host_matches = true;
}
});
});
if (host_matches) {
response.push(host);
}
});
}
return response;
}
};
module.exports = internalHost;

View File

@ -0,0 +1,150 @@
const https = require('https');
const fs = require('fs');
const logger = require('../logger').ip_ranges;
const error = require('../lib/error');
const internalNginx = require('./nginx');
const { Liquid } = require('liquidjs');
const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
const regIpV4 = /^(\d+\.?){4}\/\d+/;
const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
const internalIpRanges = {
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
interval: null,
interval_processing: false,
iteration_count: 0,
initTimer: () => {
logger.info('IP Ranges Renewal Timer initialized');
internalIpRanges.interval = setInterval(internalIpRanges.fetch, internalIpRanges.interval_timeout);
},
fetchUrl: (url) => {
return new Promise((resolve, reject) => {
logger.info('Fetching ' + url);
return https.get(url, (res) => {
res.setEncoding('utf8');
let raw_data = '';
res.on('data', (chunk) => {
raw_data += chunk;
});
res.on('end', () => {
resolve(raw_data);
});
}).on('error', (err) => {
reject(err);
});
});
},
/**
* Triggered at startup and then later by a timer, this will fetch the ip ranges from services and apply them to nginx.
*/
fetch: () => {
if (!internalIpRanges.interval_processing) {
internalIpRanges.interval_processing = true;
logger.info('Fetching IP Ranges from online services...');
let ip_ranges = [];
return internalIpRanges.fetchUrl(CLOUDFRONT_URL)
.then((cloudfront_data) => {
let data = JSON.parse(cloudfront_data);
if (data && typeof data.prefixes !== 'undefined') {
data.prefixes.map((item) => {
if (item.service === 'CLOUDFRONT') {
ip_ranges.push(item.ip_prefix);
}
});
}
if (data && typeof data.ipv6_prefixes !== 'undefined') {
data.ipv6_prefixes.map((item) => {
if (item.service === 'CLOUDFRONT') {
ip_ranges.push(item.ipv6_prefix);
}
});
}
})
.then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
})
.then((cloudfare_data) => {
let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
ip_ranges = [... ip_ranges, ... items];
})
.then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
})
.then((cloudfare_data) => {
let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
ip_ranges = [... ip_ranges, ... items];
})
.then(() => {
let clean_ip_ranges = [];
ip_ranges.map((range) => {
if (range) {
clean_ip_ranges.push(range);
}
});
return internalIpRanges.generateConfig(clean_ip_ranges)
.then(() => {
if (internalIpRanges.iteration_count) {
// Reload nginx
return internalNginx.reload();
}
});
})
.then(() => {
internalIpRanges.interval_processing = false;
internalIpRanges.iteration_count++;
})
.catch((err) => {
logger.error(err.message);
internalIpRanges.interval_processing = false;
});
}
},
/**
* @param {Array} ip_ranges
* @returns {Promise}
*/
generateConfig: (ip_ranges) => {
let renderEngine = new Liquid({
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => {
let template = null;
let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
try {
template = fs.readFileSync(__dirname + '/../templates/ip_ranges.conf', {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
}
renderEngine
.parseAndRender(template, {ip_ranges: ip_ranges})
.then((config_text) => {
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
resolve(true);
})
.catch((err) => {
logger.warn('Could not write ' + filename + ':', err.message);
reject(new error.ConfigurationError(err.message));
});
});
}
};
module.exports = internalIpRanges;

435
backend/internal/nginx.js Normal file
View File

@ -0,0 +1,435 @@
const _ = require('lodash');
const fs = require('fs');
const logger = require('../logger').nginx;
const utils = require('../lib/utils');
const error = require('../lib/error');
const { Liquid } = require('liquidjs');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
const internalNginx = {
/**
* This will:
* - test the nginx config first to make sure it's OK
* - create / recreate the config for the host
* - test again
* - IF OK: update the meta with online status
* - IF BAD: update the meta with offline status and remove the config entirely
* - then reload nginx
*
* @param {Object|String} model
* @param {String} host_type
* @param {Object} host
* @returns {Promise}
*/
configure: (model, host_type, host) => {
let combined_meta = {};
return internalNginx.test()
.then(() => {
// Nginx is OK
// We're deleting this config regardless.
return internalNginx.deleteConfig(host_type, host); // Don't throw errors, as the file may not exist at all
})
.then(() => {
return internalNginx.generateConfig(host_type, host);
})
.then(() => {
// Test nginx again and update meta with result
return internalNginx.test()
.then(() => {
// nginx is ok
combined_meta = _.assign({}, host.meta, {
nginx_online: true,
nginx_err: null
});
return model
.query()
.where('id', host.id)
.patch({
meta: combined_meta
});
})
.catch((err) => {
// Remove the error_log line because it's a docker-ism false positive that doesn't need to be reported.
// It will always look like this:
// nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (6: No such device or address)
let valid_lines = [];
let err_lines = err.message.split('\n');
err_lines.map(function (line) {
if (line.indexOf('/var/log/nginx/error.log') === -1) {
valid_lines.push(line);
}
});
if (debug_mode) {
logger.error('Nginx test failed:', valid_lines.join('\n'));
}
// config is bad, update meta and delete config
combined_meta = _.assign({}, host.meta, {
nginx_online: false,
nginx_err: valid_lines.join('\n')
});
return model
.query()
.where('id', host.id)
.patch({
meta: combined_meta
})
.then(() => {
return internalNginx.deleteConfig(host_type, host, true);
});
});
})
.then(() => {
return internalNginx.reload();
})
.then(() => {
return combined_meta;
});
},
/**
* @returns {Promise}
*/
test: () => {
if (debug_mode) {
logger.info('Testing Nginx configuration');
}
return utils.exec('/usr/sbin/nginx -t -g "error_log off;"');
},
/**
* @returns {Promise}
*/
reload: () => {
return internalNginx.test()
.then(() => {
logger.info('Reloading Nginx');
return utils.exec('/usr/sbin/nginx -s reload');
});
},
/**
* @param {String} host_type
* @param {Integer} host_id
* @returns {String}
*/
getConfigName: (host_type, host_id) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_');
if (host_type === 'default') {
return '/data/nginx/default_host/site.conf';
}
return '/data/nginx/' + host_type + '/' + host_id + '.conf';
},
/**
* Generates custom locations
* @param {Object} host
* @returns {Promise}
*/
renderLocations: (host) => {
//logger.info('host = ' + JSON.stringify(host, null, 2));
return new Promise((resolve, reject) => {
let template;
try {
template = fs.readFileSync(__dirname + '/../templates/_location.conf', {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
}
let renderer = new Liquid({
root: __dirname + '/../templates/'
});
let renderedLocations = '';
const locationRendering = async () => {
for (let i = 0; i < host.locations.length; i++) {
let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
{ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
{allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
{certificate: host.certificate}, host.locations[i]);
if (locationCopy.forward_host.indexOf('/') > -1) {
const splitted = locationCopy.forward_host.split('/');
locationCopy.forward_host = splitted.shift();
locationCopy.forward_path = `/${splitted.join('/')}`;
}
//logger.info('locationCopy = ' + JSON.stringify(locationCopy, null, 2));
// eslint-disable-next-line
renderedLocations += await renderer.parseAndRender(template, locationCopy);
}
};
locationRendering().then(() => resolve(renderedLocations));
});
},
/**
* @param {String} host_type
* @param {Object} host
* @returns {Promise}
*/
generateConfig: (host_type, host) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_');
if (debug_mode) {
logger.info('Generating ' + host_type + ' Config:', host);
}
// logger.info('host = ' + JSON.stringify(host, null, 2));
let renderEngine = new Liquid({
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => {
let template = null;
let filename = internalNginx.getConfigName(host_type, host.id);
try {
template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
}
let locationsPromise;
let origLocations;
// Manipulate the data a bit before sending it to the template
if (host_type !== 'default') {
host.use_default_location = true;
if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
}
}
if (host.locations) {
//logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2));
origLocations = [].concat(host.locations);
locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => {
host.locations = renderedLocations;
});
// Allow someone who is using / custom location path to use it, and skip the default / location
_.map(host.locations, (location) => {
if (location.path === '/') {
host.use_default_location = false;
}
});
} else {
locationsPromise = Promise.resolve();
}
// Set the IPv6 setting for the host
host.ipv6 = internalNginx.ipv6Enabled();
locationsPromise.then(() => {
renderEngine
.parseAndRender(template, host)
.then((config_text) => {
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
if (debug_mode) {
logger.success('Wrote config:', filename, config_text);
}
// Restore locations array
host.locations = origLocations;
resolve(true);
})
.catch((err) => {
if (debug_mode) {
logger.warn('Could not write ' + filename + ':', err.message);
}
reject(new error.ConfigurationError(err.message));
});
});
});
},
/**
* This generates a temporary nginx config listening on port 80 for the domain names listed
* in the certificate setup. It allows the letsencrypt acme challenge to be requested by letsencrypt
* when requesting a certificate without having a hostname set up already.
*
* @param {Object} certificate
* @returns {Promise}
*/
generateLetsEncryptRequestConfig: (certificate) => {
if (debug_mode) {
logger.info('Generating LetsEncrypt Request Config:', certificate);
}
let renderEngine = new Liquid({
root: __dirname + '/../templates/'
});
return new Promise((resolve, reject) => {
let template = null;
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
try {
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
} catch (err) {
reject(new error.ConfigurationError(err.message));
return;
}
certificate.ipv6 = internalNginx.ipv6Enabled();
renderEngine
.parseAndRender(template, certificate)
.then((config_text) => {
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
if (debug_mode) {
logger.success('Wrote config:', filename, config_text);
}
resolve(true);
})
.catch((err) => {
if (debug_mode) {
logger.warn('Could not write ' + filename + ':', err.message);
}
reject(new error.ConfigurationError(err.message));
});
});
},
/**
* This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
*
* @param {Object} certificate
* @param {Boolean} [throw_errors]
* @returns {Promise}
*/
deleteLetsEncryptRequestConfig: (certificate, throw_errors) => {
return new Promise((resolve, reject) => {
try {
let config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
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();
});
},
/**
* @param {String} host_type
* @param {Object} [host]
* @param {Boolean} [throw_errors]
* @returns {Promise}
*/
deleteConfig: (host_type, host, throw_errors) => {
host_type = host_type.replace(new RegExp('-', 'g'), '_');
return new Promise((resolve, reject) => {
try {
let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id);
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();
});
},
/**
* @param {String} host_type
* @param {Array} hosts
* @returns {Promise}
*/
bulkGenerateConfigs: (host_type, hosts) => {
let promises = [];
hosts.map(function (host) {
promises.push(internalNginx.generateConfig(host_type, host));
});
return Promise.all(promises);
},
/**
* @param {String} host_type
* @param {Array} hosts
* @param {Boolean} [throw_errors]
* @returns {Promise}
*/
bulkDeleteConfigs: (host_type, hosts, throw_errors) => {
let promises = [];
hosts.map(function (host) {
promises.push(internalNginx.deleteConfig(host_type, host, throw_errors));
});
return Promise.all(promises);
},
/**
* @param {string} config
* @returns {boolean}
*/
advancedConfigHasDefaultLocation: function (config) {
return !!config.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
},
/**
* @returns {boolean}
*/
ipv6Enabled: function () {
if (typeof process.env.DISABLE_IPV6 !== 'undefined') {
const disabled = process.env.DISABLE_IPV6.toLowerCase();
return !(disabled === 'on' || disabled === 'true' || disabled === '1' || disabled === 'yes');
}
return true;
}
};
module.exports = internalNginx;

View File

@ -0,0 +1,466 @@
const _ = require('lodash');
const error = require('../lib/error');
const proxyHostModel = require('../models/proxy_host');
const internalHost = require('./host');
const internalNginx = require('./nginx');
const internalAuditLog = require('./audit-log');
const internalCertificate = require('./certificate');
function omissions () {
return ['is_deleted'];
}
const internalProxyHost = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('proxy_hosts:create', data)
.then(() => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
})
.then(() => {
// At this point the domains should have been checked
data.owner_user_id = access.token.getUserId(1);
data = internalHost.cleanSslHstsData(data);
return proxyHostModel
.query()
.omit(omissions())
.insertAndFetch(data);
})
.then((row) => {
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, data)
.then((cert) => {
// update host with cert id
return internalProxyHost.update(access, {
id: row.id,
certificate_id: cert.id
});
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// re-fetch with cert
return internalProxyHost.get(access, {
id: row.id,
expand: ['certificate', 'owner', 'access_list.[clients,items]']
});
})
.then((row) => {
// Configure nginx
return internalNginx.configure(proxyHostModel, 'proxy_host', row)
.then(() => {
return row;
});
})
.then((row) => {
// Audit log
data.meta = _.assign({}, data.meta || {}, row.meta);
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'proxy-host',
object_id: row.id,
meta: data
})
.then(() => {
return row;
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @return {Promise}
*/
update: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('proxy_hosts:update', data.id)
.then((/*access_data*/) => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
if (typeof data.domain_names !== 'undefined') {
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'proxy', data.id));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
}
})
.then(() => {
return internalProxyHost.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Proxy Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, {
domain_names: data.domain_names || row.domain_names,
meta: _.assign({}, row.meta, data.meta)
})
.then((cert) => {
// update host with cert id
data.certificate_id = cert.id;
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
data = _.assign({}, {
domain_names: row.domain_names
}, data);
data = internalHost.cleanSslHstsData(data, row);
return proxyHostModel
.query()
.where({id: data.id})
.patch(data)
.then((saved_row) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'proxy-host',
object_id: row.id,
meta: data
})
.then(() => {
return _.omit(saved_row, omissions());
});
});
})
.then(() => {
return internalProxyHost.get(access, {
id: data.id,
expand: ['owner', 'certificate', 'access_list.[clients,items]']
})
.then((row) => {
if (!row.enabled) {
// No need to add nginx config if host is disabled
return row;
}
// Configure nginx
return internalNginx.configure(proxyHostModel, 'proxy_host', row)
.then((new_meta) => {
row.meta = new_meta;
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
});
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @return {Promise}
*/
get: (access, data) => {
if (typeof data === 'undefined') {
data = {};
}
return access.can('proxy_hosts:get', data.id)
.then((access_data) => {
let query = proxyHostModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[owner,access_list,access_list.[clients,items],certificate]')
.first();
if (access_data.permission_visibility !== 'all') {
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) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((row) => {
if (row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('proxy_hosts:delete', data.id)
.then(() => {
return internalProxyHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
}
return proxyHostModel
.query()
.where('id', row.id)
.patch({
is_deleted: 1
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('proxy_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'proxy-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
enable: (access, data) => {
return access.can('proxy_hosts:update', data.id)
.then(() => {
return internalProxyHost.get(access, {
id: data.id,
expand: ['certificate', 'owner', 'access_list']
});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (row.enabled) {
throw new error.ValidationError('Host is already enabled');
}
row.enabled = 1;
return proxyHostModel
.query()
.where('id', row.id)
.patch({
enabled: 1
})
.then(() => {
// Configure nginx
return internalNginx.configure(proxyHostModel, 'proxy_host', row);
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'enabled',
object_type: 'proxy-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
disable: (access, data) => {
return access.can('proxy_hosts:update', data.id)
.then(() => {
return internalProxyHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (!row.enabled) {
throw new error.ValidationError('Host is already disabled');
}
row.enabled = 0;
return proxyHostModel
.query()
.where('id', row.id)
.patch({
enabled: 0
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('proxy_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'disabled',
object_type: 'proxy-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* All Hosts
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('proxy_hosts:list')
.then((access_data) => {
let query = proxyHostModel
.query()
.where('is_deleted', 0)
.groupBy('id')
.omit(['is_deleted'])
.allowEager('[owner,access_list,certificate]')
.orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1));
}
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('domain_names', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
})
.then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
return internalHost.cleanAllRowsCertificateMeta(rows);
}
return rows;
});
},
/**
* Report use
*
* @param {Number} user_id
* @param {String} visibility
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = proxyHostModel
.query()
.count('id as count')
.where('is_deleted', 0);
if (visibility !== 'all') {
query.andWhere('owner_user_id', user_id);
}
return query.first()
.then((row) => {
return parseInt(row.count, 10);
});
}
};
module.exports = internalProxyHost;

View File

@ -0,0 +1,461 @@
const _ = require('lodash');
const error = require('../lib/error');
const redirectionHostModel = require('../models/redirection_host');
const internalHost = require('./host');
const internalNginx = require('./nginx');
const internalAuditLog = require('./audit-log');
const internalCertificate = require('./certificate');
function omissions () {
return ['is_deleted'];
}
const internalRedirectionHost = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('redirection_hosts:create', data)
.then((/*access_data*/) => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
})
.then(() => {
// At this point the domains should have been checked
data.owner_user_id = access.token.getUserId(1);
data = internalHost.cleanSslHstsData(data);
return redirectionHostModel
.query()
.omit(omissions())
.insertAndFetch(data);
})
.then((row) => {
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, data)
.then((cert) => {
// update host with cert id
return internalRedirectionHost.update(access, {
id: row.id,
certificate_id: cert.id
});
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// re-fetch with cert
return internalRedirectionHost.get(access, {
id: row.id,
expand: ['certificate', 'owner']
});
})
.then((row) => {
// Configure nginx
return internalNginx.configure(redirectionHostModel, 'redirection_host', row)
.then(() => {
return row;
});
})
.then((row) => {
data.meta = _.assign({}, data.meta || {}, row.meta);
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'redirection-host',
object_id: row.id,
meta: data
})
.then(() => {
return row;
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @return {Promise}
*/
update: (access, data) => {
let create_certificate = data.certificate_id === 'new';
if (create_certificate) {
delete data.certificate_id;
}
return access.can('redirection_hosts:update', data.id)
.then((/*access_data*/) => {
// Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = [];
if (typeof data.domain_names !== 'undefined') {
data.domain_names.map(function (domain_name) {
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'redirection', data.id));
});
return Promise.all(domain_name_check_promises)
.then((check_results) => {
check_results.map(function (result) {
if (result.is_taken) {
throw new error.ValidationError(result.hostname + ' is already in use');
}
});
});
}
})
.then(() => {
return internalRedirectionHost.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Redirection Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
if (create_certificate) {
return internalCertificate.createQuickCertificate(access, {
domain_names: data.domain_names || row.domain_names,
meta: _.assign({}, row.meta, data.meta)
})
.then((cert) => {
// update host with cert id
data.certificate_id = cert.id;
})
.then(() => {
return row;
});
} else {
return row;
}
})
.then((row) => {
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
data = _.assign({}, {
domain_names: row.domain_names
}, data);
data = internalHost.cleanSslHstsData(data, row);
return redirectionHostModel
.query()
.where({id: data.id})
.patch(data)
.then((saved_row) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'redirection-host',
object_id: row.id,
meta: data
})
.then(() => {
return _.omit(saved_row, omissions());
});
});
})
.then(() => {
return internalRedirectionHost.get(access, {
id: data.id,
expand: ['owner', 'certificate']
})
.then((row) => {
// Configure nginx
return internalNginx.configure(redirectionHostModel, 'redirection_host', row)
.then((new_meta) => {
row.meta = new_meta;
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
});
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @return {Promise}
*/
get: (access, data) => {
if (typeof data === 'undefined') {
data = {};
}
return access.can('redirection_hosts:get', data.id)
.then((access_data) => {
let query = redirectionHostModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[owner,certificate]')
.first();
if (access_data.permission_visibility !== 'all') {
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) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((row) => {
if (row) {
row = internalHost.cleanRowCertificateMeta(row);
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('redirection_hosts:delete', data.id)
.then(() => {
return internalRedirectionHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
}
return redirectionHostModel
.query()
.where('id', row.id)
.patch({
is_deleted: 1
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('redirection_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'redirection-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
enable: (access, data) => {
return access.can('redirection_hosts:update', data.id)
.then(() => {
return internalRedirectionHost.get(access, {
id: data.id,
expand: ['certificate', 'owner']
});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (row.enabled) {
throw new error.ValidationError('Host is already enabled');
}
row.enabled = 1;
return redirectionHostModel
.query()
.where('id', row.id)
.patch({
enabled: 1
})
.then(() => {
// Configure nginx
return internalNginx.configure(redirectionHostModel, 'redirection_host', row);
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'enabled',
object_type: 'redirection-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
disable: (access, data) => {
return access.can('redirection_hosts:update', data.id)
.then(() => {
return internalRedirectionHost.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (!row.enabled) {
throw new error.ValidationError('Host is already disabled');
}
row.enabled = 0;
return redirectionHostModel
.query()
.where('id', row.id)
.patch({
enabled: 0
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('redirection_host', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'disabled',
object_type: 'redirection-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* All Hosts
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('redirection_hosts:list')
.then((access_data) => {
let query = redirectionHostModel
.query()
.where('is_deleted', 0)
.groupBy('id')
.omit(['is_deleted'])
.allowEager('[owner,certificate]')
.orderBy('domain_names', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1));
}
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('domain_names', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
})
.then((rows) => {
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
return internalHost.cleanAllRowsCertificateMeta(rows);
}
return rows;
});
},
/**
* Report use
*
* @param {Number} user_id
* @param {String} visibility
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = redirectionHostModel
.query()
.count('id as count')
.where('is_deleted', 0);
if (visibility !== 'all') {
query.andWhere('owner_user_id', user_id);
}
return query.first()
.then((row) => {
return parseInt(row.count, 10);
});
}
};
module.exports = internalRedirectionHost;

View File

@ -0,0 +1,38 @@
const internalProxyHost = require('./proxy-host');
const internalRedirectionHost = require('./redirection-host');
const internalDeadHost = require('./dead-host');
const internalStream = require('./stream');
const internalReport = {
/**
* @param {Access} access
* @return {Promise}
*/
getHostsReport: (access) => {
return access.can('reports:hosts', 1)
.then((access_data) => {
let user_id = access.token.getUserId(1);
let promises = [
internalProxyHost.getCount(user_id, access_data.visibility),
internalRedirectionHost.getCount(user_id, access_data.visibility),
internalStream.getCount(user_id, access_data.visibility),
internalDeadHost.getCount(user_id, access_data.visibility)
];
return Promise.all(promises);
})
.then((counts) => {
return {
proxy: counts.shift(),
redirection: counts.shift(),
stream: counts.shift(),
dead: counts.shift()
};
});
}
};
module.exports = internalReport;

133
backend/internal/setting.js Normal file
View File

@ -0,0 +1,133 @@
const fs = require('fs');
const error = require('../lib/error');
const settingModel = require('../models/setting');
const internalNginx = require('./nginx');
const internalSetting = {
/**
* @param {Access} access
* @param {Object} data
* @param {String} data.id
* @return {Promise}
*/
update: (access, data) => {
return access.can('settings:update', data.id)
.then((/*access_data*/) => {
return internalSetting.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Setting could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
return settingModel
.query()
.where({id: data.id})
.patch(data);
})
.then(() => {
return internalSetting.get(access, {
id: data.id
});
})
.then((row) => {
if (row.id === 'default-site') {
// write the html if we need to
if (row.value === 'html') {
fs.writeFileSync('/data/nginx/default_www/index.html', row.meta.html, {encoding: 'utf8'});
}
// Configure nginx
return internalNginx.deleteConfig('default')
.then(() => {
return internalNginx.generateConfig('default', row);
})
.then(() => {
return internalNginx.test();
})
.then(() => {
return internalNginx.reload();
})
.then(() => {
return row;
})
.catch((/*err*/) => {
internalNginx.deleteConfig('default')
.then(() => {
return internalNginx.test();
})
.then(() => {
return internalNginx.reload();
})
.then(() => {
// I'm being slack here I know..
throw new error.ValidationError('Could not reconfigure Nginx. Please check logs.');
});
});
} else {
return row;
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {String} data.id
* @return {Promise}
*/
get: (access, data) => {
return access.can('settings:get', data.id)
.then(() => {
return settingModel
.query()
.where('id', data.id)
.first();
})
.then((row) => {
if (row) {
return row;
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* This will only count the settings
*
* @param {Access} access
* @returns {*}
*/
getCount: (access) => {
return access.can('settings:list')
.then(() => {
return settingModel
.query()
.count('id as count')
.first();
})
.then((row) => {
return parseInt(row.count, 10);
});
},
/**
* All settings
*
* @param {Access} access
* @returns {Promise}
*/
getAll: (access) => {
return access.can('settings:list')
.then(() => {
return settingModel
.query()
.orderBy('description', 'ASC');
});
}
};
module.exports = internalSetting;

348
backend/internal/stream.js Normal file
View File

@ -0,0 +1,348 @@
const _ = require('lodash');
const error = require('../lib/error');
const streamModel = require('../models/stream');
const internalNginx = require('./nginx');
const internalAuditLog = require('./audit-log');
function omissions () {
return ['is_deleted'];
}
const internalStream = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
return access.can('streams:create', data)
.then((/*access_data*/) => {
// TODO: At this point the existing ports should have been checked
data.owner_user_id = access.token.getUserId(1);
if (typeof data.meta === 'undefined') {
data.meta = {};
}
return streamModel
.query()
.omit(omissions())
.insertAndFetch(data);
})
.then((row) => {
// Configure nginx
return internalNginx.configure(streamModel, 'stream', row)
.then(() => {
return internalStream.get(access, {id: row.id, expand: ['owner']});
});
})
.then((row) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'stream',
object_id: row.id,
meta: data
})
.then(() => {
return row;
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @return {Promise}
*/
update: (access, data) => {
return access.can('streams:update', data.id)
.then((/*access_data*/) => {
// TODO: at this point the existing streams should have been checked
return internalStream.get(access, {id: data.id});
})
.then((row) => {
if (row.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
}
return streamModel
.query()
.omit(omissions())
.patchAndFetchById(row.id, data)
.then((saved_row) => {
return internalNginx.configure(streamModel, 'stream', saved_row)
.then(() => {
return internalStream.get(access, {id: row.id, expand: ['owner']});
});
})
.then((saved_row) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'stream',
object_id: row.id,
meta: data
})
.then(() => {
return _.omit(saved_row, omissions());
});
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @return {Promise}
*/
get: (access, data) => {
if (typeof data === 'undefined') {
data = {};
}
return access.can('streams:get', data.id)
.then((access_data) => {
let query = streamModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[owner]')
.first();
if (access_data.permission_visibility !== 'all') {
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) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((row) => {
if (row) {
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('streams:delete', data.id)
.then(() => {
return internalStream.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
}
return streamModel
.query()
.where('id', row.id)
.patch({
is_deleted: 1
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('stream', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'stream',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
enable: (access, data) => {
return access.can('streams:update', data.id)
.then(() => {
return internalStream.get(access, {
id: data.id,
expand: ['owner']
});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (row.enabled) {
throw new error.ValidationError('Host is already enabled');
}
row.enabled = 1;
return streamModel
.query()
.where('id', row.id)
.patch({
enabled: 1
})
.then(() => {
// Configure nginx
return internalNginx.configure(streamModel, 'stream', row);
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'enabled',
object_type: 'stream',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
disable: (access, data) => {
return access.can('streams:update', data.id)
.then(() => {
return internalStream.get(access, {id: data.id});
})
.then((row) => {
if (!row) {
throw new error.ItemNotFoundError(data.id);
} else if (!row.enabled) {
throw new error.ValidationError('Host is already disabled');
}
row.enabled = 0;
return streamModel
.query()
.where('id', row.id)
.patch({
enabled: 0
})
.then(() => {
// Delete Nginx Config
return internalNginx.deleteConfig('stream', row)
.then(() => {
return internalNginx.reload();
});
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'disabled',
object_type: 'stream-host',
object_id: row.id,
meta: _.omit(row, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* All Streams
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('streams:list')
.then((access_data) => {
let query = streamModel
.query()
.where('is_deleted', 0)
.groupBy('id')
.omit(['is_deleted'])
.allowEager('[owner]')
.orderBy('incoming_port', 'ASC');
if (access_data.permission_visibility !== 'all') {
query.andWhere('owner_user_id', access.token.getUserId(1));
}
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('incoming_port', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
});
},
/**
* Report use
*
* @param {Number} user_id
* @param {String} visibility
* @returns {Promise}
*/
getCount: (user_id, visibility) => {
let query = streamModel
.query()
.count('id as count')
.where('is_deleted', 0);
if (visibility !== 'all') {
query.andWhere('owner_user_id', user_id);
}
return query.first()
.then((row) => {
return parseInt(row.count, 10);
});
}
};
module.exports = internalStream;

162
backend/internal/token.js Normal file
View File

@ -0,0 +1,162 @@
const _ = require('lodash');
const error = require('../lib/error');
const userModel = require('../models/user');
const authModel = require('../models/auth');
const helpers = require('../lib/helpers');
const TokenModel = require('../models/token');
module.exports = {
/**
* @param {Object} data
* @param {String} data.identity
* @param {String} data.secret
* @param {String} [data.scope]
* @param {String} [data.expiry]
* @param {String} [issuer]
* @returns {Promise}
*/
getTokenFromEmail: (data, issuer) => {
let Token = new TokenModel();
data.scope = data.scope || 'user';
data.expiry = data.expiry || '1d';
return userModel
.query()
.where('email', data.identity)
.andWhere('is_deleted', 0)
.andWhere('is_disabled', 0)
.first()
.then((user) => {
if (user) {
// Get auth
return authModel
.query()
.where('user_id', '=', user.id)
.where('type', '=', 'password')
.first()
.then((auth) => {
if (auth) {
return auth.verifyPassword(data.secret)
.then((valid) => {
if (valid) {
if (data.scope !== 'user' && _.indexOf(user.roles, data.scope) === -1) {
// The scope requested doesn't exist as a role against the user,
// you shall not pass.
throw new error.AuthError('Invalid scope: ' + data.scope);
}
// Create a moment of the expiry expression
let expiry = helpers.parseDatePeriod(data.expiry);
if (expiry === null) {
throw new error.AuthError('Invalid expiry time: ' + data.expiry);
}
return Token.create({
iss: issuer || 'api',
attrs: {
id: user.id
},
scope: [data.scope],
expiresIn: data.expiry
})
.then((signed) => {
return {
token: signed.token,
expires: expiry.toISOString()
};
});
} else {
throw new error.AuthError('Invalid password');
}
});
} else {
throw new error.AuthError('No password auth for user');
}
});
} else {
throw new error.AuthError('No relevant user found');
}
});
},
/**
* @param {Access} access
* @param {Object} [data]
* @param {String} [data.expiry]
* @param {String} [data.scope] Only considered if existing token scope is admin
* @returns {Promise}
*/
getFreshToken: (access, data) => {
let Token = new TokenModel();
data = data || {};
data.expiry = data.expiry || '1d';
if (access && access.token.getUserId(0)) {
// Create a moment of the expiry expression
let expiry = helpers.parseDatePeriod(data.expiry);
if (expiry === null) {
throw new error.AuthError('Invalid expiry time: ' + data.expiry);
}
let token_attrs = {
id: access.token.getUserId(0)
};
// Only admins can request otherwise scoped tokens
let scope = access.token.get('scope');
if (data.scope && access.token.hasScope('admin')) {
scope = [data.scope];
if (data.scope === 'job-board' || data.scope === 'worker') {
token_attrs.id = 0;
}
}
return Token.create({
iss: 'api',
scope: scope,
attrs: token_attrs,
expiresIn: data.expiry
})
.then((signed) => {
return {
token: signed.token,
expires: expiry.toISOString()
};
});
} else {
throw new error.AssertionFailedError('Existing token contained invalid user data');
}
},
/**
* @param {Object} user
* @returns {Promise}
*/
getTokenFromUser: (user) => {
const expire = '1d';
const Token = new TokenModel();
const expiry = helpers.parseDatePeriod(expire);
return Token.create({
iss: 'api',
attrs: {
id: user.id
},
scope: ['user'],
expiresIn: expire
})
.then((signed) => {
return {
token: signed.token,
expires: expiry.toISOString(),
user: user
};
});
}
};

518
backend/internal/user.js Normal file
View File

@ -0,0 +1,518 @@
const _ = require('lodash');
const error = require('../lib/error');
const userModel = require('../models/user');
const userPermissionModel = require('../models/user_permission');
const authModel = require('../models/auth');
const gravatar = require('gravatar');
const internalToken = require('./token');
const internalAuditLog = require('./audit-log');
function omissions () {
return ['is_deleted'];
}
const internalUser = {
/**
* @param {Access} access
* @param {Object} data
* @returns {Promise}
*/
create: (access, data) => {
let auth = data.auth || null;
delete data.auth;
data.avatar = data.avatar || '';
data.roles = data.roles || [];
if (typeof data.is_disabled !== 'undefined') {
data.is_disabled = data.is_disabled ? 1 : 0;
}
return access.can('users:create', data)
.then(() => {
data.avatar = gravatar.url(data.email, {default: 'mm'});
return userModel
.query()
.omit(omissions())
.insertAndFetch(data);
})
.then((user) => {
if (auth) {
return authModel
.query()
.insert({
user_id: user.id,
type: auth.type,
secret: auth.secret,
meta: {}
})
.then(() => {
return user;
});
} else {
return user;
}
})
.then((user) => {
// Create permissions row as well
let is_admin = data.roles.indexOf('admin') !== -1;
return userPermissionModel
.query()
.insert({
user_id: user.id,
visibility: is_admin ? 'all' : 'user',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage',
certificates: 'manage'
})
.then(() => {
return internalUser.get(access, {id: user.id, expand: ['permissions']});
});
})
.then((user) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'created',
object_type: 'user',
object_id: user.id,
meta: user
})
.then(() => {
return user;
});
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {String} [data.email]
* @param {String} [data.name]
* @return {Promise}
*/
update: (access, data) => {
if (typeof data.is_disabled !== 'undefined') {
data.is_disabled = data.is_disabled ? 1 : 0;
}
return access.can('users:update', data.id)
.then(() => {
// Make sure that the user being updated doesn't change their email to another user that is already using it
// 1. get user we want to update
return internalUser.get(access, {id: data.id})
.then((user) => {
// 2. if email is to be changed, find other users with that email
if (typeof data.email !== 'undefined') {
data.email = data.email.toLowerCase().trim();
if (user.email !== data.email) {
return internalUser.isEmailAvailable(data.email, data.id)
.then((available) => {
if (!available) {
throw new error.ValidationError('Email address already in use - ' + data.email);
}
return user;
});
}
}
// No change to email:
return user;
});
})
.then((user) => {
if (user.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
}
data.avatar = gravatar.url(data.email || user.email, {default: 'mm'});
return userModel
.query()
.omit(omissions())
.patchAndFetchById(user.id, data)
.then((saved_user) => {
return _.omit(saved_user, omissions());
});
})
.then(() => {
return internalUser.get(access, {id: data.id});
})
.then((user) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'user',
object_id: user.id,
meta: data
})
.then(() => {
return user;
});
});
},
/**
* @param {Access} access
* @param {Object} [data]
* @param {Integer} [data.id] Defaults to the token user
* @param {Array} [data.expand]
* @param {Array} [data.omit]
* @return {Promise}
*/
get: (access, data) => {
if (typeof data === 'undefined') {
data = {};
}
if (typeof data.id === 'undefined' || !data.id) {
data.id = access.token.getUserId(0);
}
return access.can('users:get', data.id)
.then(() => {
let query = userModel
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[permissions]')
.first();
// Custom omissions
if (typeof data.omit !== 'undefined' && data.omit !== null) {
query.omit(data.omit);
}
if (typeof data.expand !== 'undefined' && data.expand !== null) {
query.eager('[' + data.expand.join(', ') + ']');
}
return query;
})
.then((row) => {
if (row) {
return _.omit(row, omissions());
} else {
throw new error.ItemNotFoundError(data.id);
}
});
},
/**
* Checks if an email address is available, but if a user_id is supplied, it will ignore checking
* against that user.
*
* @param email
* @param user_id
*/
isEmailAvailable: (email, user_id) => {
let query = userModel
.query()
.where('email', '=', email.toLowerCase().trim())
.where('is_deleted', 0)
.first();
if (typeof user_id !== 'undefined') {
query.where('id', '!=', user_id);
}
return query
.then((user) => {
return !user;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {String} [data.reason]
* @returns {Promise}
*/
delete: (access, data) => {
return access.can('users:delete', data.id)
.then(() => {
return internalUser.get(access, {id: data.id});
})
.then((user) => {
if (!user) {
throw new error.ItemNotFoundError(data.id);
}
// Make sure user can't delete themselves
if (user.id === access.token.getUserId(0)) {
throw new error.PermissionError('You cannot delete yourself.');
}
return userModel
.query()
.where('id', user.id)
.patch({
is_deleted: 1
})
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'deleted',
object_type: 'user',
object_id: user.id,
meta: _.omit(user, omissions())
});
});
})
.then(() => {
return true;
});
},
/**
* This will only count the users
*
* @param {Access} access
* @param {String} [search_query]
* @returns {*}
*/
getCount: (access, search_query) => {
return access.can('users:list')
.then(() => {
let query = userModel
.query()
.count('id as count')
.where('is_deleted', 0)
.first();
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('user.name', 'like', '%' + search_query + '%')
.orWhere('user.email', 'like', '%' + search_query + '%');
});
}
return query;
})
.then((row) => {
return parseInt(row.count, 10);
});
},
/**
* All users
*
* @param {Access} access
* @param {Array} [expand]
* @param {String} [search_query]
* @returns {Promise}
*/
getAll: (access, expand, search_query) => {
return access.can('users:list')
.then(() => {
let query = userModel
.query()
.where('is_deleted', 0)
.groupBy('id')
.omit(['is_deleted'])
.allowEager('[permissions]')
.orderBy('name', 'ASC');
// Query is used for searching
if (typeof search_query === 'string') {
query.where(function () {
this.where('name', 'like', '%' + search_query + '%')
.orWhere('email', 'like', '%' + search_query + '%');
});
}
if (typeof expand !== 'undefined' && expand !== null) {
query.eager('[' + expand.join(', ') + ']');
}
return query;
});
},
/**
* @param {Access} access
* @param {Integer} [id_requested]
* @returns {[String]}
*/
getUserOmisionsByAccess: (access, id_requested) => {
let response = []; // Admin response
if (!access.token.hasScope('admin') && access.token.getUserId(0) !== id_requested) {
response = ['roles', 'is_deleted']; // Restricted response
}
return response;
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
* @param {String} data.type
* @param {String} data.secret
* @return {Promise}
*/
setPassword: (access, data) => {
return access.can('users:password', data.id)
.then(() => {
return internalUser.get(access, {id: data.id});
})
.then((user) => {
if (user.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
}
if (user.id === access.token.getUserId(0)) {
// they're setting their own password. Make sure their current password is correct
if (typeof data.current === 'undefined' || !data.current) {
throw new error.ValidationError('Current password was not supplied');
}
return internalToken.getTokenFromEmail({
identity: user.email,
secret: data.current
})
.then(() => {
return user;
});
}
return user;
})
.then((user) => {
// Get auth, patch if it exists
return authModel
.query()
.where('user_id', user.id)
.andWhere('type', data.type)
.first()
.then((existing_auth) => {
if (existing_auth) {
// patch
return authModel
.query()
.where('user_id', user.id)
.andWhere('type', data.type)
.patch({
type: data.type, // This is required for the model to encrypt on save
secret: data.secret
});
} else {
// insert
return authModel
.query()
.insert({
user_id: user.id,
type: data.type,
secret: data.secret,
meta: {}
});
}
})
.then(() => {
// Add to Audit Log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'user',
object_id: user.id,
meta: {
name: user.name,
password_changed: true,
auth_type: data.type
}
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @return {Promise}
*/
setPermissions: (access, data) => {
return access.can('users:permissions', data.id)
.then(() => {
return internalUser.get(access, {id: data.id});
})
.then((user) => {
if (user.id !== data.id) {
// Sanity check that something crazy hasn't happened
throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
}
return user;
})
.then((user) => {
// Get perms row, patch if it exists
return userPermissionModel
.query()
.where('user_id', user.id)
.first()
.then((existing_auth) => {
if (existing_auth) {
// patch
return userPermissionModel
.query()
.where('user_id', user.id)
.patchAndFetchById(existing_auth.id, _.assign({user_id: user.id}, data));
} else {
// insert
return userPermissionModel
.query()
.insertAndFetch(_.assign({user_id: user.id}, data));
}
})
.then((permissions) => {
// Add to Audit Log
return internalAuditLog.add(access, {
action: 'updated',
object_type: 'user',
object_id: user.id,
meta: {
name: user.name,
permissions: permissions
}
});
});
})
.then(() => {
return true;
});
},
/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
*/
loginAs: (access, data) => {
return access.can('users:loginas', data.id)
.then(() => {
return internalUser.get(access, data);
})
.then((user) => {
return internalToken.getTokenFromUser(user);
});
}
};
module.exports = internalUser;

19
backend/knexfile.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = {
development: {
client: 'mysql',
migrations: {
tableName: 'migrations',
stub: 'lib/migrate_template.js',
directory: 'migrations'
}
},
production: {
client: 'mysql',
migrations: {
tableName: 'migrations',
stub: 'lib/migrate_template.js',
directory: 'migrations'
}
}
};

314
backend/lib/access.js Normal file
View File

@ -0,0 +1,314 @@
/**
* Some Notes: This is a friggin complicated piece of code.
*
* "scope" in this file means "where did this token come from and what is using it", so 99% of the time
* the "scope" is going to be "user" because it would be a user token. This is not to be confused with
* the "role" which could be "user" or "admin". The scope in fact, could be "worker" or anything else.
*
*
*/
const _ = require('lodash');
const logger = require('../logger').access;
const validator = require('ajv');
const error = require('./error');
const userModel = require('../models/user');
const proxyHostModel = require('../models/proxy_host');
const TokenModel = require('../models/token');
const roleSchema = require('./access/roles.json');
const permsSchema = require('./access/permissions.json');
module.exports = function (token_string) {
let Token = new TokenModel();
let token_data = null;
let initialised = false;
let object_cache = {};
let allow_internal_access = false;
let user_roles = [];
let permissions = {};
/**
* Loads the Token object from the token string
*
* @returns {Promise}
*/
this.init = () => {
return new Promise((resolve, reject) => {
if (initialised) {
resolve();
} else if (!token_string) {
reject(new error.PermissionError('Permission Denied'));
} else {
resolve(Token.load(token_string)
.then((data) => {
token_data = data;
// At this point we need to load the user from the DB and make sure they:
// - exist (and not soft deleted)
// - still have the appropriate scopes for this token
// This is only required when the User ID is supplied or if the token scope has `user`
if (token_data.attrs.id || (typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'user') !== -1)) {
// Has token user id or token user scope
return userModel
.query()
.where('id', token_data.attrs.id)
.andWhere('is_deleted', 0)
.andWhere('is_disabled', 0)
.allowEager('[permissions]')
.eager('[permissions]')
.first()
.then((user) => {
if (user) {
// make sure user has all scopes of the token
// The `user` role is not added against the user row, so we have to just add it here to get past this check.
user.roles.push('user');
let is_ok = true;
_.forEach(token_data.scope, (scope_item) => {
if (_.indexOf(user.roles, scope_item) === -1) {
is_ok = false;
}
});
if (!is_ok) {
throw new error.AuthError('Invalid token scope for User');
} else {
initialised = true;
user_roles = user.roles;
permissions = user.permissions;
}
} else {
throw new error.AuthError('User cannot be loaded for Token');
}
});
} else {
initialised = true;
}
}));
}
});
};
/**
* Fetches the object ids from the database, only once per object type, for this token.
* This only applies to USER token scopes, as all other tokens are not really bound
* by object scopes
*
* @param {String} object_type
* @returns {Promise}
*/
this.loadObjects = (object_type) => {
return new Promise((resolve, reject) => {
if (Token.hasScope('user')) {
if (typeof token_data.attrs.id === 'undefined' || !token_data.attrs.id) {
reject(new error.AuthError('User Token supplied without a User ID'));
} else {
let token_user_id = token_data.attrs.id ? token_data.attrs.id : 0;
let query;
if (typeof object_cache[object_type] === 'undefined') {
switch (object_type) {
// USERS - should only return yourself
case 'users':
resolve(token_user_id ? [token_user_id] : []);
break;
// Proxy Hosts
case 'proxy_hosts':
query = proxyHostModel
.query()
.select('id')
.andWhere('is_deleted', 0);
if (permissions.visibility === 'user') {
query.andWhere('owner_user_id', token_user_id);
}
resolve(query
.then((rows) => {
let result = [];
_.forEach(rows, (rule_row) => {
result.push(rule_row.id);
});
// enum should not have less than 1 item
if (!result.length) {
result.push(0);
}
return result;
})
);
break;
// DEFAULT: null
default:
resolve(null);
break;
}
} else {
resolve(object_cache[object_type]);
}
}
} else {
resolve(null);
}
})
.then((objects) => {
object_cache[object_type] = objects;
return objects;
});
};
/**
* Creates a schema object on the fly with the IDs and other values required to be checked against the permissionSchema
*
* @param {String} permission_label
* @returns {Object}
*/
this.getObjectSchema = (permission_label) => {
let base_object_type = permission_label.split(':').shift();
let schema = {
$id: 'objects',
$schema: 'http://json-schema.org/draft-07/schema#',
description: 'Actor Properties',
type: 'object',
additionalProperties: false,
properties: {
user_id: {
anyOf: [
{
type: 'number',
enum: [Token.get('attrs').id]
}
]
},
scope: {
type: 'string',
pattern: '^' + Token.get('scope') + '$'
}
}
};
return this.loadObjects(base_object_type)
.then((object_result) => {
if (typeof object_result === 'object' && object_result !== null) {
schema.properties[base_object_type] = {
type: 'number',
enum: object_result,
minimum: 1
};
} else {
schema.properties[base_object_type] = {
type: 'number',
minimum: 1
};
}
return schema;
});
};
return {
token: Token,
/**
*
* @param {Boolean} [allow_internal]
* @returns {Promise}
*/
load: (allow_internal) => {
return new Promise(function (resolve/*, reject*/) {
if (token_string) {
resolve(Token.load(token_string));
} else {
allow_internal_access = allow_internal;
resolve(allow_internal_access || null);
}
});
},
reloadObjects: this.loadObjects,
/**
*
* @param {String} permission
* @param {*} [data]
* @returns {Promise}
*/
can: (permission, data) => {
if (allow_internal_access === true) {
return Promise.resolve(true);
//return true;
} else {
return this.init()
.then(() => {
// Initialised, token decoded ok
return this.getObjectSchema(permission)
.then((objectSchema) => {
let data_schema = {
[permission]: {
data: data,
scope: Token.get('scope'),
roles: user_roles,
permission_visibility: permissions.visibility,
permission_proxy_hosts: permissions.proxy_hosts,
permission_redirection_hosts: permissions.redirection_hosts,
permission_dead_hosts: permissions.dead_hosts,
permission_streams: permissions.streams,
permission_access_lists: permissions.access_lists,
permission_certificates: permissions.certificates
}
};
let permissionSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
$async: true,
$id: 'permissions',
additionalProperties: false,
properties: {}
};
permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json');
// logger.info('objectSchema', JSON.stringify(objectSchema, null, 2));
// logger.info('permissionSchema', JSON.stringify(permissionSchema, null, 2));
// logger.info('data_schema', JSON.stringify(data_schema, null, 2));
let ajv = validator({
verbose: true,
allErrors: true,
format: 'full',
missingRefs: 'fail',
breakOnError: true,
coerceTypes: true,
schemas: [
roleSchema,
permsSchema,
objectSchema,
permissionSchema
]
});
return ajv.validate('permissions', data_schema)
.then(() => {
return data_schema[permission];
});
});
})
.catch((err) => {
err.permission = permission;
err.permission_data = data;
logger.error(permission, data, err.message);
throw new error.PermissionError('Permission Denied', err);
});
}
}
};
};

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_access_lists", "roles"],
"properties": {
"permission_access_lists": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_access_lists", "roles"],
"properties": {
"permission_access_lists": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_access_lists", "roles"],
"properties": {
"permission_access_lists": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_access_lists", "roles"],
"properties": {
"permission_access_lists": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_access_lists", "roles"],
"properties": {
"permission_access_lists": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_certificates", "roles"],
"properties": {
"permission_certificates": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_certificates", "roles"],
"properties": {
"permission_certificates": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_certificates", "roles"],
"properties": {
"permission_certificates": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_certificates", "roles"],
"properties": {
"permission_certificates": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_certificates", "roles"],
"properties": {
"permission_certificates": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_dead_hosts", "roles"],
"properties": {
"permission_dead_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_dead_hosts", "roles"],
"properties": {
"permission_dead_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_dead_hosts", "roles"],
"properties": {
"permission_dead_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_dead_hosts", "roles"],
"properties": {
"permission_dead_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_dead_hosts", "roles"],
"properties": {
"permission_dead_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "perms",
"definitions": {
"view": {
"type": "string",
"pattern": "^(view|manage)$"
},
"manage": {
"type": "string",
"pattern": "^(manage)$"
}
}
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_proxy_hosts", "roles"],
"properties": {
"permission_proxy_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_proxy_hosts", "roles"],
"properties": {
"permission_proxy_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_proxy_hosts", "roles"],
"properties": {
"permission_proxy_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_proxy_hosts", "roles"],
"properties": {
"permission_proxy_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_proxy_hosts", "roles"],
"properties": {
"permission_proxy_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_redirection_hosts", "roles"],
"properties": {
"permission_redirection_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_redirection_hosts", "roles"],
"properties": {
"permission_redirection_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_redirection_hosts", "roles"],
"properties": {
"permission_redirection_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_redirection_hosts", "roles"],
"properties": {
"permission_redirection_hosts": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_redirection_hosts", "roles"],
"properties": {
"permission_redirection_hosts": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/user"
}
]
}

View File

@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "roles",
"definitions": {
"admin": {
"type": "object",
"required": ["scope", "roles"],
"properties": {
"scope": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^user$"
}
},
"roles": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^admin$"
}
}
}
},
"user": {
"type": "object",
"required": ["scope"],
"properties": {
"scope": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^user$"
}
}
}
}
}
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_streams", "roles"],
"properties": {
"permission_streams": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_streams", "roles"],
"properties": {
"permission_streams": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_streams", "roles"],
"properties": {
"permission_streams": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_streams", "roles"],
"properties": {
"permission_streams": {
"$ref": "perms#/definitions/view"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["permission_streams", "roles"],
"properties": {
"permission_streams": {
"$ref": "perms#/definitions/manage"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"enum": ["user"]
}
}
}
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["data", "scope"],
"properties": {
"data": {
"$ref": "objects#/properties/users"
},
"scope": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^user$"
}
}
}
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["data", "scope"],
"properties": {
"data": {
"$ref": "objects#/properties/users"
},
"scope": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^user$"
}
}
}
}
]
}

View File

@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}

View File

@ -0,0 +1,23 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
},
{
"type": "object",
"required": ["data", "scope"],
"properties": {
"data": {
"$ref": "objects#/properties/users"
},
"scope": {
"type": "array",
"contains": {
"type": "string",
"pattern": "^user$"
}
}
}
}
]
}

90
backend/lib/error.js Normal file
View File

@ -0,0 +1,90 @@
const _ = require('lodash');
const util = require('util');
module.exports = {
PermissionError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = 'Permission Denied';
this.public = true;
this.status = 403;
},
ItemNotFoundError: function (id, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = 'Item Not Found - ' + id;
this.public = true;
this.status = 404;
},
AuthError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.public = true;
this.status = 401;
},
InternalError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.status = 500;
this.public = false;
},
InternalValidationError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.status = 400;
this.public = false;
},
ConfigurationError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.status = 400;
this.public = true;
},
CacheError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.message = message;
this.previous = previous;
this.status = 500;
this.public = false;
},
ValidationError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.public = true;
this.status = 400;
},
AssertionFailedError: function (message, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = message;
this.public = false;
this.status = 400;
}
};
_.forEach(module.exports, function (error) {
util.inherits(error, Error);
});

View File

@ -0,0 +1,40 @@
const validator = require('../validator');
module.exports = function (req, res, next) {
if (req.headers.origin) {
const originSchema = {
oneOf: [
{
type: 'string',
pattern: '^[a-z\\-]+:\\/\\/(?:[\\w\\-\\.]+(:[0-9]+)?/?)?$'
},
{
type: 'string',
pattern: '^[a-z\\-]+:\\/\\/(?:\\[([a-z0-9]{0,4}\\:?)+\\])?/?(:[0-9]+)?$'
}
]
};
// very relaxed validation....
validator(originSchema, req.headers.origin)
.then(function () {
res.set({
'Access-Control-Allow-Origin': req.headers.origin,
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'OPTIONS, GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit',
'Access-Control-Max-Age': 5 * 60,
'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit'
});
next();
})
.catch(next);
} else {
// No origin
next();
}
};

View File

@ -0,0 +1,15 @@
const Access = require('../access');
module.exports = () => {
return function (req, res, next) {
res.locals.access = null;
let access = new Access(res.locals.token || null);
access.load()
.then(() => {
res.locals.access = access;
next();
})
.catch(next);
};
};

View File

@ -0,0 +1,13 @@
module.exports = function () {
return function (req, res, next) {
if (req.headers.authorization) {
let parts = req.headers.authorization.split(' ');
if (parts && parts[0] === 'Bearer' && parts[1]) {
res.locals.token = parts[1];
}
}
next();
};
};

View File

@ -0,0 +1,55 @@
let _ = require('lodash');
module.exports = function (default_sort, default_offset, default_limit, max_limit) {
/**
* This will setup the req query params with filtered data and defaults
*
* sort will be an array of fields and their direction
* offset will be an int, defaulting to zero if no other default supplied
* limit will be an int, defaulting to 50 if no other default supplied, and limited to the max if that was supplied
*
*/
return function (req, res, next) {
req.query.offset = typeof req.query.limit === 'undefined' ? default_offset || 0 : parseInt(req.query.offset, 10);
req.query.limit = typeof req.query.limit === 'undefined' ? default_limit || 50 : parseInt(req.query.limit, 10);
if (max_limit && req.query.limit > max_limit) {
req.query.limit = max_limit;
}
// Sorting
let sort = typeof req.query.sort === 'undefined' ? default_sort : req.query.sort;
let myRegexp = /.*\.(asc|desc)$/ig;
let sort_array = [];
sort = sort.split(',');
_.map(sort, function (val) {
let matches = myRegexp.exec(val);
if (matches !== null) {
let dir = matches[1];
sort_array.push({
field: val.substr(0, val.length - (dir.length + 1)),
dir: dir.toLowerCase()
});
} else {
sort_array.push({
field: val,
dir: 'asc'
});
}
});
// Sort will now be in this format:
// [
// { field: 'field1', dir: 'asc' },
// { field: 'field2', dir: 'desc' }
// ]
req.query.sort = sort_array;
next();
};
};

View File

@ -0,0 +1,9 @@
module.exports = (req, res, next) => {
if (req.params.user_id === 'me' && res.locals.access) {
req.params.user_id = res.locals.access.token.get('attrs').id;
} else {
req.params.user_id = parseInt(req.params.user_id, 10);
}
next();
};

32
backend/lib/helpers.js Normal file
View File

@ -0,0 +1,32 @@
const moment = require('moment');
module.exports = {
/**
* Takes an expression such as 30d and returns a moment object of that date in future
*
* Key Shorthand
* ==================
* years y
* quarters Q
* months M
* weeks w
* days d
* hours h
* minutes m
* seconds s
* milliseconds ms
*
* @param {String} expression
* @returns {Object}
*/
parseDatePeriod: function (expression) {
let matches = expression.match(/^([0-9]+)(y|Q|M|w|d|h|m|s|ms)$/m);
if (matches) {
return moment().add(matches[1], matches[2]);
}
return null;
}
};

View File

@ -0,0 +1,55 @@
const migrate_name = 'identifier_for_migrate';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex, Promise) {
logger.info('[' + migrate_name + '] Migrating Up...');
// Create Table example:
/*return knex.schema.createTable('notification', (table) => {
table.increments().primary();
table.string('name').notNull();
table.string('type').notNull();
table.integer('created_on').notNull();
table.integer('modified_on').notNull();
})
.then(function () {
logger.info('[' + migrate_name + '] Notification Table created');
});*/
logger.info('[' + migrate_name + '] Migrating Up Complete');
return Promise.resolve(true);
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.info('[' + migrate_name + '] Migrating Down...');
// Drop table example:
/*return knex.schema.dropTable('notification')
.then(() => {
logger.info('[' + migrate_name + '] Notification Table dropped');
});*/
logger.info('[' + migrate_name + '] Migrating Down Complete');
return Promise.resolve(true);
};

20
backend/lib/utils.js Normal file
View File

@ -0,0 +1,20 @@
const exec = require('child_process').exec;
module.exports = {
/**
* @param {String} cmd
* @returns {Promise}
*/
exec: function (cmd) {
return new Promise((resolve, reject) => {
exec(cmd, function (err, stdout, /*stderr*/) {
if (err && typeof err === 'object') {
reject(err);
} else {
resolve(stdout.trim());
}
});
});
}
};

View File

@ -0,0 +1,45 @@
const error = require('../error');
const path = require('path');
const parser = require('json-schema-ref-parser');
const ajv = require('ajv')({
verbose: true,
validateSchema: true,
allErrors: false,
format: 'full',
coerceTypes: true
});
/**
* @param {Object} schema
* @param {Object} payload
* @returns {Promise}
*/
function apiValidator (schema, payload/*, description*/) {
return new Promise(function Promise_apiValidator (resolve, reject) {
if (typeof payload === 'undefined') {
reject(new error.ValidationError('Payload is undefined'));
}
let validate = ajv.compile(schema);
let valid = validate(payload);
if (valid && !validate.errors) {
resolve(payload);
} else {
let message = ajv.errorsText(validate.errors);
let err = new error.ValidationError(message);
err.debug = [validate.errors, payload];
reject(err);
}
});
}
apiValidator.loadSchemas = parser
.dereference(path.resolve('schema/index.json'))
.then((schema) => {
ajv.addSchema(schema);
return schema;
});
module.exports = apiValidator;

View File

@ -0,0 +1,49 @@
const _ = require('lodash');
const error = require('../error');
const definitions = require('../../schema/definitions.json');
RegExp.prototype.toJSON = RegExp.prototype.toString;
const ajv = require('ajv')({
verbose: true, //process.env.NODE_ENV === 'development',
allErrors: true,
format: 'full', // strict regexes for format checks
coerceTypes: true,
schemas: [
definitions
]
});
/**
*
* @param {Object} schema
* @param {Object} payload
* @returns {Promise}
*/
function validator (schema, payload) {
return new Promise(function (resolve, reject) {
if (!payload) {
reject(new error.InternalValidationError('Payload is falsy'));
} else {
try {
let validate = ajv.compile(schema);
let valid = validate(payload);
if (valid && !validate.errors) {
resolve(_.cloneDeep(payload));
} else {
let message = ajv.errorsText(validate.errors);
reject(new error.InternalValidationError(message));
}
} catch (err) {
reject(err);
}
}
});
}
module.exports = validator;

13
backend/logger.js Normal file
View File

@ -0,0 +1,13 @@
const {Signale} = require('signale');
module.exports = {
global: new Signale({scope: 'Global '}),
migrate: new Signale({scope: 'Migrate '}),
express: new Signale({scope: 'Express '}),
access: new Signale({scope: 'Access '}),
nginx: new Signale({scope: 'Nginx '}),
ssl: new Signale({scope: 'SSL '}),
import: new Signale({scope: 'Importer '}),
setup: new Signale({scope: 'Setup '}),
ip_ranges: new Signale({scope: 'IP Ranges'})
};

15
backend/migrate.js Normal file
View File

@ -0,0 +1,15 @@
const db = require('./db');
const logger = require('./logger').migrate;
module.exports = {
latest: function () {
return db.migrate.currentVersion()
.then((version) => {
logger.info('Current database version:', version);
return db.migrate.latest({
tableName: 'migrations',
directory: 'migrations'
});
});
}
};

View File

@ -0,0 +1,205 @@
const migrate_name = 'initial-schema';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex/*, Promise*/) {
logger.info('[' + migrate_name + '] Migrating Up...');
return knex.schema.createTable('auth', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('user_id').notNull().unsigned();
table.string('type', 30).notNull();
table.string('secret').notNull();
table.json('meta').notNull();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
})
.then(() => {
logger.info('[' + migrate_name + '] auth Table created');
return knex.schema.createTable('user', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.integer('is_disabled').notNull().unsigned().defaultTo(0);
table.string('email').notNull();
table.string('name').notNull();
table.string('nickname').notNull();
table.string('avatar').notNull();
table.json('roles').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] user Table created');
return knex.schema.createTable('user_permission', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('user_id').notNull().unsigned();
table.string('visibility').notNull();
table.string('proxy_hosts').notNull();
table.string('redirection_hosts').notNull();
table.string('dead_hosts').notNull();
table.string('streams').notNull();
table.string('access_lists').notNull();
table.string('certificates').notNull();
table.unique('user_id');
});
})
.then(() => {
logger.info('[' + migrate_name + '] user_permission Table created');
return knex.schema.createTable('proxy_host', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.json('domain_names').notNull();
table.string('forward_ip').notNull();
table.integer('forward_port').notNull().unsigned();
table.integer('access_list_id').notNull().unsigned().defaultTo(0);
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.integer('caching_enabled').notNull().unsigned().defaultTo(0);
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table created');
return knex.schema.createTable('redirection_host', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.json('domain_names').notNull();
table.string('forward_domain_name').notNull();
table.integer('preserve_path').notNull().unsigned().defaultTo(0);
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] redirection_host Table created');
return knex.schema.createTable('dead_host', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.json('domain_names').notNull();
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] dead_host Table created');
return knex.schema.createTable('stream', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.integer('incoming_port').notNull().unsigned();
table.string('forward_ip').notNull();
table.integer('forwarding_port').notNull().unsigned();
table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0);
table.integer('udp_forwarding').notNull().unsigned().defaultTo(0);
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] stream Table created');
return knex.schema.createTable('access_list', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('name').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] access_list Table created');
return knex.schema.createTable('certificate', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('owner_user_id').notNull().unsigned();
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
table.string('provider').notNull();
table.string('nice_name').notNull().defaultTo('');
table.json('domain_names').notNull();
table.dateTime('expires_on').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] certificate Table created');
return knex.schema.createTable('access_list_auth', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('access_list_id').notNull().unsigned();
table.string('username').notNull();
table.string('password').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] access_list_auth Table created');
return knex.schema.createTable('audit_log', (table) => {
table.increments().primary();
table.dateTime('created_on').notNull();
table.dateTime('modified_on').notNull();
table.integer('user_id').notNull().unsigned();
table.string('object_type').notNull().defaultTo('');
table.integer('object_id').notNull().unsigned().defaultTo(0);
table.string('action').notNull();
table.json('meta').notNull();
});
})
.then(() => {
logger.info('[' + migrate_name + '] audit_log Table created');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.warn('[' + migrate_name + '] You can\'t migrate down the initial data.');
return Promise.resolve(true);
};

View File

@ -0,0 +1,35 @@
const migrate_name = 'websockets';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex/*, Promise*/) {
logger.info('[' + migrate_name + '] Migrating Up...');
return knex.schema.table('proxy_host', function (proxy_host) {
proxy_host.integer('allow_websocket_upgrade').notNull().unsigned().defaultTo(0);
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table altered');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
return Promise.resolve(true);
};

View File

@ -0,0 +1,34 @@
const migrate_name = 'forward_host';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex/*, Promise*/) {
logger.info('[' + migrate_name + '] Migrating Up...');
return knex.schema.table('proxy_host', function (proxy_host) {
proxy_host.renameColumn('forward_ip', 'forward_host');
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table altered');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
return Promise.resolve(true);
};

View File

@ -0,0 +1,49 @@
const migrate_name = 'http2_support';
const logger = require('../logger').migrate;
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.up = function (knex/*, Promise*/) {
logger.info('[' + migrate_name + '] Migrating Up...');
return knex.schema.table('proxy_host', function (proxy_host) {
proxy_host.integer('http2_support').notNull().unsigned().defaultTo(0);
})
.then(() => {
logger.info('[' + migrate_name + '] proxy_host Table altered');
return knex.schema.table('redirection_host', function (redirection_host) {
redirection_host.integer('http2_support').notNull().unsigned().defaultTo(0);
});
})
.then(() => {
logger.info('[' + migrate_name + '] redirection_host Table altered');
return knex.schema.table('dead_host', function (dead_host) {
dead_host.integer('http2_support').notNull().unsigned().defaultTo(0);
});
})
.then(() => {
logger.info('[' + migrate_name + '] dead_host Table altered');
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @param {Promise} Promise
* @returns {Promise}
*/
exports.down = function (knex, Promise) {
logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
return Promise.resolve(true);
};

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