mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-06-18 02:06:25 +00:00
Compare commits
1085 Commits
Author | SHA1 | Date | |
---|---|---|---|
aec30207da | |||
209c1b3334 | |||
58138fbac4 | |||
da820db4e1 | |||
89a405f60c | |||
0353051436 | |||
a3630a6286 | |||
10d9760242 | |||
c722eb1cea | |||
0472abacd2 | |||
a2e85ceed8 | |||
cddd6fb985 | |||
db23c9a52f | |||
8646cb5a19 | |||
fe0c04610f | |||
9f16dae2ff | |||
00264bcfb2 | |||
834fb1a361 | |||
1be87f48c1 | |||
9c54d1b718 | |||
f7d1c490b3 | |||
fe4bd9fed6 | |||
58ef9a688e | |||
d19ebf5925 | |||
96fc6a20bb | |||
e69684919c | |||
be39253a6f | |||
30772a48bd | |||
33c867895c | |||
a7fe687bae | |||
4028120f55 | |||
d1119ec63f | |||
4c906283df | |||
8ec0c76f51 | |||
c70f65d349 | |||
883a272b0a | |||
6aee2bbcba | |||
025fc9776b | |||
b699f05f47 | |||
f7c87f63bd | |||
e4ef095254 | |||
09d5e2c94f | |||
459b7a2223 | |||
9c813bcce3 | |||
b8596ac01c | |||
082c4e1008 | |||
2273eae6ee | |||
997e9d431b | |||
b3564b6d4b | |||
4e27cdabc4 | |||
965873adc5 | |||
5de95a8c90 | |||
fa557d8159 | |||
bc8211a6a9 | |||
1c498f84ad | |||
ea6e9757e3 | |||
1308ae42c2 | |||
7be548575b | |||
c6aab8d4e6 | |||
da55e93183 | |||
af475ab5d4 | |||
7d85463dae | |||
13d4f98fdb | |||
388fff84f2 | |||
49a765516c | |||
27bc8c4e33 | |||
881a067aff | |||
1975e4a151 | |||
4704bd6a38 | |||
ca56e0483f | |||
3b8cb86d72 | |||
5165de4a91 | |||
1ab3575c68 | |||
ccf9cce825 | |||
3ad2188f78 | |||
33dbffb974 | |||
289e438c59 | |||
e08a4d4490 | |||
d1d1819677 | |||
4e0768d56c | |||
3666364418 | |||
9052502a17 | |||
b608d3392d | |||
edb81ecce0 | |||
e24181936f | |||
940d06cac9 | |||
134902d127 | |||
2df4620d05 | |||
f41b1069ae | |||
004a93fbc3 | |||
2d9f04edcd | |||
53dbe258a5 | |||
e4ba22f0f8 | |||
3197de41de | |||
0f7be7987b | |||
853c48dff6 | |||
410c3484ab | |||
44e9f377f9 | |||
0f3b76f607 | |||
f426e64569 | |||
4867db078c | |||
6b565e628f | |||
881d70502b | |||
62e4edddf0 | |||
4b9c02cc0c | |||
5af834e40b | |||
6f8db95249 | |||
fe93cb3474 | |||
fa851b61da | |||
3333a32612 | |||
9a79fce498 | |||
b1180f5077 | |||
5454352fe5 | |||
aee93a2f6f | |||
f38cb5b500 | |||
f1b7156c89 | |||
98465cf1b0 | |||
137e865b66 | |||
e740fb4064 | |||
f91f0ee8db | |||
1c9f751512 | |||
a602bdd514 | |||
f7b2be68cc | |||
ab4586fc6b | |||
a984a68065 | |||
52875fca6e | |||
63b50fcd95 | |||
5ab4aea03f | |||
d73135378e | |||
e19d685cb6 | |||
c8caaa56d9 | |||
11a98f4c12 | |||
4a85d4ac4e | |||
3138ba46ce | |||
cdd0b2e6d3 | |||
f458730d87 | |||
d20873dcbb | |||
d1e9407e4d | |||
63ee69f432 | |||
f39e527680 | |||
2dd4434ceb | |||
81054631f9 | |||
53d61bd626 | |||
847e879b3f | |||
4c59400731 | |||
824c837a38 | |||
2a06384a4a | |||
05307aa253 | |||
3d2406ac3d | |||
0127dc7f03 | |||
4349d42636 | |||
4b6f9d9419 | |||
c3f019c911 | |||
ecf0290203 | |||
4f41fe0c95 | |||
c3735fdbbb | |||
c432c34fb3 | |||
a1245bc161 | |||
db4ab1d548 | |||
86ddd9c83c | |||
67208e43cc | |||
ddf80302c6 | |||
5f2576946d | |||
9fe07fa6c3 | |||
d9b9af543e | |||
eb2e2e0478 | |||
9225d5d442 | |||
308a7149ed | |||
8a4a7d0caf | |||
5d03ede100 | |||
4a86bb42cc | |||
dad8561ea1 | |||
56a92e5c0e | |||
9d672f5813 | |||
d5ed70dbb6 | |||
c197e66d62 | |||
91cf3c8873 | |||
7f5e0414ac | |||
d179887c15 | |||
35abb4d7ae | |||
61b290e220 | |||
e1bcef6e5c | |||
81f51f9e2d | |||
661953db25 | |||
065c2dac42 | |||
2926844cbe | |||
c1960f3793 | |||
11a29a8b67 | |||
c40e48e678 | |||
124cb18e17 | |||
5ac9dc0758 | |||
9a799d51ce | |||
77eb618758 | |||
79fedfcea4 | |||
8fdb8ac853 | |||
4fdc80be01 | |||
f8e6c8d018 | |||
c3469de61b | |||
ea61b15a40 | |||
60175e6d8c | |||
2a07445005 | |||
dad3e1da7c | |||
82d9452001 | |||
095bc8f676 | |||
8c15340b83 | |||
a13f7c3792 | |||
6748985669 | |||
e2957f070b | |||
fccbde1371 | |||
fec36834f7 | |||
00aeef75b6 | |||
5b7682f13c | |||
b30fcb50c8 | |||
100c56ad10 | |||
44bebf366a | |||
6a28701242 | |||
09d1d3744c | |||
84e0b30f8d | |||
546ce8d4bc | |||
9b40bb288d | |||
c812b674b6 | |||
86e63197f6 | |||
c371b2e953 | |||
2142e25029 | |||
30076a0e66 | |||
42bd39163a | |||
cc4891d9ec | |||
40c26839f5 | |||
2ff66ee238 | |||
9d60b4a756 | |||
d2becc0681 | |||
579c32a724 | |||
b08ef17894 | |||
589ab8757e | |||
abdaac8584 | |||
d5c950a231 | |||
d9a1701927 | |||
6e500c35dc | |||
a06e96061f | |||
f0513d34f9 | |||
09349efbbe | |||
06453e9668 | |||
b1e904df84 | |||
5f435b6325 | |||
7b48488c29 | |||
3f6ad0d807 | |||
edba369ae8 | |||
b77d916bdd | |||
2706454635 | |||
32a3bb1d6d | |||
95665ca378 | |||
09d6cf7c48 | |||
2addc48a9b | |||
ebf07a7912 | |||
abe6493244 | |||
9f192ab275 | |||
52e013d289 | |||
331da3841e | |||
e227f4177b | |||
88fa7cdfff | |||
f3b3072711 | |||
cf6cc7dcc5 | |||
448c8a2dd5 | |||
634cfe13f1 | |||
7597515c20 | |||
93f57aece5 | |||
ef6da1bbe1 | |||
4ad9e68886 | |||
9b35e7c188 | |||
2aa6e55d6b | |||
1ac28410ff | |||
b0fd976b97 | |||
7fe7e94fbd | |||
8864960eb4 | |||
23326895b2 | |||
d2f707b76d | |||
a7f0c3b730 | |||
a9e84f1750 | |||
7ca3a9e7a6 | |||
c80d099193 | |||
35aba13122 | |||
b69e493c54 | |||
99d73a2da8 | |||
3c23aa935e | |||
8dee139810 | |||
6349cb6094 | |||
452838b04a | |||
fd30cfe98b | |||
6f281fef42 | |||
5920b0cf5e | |||
41bbfcf165 | |||
80a93e17fa | |||
4a1eebc54b | |||
264ba71462 | |||
e229fa89f8 | |||
d3b72ae07d | |||
b62b6b5112 | |||
c44f8c6155 | |||
0dfa3d9ca3 | |||
8c7c84906b | |||
662143cf21 | |||
c60fc7926e | |||
cfbdc6c340 | |||
2f6d8257ec | |||
b9a6b5d4f5 | |||
32f77dbcee | |||
052cb8f12d | |||
03b544023b | |||
5070499cfd | |||
e77b13d36e | |||
4bb237d7c2 | |||
aa5a7faa94 | |||
837f4dcbd4 | |||
d73a246b66 | |||
f85e82973d | |||
84afec567c | |||
e1525e5d56 | |||
d2688cf08c | |||
7372319568 | |||
60ffec5c64 | |||
23c88f6955 | |||
dd14207b63 | |||
103adfbb57 | |||
b673ebe2ca | |||
0e0c3df0cd | |||
8dbd482e08 | |||
ab5f7c0f26 | |||
191f493eb9 | |||
d1f4640a9c | |||
3d97f4578d | |||
fb0ef08fd8 | |||
0de78205b5 | |||
e0821bd927 | |||
e5966b54a8 | |||
d2f6b09901 | |||
5c8aa8517b | |||
1e5916db28 | |||
a3ae6956e2 | |||
518b84b38b | |||
932dc4bf02 | |||
bdc3a555b6 | |||
d4dcb61ee6 | |||
cce73beb2d | |||
4db34f5894 | |||
063ac4619f | |||
d1a338107b | |||
0d0b7e117f | |||
3538f9719f | |||
feaafdc559 | |||
edf369a3d4 | |||
eb148eb8f0 | |||
4251157ffa | |||
9866eec21c | |||
e879d41ee4 | |||
bb26f5b2c7 | |||
8e61d3eadf | |||
749ab36b1a | |||
c68874743d | |||
1a76f4ebfc | |||
59238d1dc1 | |||
661f3d6899 | |||
14b889a85f | |||
ac25171420 | |||
7281ed5968 | |||
dc541b2c72 | |||
9a854fd8fe | |||
8eb44c404d | |||
61b25e1213 | |||
d3a5a3d0d6 | |||
366fcf0bed | |||
29c0fcbad6 | |||
de84d5d463 | |||
078114ee67 | |||
49f350fb00 | |||
e141b5ff20 | |||
181f163cb5 | |||
30a9d3ae8d | |||
83e09ad5a7 | |||
8e5255a275 | |||
e4f06368bb | |||
0edd87324c | |||
96e034aa75 | |||
821432263a | |||
5edb16f36e | |||
a233bc0045 | |||
eed40d095e | |||
0d0e5295f4 | |||
51ac4bc688 | |||
4f97592965 | |||
be5a763d39 | |||
c435ce0224 | |||
67d8ede247 | |||
5e98ce32b7 | |||
a2c01655f0 | |||
3a71281937 | |||
f235ec8b5a | |||
fa7df05b92 | |||
1f3ac7a9ec | |||
5bd002a568 | |||
5fb0cc5fab | |||
818b9595aa | |||
c78f641e85 | |||
081380c8d5 | |||
7e451bce0b | |||
a082ec0604 | |||
973a10a9d1 | |||
1ec95096d5 | |||
e81cc45405 | |||
b9ef11e8bf | |||
0d8dd03c3d | |||
74d610d9ad | |||
9146ca6c63 | |||
d7e0ae0fa0 | |||
29ee48530c | |||
abe53a4bdd | |||
2d23bedf12 | |||
4e17fb476b | |||
c803ec7e26 | |||
7e67f33766 | |||
9dd5644183 | |||
5a8028a72d | |||
747de511d4 | |||
7800938fd2 | |||
ab80fe13e9 | |||
5d106c4064 | |||
2ac1026e4b | |||
b78c7e1c53 | |||
849bdcda7b | |||
5aae8cd0e3 | |||
adc5a2020a | |||
40b1521f72 | |||
ac23c66659 | |||
84bc33db8a | |||
6392df36c3 | |||
c82843279c | |||
b394eb8e55 | |||
bb422d4454 | |||
3dfe23836c | |||
d45f39aae3 | |||
cb091040a8 | |||
ddd538944a | |||
1f879f67a9 | |||
ee89dedd0f | |||
9ab5333652 | |||
3bd97ae1b0 | |||
432062e0f4 | |||
0c8bbb4bc2 | |||
48e96c46d5 | |||
25e9acf618 | |||
a517e80236 | |||
3d4d3bc73b | |||
cf4d1f73fa | |||
c203d1a0d8 | |||
5f29f6b039 | |||
f75b5b867b | |||
67463ca136 | |||
8db541f37f | |||
a5229d0e92 | |||
38ec0f9f95 | |||
3d80759a21 | |||
d95cd36b3e | |||
4c6b96ad5d | |||
c3bef2867e | |||
efc5bff2e1 | |||
ffe3db8c08 | |||
4ada0feae3 | |||
e17de6058e | |||
9efe6cfb39 | |||
c86a1a50bd | |||
c55476b196 | |||
3b47decbb0 | |||
d0bfa082e0 | |||
6b7a8b009e | |||
ca59e585d8 | |||
bbde7a108a | |||
87731a8b5c | |||
29d4bd4ccf | |||
925ad90f91 | |||
650ae61c43 | |||
02f3f9704f | |||
da7c3057b4 | |||
040b45cafa | |||
8ece310b9f | |||
96959db3c2 | |||
6360100611 | |||
b833044cea | |||
97909830f5 | |||
8ae2de2f49 | |||
bf7b659e89 | |||
4e3c7749af | |||
f63441921f | |||
725ba83606 | |||
281906c0b5 | |||
8ed121f43d | |||
81a9cab2b3 | |||
8d98a417c5 | |||
6fa81b179b | |||
9e169fbb42 | |||
27f84f880a | |||
0d9c941b4e | |||
8865aa9c8c | |||
6d8c4218f1 | |||
c134a43337 | |||
780759dc27 | |||
85128f08f3 | |||
d2f8c1e5f1 | |||
9c88b9c1e9 | |||
13fd2ce4e2 | |||
9979f516d6 | |||
39a5cd2d6e | |||
784516283f | |||
ce503232c3 | |||
f2edf9130f | |||
413ab50fc4 | |||
c1880bd3ff | |||
0f0a672275 | |||
06c5f991e7 | |||
babc5b7a38 | |||
b96c996a45 | |||
fb8f2c2f9a | |||
6794937391 | |||
f022e84979 | |||
fd5ac952cc | |||
07f60e5c77 | |||
628b8a7e1f | |||
30a442807d | |||
1626c8edd1 | |||
ca6561bf6c | |||
273a81471d | |||
8b07a67133 | |||
32089ea272 | |||
658acd147c | |||
ca3370a6ac | |||
c4e2557de2 | |||
6f2b4fdf86 | |||
f302ff71c9 | |||
fee87a44d6 | |||
8944609b63 | |||
be87c45f27 | |||
1b1807c79a | |||
a8f4699816 | |||
ac3df6dd77 | |||
5c67908460 | |||
7b67ef3015 | |||
e5a3b5ee2f | |||
5e9ff4d2bf | |||
daa71764b6 | |||
6a6c2ef192 | |||
320315956d | |||
4f10d129c2 | |||
62eb3fcd85 | |||
ab40e4e2cf | |||
0bb9450642 | |||
a6e15532b9 | |||
9a89a8a77e | |||
fe3675dc7a | |||
5c9acc2bff | |||
c94e937a50 | |||
3e4e10e644 | |||
ba7bb57ca2 | |||
14c125150a | |||
053701a702 | |||
3fc3e43042 | |||
b0dc68d7d4 | |||
e895baaeb4 | |||
c47f6fdb21 | |||
9e188e441a | |||
f6efcdf9f9 | |||
b1ceda3af4 | |||
cd3a0684d0 | |||
f25e54c6cb | |||
66f86cf497 | |||
d260edc547 | |||
ba1e6fa984 | |||
6b59f36213 | |||
1894960762 | |||
83c5c55f32 | |||
fb8c0b9a48 | |||
d34691152c | |||
cea80b482e | |||
c460a8fa5c | |||
5f852437fe | |||
8aded1a685 | |||
f2acb9e150 | |||
6f3a00c9b8 | |||
fbae107c04 | |||
6c1ae77a2a | |||
67e8ca6714 | |||
a56d976947 | |||
ac0bb6bee2 | |||
dee67dac75 | |||
9458cfbd1a | |||
4b8bdd22b3 | |||
a4c143e2d1 | |||
e91019feb9 | |||
8a37ec72b7 | |||
c263a33095 | |||
4b2c0115db | |||
673f40bd85 | |||
b9f8108cd3 | |||
a16ecf656b | |||
842cff130b | |||
346b9b4b79 | |||
56c317d223 | |||
b7b150a979 | |||
fae848bd1b | |||
a5b8087dc5 | |||
7aa078e025 | |||
4b6b276b64 | |||
0373daae5c | |||
7f30dd0475 | |||
d2a77c2371 | |||
104f65b541 | |||
d0fb4b6914 | |||
42c3272def | |||
2812889d61 | |||
bd3a13b2a5 | |||
289d179142 | |||
deca493912 | |||
d16bf7d6c0 | |||
3f1415dad1 | |||
3e744b6b2d | |||
56c4f8a106 | |||
99ef8bae4c | |||
b7f0343730 | |||
c807b59fb4 | |||
60fc57431a | |||
d988a3a307 | |||
de763d3fa9 | |||
21bfb61cc8 | |||
a79adeb280 | |||
9b7a019222 | |||
e65143d276 | |||
61bb183eda | |||
f3d3a6db91 | |||
9ebb443cb7 | |||
fa4c4d0a8d | |||
3e1518fef6 | |||
e59db84721 | |||
c281b31fc8 | |||
1c93ca9896 | |||
df5836e573 | |||
41ef35f0d0 | |||
5e6ce8643f | |||
f575400bc8 | |||
6d9a335b0e | |||
f94eb5f318 | |||
245fa421a2 | |||
655094a816 | |||
d544650b05 | |||
d9d682585c | |||
44a202552e | |||
fd6673420b | |||
0e9cd5db9c | |||
6da6e6f145 | |||
bdaa7460e4 | |||
d6d1c1ac35 | |||
67958155fc | |||
198bd74ec6 | |||
92eec95dad | |||
b73a034fca | |||
11b508f021 | |||
c2b5be37f9 | |||
1a04863a08 | |||
077d3eb993 | |||
ac38221bdf | |||
9f146b8fc3 | |||
9a2d9659a7 | |||
6faae5350a | |||
2616709e7f | |||
bed9ff084c | |||
fb3082b0bb | |||
c8439b8429 | |||
4c3632d3e7 | |||
24d8cd57da | |||
b7c0a8b0c2 | |||
d6d7b22b1e | |||
5269c957ce | |||
bf8d2672c8 | |||
8461acab9b | |||
731ae43fe8 | |||
5354c85352 | |||
22a37bb923 | |||
07bbece704 | |||
9af2f50d81 | |||
7b148f7970 | |||
a1e52d919f | |||
899b487daa | |||
86eeb5fc44 | |||
62a708b416 | |||
a7ce8704b3 | |||
7319a13077 | |||
95bd4d93c5 | |||
69c33f0395 | |||
cd4caea2dc | |||
c9daf19940 | |||
7c2540b193 | |||
3e600552dc | |||
69ee6b1699 | |||
ca1ea042b2 | |||
f26df7d9bb | |||
ba45705571 | |||
bf8ea71c77 | |||
7deb64a5de | |||
e283865d3d | |||
a32be3e96b | |||
0cfd6eab3f | |||
c2361f13e6 | |||
bc81de54b9 | |||
07884bc9b1 | |||
58c3204187 | |||
19d3deddd4 | |||
f0233b947e | |||
c6a90a2fd0 | |||
3607c30d98 | |||
717105f243 | |||
2373e4a06d | |||
4c76803f13 | |||
6a46e88f8f | |||
e4e94d5be0 | |||
a3b896fa70 | |||
60347a90e9 | |||
a02d4ec46f | |||
485bae8f22 | |||
655477316b | |||
e22f87dee7 | |||
d3337322dd | |||
6202f4f943 | |||
b42cc9ed3e | |||
fbf72c0f61 | |||
cbd0b0c070 | |||
874f049323 | |||
42ab4020e2 | |||
7ab9683b87 | |||
865facfd05 | |||
0951f4a202 | |||
882ec27969 | |||
a84158c1ff | |||
161d3ec817 | |||
5b15249689 | |||
602fce1c7e | |||
f2f653e345 | |||
b55738bd6e | |||
b39a59ce72 | |||
9872daf29f | |||
91044e730b | |||
656a7dceef | |||
d636502eaa | |||
389fd158ad | |||
30fa63b379 | |||
691063545c | |||
421934efed | |||
f056b9dc7f | |||
48d421ba28 | |||
096b714117 | |||
0d25dc1aaa | |||
63d3c2d06f | |||
5fc704ccad | |||
61d99561c1 | |||
c26ce2083f | |||
847d71f72a | |||
3c35039445 | |||
1a64d44857 | |||
ba5f0c212c | |||
4eddb5d7f3 | |||
3b104710d5 | |||
74db0004bd | |||
6e67352a0f | |||
b127f02468 | |||
c9c53d9670 | |||
d36dbb868b | |||
b7fb2cfe92 | |||
d0a0c77556 | |||
9469b9c78a | |||
e4988f34c7 | |||
1fe9e24f0a | |||
9c39de3454 | |||
9bb68ad4eb | |||
5bf774bee1 | |||
99514464fb | |||
3bf1c1e531 | |||
e2e31094aa | |||
f29ff15167 | |||
1c64252015 | |||
ead19915f3 | |||
967e0dd98a | |||
bd0324dba0 | |||
607fb83a1e | |||
bb5fc58f3a | |||
afbec0aca9 | |||
1e5d9dfbff | |||
cfcb657cde | |||
7f243e6f06 | |||
7e7032c051 | |||
b7b808d98d | |||
a21289bf11 | |||
4a8d01224a | |||
f0eebc43e3 | |||
49fbf031d1 | |||
4060718e5c | |||
49b0f11ae7 | |||
9b83d35ef4 | |||
eb20add0c7 | |||
1f122e9145 | |||
329d0ecaed | |||
77a2ee948a | |||
ebeda6345e | |||
e35138ebed | |||
8ba6c4f7e7 | |||
6df7b72e08 | |||
fe13b12f43 | |||
ea28da90b2 | |||
b243324c65 | |||
a2dde00f40 | |||
5ff07faa7e | |||
272c652847 | |||
3964bbf3fe | |||
11175aaa5f | |||
7fcc4a7ef0 | |||
5abb9458c7 | |||
0ca5587a6f | |||
d29650882b | |||
9c3a7b02ec | |||
ef3a073af5 | |||
15c4857a4b | |||
63a71afbc8 | |||
64761ee9c6 | |||
d6c344b5ec | |||
d27826d10e | |||
4ac52a0e25 | |||
efa841d75a | |||
d1fac583ea | |||
8cb44c7b97 | |||
f2293a9dda | |||
da0d1d4a2f | |||
6a8d5e2166 | |||
d732665a23 | |||
e0748c9bc7 | |||
23573543a3 | |||
bfb328238e | |||
64cc4f57d6 | |||
7a3c91c6a4 | |||
508bc62852 | |||
59e8446d47 | |||
d13596d2f7 | |||
9adccfa341 | |||
5cc3b53378 | |||
b62b0a2fb7 | |||
1faac4edf2 | |||
4c60dce169 | |||
771f31f44d | |||
8bedb95e1d | |||
ac4be08df2 | |||
0d6e058e23 | |||
bee2ceb667 | |||
6af13d4f40 | |||
9dd0ebd899 | |||
6e97bfa717 | |||
07b69f41eb | |||
6bd2ac7d6d | |||
528e5ef3bc | |||
bc1c50ac92 | |||
8c2ab42b75 | |||
62053d15d4 | |||
6fed642aba | |||
72ac549a58 | |||
9f38617135 | |||
94eec805df | |||
05a940e732 | |||
1c43cc2181 | |||
657ee73ff1 | |||
4ee5d993cf | |||
70a445e2d7 | |||
2115da210d | |||
540554c4f6 | |||
1337c50d28 | |||
c5ceb3b2b1 | |||
57fc1d8f08 | |||
1518ecd1e9 | |||
6be0343918 | |||
cf8812c932 | |||
5bc3e474a9 | |||
13eaa346bc | |||
d7437cc4a7 | |||
ddb3c6590c | |||
89d6773bda | |||
3651b9484f | |||
2200c950b7 | |||
14f84f01b5 | |||
cb014027bb | |||
32e5155783 | |||
a3159ad59e | |||
60a40197f1 | |||
7d693a4271 | |||
f192748bf9 | |||
96f401cba6 | |||
ffd2430160 | |||
190cd2d6bb | |||
7ba58bdbd3 | |||
08ab62108f | |||
1028de8158 | |||
301499dc52 | |||
5c2f13ed8e | |||
e30ad81f69 | |||
21f36f535f | |||
c14236823a | |||
551a9fe1c6 | |||
e3399e1035 | |||
c413b4af3f | |||
dbf5dec23b | |||
10f0eb17d7 | |||
e3b680c351 | |||
0df0545777 | |||
165bfc9f5f | |||
5830bd73b9 | |||
3c4ce839b9 | |||
ac9f052309 | |||
049e424957 | |||
07e78aec48 | |||
3fec135fe5 | |||
867fe1322b | |||
95208a50a7 | |||
514b13fcc2 | |||
4cbc1f5bbe | |||
64de36cdf2 | |||
093b48ad7b | |||
05f6a55a0b | |||
2523424f68 | |||
b81325d7bf | |||
3e10b7b2b1 | |||
e5cb750015 | |||
28f72086ec | |||
a6b9bd7b01 | |||
2c5eac9dad | |||
87f61b8527 | |||
74bfe490c6 | |||
015167f34d | |||
4bafc7ff1a | |||
bf8beb50b4 | |||
e5034a34f5 | |||
a561605653 | |||
e8596c1554 | |||
ab67481e99 | |||
1b611e67c8 | |||
c5aa2b9f77 | |||
cff6c4d1f5 | |||
077cf75ef2 | |||
ff1770204c | |||
b9a95840e0 | |||
2d7576c57e | |||
251aac716a | |||
6694a42270 | |||
f78a4c6ad1 | |||
83fad8bcda | |||
f539e813aa | |||
5d65166777 | |||
70346138a7 | |||
d68656559c | |||
01660b5b80 | |||
74010acd85 | |||
7c7d255172 | |||
058f1e9835 | |||
b4fc629ec0 | |||
ae06b2da75 | |||
54d423a11f | |||
5da6c97a00 | |||
bf2f13443f | |||
9ce4c3fe2f | |||
4a07bf666d | |||
5be46b4b20 | |||
7fd825b76b | |||
b23d59dec7 | |||
492d450d26 | |||
04412f3624 | |||
c41057b28a | |||
8312bc0100 | |||
85ac43bc5e | |||
d1a0780c7a | |||
f9b8d76527 | |||
26f00eeae4 | |||
1bc2df2178 | |||
8dfbcef198 | |||
6690b7735d | |||
a9e7222e5e | |||
f8edeb2775 | |||
d1786fe159 | |||
157a12fb7c | |||
3f723b1638 | |||
e2e9835d01 | |||
7599617b67 | |||
18a5b11033 | |||
fff31b0f34 | |||
c02e30663a | |||
4c6527cafc | |||
55bddb12e5 | |||
d95861e1fb | |||
94754a5cb3 | |||
546f862236 | |||
f105e29e56 | |||
5c15993d06 | |||
a369ea1080 | |||
98068c0f57 | |||
e0ef8683a2 | |||
66412a75f9 | |||
84d8fb0899 | |||
c631537dbe | |||
8d2f49541c | |||
55a28e3437 | |||
67ea2d01c8 | |||
dab229e37c | |||
7084473330 | |||
dd2e335fae | |||
1ff87bbc12 | |||
2ebfdcf0c9 | |||
8ab161a3ee | |||
e74b9617be | |||
c3d88c83e3 | |||
3e912a7474 | |||
0d726a1d83 | |||
affabf065e | |||
e6ea77d263 | |||
df73c2a458 | |||
96c5c79aef | |||
64922f07ff | |||
bae21f3210 | |||
0702a4e58e | |||
31f1d304d6 | |||
291a74c295 | |||
c0e9d1eb2f | |||
a7cabdde3a | |||
3af560c2d0 | |||
1d23d5c761 | |||
995db12f22 | |||
4c60bfb66b | |||
1716747047 | |||
090b4d0388 | |||
a9f068daa8 | |||
f5ee91aeb3 | |||
e2ee2cbf2d | |||
dcf8364899 | |||
b783602786 | |||
005e64eb9f | |||
e9e5d293cc | |||
a57255350f | |||
781442bf1e | |||
604bd2c576 | |||
d9e1e1bbb7 | |||
907e9e182d | |||
0f238a5021 | |||
8d432bd60a | |||
fd932c7678 | |||
46a9f5cb96 | |||
f990d3f674 | |||
4a6de8deee | |||
9a7a216b23 | |||
fccaaaae4d | |||
a882b0be82 | |||
db7bbab768 | |||
030e553549 | |||
8b0ca8e367 | |||
83b2b07200 | |||
bdb591af9e | |||
2993a08777 | |||
2a2d3d57ec | |||
33c2c131c2 | |||
e4286c96a7 | |||
2d9486b6fd | |||
632ee2d0bd | |||
b09f201819 | |||
baaf39c23d | |||
b7467c10e8 | |||
701ef18606 | |||
3e7d2b216b | |||
41f16c20b6 | |||
96bc0b53c3 | |||
b80baa78ef | |||
ce88e0745d | |||
256bd2336f | |||
1b6993ee70 | |||
af319b4729 | |||
1a15b4f18d | |||
3ddd3b49fd | |||
e2c4b32311 | |||
8fb2821343 | |||
93f29734b7 |
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -6,15 +6,30 @@ labels: bug
|
|||||||
assignees: ''
|
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**
|
**Checklist**
|
||||||
- Have you pulled and found the error with `jc21/nginx-proxy-manager:latest` docker image?
|
- 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?
|
- Are you sure you're not using someone else's docker image?
|
||||||
- If having problems with Lets Encrypt, have you made absolutely sure your site is accessible from outside of your network?
|
- Yes / No
|
||||||
|
- Have you searched for similar issues (both open and closed)?
|
||||||
|
- Yes / No
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
- A clear and concise description of what the bug is.
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
- What version of Nginx Proxy Manager is reported on the login page?
|
|
||||||
|
|
||||||
|
**Nginx Proxy Manager Version**
|
||||||
|
<!-- What version of Nginx Proxy Manager is reported on the login page? -->
|
||||||
|
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
Steps to reproduce the behavior:
|
Steps to reproduce the behavior:
|
||||||
@ -23,14 +38,18 @@ Steps to reproduce the behavior:
|
|||||||
3. Scroll down to '....'
|
3. Scroll down to '....'
|
||||||
4. See error
|
4. See error
|
||||||
|
|
||||||
|
|
||||||
**Expected behavior**
|
**Expected behavior**
|
||||||
A clear and concise description of what you expected to happen.
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
|
||||||
**Screenshots**
|
**Screenshots**
|
||||||
If applicable, add screenshots to help explain your problem.
|
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
|
|
||||||
**Operating System**
|
**Operating System**
|
||||||
- Please specify if using a Rpi, Mac, orchestration tool or any other setups that might affect the reproduction of this error.
|
<!-- Please specify if using a Rpi, Mac, orchestration tool or any other setups that might affect the reproduction of this error. -->
|
||||||
|
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here, docker version, browser version if applicable to the problem. Too much info is better than too little.
|
<!-- 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. -->
|
||||||
|
18
.github/ISSUE_TEMPLATE/dns_challenge_request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/dns_challenge_request.md
vendored
Normal 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>`.
|
||||||
|
-->
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -7,14 +7,26 @@ 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.**
|
**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 [...]
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
A clear and concise description of what you want to happen.
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
**Describe alternatives you've considered**
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or screenshots about the feature request here.
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
|
21
.github/workflows/stale.yml
vendored
Normal file
21
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: 'Close stale issues and PRs'
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '30 1 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
with:
|
||||||
|
stale-issue-label: 'stale'
|
||||||
|
stale-pr-label: 'stale'
|
||||||
|
stale-issue-message: 'Issue is now considered stale. If you want to keep it open, please comment :+1:'
|
||||||
|
stale-pr-message: 'PR is now considered stale. If you want to keep it open, please comment :+1:'
|
||||||
|
close-issue-message: 'Issue was closed due to inactivity.'
|
||||||
|
close-pr-message: 'PR was closed due to inactivity.'
|
||||||
|
days-before-stale: 182
|
||||||
|
days-before-close: 365
|
||||||
|
operations-per-run: 50
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,4 +2,4 @@
|
|||||||
.idea
|
.idea
|
||||||
._*
|
._*
|
||||||
.vscode
|
.vscode
|
||||||
|
certbot-help.txt
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"database": {
|
|
||||||
"engine": "mysql",
|
|
||||||
"host": "db",
|
|
||||||
"name": "npm",
|
|
||||||
"user": "npm",
|
|
||||||
"password": "npm",
|
|
||||||
"port": 3306
|
|
||||||
}
|
|
||||||
}
|
|
258
Jenkinsfile
vendored
258
Jenkinsfile
vendored
@ -1,3 +1,9 @@
|
|||||||
|
import groovy.transform.Field
|
||||||
|
|
||||||
|
@Field
|
||||||
|
def shOutput = ""
|
||||||
|
def buildxPushTags = ""
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent {
|
agent {
|
||||||
label 'docker-multiarch'
|
label 'docker-multiarch'
|
||||||
@ -5,12 +11,13 @@ pipeline {
|
|||||||
options {
|
options {
|
||||||
buildDiscarder(logRotator(numToKeepStr: '5'))
|
buildDiscarder(logRotator(numToKeepStr: '5'))
|
||||||
disableConcurrentBuilds()
|
disableConcurrentBuilds()
|
||||||
|
ansiColor('xterm')
|
||||||
}
|
}
|
||||||
environment {
|
environment {
|
||||||
IMAGE = "nginx-proxy-manager"
|
IMAGE = 'nginx-proxy-manager'
|
||||||
BUILD_VERSION = getVersion()
|
BUILD_VERSION = getVersion()
|
||||||
MAJOR_VERSION = "2"
|
MAJOR_VERSION = '2'
|
||||||
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}"
|
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')}"
|
||||||
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
|
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
|
||||||
COMPOSE_FILE = 'docker/docker-compose.ci.yml'
|
COMPOSE_FILE = 'docker/docker-compose.ci.yml'
|
||||||
COMPOSE_INTERACTIVE_NO_CLI = 1
|
COMPOSE_INTERACTIVE_NO_CLI = 1
|
||||||
@ -25,7 +32,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest"
|
buildxPushTags = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,69 +45,128 @@ pipeline {
|
|||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
// Defaults to the Branch name, which is applies to all branches AND pr's
|
// Defaults to the Branch name, which is applies to all branches AND pr's
|
||||||
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
|
buildxPushTags = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
stage('Versions') {
|
||||||
}
|
steps {
|
||||||
stage('Frontend') {
|
sh 'cat frontend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge frontend/package.json'
|
||||||
steps {
|
sh 'echo -e "\\E[1;36mFrontend Version is:\\E[1;33m $(cat frontend/package.json | jq -r .version)\\E[0m"'
|
||||||
ansiColor('xterm') {
|
sh 'cat backend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge backend/package.json'
|
||||||
sh './scripts/frontend-build'
|
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('Backend') {
|
}
|
||||||
steps {
|
}
|
||||||
ansiColor('xterm') {
|
stage('Builds') {
|
||||||
echo 'Checking Syntax ...'
|
parallel {
|
||||||
// See: https://github.com/yarnpkg/yarn/issues/3254
|
stage('Project') {
|
||||||
sh '''docker run --rm \\
|
steps {
|
||||||
-v "$(pwd)/backend:/app" \\
|
script {
|
||||||
-w /app \\
|
// Frontend and Backend
|
||||||
node:latest \\
|
def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
|
||||||
sh -c "yarn install && yarn eslint . && rm -rf node_modules"
|
set -e
|
||||||
'''
|
./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
|
||||||
|
./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
|
||||||
echo 'Docker Build ...'
|
''')
|
||||||
sh '''docker build --pull --no-cache --squash --compress \\
|
shOutput = readFile "${env.WORKSPACE}/tmp-sh-build"
|
||||||
-t "${IMAGE}:ci-${BUILD_NUMBER}" \\
|
if (shStatusCode != 0) {
|
||||||
-f docker/Dockerfile \\
|
error "${shOutput}"
|
||||||
--build-arg TARGETPLATFORM=linux/amd64 \\
|
}
|
||||||
--build-arg BUILDPLATFORM=linux/amd64 \\
|
}
|
||||||
--build-arg BUILD_VERSION="${BUILD_VERSION}" \\
|
}
|
||||||
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
|
post {
|
||||||
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
|
always {
|
||||||
.
|
sh 'rm -f ${WORKSPACE}/tmp-sh-build'
|
||||||
'''
|
}
|
||||||
}
|
failure {
|
||||||
}
|
npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
|
||||||
}
|
}
|
||||||
stage('Test') {
|
}
|
||||||
steps {
|
}
|
||||||
ansiColor('xterm') {
|
stage('Docs') {
|
||||||
// Bring up a stack
|
steps {
|
||||||
sh 'docker-compose up -d fullstack'
|
dir(path: 'docs') {
|
||||||
sh './scripts/wait-healthy $(docker-compose ps -q fullstack) 120'
|
sh 'yarn install'
|
||||||
|
sh 'yarn build'
|
||||||
// Run tests
|
}
|
||||||
sh 'rm -rf test/results'
|
dir(path: 'docs/.vuepress/dist') {
|
||||||
sh 'docker-compose up cypress'
|
sh 'tar -czf ../../docs.tgz *'
|
||||||
// Get results
|
}
|
||||||
sh 'docker cp -L "$(docker-compose ps -q cypress):/results" test/'
|
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post {
|
stage('Cypress') {
|
||||||
always {
|
steps {
|
||||||
junit 'test/results/junit/*'
|
// Creating will also create the network prior to
|
||||||
// Cypress videos and screenshot artifacts
|
// using it in parallel stages below and mitigating
|
||||||
dir(path: 'test/results') {
|
// a race condition.
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
|
sh 'docker-compose build cypress-sqlite'
|
||||||
|
sh 'docker-compose build cypress-mysql'
|
||||||
|
sh 'docker-compose create cypress-sqlite'
|
||||||
|
sh 'docker-compose create cypress-mysql'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Integration Tests') {
|
||||||
|
parallel {
|
||||||
|
stage('Sqlite') {
|
||||||
|
steps {
|
||||||
|
// Bring up a stack
|
||||||
|
sh 'docker-compose up -d fullstack-sqlite'
|
||||||
|
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
|
||||||
|
// Stop and Start it, as this will test it's ability to restart with existing data
|
||||||
|
sh 'docker-compose stop fullstack-sqlite'
|
||||||
|
sh 'docker-compose start fullstack-sqlite'
|
||||||
|
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
|
||||||
|
|
||||||
|
// Run tests
|
||||||
|
sh 'rm -rf test/results-sqlite'
|
||||||
|
sh 'docker-compose up cypress-sqlite'
|
||||||
|
// Get results
|
||||||
|
sh 'docker cp -L "$(docker-compose ps --all -q cypress-sqlite):/test/results" test/results-sqlite'
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
// Dumps to analyze later
|
||||||
|
sh 'mkdir -p debug/sqlite'
|
||||||
|
sh 'docker-compose logs fullstack-sqlite > debug/sqlite/docker_fullstack_sqlite.log'
|
||||||
|
// Cypress videos and screenshot artifacts
|
||||||
|
dir(path: 'test/results-sqlite') {
|
||||||
|
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
|
||||||
|
}
|
||||||
|
junit 'test/results-sqlite/junit/*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Mysql') {
|
||||||
|
steps {
|
||||||
|
// Bring up a stack
|
||||||
|
sh 'docker-compose up -d fullstack-mysql'
|
||||||
|
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-mysql) 120'
|
||||||
|
|
||||||
|
// Run tests
|
||||||
|
sh 'rm -rf test/results-mysql'
|
||||||
|
sh 'docker-compose up cypress-mysql'
|
||||||
|
// Get results
|
||||||
|
sh 'docker cp -L "$(docker-compose ps --all -q cypress-mysql):/test/results" test/results-mysql'
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
// Dumps to analyze later
|
||||||
|
sh 'mkdir -p debug/mysql'
|
||||||
|
sh 'docker-compose logs fullstack-mysql > debug/mysql/docker_fullstack_mysql.log'
|
||||||
|
sh 'docker-compose logs db > debug/mysql/docker_db.log'
|
||||||
|
// Cypress videos and screenshot artifacts
|
||||||
|
dir(path: 'test/results-mysql') {
|
||||||
|
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
|
||||||
|
}
|
||||||
|
junit 'test/results-mysql/junit/*'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Dumps to analyze later
|
|
||||||
sh 'mkdir -p debug'
|
|
||||||
sh 'docker-compose logs fullstack | gzip > debug/docker_fullstack.log.gz'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,28 +177,53 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
ansiColor('xterm') {
|
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
|
||||||
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
|
sh 'docker login -u "${duser}" -p "${dpass}"'
|
||||||
sh "docker login -u '${duser}' -p '${dpass}'"
|
sh "./scripts/buildx --push ${buildxPushTags}"
|
||||||
// Buildx with push
|
|
||||||
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('PR Comment') {
|
stage('Docs / Comment') {
|
||||||
when {
|
parallel {
|
||||||
allOf {
|
stage('Master Docs') {
|
||||||
changeRequest()
|
when {
|
||||||
not {
|
allOf {
|
||||||
equals expected: 'UNSTABLE', actual: currentBuild.result
|
branch 'master'
|
||||||
|
not {
|
||||||
|
equals expected: 'UNSTABLE', actual: currentBuild.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
npmDocsReleaseMaster()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
stage('Develop Docs') {
|
||||||
steps {
|
when {
|
||||||
ansiColor('xterm') {
|
allOf {
|
||||||
script {
|
branch 'develop'
|
||||||
def comment = pullRequest.comment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`")
|
not {
|
||||||
|
equals expected: 'UNSTABLE', actual: currentBuild.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
npmDocsReleaseDevelop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('PR Comment') {
|
||||||
|
when {
|
||||||
|
allOf {
|
||||||
|
changeRequest()
|
||||||
|
not {
|
||||||
|
equals expected: 'UNSTABLE', actual: currentBuild.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,20 +231,21 @@ pipeline {
|
|||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
sh 'docker-compose down --rmi all --remove-orphans --volumes -t 30'
|
sh 'docker-compose down --remove-orphans --volumes -t 30'
|
||||||
sh 'echo Reverting ownership'
|
sh 'echo Reverting ownership'
|
||||||
sh 'docker run --rm -v $(pwd):/data ${DOCKER_CI_TOOLS} chown -R $(id -u):$(id -g) /data'
|
sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
|
||||||
}
|
}
|
||||||
success {
|
success {
|
||||||
juxtapose event: 'success'
|
juxtapose event: 'success'
|
||||||
sh 'figlet "SUCCESS"'
|
sh 'figlet "SUCCESS"'
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
|
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
||||||
juxtapose event: 'failure'
|
juxtapose event: 'failure'
|
||||||
sh 'figlet "FAILURE"'
|
sh 'figlet "FAILURE"'
|
||||||
}
|
}
|
||||||
unstable {
|
unstable {
|
||||||
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
|
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
||||||
juxtapose event: 'unstable'
|
juxtapose event: 'unstable'
|
||||||
sh 'figlet "UNSTABLE"'
|
sh 'figlet "UNSTABLE"'
|
||||||
}
|
}
|
||||||
|
146
README.md
146
README.md
@ -1,16 +1,21 @@
|
|||||||

|
<p align="center">
|
||||||
|
<img src="https://nginxproxymanager.com/github.png">
|
||||||
# Nginx Proxy Manager
|
<br><br>
|
||||||
|
<img src="https://img.shields.io/badge/version-2.11.1-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">
|
||||||
[](https://ci.nginxproxymanager.jc21.com/job/nginx-proxy-manager/job/master/)
|
<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
|
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.
|
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
|
## Project Goal
|
||||||
|
|
||||||
@ -32,54 +37,6 @@ so that the barrier for entry here is low.
|
|||||||
- User management, permissions and audit log
|
- User management, permissions and audit log
|
||||||
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/login.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/dashboard.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/proxy-hosts-new2.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/redirection-hosts.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/redirection-hosts-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/streams.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/streams-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/dead-hosts.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/dead-hosts-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/certificates-new2.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/access-lists.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/access-lists-new1.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/users.jpg)
|
|
||||||
[](https://public.jc21.com/nginx-proxy-manager/v2/large/users-permissions.jpg)
|
|
||||||
[](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`
|
|
||||||
|
|
||||||
|
|
||||||
## 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
|
## 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.
|
I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
|
||||||
@ -89,13 +46,76 @@ I won't go in to too much detail here but here are the basics for someone new to
|
|||||||
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)
|
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
|
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
|
||||||
|
|
||||||
|
## Quick Setup
|
||||||
|
|
||||||
## Nginx Proxy Manager in the wild
|
1. Install Docker and Docker-Compose
|
||||||
|
|
||||||
As this software gains popularity it's common to see it integrated with other platforms. Please be aware that unless specifically mentioned in the documenation of those
|
- [Docker Install documentation](https://docs.docker.com/install/)
|
||||||
integrations, they are *not supported* by me and any donation links on the pages of those integrations will not come to me even though it looks like it.
|
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
|
||||||
|
|
||||||
Known integrations:
|
2. Create a docker-compose.yml file similar to this:
|
||||||
|
|
||||||
- [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager)
|
```yml
|
||||||
- [UnRaid / Synology](https://github.com/jlesage/docker-nginx-proxy-manager)
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: 'jc21/nginx-proxy-manager:latest'
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- '80:80'
|
||||||
|
- '81:81'
|
||||||
|
- '443:443'
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
|
||||||
|
|
||||||
|
3. Bring up your stack by running
|
||||||
|
|
||||||
|
```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.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
|
||||||
|
|
||||||
|
CI is used in this project. All PR's must pass before being considered. After passing,
|
||||||
|
docker builds for PR's are available on dockerhub for manual verifications.
|
||||||
|
|
||||||
|
Documentation within the `develop` branch is available for preview at
|
||||||
|
[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
|
||||||
|
|
||||||
|
|
||||||
|
### 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. [Reddit](https://reddit.com/r/nginxproxymanager)
|
||||||
|
2
backend/.gitignore
vendored
2
backend/.gitignore
vendored
@ -4,3 +4,5 @@ yarn-error.log
|
|||||||
tmp
|
tmp
|
||||||
certbot.log
|
certbot.log
|
||||||
node_modules
|
node_modules
|
||||||
|
core.*
|
||||||
|
|
||||||
|
8
backend/.vscode/settings.json
vendored
Normal file
8
backend/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ const express = require('express');
|
|||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const fileUpload = require('express-fileupload');
|
const fileUpload = require('express-fileupload');
|
||||||
const compression = require('compression');
|
const compression = require('compression');
|
||||||
|
const config = require('./lib/config');
|
||||||
const log = require('./logger').express;
|
const log = require('./logger').express;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,7 +25,7 @@ app.enable('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
|
|||||||
app.enable('strict routing');
|
app.enable('strict routing');
|
||||||
|
|
||||||
// pretty print JSON when not live
|
// pretty print JSON when not live
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (config.debug()) {
|
||||||
app.set('json spaces', 2);
|
app.set('json spaces', 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,13 +41,12 @@ app.use(function (req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.set({
|
res.set({
|
||||||
'Strict-Transport-Security': 'includeSubDomains; max-age=631138519; preload',
|
'X-XSS-Protection': '1; mode=block',
|
||||||
'X-XSS-Protection': '1; mode=block',
|
'X-Content-Type-Options': 'nosniff',
|
||||||
'X-Content-Type-Options': 'nosniff',
|
'X-Frame-Options': x_frame_options,
|
||||||
'X-Frame-Options': x_frame_options,
|
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
||||||
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
|
Pragma: 'no-cache',
|
||||||
Pragma: 'no-cache',
|
Expires: 0
|
||||||
Expires: 0
|
|
||||||
});
|
});
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -66,7 +66,7 @@ app.use(function (err, req, res, next) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (config.debug() || (req.baseUrl + req.path).includes('nginx/certificates')) {
|
||||||
payload.debug = {
|
payload.debug = {
|
||||||
stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null,
|
stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null,
|
||||||
previous: err.previous
|
previous: err.previous
|
||||||
@ -75,7 +75,7 @@ app.use(function (err, req, res, next) {
|
|||||||
|
|
||||||
// Not every error is worth logging - but this is good for now until it gets annoying.
|
// Not every error is worth logging - but this is good for now until it gets annoying.
|
||||||
if (typeof err.stack !== 'undefined' && err.stack) {
|
if (typeof err.stack !== 'undefined' && err.stack) {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (config.debug()) {
|
||||||
log.debug(err.stack);
|
log.debug(err.stack);
|
||||||
} else if (typeof err.public == 'undefined' || !err.public) {
|
} else if (typeof err.public == 'undefined' || !err.public) {
|
||||||
log.warn(err.message);
|
log.warn(err.message);
|
||||||
|
26
backend/config/sqlite-test-db.json
Normal file
26
backend/config/sqlite-test-db.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,27 @@
|
|||||||
const config = require('config');
|
const config = require('./lib/config');
|
||||||
|
|
||||||
if (!config.has('database')) {
|
if (!config.has('database')) {
|
||||||
throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md');
|
throw new Error('Database config does not exist! Please read the instructions: https://nginxproxymanager.com/setup/');
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = {
|
function generateDbConfig() {
|
||||||
client: config.database.engine,
|
const cfg = config.get('database');
|
||||||
connection: {
|
if (cfg.engine === 'knex-native') {
|
||||||
host: config.database.host,
|
return cfg.knex;
|
||||||
user: config.database.user,
|
|
||||||
password: config.database.password,
|
|
||||||
database: config.database.name,
|
|
||||||
port: config.database.port
|
|
||||||
},
|
|
||||||
migrations: {
|
|
||||||
tableName: 'migrations'
|
|
||||||
}
|
}
|
||||||
};
|
return {
|
||||||
|
client: cfg.engine,
|
||||||
if (typeof config.database.version !== 'undefined') {
|
connection: {
|
||||||
data.version = config.database.version;
|
host: cfg.host,
|
||||||
|
user: cfg.user,
|
||||||
|
password: cfg.password,
|
||||||
|
database: cfg.name,
|
||||||
|
port: cfg.port
|
||||||
|
},
|
||||||
|
migrations: {
|
||||||
|
tableName: 'migrations'
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = require('knex')(data);
|
module.exports = require('knex')(generateDbConfig());
|
||||||
|
@ -40,6 +40,210 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/nginx/proxy-hosts": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "getProxyHosts",
|
||||||
|
"summary": "Get all proxy hosts",
|
||||||
|
"tags": ["Proxy Hosts"],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": ["users"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "expand",
|
||||||
|
"description": "Expansions",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["access_list", "owner", "certificate"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "200 response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"created_on": "2023-03-30T01:12:23.000Z",
|
||||||
|
"modified_on": "2023-03-30T02:15:40.000Z",
|
||||||
|
"owner_user_id": 1,
|
||||||
|
"domain_names": ["aasdasdad"],
|
||||||
|
"forward_host": "asdasd",
|
||||||
|
"forward_port": 80,
|
||||||
|
"access_list_id": 0,
|
||||||
|
"certificate_id": 0,
|
||||||
|
"ssl_forced": 0,
|
||||||
|
"caching_enabled": 0,
|
||||||
|
"block_exploits": 0,
|
||||||
|
"advanced_config": "sdfsdfsdf",
|
||||||
|
"meta": {
|
||||||
|
"letsencrypt_agree": false,
|
||||||
|
"dns_challenge": false,
|
||||||
|
"nginx_online": false,
|
||||||
|
"nginx_err": "Command failed: /usr/sbin/nginx -t -g \"error_log off;\"\nnginx: [emerg] unknown directive \"sdfsdfsdf\" in /data/nginx/proxy_host/1.conf:37\nnginx: configuration file /etc/nginx/nginx.conf test failed\n"
|
||||||
|
},
|
||||||
|
"allow_websocket_upgrade": 0,
|
||||||
|
"http2_support": 0,
|
||||||
|
"forward_scheme": "http",
|
||||||
|
"enabled": 1,
|
||||||
|
"locations": [],
|
||||||
|
"hsts_enabled": 0,
|
||||||
|
"hsts_subdomains": 0,
|
||||||
|
"owner": {
|
||||||
|
"id": 1,
|
||||||
|
"created_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"modified_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"is_deleted": 0,
|
||||||
|
"is_disabled": 0,
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"name": "Administrator",
|
||||||
|
"nickname": "Admin",
|
||||||
|
"avatar": "",
|
||||||
|
"roles": ["admin"]
|
||||||
|
},
|
||||||
|
"access_list": null,
|
||||||
|
"certificate": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"created_on": "2023-03-30T02:11:49.000Z",
|
||||||
|
"modified_on": "2023-03-30T02:11:49.000Z",
|
||||||
|
"owner_user_id": 1,
|
||||||
|
"domain_names": ["test.example.com"],
|
||||||
|
"forward_host": "1.1.1.1",
|
||||||
|
"forward_port": 80,
|
||||||
|
"access_list_id": 0,
|
||||||
|
"certificate_id": 0,
|
||||||
|
"ssl_forced": 0,
|
||||||
|
"caching_enabled": 0,
|
||||||
|
"block_exploits": 0,
|
||||||
|
"advanced_config": "",
|
||||||
|
"meta": {
|
||||||
|
"letsencrypt_agree": false,
|
||||||
|
"dns_challenge": false,
|
||||||
|
"nginx_online": true,
|
||||||
|
"nginx_err": null
|
||||||
|
},
|
||||||
|
"allow_websocket_upgrade": 0,
|
||||||
|
"http2_support": 0,
|
||||||
|
"forward_scheme": "http",
|
||||||
|
"enabled": 1,
|
||||||
|
"locations": [],
|
||||||
|
"hsts_enabled": 0,
|
||||||
|
"hsts_subdomains": 0,
|
||||||
|
"owner": {
|
||||||
|
"id": 1,
|
||||||
|
"created_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"modified_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"is_deleted": 0,
|
||||||
|
"is_disabled": 0,
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"name": "Administrator",
|
||||||
|
"nickname": "Admin",
|
||||||
|
"avatar": "",
|
||||||
|
"roles": ["admin"]
|
||||||
|
},
|
||||||
|
"access_list": null,
|
||||||
|
"certificate": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProxyHostsList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"operationId": "createProxyHost",
|
||||||
|
"summary": "Create a Proxy Host",
|
||||||
|
"tags": ["Proxy Hosts"],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": ["users"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "proxyhost",
|
||||||
|
"description": "Proxy Host Payload",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProxyHostObject"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "201 response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"id": 3,
|
||||||
|
"created_on": "2023-03-30T02:31:27.000Z",
|
||||||
|
"modified_on": "2023-03-30T02:31:27.000Z",
|
||||||
|
"owner_user_id": 1,
|
||||||
|
"domain_names": ["test2.example.com"],
|
||||||
|
"forward_host": "1.1.1.1",
|
||||||
|
"forward_port": 80,
|
||||||
|
"access_list_id": 0,
|
||||||
|
"certificate_id": 0,
|
||||||
|
"ssl_forced": 0,
|
||||||
|
"caching_enabled": 0,
|
||||||
|
"block_exploits": 0,
|
||||||
|
"advanced_config": "",
|
||||||
|
"meta": {
|
||||||
|
"letsencrypt_agree": false,
|
||||||
|
"dns_challenge": false
|
||||||
|
},
|
||||||
|
"allow_websocket_upgrade": 0,
|
||||||
|
"http2_support": 0,
|
||||||
|
"forward_scheme": "http",
|
||||||
|
"enabled": 1,
|
||||||
|
"locations": [],
|
||||||
|
"hsts_enabled": 0,
|
||||||
|
"hsts_subdomains": 0,
|
||||||
|
"certificate": null,
|
||||||
|
"owner": {
|
||||||
|
"id": 1,
|
||||||
|
"created_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"modified_on": "2023-03-30T01:11:50.000Z",
|
||||||
|
"is_deleted": 0,
|
||||||
|
"is_disabled": 0,
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"name": "Administrator",
|
||||||
|
"nickname": "Admin",
|
||||||
|
"avatar": "",
|
||||||
|
"roles": ["admin"]
|
||||||
|
},
|
||||||
|
"access_list": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProxyHostObject"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/schema": {
|
"/schema": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "schema",
|
"operationId": "schema",
|
||||||
@ -55,14 +259,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "refreshToken",
|
"operationId": "refreshToken",
|
||||||
"summary": "Refresh your access token",
|
"summary": "Refresh your access token",
|
||||||
"tags": [
|
"tags": ["Tokens"],
|
||||||
"Tokens"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["tokens"]
|
||||||
"tokens"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -104,19 +304,14 @@
|
|||||||
"scope": {
|
"scope": {
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["user"]
|
||||||
"user"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"secret": {
|
"secret": {
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["identity", "secret"],
|
||||||
"identity",
|
|
||||||
"secret"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,23 +339,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"summary": "Request a new access token from credentials",
|
"summary": "Request a new access token from credentials",
|
||||||
"tags": [
|
"tags": ["Tokens"]
|
||||||
"Tokens"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/settings": {
|
"/settings": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getSettings",
|
"operationId": "getSettings",
|
||||||
"summary": "Get all settings",
|
"summary": "Get all settings",
|
||||||
"tags": [
|
"tags": ["Settings"],
|
||||||
"Settings"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["settings"]
|
||||||
"settings"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -194,14 +383,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "getSetting",
|
"operationId": "getSetting",
|
||||||
"summary": "Get a setting",
|
"summary": "Get a setting",
|
||||||
"tags": [
|
"tags": ["Settings"],
|
||||||
"Settings"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["settings"]
|
||||||
"settings"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -244,14 +429,10 @@
|
|||||||
"put": {
|
"put": {
|
||||||
"operationId": "updateSetting",
|
"operationId": "updateSetting",
|
||||||
"summary": "Update a setting",
|
"summary": "Update a setting",
|
||||||
"tags": [
|
"tags": ["Settings"],
|
||||||
"Settings"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["settings"]
|
||||||
"settings"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -305,14 +486,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "getUsers",
|
"operationId": "getUsers",
|
||||||
"summary": "Get all users",
|
"summary": "Get all users",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -322,9 +499,7 @@
|
|||||||
"description": "Expansions",
|
"description": "Expansions",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": ["permissions"]
|
||||||
"permissions"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -345,9 +520,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"]
|
||||||
"admin"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -362,9 +535,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"],
|
||||||
"admin"
|
|
||||||
],
|
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"visibility": "all",
|
"visibility": "all",
|
||||||
"proxy_hosts": "manage",
|
"proxy_hosts": "manage",
|
||||||
@ -389,14 +560,10 @@
|
|||||||
"post": {
|
"post": {
|
||||||
"operationId": "createUser",
|
"operationId": "createUser",
|
||||||
"summary": "Create a User",
|
"summary": "Create a User",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -426,9 +593,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"],
|
||||||
"admin"
|
|
||||||
],
|
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"visibility": "all",
|
"visibility": "all",
|
||||||
"proxy_hosts": "manage",
|
"proxy_hosts": "manage",
|
||||||
@ -454,14 +619,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "getUser",
|
"operationId": "getUser",
|
||||||
"summary": "Get a user",
|
"summary": "Get a user",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -501,9 +662,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"]
|
||||||
"admin"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -518,14 +677,10 @@
|
|||||||
"put": {
|
"put": {
|
||||||
"operationId": "updateUser",
|
"operationId": "updateUser",
|
||||||
"summary": "Update a User",
|
"summary": "Update a User",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -574,9 +729,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"]
|
||||||
"admin"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -591,14 +744,10 @@
|
|||||||
"delete": {
|
"delete": {
|
||||||
"operationId": "deleteUser",
|
"operationId": "deleteUser",
|
||||||
"summary": "Delete a User",
|
"summary": "Delete a User",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -637,14 +786,10 @@
|
|||||||
"put": {
|
"put": {
|
||||||
"operationId": "updateUserAuth",
|
"operationId": "updateUserAuth",
|
||||||
"summary": "Update a User's Authentication",
|
"summary": "Update a User's Authentication",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -700,14 +845,10 @@
|
|||||||
"put": {
|
"put": {
|
||||||
"operationId": "updateUserPermissions",
|
"operationId": "updateUserPermissions",
|
||||||
"summary": "Update a User's Permissions",
|
"summary": "Update a User's Permissions",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -755,14 +896,10 @@
|
|||||||
"put": {
|
"put": {
|
||||||
"operationId": "loginAsUser",
|
"operationId": "loginAsUser",
|
||||||
"summary": "Login as this user",
|
"summary": "Login as this user",
|
||||||
"tags": [
|
"tags": ["Users"],
|
||||||
"Users"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["users"]
|
||||||
"users"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
@ -797,9 +934,7 @@
|
|||||||
"name": "Jamie Curnow",
|
"name": "Jamie Curnow",
|
||||||
"nickname": "James",
|
"nickname": "James",
|
||||||
"avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
|
"avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
|
||||||
"roles": [
|
"roles": ["admin"]
|
||||||
"admin"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -807,11 +942,7 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Login object",
|
"description": "Login object",
|
||||||
"required": [
|
"required": ["expires", "token", "user"],
|
||||||
"expires",
|
|
||||||
"token",
|
|
||||||
"user"
|
|
||||||
],
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"expires": {
|
"expires": {
|
||||||
@ -840,14 +971,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "reportsHosts",
|
"operationId": "reportsHosts",
|
||||||
"summary": "Report on Host Statistics",
|
"summary": "Report on Host Statistics",
|
||||||
"tags": [
|
"tags": ["Reports"],
|
||||||
"Reports"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["reports"]
|
||||||
"reports"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -878,14 +1005,10 @@
|
|||||||
"get": {
|
"get": {
|
||||||
"operationId": "getAuditLog",
|
"operationId": "getAuditLog",
|
||||||
"summary": "Get Audit Log",
|
"summary": "Get Audit Log",
|
||||||
"tags": [
|
"tags": ["Audit Log"],
|
||||||
"Audit Log"
|
|
||||||
],
|
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BearerAuth": [
|
"BearerAuth": ["audit-log"]
|
||||||
"audit-log"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -925,10 +1048,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Health object",
|
"description": "Health object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": ["status", "version"],
|
||||||
"status",
|
|
||||||
"version"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -944,11 +1064,7 @@
|
|||||||
"revision": 0
|
"revision": 0
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": ["major", "minor", "revision"],
|
||||||
"major",
|
|
||||||
"minor",
|
|
||||||
"revision"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"major": {
|
"major": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@ -969,10 +1085,7 @@
|
|||||||
"TokenObject": {
|
"TokenObject": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Token object",
|
"description": "Token object",
|
||||||
"required": [
|
"required": ["expires", "token"],
|
||||||
"expires",
|
|
||||||
"token"
|
|
||||||
],
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"expires": {
|
"expires": {
|
||||||
@ -988,16 +1101,147 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ProxyHostObject": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Proxy Host object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"created_on",
|
||||||
|
"modified_on",
|
||||||
|
"owner_user_id",
|
||||||
|
"domain_names",
|
||||||
|
"forward_host",
|
||||||
|
"forward_port",
|
||||||
|
"access_list_id",
|
||||||
|
"certificate_id",
|
||||||
|
"ssl_forced",
|
||||||
|
"caching_enabled",
|
||||||
|
"block_exploits",
|
||||||
|
"advanced_config",
|
||||||
|
"meta",
|
||||||
|
"allow_websocket_upgrade",
|
||||||
|
"http2_support",
|
||||||
|
"forward_scheme",
|
||||||
|
"enabled",
|
||||||
|
"locations",
|
||||||
|
"hsts_enabled",
|
||||||
|
"hsts_subdomains",
|
||||||
|
"certificate",
|
||||||
|
"use_default_location",
|
||||||
|
"ipv6"
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Proxy Host ID",
|
||||||
|
"minimum": 1,
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"created_on": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Created Date",
|
||||||
|
"example": "2020-01-30T09:36:08.000Z"
|
||||||
|
},
|
||||||
|
"modified_on": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Modified Date",
|
||||||
|
"example": "2020-01-30T09:41:04.000Z"
|
||||||
|
},
|
||||||
|
"owner_user_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"example": 1
|
||||||
|
},
|
||||||
|
"domain_names": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"forward_host": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"forward_port": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"access_list_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"certificate_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ssl_forced": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"caching_enabled": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"block_exploits": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"advanced_config": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"allow_websocket_upgrade": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"http2_support": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"forward_scheme": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"locations": {
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"hsts_enabled": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hsts_subdomains": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"type": "object",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"type": "object",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"access_list": {
|
||||||
|
"type": "object",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"use_default_location": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"ipv6": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ProxyHostsList": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Proxyn Hosts list",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/ProxyHostObject"
|
||||||
|
}
|
||||||
|
},
|
||||||
"SettingObject": {
|
"SettingObject": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Setting object",
|
"description": "Setting object",
|
||||||
"required": [
|
"required": ["id", "name", "description", "value", "meta"],
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"description",
|
|
||||||
"value",
|
|
||||||
"meta"
|
|
||||||
],
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@ -1057,17 +1301,7 @@
|
|||||||
"UserObject": {
|
"UserObject": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "User object",
|
"description": "User object",
|
||||||
"required": [
|
"required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"],
|
||||||
"id",
|
|
||||||
"created_on",
|
|
||||||
"modified_on",
|
|
||||||
"is_disabled",
|
|
||||||
"email",
|
|
||||||
"name",
|
|
||||||
"nickname",
|
|
||||||
"avatar",
|
|
||||||
"roles"
|
|
||||||
],
|
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@ -1117,9 +1351,7 @@
|
|||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
"description": "Roles applied",
|
"description": "Roles applied",
|
||||||
"example": [
|
"example": ["admin"],
|
||||||
"admin"
|
|
||||||
],
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -1137,10 +1369,7 @@
|
|||||||
"AuthObject": {
|
"AuthObject": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Authentication Object",
|
"description": "Authentication Object",
|
||||||
"required": [
|
"required": ["type", "secret"],
|
||||||
"type",
|
|
||||||
"secret"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -1167,64 +1396,37 @@
|
|||||||
"visibility": {
|
"visibility": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Visibility Type",
|
"description": "Visibility Type",
|
||||||
"enum": [
|
"enum": ["all", "user"]
|
||||||
"all",
|
|
||||||
"user"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"access_lists": {
|
"access_lists": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Access Lists Permissions",
|
"description": "Access Lists Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"dead_hosts": {
|
"dead_hosts": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "404 Hosts Permissions",
|
"description": "404 Hosts Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"proxy_hosts": {
|
"proxy_hosts": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Proxy Hosts Permissions",
|
"description": "Proxy Hosts Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"redirection_hosts": {
|
"redirection_hosts": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Redirection Permissions",
|
"description": "Redirection Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"streams": {
|
"streams": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Streams Permissions",
|
"description": "Streams Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"certificates": {
|
"certificates": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Certificates Permissions",
|
"description": "Certificates Permissions",
|
||||||
"enum": [
|
"enum": ["hidden", "view", "manage"]
|
||||||
"hidden",
|
|
||||||
"view",
|
|
||||||
"manage"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1251,4 +1453,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const logger = require('./logger').global;
|
const logger = require('./logger').global;
|
||||||
|
|
||||||
function appStart () {
|
async function appStart () {
|
||||||
const migrate = require('./migrate');
|
const migrate = require('./migrate');
|
||||||
const setup = require('./setup');
|
const setup = require('./setup');
|
||||||
const app = require('./app');
|
const app = require('./app');
|
||||||
@ -45,3 +45,4 @@ try {
|
|||||||
logger.error(err.message, err);
|
logger.error(err.message, err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const batchflow = require('batchflow');
|
const batchflow = require('batchflow');
|
||||||
const logger = require('../logger').access;
|
const logger = require('../logger').access;
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
const accessListModel = require('../models/access_list');
|
const utils = require('../lib/utils');
|
||||||
const accessListAuthModel = require('../models/access_list_auth');
|
const accessListModel = require('../models/access_list');
|
||||||
const proxyHostModel = require('../models/proxy_host');
|
const accessListAuthModel = require('../models/access_list_auth');
|
||||||
const internalAuditLog = require('./audit-log');
|
const accessListClientModel = require('../models/access_list_client');
|
||||||
const internalNginx = require('./nginx');
|
const proxyHostModel = require('../models/proxy_host');
|
||||||
const utils = require('../lib/utils');
|
const internalAuditLog = require('./audit-log');
|
||||||
|
const internalNginx = require('./nginx');
|
||||||
|
|
||||||
function omissions () {
|
function omissions () {
|
||||||
return ['is_deleted'];
|
return ['is_deleted'];
|
||||||
@ -26,17 +27,20 @@ const internalAccessList = {
|
|||||||
.then((/*access_data*/) => {
|
.then((/*access_data*/) => {
|
||||||
return accessListModel
|
return accessListModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
|
||||||
.insertAndFetch({
|
.insertAndFetch({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
|
satisfy_any: data.satisfy_any,
|
||||||
|
pass_auth: data.pass_auth,
|
||||||
owner_user_id: access.token.getUserId(1)
|
owner_user_id: access.token.getUserId(1)
|
||||||
});
|
})
|
||||||
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
data.id = row.id;
|
data.id = row.id;
|
||||||
|
|
||||||
// Now add the items
|
|
||||||
let promises = [];
|
let promises = [];
|
||||||
|
|
||||||
|
// Now add the items
|
||||||
data.items.map((item) => {
|
data.items.map((item) => {
|
||||||
promises.push(accessListAuthModel
|
promises.push(accessListAuthModel
|
||||||
.query()
|
.query()
|
||||||
@ -48,13 +52,27 @@ const internalAccessList = {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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);
|
return Promise.all(promises);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// re-fetch with expansions
|
// re-fetch with expansions
|
||||||
return internalAccessList.get(access, {
|
return internalAccessList.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ['owner', 'items']
|
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
|
||||||
}, true /* <- skip masking */);
|
}, true /* <- skip masking */);
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
@ -64,7 +82,7 @@ const internalAccessList = {
|
|||||||
return internalAccessList.build(row)
|
return internalAccessList.build(row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (row.proxy_host_count) {
|
if (row.proxy_host_count) {
|
||||||
return internalNginx.reload();
|
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -100,7 +118,6 @@ const internalAccessList = {
|
|||||||
// Sanity check that something crazy hasn't happened
|
// Sanity check that something crazy hasn't happened
|
||||||
throw new error.InternalValidationError('Access List could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
throw new error.InternalValidationError('Access List could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// patch name if specified
|
// patch name if specified
|
||||||
@ -109,7 +126,9 @@ const internalAccessList = {
|
|||||||
.query()
|
.query()
|
||||||
.where({id: data.id})
|
.where({id: data.id})
|
||||||
.patch({
|
.patch({
|
||||||
name: data.name
|
name: data.name,
|
||||||
|
satisfy_any: data.satisfy_any,
|
||||||
|
pass_auth: data.pass_auth,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -153,6 +172,39 @@ const internalAccessList = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.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(() => {
|
.then(() => {
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
return internalAuditLog.add(access, {
|
return internalAuditLog.add(access, {
|
||||||
@ -166,14 +218,14 @@ const internalAccessList = {
|
|||||||
// re-fetch with expansions
|
// re-fetch with expansions
|
||||||
return internalAccessList.get(access, {
|
return internalAccessList.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ['owner', 'items']
|
expand: ['owner', 'items', 'clients', 'proxy_hosts.[certificate,access_list.[clients,items]]']
|
||||||
}, true /* <- skip masking */);
|
}, true /* <- skip masking */);
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
return internalAccessList.build(row)
|
return internalAccessList.build(row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (row.proxy_host_count) {
|
if (row.proxy_host_count) {
|
||||||
return internalNginx.reload();
|
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -204,35 +256,31 @@ const internalAccessList = {
|
|||||||
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
||||||
.where('access_list.is_deleted', 0)
|
.where('access_list.is_deleted', 0)
|
||||||
.andWhere('access_list.id', data.id)
|
.andWhere('access_list.id', data.id)
|
||||||
.allowEager('[owner,items,proxy_hosts]')
|
.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
|
||||||
.omit(['access_list.is_deleted'])
|
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
|
query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
|
|
||||||
row = internalAccessList.maskItems(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
|
||||||
|
row = internalAccessList.maskItems(row);
|
||||||
|
}
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -246,7 +294,7 @@ const internalAccessList = {
|
|||||||
delete: (access, data) => {
|
delete: (access, data) => {
|
||||||
return access.can('access_lists:delete', data.id)
|
return access.can('access_lists:delete', data.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items']});
|
return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
@ -329,12 +377,11 @@ const internalAccessList = {
|
|||||||
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
||||||
.where('access_list.is_deleted', 0)
|
.where('access_list.is_deleted', 0)
|
||||||
.groupBy('access_list.id')
|
.groupBy('access_list.id')
|
||||||
.omit(['access_list.is_deleted'])
|
.allowGraph('[owner,items,clients]')
|
||||||
.allowEager('[owner,items]')
|
|
||||||
.orderBy('access_list.name', 'ASC');
|
.orderBy('access_list.name', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
@ -345,10 +392,10 @@ const internalAccessList = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
})
|
})
|
||||||
.then((rows) => {
|
.then((rows) => {
|
||||||
if (rows) {
|
if (rows) {
|
||||||
@ -455,7 +502,7 @@ const internalAccessList = {
|
|||||||
if (typeof item.password !== 'undefined' && item.password.length) {
|
if (typeof item.password !== 'undefined' && item.password.length) {
|
||||||
logger.info('Adding: ' + item.username);
|
logger.info('Adding: ' + item.username);
|
||||||
|
|
||||||
utils.exec('/usr/bin/htpasswd -b "' + htpasswd_file + '" "' + item.username + '" "' + item.password + '"')
|
utils.execFile('/usr/bin/htpasswd', ['-b', htpasswd_file, item.username, item.password])
|
||||||
.then((/*result*/) => {
|
.then((/*result*/) => {
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
|
@ -19,7 +19,7 @@ const internalAuditLog = {
|
|||||||
.orderBy('created_on', 'DESC')
|
.orderBy('created_on', 'DESC')
|
||||||
.orderBy('id', 'DESC')
|
.orderBy('id', 'DESC')
|
||||||
.limit(100)
|
.limit(100)
|
||||||
.allowEager('[user]');
|
.allowGraph('[user]');
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string') {
|
||||||
@ -29,7 +29,7 @@ const internalAuditLog = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const deadHostModel = require('../models/dead_host');
|
const deadHostModel = require('../models/dead_host');
|
||||||
const internalHost = require('./host');
|
const internalHost = require('./host');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
@ -49,8 +50,8 @@ const internalDeadHost = {
|
|||||||
|
|
||||||
return deadHostModel
|
return deadHostModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
.insertAndFetch(data)
|
||||||
.insertAndFetch(data);
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (create_certificate) {
|
if (create_certificate) {
|
||||||
@ -218,31 +219,28 @@ const internalDeadHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowEager('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
row = internalHost.cleanRowCertificateMeta(row);
|
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -404,8 +402,7 @@ const internalDeadHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.omit(['is_deleted'])
|
.allowGraph('[owner,certificate]')
|
||||||
.allowEager('[owner,certificate]')
|
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy('domain_names', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@ -420,10 +417,10 @@ const internalDeadHost = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
})
|
})
|
||||||
.then((rows) => {
|
.then((rows) => {
|
||||||
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
||||||
|
@ -106,7 +106,7 @@ const internalHost = {
|
|||||||
response_object.total_count += response_object.redirection_hosts.length;
|
response_object.total_count += response_object.redirection_hosts.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promises_results[1]) {
|
if (promises_results[2]) {
|
||||||
// Dead Hosts
|
// Dead Hosts
|
||||||
response_object.dead_hosts = internalHost._getHostsWithDomains(promises_results[2], domain_names);
|
response_object.dead_hosts = internalHost._getHostsWithDomains(promises_results[2], domain_names);
|
||||||
response_object.total_count += response_object.dead_hosts.length;
|
response_object.total_count += response_object.dead_hosts.length;
|
||||||
@ -158,7 +158,7 @@ const internalHost = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promises_results[1]) {
|
if (promises_results[2]) {
|
||||||
// Dead Hosts
|
// Dead Hosts
|
||||||
if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[2], ignore_type === 'dead' && ignore_id ? ignore_id : 0)) {
|
if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[2], ignore_type === 'dead' && ignore_id ? ignore_id : 0)) {
|
||||||
is_taken = true;
|
is_taken = true;
|
||||||
|
@ -2,13 +2,16 @@ const https = require('https');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const logger = require('../logger').ip_ranges;
|
const logger = require('../logger').ip_ranges;
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const { Liquid } = require('liquidjs');
|
|
||||||
|
|
||||||
const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
|
const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
|
||||||
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
|
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
|
||||||
const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
|
const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
|
||||||
|
|
||||||
|
const regIpV4 = /^(\d+\.?){4}\/\d+/;
|
||||||
|
const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
|
||||||
|
|
||||||
const internalIpRanges = {
|
const internalIpRanges = {
|
||||||
|
|
||||||
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
|
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
|
||||||
@ -74,14 +77,14 @@ const internalIpRanges = {
|
|||||||
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
|
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
|
||||||
})
|
})
|
||||||
.then((cloudfare_data) => {
|
.then((cloudfare_data) => {
|
||||||
let items = cloudfare_data.split('\n');
|
let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
|
||||||
ip_ranges = [... ip_ranges, ... items];
|
ip_ranges = [... ip_ranges, ... items];
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
|
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
|
||||||
})
|
})
|
||||||
.then((cloudfare_data) => {
|
.then((cloudfare_data) => {
|
||||||
let items = cloudfare_data.split('\n');
|
let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
|
||||||
ip_ranges = [... ip_ranges, ... items];
|
ip_ranges = [... ip_ranges, ... items];
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -116,10 +119,7 @@ const internalIpRanges = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
generateConfig: (ip_ranges) => {
|
generateConfig: (ip_ranges) => {
|
||||||
let renderEngine = new Liquid({
|
const renderEngine = utils.getRenderEngine();
|
||||||
root: __dirname + '/../templates/'
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let template = null;
|
let template = null;
|
||||||
let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
|
let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const logger = require('../logger').nginx;
|
const logger = require('../logger').nginx;
|
||||||
const utils = require('../lib/utils');
|
const config = require('../lib/config');
|
||||||
const error = require('../lib/error');
|
const utils = require('../lib/utils');
|
||||||
const { Liquid } = require('liquidjs');
|
const error = require('../lib/error');
|
||||||
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
|
|
||||||
|
|
||||||
const internalNginx = {
|
const internalNginx = {
|
||||||
|
|
||||||
@ -29,7 +28,9 @@ const internalNginx = {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
// Nginx is OK
|
// Nginx is OK
|
||||||
// We're deleting this config regardless.
|
// We're deleting this config regardless.
|
||||||
return internalNginx.deleteConfig(host_type, host); // Don't throw errors, as the file may not exist at all
|
// Don't throw errors, as the file may not exist at all
|
||||||
|
// Delete the .err file too
|
||||||
|
return internalNginx.deleteConfig(host_type, host, false, true);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalNginx.generateConfig(host_type, host);
|
return internalNginx.generateConfig(host_type, host);
|
||||||
@ -64,7 +65,7 @@ const internalNginx = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.error('Nginx test failed:', valid_lines.join('\n'));
|
logger.error('Nginx test failed:', valid_lines.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +81,9 @@ const internalNginx = {
|
|||||||
.patch({
|
.patch({
|
||||||
meta: combined_meta
|
meta: combined_meta
|
||||||
})
|
})
|
||||||
|
.then(() => {
|
||||||
|
internalNginx.renameConfigAsError(host_type, host);
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalNginx.deleteConfig(host_type, host, true);
|
return internalNginx.deleteConfig(host_type, host, true);
|
||||||
});
|
});
|
||||||
@ -97,7 +101,7 @@ const internalNginx = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
test: () => {
|
test: () => {
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.info('Testing Nginx configuration');
|
logger.info('Testing Nginx configuration');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,13 +125,10 @@ const internalNginx = {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
getConfigName: (host_type, host_id) => {
|
getConfigName: (host_type, host_id) => {
|
||||||
host_type = host_type.replace(new RegExp('-', 'g'), '_');
|
|
||||||
|
|
||||||
if (host_type === 'default') {
|
if (host_type === 'default') {
|
||||||
return '/data/nginx/default_host/site.conf';
|
return '/data/nginx/default_host/site.conf';
|
||||||
}
|
}
|
||||||
|
return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf';
|
||||||
return '/data/nginx/' + host_type + '/' + host_id + '.conf';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,12 +147,16 @@ const internalNginx = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderer = new Liquid();
|
const renderEngine = utils.getRenderEngine();
|
||||||
let renderedLocations = '';
|
let renderedLocations = '';
|
||||||
|
|
||||||
const locationRendering = async () => {
|
const locationRendering = async () => {
|
||||||
for (let i = 0; i < host.locations.length; i++) {
|
for (let i = 0; i < host.locations.length; i++) {
|
||||||
let locationCopy = Object.assign({}, host.locations[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) {
|
if (locationCopy.forward_host.indexOf('/') > -1) {
|
||||||
const splitted = locationCopy.forward_host.split('/');
|
const splitted = locationCopy.forward_host.split('/');
|
||||||
@ -161,11 +166,13 @@ const internalNginx = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
renderedLocations += await renderer.parseAndRender(template, locationCopy);
|
renderedLocations += await renderEngine.parseAndRender(template, locationCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
locationRendering().then(() => resolve(renderedLocations));
|
locationRendering().then(() => resolve(renderedLocations));
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -175,22 +182,20 @@ const internalNginx = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
generateConfig: (host_type, host) => {
|
generateConfig: (host_type, host) => {
|
||||||
host_type = host_type.replace(new RegExp('-', 'g'), '_');
|
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
|
||||||
|
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.info('Generating ' + host_type + ' Config:', host);
|
logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderEngine = new Liquid({
|
const renderEngine = utils.getRenderEngine();
|
||||||
root: __dirname + '/../templates/'
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let template = null;
|
let template = null;
|
||||||
let filename = internalNginx.getConfigName(host_type, host.id);
|
let filename = internalNginx.getConfigName(nice_host_type, host.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'});
|
template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', {encoding: 'utf8'});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new error.ConfigurationError(err.message));
|
reject(new error.ConfigurationError(err.message));
|
||||||
return;
|
return;
|
||||||
@ -200,7 +205,7 @@ const internalNginx = {
|
|||||||
let origLocations;
|
let origLocations;
|
||||||
|
|
||||||
// Manipulate the data a bit before sending it to the template
|
// Manipulate the data a bit before sending it to the template
|
||||||
if (host_type !== 'default') {
|
if (nice_host_type !== 'default') {
|
||||||
host.use_default_location = true;
|
host.use_default_location = true;
|
||||||
if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
|
if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
|
||||||
host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
|
host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
|
||||||
@ -208,6 +213,7 @@ const internalNginx = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (host.locations) {
|
if (host.locations) {
|
||||||
|
//logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2));
|
||||||
origLocations = [].concat(host.locations);
|
origLocations = [].concat(host.locations);
|
||||||
locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => {
|
locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => {
|
||||||
host.locations = renderedLocations;
|
host.locations = renderedLocations;
|
||||||
@ -224,13 +230,16 @@ const internalNginx = {
|
|||||||
locationsPromise = Promise.resolve();
|
locationsPromise = Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the IPv6 setting for the host
|
||||||
|
host.ipv6 = internalNginx.ipv6Enabled();
|
||||||
|
|
||||||
locationsPromise.then(() => {
|
locationsPromise.then(() => {
|
||||||
renderEngine
|
renderEngine
|
||||||
.parseAndRender(template, host)
|
.parseAndRender(template, host)
|
||||||
.then((config_text) => {
|
.then((config_text) => {
|
||||||
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
|
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
|
||||||
|
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.success('Wrote config:', filename, config_text);
|
logger.success('Wrote config:', filename, config_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +249,7 @@ const internalNginx = {
|
|||||||
resolve(true);
|
resolve(true);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.warn('Could not write ' + filename + ':', err.message);
|
logger.warn('Could not write ' + filename + ':', err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,17 +268,16 @@ const internalNginx = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
generateLetsEncryptRequestConfig: (certificate) => {
|
generateLetsEncryptRequestConfig: (certificate) => {
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.info('Generating LetsEncrypt Request Config:', certificate);
|
logger.info('Generating LetsEncrypt Request Config:', certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderEngine = new Liquid({
|
const renderEngine = utils.getRenderEngine();
|
||||||
root: __dirname + '/../templates/'
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let template = null;
|
let template = null;
|
||||||
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
|
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -277,19 +285,21 @@ const internalNginx = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
certificate.ipv6 = internalNginx.ipv6Enabled();
|
||||||
|
|
||||||
renderEngine
|
renderEngine
|
||||||
.parseAndRender(template, certificate)
|
.parseAndRender(template, certificate)
|
||||||
.then((config_text) => {
|
.then((config_text) => {
|
||||||
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
|
fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
|
||||||
|
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.success('Wrote config:', filename, config_text);
|
logger.success('Wrote config:', filename, config_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (debug_mode) {
|
if (config.debug()) {
|
||||||
logger.warn('Could not write ' + filename + ':', err.message);
|
logger.warn('Could not write ' + filename + ':', err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,33 +308,39 @@ const internalNginx = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple wrapper around unlinkSync that writes to the logger
|
||||||
|
*
|
||||||
|
* @param {String} filename
|
||||||
|
*/
|
||||||
|
deleteFile: (filename) => {
|
||||||
|
logger.debug('Deleting file: ' + filename);
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(filename);
|
||||||
|
} catch (err) {
|
||||||
|
logger.debug('Could not delete file:', JSON.stringify(err, null, 2));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} host_type
|
||||||
|
* @returns String
|
||||||
|
*/
|
||||||
|
getFileFriendlyHostType: (host_type) => {
|
||||||
|
return host_type.replace(new RegExp('-', 'g'), '_');
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
|
* This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
|
||||||
*
|
*
|
||||||
* @param {Object} certificate
|
* @param {Object} certificate
|
||||||
* @param {Boolean} [throw_errors]
|
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
deleteLetsEncryptRequestConfig: (certificate, throw_errors) => {
|
deleteLetsEncryptRequestConfig: (certificate) => {
|
||||||
return new Promise((resolve, reject) => {
|
const config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
||||||
try {
|
return new Promise((resolve/*, reject*/) => {
|
||||||
let config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
internalNginx.deleteFile(config_file);
|
||||||
|
|
||||||
if (debug_mode) {
|
|
||||||
logger.warn('Deleting nginx config: ' + config_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.unlinkSync(config_file);
|
|
||||||
} catch (err) {
|
|
||||||
if (debug_mode) {
|
|
||||||
logger.warn('Could not delete config:', err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (throw_errors) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -332,35 +348,42 @@ const internalNginx = {
|
|||||||
/**
|
/**
|
||||||
* @param {String} host_type
|
* @param {String} host_type
|
||||||
* @param {Object} [host]
|
* @param {Object} [host]
|
||||||
* @param {Boolean} [throw_errors]
|
* @param {Boolean} [delete_err_file]
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
deleteConfig: (host_type, host, throw_errors) => {
|
deleteConfig: (host_type, host, delete_err_file) => {
|
||||||
host_type = host_type.replace(new RegExp('-', 'g'), '_');
|
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
|
||||||
|
const config_file_err = config_file + '.err';
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve/*, reject*/) => {
|
||||||
try {
|
internalNginx.deleteFile(config_file);
|
||||||
let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id);
|
if (delete_err_file) {
|
||||||
|
internalNginx.deleteFile(config_file_err);
|
||||||
if (debug_mode) {
|
|
||||||
logger.warn('Deleting nginx config: ' + config_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.unlinkSync(config_file);
|
|
||||||
} catch (err) {
|
|
||||||
if (debug_mode) {
|
|
||||||
logger.warn('Could not delete config:', err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (throw_errors) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} host_type
|
||||||
|
* @param {Object} [host]
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
renameConfigAsError: (host_type, host) => {
|
||||||
|
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
|
||||||
|
const config_file_err = config_file + '.err';
|
||||||
|
|
||||||
|
return new Promise((resolve/*, reject*/) => {
|
||||||
|
fs.unlink(config_file, () => {
|
||||||
|
// ignore result, continue
|
||||||
|
fs.rename(config_file, config_file_err, () => {
|
||||||
|
// also ignore result, as this is a debugging informative file anyway
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} host_type
|
* @param {String} host_type
|
||||||
* @param {Array} hosts
|
* @param {Array} hosts
|
||||||
@ -378,13 +401,12 @@ const internalNginx = {
|
|||||||
/**
|
/**
|
||||||
* @param {String} host_type
|
* @param {String} host_type
|
||||||
* @param {Array} hosts
|
* @param {Array} hosts
|
||||||
* @param {Boolean} [throw_errors]
|
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
bulkDeleteConfigs: (host_type, hosts, throw_errors) => {
|
bulkDeleteConfigs: (host_type, hosts) => {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
hosts.map(function (host) {
|
hosts.map(function (host) {
|
||||||
promises.push(internalNginx.deleteConfig(host_type, host, throw_errors));
|
promises.push(internalNginx.deleteConfig(host_type, host, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
@ -394,8 +416,20 @@ const internalNginx = {
|
|||||||
* @param {string} config
|
* @param {string} config
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
advancedConfigHasDefaultLocation: function (config) {
|
advancedConfigHasDefaultLocation: function (cfg) {
|
||||||
return !!config.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
|
return !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const proxyHostModel = require('../models/proxy_host');
|
const proxyHostModel = require('../models/proxy_host');
|
||||||
const internalHost = require('./host');
|
const internalHost = require('./host');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
@ -49,8 +50,8 @@ const internalProxyHost = {
|
|||||||
|
|
||||||
return proxyHostModel
|
return proxyHostModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
.insertAndFetch(data)
|
||||||
.insertAndFetch(data);
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (create_certificate) {
|
if (create_certificate) {
|
||||||
@ -73,7 +74,7 @@ const internalProxyHost = {
|
|||||||
// re-fetch with cert
|
// re-fetch with cert
|
||||||
return internalProxyHost.get(access, {
|
return internalProxyHost.get(access, {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
expand: ['certificate', 'owner', 'access_list']
|
expand: ['certificate', 'owner', 'access_list.[clients,items]']
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
@ -170,6 +171,7 @@ const internalProxyHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where({id: data.id})
|
.where({id: data.id})
|
||||||
.patch(data)
|
.patch(data)
|
||||||
|
.then(utils.omitRow(omissions()))
|
||||||
.then((saved_row) => {
|
.then((saved_row) => {
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
return internalAuditLog.add(access, {
|
return internalAuditLog.add(access, {
|
||||||
@ -179,16 +181,20 @@ const internalProxyHost = {
|
|||||||
meta: data
|
meta: data
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return _.omit(saved_row, omissions());
|
return saved_row;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalProxyHost.get(access, {
|
return internalProxyHost.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ['owner', 'certificate', 'access_list']
|
expand: ['owner', 'certificate', 'access_list.[clients,items]']
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
|
if (!row.enabled) {
|
||||||
|
// No need to add nginx config if host is disabled
|
||||||
|
return row;
|
||||||
|
}
|
||||||
// Configure nginx
|
// Configure nginx
|
||||||
return internalNginx.configure(proxyHostModel, 'proxy_host', row)
|
return internalNginx.configure(proxyHostModel, 'proxy_host', row)
|
||||||
.then((new_meta) => {
|
.then((new_meta) => {
|
||||||
@ -219,31 +225,29 @@ const internalProxyHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowEager('[owner,access_list,certificate]')
|
.allowGraph('[owner,access_list.[clients,items],certificate]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
row = internalHost.cleanRowCertificateMeta(row);
|
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
row = internalHost.cleanRowCertificateMeta(row);
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -405,8 +409,7 @@ const internalProxyHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.omit(['is_deleted'])
|
.allowGraph('[owner,access_list,certificate]')
|
||||||
.allowEager('[owner,access_list,certificate]')
|
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy('domain_names', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@ -421,10 +424,10 @@ const internalProxyHost = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
})
|
})
|
||||||
.then((rows) => {
|
.then((rows) => {
|
||||||
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const redirectionHostModel = require('../models/redirection_host');
|
const redirectionHostModel = require('../models/redirection_host');
|
||||||
const internalHost = require('./host');
|
const internalHost = require('./host');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
@ -49,8 +50,8 @@ const internalRedirectionHost = {
|
|||||||
|
|
||||||
return redirectionHostModel
|
return redirectionHostModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
.insertAndFetch(data)
|
||||||
.insertAndFetch(data);
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (create_certificate) {
|
if (create_certificate) {
|
||||||
@ -65,9 +66,8 @@ const internalRedirectionHost = {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
return row;
|
return row;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
|
return row;
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
// re-fetch with cert
|
// re-fetch with cert
|
||||||
@ -218,31 +218,29 @@ const internalRedirectionHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowEager('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
row = internalHost.cleanRowCertificateMeta(row);
|
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
row = internalHost.cleanRowCertificateMeta(row);
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -404,8 +402,7 @@ const internalRedirectionHost = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.omit(['is_deleted'])
|
.allowGraph('[owner,certificate]')
|
||||||
.allowEager('[owner,certificate]')
|
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy('domain_names', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@ -420,10 +417,10 @@ const internalRedirectionHost = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
})
|
})
|
||||||
.then((rows) => {
|
.then((rows) => {
|
||||||
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const streamModel = require('../models/stream');
|
const streamModel = require('../models/stream');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
@ -27,8 +28,8 @@ const internalStream = {
|
|||||||
|
|
||||||
return streamModel
|
return streamModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
.insertAndFetch(data)
|
||||||
.insertAndFetch(data);
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
// Configure nginx
|
// Configure nginx
|
||||||
@ -71,8 +72,8 @@ const internalStream = {
|
|||||||
|
|
||||||
return streamModel
|
return streamModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
|
||||||
.patchAndFetchById(row.id, data)
|
.patchAndFetchById(row.id, data)
|
||||||
|
.then(utils.omitRow(omissions()))
|
||||||
.then((saved_row) => {
|
.then((saved_row) => {
|
||||||
return internalNginx.configure(streamModel, 'stream', saved_row)
|
return internalNginx.configure(streamModel, 'stream', saved_row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -88,7 +89,7 @@ const internalStream = {
|
|||||||
meta: data
|
meta: data
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return _.omit(saved_row, omissions());
|
return saved_row;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -113,30 +114,28 @@ const internalStream = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowEager('[owner]')
|
.allowGraph('[owner]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -298,8 +297,7 @@ const internalStream = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.omit(['is_deleted'])
|
.allowGraph('[owner]')
|
||||||
.allowEager('[owner]')
|
|
||||||
.orderBy('incoming_port', 'ASC');
|
.orderBy('incoming_port', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@ -314,10 +312,10 @@ const internalStream = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ module.exports = {
|
|||||||
|
|
||||||
return userModel
|
return userModel
|
||||||
.query()
|
.query()
|
||||||
.where('email', data.identity)
|
.where('email', data.identity.toLowerCase().trim())
|
||||||
.andWhere('is_deleted', 0)
|
.andWhere('is_deleted', 0)
|
||||||
.andWhere('is_disabled', 0)
|
.andWhere('is_disabled', 0)
|
||||||
.first()
|
.first()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const utils = require('../lib/utils');
|
||||||
const userModel = require('../models/user');
|
const userModel = require('../models/user');
|
||||||
const userPermissionModel = require('../models/user_permission');
|
const userPermissionModel = require('../models/user_permission');
|
||||||
const authModel = require('../models/auth');
|
const authModel = require('../models/auth');
|
||||||
@ -35,8 +36,8 @@ const internalUser = {
|
|||||||
|
|
||||||
return userModel
|
return userModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
.insertAndFetch(data)
|
||||||
.insertAndFetch(data);
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((user) => {
|
.then((user) => {
|
||||||
if (auth) {
|
if (auth) {
|
||||||
@ -140,11 +141,8 @@ const internalUser = {
|
|||||||
|
|
||||||
return userModel
|
return userModel
|
||||||
.query()
|
.query()
|
||||||
.omit(omissions())
|
|
||||||
.patchAndFetchById(user.id, data)
|
.patchAndFetchById(user.id, data)
|
||||||
.then((saved_user) => {
|
.then(utils.omitRow(omissions()));
|
||||||
return _.omit(saved_user, omissions());
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalUser.get(access, {id: data.id});
|
return internalUser.get(access, {id: data.id});
|
||||||
@ -186,26 +184,24 @@ const internalUser = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowEager('[permissions]')
|
.allowGraph('[permissions]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
// Custom omissions
|
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
|
||||||
query.omit(data.omit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||||
query.eager('[' + data.expand.join(', ') + ']');
|
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row) {
|
if (!row) {
|
||||||
return _.omit(row, omissions());
|
|
||||||
} else {
|
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
// Custom omissions
|
||||||
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
|
row = _.omit(row, data.omit);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -322,8 +318,7 @@ const internalUser = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.omit(['is_deleted'])
|
.allowGraph('[permissions]')
|
||||||
.allowEager('[permissions]')
|
|
||||||
.orderBy('name', 'ASC');
|
.orderBy('name', 'ASC');
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
@ -335,10 +330,10 @@ const internalUser = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof expand !== 'undefined' && expand !== null) {
|
if (typeof expand !== 'undefined' && expand !== null) {
|
||||||
query.eager('[' + expand.join(', ') + ']');
|
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query.then(utils.omitRows(omissions()));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ module.exports = function (token_string) {
|
|||||||
.where('id', token_data.attrs.id)
|
.where('id', token_data.attrs.id)
|
||||||
.andWhere('is_deleted', 0)
|
.andWhere('is_deleted', 0)
|
||||||
.andWhere('is_disabled', 0)
|
.andWhere('is_disabled', 0)
|
||||||
.allowEager('[permissions]')
|
.allowGraph('[permissions]')
|
||||||
.eager('[permissions]')
|
.withGraphFetched('[permissions]')
|
||||||
.first()
|
.first()
|
||||||
.then((user) => {
|
.then((user) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
78
backend/lib/certbot.js
Normal file
78
backend/lib/certbot.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
const dnsPlugins = require('../global/certbot-dns-plugins.json');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const error = require('./error');
|
||||||
|
const logger = require('../logger').certbot;
|
||||||
|
const batchflow = require('batchflow');
|
||||||
|
|
||||||
|
const CERTBOT_VERSION_REPLACEMENT = '$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')';
|
||||||
|
|
||||||
|
const certbot = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {array} pluginKeys
|
||||||
|
*/
|
||||||
|
installPlugins: async function (pluginKeys) {
|
||||||
|
let hasErrors = false;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (pluginKeys.length === 0) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
batchflow(pluginKeys).sequential()
|
||||||
|
.each((i, pluginKey, next) => {
|
||||||
|
certbot.installPlugin(pluginKey)
|
||||||
|
.then(() => {
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
hasErrors = true;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.error((err) => {
|
||||||
|
logger.error(err.message);
|
||||||
|
})
|
||||||
|
.end(() => {
|
||||||
|
if (hasErrors) {
|
||||||
|
reject(new error.CommandError('Some plugins failed to install. Please check the logs above', 1));
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs a cerbot plugin given the key for the object from
|
||||||
|
* ../global/certbot-dns-plugins.json
|
||||||
|
*
|
||||||
|
* @param {string} pluginKey
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
installPlugin: async function (pluginKey) {
|
||||||
|
if (typeof dnsPlugins[pluginKey] === 'undefined') {
|
||||||
|
// throw Error(`Certbot plugin ${pluginKey} not found`);
|
||||||
|
throw new error.ItemNotFoundError(pluginKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const plugin = dnsPlugins[pluginKey];
|
||||||
|
logger.start(`Installing ${pluginKey}...`);
|
||||||
|
|
||||||
|
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||||
|
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||||
|
|
||||||
|
const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate';
|
||||||
|
return utils.exec(cmd)
|
||||||
|
.then((result) => {
|
||||||
|
logger.complete(`Installed ${pluginKey}`);
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = certbot;
|
184
backend/lib/config.js
Normal file
184
backend/lib/config.js
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const NodeRSA = require('node-rsa');
|
||||||
|
const logger = require('../logger').global;
|
||||||
|
|
||||||
|
const keysFile = '/data/keys.json';
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
// 1. Load from config file first (not recommended anymore)
|
||||||
|
// 2. Use config env variables next
|
||||||
|
const configure = () => {
|
||||||
|
const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
|
||||||
|
if (fs.existsSync(filename)) {
|
||||||
|
let configData;
|
||||||
|
try {
|
||||||
|
configData = require(filename);
|
||||||
|
} catch (err) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configData && configData.database) {
|
||||||
|
logger.info(`Using configuration from file: ${filename}`);
|
||||||
|
instance = configData;
|
||||||
|
instance.keys = getKeys();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const envMysqlHost = process.env.DB_MYSQL_HOST || null;
|
||||||
|
const envMysqlUser = process.env.DB_MYSQL_USER || null;
|
||||||
|
const envMysqlName = process.env.DB_MYSQL_NAME || null;
|
||||||
|
if (envMysqlHost && envMysqlUser && envMysqlName) {
|
||||||
|
// we have enough mysql creds to go with mysql
|
||||||
|
logger.info('Using MySQL configuration');
|
||||||
|
instance = {
|
||||||
|
database: {
|
||||||
|
engine: 'mysql',
|
||||||
|
host: envMysqlHost,
|
||||||
|
port: process.env.DB_MYSQL_PORT || 3306,
|
||||||
|
user: envMysqlUser,
|
||||||
|
password: process.env.DB_MYSQL_PASSWORD,
|
||||||
|
name: envMysqlName,
|
||||||
|
},
|
||||||
|
keys: getKeys(),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
|
||||||
|
logger.info(`Using Sqlite: ${envSqliteFile}`);
|
||||||
|
instance = {
|
||||||
|
database: {
|
||||||
|
engine: 'knex-native',
|
||||||
|
knex: {
|
||||||
|
client: 'sqlite3',
|
||||||
|
connection: {
|
||||||
|
filename: envSqliteFile
|
||||||
|
},
|
||||||
|
useNullAsDefault: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keys: getKeys(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getKeys = () => {
|
||||||
|
// Get keys from file
|
||||||
|
if (!fs.existsSync(keysFile)) {
|
||||||
|
generateKeys();
|
||||||
|
} else if (process.env.DEBUG) {
|
||||||
|
logger.info('Keys file exists OK');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return require(keysFile);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('Could not read JWT key pair from config file: ' + keysFile, err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateKeys = () => {
|
||||||
|
logger.info('Creating a new JWT key pair...');
|
||||||
|
// Now create the keys and save them in the config.
|
||||||
|
const key = new NodeRSA({ b: 2048 });
|
||||||
|
key.generateKeyPair();
|
||||||
|
|
||||||
|
const keys = {
|
||||||
|
key: key.exportKey('private').toString(),
|
||||||
|
pub: key.exportKey('public').toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write keys config
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
logger.info('Wrote JWT key pair to config file: ' + keysFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} key ie: 'database' or 'database.engine'
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
has: function(key) {
|
||||||
|
instance === null && configure();
|
||||||
|
const keys = key.split('.');
|
||||||
|
let level = instance;
|
||||||
|
let has = true;
|
||||||
|
keys.forEach((keyItem) =>{
|
||||||
|
if (typeof level[keyItem] === 'undefined') {
|
||||||
|
has = false;
|
||||||
|
} else {
|
||||||
|
level = level[keyItem];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return has;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a specific key from the top level
|
||||||
|
*
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
get: function (key) {
|
||||||
|
instance === null && configure();
|
||||||
|
if (key && typeof instance[key] !== 'undefined') {
|
||||||
|
return instance[key];
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a sqlite configuration?
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isSqlite: function () {
|
||||||
|
instance === null && configure();
|
||||||
|
return instance.database.knex && instance.database.knex.client === 'sqlite3';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are we running in debug mdoe?
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
debug: function () {
|
||||||
|
return !!process.env.DEBUG;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a public key
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getPublicKey: function () {
|
||||||
|
instance === null && configure();
|
||||||
|
return instance.keys.pub;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a private key
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getPrivateKey: function () {
|
||||||
|
instance === null && configure();
|
||||||
|
return instance.keys.key;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
useLetsencryptStaging: function () {
|
||||||
|
return !!process.env.LE_STAGING;
|
||||||
|
}
|
||||||
|
};
|
@ -82,7 +82,16 @@ module.exports = {
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
this.public = false;
|
this.public = false;
|
||||||
this.status = 400;
|
this.status = 400;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
CommandError: function (stdErr, code, previous) {
|
||||||
|
Error.captureStackTrace(this, this.constructor);
|
||||||
|
this.name = this.constructor.name;
|
||||||
|
this.previous = previous;
|
||||||
|
this.message = stdErr;
|
||||||
|
this.code = code;
|
||||||
|
this.public = false;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
_.forEach(module.exports, function (error) {
|
_.forEach(module.exports, function (error) {
|
||||||
|
@ -4,11 +4,21 @@ module.exports = function (req, res, next) {
|
|||||||
|
|
||||||
if (req.headers.origin) {
|
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....
|
// very relaxed validation....
|
||||||
validator({
|
validator(originSchema, req.headers.origin)
|
||||||
type: 'string',
|
|
||||||
pattern: '^[a-z\\-]+:\\/\\/(?:[\\w\\-\\.]+(:[0-9]+)?/?)?$'
|
|
||||||
}, req.headers.origin)
|
|
||||||
.then(function () {
|
.then(function () {
|
||||||
res.set({
|
res.set({
|
||||||
'Access-Control-Allow-Origin': req.headers.origin,
|
'Access-Control-Allow-Origin': req.headers.origin,
|
||||||
|
@ -1,14 +1,41 @@
|
|||||||
const exec = require('child_process').exec;
|
const _ = require('lodash');
|
||||||
|
const exec = require('child_process').exec;
|
||||||
|
const execFile = require('child_process').execFile;
|
||||||
|
const { Liquid } = require('liquidjs');
|
||||||
|
const logger = require('../logger').global;
|
||||||
|
const error = require('./error');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
exec: async function(cmd, options = {}) {
|
||||||
|
logger.debug('CMD:', cmd);
|
||||||
|
|
||||||
|
const { stdout, stderr } = await new Promise((resolve, reject) => {
|
||||||
|
const child = exec(cmd, options, (isError, stdout, stderr) => {
|
||||||
|
if (isError) {
|
||||||
|
reject(new error.CommandError(stderr, isError));
|
||||||
|
} else {
|
||||||
|
resolve({ stdout, stderr });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('error', (e) => {
|
||||||
|
reject(new error.CommandError(stderr, 1, e));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return stdout;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} cmd
|
* @param {String} cmd
|
||||||
|
* @param {Array} args
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
exec: function (cmd) {
|
execFile: function (cmd, args) {
|
||||||
|
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(cmd, function (err, stdout, /*stderr*/) {
|
execFile(cmd, args, function (err, stdout, /*stderr*/) {
|
||||||
if (err && typeof err === 'object') {
|
if (err && typeof err === 'object') {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
@ -16,5 +43,64 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in objection query builder
|
||||||
|
*
|
||||||
|
* @param {Array} omissions
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
omitRow: function (omissions) {
|
||||||
|
/**
|
||||||
|
* @param {Object} row
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
return (row) => {
|
||||||
|
return _.omit(row, omissions);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in objection query builder
|
||||||
|
*
|
||||||
|
* @param {Array} omissions
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
omitRows: function (omissions) {
|
||||||
|
/**
|
||||||
|
* @param {Array} rows
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
return (rows) => {
|
||||||
|
rows.forEach((row, idx) => {
|
||||||
|
rows[idx] = _.omit(row, omissions);
|
||||||
|
});
|
||||||
|
return rows;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Object} Liquid render engine
|
||||||
|
*/
|
||||||
|
getRenderEngine: function () {
|
||||||
|
const renderEngine = new Liquid({
|
||||||
|
root: __dirname + '/../templates/'
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nginxAccessRule expects the object given to have 2 properties:
|
||||||
|
*
|
||||||
|
* directive string
|
||||||
|
* address string
|
||||||
|
*/
|
||||||
|
renderEngine.registerFilter('nginxAccessRule', (v) => {
|
||||||
|
if (typeof v.directive !== 'undefined' && typeof v.address !== 'undefined' && v.directive && v.address) {
|
||||||
|
return `${v.directive} ${v.address};`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderEngine;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ const definitions = require('../../schema/definitions.json');
|
|||||||
RegExp.prototype.toJSON = RegExp.prototype.toString;
|
RegExp.prototype.toJSON = RegExp.prototype.toString;
|
||||||
|
|
||||||
const ajv = require('ajv')({
|
const ajv = require('ajv')({
|
||||||
verbose: true, //process.env.NODE_ENV === 'development',
|
verbose: true,
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
format: 'full', // strict regexes for format checks
|
format: 'full', // strict regexes for format checks
|
||||||
coerceTypes: true,
|
coerceTypes: true,
|
||||||
|
@ -7,6 +7,7 @@ module.exports = {
|
|||||||
access: new Signale({scope: 'Access '}),
|
access: new Signale({scope: 'Access '}),
|
||||||
nginx: new Signale({scope: 'Nginx '}),
|
nginx: new Signale({scope: 'Nginx '}),
|
||||||
ssl: new Signale({scope: 'SSL '}),
|
ssl: new Signale({scope: 'SSL '}),
|
||||||
|
certbot: new Signale({scope: 'Certbot '}),
|
||||||
import: new Signale({scope: 'Importer '}),
|
import: new Signale({scope: 'Importer '}),
|
||||||
setup: new Signale({scope: 'Setup '}),
|
setup: new Signale({scope: 'Setup '}),
|
||||||
ip_ranges: new Signale({scope: 'IP Ranges'})
|
ip_ranges: new Signale({scope: 'IP Ranges'})
|
||||||
|
@ -22,22 +22,6 @@ exports.up = function (knex/*, Promise*/) {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info('[' + migrate_name + '] setting Table created');
|
logger.info('[' + migrate_name + '] setting Table created');
|
||||||
|
|
||||||
// TODO: add settings
|
|
||||||
let settingModel = require('../models/setting');
|
|
||||||
|
|
||||||
return settingModel
|
|
||||||
.query()
|
|
||||||
.insert({
|
|
||||||
id: 'default-site',
|
|
||||||
name: 'Default Site',
|
|
||||||
description: 'What to show when Nginx is hit with an unknown Host',
|
|
||||||
value: 'congratulations',
|
|
||||||
meta: {}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
logger.info('[' + migrate_name + '] Default settings added');
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
53
backend/migrations/20200410143839_access_list_client.js
Normal file
53
backend/migrations/20200410143839_access_list_client.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const migrate_name = 'access_list_client';
|
||||||
|
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('access_list_client', (table) => {
|
||||||
|
table.increments().primary();
|
||||||
|
table.dateTime('created_on').notNull();
|
||||||
|
table.dateTime('modified_on').notNull();
|
||||||
|
table.integer('access_list_id').notNull().unsigned();
|
||||||
|
table.string('address').notNull();
|
||||||
|
table.string('directive').notNull();
|
||||||
|
table.json('meta').notNull();
|
||||||
|
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] access_list_client Table created');
|
||||||
|
|
||||||
|
return knex.schema.table('access_list', function (access_list) {
|
||||||
|
access_list.integer('satify_any').notNull().defaultTo(0);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] access_list Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex/*, Promise*/) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.dropTable('access_list_client')
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] access_list_client Table dropped');
|
||||||
|
});
|
||||||
|
};
|
34
backend/migrations/20200410143840_access_list_client_fix.js
Normal file
34
backend/migrations/20200410143840_access_list_client_fix.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const migrate_name = 'access_list_client_fix';
|
||||||
|
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('access_list', function (access_list) {
|
||||||
|
access_list.renameColumn('satify_any', 'satisfy_any');
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] access_list 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);
|
||||||
|
};
|
41
backend/migrations/20201014143841_pass_auth.js
Normal file
41
backend/migrations/20201014143841_pass_auth.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const migrate_name = 'pass_auth';
|
||||||
|
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('access_list', function (access_list) {
|
||||||
|
access_list.integer('pass_auth').notNull().defaultTo(1);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] access_list Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex/*, Promise*/) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.table('access_list', function (access_list) {
|
||||||
|
access_list.dropColumn('pass_auth');
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] access_list pass_auth Column dropped');
|
||||||
|
});
|
||||||
|
};
|
41
backend/migrations/20210210154702_redirection_scheme.js
Normal file
41
backend/migrations/20210210154702_redirection_scheme.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const migrate_name = 'redirection_scheme';
|
||||||
|
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('redirection_host', (table) => {
|
||||||
|
table.string('forward_scheme').notNull().defaultTo('$scheme');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] redirection_host Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex/*, Promise*/) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.table('redirection_host', (table) => {
|
||||||
|
table.dropColumn('forward_scheme');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] redirection_host Table altered');
|
||||||
|
});
|
||||||
|
};
|
41
backend/migrations/20210210154703_redirection_status_code.js
Normal file
41
backend/migrations/20210210154703_redirection_status_code.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const migrate_name = 'redirection_status_code';
|
||||||
|
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('redirection_host', (table) => {
|
||||||
|
table.integer('forward_http_code').notNull().unsigned().defaultTo(302);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] redirection_host Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex/*, Promise*/) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.table('redirection_host', (table) => {
|
||||||
|
table.dropColumn('forward_http_code');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] redirection_host Table altered');
|
||||||
|
});
|
||||||
|
};
|
40
backend/migrations/20210423103500_stream_domain.js
Normal file
40
backend/migrations/20210423103500_stream_domain.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const migrate_name = 'stream_domain';
|
||||||
|
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('stream', (table) => {
|
||||||
|
table.renameColumn('forward_ip', 'forwarding_host');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] stream Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex/*, Promise*/) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.table('stream', (table) => {
|
||||||
|
table.renameColumn('forwarding_host', 'forward_ip');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] stream Table altered');
|
||||||
|
});
|
||||||
|
};
|
50
backend/migrations/20211108145214_regenerate_default_host.js
Normal file
50
backend/migrations/20211108145214_regenerate_default_host.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const migrate_name = 'stream_domain';
|
||||||
|
const logger = require('../logger').migrate;
|
||||||
|
const internalNginx = require('../internal/nginx');
|
||||||
|
|
||||||
|
async function regenerateDefaultHost(knex) {
|
||||||
|
const row = await knex('setting').select('*').where('id', 'default-site').first();
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalNginx.deleteConfig('default')
|
||||||
|
.then(() => {
|
||||||
|
return internalNginx.generateConfig('default', row);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return internalNginx.test();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return internalNginx.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate
|
||||||
|
*
|
||||||
|
* @see http://knexjs.org/#Schema
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.up = function (knex) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Up...');
|
||||||
|
|
||||||
|
return regenerateDefaultHost(knex);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @param {Promise} Promise
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return regenerateDefaultHost(knex);
|
||||||
|
};
|
@ -1,17 +1,19 @@
|
|||||||
// Objection Docs:
|
// Objection Docs:
|
||||||
// http://vincit.github.io/objection.js/
|
// http://vincit.github.io/objection.js/
|
||||||
|
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
const AccessListAuth = require('./access_list_auth');
|
const AccessListAuth = require('./access_list_auth');
|
||||||
|
const AccessListClient = require('./access_list_client');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class AccessList extends Model {
|
class AccessList extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
@ -20,7 +22,7 @@ class AccessList extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -48,7 +50,6 @@ class AccessList extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
items: {
|
items: {
|
||||||
@ -57,9 +58,14 @@ class AccessList extends Model {
|
|||||||
join: {
|
join: {
|
||||||
from: 'access_list.id',
|
from: 'access_list.id',
|
||||||
to: 'access_list_auth.access_list_id'
|
to: 'access_list_auth.access_list_id'
|
||||||
},
|
}
|
||||||
modify: function (qb) {
|
},
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']);
|
clients: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: AccessListClient,
|
||||||
|
join: {
|
||||||
|
from: 'access_list.id',
|
||||||
|
to: 'access_list_client.access_list_id'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
proxy_hosts: {
|
proxy_hosts: {
|
||||||
@ -71,7 +77,6 @@ class AccessList extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('proxy_host.is_deleted', 0);
|
qb.where('proxy_host.is_deleted', 0);
|
||||||
qb.omit(['is_deleted', 'meta']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class AccessListAuth extends Model {
|
class AccessListAuth extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
@ -18,7 +19,7 @@ class AccessListAuth extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -44,7 +45,6 @@ class AccessListAuth extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('access_list.is_deleted', 0);
|
qb.where('access_list.is_deleted', 0);
|
||||||
qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
54
backend/models/access_list_client.js
Normal file
54
backend/models/access_list_client.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Objection Docs:
|
||||||
|
// http://vincit.github.io/objection.js/
|
||||||
|
|
||||||
|
const db = require('../db');
|
||||||
|
const Model = require('objection').Model;
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
|
Model.knex(db);
|
||||||
|
|
||||||
|
class AccessListClient extends Model {
|
||||||
|
$beforeInsert () {
|
||||||
|
this.created_on = now();
|
||||||
|
this.modified_on = now();
|
||||||
|
|
||||||
|
// Default for meta
|
||||||
|
if (typeof this.meta === 'undefined') {
|
||||||
|
this.meta = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate () {
|
||||||
|
this.modified_on = now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get name () {
|
||||||
|
return 'AccessListClient';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get tableName () {
|
||||||
|
return 'access_list_client';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get jsonAttributes () {
|
||||||
|
return ['meta'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings () {
|
||||||
|
return {
|
||||||
|
access_list: {
|
||||||
|
relation: Model.HasOneRelation,
|
||||||
|
modelClass: require('./access_list'),
|
||||||
|
join: {
|
||||||
|
from: 'access_list_client.access_list_id',
|
||||||
|
to: 'access_list.id'
|
||||||
|
},
|
||||||
|
modify: function (qb) {
|
||||||
|
qb.where('access_list.is_deleted', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AccessListClient;
|
@ -4,13 +4,14 @@
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class AuditLog extends Model {
|
class AuditLog extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
@ -19,7 +20,7 @@ class AuditLog extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -42,9 +43,6 @@ class AuditLog extends Model {
|
|||||||
join: {
|
join: {
|
||||||
from: 'audit_log.user_id',
|
from: 'audit_log.user_id',
|
||||||
to: 'user.id'
|
to: 'user.id'
|
||||||
},
|
|
||||||
modify: function (qb) {
|
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'roles']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@ const bcrypt = require('bcrypt');
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
@ -24,8 +25,8 @@ function encryptPassword () {
|
|||||||
|
|
||||||
class Auth extends Model {
|
class Auth extends Model {
|
||||||
$beforeInsert (queryContext) {
|
$beforeInsert (queryContext) {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
@ -36,7 +37,7 @@ class Auth extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate (queryContext) {
|
$beforeUpdate (queryContext) {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
return encryptPassword.apply(this, queryContext);
|
return encryptPassword.apply(this, queryContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +74,6 @@ class Auth extends Model {
|
|||||||
},
|
},
|
||||||
filter: {
|
filter: {
|
||||||
is_deleted: 0
|
is_deleted: 0
|
||||||
},
|
|
||||||
modify: function (qb) {
|
|
||||||
qb.omit(['is_deleted']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,17 +4,18 @@
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class Certificate extends Model {
|
class Certificate extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for expires_on
|
// Default for expires_on
|
||||||
if (typeof this.expires_on === 'undefined') {
|
if (typeof this.expires_on === 'undefined') {
|
||||||
this.expires_on = Model.raw('NOW()');
|
this.expires_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default for domain_names
|
// Default for domain_names
|
||||||
@ -31,7 +32,7 @@ class Certificate extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Sort domain_names
|
// Sort domain_names
|
||||||
if (typeof this.domain_names !== 'undefined') {
|
if (typeof this.domain_names !== 'undefined') {
|
||||||
@ -62,7 +63,6 @@ class Certificate extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5,13 +5,14 @@ const db = require('../db');
|
|||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
const Certificate = require('./certificate');
|
const Certificate = require('./certificate');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class DeadHost extends Model {
|
class DeadHost extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for domain_names
|
// Default for domain_names
|
||||||
if (typeof this.domain_names === 'undefined') {
|
if (typeof this.domain_names === 'undefined') {
|
||||||
@ -27,7 +28,7 @@ class DeadHost extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Sort domain_names
|
// Sort domain_names
|
||||||
if (typeof this.domain_names !== 'undefined') {
|
if (typeof this.domain_names !== 'undefined') {
|
||||||
@ -58,7 +59,6 @@ class DeadHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
certificate: {
|
certificate: {
|
||||||
@ -70,7 +70,6 @@ class DeadHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('certificate.is_deleted', 0);
|
qb.where('certificate.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
13
backend/models/now_helper.js
Normal file
13
backend/models/now_helper.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const db = require('../db');
|
||||||
|
const config = require('../lib/config');
|
||||||
|
const Model = require('objection').Model;
|
||||||
|
|
||||||
|
Model.knex(db);
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
if (config.isSqlite()) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
return Model.raw("datetime('now','localtime')");
|
||||||
|
}
|
||||||
|
return Model.raw('NOW()');
|
||||||
|
};
|
@ -6,13 +6,14 @@ const Model = require('objection').Model;
|
|||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
const AccessList = require('./access_list');
|
const AccessList = require('./access_list');
|
||||||
const Certificate = require('./certificate');
|
const Certificate = require('./certificate');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class ProxyHost extends Model {
|
class ProxyHost extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for domain_names
|
// Default for domain_names
|
||||||
if (typeof this.domain_names === 'undefined') {
|
if (typeof this.domain_names === 'undefined') {
|
||||||
@ -28,7 +29,7 @@ class ProxyHost extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Sort domain_names
|
// Sort domain_names
|
||||||
if (typeof this.domain_names !== 'undefined') {
|
if (typeof this.domain_names !== 'undefined') {
|
||||||
@ -59,7 +60,6 @@ class ProxyHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
access_list: {
|
access_list: {
|
||||||
@ -71,7 +71,6 @@ class ProxyHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('access_list.is_deleted', 0);
|
qb.where('access_list.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
certificate: {
|
certificate: {
|
||||||
@ -83,7 +82,6 @@ class ProxyHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('certificate.is_deleted', 0);
|
qb.where('certificate.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
// Objection Docs:
|
// Objection Docs:
|
||||||
// http://vincit.github.io/objection.js/
|
// http://vincit.github.io/objection.js/
|
||||||
|
|
||||||
@ -5,13 +6,14 @@ const db = require('../db');
|
|||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
const Certificate = require('./certificate');
|
const Certificate = require('./certificate');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class RedirectionHost extends Model {
|
class RedirectionHost extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for domain_names
|
// Default for domain_names
|
||||||
if (typeof this.domain_names === 'undefined') {
|
if (typeof this.domain_names === 'undefined') {
|
||||||
@ -27,7 +29,7 @@ class RedirectionHost extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Sort domain_names
|
// Sort domain_names
|
||||||
if (typeof this.domain_names !== 'undefined') {
|
if (typeof this.domain_names !== 'undefined') {
|
||||||
@ -58,7 +60,6 @@ class RedirectionHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
certificate: {
|
certificate: {
|
||||||
@ -70,7 +71,6 @@ class RedirectionHost extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('certificate.is_deleted', 0);
|
qb.where('certificate.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class Stream extends Model {
|
class Stream extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
@ -19,7 +20,7 @@ class Stream extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -45,7 +46,6 @@ class Stream extends Model {
|
|||||||
},
|
},
|
||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'is_deleted', 'email', 'roles']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,36 +4,38 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const config = require('config');
|
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
const config = require('../lib/config');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
|
const logger = require('../logger').global;
|
||||||
const ALGO = 'RS256';
|
const ALGO = 'RS256';
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
const public_key = config.get('jwt.pub');
|
|
||||||
const private_key = config.get('jwt.key');
|
|
||||||
|
|
||||||
let token_data = {};
|
let token_data = {};
|
||||||
|
|
||||||
let self = {
|
const self = {
|
||||||
/**
|
/**
|
||||||
* @param {Object} payload
|
* @param {Object} payload
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create: (payload) => {
|
create: (payload) => {
|
||||||
|
if (!config.getPrivateKey()) {
|
||||||
|
logger.error('Private key is empty!');
|
||||||
|
}
|
||||||
// sign with RSA SHA256
|
// sign with RSA SHA256
|
||||||
let options = {
|
const options = {
|
||||||
algorithm: ALGO,
|
algorithm: ALGO,
|
||||||
expiresIn: payload.expiresIn || '1d'
|
expiresIn: payload.expiresIn || '1d'
|
||||||
};
|
};
|
||||||
|
|
||||||
payload.jti = crypto.randomBytes(12)
|
payload.jti = crypto.randomBytes(12)
|
||||||
.toString('base64')
|
.toString('base64')
|
||||||
.substr(-8);
|
.substring(-8);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
jwt.sign(payload, private_key, options, (err, token) => {
|
jwt.sign(payload, config.getPrivateKey(), options, (err, token) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
@ -52,12 +54,15 @@ module.exports = function () {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
load: function (token) {
|
load: function (token) {
|
||||||
|
if (!config.getPublicKey()) {
|
||||||
|
logger.error('Public key is empty!');
|
||||||
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
if (!token || token === null || token === 'null') {
|
if (!token || token === null || token === 'null') {
|
||||||
reject(new error.AuthError('Empty token'));
|
reject(new error.AuthError('Empty token'));
|
||||||
} else {
|
} else {
|
||||||
jwt.verify(token, public_key, {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
|
jwt.verify(token, config.getPublicKey(), {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
||||||
if (err.name === 'TokenExpiredError') {
|
if (err.name === 'TokenExpiredError') {
|
||||||
@ -72,8 +77,6 @@ module.exports = function () {
|
|||||||
// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
|
// Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
|
||||||
// For 30 days at least, we need to replace 'all' with user.
|
// For 30 days at least, we need to replace 'all' with user.
|
||||||
if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
|
if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
|
||||||
//console.log('Warning! Replacing "all" scope with "user"');
|
|
||||||
|
|
||||||
token_data.scope = ['user'];
|
token_data.scope = ['user'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +126,7 @@ module.exports = function () {
|
|||||||
* @returns {Integer}
|
* @returns {Integer}
|
||||||
*/
|
*/
|
||||||
getUserId: (default_value) => {
|
getUserId: (default_value) => {
|
||||||
let attrs = self.get('attrs');
|
const attrs = self.get('attrs');
|
||||||
if (attrs && typeof attrs.id !== 'undefined' && attrs.id) {
|
if (attrs && typeof attrs.id !== 'undefined' && attrs.id) {
|
||||||
return attrs.id;
|
return attrs.id;
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const UserPermission = require('./user_permission');
|
const UserPermission = require('./user_permission');
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class User extends Model {
|
class User extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
|
|
||||||
// Default for roles
|
// Default for roles
|
||||||
if (typeof this.roles === 'undefined') {
|
if (typeof this.roles === 'undefined') {
|
||||||
@ -19,7 +20,7 @@ class User extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -42,9 +43,6 @@ class User extends Model {
|
|||||||
join: {
|
join: {
|
||||||
from: 'user.id',
|
from: 'user.id',
|
||||||
to: 'user_permission.user_id'
|
to: 'user_permission.user_id'
|
||||||
},
|
|
||||||
modify: function (qb) {
|
|
||||||
qb.omit(['id', 'created_on', 'modified_on', 'user_id']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,17 +3,18 @@
|
|||||||
|
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
class UserPermission extends Model {
|
class UserPermission extends Model {
|
||||||
$beforeInsert () {
|
$beforeInsert () {
|
||||||
this.created_on = Model.raw('NOW()');
|
this.created_on = now();
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
this.modified_on = Model.raw('NOW()');
|
this.modified_on = now();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
|
@ -1,35 +1,31 @@
|
|||||||
{
|
{
|
||||||
"name": "nginx-proxy-manager",
|
"name": "nginx-proxy-manager",
|
||||||
"version": "2.1.1",
|
"version": "0.0.0",
|
||||||
"description": "A beautiful interface for creating Nginx endpoints",
|
"description": "A beautiful interface for creating Nginx endpoints",
|
||||||
"main": "js/index.js",
|
"main": "js/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.11.0",
|
"ajv": "^6.12.0",
|
||||||
|
"archiver": "^5.3.0",
|
||||||
"batchflow": "^0.4.0",
|
"batchflow": "^0.4.0",
|
||||||
"bcrypt": "^3.0.8",
|
"bcrypt": "^5.0.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"config": "^3.2.5",
|
"express": "^4.17.3",
|
||||||
"diskdb": "^0.1.17",
|
"express-fileupload": "^1.1.9",
|
||||||
"express": "^4.17.1",
|
|
||||||
"express-fileupload": "^1.1.6",
|
|
||||||
"gravatar": "^1.8.0",
|
"gravatar": "^1.8.0",
|
||||||
"html-entities": "^1.2.1",
|
"json-schema-ref-parser": "^8.0.0",
|
||||||
"json-schema-ref-parser": "^7.1.3",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"knex": "2.4.2",
|
||||||
"knex": "^0.20.10",
|
"liquidjs": "10.6.1",
|
||||||
"liquidjs": "^9.7.1",
|
"lodash": "^4.17.21",
|
||||||
"lodash": "^4.17.15",
|
"moment": "^2.29.4",
|
||||||
"moment": "^2.24.0",
|
|
||||||
"mysql": "^2.18.1",
|
"mysql": "^2.18.1",
|
||||||
"node-rsa": "^1.0.7",
|
"node-rsa": "^1.0.8",
|
||||||
"nodemon": "^2.0.2",
|
"objection": "3.0.1",
|
||||||
"objection": "^2.1.3",
|
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"restler": "^3.4.0",
|
"signale": "1.4.0",
|
||||||
"signale": "^1.4.0",
|
"sqlite3": "5.1.6",
|
||||||
"temp-write": "^4.0.0",
|
"temp-write": "^4.0.0"
|
||||||
"unix-timestamp": "^0.2.0"
|
|
||||||
},
|
},
|
||||||
"signale": {
|
"signale": {
|
||||||
"displayDate": true,
|
"displayDate": true,
|
||||||
@ -38,8 +34,9 @@
|
|||||||
"author": "Jamie Curnow <jc@jc21.com>",
|
"author": "Jamie Curnow <jc@jc21.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^8.36.0",
|
||||||
"eslint-plugin-align-assignments": "^1.1.2",
|
"eslint-plugin-align-assignments": "^1.1.2",
|
||||||
"prettier": "^1.19.1"
|
"nodemon": "^2.0.2",
|
||||||
|
"prettier": "^2.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ router
|
|||||||
.post((req, res, next) => {
|
.post((req, res, next) => {
|
||||||
apiValidator({$ref: 'endpoints/certificates#/links/1/schema'}, req.body)
|
apiValidator({$ref: 'endpoints/certificates#/links/1/schema'}, req.body)
|
||||||
.then((payload) => {
|
.then((payload) => {
|
||||||
|
req.setTimeout(900000); // 15 minutes timeout
|
||||||
return internalCertificate.create(res.locals.access, payload);
|
return internalCertificate.create(res.locals.access, payload);
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@ -67,6 +68,32 @@ router
|
|||||||
.catch(next);
|
.catch(next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test HTTP challenge for domains
|
||||||
|
*
|
||||||
|
* /api/nginx/certificates/test-http
|
||||||
|
*/
|
||||||
|
router
|
||||||
|
.route('/test-http')
|
||||||
|
.options((req, res) => {
|
||||||
|
res.sendStatus(204);
|
||||||
|
})
|
||||||
|
.all(jwtdecode())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/nginx/certificates/test-http
|
||||||
|
*
|
||||||
|
* Test HTTP challenge for domains
|
||||||
|
*/
|
||||||
|
.get((req, res, next) => {
|
||||||
|
internalCertificate.testHttpsChallenge(res.locals.access, JSON.parse(req.query.domains))
|
||||||
|
.then((result) => {
|
||||||
|
res.status(200)
|
||||||
|
.send(result);
|
||||||
|
})
|
||||||
|
.catch(next);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific certificate
|
* Specific certificate
|
||||||
*
|
*
|
||||||
@ -197,6 +224,7 @@ router
|
|||||||
* Renew certificate
|
* Renew certificate
|
||||||
*/
|
*/
|
||||||
.post((req, res, next) => {
|
.post((req, res, next) => {
|
||||||
|
req.setTimeout(900000); // 15 minutes timeout
|
||||||
internalCertificate.renew(res.locals.access, {
|
internalCertificate.renew(res.locals.access, {
|
||||||
id: parseInt(req.params.certificate_id, 10)
|
id: parseInt(req.params.certificate_id, 10)
|
||||||
})
|
})
|
||||||
@ -207,6 +235,34 @@ router
|
|||||||
.catch(next);
|
.catch(next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download LE Certs
|
||||||
|
*
|
||||||
|
* /api/nginx/certificates/123/download
|
||||||
|
*/
|
||||||
|
router
|
||||||
|
.route('/:certificate_id/download')
|
||||||
|
.options((req, res) => {
|
||||||
|
res.sendStatus(204);
|
||||||
|
})
|
||||||
|
.all(jwtdecode())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/nginx/certificates/123/download
|
||||||
|
*
|
||||||
|
* Renew certificate
|
||||||
|
*/
|
||||||
|
.get((req, res, next) => {
|
||||||
|
internalCertificate.download(res.locals.access, {
|
||||||
|
id: parseInt(req.params.certificate_id, 10)
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
res.status(200)
|
||||||
|
.download(result.fileName);
|
||||||
|
})
|
||||||
|
.catch(next);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate Certs before saving
|
* Validate Certs before saving
|
||||||
*
|
*
|
||||||
|
@ -153,7 +153,7 @@
|
|||||||
"example": "john@example.com",
|
"example": "john@example.com",
|
||||||
"format": "email",
|
"format": "email",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 8,
|
"minLength": 6,
|
||||||
"maxLength": 100
|
"maxLength": 100
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
@ -172,13 +172,26 @@
|
|||||||
"description": "Domain Names separated by a comma",
|
"description": "Domain Names separated by a comma",
|
||||||
"example": "*.jc21.com,blog.jc21.com",
|
"example": "*.jc21.com,blog.jc21.com",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"maxItems": 15,
|
"maxItems": 30,
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$"
|
"pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"http_code": {
|
||||||
|
"description": "Redirect HTTP Status Code",
|
||||||
|
"example": 302,
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 300,
|
||||||
|
"maximum": 308
|
||||||
|
},
|
||||||
|
"scheme": {
|
||||||
|
"description": "RFC Protocol",
|
||||||
|
"example": "HTTPS or $scheme",
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 4
|
||||||
|
},
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"description": "Is Enabled",
|
"description": "Is Enabled",
|
||||||
"example": true,
|
"example": true,
|
||||||
|
@ -1,168 +1,236 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"$id": "endpoints/access-lists",
|
"$id": "endpoints/access-lists",
|
||||||
"title": "Access Lists",
|
"title": "Access Lists",
|
||||||
"description": "Endpoints relating to Access Lists",
|
"description": "Endpoints relating to Access Lists",
|
||||||
"stability": "stable",
|
"stability": "stable",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"id": {
|
"id": {
|
||||||
"$ref": "../definitions.json#/definitions/id"
|
"$ref": "../definitions.json#/definitions/id"
|
||||||
},
|
},
|
||||||
"created_on": {
|
"created_on": {
|
||||||
"$ref": "../definitions.json#/definitions/created_on"
|
"$ref": "../definitions.json#/definitions/created_on"
|
||||||
},
|
},
|
||||||
"modified_on": {
|
"modified_on": {
|
||||||
"$ref": "../definitions.json#/definitions/modified_on"
|
"$ref": "../definitions.json#/definitions/modified_on"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the Access List"
|
"description": "Name of the Access List"
|
||||||
},
|
},
|
||||||
"meta": {
|
"directive": {
|
||||||
"type": "object"
|
"type": "string",
|
||||||
}
|
"enum": ["allow", "deny"]
|
||||||
},
|
},
|
||||||
"properties": {
|
"address": {
|
||||||
"id": {
|
"oneOf": [
|
||||||
"$ref": "#/definitions/id"
|
{
|
||||||
},
|
"type": "string",
|
||||||
"created_on": {
|
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
|
||||||
"$ref": "#/definitions/created_on"
|
},
|
||||||
},
|
{
|
||||||
"modified_on": {
|
"type": "string",
|
||||||
"$ref": "#/definitions/modified_on"
|
"pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
|
||||||
},
|
},
|
||||||
"name": {
|
{
|
||||||
"$ref": "#/definitions/name"
|
"type": "string",
|
||||||
},
|
"pattern": "^all$"
|
||||||
"meta": {
|
}
|
||||||
"$ref": "#/definitions/meta"
|
]
|
||||||
}
|
},
|
||||||
},
|
"satisfy_any": {
|
||||||
"links": [
|
"type": "boolean"
|
||||||
{
|
},
|
||||||
"title": "List",
|
"pass_auth": {
|
||||||
"description": "Returns a list of Access Lists",
|
"type": "boolean"
|
||||||
"href": "/nginx/access-lists",
|
},
|
||||||
"access": "private",
|
"meta": {
|
||||||
"method": "GET",
|
"type": "object"
|
||||||
"rel": "self",
|
}
|
||||||
"http_header": {
|
},
|
||||||
"$ref": "../examples.json#/definitions/auth_header"
|
"properties": {
|
||||||
},
|
"id": {
|
||||||
"targetSchema": {
|
"$ref": "#/definitions/id"
|
||||||
"type": "array",
|
},
|
||||||
"items": {
|
"created_on": {
|
||||||
"$ref": "#/properties"
|
"$ref": "#/definitions/created_on"
|
||||||
}
|
},
|
||||||
}
|
"modified_on": {
|
||||||
},
|
"$ref": "#/definitions/modified_on"
|
||||||
{
|
},
|
||||||
"title": "Create",
|
"name": {
|
||||||
"description": "Creates a new Access List",
|
"$ref": "#/definitions/name"
|
||||||
"href": "/nginx/access-list",
|
},
|
||||||
"access": "private",
|
"meta": {
|
||||||
"method": "POST",
|
"$ref": "#/definitions/meta"
|
||||||
"rel": "create",
|
}
|
||||||
"http_header": {
|
},
|
||||||
"$ref": "../examples.json#/definitions/auth_header"
|
"links": [
|
||||||
},
|
{
|
||||||
"schema": {
|
"title": "List",
|
||||||
"type": "object",
|
"description": "Returns a list of Access Lists",
|
||||||
"additionalProperties": false,
|
"href": "/nginx/access-lists",
|
||||||
"required": [
|
"access": "private",
|
||||||
"name"
|
"method": "GET",
|
||||||
],
|
"rel": "self",
|
||||||
"properties": {
|
"http_header": {
|
||||||
"name": {
|
"$ref": "../examples.json#/definitions/auth_header"
|
||||||
"$ref": "#/definitions/name"
|
},
|
||||||
},
|
"targetSchema": {
|
||||||
"items": {
|
"type": "array",
|
||||||
"type": "array",
|
"items": {
|
||||||
"minItems": 1,
|
"$ref": "#/properties"
|
||||||
"items": {
|
}
|
||||||
"type": "object",
|
}
|
||||||
"additionalProperties": false,
|
},
|
||||||
"properties": {
|
{
|
||||||
"username": {
|
"title": "Create",
|
||||||
"type": "string",
|
"description": "Creates a new Access List",
|
||||||
"minLength": 1
|
"href": "/nginx/access-list",
|
||||||
},
|
"access": "private",
|
||||||
"password": {
|
"method": "POST",
|
||||||
"type": "string",
|
"rel": "create",
|
||||||
"minLength": 1
|
"http_header": {
|
||||||
}
|
"$ref": "../examples.json#/definitions/auth_header"
|
||||||
}
|
},
|
||||||
}
|
"schema": {
|
||||||
},
|
"type": "object",
|
||||||
"meta": {
|
"additionalProperties": false,
|
||||||
"$ref": "#/definitions/meta"
|
"required": ["name"],
|
||||||
}
|
"properties": {
|
||||||
}
|
"name": {
|
||||||
},
|
"$ref": "#/definitions/name"
|
||||||
"targetSchema": {
|
},
|
||||||
"properties": {
|
"satisfy_any": {
|
||||||
"$ref": "#/properties"
|
"$ref": "#/definitions/satisfy_any"
|
||||||
}
|
},
|
||||||
}
|
"pass_auth": {
|
||||||
},
|
"$ref": "#/definitions/pass_auth"
|
||||||
{
|
},
|
||||||
"title": "Update",
|
"items": {
|
||||||
"description": "Updates a existing Access List",
|
"type": "array",
|
||||||
"href": "/nginx/access-list/{definitions.identity.example}",
|
"minItems": 0,
|
||||||
"access": "private",
|
"items": {
|
||||||
"method": "PUT",
|
"type": "object",
|
||||||
"rel": "update",
|
"additionalProperties": false,
|
||||||
"http_header": {
|
"properties": {
|
||||||
"$ref": "../examples.json#/definitions/auth_header"
|
"username": {
|
||||||
},
|
"type": "string",
|
||||||
"schema": {
|
"minLength": 1
|
||||||
"type": "object",
|
},
|
||||||
"additionalProperties": false,
|
"password": {
|
||||||
"properties": {
|
"type": "string",
|
||||||
"name": {
|
"minLength": 1
|
||||||
"$ref": "#/definitions/name"
|
}
|
||||||
},
|
}
|
||||||
"items": {
|
}
|
||||||
"type": "array",
|
},
|
||||||
"minItems": 1,
|
"clients": {
|
||||||
"items": {
|
"type": "array",
|
||||||
"type": "object",
|
"minItems": 0,
|
||||||
"additionalProperties": false,
|
"items": {
|
||||||
"properties": {
|
"type": "object",
|
||||||
"username": {
|
"additionalProperties": false,
|
||||||
"type": "string",
|
"properties": {
|
||||||
"minLength": 1
|
"address": {
|
||||||
},
|
"$ref": "#/definitions/address"
|
||||||
"password": {
|
},
|
||||||
"type": "string",
|
"directive": {
|
||||||
"minLength": 0
|
"$ref": "#/definitions/directive"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"meta": {
|
||||||
},
|
"$ref": "#/definitions/meta"
|
||||||
"targetSchema": {
|
}
|
||||||
"properties": {
|
}
|
||||||
"$ref": "#/properties"
|
},
|
||||||
}
|
"targetSchema": {
|
||||||
}
|
"properties": {
|
||||||
},
|
"$ref": "#/properties"
|
||||||
{
|
}
|
||||||
"title": "Delete",
|
}
|
||||||
"description": "Deletes a existing Access List",
|
},
|
||||||
"href": "/nginx/access-list/{definitions.identity.example}",
|
{
|
||||||
"access": "private",
|
"title": "Update",
|
||||||
"method": "DELETE",
|
"description": "Updates a existing Access List",
|
||||||
"rel": "delete",
|
"href": "/nginx/access-list/{definitions.identity.example}",
|
||||||
"http_header": {
|
"access": "private",
|
||||||
"$ref": "../examples.json#/definitions/auth_header"
|
"method": "PUT",
|
||||||
},
|
"rel": "update",
|
||||||
"targetSchema": {
|
"http_header": {
|
||||||
"type": "boolean"
|
"$ref": "../examples.json#/definitions/auth_header"
|
||||||
}
|
},
|
||||||
}
|
"schema": {
|
||||||
]
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/definitions/name"
|
||||||
|
},
|
||||||
|
"satisfy_any": {
|
||||||
|
"$ref": "#/definitions/satisfy_any"
|
||||||
|
},
|
||||||
|
"pass_auth": {
|
||||||
|
"$ref": "#/definitions/pass_auth"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 0,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"username": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"clients": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 0,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"$ref": "#/definitions/address"
|
||||||
|
},
|
||||||
|
"directive": {
|
||||||
|
"$ref": "#/definitions/directive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targetSchema": {
|
||||||
|
"properties": {
|
||||||
|
"$ref": "#/properties"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Delete",
|
||||||
|
"description": "Deletes a existing Access List",
|
||||||
|
"href": "/nginx/access-list/{definitions.identity.example}",
|
||||||
|
"access": "private",
|
||||||
|
"method": "DELETE",
|
||||||
|
"rel": "delete",
|
||||||
|
"http_header": {
|
||||||
|
"$ref": "../examples.json#/definitions/auth_header"
|
||||||
|
},
|
||||||
|
"targetSchema": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,24 @@
|
|||||||
},
|
},
|
||||||
"letsencrypt_agree": {
|
"letsencrypt_agree": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"dns_challenge": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"dns_provider": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dns_provider_credentials": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"propagation_seconds": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +157,17 @@
|
|||||||
"targetSchema": {
|
"targetSchema": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Test HTTP Challenge",
|
||||||
|
"description": "Tests whether the HTTP challenge should work",
|
||||||
|
"href": "/nginx/certificates/{definitions.identity.example}/test-http",
|
||||||
|
"access": "private",
|
||||||
|
"method": "GET",
|
||||||
|
"rel": "info",
|
||||||
|
"http_header": {
|
||||||
|
"$ref": "../examples.json#/definitions/auth_header"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"forward_host": {
|
"forward_host": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"maxLength": 50
|
"maxLength": 255
|
||||||
},
|
},
|
||||||
"forward_port": {
|
"forward_port": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
@ -18,6 +18,12 @@
|
|||||||
"domain_names": {
|
"domain_names": {
|
||||||
"$ref": "../definitions.json#/definitions/domain_names"
|
"$ref": "../definitions.json#/definitions/domain_names"
|
||||||
},
|
},
|
||||||
|
"forward_http_code": {
|
||||||
|
"$ref": "../definitions.json#/definitions/http_code"
|
||||||
|
},
|
||||||
|
"forward_scheme": {
|
||||||
|
"$ref": "../definitions.json#/definitions/scheme"
|
||||||
|
},
|
||||||
"forward_domain_name": {
|
"forward_domain_name": {
|
||||||
"$ref": "../definitions.json#/definitions/domain_name"
|
"$ref": "../definitions.json#/definitions/domain_name"
|
||||||
},
|
},
|
||||||
@ -67,6 +73,12 @@
|
|||||||
"domain_names": {
|
"domain_names": {
|
||||||
"$ref": "#/definitions/domain_names"
|
"$ref": "#/definitions/domain_names"
|
||||||
},
|
},
|
||||||
|
"forward_http_code": {
|
||||||
|
"$ref": "#/definitions/forward_http_code"
|
||||||
|
},
|
||||||
|
"forward_scheme": {
|
||||||
|
"$ref": "#/definitions/forward_scheme"
|
||||||
|
},
|
||||||
"forward_domain_name": {
|
"forward_domain_name": {
|
||||||
"$ref": "#/definitions/forward_domain_name"
|
"$ref": "#/definitions/forward_domain_name"
|
||||||
},
|
},
|
||||||
@ -134,12 +146,20 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"domain_names",
|
"domain_names",
|
||||||
|
"forward_scheme",
|
||||||
|
"forward_http_code",
|
||||||
"forward_domain_name"
|
"forward_domain_name"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"domain_names": {
|
"domain_names": {
|
||||||
"$ref": "#/definitions/domain_names"
|
"$ref": "#/definitions/domain_names"
|
||||||
},
|
},
|
||||||
|
"forward_http_code": {
|
||||||
|
"$ref": "#/definitions/forward_http_code"
|
||||||
|
},
|
||||||
|
"forward_scheme": {
|
||||||
|
"$ref": "#/definitions/forward_scheme"
|
||||||
|
},
|
||||||
"forward_domain_name": {
|
"forward_domain_name": {
|
||||||
"$ref": "#/definitions/forward_domain_name"
|
"$ref": "#/definitions/forward_domain_name"
|
||||||
},
|
},
|
||||||
@ -195,6 +215,12 @@
|
|||||||
"domain_names": {
|
"domain_names": {
|
||||||
"$ref": "#/definitions/domain_names"
|
"$ref": "#/definitions/domain_names"
|
||||||
},
|
},
|
||||||
|
"forward_http_code": {
|
||||||
|
"$ref": "#/definitions/forward_http_code"
|
||||||
|
},
|
||||||
|
"forward_scheme": {
|
||||||
|
"$ref": "#/definitions/forward_scheme"
|
||||||
|
},
|
||||||
"forward_domain_name": {
|
"forward_domain_name": {
|
||||||
"$ref": "#/definitions/forward_domain_name"
|
"$ref": "#/definitions/forward_domain_name"
|
||||||
},
|
},
|
||||||
|
@ -20,9 +20,20 @@
|
|||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"maximum": 65535
|
"maximum": 65535
|
||||||
},
|
},
|
||||||
"forward_ip": {
|
"forwarding_host": {
|
||||||
"type": "string",
|
"anyOf": [
|
||||||
"format": "ipv4"
|
{
|
||||||
|
"$ref": "../definitions.json#/definitions/domain_name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "ipv4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "ipv6"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"forwarding_port": {
|
"forwarding_port": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@ -55,8 +66,8 @@
|
|||||||
"incoming_port": {
|
"incoming_port": {
|
||||||
"$ref": "#/definitions/incoming_port"
|
"$ref": "#/definitions/incoming_port"
|
||||||
},
|
},
|
||||||
"forward_ip": {
|
"forwarding_host": {
|
||||||
"$ref": "#/definitions/forward_ip"
|
"$ref": "#/definitions/forwarding_host"
|
||||||
},
|
},
|
||||||
"forwarding_port": {
|
"forwarding_port": {
|
||||||
"$ref": "#/definitions/forwarding_port"
|
"$ref": "#/definitions/forwarding_port"
|
||||||
@ -107,15 +118,15 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": [
|
"required": [
|
||||||
"incoming_port",
|
"incoming_port",
|
||||||
"forward_ip",
|
"forwarding_host",
|
||||||
"forwarding_port"
|
"forwarding_port"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"incoming_port": {
|
"incoming_port": {
|
||||||
"$ref": "#/definitions/incoming_port"
|
"$ref": "#/definitions/incoming_port"
|
||||||
},
|
},
|
||||||
"forward_ip": {
|
"forwarding_host": {
|
||||||
"$ref": "#/definitions/forward_ip"
|
"$ref": "#/definitions/forwarding_host"
|
||||||
},
|
},
|
||||||
"forwarding_port": {
|
"forwarding_port": {
|
||||||
"$ref": "#/definitions/forwarding_port"
|
"$ref": "#/definitions/forwarding_port"
|
||||||
@ -154,8 +165,8 @@
|
|||||||
"incoming_port": {
|
"incoming_port": {
|
||||||
"$ref": "#/definitions/incoming_port"
|
"$ref": "#/definitions/incoming_port"
|
||||||
},
|
},
|
||||||
"forward_ip": {
|
"forwarding_host": {
|
||||||
"$ref": "#/definitions/forward_ip"
|
"$ref": "#/definitions/forwarding_host"
|
||||||
},
|
},
|
||||||
"forwarding_port": {
|
"forwarding_port": {
|
||||||
"$ref": "#/definitions/forwarding_port"
|
"$ref": "#/definitions/forwarding_port"
|
||||||
|
49
backend/scripts/install-certbot-plugins
Executable file
49
backend/scripts/install-certbot-plugins
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/node
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
// Install all plugins defined in `certbot-dns-plugins.json`:
|
||||||
|
// ./install-certbot-plugins
|
||||||
|
// Install one or more specific plugins:
|
||||||
|
// ./install-certbot-plugins route53 cloudflare
|
||||||
|
//
|
||||||
|
// Usage with a running docker container:
|
||||||
|
// docker exec npm_core /command/s6-setuidgid 1000:1000 bash -c "/app/scripts/install-certbot-plugins"
|
||||||
|
//
|
||||||
|
|
||||||
|
const dnsPlugins = require('../global/certbot-dns-plugins.json');
|
||||||
|
const certbot = require('../lib/certbot');
|
||||||
|
const logger = require('../logger').certbot;
|
||||||
|
const batchflow = require('batchflow');
|
||||||
|
|
||||||
|
let hasErrors = false;
|
||||||
|
let failingPlugins = [];
|
||||||
|
|
||||||
|
let pluginKeys = Object.keys(dnsPlugins);
|
||||||
|
if (process.argv.length > 2) {
|
||||||
|
pluginKeys = process.argv.slice(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
batchflow(pluginKeys).sequential()
|
||||||
|
.each((i, pluginKey, next) => {
|
||||||
|
certbot.installPlugin(pluginKey)
|
||||||
|
.then(() => {
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
hasErrors = true;
|
||||||
|
failingPlugins.push(pluginKey);
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.error((err) => {
|
||||||
|
logger.error(err.message);
|
||||||
|
})
|
||||||
|
.end(() => {
|
||||||
|
if (hasErrors) {
|
||||||
|
logger.error('Some plugins failed to install. Please check the logs above. Failing plugins: ' + '\n - ' + failingPlugins.join('\n - '));
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
logger.complete('Plugins installed successfully');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
213
backend/setup.js
213
backend/setup.js
@ -1,69 +1,23 @@
|
|||||||
const fs = require('fs');
|
const config = require('./lib/config');
|
||||||
const NodeRSA = require('node-rsa');
|
|
||||||
const config = require('config');
|
|
||||||
const logger = require('./logger').setup;
|
const logger = require('./logger').setup;
|
||||||
|
const certificateModel = require('./models/certificate');
|
||||||
const userModel = require('./models/user');
|
const userModel = require('./models/user');
|
||||||
const userPermissionModel = require('./models/user_permission');
|
const userPermissionModel = require('./models/user_permission');
|
||||||
|
const utils = require('./lib/utils');
|
||||||
const authModel = require('./models/auth');
|
const authModel = require('./models/auth');
|
||||||
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
|
const settingModel = require('./models/setting');
|
||||||
|
const certbot = require('./lib/certbot');
|
||||||
module.exports = function () {
|
/**
|
||||||
return new Promise((resolve, reject) => {
|
* Creates a default admin users if one doesn't already exist in the database
|
||||||
// Now go and check if the jwt gpg keys have been created and if not, create them
|
*
|
||||||
if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) {
|
* @returns {Promise}
|
||||||
logger.info('Creating a new JWT key pair...');
|
*/
|
||||||
|
const setupDefaultUser = () => {
|
||||||
// jwt keys are not configured properly
|
return userModel
|
||||||
const filename = config.util.getEnv('NODE_CONFIG_DIR') + '/' + (config.util.getEnv('NODE_ENV') || 'default') + '.json';
|
.query()
|
||||||
let config_data = {};
|
.select(userModel.raw('COUNT(`id`) as `count`'))
|
||||||
|
.where('is_deleted', 0)
|
||||||
try {
|
.first()
|
||||||
config_data = require(filename);
|
|
||||||
} catch (err) {
|
|
||||||
// do nothing
|
|
||||||
if (debug_mode) {
|
|
||||||
logger.debug(filename + ' config file could not be required');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now create the keys and save them in the config.
|
|
||||||
let key = new NodeRSA({b: 2048});
|
|
||||||
key.generateKeyPair();
|
|
||||||
|
|
||||||
config_data.jwt = {
|
|
||||||
key: key.exportKey('private').toString(),
|
|
||||||
pub: key.exportKey('public').toString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Write config
|
|
||||||
fs.writeFile(filename, JSON.stringify(config_data, null, 2), (err) => {
|
|
||||||
if (err) {
|
|
||||||
logger.error('Could not write JWT key pair to config file: ' + filename);
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
logger.info('Wrote JWT key pair to config file: ' + filename);
|
|
||||||
|
|
||||||
logger.warn('Restarting interface to apply new configuration');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// JWT key pair exists
|
|
||||||
if (debug_mode) {
|
|
||||||
logger.debug('JWT Keypair already exists');
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return userModel
|
|
||||||
.query()
|
|
||||||
.select(userModel.raw('COUNT(`id`) as `count`'))
|
|
||||||
.where('is_deleted', 0)
|
|
||||||
.first();
|
|
||||||
})
|
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row.count) {
|
if (!row.count) {
|
||||||
// Create a new user and set password
|
// Create a new user and set password
|
||||||
@ -75,7 +29,7 @@ module.exports = function () {
|
|||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
nickname: 'Admin',
|
nickname: 'Admin',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
roles: ['admin']
|
roles: ['admin'],
|
||||||
};
|
};
|
||||||
|
|
||||||
return userModel
|
return userModel
|
||||||
@ -88,28 +42,129 @@ module.exports = function () {
|
|||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
type: 'password',
|
type: 'password',
|
||||||
secret: 'changeme',
|
secret: 'changeme',
|
||||||
meta: {}
|
meta: {},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return userPermissionModel
|
return userPermissionModel.query().insert({
|
||||||
.query()
|
user_id: user.id,
|
||||||
.insert({
|
visibility: 'all',
|
||||||
user_id: user.id,
|
proxy_hosts: 'manage',
|
||||||
visibility: 'all',
|
redirection_hosts: 'manage',
|
||||||
proxy_hosts: 'manage',
|
dead_hosts: 'manage',
|
||||||
redirection_hosts: 'manage',
|
streams: 'manage',
|
||||||
dead_hosts: 'manage',
|
access_lists: 'manage',
|
||||||
streams: 'manage',
|
certificates: 'manage',
|
||||||
access_lists: 'manage',
|
});
|
||||||
certificates: 'manage'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info('Initial setup completed');
|
logger.info('Initial admin setup completed');
|
||||||
});
|
});
|
||||||
} else if (debug_mode) {
|
} else if (config.debug()) {
|
||||||
logger.debug('Admin user setup not required');
|
logger.info('Admin user setup not required');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates default settings if they don't already exist in the database
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const setupDefaultSettings = () => {
|
||||||
|
return settingModel
|
||||||
|
.query()
|
||||||
|
.select(settingModel.raw('COUNT(`id`) as `count`'))
|
||||||
|
.where({id: 'default-site'})
|
||||||
|
.first()
|
||||||
|
.then((row) => {
|
||||||
|
if (!row.count) {
|
||||||
|
settingModel
|
||||||
|
.query()
|
||||||
|
.insert({
|
||||||
|
id: 'default-site',
|
||||||
|
name: 'Default Site',
|
||||||
|
description: 'What to show when Nginx is hit with an unknown Host',
|
||||||
|
value: 'congratulations',
|
||||||
|
meta: {},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('Default settings added');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (config.debug()) {
|
||||||
|
logger.info('Default setting setup not required');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs all Certbot plugins which are required for an installed certificate
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const setupCertbotPlugins = () => {
|
||||||
|
return certificateModel
|
||||||
|
.query()
|
||||||
|
.where('is_deleted', 0)
|
||||||
|
.andWhere('provider', 'letsencrypt')
|
||||||
|
.then((certificates) => {
|
||||||
|
if (certificates && certificates.length) {
|
||||||
|
let plugins = [];
|
||||||
|
let promises = [];
|
||||||
|
|
||||||
|
certificates.map(function (certificate) {
|
||||||
|
if (certificate.meta && certificate.meta.dns_challenge === true) {
|
||||||
|
if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
|
||||||
|
plugins.push(certificate.meta.dns_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure credentials file exists
|
||||||
|
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
||||||
|
// Escape single quotes and backslashes
|
||||||
|
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
|
||||||
|
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
|
||||||
|
promises.push(utils.exec(credentials_cmd));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return certbot.installPlugins(plugins)
|
||||||
|
.then(() => {
|
||||||
|
if (promises.length) {
|
||||||
|
return Promise.all(promises)
|
||||||
|
.then(() => {
|
||||||
|
logger.info('Added Certbot plugins ' + plugins.join(', '));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a timer to call run the logrotation binary every two days
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const setupLogrotation = () => {
|
||||||
|
const intervalTimeout = 1000 * 60 * 60 * 24 * 2; // 2 days
|
||||||
|
|
||||||
|
const runLogrotate = async () => {
|
||||||
|
try {
|
||||||
|
await utils.exec('logrotate /etc/logrotate.d/nginx-proxy-manager');
|
||||||
|
logger.info('Logrotate completed.');
|
||||||
|
} catch (e) { logger.warn(e); }
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info('Logrotate Timer initialized');
|
||||||
|
setInterval(runLogrotate, intervalTimeout);
|
||||||
|
// And do this now as well
|
||||||
|
return runLogrotate();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
return setupDefaultUser()
|
||||||
|
.then(setupDefaultSettings)
|
||||||
|
.then(setupCertbotPlugins)
|
||||||
|
.then(setupLogrotation);
|
||||||
|
};
|
||||||
|
25
backend/templates/_access.conf
Normal file
25
backend/templates/_access.conf
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{% if access_list_id > 0 %}
|
||||||
|
{% if access_list.items.length > 0 %}
|
||||||
|
# Authorization
|
||||||
|
auth_basic "Authorization required";
|
||||||
|
auth_basic_user_file /data/access/{{ access_list_id }};
|
||||||
|
|
||||||
|
{% if access_list.pass_auth == 0 %}
|
||||||
|
proxy_set_header Authorization "";
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Access Rules: {{ access_list.clients | size }} total
|
||||||
|
{% for client in access_list.clients %}
|
||||||
|
{{client | nginxAccessRule}}
|
||||||
|
{% endfor %}
|
||||||
|
deny all;
|
||||||
|
|
||||||
|
# Access checks must...
|
||||||
|
{% if access_list.satisfy_any == 1 %}
|
||||||
|
satisfy any;
|
||||||
|
{% else %}
|
||||||
|
satisfy all;
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
@ -1,8 +1,8 @@
|
|||||||
{% if certificate and certificate_id > 0 -%}
|
{% if certificate and certificate_id > 0 -%}
|
||||||
{% if ssl_forced == 1 or ssl_forced == true %}
|
{% if ssl_forced == 1 or ssl_forced == true %}
|
||||||
{% if hsts_enabled == 1 or hsts_enabled == true %}
|
{% if hsts_enabled == 1 or hsts_enabled == true %}
|
||||||
# HSTS (ngx_http_headers_module is required) (31536000 seconds = 1 year)
|
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
|
||||||
add_header Strict-Transport-Security "max-age=31536000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always;
|
add_header Strict-Transport-Security $hsts_header always;
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
3
backend/templates/_hsts_map.conf
Normal file
3
backend/templates/_hsts_map.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
map $scheme $hsts_header {
|
||||||
|
https "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload";
|
||||||
|
}
|
@ -1,5 +1,15 @@
|
|||||||
listen 80;
|
listen 80;
|
||||||
|
{% if ipv6 -%}
|
||||||
|
listen [::]:80;
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:80;
|
||||||
|
{% endif %}
|
||||||
{% if certificate -%}
|
{% if certificate -%}
|
||||||
listen 443 ssl{% if http2_support %} http2{% endif %};
|
listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||||
|
{% if ipv6 -%}
|
||||||
|
listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:443;
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
server_name {{ domain_names | join: " " }};
|
server_name {{ domain_names | join: " " }};
|
||||||
|
@ -1,9 +1,26 @@
|
|||||||
|
{% include "_hsts_map.conf" %}
|
||||||
|
|
||||||
location {{ path }} {
|
location {{ path }} {
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-Scheme $scheme;
|
proxy_set_header X-Forwarded-Scheme $scheme;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
|
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
|
||||||
|
|
||||||
|
{% include "_access.conf" %}
|
||||||
|
{% include "_assets.conf" %}
|
||||||
|
{% include "_exploits.conf" %}
|
||||||
|
{% include "_forced_ssl.conf" %}
|
||||||
|
{% include "_hsts.conf" %}
|
||||||
|
|
||||||
|
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{{ advanced_config }}
|
{{ advanced_config }}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
{% include "_header_comment.conf" %}
|
{% include "_header_comment.conf" %}
|
||||||
|
|
||||||
{% if enabled %}
|
{% if enabled %}
|
||||||
|
|
||||||
|
{% include "_hsts_map.conf" %}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
{% include "_listen.conf" %}
|
{% include "_listen.conf" %}
|
||||||
{% include "_certificates.conf" %}
|
{% include "_certificates.conf" %}
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
|
{% include "_forced_ssl.conf" %}
|
||||||
|
|
||||||
access_log /data/logs/dead_host-{{ id }}.log standard;
|
access_log /data/logs/dead-host-{{ id }}_access.log standard;
|
||||||
|
error_log /data/logs/dead-host-{{ id }}_error.log warn;
|
||||||
|
|
||||||
{{ advanced_config }}
|
{{ advanced_config }}
|
||||||
|
|
||||||
{% if use_default_location %}
|
{% if use_default_location %}
|
||||||
location / {
|
location / {
|
||||||
{% include "_forced_ssl.conf" %}
|
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,30 @@
|
|||||||
{%- else %}
|
{%- else %}
|
||||||
server {
|
server {
|
||||||
listen 80 default;
|
listen 80 default;
|
||||||
|
{% if ipv6 -%}
|
||||||
|
listen [::]:80 default;
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:80 default;
|
||||||
|
{% endif %}
|
||||||
server_name default-host.localhost;
|
server_name default-host.localhost;
|
||||||
access_log /data/logs/default_host.log combined;
|
access_log /data/logs/default-host_access.log combined;
|
||||||
|
error_log /data/logs/default-host_error.log warn;
|
||||||
{% include "_exploits.conf" %}
|
{% include "_exploits.conf" %}
|
||||||
|
|
||||||
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
|
||||||
{%- if value == "404" %}
|
{%- if value == "404" %}
|
||||||
location / {
|
location / {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{%- if value == "444" %}
|
||||||
|
location / {
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{%- if value == "redirect" %}
|
{%- if value == "redirect" %}
|
||||||
location / {
|
location / {
|
||||||
return 301 {{ meta.redirect }};
|
return 301 {{ meta.redirect }};
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
{% if ipv6 -%}
|
||||||
|
listen [::]:80;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
server_name {{ domain_names | join: " " }};
|
server_name {{ domain_names | join: " " }};
|
||||||
|
|
||||||
access_log /data/logs/letsencrypt-requests.log standard;
|
access_log /data/logs/letsencrypt-requests_access.log standard;
|
||||||
|
error_log /data/logs/letsencrypt-requests_error.log warn;
|
||||||
|
|
||||||
include conf.d/include/letsencrypt-acme-challenge.conf;
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{% include "_header_comment.conf" %}
|
{% include "_header_comment.conf" %}
|
||||||
|
|
||||||
{% if enabled %}
|
{% if enabled %}
|
||||||
|
|
||||||
|
{% include "_hsts_map.conf" %}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
set $forward_scheme {{ forward_scheme }};
|
set $forward_scheme {{ forward_scheme }};
|
||||||
set $server "{{ forward_host }}";
|
set $server "{{ forward_host }}";
|
||||||
@ -11,8 +14,16 @@ server {
|
|||||||
{% include "_assets.conf" %}
|
{% include "_assets.conf" %}
|
||||||
{% include "_exploits.conf" %}
|
{% include "_exploits.conf" %}
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
|
{% include "_forced_ssl.conf" %}
|
||||||
|
|
||||||
access_log /data/logs/proxy_host-{{ id }}.log proxy;
|
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
access_log /data/logs/proxy-host-{{ id }}_access.log proxy;
|
||||||
|
error_log /data/logs/proxy-host-{{ id }}_error.log warn;
|
||||||
|
|
||||||
{{ advanced_config }}
|
{{ advanced_config }}
|
||||||
|
|
||||||
@ -21,18 +32,13 @@ server {
|
|||||||
{% if use_default_location %}
|
{% if use_default_location %}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
{%- if access_list_id > 0 -%}
|
|
||||||
# Access List
|
|
||||||
auth_basic "Authorization required";
|
|
||||||
auth_basic_user_file /data/access/{{ access_list_id }};
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{% include "_forced_ssl.conf" %}
|
{% include "_access.conf" %}
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
|
|
||||||
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection $http_connection;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
{% include "_header_comment.conf" %}
|
{% include "_header_comment.conf" %}
|
||||||
|
|
||||||
{% if enabled %}
|
{% if enabled %}
|
||||||
|
|
||||||
|
{% include "_hsts_map.conf" %}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
{% include "_listen.conf" %}
|
{% include "_listen.conf" %}
|
||||||
{% include "_certificates.conf" %}
|
{% include "_certificates.conf" %}
|
||||||
{% include "_assets.conf" %}
|
{% include "_assets.conf" %}
|
||||||
{% include "_exploits.conf" %}
|
{% include "_exploits.conf" %}
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
|
{% include "_forced_ssl.conf" %}
|
||||||
|
|
||||||
access_log /data/logs/redirection_host-{{ id }}.log standard;
|
access_log /data/logs/redirection-host-{{ id }}_access.log standard;
|
||||||
|
error_log /data/logs/redirection-host-{{ id }}_error.log warn;
|
||||||
|
|
||||||
{{ advanced_config }}
|
{{ advanced_config }}
|
||||||
|
|
||||||
{% if use_default_location %}
|
{% if use_default_location %}
|
||||||
location / {
|
location / {
|
||||||
{% include "_forced_ssl.conf" %}
|
|
||||||
{% include "_hsts.conf" %}
|
{% include "_hsts.conf" %}
|
||||||
|
|
||||||
{% if preserve_path == 1 or preserve_path == true %}
|
{% if preserve_path == 1 or preserve_path == true %}
|
||||||
return 301 $scheme://{{ forward_domain_name }}$request_uri;
|
return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }}$request_uri;
|
||||||
{% else %}
|
{% else %}
|
||||||
return 301 $scheme://{{ forward_domain_name }};
|
return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -6,7 +6,13 @@
|
|||||||
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
|
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
|
||||||
server {
|
server {
|
||||||
listen {{ incoming_port }};
|
listen {{ incoming_port }};
|
||||||
proxy_pass {{ forward_ip }}:{{ forwarding_port }};
|
{% if ipv6 -%}
|
||||||
|
listen [::]:{{ incoming_port }};
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:{{ incoming_port }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
# Custom
|
# Custom
|
||||||
include /data/nginx/custom/server_stream[.]conf;
|
include /data/nginx/custom/server_stream[.]conf;
|
||||||
@ -16,7 +22,12 @@ server {
|
|||||||
{% if udp_forwarding == 1 or udp_forwarding == true %}
|
{% if udp_forwarding == 1 or udp_forwarding == true %}
|
||||||
server {
|
server {
|
||||||
listen {{ incoming_port }} udp;
|
listen {{ incoming_port }} udp;
|
||||||
proxy_pass {{ forward_ip }}:{{ forwarding_port }};
|
{% if ipv6 -%}
|
||||||
|
listen [::]:{{ incoming_port }} udp;
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:{{ incoming_port }} udp;
|
||||||
|
{% endif %}
|
||||||
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
# Custom
|
# Custom
|
||||||
include /data/nginx/custom/server_stream[.]conf;
|
include /data/nginx/custom/server_stream[.]conf;
|
||||||
|
3890
backend/yarn.lock
3890
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,17 +0,0 @@
|
|||||||
## Advanced Nginx Configuration
|
|
||||||
|
|
||||||
If you are a more advanced user, you might be itching for extra Nginx customizability.
|
|
||||||
|
|
||||||
NPM has the ability to include different custom configuration snippets in different places.
|
|
||||||
|
|
||||||
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
|
|
||||||
|
|
||||||
`/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
|
|
||||||
|
|
||||||
Every file is optional.
|
|
150
doc/INSTALL.md
150
doc/INSTALL.md
@ -1,150 +0,0 @@
|
|||||||
## Installation and Configuration
|
|
||||||
|
|
||||||
If you just want to get up and running in the quickest time possible, grab all the files in
|
|
||||||
the [doc/example/](https://github.com/jc21/nginx-proxy-manager/tree/master/doc/example)
|
|
||||||
folder and run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Configuration File
|
|
||||||
|
|
||||||
**The configuration file needs to be provided by you!**
|
|
||||||
|
|
||||||
Don't worry, this is easy to do.
|
|
||||||
|
|
||||||
The app requires a configuration file to let it know what database you're using.
|
|
||||||
|
|
||||||
Here's an example configuration for `mysql` (or mariadb) that is compatible with the docker-compose example below:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"database": {
|
|
||||||
"engine": "mysql",
|
|
||||||
"host": "db",
|
|
||||||
"name": "npm",
|
|
||||||
"user": "npm",
|
|
||||||
"password": "npm",
|
|
||||||
"port": 3306
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you've created your configuration file it's easy to mount it in the docker container.
|
|
||||||
|
|
||||||
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys
|
|
||||||
affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
|
|
||||||
|
|
||||||
|
|
||||||
### Database
|
|
||||||
|
|
||||||
This app doesn't come with a database, you have to provide one yourself. Currently only `mysql/mariadb` is supported for the minimum versions:
|
|
||||||
|
|
||||||
- MySQL v5.7.8+
|
|
||||||
- MariaDB v10.2.7+
|
|
||||||
|
|
||||||
It's easy to use another docker container for your database also and link it as part of the docker stack, so that's what the following examples
|
|
||||||
are going to use.
|
|
||||||
|
|
||||||
|
|
||||||
### Running the App
|
|
||||||
|
|
||||||
Via `docker-compose`:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
version: "3"
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
image: jc21/nginx-proxy-manager:2
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
# Public HTTP Port:
|
|
||||||
- 80:80
|
|
||||||
# Public HTTPS Port:
|
|
||||||
- 443:443
|
|
||||||
# Admin Web Port:
|
|
||||||
- 81:81
|
|
||||||
volumes:
|
|
||||||
# Make sure this config.json file exists as per instructions above:
|
|
||||||
- ./config.json:/app/config/production.json
|
|
||||||
- ./data:/data
|
|
||||||
- ./letsencrypt:/etc/letsencrypt
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
db:
|
|
||||||
image: mariadb:latest
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: "npm"
|
|
||||||
MYSQL_DATABASE: "npm"
|
|
||||||
MYSQL_USER: "npm"
|
|
||||||
MYSQL_PASSWORD: "npm"
|
|
||||||
volumes:
|
|
||||||
- ./data/mysql:/var/lib/mysql
|
|
||||||
```
|
|
||||||
|
|
||||||
Then:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Running on Raspberry PI / ARM devices
|
|
||||||
|
|
||||||
The docker images support the following architectures:
|
|
||||||
- amd64
|
|
||||||
- arm64
|
|
||||||
- armv7
|
|
||||||
|
|
||||||
The docker images are a manifest of all the architecture docker builds supported, so this means
|
|
||||||
you don't have to worry about doing anything special and you can follow the common instructions above.
|
|
||||||
|
|
||||||
Check out the [dockerhub tags](https://cloud.docker.com/repository/registry-1.docker.io/jc21/nginx-proxy-manager/tags)
|
|
||||||
for a list of supported architectures and if you want one that doesn't exist,
|
|
||||||
[create a feature request](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
|
|
||||||
|
|
||||||
Also, if you don't know how to already, follow [this guide to install docker and docker-compose](https://manre-universe.net/how-to-run-docker-and-docker-compose-on-raspbian/)
|
|
||||||
on Raspbian.
|
|
||||||
|
|
||||||
|
|
||||||
### Initial Run
|
|
||||||
|
|
||||||
After the app is running for the first time, the following will happen:
|
|
||||||
|
|
||||||
- The database will initialize with table structures
|
|
||||||
- GPG keys will be generated and saved in the configuration file
|
|
||||||
- A default admin user will be created
|
|
||||||
|
|
||||||
This process can take a couple of minutes depending on your machine.
|
|
||||||
|
|
||||||
|
|
||||||
### 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.
|
|
||||||
|
|
||||||
|
|
||||||
### Advanced Options
|
|
||||||
|
|
||||||
#### X-FRAME-OPTIONS Header
|
|
||||||
|
|
||||||
You can configure the [`X-FRAME-OPTIONS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) header
|
|
||||||
value by specifying it as a Docker environment variable. The default if not specified is `deny`.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
...
|
|
||||||
environment:
|
|
||||||
X_FRAME_OPTIONS: "sameorigin"
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
... -e "X_FRAME_OPTIONS=sameorigin" ...
|
|
||||||
```
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"database": {
|
|
||||||
"engine": "mysql",
|
|
||||||
"host": "db",
|
|
||||||
"name": "npm",
|
|
||||||
"user": "npm",
|
|
||||||
"password": "npm",
|
|
||||||
"port": 3306
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
image: jc21/nginx-proxy-manager:latest
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
- 81:81
|
|
||||||
- 443:443
|
|
||||||
volumes:
|
|
||||||
- ./config.json:/app/config/production.json
|
|
||||||
- ./data:/data
|
|
||||||
- ./letsencrypt:/etc/letsencrypt
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
environment:
|
|
||||||
# if you want pretty colors in your docker logs:
|
|
||||||
- FORCE_COLOR=1
|
|
||||||
db:
|
|
||||||
image: mariadb:latest
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: "npm"
|
|
||||||
MYSQL_DATABASE: "npm"
|
|
||||||
MYSQL_USER: "npm"
|
|
||||||
MYSQL_PASSWORD: "npm"
|
|
||||||
volumes:
|
|
||||||
- ./data/mysql:/var/lib/mysql
|
|
14
docker/.dive-ci
Normal file
14
docker/.dive-ci
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
rules:
|
||||||
|
# If the efficiency is measured below X%, mark as failed.
|
||||||
|
# Expressed as a ratio between 0-1.
|
||||||
|
lowestEfficiency: 0.99
|
||||||
|
|
||||||
|
# If the amount of wasted space is at least X or larger than X, mark as failed.
|
||||||
|
# Expressed in B, KB, MB, and GB.
|
||||||
|
highestWastedBytes: 15MB
|
||||||
|
|
||||||
|
# If the amount of wasted space makes up for X% or more of the image, mark as failed.
|
||||||
|
# Note: the base image layer is NOT included in the total image size.
|
||||||
|
# Expressed as a ratio between 0-1; fails if the threshold is met or crossed.
|
||||||
|
highestUserWastedPercent: 0.02
|
||||||
|
|
@ -3,46 +3,60 @@
|
|||||||
|
|
||||||
# This file assumes that the frontend has been built using ./scripts/frontend-build
|
# This file assumes that the frontend has been built using ./scripts/frontend-build
|
||||||
|
|
||||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} jc21/alpine-nginx-full:node
|
FROM nginxproxymanager/nginx-full:certbot-node
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG BUILDPLATFORM
|
|
||||||
ARG BUILD_VERSION
|
ARG BUILD_VERSION
|
||||||
ARG BUILD_COMMIT
|
ARG BUILD_COMMIT
|
||||||
ARG BUILD_DATE
|
ARG BUILD_DATE
|
||||||
|
|
||||||
ENV SUPPRESS_NO_CONFIG_WARNING=1
|
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
|
||||||
ENV S6_FIX_ATTRS_HIDDEN=1
|
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
|
||||||
ENV NODE_ENV=production
|
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
|
||||||
|
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||||
|
S6_FIX_ATTRS_HIDDEN=1 \
|
||||||
|
S6_KILL_FINISH_MAXTIME=10000 \
|
||||||
|
S6_VERBOSITY=1 \
|
||||||
|
NODE_ENV=production \
|
||||||
|
NPM_BUILD_VERSION="${BUILD_VERSION}" \
|
||||||
|
NPM_BUILD_COMMIT="${BUILD_COMMIT}" \
|
||||||
|
NPM_BUILD_DATE="${BUILD_DATE}" \
|
||||||
|
NODE_OPTIONS="--openssl-legacy-provider"
|
||||||
|
|
||||||
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
|
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
|
||||||
&& rm -rf /etc/nginx \
|
&& apt-get update \
|
||||||
&& apk update \
|
&& apt-get install -y --no-install-recommends jq logrotate \
|
||||||
&& apk add python2 certbot jq \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV NPM_BUILD_VERSION="${BUILD_VERSION}" NPM_BUILD_COMMIT="${BUILD_COMMIT}" NPM_BUILD_DATE="${BUILD_DATE}"
|
|
||||||
|
|
||||||
# s6 overlay
|
# s6 overlay
|
||||||
COPY scripts/install-s6 /tmp/install-s6
|
COPY docker/scripts/install-s6 /tmp/install-s6
|
||||||
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
|
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80 81 443
|
||||||
EXPOSE 81
|
|
||||||
EXPOSE 443
|
|
||||||
EXPOSE 9876
|
|
||||||
|
|
||||||
COPY docker/rootfs /
|
COPY backend /app
|
||||||
ADD backend /app
|
COPY frontend/dist /app/frontend
|
||||||
ADD frontend/dist /app/frontend
|
COPY global /app/global
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN yarn install
|
RUN yarn install \
|
||||||
|
&& yarn cache clean
|
||||||
|
|
||||||
|
# add late to limit cache-busting by modifications
|
||||||
|
COPY docker/rootfs /
|
||||||
|
|
||||||
# Remove frontend service not required for prod, dev nginx config as well
|
# Remove frontend service not required for prod, dev nginx config as well
|
||||||
RUN rm -rf /etc/services.d/frontend RUN rm -f /etc/nginx/conf.d/dev.conf
|
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
|
||||||
|
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager
|
||||||
|
|
||||||
VOLUME [ "/data", "/etc/letsencrypt" ]
|
VOLUME [ "/data" ]
|
||||||
CMD [ "/init" ]
|
ENTRYPOINT [ "/init" ]
|
||||||
|
|
||||||
HEALTHCHECK --interval=5s --timeout=3s CMD /bin/check-health
|
LABEL org.label-schema.schema-version="1.0" \
|
||||||
|
org.label-schema.license="MIT" \
|
||||||
|
org.label-schema.name="nginx-proxy-manager" \
|
||||||
|
org.label-schema.description="Docker container for managing Nginx proxy hosts with a simple, powerful interface " \
|
||||||
|
org.label-schema.url="https://github.com/jc21/nginx-proxy-manager" \
|
||||||
|
org.label-schema.vcs-url="https://github.com/jc21/nginx-proxy-manager.git" \
|
||||||
|
org.label-schema.cmd="docker run --rm -ti jc21/nginx-proxy-manager:latest"
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
FROM jc21/alpine-nginx-full:node
|
FROM nginxproxymanager/nginx-full:certbot-node
|
||||||
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
|
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
|
||||||
|
|
||||||
ENV S6_LOGGING=0
|
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
|
||||||
ENV SUPPRESS_NO_CONFIG_WARNING=1
|
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
|
||||||
ENV S6_FIX_ATTRS_HIDDEN=1
|
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
|
||||||
|
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||||
|
S6_FIX_ATTRS_HIDDEN=1 \
|
||||||
|
S6_KILL_FINISH_MAXTIME=10000 \
|
||||||
|
S6_VERBOSITY=2 \
|
||||||
|
NODE_OPTIONS="--openssl-legacy-provider"
|
||||||
|
|
||||||
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
|
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
|
||||||
&& rm -rf /etc/nginx \
|
&& apt-get update \
|
||||||
&& apk update \
|
&& apt-get install -y jq python3-pip logrotate \
|
||||||
&& apk add python2 certbot jq \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/cache/apk/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Task
|
# Task
|
||||||
RUN cd /usr \
|
RUN cd /usr \
|
||||||
@ -18,15 +23,11 @@ RUN cd /usr \
|
|||||||
|
|
||||||
COPY rootfs /
|
COPY rootfs /
|
||||||
RUN rm -f /etc/nginx/conf.d/production.conf
|
RUN rm -f /etc/nginx/conf.d/production.conf
|
||||||
|
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
|
||||||
|
|
||||||
# s6 overlay
|
# s6 overlay
|
||||||
RUN curl -L -o /tmp/s6-overlay-amd64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz" \
|
COPY scripts/install-s6 /tmp/install-s6
|
||||||
&& tar -xzf /tmp/s6-overlay-amd64.tar.gz -C /
|
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80 81 443
|
||||||
EXPOSE 81
|
ENTRYPOINT [ "/init" ]
|
||||||
EXPOSE 443
|
|
||||||
|
|
||||||
CMD [ "/init" ]
|
|
||||||
|
|
||||||
HEALTHCHECK --interval=5s --timeout=3s CMD /bin/check-health
|
|
||||||
|
@ -1,44 +1,91 @@
|
|||||||
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
|
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
|
||||||
version: "3"
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
|
|
||||||
fullstack:
|
fullstack-mysql:
|
||||||
image: ${IMAGE}:ci-${BUILD_NUMBER}
|
image: "${IMAGE}:ci-${BUILD_NUMBER}"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
DEBUG: 'true'
|
||||||
- FORCE_COLOR=1
|
LE_STAGING: 'true'
|
||||||
|
FORCE_COLOR: 1
|
||||||
|
DB_MYSQL_HOST: 'db'
|
||||||
|
DB_MYSQL_PORT: '3306'
|
||||||
|
DB_MYSQL_USER: 'npm'
|
||||||
|
DB_MYSQL_PASSWORD: 'npm'
|
||||||
|
DB_MYSQL_NAME: 'npm'
|
||||||
volumes:
|
volumes:
|
||||||
- npm_data:/data
|
- npm_data_mysql:/data
|
||||||
- ../.jenkins/config.json:/app/config/production.json
|
- npm_le_mysql:/etc/letsencrypt
|
||||||
expose:
|
expose:
|
||||||
- 81
|
- 81
|
||||||
- 80
|
- 80
|
||||||
- 443
|
- 443
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "/usr/bin/check-health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
|
||||||
|
fullstack-sqlite:
|
||||||
|
image: "${IMAGE}:ci-${BUILD_NUMBER}"
|
||||||
|
environment:
|
||||||
|
DEBUG: 'true'
|
||||||
|
LE_STAGING: 'true'
|
||||||
|
FORCE_COLOR: 1
|
||||||
|
DB_SQLITE_FILE: '/data/mydb.sqlite'
|
||||||
|
PUID: 1000
|
||||||
|
PGID: 1000
|
||||||
|
DISABLE_IPV6: 'true'
|
||||||
|
volumes:
|
||||||
|
- npm_data_sqlite:/data
|
||||||
|
- npm_le_sqlite:/etc/letsencrypt
|
||||||
|
expose:
|
||||||
|
- 81
|
||||||
|
- 80
|
||||||
|
- 443
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "/usr/bin/check-health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: jc21/mariadb-aria
|
image: jc21/mariadb-aria
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "npm"
|
MYSQL_ROOT_PASSWORD: 'npm'
|
||||||
MYSQL_DATABASE: "npm"
|
MYSQL_DATABASE: 'npm'
|
||||||
MYSQL_USER: "npm"
|
MYSQL_USER: 'npm'
|
||||||
MYSQL_PASSWORD: "npm"
|
MYSQL_PASSWORD: 'npm'
|
||||||
volumes:
|
volumes:
|
||||||
- db_data:/var/lib/mysql
|
- mysql_data:/var/lib/mysql
|
||||||
|
|
||||||
cypress:
|
cypress-mysql:
|
||||||
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
|
image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
|
||||||
build:
|
build:
|
||||||
context: ../
|
context: ../test/
|
||||||
dockerfile: test/cypress/Dockerfile
|
dockerfile: cypress/Dockerfile
|
||||||
environment:
|
environment:
|
||||||
CYPRESS_baseUrl: "http://fullstack:81"
|
CYPRESS_baseUrl: 'http://fullstack-mysql:81'
|
||||||
volumes:
|
volumes:
|
||||||
- cypress-logs:/results
|
- cypress_logs_mysql:/results
|
||||||
|
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
|
||||||
|
|
||||||
|
cypress-sqlite:
|
||||||
|
image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
|
||||||
|
build:
|
||||||
|
context: ../test/
|
||||||
|
dockerfile: cypress/Dockerfile
|
||||||
|
environment:
|
||||||
|
CYPRESS_baseUrl: "http://fullstack-sqlite:81"
|
||||||
|
volumes:
|
||||||
|
- cypress_logs_sqlite:/results
|
||||||
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
|
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
cypress-logs:
|
cypress_logs_mysql:
|
||||||
npm_data:
|
cypress_logs_sqlite:
|
||||||
db_data:
|
npm_data_mysql:
|
||||||
|
npm_data_sqlite:
|
||||||
|
npm_le_sqlite:
|
||||||
|
npm_le_mysql:
|
||||||
|
mysql_data:
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
|
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
|
||||||
version: "3"
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
|
|
||||||
npm:
|
npm:
|
||||||
image: nginxproxymanager:dev
|
image: nginxproxymanager:dev
|
||||||
|
container_name: npm_core
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: ./dev/Dockerfile
|
dockerfile: ./dev/Dockerfile
|
||||||
@ -11,39 +12,57 @@ services:
|
|||||||
- 3080:80
|
- 3080:80
|
||||||
- 3081:81
|
- 3081:81
|
||||||
- 3443:443
|
- 3443:443
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=development
|
PUID: 1000
|
||||||
- FORCE_COLOR=1
|
PGID: 1000
|
||||||
- DEVELOPMENT=true
|
FORCE_COLOR: 1
|
||||||
|
# specifically for dev:
|
||||||
|
DEBUG: 'true'
|
||||||
|
DEVELOPMENT: 'true'
|
||||||
|
LE_STAGING: 'true'
|
||||||
|
# db:
|
||||||
|
DB_MYSQL_HOST: 'db'
|
||||||
|
DB_MYSQL_PORT: '3306'
|
||||||
|
DB_MYSQL_USER: 'npm'
|
||||||
|
DB_MYSQL_PASSWORD: 'npm'
|
||||||
|
DB_MYSQL_NAME: 'npm'
|
||||||
|
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||||
|
# DISABLE_IPV6: "true"
|
||||||
volumes:
|
volumes:
|
||||||
- npm_data:/data
|
- npm_data:/data
|
||||||
- le_data:/etc/letsencrypt
|
- le_data:/etc/letsencrypt
|
||||||
- ..:/app
|
- ../backend:/app
|
||||||
|
- ../frontend:/app/frontend
|
||||||
|
- ../global:/app/global
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: jc21/mariadb-aria
|
image: jc21/mariadb-aria
|
||||||
|
container_name: npm_db
|
||||||
|
ports:
|
||||||
|
- 33306:3306
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "npm"
|
MYSQL_ROOT_PASSWORD: 'npm'
|
||||||
MYSQL_DATABASE: "npm"
|
MYSQL_DATABASE: 'npm'
|
||||||
MYSQL_USER: "npm"
|
MYSQL_USER: 'npm'
|
||||||
MYSQL_PASSWORD: "npm"
|
MYSQL_PASSWORD: 'npm'
|
||||||
volumes:
|
volumes:
|
||||||
- db_data:/var/lib/mysql
|
- db_data:/var/lib/mysql
|
||||||
|
|
||||||
swagger:
|
|
||||||
image: 'swaggerapi/swagger-ui:latest'
|
|
||||||
ports:
|
|
||||||
- 3001:80
|
|
||||||
environment:
|
|
||||||
URL: "http://127.0.0.1:3081/api/schema"
|
|
||||||
PORT: '80'
|
|
||||||
depends_on:
|
|
||||||
- npm
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
npm_data:
|
npm_data:
|
||||||
|
name: npm_core_data
|
||||||
le_data:
|
le_data:
|
||||||
|
name: npm_le_data
|
||||||
db_data:
|
db_data:
|
||||||
|
name: npm_db_data
|
||||||
|
|
||||||
|
networks:
|
||||||
|
nginx_proxy_manager:
|
||||||
|
name: npm_network
|
||||||
|
2
docker/rootfs/etc/cont-finish.d/.gitignore
vendored
2
docker/rootfs/etc/cont-finish.d/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
2
docker/rootfs/etc/cont-init.d/.gitignore
vendored
2
docker/rootfs/etc/cont-init.d/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
2
docker/rootfs/etc/fix-attrs.d/.gitignore
vendored
2
docker/rootfs/etc/fix-attrs.d/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
@ -1,4 +1,6 @@
|
|||||||
text = True
|
text = True
|
||||||
non-interactive = True
|
non-interactive = True
|
||||||
authenticator = webroot
|
|
||||||
webroot-path = /data/letsencrypt-acme-challenge
|
webroot-path = /data/letsencrypt-acme-challenge
|
||||||
|
key-type = ecdsa
|
||||||
|
elliptic-curve = secp384r1
|
||||||
|
preferred-chain = ISRG Root X1
|
||||||
|
27
docker/rootfs/etc/logrotate.d/nginx-proxy-manager
Normal file
27
docker/rootfs/etc/logrotate.d/nginx-proxy-manager
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/data/logs/*_access.log /data/logs/*/access.log {
|
||||||
|
su npm npm
|
||||||
|
create 0644
|
||||||
|
weekly
|
||||||
|
rotate 4
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
sharedscripts
|
||||||
|
postrotate
|
||||||
|
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
|
||||||
|
endscript
|
||||||
|
}
|
||||||
|
|
||||||
|
/data/logs/*_error.log /data/logs/*/error.log {
|
||||||
|
su npm npm
|
||||||
|
create 0644
|
||||||
|
weekly
|
||||||
|
rotate 10
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
sharedscripts
|
||||||
|
postrotate
|
||||||
|
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
|
||||||
|
endscript
|
||||||
|
}
|
@ -8,10 +8,11 @@ server {
|
|||||||
set $port "80";
|
set $port "80";
|
||||||
|
|
||||||
server_name localhost-nginx-proxy-manager;
|
server_name localhost-nginx-proxy-manager;
|
||||||
access_log /data/logs/default.log standard;
|
access_log /data/logs/fallback_access.log standard;
|
||||||
error_log /dev/null crit;
|
error_log /data/logs/fallback_error.log warn;
|
||||||
include conf.d/include/assets.conf;
|
include conf.d/include/assets.conf;
|
||||||
include conf.d/include/block-exploits.conf;
|
include conf.d/include/block-exploits.conf;
|
||||||
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
index index.html;
|
index index.html;
|
||||||
@ -29,11 +30,10 @@ server {
|
|||||||
set $port "443";
|
set $port "443";
|
||||||
|
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
access_log /data/logs/default.log standard;
|
access_log /data/logs/fallback_access.log standard;
|
||||||
error_log /dev/null crit;
|
error_log /dev/null crit;
|
||||||
ssl_certificate /data/nginx/dummycert.pem;
|
|
||||||
ssl_certificate_key /data/nginx/dummykey.pem;
|
|
||||||
include conf.d/include/ssl-ciphers.conf;
|
include conf.d/include/ssl-ciphers.conf;
|
||||||
|
ssl_reject_handshake on;
|
||||||
|
|
||||||
return 444;
|
return 444;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,9 @@ server {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_pass http://127.0.0.1:3000/;
|
proxy_pass http://127.0.0.1:3000/;
|
||||||
|
|
||||||
|
proxy_read_timeout 15m;
|
||||||
|
proxy_send_timeout 15m;
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
location ~* ^.*\.(css|js|jpe?g|gif|png|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
||||||
if_modified_since off;
|
if_modified_since off;
|
||||||
|
|
||||||
# use the public cache
|
# use the public cache
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
set $test "";
|
||||||
if ($scheme = "http") {
|
if ($scheme = "http") {
|
||||||
|
set $test "H";
|
||||||
|
}
|
||||||
|
if ($request_uri = /.well-known/acme-challenge/test-challenge) {
|
||||||
|
set $test "${test}T";
|
||||||
|
}
|
||||||
|
if ($test = H) {
|
||||||
return 301 https://$host$request_uri;
|
return 301 https://$host$request_uri;
|
||||||
}
|
}
|
||||||
|
@ -1,196 +1,2 @@
|
|||||||
|
# This should be left blank is it is populated programatically
|
||||||
set_real_ip_from 144.220.0.0/16;
|
# by the application backend.
|
||||||
|
|
||||||
set_real_ip_from 52.124.128.0/17;
|
|
||||||
|
|
||||||
set_real_ip_from 54.230.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 54.239.128.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 52.82.128.0/19;
|
|
||||||
|
|
||||||
set_real_ip_from 99.84.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.172.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 205.251.192.0/19;
|
|
||||||
|
|
||||||
set_real_ip_from 54.239.192.0/19;
|
|
||||||
|
|
||||||
set_real_ip_from 70.132.0.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 13.32.0.0/15;
|
|
||||||
|
|
||||||
set_real_ip_from 13.224.0.0/14;
|
|
||||||
|
|
||||||
set_real_ip_from 13.35.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.164.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.168.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 71.152.0.0/17;
|
|
||||||
|
|
||||||
set_real_ip_from 216.137.32.0/19;
|
|
||||||
|
|
||||||
set_real_ip_from 205.251.249.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 99.86.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 52.46.0.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 52.84.0.0/15;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.173.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 130.176.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 64.252.64.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.174.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 64.252.128.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 205.251.254.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 143.204.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 205.251.252.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 204.246.176.0/20;
|
|
||||||
|
|
||||||
set_real_ip_from 13.249.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 54.240.128.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 205.251.250.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 52.222.128.0/17;
|
|
||||||
|
|
||||||
set_real_ip_from 54.182.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 54.192.0.0/16;
|
|
||||||
|
|
||||||
set_real_ip_from 13.124.199.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 34.226.14.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 52.15.127.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 35.158.136.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 52.57.254.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 18.216.170.128/25;
|
|
||||||
|
|
||||||
set_real_ip_from 13.52.204.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 13.54.63.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 13.59.250.0/26;
|
|
||||||
|
|
||||||
set_real_ip_from 13.210.67.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 35.167.191.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 52.47.139.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 52.199.127.192/26;
|
|
||||||
|
|
||||||
set_real_ip_from 52.212.248.0/26;
|
|
||||||
|
|
||||||
set_real_ip_from 52.66.194.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 13.113.203.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 99.79.168.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 34.195.252.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 35.162.63.192/26;
|
|
||||||
|
|
||||||
set_real_ip_from 34.223.12.224/27;
|
|
||||||
|
|
||||||
set_real_ip_from 52.56.127.0/25;
|
|
||||||
|
|
||||||
set_real_ip_from 34.223.80.192/26;
|
|
||||||
|
|
||||||
set_real_ip_from 13.228.69.0/24;
|
|
||||||
|
|
||||||
set_real_ip_from 34.216.51.0/25;
|
|
||||||
|
|
||||||
set_real_ip_from 3.231.2.0/25;
|
|
||||||
|
|
||||||
set_real_ip_from 54.233.255.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 18.200.212.0/23;
|
|
||||||
|
|
||||||
set_real_ip_from 52.52.191.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 3.234.232.224/27;
|
|
||||||
|
|
||||||
set_real_ip_from 52.78.247.128/26;
|
|
||||||
|
|
||||||
set_real_ip_from 52.220.191.0/26;
|
|
||||||
|
|
||||||
set_real_ip_from 34.232.163.208/29;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:eee::/48;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:4000::/36;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:3000::/36;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:f000::/36;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:fff::/48;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:2000::/36;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:1000::/36;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:ddd::/48;
|
|
||||||
|
|
||||||
set_real_ip_from 2600:9000:5300::/40;
|
|
||||||
|
|
||||||
set_real_ip_from 173.245.48.0/20;
|
|
||||||
|
|
||||||
set_real_ip_from 103.21.244.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 103.22.200.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 103.31.4.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 141.101.64.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 108.162.192.0/18;
|
|
||||||
|
|
||||||
set_real_ip_from 190.93.240.0/20;
|
|
||||||
|
|
||||||
set_real_ip_from 188.114.96.0/20;
|
|
||||||
|
|
||||||
set_real_ip_from 197.234.240.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 198.41.128.0/17;
|
|
||||||
|
|
||||||
set_real_ip_from 162.158.0.0/15;
|
|
||||||
|
|
||||||
set_real_ip_from 104.16.0.0/12;
|
|
||||||
|
|
||||||
set_real_ip_from 172.64.0.0/13;
|
|
||||||
|
|
||||||
set_real_ip_from 131.0.72.0/22;
|
|
||||||
|
|
||||||
set_real_ip_from 2400:cb00::/32;
|
|
||||||
|
|
||||||
set_real_ip_from 2606:4700::/32;
|
|
||||||
|
|
||||||
set_real_ip_from 2803:f800::/32;
|
|
||||||
|
|
||||||
set_real_ip_from 2405:b500::/32;
|
|
||||||
|
|
||||||
set_real_ip_from 2405:8100::/32;
|
|
||||||
|
|
||||||
set_real_ip_from 2a06:98c0::/29;
|
|
||||||
|
|
||||||
set_real_ip_from 2c0f:f248::/32;
|
|
||||||
|
@ -5,6 +5,7 @@ location ^~ /.well-known/acme-challenge/ {
|
|||||||
# Since this is for letsencrypt authentication of a domain and they do not give IP ranges of their infrastructure
|
# Since this is for letsencrypt authentication of a domain and they do not give IP ranges of their infrastructure
|
||||||
# we need to open up access by turning off auth and IP ACL for this location.
|
# we need to open up access by turning off auth and IP ACL for this location.
|
||||||
auth_basic off;
|
auth_basic off;
|
||||||
|
auth_request off;
|
||||||
allow all;
|
allow all;
|
||||||
|
|
||||||
# Set correct content type. According to this:
|
# Set correct content type. According to this:
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user