├── .gitignore ├── .version ├── Jenkinsfile ├── LICENSE ├── README-en.md ├── README.md ├── backend ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── .vscode │ └── settings.json ├── app.js ├── config │ ├── README.md │ ├── default.json │ └── sqlite-test-db.json ├── db.js ├── doc │ └── api.swagger.json ├── frontend │ ├── assets │ │ ├── source-sans-pro-v14-latin-ext_latin-700.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-700.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-700italic.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-700italic.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-italic.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-italic.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-regular.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-regular.woff2 │ │ └── tabler-ui │ │ │ ├── 002c4ac5d524b182b619dcb82bb3d63e.svg │ │ │ ├── 00c939ce7a61613960b91abb1f32afec.svg │ │ │ ├── 00e381f9ec82e9bf2cbb2a7d07bd6ffa.svg │ │ │ ├── 00e4a77f34085941311267a12f69f741.svg │ │ │ ├── 01473a4b1a1515654d1284e06a565487.svg │ │ │ ├── 027ef2b4fb6d82652c1b4ea5277bfc77.svg │ │ │ ├── 02985f30df285b97ab529ce9b12a4ab2.svg │ │ │ ├── 04c2d098b145b4ef153e5e68d4e6a283.svg │ │ │ ├── 069b07b838df10543f81c55b9c257a1b.svg │ │ │ ├── 080f2387b8ea5294a469e7ada4d3da8f.svg │ │ │ ├── 0867ca4d14a621ab9f4ec2ba425cedd9.svg │ │ │ ├── 086ebd78b096b1ae28e255151e9b5033.svg │ │ │ ├── 09032b32c871d636121aaf0b20bdc66c.svg │ │ │ ├── 095cf7f0f3609c50ee8856a2e1308669.svg │ │ │ ├── 0980633357b5ff682f74ef8697e9109f.svg │ │ │ ├── 0ab93acc2e9c86ed30126b25ba2273f5.svg │ │ │ ├── 0ae3a1616fd93697411dcbb4c287ff9d.svg │ │ │ ├── 0bcef270ef4fe8b473b718e28925f3c7.svg │ │ │ ├── 0d03a94f0bb3fbb8bafe4ef22ae1f8ab.svg │ │ │ ├── 0d29b851ede91eeb197d2f6af55d9a29.svg │ │ │ ├── 0d7f439ea81a7dc1b7e2e153b89209d1.svg │ │ │ ├── 0e51972c264c2cb188c347cb5a5c1d80.svg │ │ │ ├── 0fffdc4abb38bf1ad94ba5e1295d53c7.svg │ │ │ ├── 11612d785462813fa6c37a4508c6fb5b.svg │ │ │ ├── 131024ae018e4435ae26079ce8b7038b.svg │ │ │ ├── 1373eb8769dd878d38ad61a50b8eb291.svg │ │ │ ├── 13db15f1adddaa6757b5e06575c7088d.svg │ │ │ ├── 1404e490bc4ef4e6c2ed5de118578c38.svg │ │ │ ├── 142116714fd7536ffbfbf580bdaf9a9f.svg │ │ │ ├── 14f839c8391cd7bbd11cddba435006d2.svg │ │ │ ├── 16276bda8b86298c44292b2c2c4bce7a.svg │ │ │ ├── 163b5642c81b7781420e2c1c6ac9d93d.svg │ │ │ ├── 164feaa1f07e28af064ba4f8d1d8c930.svg │ │ │ ├── 171a190d8661f72551c97cfd023f59d5.svg │ │ │ ├── 173da534ba6477fb5d8c5cd5e2158f75.svg │ │ │ ├── 17eece3c07dbe5bd4ed04e93afd48820.svg │ │ │ ├── 195dffaad4cca86c6223685a34ce3514.svg │ │ │ ├── 1980b18fcba0ae20538632d294dce4b5.svg │ │ │ ├── 19aa981178cc9d46cbc09c61c3a5582c.svg │ │ │ ├── 19b39106bc694a7e4ccf0458fa08b328.svg │ │ │ ├── 1a0a0dcdfa761a13d5e91d6cbf3fb600.svg │ │ │ ├── 1a50381e56e0c65af5ca78ee4aa6e566.svg │ │ │ ├── 1a8a9c6cfee1a4b081b898f3e315f4ec.svg │ │ │ ├── 1b602c9fbb8dd47e2e4891df45f94871.svg │ │ │ ├── 1beb8731e787d165e806ded33ed867b0.svg │ │ │ ├── 1c37b533c26e19b0e0c67c0909eb68eb.svg │ │ │ ├── 1c5dfbef43d7ef95373b6bf7f93c58a6.svg │ │ │ ├── 1d58a8d49089620cbfabdc33f954e677.svg │ │ │ ├── 1e1e9b8e20fb277a00c961c7887beeca.svg │ │ │ ├── 1fe7fa39318bc5175bca9e02f62774f0.svg │ │ │ ├── 2018a70ba79c5d4022e4ab0e262b7b0c.svg │ │ │ ├── 214fc582eefd2adc4b3e82c766f6d104.svg │ │ │ ├── 21aa78abc4777c516a9e6776ed2b7f41.svg │ │ │ ├── 22d84fe88ebe4c35e1ac0b36dfd935a3.svg │ │ │ ├── 22f2f241aa6f3ec0d336fd150146ae34.svg │ │ │ ├── 22fbcf71a6a7feae95bbebf3a819ab94.svg │ │ │ ├── 235f4e7059f14d617f5bb88e733ed622.svg │ │ │ ├── 236ee866e6008f711adc2b0c53e8f6f5.svg │ │ │ ├── 2469f6fce1f4d6b50aa18902b03b7c77.svg │ │ │ ├── 24985a54d9f46fe765003bc2b7a351ce.svg │ │ │ ├── 24bd76f285a855b886bea1dbc8aff546.svg │ │ │ ├── 28763f267e98f51602109beaad91abe4.svg │ │ │ ├── 28aba54a61e5dcbd2dfea4f8d143b58d.svg │ │ │ ├── 28b723aaa5044eaa57d0e361772cd921.svg │ │ │ ├── 2926a9cbcf9cb75f72272b6970c973ff.svg │ │ │ ├── 2a27911fc59e5311f422f0185a57f0df.svg │ │ │ ├── 2a5a613b2f9a2e44e0ab3bc628150e7b.svg │ │ │ ├── 2a86b695698c807fb6c0512c0b7243f8.ttf │ │ │ ├── 2b01c8d7133515438f54bca721368f43.svg │ │ │ ├── 2bba212985d834dbb686230b790c0b98.svg │ │ │ ├── 2bf489b8013447621771d80d9abf8b01.svg │ │ │ ├── 2c53123099f8c2ce8b95c419108d0b98.svg │ │ │ ├── 2c80051eb4ed6fc1538f3eed46469913.svg │ │ │ ├── 2e6d4832b85fb8f3e935472d2240cc9d.svg │ │ │ ├── 2ec00a7cec3cd413884224cd8183ff50.svg │ │ │ ├── 2ecaed2a529c7f847ec2cc68113aba43.svg │ │ │ ├── 2eea09d0c30825e287a10d1eac2eeec5.svg │ │ │ ├── 2f2337a481220d675cfa2b6351f76652.svg │ │ │ ├── 2f8262cc7d07bd4ae72c616e32615304.svg │ │ │ ├── 2f83d0688d6d39dac1c3751c684af88e.svg │ │ │ ├── 2f8aa6a3d90c4e52913fa76a2be2e842.svg │ │ │ ├── 3131c3510299682637f35f1848463f0b.svg │ │ │ ├── 31ab68efc55818d34da6913c98c848bf.svg │ │ │ ├── 32286f8cb1440b454a1b3ed5d60de480.svg │ │ │ ├── 325806d3f4024c3c4c87965059f654db.svg │ │ │ ├── 32b4f3da129df582461489d172623edb.svg │ │ │ ├── 333793d1d77ea0288457087e02f00968.svg │ │ │ ├── 334584fe7a3b17ffc1c82dc0dee86002.svg │ │ │ ├── 33a70f15c7966770192ec58f53493d2a.svg │ │ │ ├── 344186789bbe633957861d9a333a94ac.svg │ │ │ ├── 34f3f20283179d4f7a61acb9a8ece100.svg │ │ │ ├── 34f766abb73b9a47873b99c777f5c39b.svg │ │ │ ├── 34fab6888545c72cfc1e51322693667f.svg │ │ │ ├── 372023debb62f1339555db60e899a507.svg │ │ │ ├── 372656ecd2e15b6c70bf91024f06d8df.svg │ │ │ ├── 3766a794da2c97aca82f8603774a3c3e.svg │ │ │ ├── 37c19e99ab465c891c4eaf7d063ddd34.svg │ │ │ ├── 37c4c24366a251ba5f2eb21f198cd314.svg │ │ │ ├── 3868005de3792f462620d83e1ce12174.svg │ │ │ ├── 38aa0a732391597679db496f459d5692.svg │ │ │ ├── 39c2e129f9d5f2602ec325dce9b7f1ee.svg │ │ │ ├── 3a025f8241385eda2da6b9bd60d80977.svg │ │ │ ├── 3aa03461587957e0acde7fc1acb045e2.svg │ │ │ ├── 3aa470988d9b979a572be12a0cbd42f1.svg │ │ │ ├── 3c25f404c1260f4b3c9fcdff2d2d8ba5.svg │ │ │ ├── 3c91de23706fd97b70da1131b47ffd06.svg │ │ │ ├── 3ce4cad6cbf7ae7aa18864c154e51478.svg │ │ │ ├── 3d222577b8647b41000999248827d79a.svg │ │ │ ├── 3d72f390815161ff78d2140d8386f3f6.svg │ │ │ ├── 3e29b66814026d8ed111806f1dd34ae4.svg │ │ │ ├── 3f6ee6c7e9e89bad505355dd8b0512ab.svg │ │ │ ├── 3feaa4f5becc973b96298ce62533ebb5.svg │ │ │ ├── 40fc809f59778931cdd1fce2b97ccfa9.svg │ │ │ ├── 422e0adbff13b7c0616db205b2f025fd.svg │ │ │ ├── 439aefbd14d40572fd54232fd8437ea6.svg │ │ │ ├── 448584b415da471a25dce979f07e8526.svg │ │ │ ├── 45c5842b34d4196c48048c0ce600266b.svg │ │ │ ├── 468af801120c21b0cfb02da5302a1ccf.svg │ │ │ ├── 46f0df63716157cb114cd9150e2be993.svg │ │ │ ├── 472a4da317e89b214a377458c869604e.svg │ │ │ ├── 497ba378ee14ba60203bb2ba743a8c94.svg │ │ │ ├── 4b8c26ac7a184ebdab3595f4978b6705.svg │ │ │ ├── 4bfe14e3a8332437bf0fd38caa47e54e.svg │ │ │ ├── 4ca3a62afc26764afc7da43f17360669.svg │ │ │ ├── 4ce0e8e2df519f1b8be56891ec493756.svg │ │ │ ├── 4d3de2f9f4ace61d3fe90b4784bc1d1f.svg │ │ │ ├── 4d72b50ae057f4f02a2a989854bd139e.svg │ │ │ ├── 4dc93134776daeea60d0ba3266d9c013.svg │ │ │ ├── 4e36fd773931aea79047c4facf8701fa.svg │ │ │ ├── 4f49ee16126497f056a428b5ace16e4f.svg │ │ │ ├── 504c3af97de8c7fc739e4c02def07cc7.svg │ │ │ ├── 509fd847d6d39ef34e36fa74da62f047.svg │ │ │ ├── 50a191d6b7131b337080a64f8f5c6c2b.svg │ │ │ ├── 526844fdfcdee69a0684228c617b0f08.svg │ │ │ ├── 52dcec651fbfabffd5f036a14bb46d59.svg │ │ │ ├── 54b9926864599fc7f9c78f4b2fe32a56.svg │ │ │ ├── 55073d98d77a5b6ce0c1cd3e76d22b2a.svg │ │ │ ├── 556120eb2600403fa2f59d2061a3bfe5.svg │ │ │ ├── 561695f13ae68c27b7d779405747f058.svg │ │ │ ├── 56b833cd572459ac7f738b4d55fd8488.svg │ │ │ ├── 573059db5f8f4570b5c51997665e04b0.svg │ │ │ ├── 585bd4f8c33d33e037299bbd9ec377e7.svg │ │ │ ├── 589869c174868607a35990b62e899884.svg │ │ │ ├── 58aed8593cc44a210d7e221b65d4b81e.svg │ │ │ ├── 5993e47165d45f061fd101cdf2a697bf.svg │ │ │ ├── 59f64f536393f9e861bc745521065466.svg │ │ │ ├── 5bd44ee63d52881e1a401f7464a6e268.svg │ │ │ ├── 5be1f9df879b4689d72760e9f4bf0dfd.svg │ │ │ ├── 5be7f9740d57aef03866f81e2ccc572c.svg │ │ │ ├── 5bef651634e15deeb10473979342806e.svg │ │ │ ├── 5cb27aff6057bc852496fd9fc8f2390d.svg │ │ │ ├── 5df257442bbabb043b75ac6db9a0a76c.svg │ │ │ ├── 5ecefc1b6c456d04472733c137c2fc2f.svg │ │ │ ├── 5ee3887c3b9dd3159333e52093f92345.svg │ │ │ ├── 5f07a75e0b4602664e67e4f21f4ff0d1.svg │ │ │ ├── 5fd810e3705601b70a5add516a4127a0.svg │ │ │ ├── 5ff75fd90c5718a9b3ecb8dc00421429.svg │ │ │ ├── 618571b8fc30d19b022536ef372c10e4.svg │ │ │ ├── 61a887f300f8d186c6ffea7eeff094e9.svg │ │ │ ├── 61d33f2a21657d93f32bfc4946358e99.svg │ │ │ ├── 61df808c835661d586f77238aff050a6.svg │ │ │ ├── 63646eb9c7fb162ba07dcc3331eb4321.woff │ │ │ ├── 637ec89ab052cad77631c380a72dae96.svg │ │ │ ├── 63a9ebf4fb32fcea2238d716b40507dd.svg │ │ │ ├── 6402fdd4373e2e5872395670210b09ff.svg │ │ │ ├── 64fc84e6ed5eced1e97ce9830c1b2380.svg │ │ │ ├── 667e1bd45c5bd6fe32206b64021cbe38.svg │ │ │ ├── 66c06df9665f425bc48837adb97e6902.svg │ │ │ ├── 66c8304a1ea873e2508c83386debe068.svg │ │ │ ├── 69700956dfc5dd9519246c7720fb2b49.svg │ │ │ ├── 6a184f43119a1d196f3fc0bd6e8dea3b.svg │ │ │ ├── 6ae76a66067996ce0b9efc490f0c4439.svg │ │ │ ├── 6befb41c86d857fffe16761835048047.svg │ │ │ ├── 6c301d55ae5fced9aecb48dd72eab4ca.svg │ │ │ ├── 6ce099dc3b7955ef699eacef227ce1f6.svg │ │ │ ├── 6d8f20baaec067acea1429e89988ed1f.svg │ │ │ ├── 6f0e07d1d6bddc4d00cd9d0f8e22bea1.svg │ │ │ ├── 6f4bc8663dcd1dc328dc150970077d71.svg │ │ │ ├── 6fb1103d3f287395c7c5a9e3cd33c40a.svg │ │ │ ├── 708f3d4239b21b059993eb24bd89c29e.eot │ │ │ ├── 70ff7b96b783a7074593f2e29206d67b.svg │ │ │ ├── 71fa415ce733ac3c01e2a894faaa7a0d.svg │ │ │ ├── 7283d56a69b3cc3d949141da790cfb08.svg │ │ │ ├── 746cbfcac47eede5533a5b5ae9ad93bb.svg │ │ │ ├── 749bd8bdbdce60a022cbc5a0b1273678.svg │ │ │ ├── 753c86c411ca6a387efb6d434ae9d3aa.svg │ │ │ ├── 761243b8b79ab99b36d19404e2d8d2e5.svg │ │ │ ├── 76a1bf55ea5892481b9327ef1d026a2d.svg │ │ │ ├── 7763acf22ded58dc59ac367df76a8b16.svg │ │ │ ├── 78797206531d5cd9b88c76e99a604db9.svg │ │ │ ├── 78b358f3aa6e332355f900d133d3eff4.svg │ │ │ ├── 7904c4ced6faaeac36f86734f0c456e8.svg │ │ │ ├── 79382cadc3ef798a1e4843ab25ad15ee.svg │ │ │ ├── 79ba6e3c2d14b2c57c926bae8fddfe72.svg │ │ │ ├── 7b28c4d150bdece38bf2fde2750abf36.svg │ │ │ ├── 7b602d3e01d20b25965fe614f7ee170a.svg │ │ │ ├── 7c5207e424f173999b3d40936d23cb24.svg │ │ │ ├── 7ca8ac543d88f764871657e450140e2a.svg │ │ │ ├── 7d217485b17c6e73ea4f5498fd882ae9.svg │ │ │ ├── 7e384ba6bba38efc8087c4755f45c4da.svg │ │ │ ├── 7eda7cfe70940d17cb21326764a2a5ff.svg │ │ │ ├── 7fb3c1a8b81db1c5e7d803f33bc3c8ed.svg │ │ │ ├── 806e6e3f361f000a504747b2395db843.svg │ │ │ ├── 817c39e227c671101621b8d8a0708489.svg │ │ │ ├── 81957a380875b95df452138d39a718e7.svg │ │ │ ├── 81ba1767aca033283336beb93ee7c845.svg │ │ │ ├── 81d77f96efeb3dda38a5ba10a3086f20.svg │ │ │ ├── 81dae9d589109e3f1a0e5a3a214a2a1c.svg │ │ │ ├── 8252e9bfdbcd82ca9c3f90c88bea7d8c.svg │ │ │ ├── 8355dd6a3ddf89adc9830f992b9bd28d.svg │ │ │ ├── 835a10be123b730a314ddb29f0b2cbad.svg │ │ │ ├── 836379c2140222b10910b4aaeea39657.svg │ │ │ ├── 83a17b118ab7d9a19762ee4a07bcf20f.svg │ │ │ ├── 845944cc6e6d73362a9b7f40a37a1b59.svg │ │ │ ├── 85d4f5d2443429b67a3a229bb80dae62.svg │ │ │ ├── 870ef3b969939abef2b6360b772063c5.svg │ │ │ ├── 878eea621a167b85e70659b77ef9cc89.svg │ │ │ ├── 888d0c163d8c67fa4f9b5ed009259258.svg │ │ │ ├── 88ec96340d618ef1b92038d0c1a841bf.svg │ │ │ ├── 895503a46b73113a6b59f09bd366bd24.svg │ │ │ ├── 89aa3ac81eab471c825cb6ace94f991b.svg │ │ │ ├── 89e7a1201a352eb37f9f11568dc08411.svg │ │ │ ├── 8b04e9882a8f2920cc3d4bfd7b9bdea3.svg │ │ │ ├── 8b3d8f4ab3413f7bdd4d6058e068deb5.svg │ │ │ ├── 8c013431afbeac1c0a0188ae158d3020.svg │ │ │ ├── 8def2fadd8ad3cae53fe460c064e9a81.svg │ │ │ ├── 8e24146131f2b7fdde835aecbfba02db.svg │ │ │ ├── 8e39a2a1a761155dab4be2bfbf18d5a2.svg │ │ │ ├── 8eb827859b2d4feebe22743c0730cda8.svg │ │ │ ├── 8ff7402b410311bd76287f24a27b1d34.svg │ │ │ ├── 9168cfe75e31bdacea8431d8867c22cf.svg │ │ │ ├── 917fc6be0f1b4ae8acab1f9a002f262d.svg │ │ │ ├── 91cf616b95e5ae6df531aeac87cc8427.svg │ │ │ ├── 9200a75ef442733b0c84cfabcd695201.svg │ │ │ ├── 924e8cec15dda01b60323714fe865a6f.svg │ │ │ ├── 92ee5a790e65b67d4f0e05018bb6637c.svg │ │ │ ├── 93a215cd4bea4a40059c7cabdd046514.svg │ │ │ ├── 96980dee5558ff4b27cd8b2c19398f14.svg │ │ │ ├── 96d7ac530243f8faab5b62c6e04fa290.svg │ │ │ ├── 97d879928d89dd9eca9fbd5842339019.svg │ │ │ ├── 980142471e4ec88f974bddf20728cf31.svg │ │ │ ├── 982f8c0e3ab7cd19b88d228fdddae0d5.svg │ │ │ ├── 98f3e61d65b7393a797437b0380aa492.svg │ │ │ ├── 99541ad4cbf69050c95e6405815fee59.svg │ │ │ ├── 9a8dbcaa662599be5e980a068dcf031d.svg │ │ │ ├── 9bcaf0680fc030b391ffb81539b8b778.svg │ │ │ ├── 9d1309edd965ab2193e17471cbbc9e00.svg │ │ │ ├── 9ead3c2be0a5d8600b8d1d3fa462ac71.svg │ │ │ ├── 9f8e248d6e1a98b738dbc5de8efd3cec.svg │ │ │ ├── a03c26ba332af2f3e1637e3d9e1f0d82.svg │ │ │ ├── a07fc86f41614b2d31652b0fde06f30e.svg │ │ │ ├── a1e35d19986200708ab355eb02a74acb.svg │ │ │ ├── a2cdfa4ee5eeed3ba4ec6fba26989a2b.svg │ │ │ ├── a44a1992589f8b1933554780530eb27a.svg │ │ │ ├── a4b204f8ac2f608333c244c963846403.svg │ │ │ ├── a6f5dd9d0dc98d91b7db291a5f682783.svg │ │ │ ├── a7000fb4004c1d6aeec60dd3f6d4fd65.svg │ │ │ ├── a70e41e8f82a4a037a40c72a48702953.svg │ │ │ ├── a87f067bd62baa8dfe0a0188eecd1239.svg │ │ │ ├── a8ed82bb913f6580a5bc6cfb7da63347.svg │ │ │ ├── a93a6747e809c43b85d01cc005f03a8f.svg │ │ │ ├── aa7287a1c446d6d0f54ca2e9e01a2ff0.svg │ │ │ ├── aa83ab33512f9c7afb3d6499891c7f93.svg │ │ │ ├── ac27d16a62e5320b55341d39d53820de.svg │ │ │ ├── aeb5948cb50d85ba5de62379a267b7a8.svg │ │ │ ├── afe26325e1efbea11cc4b75fff3c6c2a.svg │ │ │ ├── afe394d28ed8a3a284e7dadc64c1b8c9.svg │ │ │ ├── b0e1a52fe17361ed7ded541b8046f701.svg │ │ │ ├── b139b8d0a6aceb4b89bd27e86fc0baee.svg │ │ │ ├── b28715adb6121a5d207a9c3a973674c4.svg │ │ │ ├── b2c3af50ca57b933486aa4140ed53d2a.svg │ │ │ ├── b31876a4777251c7a6d1543c8dffb887.svg │ │ │ ├── b3753c38cad90dd24c37f6e98f81ecd1.svg │ │ │ ├── b39b25771d35068f3c94dd8407cf4240.svg │ │ │ ├── b41a546a46b9397f74e1fe802fdf94d2.svg │ │ │ ├── b45b9104e7bbc3c762a7846f2beeef7d.svg │ │ │ ├── b48ea3f80cebc0d390690270e2dddf23.svg │ │ │ ├── b4f46de79fea4f007d09addd654d4e49.svg │ │ │ ├── b5a47ba9c22161ea886c2b238805da6d.svg │ │ │ ├── b5fc8ffccfd4b22c373f03d602053f4f.svg │ │ │ ├── b60d397e09401e498f1bc0d78d851576.svg │ │ │ ├── b6c1cdf742f4d601af01fde608c1743f.svg │ │ │ ├── b6ebe3b4fee19a4cefa9dff70fe72318.svg │ │ │ ├── b75d28391692c79b3520d43e34d7f566.svg │ │ │ ├── b770dcc7727b7ab2e75094f3d7f70c75.svg │ │ │ ├── b86e403f8c14d228deb0475a788e8e64.svg │ │ │ ├── b89186c1d0b76fcc1c8756316a708069.svg │ │ │ ├── b8b78e97a838db782715800cebd39f88.svg │ │ │ ├── b9b286f92869adad1770ee35f4305f80.svg │ │ │ ├── b9fc65f0b79353b28d95f36c4167c5fd.svg │ │ │ ├── bb68b84b67a3105d6f95bd037671a959.svg │ │ │ ├── bc2544cd2f721336d296767abb2468bc.svg │ │ │ ├── bcce3131578604105d40c3f1d9c312f4.svg │ │ │ ├── bd37ee55de795aaa26279684f6db0a2b.svg │ │ │ ├── bd4781d818a0fce73e14ff528f81eaca.svg │ │ │ ├── bdb53b3598f481db088ee173ecbcc90e.svg │ │ │ ├── bf5bcdbf1e484b458c06d4b1a1320e68.svg │ │ │ ├── c127a6838f88dd6e276c5950b03229c4.svg │ │ │ ├── c33010677f26a39c7661afe2cef23d2b.svg │ │ │ ├── c3b2edf4992833159409eeefa21671a9.svg │ │ │ ├── c4edebf5831ff71fa3c9a99ceb08f3e7.svg │ │ │ ├── c58f3d8b73fcd4e1973b916ddc138aef.svg │ │ │ ├── c982d1e5cf833f20088dfc51bf1c7b48.svg │ │ │ ├── c987fc777f727d757d8fe49e0a023856.svg │ │ │ ├── c9bd0d0c625690921f86b526fc28abca.svg │ │ │ ├── ca665413123c772764a1bcd5cb2d5438.svg │ │ │ ├── cbc619d2ce35f68d25273a91c2ef7008.svg │ │ │ ├── ccefb0b99dbb0bbb7894b5f72b59937d.svg │ │ │ ├── cd1f55b02ca2643c3f9930941074ab0f.svg │ │ │ ├── cdbfe8d5d9dedda3b31461c2279a3bb4.svg │ │ │ ├── cdeda2d50c2b6776a8d8fe1efb83514d.svg │ │ │ ├── cdfe4378f3b9cec5d8970773af4188fe.svg │ │ │ ├── ce04235265136eb8d8c3e08c84245fdc.svg │ │ │ ├── ce4527ffebfa10264a74c6864a10e4a9.svg │ │ │ ├── cf72afaefbb020329b34c986e0b6d656.svg │ │ │ ├── d047975de88c64a494fa72ccdc858802.svg │ │ │ ├── d09393ee87fcd68d7067c4d2137f9203.svg │ │ │ ├── d0a7072bf2f0de910204f3dea476df08.svg │ │ │ ├── d134e574d52ebb8c0570a742af44a141.svg │ │ │ ├── d26e6639eeb08dec00885a3b8d54a39f.svg │ │ │ ├── d2b0e987a0cf17cbd234af006785604c.svg │ │ │ ├── d3650ff582a4b94d7247bc9e2e93182c.svg │ │ │ ├── d5ff4688383a2708f70cbea93ebfa1bf.svg │ │ │ ├── d698662001b0492a7bc81a706c8cb2aa.svg │ │ │ ├── d6c82c2d0098885123e33c0980f41d28.svg │ │ │ ├── d712c57a35f415198f32c2998e941ff0.svg │ │ │ ├── d72057feba4dd447b46932c302d90117.svg │ │ │ ├── d72a37c0792ea448ece37308008f1138.svg │ │ │ ├── d7a617ae56cf8ba008870bf4f32a800e.svg │ │ │ ├── d7a83733193d2e4c8c2dba3f2d6e5a9f.svg │ │ │ ├── d7f58eca10ca8fa909b3b4f215ffc38e.svg │ │ │ ├── d89193666cbc922f58c07fdca98ff594.svg │ │ │ ├── d95ef50b1eb9ed18c1518bd238ac4387.svg │ │ │ ├── da7ce6fa45782c29f39f265c19972374.svg │ │ │ ├── da8a9112ae87067d99626518f54ed108.svg │ │ │ ├── dbd0080126f71f19893d360da18f8abd.svg │ │ │ ├── dbfca214cfe8f989857e7df3fb867c15.svg │ │ │ ├── dbffa92e803a5cc83d4ea6a6900a6df4.svg │ │ │ ├── dc17cca0bd2e05636f4747119d2ebbb9.svg │ │ │ ├── df36b747305a82f095b632730a75cbad.svg │ │ │ ├── dff2328608ae1733400ad58fef052247.svg │ │ │ ├── e108533ae7e11018e0dc70ea54c69107.svg │ │ │ ├── e1b1759ccf64e586f9fcbad7c095671c.svg │ │ │ ├── e1ffae80660e1ac3fc3851ff53fac932.svg │ │ │ ├── e25ef0590d3a6f7815b410d0323b1108.svg │ │ │ ├── e2cb4e5eccd5fbed1df98d3e401d7454.svg │ │ │ ├── e353adcbfbd67939a3c4ac2d85876bb1.svg │ │ │ ├── e6cb3a2c375fc72a205b14a22130fb4d.svg │ │ │ ├── e76a6daded06b07e837dfd7d0b921408.svg │ │ │ ├── e7a661ae2f081827b2b386a565b66567.svg │ │ │ ├── ea7d7cda2f2d3255792dcc1153627087.svg │ │ │ ├── ea81b6ddb546b4b6cba1e01b509a9518.svg │ │ │ ├── eac86ee7c3cc6467b0d5b27c56e1f3b0.svg │ │ │ ├── eb8d0ab2badab3da58e9499689b3df13.svg │ │ │ ├── ec48e940536f7bd690f8e567f9a6b9ca.svg │ │ │ ├── ecf540b373d1b812a683933167ab28c0.svg │ │ │ ├── f0d7db0281b36a76685ef91597a8f709.svg │ │ │ ├── f0e56e84434d8300a43a09ac019c1d17.svg │ │ │ ├── f11d58adf67c5e39d2db4f50bd2bf0cf.svg │ │ │ ├── f1543fd885ab4d3db3d942f98a30cb4c.svg │ │ │ ├── f15d5901ccf9ff467b96ebfea08ff80d.svg │ │ │ ├── f34ac49459d6f2b046571faeadac7003.svg │ │ │ ├── f3da706de25d23f89f9c530b06b008fd.svg │ │ │ ├── f46653a45444eea5c760cd2d967262f1.svg │ │ │ ├── f4d75cd2153d4aff6b2df496720125b3.svg │ │ │ ├── f54fab7e266b3d1b390c4530b94d349c.svg │ │ │ ├── f64da0a0b0bcf898c35e2ed23e0e90c4.svg │ │ │ ├── f693d7f2896bf0488313d690136e7f38.svg │ │ │ ├── f6b5bf2c23432efed6b3832c5ed261de.svg │ │ │ ├── f89db516d163a8a820d64c3868a370b5.svg │ │ │ ├── f8dfc14d7d7f08b9f5f2773908259ad4.svg │ │ │ ├── f9c9bf9a80cc6d96dccba0504a849e81.svg │ │ │ ├── fa3a0d10ea0f50aca82ed7a6c1551518.svg │ │ │ ├── fbb16508f3767203f5f14319774d3f61.svg │ │ │ ├── fbdd9806f1e35c0edbc2ea97d7c994b2.svg │ │ │ ├── fc8abeebf8b90cc76634f45369ad5bc4.svg │ │ │ ├── fdff12cddc2011045a963c098fd06292.svg │ │ │ ├── ff89497ff4569bd2a537f07f49d076d5.svg │ │ │ └── ffc25d95190ee9888213146b777b023c.svg │ ├── css │ │ └── main.css │ ├── images │ │ ├── default-avatar.jpg │ │ ├── favicons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── browserconfig.xml │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon.ico │ │ │ ├── mstile-150x150.png │ │ │ ├── safari-pinned-tab.svg │ │ │ └── site.webmanifest │ │ ├── logo-256.png │ │ └── logo-text-vertical-grey.png │ ├── index.html │ ├── js │ │ ├── 0.bundle.0.js │ │ ├── 10.bundle.10.js │ │ ├── 11.bundle.11.js │ │ ├── 12.bundle.12.js │ │ ├── 13.bundle.13.js │ │ ├── 14.bundle.14.js │ │ ├── 15.bundle.15.js │ │ ├── 16.bundle.16.js │ │ ├── 17.bundle.17.js │ │ ├── 18.bundle.18.js │ │ ├── 19.bundle.19.js │ │ ├── 20.bundle.20.js │ │ ├── 21.bundle.21.js │ │ ├── 22.bundle.22.js │ │ ├── 23.bundle.23.js │ │ ├── 24.bundle.24.js │ │ ├── 25.bundle.25.js │ │ ├── 26.bundle.26.js │ │ ├── 27.bundle.27.js │ │ ├── 28.bundle.28.js │ │ ├── 29.bundle.29.js │ │ ├── 3.bundle.3.js │ │ ├── 30.bundle.30.js │ │ ├── 31.bundle.31.js │ │ ├── 32.bundle.32.js │ │ ├── 33.bundle.33.js │ │ ├── 34.bundle.34.js │ │ ├── 35.bundle.35.js │ │ ├── 4.bundle.4.js │ │ ├── 5.bundle.5.js │ │ ├── 6.bundle.6.js │ │ ├── 7.bundle.7.js │ │ ├── 8.bundle.8.js │ │ ├── 9.bundle.9.js │ │ ├── login.bundle.js │ │ └── main.bundle.js │ └── login.html ├── global │ └── certbot-dns-plugins.js ├── index.js ├── internal │ ├── access-list.js │ ├── audit-log.js │ ├── certificate.js │ ├── dead-host.js │ ├── host.js │ ├── ip_ranges.js │ ├── nginx.js │ ├── proxy-host.js │ ├── redirection-host.js │ ├── report.js │ ├── setting.js │ ├── stream.js │ ├── token.js │ └── user.js ├── knexfile.js ├── lib │ ├── access.js │ ├── access │ │ ├── access_lists-create.json │ │ ├── access_lists-delete.json │ │ ├── access_lists-get.json │ │ ├── access_lists-list.json │ │ ├── access_lists-update.json │ │ ├── auditlog-list.json │ │ ├── certificates-create.json │ │ ├── certificates-delete.json │ │ ├── certificates-get.json │ │ ├── certificates-list.json │ │ ├── certificates-update.json │ │ ├── dead_hosts-create.json │ │ ├── dead_hosts-delete.json │ │ ├── dead_hosts-get.json │ │ ├── dead_hosts-list.json │ │ ├── dead_hosts-update.json │ │ ├── permissions.json │ │ ├── proxy_hosts-create.json │ │ ├── proxy_hosts-delete.json │ │ ├── proxy_hosts-get.json │ │ ├── proxy_hosts-list.json │ │ ├── proxy_hosts-update.json │ │ ├── redirection_hosts-create.json │ │ ├── redirection_hosts-delete.json │ │ ├── redirection_hosts-get.json │ │ ├── redirection_hosts-list.json │ │ ├── redirection_hosts-update.json │ │ ├── reports-hosts.json │ │ ├── roles.json │ │ ├── settings-get.json │ │ ├── settings-list.json │ │ ├── settings-update.json │ │ ├── streams-create.json │ │ ├── streams-delete.json │ │ ├── streams-get.json │ │ ├── streams-list.json │ │ ├── streams-update.json │ │ ├── users-create.json │ │ ├── users-delete.json │ │ ├── users-get.json │ │ ├── users-list.json │ │ ├── users-loginas.json │ │ ├── users-password.json │ │ ├── users-permissions.json │ │ └── users-update.json │ ├── error.js │ ├── express │ │ ├── cors.js │ │ ├── jwt-decode.js │ │ ├── jwt.js │ │ ├── pagination.js │ │ └── user-id-from-me.js │ ├── helpers.js │ ├── migrate_template.js │ ├── utils.js │ └── validator │ │ ├── api.js │ │ └── index.js ├── logger.js ├── migrate.js ├── migrations │ ├── 20180618015850_initial.js │ ├── 20180929054513_websockets.js │ ├── 20181019052346_forward_host.js │ ├── 20181113041458_http2_support.js │ ├── 20181213013211_forward_scheme.js │ ├── 20190104035154_disabled.js │ ├── 20190215115310_customlocations.js │ ├── 20190218060101_hsts.js │ ├── 20190227065017_settings.js │ ├── 20200410143839_access_list_client.js │ ├── 20200410143840_access_list_client_fix.js │ ├── 20201014143841_pass_auth.js │ ├── 20210210154702_redirection_scheme.js │ ├── 20210210154703_redirection_status_code.js │ ├── 20210423103500_stream_domain.js │ └── 20211108145214_regenerate_default_host.js ├── models │ ├── access_list.js │ ├── access_list_auth.js │ ├── access_list_client.js │ ├── audit-log.js │ ├── auth.js │ ├── certificate.js │ ├── dead_host.js │ ├── now_helper.js │ ├── proxy_host.js │ ├── redirection_host.js │ ├── setting.js │ ├── stream.js │ ├── token.js │ ├── user.js │ └── user_permission.js ├── nodemon.json ├── package.json ├── routes │ └── api │ │ ├── audit-log.js │ │ ├── main.js │ │ ├── nginx │ │ ├── access_lists.js │ │ ├── certificates.js │ │ ├── dead_hosts.js │ │ ├── proxy_hosts.js │ │ ├── redirection_hosts.js │ │ └── streams.js │ │ ├── reports.js │ │ ├── schema.js │ │ ├── settings.js │ │ ├── tokens.js │ │ └── users.js ├── schema │ ├── definitions.json │ ├── endpoints │ │ ├── access-lists.json │ │ ├── certificates.json │ │ ├── dead-hosts.json │ │ ├── proxy-hosts.json │ │ ├── redirection-hosts.json │ │ ├── settings.json │ │ ├── streams.json │ │ ├── tokens.json │ │ └── users.json │ ├── examples.json │ └── index.json ├── setup.js ├── templates │ ├── _access.conf │ ├── _assets.conf │ ├── _certificates.conf │ ├── _exploits.conf │ ├── _forced_ssl.conf │ ├── _header_comment.conf │ ├── _hsts.conf │ ├── _listen.conf │ ├── _location.conf │ ├── dead_host.conf │ ├── default.conf │ ├── ip_ranges.conf │ ├── letsencrypt-request.conf │ ├── proxy_host.conf │ ├── redirection_host.conf │ └── stream.conf └── yarn.lock ├── docker ├── .dive-ci ├── Dockerfile ├── Dockerfile-zh ├── dev │ └── Dockerfile ├── docker-compose.ci.yml ├── docker-compose.dev.yml ├── rootfs │ ├── bin │ │ ├── check-health │ │ └── handle-ipv6-setting │ ├── etc │ │ ├── letsencrypt.ini │ │ ├── logrotate.d │ │ │ └── nginx-proxy-manager │ │ ├── nginx │ │ │ ├── conf.d │ │ │ │ ├── default.conf │ │ │ │ ├── dev.conf │ │ │ │ ├── include │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── assets.conf │ │ │ │ │ ├── block-exploits.conf │ │ │ │ │ ├── force-ssl.conf │ │ │ │ │ ├── ip_ranges.conf │ │ │ │ │ ├── letsencrypt-acme-challenge.conf │ │ │ │ │ ├── proxy.conf │ │ │ │ │ └── ssl-ciphers.conf │ │ │ │ └── production.conf │ │ │ ├── mime.types │ │ │ └── nginx.conf │ │ └── s6-overlay │ │ │ └── s6-rc.d │ │ │ ├── backend │ │ │ ├── dependencies.d │ │ │ │ └── prepare │ │ │ ├── run │ │ │ └── type │ │ │ ├── frontend │ │ │ ├── dependencies.d │ │ │ │ └── prepare │ │ │ ├── run │ │ │ └── type │ │ │ ├── nginx │ │ │ ├── dependencies.d │ │ │ │ └── prepare │ │ │ ├── run │ │ │ └── type │ │ │ ├── prepare │ │ │ ├── dependencies.d │ │ │ │ └── base │ │ │ ├── script.sh │ │ │ ├── type │ │ │ └── up │ │ │ └── user │ │ │ └── contents.d │ │ │ ├── backend │ │ │ ├── frontend │ │ │ ├── nginx │ │ │ └── prepare │ ├── root │ │ └── .bashrc │ └── var │ │ └── www │ │ └── html │ │ └── index.html └── scripts │ └── install-s6 ├── docs ├── .gitignore ├── .vuepress │ ├── config.js │ ├── public │ │ ├── github.png │ │ ├── icon.png │ │ ├── logo.png │ │ ├── logo.svg │ │ ├── nerd-font.woff2 │ │ ├── robots.txt │ │ └── screenshots │ │ │ ├── access-lists.png │ │ │ ├── audit-log.png │ │ │ ├── certificates.png │ │ │ ├── custom-settings.png │ │ │ ├── dashboard.png │ │ │ ├── dead-hosts.png │ │ │ ├── login.png │ │ │ ├── permissions.png │ │ │ ├── proxy-hosts-add.png │ │ │ ├── proxy-hosts.png │ │ │ └── redirection-hosts.png │ └── styles │ │ ├── index.styl │ │ └── palette.styl ├── README.md ├── advanced-config │ └── README.md ├── faq │ └── README.md ├── guide │ └── README.md ├── package.json ├── screenshots │ └── README.md ├── setup │ └── README.md ├── third-party │ └── README.md ├── upgrading │ └── README.md └── yarn.lock ├── frontend ├── .babelrc ├── .gitignore ├── app-images │ ├── default-avatar.jpg │ ├── favicons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ ├── safari-pinned-tab.svg │ │ └── site.webmanifest │ ├── logo-256.png │ └── logo-text-vertical-grey.png ├── fonts │ ├── feather │ └── source-sans-pro │ │ ├── source-sans-pro-v14-latin-ext_latin-700.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-700.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-700italic.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-700italic.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-italic.woff │ │ ├── source-sans-pro-v14-latin-ext_latin-italic.woff2 │ │ ├── source-sans-pro-v14-latin-ext_latin-regular.woff │ │ └── source-sans-pro-v14-latin-ext_latin-regular.woff2 ├── html │ ├── index.ejs │ ├── login.ejs │ └── partials │ │ ├── footer.ejs │ │ └── header.ejs ├── images ├── js │ ├── app │ │ ├── api.js │ │ ├── audit-log │ │ │ ├── list │ │ │ │ ├── item.ejs │ │ │ │ ├── item.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── main.ejs │ │ │ ├── main.js │ │ │ ├── meta.ejs │ │ │ └── meta.js │ │ ├── cache.js │ │ ├── controller.js │ │ ├── dashboard │ │ │ ├── main.ejs │ │ │ └── main.js │ │ ├── empty │ │ │ ├── main.ejs │ │ │ └── main.js │ │ ├── error │ │ │ ├── main.ejs │ │ │ └── main.js │ │ ├── help │ │ │ ├── main.ejs │ │ │ └── main.js │ │ ├── i18n.js │ │ ├── main.js │ │ ├── nginx │ │ │ ├── access │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── form │ │ │ │ │ ├── client.ejs │ │ │ │ │ ├── client.js │ │ │ │ │ ├── item.ejs │ │ │ │ │ └── item.js │ │ │ │ ├── list │ │ │ │ │ ├── item.ejs │ │ │ │ │ ├── item.js │ │ │ │ │ ├── main.ejs │ │ │ │ │ └── main.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── certificates-list-item.ejs │ │ │ ├── certificates │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── list │ │ │ │ │ ├── item.ejs │ │ │ │ │ ├── item.js │ │ │ │ │ ├── main.ejs │ │ │ │ │ └── main.js │ │ │ │ ├── main.ejs │ │ │ │ ├── main.js │ │ │ │ ├── renew.ejs │ │ │ │ ├── renew.js │ │ │ │ ├── test.ejs │ │ │ │ └── test.js │ │ │ ├── dead │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── list │ │ │ │ │ ├── item.ejs │ │ │ │ │ ├── item.js │ │ │ │ │ ├── main.ejs │ │ │ │ │ └── main.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── proxy │ │ │ │ ├── access-list-item.ejs │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── list │ │ │ │ │ ├── item.ejs │ │ │ │ │ ├── item.js │ │ │ │ │ ├── main.ejs │ │ │ │ │ └── main.js │ │ │ │ ├── location-item.ejs │ │ │ │ ├── location.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── redirection │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── list │ │ │ │ │ ├── item.ejs │ │ │ │ │ ├── item.js │ │ │ │ │ ├── main.ejs │ │ │ │ │ └── main.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ └── stream │ │ │ │ ├── delete.ejs │ │ │ │ ├── delete.js │ │ │ │ ├── form.ejs │ │ │ │ ├── form.js │ │ │ │ ├── list │ │ │ │ ├── item.ejs │ │ │ │ ├── item.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ ├── router.js │ │ ├── settings │ │ │ ├── default-site │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── list │ │ │ │ ├── item.ejs │ │ │ │ ├── item.js │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── main.ejs │ │ │ └── main.js │ │ ├── tokens.js │ │ ├── ui │ │ │ ├── footer │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── header │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ │ ├── main.ejs │ │ │ ├── main.js │ │ │ └── menu │ │ │ │ ├── main.ejs │ │ │ │ └── main.js │ │ ├── user │ │ │ ├── delete.ejs │ │ │ ├── delete.js │ │ │ ├── form.ejs │ │ │ ├── form.js │ │ │ ├── password.ejs │ │ │ ├── password.js │ │ │ ├── permissions.ejs │ │ │ └── permissions.js │ │ └── users │ │ │ ├── list │ │ │ ├── item.ejs │ │ │ ├── item.js │ │ │ ├── main.ejs │ │ │ └── main.js │ │ │ ├── main.ejs │ │ │ └── main.js │ ├── i18n │ │ └── messages.json │ ├── index.js │ ├── lib │ │ ├── helpers.js │ │ └── marionette.js │ ├── login.js │ ├── login │ │ ├── main.js │ │ └── ui │ │ │ ├── login.ejs │ │ │ └── login.js │ └── models │ │ ├── access-list.js │ │ ├── audit-log.js │ │ ├── certificate.js │ │ ├── dead-host.js │ │ ├── proxy-host-location.js │ │ ├── proxy-host.js │ │ ├── redirection-host.js │ │ ├── setting.js │ │ ├── stream.js │ │ └── user.js ├── package.json ├── scss │ ├── custom.scss │ ├── fonts.scss │ ├── selectize.scss │ ├── styles.scss │ └── tabler-extra.scss ├── webpack.config.js └── yarn.lock ├── global └── certbot-dns-plugins.js ├── scripts ├── .common.sh ├── build-zh ├── buildx ├── buildx-zh ├── ci │ ├── frontend-build │ └── test-and-build ├── destroy-dev ├── docs-build ├── docs-upload ├── start-dev ├── stop-dev ├── test-dev └── wait-healthy └── test ├── .dockerignore ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── README.md ├── cypress ├── Dockerfile ├── config │ ├── ci.json │ └── dev.json ├── fixtures │ └── example.json ├── integration │ └── api │ │ ├── Health.spec.js │ │ └── Users.spec.js ├── plugins │ ├── backendApi │ │ ├── client.js │ │ ├── logger.js │ │ └── task.js │ └── index.js └── support │ ├── commands.js │ └── index.js ├── jsconfig.json ├── multi-reporter.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | ._* 4 | .vscode 5 | certbot-help.txt 6 | -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | 2.9.22 2 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | config/development.json 2 | data/* 3 | yarn-error.log 4 | tmp 5 | certbot.log 6 | node_modules 7 | core.* 8 | 9 | -------------------------------------------------------------------------------- /backend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 320, 3 | "tabWidth": 4, 4 | "useTabs": true, 5 | "semi": true, 6 | "singleQuote": true, 7 | "bracketSpacing": true, 8 | "jsxBracketSameLine": true, 9 | "trailingComma": "all", 10 | "proseWrap": "always" 11 | } 12 | -------------------------------------------------------------------------------- /backend/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.insertSpaces": false, 3 | "editor.formatOnSave": true, 4 | "files.trimTrailingWhitespace": true, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll.eslint": true 7 | } 8 | } -------------------------------------------------------------------------------- /backend/config/README.md: -------------------------------------------------------------------------------- 1 | These files are use in development and are not deployed as part of the final product. 2 | -------------------------------------------------------------------------------- /backend/config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "engine": "mysql", 4 | "host": "db", 5 | "name": "npm", 6 | "user": "npm", 7 | "password": "npm", 8 | "port": 3306 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /backend/config/sqlite-test-db.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "engine": "knex-native", 4 | "knex": { 5 | "client": "sqlite3", 6 | "connection": { 7 | "filename": "/app/config/mydb.sqlite" 8 | }, 9 | "pool": { 10 | "min": 0, 11 | "max": 1, 12 | "createTimeoutMillis": 3000, 13 | "acquireTimeoutMillis": 30000, 14 | "idleTimeoutMillis": 30000, 15 | "reapIntervalMillis": 1000, 16 | "createRetryIntervalMillis": 100, 17 | "propagateCreateError": false 18 | }, 19 | "migrations": { 20 | "tableName": "migrations", 21 | "stub": "src/backend/lib/migrate_template.js", 22 | "directory": "src/backend/migrations" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /backend/db.js: -------------------------------------------------------------------------------- 1 | const config = require('config'); 2 | 3 | if (!config.has('database')) { 4 | throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md'); 5 | } 6 | 7 | function generateDbConfig() { 8 | if (config.database.engine === 'knex-native') { 9 | return config.database.knex; 10 | } else 11 | return { 12 | client: config.database.engine, 13 | connection: { 14 | host: config.database.host, 15 | user: config.database.user, 16 | password: config.database.password, 17 | database: config.database.name, 18 | port: config.database.port 19 | }, 20 | migrations: { 21 | tableName: 'migrations' 22 | } 23 | }; 24 | } 25 | 26 | 27 | let data = generateDbConfig(); 28 | 29 | if (typeof config.database.version !== 'undefined') { 30 | data.version = config.database.version; 31 | } 32 | 33 | module.exports = require('knex')(data); 34 | -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700.woff -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700.woff2 -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700italic.woff -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-700italic.woff2 -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-italic.woff -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-italic.woff2 -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-regular.woff -------------------------------------------------------------------------------- /backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/source-sans-pro-v14-latin-ext_latin-regular.woff2 -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/002c4ac5d524b182b619dcb82bb3d63e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/069b07b838df10543f81c55b9c257a1b.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/080f2387b8ea5294a469e7ada4d3da8f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/086ebd78b096b1ae28e255151e9b5033.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/09032b32c871d636121aaf0b20bdc66c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/0ae3a1616fd93697411dcbb4c287ff9d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/0bcef270ef4fe8b473b718e28925f3c7.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/11612d785462813fa6c37a4508c6fb5b.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/131024ae018e4435ae26079ce8b7038b.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/1373eb8769dd878d38ad61a50b8eb291.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/14f839c8391cd7bbd11cddba435006d2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/19b39106bc694a7e4ccf0458fa08b328.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/1a50381e56e0c65af5ca78ee4aa6e566.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/1beb8731e787d165e806ded33ed867b0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/1c37b533c26e19b0e0c67c0909eb68eb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/1d58a8d49089620cbfabdc33f954e677.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2018a70ba79c5d4022e4ab0e262b7b0c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/22d84fe88ebe4c35e1ac0b36dfd935a3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/22fbcf71a6a7feae95bbebf3a819ab94.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/236ee866e6008f711adc2b0c53e8f6f5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/24bd76f285a855b886bea1dbc8aff546.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/28aba54a61e5dcbd2dfea4f8d143b58d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2a27911fc59e5311f422f0185a57f0df.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2a86b695698c807fb6c0512c0b7243f8.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/tabler-ui/2a86b695698c807fb6c0512c0b7243f8.ttf -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2bba212985d834dbb686230b790c0b98.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2c53123099f8c2ce8b95c419108d0b98.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/2f8aa6a3d90c4e52913fa76a2be2e842.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/325806d3f4024c3c4c87965059f654db.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/32b4f3da129df582461489d172623edb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/33a70f15c7966770192ec58f53493d2a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/468af801120c21b0cfb02da5302a1ccf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/46f0df63716157cb114cd9150e2be993.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/472a4da317e89b214a377458c869604e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/509fd847d6d39ef34e36fa74da62f047.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/526844fdfcdee69a0684228c617b0f08.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/54b9926864599fc7f9c78f4b2fe32a56.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/55073d98d77a5b6ce0c1cd3e76d22b2a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/573059db5f8f4570b5c51997665e04b0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/5993e47165d45f061fd101cdf2a697bf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/5bd44ee63d52881e1a401f7464a6e268.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/5ecefc1b6c456d04472733c137c2fc2f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/5f07a75e0b4602664e67e4f21f4ff0d1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/5fd810e3705601b70a5add516a4127a0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/63646eb9c7fb162ba07dcc3331eb4321.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/tabler-ui/63646eb9c7fb162ba07dcc3331eb4321.woff -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/637ec89ab052cad77631c380a72dae96.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/63a9ebf4fb32fcea2238d716b40507dd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/6402fdd4373e2e5872395670210b09ff.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/69700956dfc5dd9519246c7720fb2b49.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/6ae76a66067996ce0b9efc490f0c4439.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/6f4bc8663dcd1dc328dc150970077d71.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/6fb1103d3f287395c7c5a9e3cd33c40a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/708f3d4239b21b059993eb24bd89c29e.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/assets/tabler-ui/708f3d4239b21b059993eb24bd89c29e.eot -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/76a1bf55ea5892481b9327ef1d026a2d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/78797206531d5cd9b88c76e99a604db9.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/78b358f3aa6e332355f900d133d3eff4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/7b602d3e01d20b25965fe614f7ee170a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/7d217485b17c6e73ea4f5498fd882ae9.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/7eda7cfe70940d17cb21326764a2a5ff.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/7fb3c1a8b81db1c5e7d803f33bc3c8ed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/81957a380875b95df452138d39a718e7.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/81dae9d589109e3f1a0e5a3a214a2a1c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/836379c2140222b10910b4aaeea39657.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/85d4f5d2443429b67a3a229bb80dae62.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/870ef3b969939abef2b6360b772063c5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/88ec96340d618ef1b92038d0c1a841bf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/89aa3ac81eab471c825cb6ace94f991b.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/8b3d8f4ab3413f7bdd4d6058e068deb5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/8e24146131f2b7fdde835aecbfba02db.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/8ff7402b410311bd76287f24a27b1d34.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/91cf616b95e5ae6df531aeac87cc8427.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/924e8cec15dda01b60323714fe865a6f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/92ee5a790e65b67d4f0e05018bb6637c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/96980dee5558ff4b27cd8b2c19398f14.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/982f8c0e3ab7cd19b88d228fdddae0d5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/99541ad4cbf69050c95e6405815fee59.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/9a8dbcaa662599be5e980a068dcf031d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/9bcaf0680fc030b391ffb81539b8b778.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/9ead3c2be0a5d8600b8d1d3fa462ac71.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a03c26ba332af2f3e1637e3d9e1f0d82.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a07fc86f41614b2d31652b0fde06f30e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a1e35d19986200708ab355eb02a74acb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a6f5dd9d0dc98d91b7db291a5f682783.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a7000fb4004c1d6aeec60dd3f6d4fd65.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/a8ed82bb913f6580a5bc6cfb7da63347.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/afe394d28ed8a3a284e7dadc64c1b8c9.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b0e1a52fe17361ed7ded541b8046f701.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b139b8d0a6aceb4b89bd27e86fc0baee.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b28715adb6121a5d207a9c3a973674c4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b41a546a46b9397f74e1fe802fdf94d2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b45b9104e7bbc3c762a7846f2beeef7d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b4f46de79fea4f007d09addd654d4e49.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b60d397e09401e498f1bc0d78d851576.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b75d28391692c79b3520d43e34d7f566.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b86e403f8c14d228deb0475a788e8e64.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b89186c1d0b76fcc1c8756316a708069.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b9b286f92869adad1770ee35f4305f80.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/b9fc65f0b79353b28d95f36c4167c5fd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/c127a6838f88dd6e276c5950b03229c4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/c58f3d8b73fcd4e1973b916ddc138aef.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/c9bd0d0c625690921f86b526fc28abca.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/ccefb0b99dbb0bbb7894b5f72b59937d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/cd1f55b02ca2643c3f9930941074ab0f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/cdbfe8d5d9dedda3b31461c2279a3bb4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/cdeda2d50c2b6776a8d8fe1efb83514d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/cdfe4378f3b9cec5d8970773af4188fe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d047975de88c64a494fa72ccdc858802.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d134e574d52ebb8c0570a742af44a141.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d26e6639eeb08dec00885a3b8d54a39f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d2b0e987a0cf17cbd234af006785604c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d712c57a35f415198f32c2998e941ff0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d72057feba4dd447b46932c302d90117.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d7a617ae56cf8ba008870bf4f32a800e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d7a83733193d2e4c8c2dba3f2d6e5a9f.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d7f58eca10ca8fa909b3b4f215ffc38e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/d95ef50b1eb9ed18c1518bd238ac4387.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/da7ce6fa45782c29f39f265c19972374.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/da8a9112ae87067d99626518f54ed108.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/dbffa92e803a5cc83d4ea6a6900a6df4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/df36b747305a82f095b632730a75cbad.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/dff2328608ae1733400ad58fef052247.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/e1b1759ccf64e586f9fcbad7c095671c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/e6cb3a2c375fc72a205b14a22130fb4d.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/e76a6daded06b07e837dfd7d0b921408.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/eb8d0ab2badab3da58e9499689b3df13.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/ec48e940536f7bd690f8e567f9a6b9ca.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/f3da706de25d23f89f9c530b06b008fd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/f4d75cd2153d4aff6b2df496720125b3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/f8dfc14d7d7f08b9f5f2773908259ad4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/assets/tabler-ui/ffc25d95190ee9888213146b777b023c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/frontend/images/default-avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/default-avatar.jpg -------------------------------------------------------------------------------- /backend/frontend/images/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #333333 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /backend/frontend/images/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/favicon.ico -------------------------------------------------------------------------------- /backend/frontend/images/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /backend/frontend/images/favicons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/images/favicons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/images/favicons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /backend/frontend/images/logo-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/logo-256.png -------------------------------------------------------------------------------- /backend/frontend/images/logo-text-vertical-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/backend/frontend/images/logo-text-vertical-grey.png -------------------------------------------------------------------------------- /backend/knexfile.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | development: { 3 | client: 'mysql', 4 | migrations: { 5 | tableName: 'migrations', 6 | stub: 'lib/migrate_template.js', 7 | directory: 'migrations' 8 | } 9 | }, 10 | 11 | production: { 12 | client: 'mysql', 13 | migrations: { 14 | tableName: 'migrations', 15 | stub: 'lib/migrate_template.js', 16 | directory: 'migrations' 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /backend/lib/access/access_lists-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_access_lists", "roles"], 9 | "properties": { 10 | "permission_access_lists": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/access_lists-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_access_lists", "roles"], 9 | "properties": { 10 | "permission_access_lists": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/access_lists-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_access_lists", "roles"], 9 | "properties": { 10 | "permission_access_lists": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/access_lists-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_access_lists", "roles"], 9 | "properties": { 10 | "permission_access_lists": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/access_lists-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_access_lists", "roles"], 9 | "properties": { 10 | "permission_access_lists": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/auditlog-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/certificates-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_certificates", "roles"], 9 | "properties": { 10 | "permission_certificates": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/certificates-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_certificates", "roles"], 9 | "properties": { 10 | "permission_certificates": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/certificates-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_certificates", "roles"], 9 | "properties": { 10 | "permission_certificates": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/certificates-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_certificates", "roles"], 9 | "properties": { 10 | "permission_certificates": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/certificates-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_certificates", "roles"], 9 | "properties": { 10 | "permission_certificates": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/dead_hosts-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_dead_hosts", "roles"], 9 | "properties": { 10 | "permission_dead_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/dead_hosts-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_dead_hosts", "roles"], 9 | "properties": { 10 | "permission_dead_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/dead_hosts-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_dead_hosts", "roles"], 9 | "properties": { 10 | "permission_dead_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/dead_hosts-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_dead_hosts", "roles"], 9 | "properties": { 10 | "permission_dead_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/dead_hosts-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_dead_hosts", "roles"], 9 | "properties": { 10 | "permission_dead_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/permissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "perms", 4 | "definitions": { 5 | "view": { 6 | "type": "string", 7 | "pattern": "^(view|manage)$" 8 | }, 9 | "manage": { 10 | "type": "string", 11 | "pattern": "^(manage)$" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /backend/lib/access/proxy_hosts-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_proxy_hosts", "roles"], 9 | "properties": { 10 | "permission_proxy_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/proxy_hosts-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_proxy_hosts", "roles"], 9 | "properties": { 10 | "permission_proxy_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/proxy_hosts-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_proxy_hosts", "roles"], 9 | "properties": { 10 | "permission_proxy_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/proxy_hosts-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_proxy_hosts", "roles"], 9 | "properties": { 10 | "permission_proxy_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/proxy_hosts-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_proxy_hosts", "roles"], 9 | "properties": { 10 | "permission_proxy_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/redirection_hosts-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_redirection_hosts", "roles"], 9 | "properties": { 10 | "permission_redirection_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/redirection_hosts-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_redirection_hosts", "roles"], 9 | "properties": { 10 | "permission_redirection_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/redirection_hosts-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_redirection_hosts", "roles"], 9 | "properties": { 10 | "permission_redirection_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/redirection_hosts-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_redirection_hosts", "roles"], 9 | "properties": { 10 | "permission_redirection_hosts": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/redirection_hosts-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_redirection_hosts", "roles"], 9 | "properties": { 10 | "permission_redirection_hosts": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/reports-hosts.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/user" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/roles.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "roles", 4 | "definitions": { 5 | "admin": { 6 | "type": "object", 7 | "required": ["scope", "roles"], 8 | "properties": { 9 | "scope": { 10 | "type": "array", 11 | "contains": { 12 | "type": "string", 13 | "pattern": "^user$" 14 | } 15 | }, 16 | "roles": { 17 | "type": "array", 18 | "contains": { 19 | "type": "string", 20 | "pattern": "^admin$" 21 | } 22 | } 23 | } 24 | }, 25 | "user": { 26 | "type": "object", 27 | "required": ["scope"], 28 | "properties": { 29 | "scope": { 30 | "type": "array", 31 | "contains": { 32 | "type": "string", 33 | "pattern": "^user$" 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /backend/lib/access/settings-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/settings-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/settings-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/streams-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_streams", "roles"], 9 | "properties": { 10 | "permission_streams": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/streams-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_streams", "roles"], 9 | "properties": { 10 | "permission_streams": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/streams-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_streams", "roles"], 9 | "properties": { 10 | "permission_streams": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/streams-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_streams", "roles"], 9 | "properties": { 10 | "permission_streams": { 11 | "$ref": "perms#/definitions/view" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/streams-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["permission_streams", "roles"], 9 | "properties": { 10 | "permission_streams": { 11 | "$ref": "perms#/definitions/manage" 12 | }, 13 | "roles": { 14 | "type": "array", 15 | "items": { 16 | "type": "string", 17 | "enum": ["user"] 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/users-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/users-delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/users-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["data", "scope"], 9 | "properties": { 10 | "data": { 11 | "$ref": "objects#/properties/users" 12 | }, 13 | "scope": { 14 | "type": "array", 15 | "contains": { 16 | "type": "string", 17 | "pattern": "^user$" 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/users-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/users-loginas.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/users-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["data", "scope"], 9 | "properties": { 10 | "data": { 11 | "$ref": "objects#/properties/users" 12 | }, 13 | "scope": { 14 | "type": "array", 15 | "contains": { 16 | "type": "string", 17 | "pattern": "^user$" 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/access/users-permissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /backend/lib/access/users-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "anyOf": [ 3 | { 4 | "$ref": "roles#/definitions/admin" 5 | }, 6 | { 7 | "type": "object", 8 | "required": ["data", "scope"], 9 | "properties": { 10 | "data": { 11 | "$ref": "objects#/properties/users" 12 | }, 13 | "scope": { 14 | "type": "array", 15 | "contains": { 16 | "type": "string", 17 | "pattern": "^user$" 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /backend/lib/express/jwt-decode.js: -------------------------------------------------------------------------------- 1 | const Access = require('../access'); 2 | 3 | module.exports = () => { 4 | return function (req, res, next) { 5 | res.locals.access = null; 6 | let access = new Access(res.locals.token || null); 7 | access.load() 8 | .then(() => { 9 | res.locals.access = access; 10 | next(); 11 | }) 12 | .catch(next); 13 | }; 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /backend/lib/express/jwt.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return function (req, res, next) { 3 | if (req.headers.authorization) { 4 | let parts = req.headers.authorization.split(' '); 5 | 6 | if (parts && parts[0] === 'Bearer' && parts[1]) { 7 | res.locals.token = parts[1]; 8 | } 9 | } 10 | 11 | next(); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /backend/lib/express/user-id-from-me.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res, next) => { 2 | if (req.params.user_id === 'me' && res.locals.access) { 3 | req.params.user_id = res.locals.access.token.get('attrs').id; 4 | } else { 5 | req.params.user_id = parseInt(req.params.user_id, 10); 6 | } 7 | 8 | next(); 9 | }; 10 | -------------------------------------------------------------------------------- /backend/lib/helpers.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment'); 2 | 3 | module.exports = { 4 | 5 | /** 6 | * Takes an expression such as 30d and returns a moment object of that date in future 7 | * 8 | * Key Shorthand 9 | * ================== 10 | * years y 11 | * quarters Q 12 | * months M 13 | * weeks w 14 | * days d 15 | * hours h 16 | * minutes m 17 | * seconds s 18 | * milliseconds ms 19 | * 20 | * @param {String} expression 21 | * @returns {Object} 22 | */ 23 | parseDatePeriod: function (expression) { 24 | let matches = expression.match(/^([0-9]+)(y|Q|M|w|d|h|m|s|ms)$/m); 25 | if (matches) { 26 | return moment().add(matches[1], matches[2]); 27 | } 28 | 29 | return null; 30 | } 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /backend/logger.js: -------------------------------------------------------------------------------- 1 | const {Signale} = require('signale'); 2 | 3 | module.exports = { 4 | global: new Signale({scope: 'Global '}), 5 | migrate: new Signale({scope: 'Migrate '}), 6 | express: new Signale({scope: 'Express '}), 7 | access: new Signale({scope: 'Access '}), 8 | nginx: new Signale({scope: 'Nginx '}), 9 | ssl: new Signale({scope: 'SSL '}), 10 | import: new Signale({scope: 'Importer '}), 11 | setup: new Signale({scope: 'Setup '}), 12 | ip_ranges: new Signale({scope: 'IP Ranges'}) 13 | }; 14 | -------------------------------------------------------------------------------- /backend/migrate.js: -------------------------------------------------------------------------------- 1 | const db = require('./db'); 2 | const logger = require('./logger').migrate; 3 | 4 | module.exports = { 5 | latest: function () { 6 | return db.migrate.currentVersion() 7 | .then((version) => { 8 | logger.info('Current database version:', version); 9 | return db.migrate.latest({ 10 | tableName: 'migrations', 11 | directory: 'migrations' 12 | }); 13 | }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /backend/migrations/20181019052346_forward_host.js: -------------------------------------------------------------------------------- 1 | const migrate_name = 'forward_host'; 2 | const logger = require('../logger').migrate; 3 | 4 | /** 5 | * Migrate 6 | * 7 | * @see http://knexjs.org/#Schema 8 | * 9 | * @param {Object} knex 10 | * @param {Promise} Promise 11 | * @returns {Promise} 12 | */ 13 | exports.up = function (knex/*, Promise*/) { 14 | logger.info('[' + migrate_name + '] Migrating Up...'); 15 | 16 | return knex.schema.table('proxy_host', function (proxy_host) { 17 | proxy_host.renameColumn('forward_ip', 'forward_host'); 18 | }) 19 | .then(() => { 20 | logger.info('[' + migrate_name + '] proxy_host Table altered'); 21 | }); 22 | }; 23 | 24 | /** 25 | * Undo Migrate 26 | * 27 | * @param {Object} knex 28 | * @param {Promise} Promise 29 | * @returns {Promise} 30 | */ 31 | exports.down = function (knex, Promise) { 32 | logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); 33 | return Promise.resolve(true); 34 | }; -------------------------------------------------------------------------------- /backend/migrations/20181213013211_forward_scheme.js: -------------------------------------------------------------------------------- 1 | const migrate_name = 'forward_scheme'; 2 | const logger = require('../logger').migrate; 3 | 4 | /** 5 | * Migrate 6 | * 7 | * @see http://knexjs.org/#Schema 8 | * 9 | * @param {Object} knex 10 | * @param {Promise} Promise 11 | * @returns {Promise} 12 | */ 13 | exports.up = function (knex/*, Promise*/) { 14 | logger.info('[' + migrate_name + '] Migrating Up...'); 15 | 16 | return knex.schema.table('proxy_host', function (proxy_host) { 17 | proxy_host.string('forward_scheme').notNull().defaultTo('http'); 18 | }) 19 | .then(() => { 20 | logger.info('[' + migrate_name + '] proxy_host Table altered'); 21 | }); 22 | }; 23 | 24 | /** 25 | * Undo Migrate 26 | * 27 | * @param {Object} knex 28 | * @param {Promise} Promise 29 | * @returns {Promise} 30 | */ 31 | exports.down = function (knex, Promise) { 32 | logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); 33 | return Promise.resolve(true); 34 | }; 35 | -------------------------------------------------------------------------------- /backend/models/now_helper.js: -------------------------------------------------------------------------------- 1 | const db = require('../db'); 2 | const config = require('config'); 3 | const Model = require('objection').Model; 4 | 5 | Model.knex(db); 6 | 7 | module.exports = function () { 8 | if (config.database.knex && config.database.knex.client === 'sqlite3') { 9 | // eslint-disable-next-line 10 | return Model.raw("datetime('now','localtime')"); 11 | } 12 | return Model.raw('NOW()'); 13 | }; 14 | -------------------------------------------------------------------------------- /backend/models/setting.js: -------------------------------------------------------------------------------- 1 | // Objection Docs: 2 | // http://vincit.github.io/objection.js/ 3 | 4 | const db = require('../db'); 5 | const Model = require('objection').Model; 6 | 7 | Model.knex(db); 8 | 9 | class Setting extends Model { 10 | $beforeInsert () { 11 | // Default for meta 12 | if (typeof this.meta === 'undefined') { 13 | this.meta = {}; 14 | } 15 | } 16 | 17 | static get name () { 18 | return 'Setting'; 19 | } 20 | 21 | static get tableName () { 22 | return 'setting'; 23 | } 24 | 25 | static get jsonAttributes () { 26 | return ['meta']; 27 | } 28 | } 29 | 30 | module.exports = Setting; 31 | -------------------------------------------------------------------------------- /backend/models/user_permission.js: -------------------------------------------------------------------------------- 1 | // Objection Docs: 2 | // http://vincit.github.io/objection.js/ 3 | 4 | const db = require('../db'); 5 | const Model = require('objection').Model; 6 | const now = require('./now_helper'); 7 | 8 | Model.knex(db); 9 | 10 | class UserPermission extends Model { 11 | $beforeInsert () { 12 | this.created_on = now(); 13 | this.modified_on = now(); 14 | } 15 | 16 | $beforeUpdate () { 17 | this.modified_on = now(); 18 | } 19 | 20 | static get name () { 21 | return 'UserPermission'; 22 | } 23 | 24 | static get tableName () { 25 | return 'user_permission'; 26 | } 27 | } 28 | 29 | module.exports = UserPermission; 30 | -------------------------------------------------------------------------------- /backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": false, 3 | "ignore": [ 4 | "data" 5 | ], 6 | "ext": "js json ejs" 7 | } 8 | -------------------------------------------------------------------------------- /backend/routes/api/reports.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const jwtdecode = require('../../lib/express/jwt-decode'); 3 | const internalReport = require('../../internal/report'); 4 | 5 | let router = express.Router({ 6 | caseSensitive: true, 7 | strict: true, 8 | mergeParams: true 9 | }); 10 | 11 | router 12 | .route('/hosts') 13 | .options((req, res) => { 14 | res.sendStatus(204); 15 | }) 16 | 17 | /** 18 | * GET /reports/hosts 19 | */ 20 | .get(jwtdecode(), (req, res, next) => { 21 | internalReport.getHostsReport(res.locals.access) 22 | .then((data) => { 23 | res.status(200) 24 | .send(data); 25 | }) 26 | .catch(next); 27 | }); 28 | 29 | module.exports = router; 30 | -------------------------------------------------------------------------------- /backend/schema/examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "examples", 4 | "type": "object", 5 | "definitions": { 6 | "name": { 7 | "description": "Name", 8 | "example": "John Smith", 9 | "type": "string", 10 | "minLength": 1, 11 | "maxLength": 255 12 | }, 13 | "auth_header": { 14 | "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.O_frfYM8RzmRsUNigHtu0_jZ_utSejyr1axMGa8rlsk", 15 | "X-API-Version": "next" 16 | }, 17 | "token": { 18 | "type": "string", 19 | "description": "JWT", 20 | "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.O_frfYM8RzmRsUNigHtu0_jZ_utSejyr1axMGa8rlsk" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /backend/templates/_access.conf: -------------------------------------------------------------------------------- 1 | {% if access_list_id > 0 %} 2 | {% if access_list.items.length > 0 %} 3 | # Authorization 4 | auth_basic "Authorization required"; 5 | auth_basic_user_file /data/access/{{ access_list_id }}; 6 | 7 | {% if access_list.pass_auth == 0 %} 8 | proxy_set_header Authorization ""; 9 | {% endif %} 10 | 11 | {% endif %} 12 | 13 | # Access Rules: {{ access_list.clients | size }} total 14 | {% for client in access_list.clients %} 15 | {{client | nginxAccessRule}} 16 | {% endfor %} 17 | deny all; 18 | 19 | # Access checks must... 20 | {% if access_list.satisfy_any == 1 %} 21 | satisfy any; 22 | {% else %} 23 | satisfy all; 24 | {% endif %} 25 | {% endif %} 26 | -------------------------------------------------------------------------------- /backend/templates/_assets.conf: -------------------------------------------------------------------------------- 1 | {% if caching_enabled == 1 or caching_enabled == true -%} 2 | # Asset Caching 3 | include conf.d/include/assets.conf; 4 | {% endif %} -------------------------------------------------------------------------------- /backend/templates/_certificates.conf: -------------------------------------------------------------------------------- 1 | {% if certificate and certificate_id > 0 -%} 2 | {% if certificate.provider == "letsencrypt" %} 3 | # Let's Encrypt SSL 4 | include conf.d/include/letsencrypt-acme-challenge.conf; 5 | include conf.d/include/ssl-ciphers.conf; 6 | ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem; 7 | ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem; 8 | {% else %} 9 | # Custom SSL 10 | ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem; 11 | ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem; 12 | {% endif %} 13 | {% endif %} 14 | 15 | -------------------------------------------------------------------------------- /backend/templates/_exploits.conf: -------------------------------------------------------------------------------- 1 | {% if block_exploits == 1 or block_exploits == true %} 2 | # Block Exploits 3 | include conf.d/include/block-exploits.conf; 4 | {% endif %} -------------------------------------------------------------------------------- /backend/templates/_forced_ssl.conf: -------------------------------------------------------------------------------- 1 | {% if certificate and certificate_id > 0 -%} 2 | {% if ssl_forced == 1 or ssl_forced == true %} 3 | # Force SSL 4 | include conf.d/include/force-ssl.conf; 5 | {% endif %} 6 | {% endif %} -------------------------------------------------------------------------------- /backend/templates/_header_comment.conf: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------ 2 | # {{ domain_names | join: ", " }} 3 | # ------------------------------------------------------------ -------------------------------------------------------------------------------- /backend/templates/_hsts.conf: -------------------------------------------------------------------------------- 1 | {% if certificate and certificate_id > 0 -%} 2 | {% if ssl_forced == 1 or ssl_forced == true %} 3 | {% if hsts_enabled == 1 or hsts_enabled == true %} 4 | # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years) 5 | add_header Strict-Transport-Security "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always; 6 | {% endif %} 7 | {% endif %} 8 | {% endif %} 9 | -------------------------------------------------------------------------------- /backend/templates/_listen.conf: -------------------------------------------------------------------------------- 1 | listen {{ monitor_port }}; 2 | {% if ipv6 -%} 3 | listen [::]:{{ monitor_port }}; 4 | {% else -%} 5 | #listen [::]:80; 6 | {% endif %} 7 | {% if certificate -%} 8 | listen {{ monitor_ports }} ssl{% if http2_support %} http2{% endif %}; 9 | {% if ipv6 -%} 10 | listen [::]:{{ monitor_ports }} ssl{% if http2_support %} http2{% endif %}; 11 | {% else -%} 12 | #listen [::]:443; 13 | {% endif %} 14 | {% endif %} 15 | server_name {{ domain_names | join: " " }}; 16 | -------------------------------------------------------------------------------- /backend/templates/_location.conf: -------------------------------------------------------------------------------- 1 | location {{ path }} { 2 | proxy_set_header Host $host; 3 | proxy_set_header X-Forwarded-Scheme $scheme; 4 | proxy_set_header X-Forwarded-Proto $scheme; 5 | proxy_set_header X-Forwarded-For $remote_addr; 6 | proxy_set_header X-Real-IP $remote_addr; 7 | proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }}; 8 | 9 | {% include "_access.conf" %} 10 | {% include "_assets.conf" %} 11 | {% include "_exploits.conf" %} 12 | {% include "_forced_ssl.conf" %} 13 | {% include "_hsts.conf" %} 14 | 15 | {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %} 16 | proxy_set_header Upgrade $http_upgrade; 17 | proxy_set_header Connection $http_connection; 18 | proxy_http_version 1.1; 19 | {% endif %} 20 | 21 | 22 | {{ advanced_config }} 23 | } 24 | 25 | -------------------------------------------------------------------------------- /backend/templates/dead_host.conf: -------------------------------------------------------------------------------- 1 | {% include "_header_comment.conf" %} 2 | 3 | {% if enabled %} 4 | server { 5 | {% include "_listen.conf" %} 6 | {% include "_certificates.conf" %} 7 | {% include "_hsts.conf" %} 8 | {% include "_forced_ssl.conf" %} 9 | 10 | access_log /data/logs/dead-host-{{ id }}_access.log standard; 11 | error_log /data/logs/dead-host-{{ id }}_error.log warn; 12 | 13 | {{ advanced_config }} 14 | 15 | {% if use_default_location %} 16 | location / { 17 | {% include "_hsts.conf" %} 18 | return 404; 19 | } 20 | {% endif %} 21 | 22 | } 23 | {% endif %} 24 | -------------------------------------------------------------------------------- /backend/templates/ip_ranges.conf: -------------------------------------------------------------------------------- 1 | {% for range in ip_ranges %} 2 | set_real_ip_from {{ range }}; 3 | {% endfor %} -------------------------------------------------------------------------------- /backend/templates/letsencrypt-request.conf: -------------------------------------------------------------------------------- 1 | {% include "_header_comment.conf" %} 2 | 3 | server { 4 | listen 80; 5 | {% if ipv6 -%} 6 | listen [::]:80; 7 | {% endif %} 8 | 9 | server_name {{ domain_names | join: " " }}; 10 | 11 | access_log /data/logs/letsencrypt-requests_access.log standard; 12 | error_log /data/logs/letsencrypt-requests_error.log warn; 13 | 14 | include conf.d/include/letsencrypt-acme-challenge.conf; 15 | 16 | location / { 17 | return 404; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docker/.dive-ci: -------------------------------------------------------------------------------- 1 | rules: 2 | # If the efficiency is measured below X%, mark as failed. 3 | # Expressed as a ratio between 0-1. 4 | lowestEfficiency: 0.99 5 | 6 | # If the amount of wasted space is at least X or larger than X, mark as failed. 7 | # Expressed in B, KB, MB, and GB. 8 | highestWastedBytes: 15MB 9 | 10 | # If the amount of wasted space makes up for X% or more of the image, mark as failed. 11 | # Note: the base image layer is NOT included in the total image size. 12 | # Expressed as a ratio between 0-1; fails if the threshold is met or crossed. 13 | highestUserWastedPercent: 0.02 14 | 15 | -------------------------------------------------------------------------------- /docker/dev/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jc21/nginx-full:certbot-node 2 | LABEL maintainer="Jamie Curnow " 3 | 4 | ENV S6_LOGGING=0 \ 5 | SUPPRESS_NO_CONFIG_WARNING=1 \ 6 | S6_FIX_ATTRS_HIDDEN=1 7 | 8 | RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ 9 | && apt-get update \ 10 | && apt-get install -y jq python3-pip logrotate \ 11 | && apt-get clean \ 12 | && rm -rf /var/lib/apt/lists/* 13 | 14 | # Task 15 | RUN cd /usr \ 16 | && curl -sL https://taskfile.dev/install.sh | sh \ 17 | && cd /root 18 | 19 | COPY rootfs / 20 | RUN rm -f /etc/nginx/conf.d/production.conf 21 | RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager 22 | 23 | # s6 overlay 24 | COPY scripts/install-s6 /tmp/install-s6 25 | RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6 26 | 27 | EXPOSE 80 81 443 28 | ENTRYPOINT [ "/init" ] 29 | -------------------------------------------------------------------------------- /docker/rootfs/bin/check-health: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OK=$(curl --silent http://127.0.0.1:81/api/ | jq --raw-output '.status') 4 | 5 | if [ "$OK" == "OK" ]; then 6 | echo "OK" 7 | exit 0 8 | else 9 | echo "NOT OK" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /docker/rootfs/etc/letsencrypt.ini: -------------------------------------------------------------------------------- 1 | text = True 2 | non-interactive = True 3 | webroot-path = /data/letsencrypt-acme-challenge 4 | key-type = ecdsa 5 | elliptic-curve = secp384r1 6 | preferred-chain = ISRG Root X1 7 | -------------------------------------------------------------------------------- /docker/rootfs/etc/logrotate.d/nginx-proxy-manager: -------------------------------------------------------------------------------- 1 | /data/logs/*_access.log /data/logs/*/access.log { 2 | create 0644 root root 3 | weekly 4 | rotate 4 5 | missingok 6 | notifempty 7 | compress 8 | sharedscripts 9 | postrotate 10 | /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true 11 | endscript 12 | } 13 | 14 | /data/logs/*_error.log /data/logs/*/error.log { 15 | create 0644 root root 16 | weekly 17 | rotate 10 18 | missingok 19 | notifempty 20 | compress 21 | sharedscripts 22 | postrotate 23 | /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true 24 | endscript 25 | } -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/dev.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 81 default; 3 | listen [::]:81 default; 4 | 5 | server_name nginxproxymanager-dev; 6 | root /app/frontend/dist; 7 | access_log /dev/null; 8 | 9 | location /api { 10 | return 302 /api/; 11 | } 12 | 13 | location /api/ { 14 | add_header X-Served-By $host; 15 | proxy_set_header Host $host; 16 | proxy_set_header X-Forwarded-Scheme $scheme; 17 | proxy_set_header X-Forwarded-Proto $scheme; 18 | proxy_set_header X-Forwarded-For $remote_addr; 19 | proxy_pass http://127.0.0.1:3000/; 20 | 21 | proxy_read_timeout 15m; 22 | proxy_send_timeout 15m; 23 | } 24 | 25 | location / { 26 | index index.html; 27 | try_files $uri $uri.html $uri/ /index.html; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/include/.gitignore: -------------------------------------------------------------------------------- 1 | resolvers.conf 2 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/include/force-ssl.conf: -------------------------------------------------------------------------------- 1 | if ($scheme = "http") { 2 | return 301 https://$host$request_uri; 3 | } 4 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/include/ip_ranges.conf: -------------------------------------------------------------------------------- 1 | # This should be left blank is it is populated programatically 2 | # by the application backend. 3 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/include/proxy.conf: -------------------------------------------------------------------------------- 1 | add_header X-Served-By $host; 2 | proxy_set_header Host $host; 3 | proxy_set_header X-Forwarded-Scheme $scheme; 4 | proxy_set_header X-Forwarded-Proto $scheme; 5 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 6 | proxy_set_header X-Real-IP $remote_addr; 7 | proxy_pass $forward_scheme://$server:$port$request_uri; 8 | 9 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/include/ssl-ciphers.conf: -------------------------------------------------------------------------------- 1 | ssl_session_timeout 5m; 2 | ssl_session_cache shared:SSL:50m; 3 | 4 | # intermediate configuration. tweak to your needs. 5 | ssl_protocols TLSv1.2 TLSv1.3; 6 | ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; 7 | ssl_prefer_server_ciphers off; 8 | -------------------------------------------------------------------------------- /docker/rootfs/etc/nginx/conf.d/production.conf: -------------------------------------------------------------------------------- 1 | # Admin Interface 2 | server { 3 | listen 81 default; 4 | listen [::]:81 default; 5 | 6 | server_name nginxproxymanager; 7 | root /app/frontend; 8 | access_log /dev/null; 9 | 10 | location /api { 11 | return 302 /api/; 12 | } 13 | 14 | location /api/ { 15 | add_header X-Served-By $host; 16 | proxy_set_header Host $host; 17 | proxy_set_header X-Forwarded-Scheme $scheme; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | proxy_set_header X-Forwarded-For $remote_addr; 20 | proxy_pass http://127.0.0.1:3000/; 21 | 22 | proxy_read_timeout 15m; 23 | proxy_send_timeout 15m; 24 | } 25 | 26 | location / { 27 | index index.html; 28 | if ($request_uri ~ ^/(.*)\.html$) { 29 | return 302 /$1; 30 | } 31 | try_files $uri $uri.html $uri/ /index.html; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/backend/dependencies.d/prepare: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/backend/dependencies.d/prepare -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/backend/run: -------------------------------------------------------------------------------- 1 | #!/command/with-contenv bash 2 | # shellcheck shell=bash 3 | 4 | set -e 5 | 6 | echo "❯ Starting backend ..." 7 | if [ "$DEVELOPMENT" == "true" ]; then 8 | cd /app || exit 1 9 | # If yarn install fails: add --verbose --network-concurrency 1 10 | yarn install 11 | node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js 12 | else 13 | cd /app || exit 1 14 | while : 15 | do 16 | node --abort_on_uncaught_exception --max_old_space_size=250 index.js 17 | sleep 1 18 | done 19 | fi 20 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/backend/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/dependencies.d/prepare: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/dependencies.d/prepare -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/run: -------------------------------------------------------------------------------- 1 | #!/command/with-contenv bash 2 | # shellcheck shell=bash 3 | 4 | set -e 5 | 6 | # This service is DEVELOPMENT only. 7 | 8 | if [ "$DEVELOPMENT" == "true" ]; then 9 | cd /app/frontend || exit 1 10 | # If yarn install fails: add --verbose --network-concurrency 1 11 | yarn install 12 | yarn watch 13 | else 14 | exit 0 15 | fi 16 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/frontend/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/prepare: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/prepare -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run: -------------------------------------------------------------------------------- 1 | #!/command/with-contenv bash 2 | # shellcheck shell=bash 3 | 4 | set -e 5 | 6 | echo "❯ Starting nginx ..." 7 | exec nginx 8 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/type: -------------------------------------------------------------------------------- 1 | oneshot 2 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/up: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | /etc/s6-overlay/s6-rc.d/prepare/script.sh 3 | -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/backend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/backend -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/frontend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/frontend -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx -------------------------------------------------------------------------------- /docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/prepare: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docker/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/prepare -------------------------------------------------------------------------------- /docker/rootfs/root/.bashrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -t 1 ]; then 4 | export PS1="\e[1;34m[\e[1;33m\u@\e[1;32mdocker-\h\e[1;37m:\w\[\e[1;34m]\e[1;36m\\$ \e[0m" 5 | fi 6 | 7 | # Aliases 8 | alias l='ls -lAsh --color' 9 | alias ls='ls -C1 --color' 10 | alias cp='cp -ip' 11 | alias rm='rm -i' 12 | alias mv='mv -i' 13 | alias h='cd ~;clear;' 14 | 15 | . /etc/os-release 16 | 17 | echo -e -n '\E[1;34m' 18 | figlet -w 120 "NginxProxyManager" 19 | echo -e "\E[1;36mVersion \E[1;32m${NPM_BUILD_VERSION:-2.0.0-dev} (${NPM_BUILD_COMMIT:-dev}) ${NPM_BUILD_DATE:-0000-00-00}\E[1;36m, OpenResty \E[1;32m${OPENRESTY_VERSION:-unknown}\E[1;36m, ${ID:-debian} \E[1;32m${VERSION:-unknown}\E[1;36m, Certbot \E[1;32m$(certbot --version)\E[0m" 20 | echo -e -n '\E[1;34m' 21 | cat /built-for-arch 22 | echo -e '\E[0m' 23 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .vuepress/dist 2 | node_modules 3 | ts 4 | -------------------------------------------------------------------------------- /docs/.vuepress/public/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/github.png -------------------------------------------------------------------------------- /docs/.vuepress/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/icon.png -------------------------------------------------------------------------------- /docs/.vuepress/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/nerd-font.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/nerd-font.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/access-lists.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/access-lists.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/audit-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/audit-log.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/certificates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/certificates.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/custom-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/custom-settings.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/dashboard.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/dead-hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/dead-hosts.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/login.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/permissions.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/proxy-hosts-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/proxy-hosts-add.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/proxy-hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/proxy-hosts.png -------------------------------------------------------------------------------- /docs/.vuepress/public/screenshots/redirection-hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/docs/.vuepress/public/screenshots/redirection-hosts.png -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | .home .hero img 2 | max-width: 500px !important 3 | min-width: 300px 4 | width: 100% 5 | 6 | .center 7 | margin 0 auto; 8 | width: 80% 9 | 10 | #main-title 11 | display: none 12 | 13 | .hero 14 | margin: 150px 25px 70px 15 | 16 | @font-face 17 | font-family: 'Nerd Font'; 18 | src: url("/nerd-font.woff2") format("woff2"); 19 | font-weight: 400; 20 | font-style: normal 21 | 22 | code 23 | font-family: 'Nerd Font', source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 24 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | $accentColor = #f15833 2 | $textColor = #663015 3 | $borderColor = #eaecef 4 | $codeBgColor = #282c34 5 | -------------------------------------------------------------------------------- /docs/guide/README.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /docs/third-party/README.md: -------------------------------------------------------------------------------- 1 | # Third Party 2 | 3 | As this software gains popularity it's common to see it integrated with other platforms. Please be aware that unless specifically mentioned in the documentation of those 4 | integrations, they are *not supported* by me. 5 | 6 | Known integrations: 7 | 8 | - [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager) 9 | - [UnRaid / Synology](https://github.com/jlesage/docker-nginx-proxy-manager) 10 | - [Proxmox Scripts](https://github.com/ej52/proxmox-scripts/tree/main/lxc/nginx-proxy-manager) 11 | - [nginxproxymanagerGraf](https://github.com/ma-karai/nginxproxymanagerGraf) 12 | 13 | 14 | If you would like your integration of NPM listed, please open a 15 | [Github issue](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) 16 | 17 | -------------------------------------------------------------------------------- /docs/upgrading/README.md: -------------------------------------------------------------------------------- 1 | # Upgrading 2 | 3 | ```bash 4 | docker-compose pull 5 | docker-compose up -d 6 | ``` 7 | 8 | This project will automatically update any databases or other requirements so you don't have to follow 9 | any crazy instructions. These steps above will pull the latest updates and recreate the docker 10 | containers. 11 | 12 | -------------------------------------------------------------------------------- /frontend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "browsers": [ 8 | "Chrome >= 65" 9 | ] 10 | }, 11 | "debug": false, 12 | "modules": false, 13 | "useBuiltIns": "usage" 14 | } 15 | ] 16 | ] 17 | } -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | webpack_stats.html 4 | yarn-error.log 5 | -------------------------------------------------------------------------------- /frontend/app-images/default-avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/default-avatar.jpg -------------------------------------------------------------------------------- /frontend/app-images/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #333333 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /frontend/app-images/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/favicon.ico -------------------------------------------------------------------------------- /frontend/app-images/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /frontend/app-images/favicons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/images/favicons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/images/favicons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /frontend/app-images/logo-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/logo-256.png -------------------------------------------------------------------------------- /frontend/app-images/logo-text-vertical-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/app-images/logo-text-vertical-grey.png -------------------------------------------------------------------------------- /frontend/fonts/feather: -------------------------------------------------------------------------------- 1 | ../node_modules/tabler-ui/dist/assets/fonts/feather -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff2 -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff2 -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff2 -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff -------------------------------------------------------------------------------- /frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2691432189/nginx-proxy-manager-monitor-zh/c79f4f9bc7c20693efc2459fc053b08133b5954e/frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff2 -------------------------------------------------------------------------------- /frontend/html/index.ejs: -------------------------------------------------------------------------------- 1 | <% var title = 'Nginx 代理管理器' %> 2 | <%- include partials/header.ejs %> 3 | 4 |
5 | 6 |
7 | 8 | 9 | <%- include partials/footer.ejs %> 10 | -------------------------------------------------------------------------------- /frontend/html/login.ejs: -------------------------------------------------------------------------------- 1 | <% var title = '登录 – Nginx 代理管理器' %> 2 | <%- include partials/header.ejs %> 3 | 4 |
5 | 6 |
7 | 8 | 9 | <%- include partials/footer.ejs %> 10 | -------------------------------------------------------------------------------- /frontend/html/partials/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /frontend/images: -------------------------------------------------------------------------------- 1 | ./node_modules/tabler-ui/dist/assets/images -------------------------------------------------------------------------------- /frontend/js/app/audit-log/list/item.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const Controller = require('../../controller'); 3 | const template = require('./item.ejs'); 4 | 5 | module.exports = Mn.View.extend({ 6 | template: template, 7 | tagName: 'tr', 8 | 9 | ui: { 10 | meta: 'a.meta' 11 | }, 12 | 13 | events: { 14 | 'click @ui.meta': function (e) { 15 | e.preventDefault(); 16 | Controller.showAuditMeta(this.model); 17 | } 18 | }, 19 | 20 | templateContext: { 21 | more: function() { 22 | switch (this.object_type) { 23 | case 'redirection-host': 24 | case 'stream': 25 | case 'proxy-host': 26 | return this.meta.domain_names.join(', '); 27 | } 28 | 29 | return '#' + (this.object_id || '?'); 30 | } 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/audit-log/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | User 4 | Event 5 |   6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /frontend/js/app/audit-log/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const ItemView = require('./item'); 3 | const template = require('./main.ejs'); 4 | 5 | const TableBody = Mn.CollectionView.extend({ 6 | tagName: 'tbody', 7 | childView: ItemView 8 | }); 9 | 10 | module.exports = Mn.View.extend({ 11 | tagName: 'table', 12 | className: 'table table-hover table-outline table-vcenter card-table', 13 | template: template, 14 | 15 | regions: { 16 | body: { 17 | el: 'tbody', 18 | replaceElement: true 19 | } 20 | }, 21 | 22 | onRender: function () { 23 | this.showChildView('body', new TableBody({ 24 | collection: this.collection 25 | })); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /frontend/js/app/audit-log/meta.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./meta.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | template: template, 6 | className: 'modal-dialog wide' 7 | }); 8 | -------------------------------------------------------------------------------- /frontend/js/app/cache.js: -------------------------------------------------------------------------------- 1 | const UserModel = require('../models/user'); 2 | 3 | let cache = { 4 | User: new UserModel.Model(), 5 | locale: 'zh', 6 | version: null 7 | }; 8 | 9 | module.exports = cache; 10 | 11 | -------------------------------------------------------------------------------- /frontend/js/app/empty/main.ejs: -------------------------------------------------------------------------------- 1 | <% if (title) { %> 2 |

<%- title %>

3 | <% } 4 | 5 | if (subtitle) { %> 6 |

<%- subtitle %>

7 | <% } 8 | 9 | if (link) { %> 10 | <%- link %> 11 | <% } %> 12 | -------------------------------------------------------------------------------- /frontend/js/app/empty/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./main.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | className: 'text-center m-7', 6 | template: template, 7 | 8 | options: { 9 | btn_color: 'teal' 10 | }, 11 | 12 | ui: { 13 | action: 'a' 14 | }, 15 | 16 | events: { 17 | 'click @ui.action': function (e) { 18 | e.preventDefault(); 19 | this.getOption('action')(); 20 | } 21 | }, 22 | 23 | templateContext: function () { 24 | return { 25 | title: this.getOption('title'), 26 | subtitle: this.getOption('subtitle'), 27 | link: this.getOption('link'), 28 | action: typeof this.getOption('action') === 'function', 29 | btn_color: this.getOption('btn_color') 30 | }; 31 | } 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /frontend/js/app/error/main.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%= code ? '' + code + ' — ' : '' %> 3 | <%- message %> 4 | 5 | <% if (retry) { %> 6 |

<%- i18n('str', 'try-again') %> 7 | <% } %> 8 | -------------------------------------------------------------------------------- /frontend/js/app/error/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./main.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | template: template, 6 | className: 'alert alert-icon alert-warning m-5', 7 | 8 | ui: { 9 | retry: 'a.retry' 10 | }, 11 | 12 | events: { 13 | 'click @ui.retry': function (e) { 14 | e.preventDefault(); 15 | this.getOption('retry')(); 16 | } 17 | }, 18 | 19 | templateContext: function () { 20 | return { 21 | message: this.getOption('message'), 22 | code: this.getOption('code'), 23 | retry: typeof this.getOption('retry') === 'function' 24 | }; 25 | } 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /frontend/js/app/help/main.ejs: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /frontend/js/app/help/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./main.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | template: template, 6 | className: 'modal-dialog wide', 7 | 8 | templateContext: function () { 9 | let content = this.getOption('content').split("\n"); 10 | 11 | return { 12 | title: this.getOption('title'), 13 | content: '

' + content.join('

') + '

' 14 | }; 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /frontend/js/app/i18n.js: -------------------------------------------------------------------------------- 1 | const Cache = ('./cache'); 2 | const messages = require('../i18n/messages.json'); 3 | 4 | /** 5 | * @param {String} namespace 6 | * @param {String} key 7 | * @param {Object} [data] 8 | */ 9 | module.exports = function (namespace, key, data) { 10 | let locale = Cache.locale; 11 | // check that the locale exists 12 | if (typeof messages[locale] === 'undefined') { 13 | locale = 'zh'; 14 | } 15 | 16 | if (typeof messages[locale][namespace] !== 'undefined' && typeof messages[locale][namespace][key] !== 'undefined') { 17 | return messages[locale][namespace][key](data); 18 | } else if (locale !== 'zh' && typeof messages['zh'][namespace] !== 'undefined' && typeof messages['zh'][namespace][key] !== 'undefined') { 19 | return messages['zh'][namespace][key](data); 20 | } 21 | 22 | return '(MISSING: ' + namespace + '/' + key + ')'; 23 | }; 24 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/form/client.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/form/client.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./client.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | template: template, 6 | className: 'row' 7 | }); 8 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/form/item.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/form/item.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./item.ejs'); 3 | 4 | module.exports = Mn.View.extend({ 5 | template: template, 6 | className: 'row' 7 | }); 8 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/list/item.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const template = require('./item.ejs'); 4 | 5 | module.exports = Mn.View.extend({ 6 | template: template, 7 | tagName: 'tr', 8 | 9 | ui: { 10 | edit: 'a.edit', 11 | delete: 'a.delete' 12 | }, 13 | 14 | events: { 15 | 'click @ui.edit': function (e) { 16 | e.preventDefault(); 17 | App.Controller.showNginxAccessListForm(this.model); 18 | }, 19 | 20 | 'click @ui.delete': function (e) { 21 | e.preventDefault(); 22 | App.Controller.showNginxAccessListDeleteConfirm(this.model); 23 | } 24 | }, 25 | 26 | templateContext: { 27 | canManage: App.Cache.User.canManage('access_lists') 28 | }, 29 | 30 | initialize: function () { 31 | this.listenTo(this.model, 'change', this.render); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'name') %> 4 | <%- i18n('access-lists', 'authorization') %> 5 | <%- i18n('access-lists', 'access') %> 6 | <%- i18n('access-lists', 'satisfy') %> 7 | <%- i18n('proxy-hosts', 'title') %> 8 | <% if (canManage) { %> 9 |   10 | <% } %> 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/access/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('access_lists') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates-list-item.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (id === 'new') { %> 3 |
4 | <%- i18n('all-hosts', 'new-cert') %> 5 |
6 | <%- i18n('all-hosts', 'with-le') %> 7 | <% } else if (id > 0) { %> 8 |
9 | <%- provider === 'other' ? nice_name : domain_names.join(', ') %> 10 |
11 | <%- i18n('ssl', provider) %> – Expires: <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %> 12 | <% } else { %> 13 |
14 | <%- i18n('all-hosts', 'none') %> 15 |
16 | <%- i18n('all-hosts', 'no-ssl') %> 17 | <% } %> 18 |
19 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates/delete.ejs: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'name') %> 4 | <%- i18n('all-hosts', 'cert-provider') %> 5 | <%- i18n('str', 'expires') %> 6 | <% if (canManage) { %> 7 |   8 | <% } %> 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('certificates') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates/renew.ejs: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/certificates/test.ejs: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/dead/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'source') %> 4 | <%- i18n('str', 'ssl') %> 5 | <%- i18n('str', 'status') %> 6 | <% if (canManage) { %> 7 |   8 | <% } %> 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/dead/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('dead_hosts') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/proxy/access-list-item.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if (id > 0) { %> 3 |
4 | <%- name %> 5 |
6 | <%- i18n('access-lists', 'item-count', {count: items.length || 0}) %>, <%- i18n('access-lists', 'client-count', {count: clients.length || 0}) %> – Created: <%- formatDbDate(created_on, 'Do MMMM YYYY, h:mm a') %> 7 | <% } else { %> 8 |
9 | <%- i18n('access-lists', 'public') %> 10 |
11 | <%- i18n('access-lists', 'public-sub') %> 12 | <% } %> 13 |
14 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/proxy/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'source') %> 4 | <%- i18n('str', 'destination') %> 5 | <%- i18n('str', 'ssl') %> 6 | <%- i18n('str', 'access') %> 7 | <%- i18n('str', 'status') %> 8 | <% if (canManage) { %> 9 |   10 | <% } %> 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/proxy/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('proxy_hosts') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/redirection/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'source') %> 4 | <%- i18n('redirection-hosts', 'forward-http-status-code') %> 5 | <%- i18n('redirection-hosts', 'forward-scheme') %> 6 | <%- i18n('str', 'destination') %> 7 | <%- i18n('str', 'ssl') %> 8 | <%- i18n('str', 'status') %> 9 | <% if (canManage) { %> 10 |   11 | <% } %> 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/redirection/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('redirection_hosts') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/stream/delete.ejs: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/stream/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('streams', 'incoming-port') %> 4 | <%- i18n('str', 'destination') %> 5 | <%- i18n('streams', 'protocol') %> 6 | <%- i18n('str', 'status') %> 7 | <% if (canManage) { %> 8 |   9 | <% } %> 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/js/app/nginx/stream/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../../main'); 3 | const ItemView = require('./item'); 4 | const template = require('./main.ejs'); 5 | 6 | const TableBody = Mn.CollectionView.extend({ 7 | tagName: 'tbody', 8 | childView: ItemView 9 | }); 10 | 11 | module.exports = Mn.View.extend({ 12 | tagName: 'table', 13 | className: 'table table-hover table-outline table-vcenter card-table', 14 | template: template, 15 | 16 | regions: { 17 | body: { 18 | el: 'tbody', 19 | replaceElement: true 20 | } 21 | }, 22 | 23 | templateContext: { 24 | canManage: App.Cache.User.canManage('streams') 25 | }, 26 | 27 | onRender: function () { 28 | this.showChildView('body', new TableBody({ 29 | collection: this.collection 30 | })); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /frontend/js/app/router.js: -------------------------------------------------------------------------------- 1 | const AppRouter = require('marionette.approuter'); 2 | const Controller = require('./controller'); 3 | 4 | module.exports = AppRouter.default.extend({ 5 | controller: Controller, 6 | appRoutes: { 7 | users: 'showUsers', 8 | logout: 'logout', 9 | 'nginx/proxy': 'showNginxProxy', 10 | 'nginx/redirection': 'showNginxRedirection', 11 | 'nginx/404': 'showNginxDead', 12 | 'nginx/stream': 'showNginxStream', 13 | 'nginx/access': 'showNginxAccess', 14 | 'nginx/certificates': 'showNginxCertificates', 15 | 'audit-log': 'showAuditLog', 16 | 'settings': 'showSettings', 17 | '*default': 'showDashboard' 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /frontend/js/app/settings/list/item.ejs: -------------------------------------------------------------------------------- 1 | 2 |
<%- name %>
3 |
4 | <%- description %> 5 |
6 | 7 | 8 |
9 | <% if (id === 'default-site') { %> 10 | <%- i18n('settings', 'default-site-' + value) %> 11 | <% } %> 12 |
13 | 14 | 15 | 21 | -------------------------------------------------------------------------------- /frontend/js/app/settings/list/item.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const App = require('../../main'); 3 | const template = require('./item.ejs'); 4 | 5 | module.exports = Mn.View.extend({ 6 | template: template, 7 | tagName: 'tr', 8 | 9 | ui: { 10 | edit: 'a.edit' 11 | }, 12 | 13 | events: { 14 | 'click @ui.edit': function (e) { 15 | e.preventDefault(); 16 | App.Controller.showSettingForm(this.model); 17 | } 18 | }, 19 | 20 | initialize: function () { 21 | this.listenTo(this.model, 'change', this.render); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /frontend/js/app/settings/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%- i18n('str', 'name') %> 3 | <%- i18n('str', 'value') %> 4 |   5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /frontend/js/app/settings/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const ItemView = require('./item'); 3 | const template = require('./main.ejs'); 4 | 5 | const TableBody = Mn.CollectionView.extend({ 6 | tagName: 'tbody', 7 | childView: ItemView 8 | }); 9 | 10 | module.exports = Mn.View.extend({ 11 | tagName: 'table', 12 | className: 'table table-hover table-outline table-vcenter card-table', 13 | template: template, 14 | 15 | regions: { 16 | body: { 17 | el: 'tbody', 18 | replaceElement: true 19 | } 20 | }, 21 | 22 | onRender: function () { 23 | this.showChildView('body', new TableBody({ 24 | collection: this.collection 25 | })); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /frontend/js/app/settings/main.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

<%- i18n('settings', 'title') %>

5 |
6 |
7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /frontend/js/app/ui/footer/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const template = require('./main.ejs'); 3 | const Cache = require('../../cache'); 4 | 5 | module.exports = Mn.View.extend({ 6 | className: 'container', 7 | template: template, 8 | 9 | templateContext: { 10 | getVersion: function () { 11 | return Cache.version || '0.0.0'; 12 | } 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /frontend/js/app/ui/main.ejs: -------------------------------------------------------------------------------- 1 |
2 | 10 |
11 |
12 | 13 |
14 |
15 |
16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /frontend/js/app/user/delete.ejs: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /frontend/js/app/users/list/main.ejs: -------------------------------------------------------------------------------- 1 | 2 |   3 | <%- i18n('str', 'name') %> 4 | <%- i18n('str', 'email') %> 5 | <%- i18n('str', 'roles') %> 6 |   7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/js/app/users/list/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const ItemView = require('./item'); 3 | const template = require('./main.ejs'); 4 | 5 | const TableBody = Mn.CollectionView.extend({ 6 | tagName: 'tbody', 7 | childView: ItemView 8 | }); 9 | 10 | module.exports = Mn.View.extend({ 11 | tagName: 'table', 12 | className: 'table table-hover table-outline table-vcenter card-table', 13 | template: template, 14 | 15 | regions: { 16 | body: { 17 | el: 'tbody', 18 | replaceElement: true 19 | } 20 | }, 21 | 22 | onRender: function () { 23 | this.showChildView('body', new TableBody({ 24 | collection: this.collection 25 | })); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /frontend/js/lib/helpers.js: -------------------------------------------------------------------------------- 1 | const numeral = require('numeral'); 2 | const moment = require('moment'); 3 | 4 | module.exports = { 5 | 6 | /** 7 | * @param {Integer} number 8 | * @returns {String} 9 | */ 10 | niceNumber: function (number) { 11 | return numeral(number).format('0,0'); 12 | }, 13 | 14 | /** 15 | * @param {String|Number} date 16 | * @param {String} format 17 | * @returns {String} 18 | */ 19 | formatDbDate: function (date, format) { 20 | if (typeof date === 'number') { 21 | return moment.unix(date).format(format); 22 | } 23 | 24 | return moment(date).format(format); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /frontend/js/lib/marionette.js: -------------------------------------------------------------------------------- 1 | const _ = require('underscore'); 2 | const Mn = require('backbone.marionette'); 3 | const i18n = require('../app/i18n'); 4 | const Helpers = require('./helpers'); 5 | const TemplateCache = require('marionette.templatecache'); 6 | 7 | Mn.setRenderer(function (template, data, view) { 8 | data = _.clone(data); 9 | data.i18n = i18n; 10 | data.formatDbDate = Helpers.formatDbDate; 11 | 12 | return TemplateCache.default.render.call(this, template, data, view); 13 | }); 14 | 15 | module.exports = Mn; 16 | -------------------------------------------------------------------------------- /frontend/js/login.js: -------------------------------------------------------------------------------- 1 | const App = require('./login/main'); 2 | 3 | $(document).ready(() => { 4 | App.start(); 5 | }); 6 | -------------------------------------------------------------------------------- /frontend/js/login/main.js: -------------------------------------------------------------------------------- 1 | const Mn = require('backbone.marionette'); 2 | const LoginView = require('./ui/login'); 3 | 4 | const App = Mn.Application.extend({ 5 | region: '#login', 6 | UI: null, 7 | 8 | onStart: function (/*app, options*/) { 9 | this.getRegion().show(new LoginView()); 10 | } 11 | }); 12 | 13 | const app = new App(); 14 | module.exports = app; 15 | -------------------------------------------------------------------------------- /frontend/js/models/access-list.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function () { 7 | return { 8 | id: undefined, 9 | created_on: null, 10 | modified_on: null, 11 | name: '', 12 | items: [], 13 | clients: [], 14 | // The following are expansions: 15 | owner: null 16 | }; 17 | } 18 | }); 19 | 20 | module.exports = { 21 | Model: model, 22 | Collection: Backbone.Collection.extend({ 23 | model: model 24 | }) 25 | }; 26 | -------------------------------------------------------------------------------- /frontend/js/models/audit-log.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function () { 7 | return { 8 | name: '' 9 | }; 10 | } 11 | }); 12 | 13 | module.exports = { 14 | Model: model, 15 | Collection: Backbone.Collection.extend({ 16 | model: model 17 | }) 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/js/models/dead-host.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function () { 7 | return { 8 | id: undefined, 9 | created_on: null, 10 | modified_on: null, 11 | domain_names: [], 12 | certificate_id: 0, 13 | ssl_forced: false, 14 | http2_support: false, 15 | hsts_enabled: false, 16 | hsts_subdomains: false, 17 | enabled: true, 18 | meta: {}, 19 | advanced_config: '', 20 | // The following are expansions: 21 | owner: null, 22 | certificate: null 23 | }; 24 | } 25 | }); 26 | 27 | module.exports = { 28 | Model: model, 29 | Collection: Backbone.Collection.extend({ 30 | model: model 31 | }) 32 | }; 33 | -------------------------------------------------------------------------------- /frontend/js/models/proxy-host-location.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function() { 7 | return { 8 | opened: false, 9 | path: '', 10 | advanced_config: '', 11 | forward_scheme: 'http', 12 | forward_host: '', 13 | forward_port: '80' 14 | } 15 | }, 16 | 17 | toJSON() { 18 | const r = Object.assign({}, this.attributes); 19 | delete r.opened; 20 | return r; 21 | }, 22 | 23 | toggleVisibility: function () { 24 | this.save({ 25 | opened: !this.get('opened') 26 | }); 27 | } 28 | }) 29 | 30 | module.exports = { 31 | Model: model, 32 | Collection: Backbone.Collection.extend({ 33 | model 34 | }) 35 | } -------------------------------------------------------------------------------- /frontend/js/models/setting.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function () { 7 | return { 8 | id: undefined, 9 | name: '', 10 | description: '', 11 | value: null, 12 | meta: [] 13 | }; 14 | } 15 | }); 16 | 17 | module.exports = { 18 | Model: model, 19 | Collection: Backbone.Collection.extend({ 20 | model: model 21 | }) 22 | }; 23 | -------------------------------------------------------------------------------- /frontend/js/models/stream.js: -------------------------------------------------------------------------------- 1 | const Backbone = require('backbone'); 2 | 3 | const model = Backbone.Model.extend({ 4 | idAttribute: 'id', 5 | 6 | defaults: function () { 7 | return { 8 | id: undefined, 9 | created_on: null, 10 | modified_on: null, 11 | incoming_port: null, 12 | forwarding_host: null, 13 | forwarding_port: null, 14 | tcp_forwarding: true, 15 | udp_forwarding: false, 16 | enabled: true, 17 | meta: {}, 18 | // The following are expansions: 19 | owner: null 20 | }; 21 | } 22 | }); 23 | 24 | module.exports = { 25 | Model: model, 26 | Collection: Backbone.Collection.extend({ 27 | model: model 28 | }) 29 | }; 30 | -------------------------------------------------------------------------------- /frontend/scss/custom.scss: -------------------------------------------------------------------------------- 1 | $primary-color: #2bcbba; 2 | 3 | .loader { 4 | color: $primary-color; 5 | } 6 | 7 | a { 8 | color: $primary-color; 9 | } 10 | 11 | a:hover { 12 | color: darken($primary-color, 10%); 13 | } 14 | 15 | .dropdown-header { 16 | padding-left: 1rem; 17 | } 18 | 19 | .dropdown-item.active, .dropdown-item:active { 20 | background-color: $primary-color; 21 | } 22 | 23 | .custom-switch-input:checked ~ .custom-switch-indicator { 24 | background: $primary-color; 25 | } 26 | 27 | .min-100 { 28 | min-height: 100px; 29 | } 30 | 31 | .card-options .dropdown-menu a:not(.btn) { 32 | margin-left: 0; 33 | } 34 | 35 | .wrap { 36 | display: flex; 37 | flex-wrap: wrap; 38 | } 39 | 40 | .col-login { 41 | max-width: 48rem; 42 | } -------------------------------------------------------------------------------- /frontend/scss/styles.scss: -------------------------------------------------------------------------------- 1 | @import "~tabler-ui/dist/assets/css/dashboard"; 2 | @import "tabler-extra"; 3 | @import "fonts"; 4 | @import "selectize"; 5 | @import "custom"; 6 | 7 | /* Before any JS content is loaded */ 8 | #app > .loader, #login > .loader, .container > .loader { 9 | position: absolute; 10 | left: 49%; 11 | top: 40%; 12 | display: block; 13 | } 14 | 15 | .no-js-warning { 16 | margin-top: 100px; 17 | } 18 | -------------------------------------------------------------------------------- /scripts/.common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Colors 4 | BLUE='\E[1;34m' 5 | CYAN='\E[1;36m' 6 | GREEN='\E[1;32m' 7 | RED='\E[1;31m' 8 | RESET='\E[0m' 9 | YELLOW='\E[1;33m' 10 | 11 | export BLUE CYAN GREEN RED RESET YELLOW 12 | 13 | # Docker Compose 14 | COMPOSE_PROJECT_NAME="npmdev" 15 | COMPOSE_FILE="docker/docker-compose.dev.yml" 16 | 17 | export COMPOSE_FILE COMPOSE_PROJECT_NAME 18 | -------------------------------------------------------------------------------- /scripts/build-zh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/ci/frontend-build" 5 | 6 | cd "${DIR}/../.." 7 | 8 | docker build -t nginx-proxy-manager-monitor-zh:2.9.22 -f docker/Dockerfile-zh . 9 | -------------------------------------------------------------------------------- /scripts/buildx-zh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/ci/frontend-build" 5 | 6 | cd "${DIR}/../.." 7 | 8 | # Buildx Builder 9 | docker buildx create --name "Buildx-NPM" || echo 10 | docker buildx use "Buildx-NPM" 11 | 12 | if [ "${BUILD_TAG:-0}" != 0 ]; then 13 | docker buildx build -f docker/Dockerfile-zh $BUILD_TAG --platform $BUILD_PLATFORM . --push 14 | else 15 | docker buildx build -f docker/Dockerfile-zh -t "chishin/nginx-proxy-manager-zh:dev" --platform linux/amd64,linux/arm64,linux/arm/7 . --push 16 | fi 17 | 18 | docker buildx rm "Buildx-NPM" 19 | 20 | echo "Multiarch build Complete" -------------------------------------------------------------------------------- /scripts/ci/frontend-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/../.common.sh" 5 | 6 | DOCKER_IMAGE=jc21/nginx-full:certbot-node 7 | 8 | # Ensure docker exists 9 | if hash docker 2>/dev/null; then 10 | docker pull "${DOCKER_IMAGE}" 11 | cd "${DIR}/../.." 12 | echo -e "${BLUE}❯ ${CYAN}Building Frontend ...${RESET}" 13 | docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -v "$(pwd)/global:/app/global" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend" 14 | echo -e "${BLUE}❯ ${GREEN}Building Frontend Complete${RESET}" 15 | else 16 | echo -e "${RED}❯ docker command is not available${RESET}" 17 | fi 18 | -------------------------------------------------------------------------------- /scripts/ci/test-and-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DOCKER_IMAGE=jc21/nginx-full:certbot-node 4 | docker pull "${DOCKER_IMAGE}" 5 | 6 | # Test 7 | docker run --rm \ 8 | -v "$(pwd)/backend:/app" \ 9 | -v "$(pwd)/global:/app/global" \ 10 | -w /app \ 11 | "${DOCKER_IMAGE}" \ 12 | sh -c 'yarn install && yarn eslint . && rm -rf node_modules' 13 | 14 | # Build 15 | docker build --pull --no-cache --squash --compress \ 16 | -t "${IMAGE}:ci-${BUILD_NUMBER}" \ 17 | -f docker/Dockerfile \ 18 | --build-arg TARGETPLATFORM=linux/amd64 \ 19 | --build-arg BUILDPLATFORM=linux/amd64 \ 20 | --build-arg BUILD_VERSION="${BUILD_VERSION}" \ 21 | --build-arg BUILD_COMMIT="${BUILD_COMMIT}" \ 22 | --build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \ 23 | . 24 | -------------------------------------------------------------------------------- /scripts/destroy-dev: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | # Ensure docker-compose exists 7 | # Make sure docker exists 8 | if hash docker-compose 2>/dev/null; then 9 | cd "${DIR}/.." 10 | echo -e "${BLUE}❯ ${CYAN}Destroying Dev Stack ...${RESET}" 11 | docker-compose down --remove-orphans --volumes 12 | else 13 | echo -e "${RED}❯ docker-compose command is not available${RESET}" 14 | fi 15 | -------------------------------------------------------------------------------- /scripts/docs-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | # Ensure docker-compose exists 7 | if hash docker 2>/dev/null; then 8 | cd "${DIR}/.." 9 | echo -e "${BLUE}❯ ${CYAN}Building Docs ...${RESET}" 10 | docker run --rm -e CI=true -v "$(pwd)/docs:/app/docs" -w /app/docs node:alpine sh -c "yarn install && yarn build && chown -R $(id -u):$(id -g) /app/docs" 11 | echo -e "${BLUE}❯ ${GREEN}Building Docs Complete${RESET}" 12 | else 13 | echo -e "${RED}❯ docker command is not available${RESET}" 14 | fi 15 | -------------------------------------------------------------------------------- /scripts/start-dev: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | # Ensure docker-compose exists 7 | if hash docker-compose 2>/dev/null; then 8 | cd "${DIR}/.." 9 | echo -e "${BLUE}❯ ${CYAN}Starting Dev Stack ...${RESET}" 10 | 11 | docker-compose up -d --remove-orphans --force-recreate --build 12 | 13 | echo "" 14 | echo -e "${CYAN}Admin UI: http://127.0.0.1:3081${RESET}" 15 | echo -e "${CYAN}Nginx: http://127.0.0.1:3080${RESET}" 16 | echo -e "${CYAN}Swagger Doc: http://127.0.0.1:3001${RESET}" 17 | echo "" 18 | 19 | if [ "$1" == "-f" ]; then 20 | echo -e "${BLUE}❯ ${YELLOW}Following Backend Container:${RESET}" 21 | docker logs -f npm_core 22 | else 23 | echo -e "${YELLOW}Hint:${RESET} You can follow the output of some of the containers with:" 24 | echo " docker logs -f npm_core" 25 | fi 26 | else 27 | echo -e "${RED}❯ docker-compose command is not available${RESET}" 28 | fi 29 | -------------------------------------------------------------------------------- /scripts/stop-dev: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | # Ensure docker-compose exists 7 | # Make sure docker exists 8 | if hash docker-compose 2>/dev/null; then 9 | cd "${DIR}/.." 10 | echo -e "${BLUE}❯ ${CYAN}Stopping Dev Stack ...${RESET}" 11 | docker-compose down --remove-orphans 12 | else 13 | echo -e "${RED}❯ docker-compose command is not available${RESET}" 14 | fi 15 | -------------------------------------------------------------------------------- /scripts/test-dev: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | # Ensure docker-compose exists 7 | if hash docker-compose 2>/dev/null; then 8 | cd "${DIR}/.." 9 | echo -e "${BLUE}❯ ${CYAN}Testing Dev Stack ...${RESET}" 10 | docker-compose exec -T npm bash -c "cd /app && task test" 11 | else 12 | echo -e "${RED}❯ docker-compose command is not available${RESET}" 13 | fi 14 | -------------------------------------------------------------------------------- /scripts/wait-healthy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | . "$DIR/.common.sh" 5 | 6 | if [ "$1" == "" ]; then 7 | echo "Waits for a docker container to be healthy." 8 | echo "Usage: $0 docker-container" 9 | exit 1 10 | fi 11 | 12 | SERVICE=$1 13 | LOOPCOUNT=0 14 | HEALTHY= 15 | LIMIT=${2:-90} 16 | 17 | echo -e "${BLUE}❯ ${CYAN}Waiting for healthy: ${YELLOW}${SERVICE}${RESET}" 18 | 19 | until [ "${HEALTHY}" = "healthy" ]; do 20 | echo -n "." 21 | sleep 1 22 | HEALTHY="$(docker inspect -f '{{.State.Health.Status}}' $SERVICE)" 23 | ((LOOPCOUNT++)) 24 | 25 | if [ "$LOOPCOUNT" == "$LIMIT" ]; then 26 | echo "" 27 | echo "" 28 | echo -e "${BLUE}❯ ${RED}Timed out waiting for healthy${RESET}" 29 | exit 1 30 | fi 31 | done 32 | 33 | echo "" 34 | echo -e "${BLUE}❯ ${GREEN}Healthy!${RESET}" 35 | -------------------------------------------------------------------------------- /test/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules 3 | results 4 | cypress/videos 5 | -------------------------------------------------------------------------------- /test/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 160, 3 | "tabWidth": 4, 4 | "useTabs": true, 5 | "semi": true, 6 | "singleQuote": true, 7 | "bracketSpacing": true, 8 | "jsxBracketSameLine": true, 9 | "trailingComma": "all", 10 | "proseWrap": "always" 11 | } 12 | -------------------------------------------------------------------------------- /test/cypress/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM cypress/included:9.4.1 2 | 3 | COPY --chown=1000 ./ /test 4 | 5 | # mkcert 6 | ENV MKCERT=1.4.2 7 | RUN wget -O /usr/bin/mkcert "https://github.com/FiloSottile/mkcert/releases/download/v${MKCERT}/mkcert-v${MKCERT}-linux-amd64" \ 8 | && chmod +x /usr/bin/mkcert 9 | 10 | WORKDIR /test 11 | RUN yarn install 12 | ENTRYPOINT [] 13 | CMD ["cypress", "run"] 14 | -------------------------------------------------------------------------------- /test/cypress/config/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "requestTimeout": 30000, 3 | "defaultCommandTimeout": 20000, 4 | "reporter": "cypress-multi-reporters", 5 | "reporterOptions": { 6 | "configFile": "multi-reporter.json" 7 | }, 8 | "videosFolder": "results/videos", 9 | "screenshotsFolder": "results/screenshots", 10 | "env": { 11 | "swaggerBase": "{{baseUrl}}/api/schema", 12 | "RETRIES": 4 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/cypress/config/dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "requestTimeout": 30000, 3 | "defaultCommandTimeout": 20000, 4 | "reporter": "cypress-multi-reporters", 5 | "reporterOptions": { 6 | "configFile": "multi-reporter.json" 7 | }, 8 | "videos": false, 9 | "screenshotsFolder": "results/screenshots", 10 | "env": { 11 | "swaggerBase": "{{baseUrl}}/api/schema", 12 | "RETRIES": 0 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /test/cypress/integration/api/Health.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | describe('Basic API checks', () => { 4 | it('Should return a valid health payload', function () { 5 | cy.task('backendApiGet', { 6 | path: '/api/', 7 | }).then((data) => { 8 | // Check the swagger schema: 9 | cy.validateSwaggerSchema('get', 200, '/', data); 10 | }); 11 | }); 12 | 13 | it('Should return a valid schema payload', function () { 14 | cy.task('backendApiGet', { 15 | path: '/api/schema', 16 | }).then((data) => { 17 | expect(data.openapi).to.be.equal('3.0.0'); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/cypress/plugins/backendApi/logger.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const chalk = require('chalk'); 3 | 4 | module.exports = function () { 5 | var arr = _.values(arguments); 6 | arr.unshift(chalk.blue.bold('[') + chalk.yellow.bold('Backend API') + chalk.blue.bold(']')); 7 | console.log.apply(null, arr); 8 | }; 9 | -------------------------------------------------------------------------------- /test/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | const {SwaggerValidation} = require('@jc21/cypress-swagger-validation'); 2 | 3 | module.exports = (on, config) => { 4 | // Replace swaggerBase config var wildcard 5 | if (typeof config.env.swaggerBase !== 'undefined') { 6 | config.env.swaggerBase = config.env.swaggerBase.replace('{{baseUrl}}', config.baseUrl); 7 | } 8 | 9 | // Plugin Events 10 | on('task', SwaggerValidation(config)); 11 | on('task', require('./backendApi/task')(config)); 12 | on('task', { 13 | log(message) { 14 | console.log(message); 15 | return null; 16 | } 17 | }); 18 | 19 | return config; 20 | }; 21 | -------------------------------------------------------------------------------- /test/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | require('cypress-plugin-retries'); 2 | 3 | import './commands'; 4 | 5 | Cypress.on('uncaught:exception', (/*err, runnable*/) => { 6 | // returning false here prevents Cypress from 7 | // failing the test 8 | return false; 9 | }); 10 | -------------------------------------------------------------------------------- /test/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "./node_modules/cypress", 4 | "cypress/**/*.js" 5 | ] 6 | } -------------------------------------------------------------------------------- /test/multi-reporter.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporterEnabled": "spec, mocha-junit-reporter", 3 | "mochaJunitReporterReporterOptions": { 4 | "jenkinsMode": true, 5 | "rootSuiteTitle": "Cypress.npm", 6 | "jenkinsClassnamePrefix": "Cypress.npm.", 7 | "mochaFile": "results/junit/cypress.npm.[hash].xml" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "@jc21/cypress-swagger-validation": "^0.0.9", 8 | "@jc21/restler": "^3.4.0", 9 | "chalk": "^4.1.0", 10 | "cypress": "^9.4.1", 11 | "cypress-multi-reporters": "^1.4.0", 12 | "cypress-plugin-retries": "^1.5.2", 13 | "eslint": "^7.6.0", 14 | "eslint-plugin-align-assignments": "^1.1.2", 15 | "eslint-plugin-chai-friendly": "^0.6.0", 16 | "eslint-plugin-cypress": "^2.11.1", 17 | "lodash": "^4.17.19", 18 | "mocha": "^8.1.1", 19 | "mocha-junit-reporter": "^2.0.0" 20 | }, 21 | "scripts": { 22 | "cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}", 23 | "cypress:headless": "cypress run --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}" 24 | }, 25 | "author": "", 26 | "license": "ISC" 27 | } 28 | --------------------------------------------------------------------------------