Compare commits

..

74 Commits

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-30 14:43:28 +00:00
c0e9d1eb2f Fix satisy typo 2020-04-22 11:11:20 +10:00
a7cabdde3a Merge pull request #376 from spalger/expand-forward-host-size
expand the maximum size of the forward_host
2020-04-17 08:59:55 +10:00
3af560c2d0 switch to 255 limit to match db 2020-04-16 15:14:49 -07:00
1d23d5c761 remove maxlength from html too 2020-04-16 15:13:28 -07:00
995db12f22 remove arbitrary length limit of forward_host 2020-04-16 14:00:22 -07:00
73 changed files with 5375 additions and 5007 deletions

View File

@ -0,0 +1,16 @@
---
name: Product Support
about: Need help configuring the software?
title: ''
labels: product-support
assignees: ''
---
**Checklist**
- Please read the [setup instructions](https://nginxproxymanager.com/setup/)
- Please read the [FAQ](https://nginxproxymanager.com/faq/)
**What is troubling you?**
_Clear and concise description of what you're trying to do and what isn't working for you_

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
.idea
._*
.vscode
certbot-help.txt

View File

@ -0,0 +1,11 @@
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
}
}
}
}

View File

@ -1 +1 @@
2.2.3
2.4.0

130
Jenkinsfile vendored
View File

@ -5,6 +5,7 @@ pipeline {
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
disableConcurrentBuilds()
ansiColor('xterm')
}
environment {
IMAGE = "nginx-proxy-manager"
@ -55,56 +56,76 @@ pipeline {
}
stage('Frontend') {
steps {
ansiColor('xterm') {
sh './scripts/frontend-build'
}
sh './scripts/frontend-build'
}
}
stage('Backend') {
steps {
ansiColor('xterm') {
echo 'Checking Syntax ...'
// See: https://github.com/yarnpkg/yarn/issues/3254
sh '''docker run --rm \\
-v "$(pwd)/backend:/app" \\
-w /app \\
node:latest \\
sh -c "yarn install && yarn eslint . && rm -rf node_modules"
'''
echo 'Checking Syntax ...'
// See: https://github.com/yarnpkg/yarn/issues/3254
sh '''docker run --rm \\
-v "$(pwd)/backend:/app" \\
-w /app \\
node:latest \\
sh -c "yarn install && yarn eslint . && rm -rf node_modules"
'''
echo 'Docker Build ...'
sh '''docker build --pull --no-cache --squash --compress \\
-t "${IMAGE}:ci-${BUILD_NUMBER}" \\
-f docker/Dockerfile \\
--build-arg TARGETPLATFORM=linux/amd64 \\
--build-arg BUILDPLATFORM=linux/amd64 \\
--build-arg BUILD_VERSION="${BUILD_VERSION}" \\
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
.
'''
}
echo 'Docker Build ...'
sh '''docker build --pull --no-cache --squash --compress \\
-t "${IMAGE}:ci-${BUILD_NUMBER}" \\
-f docker/Dockerfile \\
--build-arg TARGETPLATFORM=linux/amd64 \\
--build-arg BUILDPLATFORM=linux/amd64 \\
--build-arg BUILD_VERSION="${BUILD_VERSION}" \\
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
.
'''
}
}
stage('Test') {
stage('Integration Tests Sqlite') {
steps {
ansiColor('xterm') {
// Bring up a stack
sh 'docker-compose up -d fullstack'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack) 120'
// Bring up a stack
sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress):/results" test/'
}
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-sqlite'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack | gzip > debug/docker_fullstack.log.gz'
sh 'docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Integration Tests Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
@ -121,18 +142,16 @@ pipeline {
}
}
steps {
ansiColor('xterm') {
dir(path: 'docs') {
sh 'yarn install'
sh 'yarn build'
}
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
dir(path: 'docs') {
sh 'yarn install'
sh 'yarn build'
}
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
}
}
stage('MultiArch Build') {
@ -142,12 +161,11 @@ pipeline {
}
}
steps {
ansiColor('xterm') {
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
sh "docker login -u '${duser}' -p '${dpass}'"
// Buildx with push
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
}
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
// Docker Login
sh "docker login -u '${duser}' -p '${dpass}'"
// Buildx with push from cache
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
}
}
}
@ -193,10 +211,8 @@ pipeline {
}
}
steps {
ansiColor('xterm') {
script {
def comment = pullRequest.comment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`")
}
script {
def comment = pullRequest.comment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`")
}
}
}

153
README.md
View File

@ -1,16 +1,19 @@
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.2.3-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://ci.nginxproxymanager.com/blue/organizations/jenkins/nginx-proxy-manager/branches/">
<img src="https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fci.nginxproxymanager.com%2Fjob%2Fnginx-proxy-manager%2Fjob%2Fmaster&style=for-the-badge">
</a>
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.4.0-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://ci.nginxproxymanager.com/blue/organizations/jenkins/nginx-proxy-manager/branches/">
<img src="https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fci.nginxproxymanager.com%2Fjob%2Fnginx-proxy-manager%2Fjob%2Fmaster&style=for-the-badge">
</a>
<a href="https://gitter.im/nginx-proxy-manager/community">
<img alt="Gitter" src="https://img.shields.io/gitter/room/nginx-proxy-manager/community?style=for-the-badge">
</a>
</p>
This project comes as a pre-built docker image that enables you to easily forward to your websites
@ -48,3 +51,129 @@ I won't go in to too much detail here but here are the basics for someone new to
2. Add port forwarding for port 80 and 443 to the server hosting this project
3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
## Contributors
Special thanks to the following contributors:
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center">
<a href="https://github.com/Subv">
<img src="https://avatars1.githubusercontent.com/u/357072?s=460&u=d8adcdc91d749ae53e177973ed9b6bb6c4c894a3&v=4" width="80px;" alt=""/>
<br /><sub><b>Sebastian Valle</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Indemnity83">
<img src="https://avatars3.githubusercontent.com/u/35218?s=460&u=7082004ff35138157c868d7d9c683ccebfce5968&v=4" width="80px;" alt=""/>
<br /><sub><b>Kyle Klaus</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/theraw">
<img src="https://avatars1.githubusercontent.com/u/32969774?s=460&u=6b359971e15685fb0359e6a8c065a399b40dc228&v=4" width="80px;" alt=""/>
<br /><sub><b>ƬHE ЯAW</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/spalger">
<img src="https://avatars2.githubusercontent.com/u/1329312?s=400&u=565223e38f1c052afb4c5dcca3fcf1c63ba17ae7&v=4" width="80px;" alt=""/>
<br /><sub><b>Spencer</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Xantios">
<img src="https://avatars3.githubusercontent.com/u/1507836?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>Xantios Krugor</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dpanesso">
<img src="https://avatars2.githubusercontent.com/u/2687121?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>David Panesso</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/IronTooch">
<img src="https://avatars3.githubusercontent.com/u/27360514?s=460&u=69bf854a6647c55725f62ecb8d39249c6c0b2602&v=4" width="80px;" alt=""/>
<br /><sub><b>IronTooch</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/damianog">
<img src="https://avatars1.githubusercontent.com/u/2786682?s=460&u=76c6136fae797abb76b951cd8a246dcaecaf21af&v=4" width="80px;" alt=""/>
<br /><sub><b>Damiano</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/tfmm">
<img src="https://avatars3.githubusercontent.com/u/6880538?s=460&u=ce0160821cc4aa802df8395200f2d4956a5bc541&v=4" width="80px;" alt=""/>
<br /><sub><b>Russ</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/margaale">
<img src="https://avatars3.githubusercontent.com/u/20794934?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>Marcelo Castagna</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/Steven-Harris">
<img src="https://avatars2.githubusercontent.com/u/7720242?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>Steven Harris</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jlesage">
<img src="https://avatars0.githubusercontent.com/u/1791123?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>Jocelyn Le Sage</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/cmer">
<img src="https://avatars0.githubusercontent.com/u/412?s=460&u=67dd8b2e3661bfd6f68ec1eaa5b9821bd8a321cd&v=4" width="80px;" alt=""/>
<br /><sub><b>Carl Mercier</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/the1ts">
<img src="https://avatars1.githubusercontent.com/u/84956?s=460&v=4" width="80px;" alt=""/>
<br /><sub><b>Paul Mansfield</b></sub>
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://github.com/OhHeyAlan">
<img src="https://avatars0.githubusercontent.com/u/11955126?s=460&u=fbaa5a1a4f73ef8960132c703349bfd037fe2630&v=4" width="80px;" alt=""/>
<br /><sub><b>OhHeyAlan</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dogmatic69">
<img src="https://avatars2.githubusercontent.com/u/94674?s=460&u=ca7647de53145c6283b6373ade5dc94ba99347db&v=4" width="80px;" alt=""/>
<br /><sub><b>Carl Sutton</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/tg44">
<img src="https://avatars0.githubusercontent.com/u/31839?s=460&u=ad32f4cadfef5e5fb09cdfa4b7b7b36a99ba6811&v=4" width="80px;" alt=""/>
<br /><sub><b>Gergő Törcsvári</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/vrenjith">
<img src="https://avatars3.githubusercontent.com/u/2093241?s=460&u=96ce93a9bebabdd0a60a2dc96cd093a41d5edaba&v=4" width="80px;" alt=""/>
<br /><sub><b>vrenjith</b></sub>
</a>
</td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

View File

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

View File

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

View File

@ -30,7 +30,7 @@ const internalAccessList = {
.omit(omissions())
.insertAndFetch({
name: data.name,
satify_any: data.satify_any,
satisfy_any: data.satisfy_any,
owner_user_id: access.token.getUserId(1)
});
})
@ -71,7 +71,7 @@ const internalAccessList = {
// re-fetch with expansions
return internalAccessList.get(access, {
id: data.id,
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.clients']
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
}, true /* <- skip masking */);
})
.then((row) => {
@ -126,8 +126,8 @@ const internalAccessList = {
.query()
.where({id: data.id})
.patch({
name: data.name,
satify_any: data.satify_any,
name: data.name,
satisfy_any: data.satisfy_any,
});
}
})
@ -216,7 +216,7 @@ const internalAccessList = {
// re-fetch with expansions
return internalAccessList.get(access, {
id: data.id,
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.clients']
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
}, true /* <- skip masking */);
})
.then((row) => {
@ -254,7 +254,7 @@ const internalAccessList = {
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
.where('access_list.is_deleted', 0)
.andWhere('access_list.id', data.id)
.allowEager('[owner,items,clients,proxy_hosts,proxy_hosts.access_list.clients]')
.allowEager('[owner,items,clients,proxy_hosts.[*, access_list.[clients,items]]]')
.omit(['access_list.is_deleted'])
.first();

View File

@ -273,6 +273,7 @@ const internalNginx = {
return new Promise((resolve, reject) => {
let template = null;
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
try {
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
} catch (err) {
@ -280,6 +281,8 @@ const internalNginx = {
return;
}
certificate.ipv6 = internalNginx.ipv6Enabled();
renderEngine
.parseAndRender(template, certificate)
.then((config_text) => {

View File

@ -73,7 +73,7 @@ const internalProxyHost = {
// re-fetch with cert
return internalProxyHost.get(access, {
id: row.id,
expand: ['certificate', 'owner', 'access_list.clients']
expand: ['certificate', 'owner', 'access_list.[clients,items]']
});
})
.then((row) => {
@ -186,7 +186,7 @@ const internalProxyHost = {
.then(() => {
return internalProxyHost.get(access, {
id: data.id,
expand: ['owner', 'certificate', 'access_list.clients']
expand: ['owner', 'certificate', 'access_list.[clients,items]']
})
.then((row) => {
// Configure nginx
@ -219,7 +219,7 @@ const internalProxyHost = {
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowEager('[owner,access_list,access_list.clients,certificate]')
.allowEager('[owner,access_list,access_list.[clients,items],certificate]')
.first();
if (access_data.permission_visibility !== 'all') {

View File

@ -22,22 +22,6 @@ exports.up = function (knex/*, Promise*/) {
})
.then(() => {
logger.info('[' + migrate_name + '] setting Table created');
// TODO: add settings
let settingModel = require('../models/setting');
return settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {}
});
})
.then(() => {
logger.info('[' + migrate_name + '] Default settings added');
});
};

View File

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

View File

@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user');
const AccessListAuth = require('./access_list_auth');
const AccessListClient = require('./access_list_client');
const now = require('./now_helper');
Model.knex(db);
class AccessList extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -21,7 +22,7 @@ class AccessList extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {
@ -90,7 +91,7 @@ class AccessList extends Model {
}
get satisfy() {
return this.satify_any ? 'satisfy any' : 'satisfy all';
return this.satisfy_any ? 'satisfy any' : 'satisfy all';
}
}

View File

@ -3,13 +3,14 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class AccessListAuth extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -18,7 +19,7 @@ class AccessListAuth extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -3,13 +3,14 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class AccessListClient extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -18,7 +19,7 @@ class AccessListClient extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class AuditLog extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -19,7 +20,7 @@ class AuditLog extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -5,6 +5,7 @@ const bcrypt = require('bcrypt');
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
@ -24,8 +25,8 @@ function encryptPassword () {
class Auth extends Model {
$beforeInsert (queryContext) {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -36,7 +37,7 @@ class Auth extends Model {
}
$beforeUpdate (queryContext) {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
return encryptPassword.apply(this, queryContext);
}

View File

@ -4,17 +4,18 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class Certificate extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for expires_on
if (typeof this.expires_on === 'undefined') {
this.expires_on = Model.raw('NOW()');
this.expires_on = now();
}
// Default for domain_names
@ -31,7 +32,7 @@ class Certificate extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class DeadHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@ -27,7 +28,7 @@ class DeadHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@ -0,0 +1,13 @@
const db = require('../db');
const config = require('config');
const Model = require('objection').Model;
Model.knex(db);
module.exports = function () {
if (config.database.knex && config.database.knex.client === 'sqlite3') {
return Model.raw('date(\'now\')');
} else {
return Model.raw('NOW()');
}
};

View File

@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user');
const AccessList = require('./access_list');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class ProxyHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@ -28,7 +29,7 @@ class ProxyHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db);
class RedirectionHost extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for domain_names
if (typeof this.domain_names === 'undefined') {
@ -27,7 +28,7 @@ class RedirectionHost extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
// Sort domain_names
if (typeof this.domain_names !== 'undefined') {

View File

@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const User = require('./user');
const now = require('./now_helper');
Model.knex(db);
class Stream extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for meta
if (typeof this.meta === 'undefined') {
@ -19,7 +20,7 @@ class Stream extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -4,13 +4,14 @@
const db = require('../db');
const Model = require('objection').Model;
const UserPermission = require('./user_permission');
const now = require('./now_helper');
Model.knex(db);
class User extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
// Default for roles
if (typeof this.roles === 'undefined') {
@ -19,7 +20,7 @@ class User extends Model {
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -3,17 +3,18 @@
const db = require('../db');
const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db);
class UserPermission extends Model {
$beforeInsert () {
this.created_on = Model.raw('NOW()');
this.modified_on = Model.raw('NOW()');
this.created_on = now();
this.modified_on = now();
}
$beforeUpdate () {
this.modified_on = Model.raw('NOW()');
this.modified_on = now();
}
static get name () {

View File

@ -12,22 +12,24 @@
"config": "^3.3.1",
"diskdb": "^0.1.17",
"express": "^4.17.1",
"express-fileupload": "^1.1.6",
"express-fileupload": "^1.1.9",
"gravatar": "^1.8.0",
"html-entities": "^1.2.1",
"json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1",
"knex": "^0.20.13",
"liquidjs": "^9.11.10",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"moment": "^2.24.0",
"mysql": "^2.18.1",
"node-rsa": "^1.0.8",
"nodemon": "^2.0.2",
"objection": "^2.1.3",
"path": "^0.12.7",
"pg": "^7.12.1",
"restler": "^3.4.0",
"signale": "^1.4.0",
"sqlite3": "^4.1.1",
"temp-write": "^4.0.0",
"unix-timestamp": "^0.2.0"
},

View File

@ -1,229 +1,227 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "endpoints/access-lists",
"title": "Access Lists",
"description": "Endpoints relating to Access Lists",
"stability": "stable",
"type": "object",
"definitions": {
"id": {
"$ref": "../definitions.json#/definitions/id"
},
"created_on": {
"$ref": "../definitions.json#/definitions/created_on"
},
"modified_on": {
"$ref": "../definitions.json#/definitions/modified_on"
},
"name": {
"type": "string",
"description": "Name of the Access List"
},
"directive": {
"type": "string",
"enum": ["allow", "deny"]
},
"address": {
"oneOf": [
{
"type": "string",
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$"
},
{
"type": "string",
"pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
},
{
"type": "string",
"pattern": "^any$"
}
]
},
"satify_any": {
"type": "boolean"
},
"meta": {
"type": "object"
}
},
"properties": {
"id": {
"$ref": "#/definitions/id"
},
"created_on": {
"$ref": "#/definitions/created_on"
},
"modified_on": {
"$ref": "#/definitions/modified_on"
},
"name": {
"$ref": "#/definitions/name"
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"links": [
{
"title": "List",
"description": "Returns a list of Access Lists",
"href": "/nginx/access-lists",
"access": "private",
"method": "GET",
"rel": "self",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "array",
"items": {
"$ref": "#/properties"
}
}
},
{
"title": "Create",
"description": "Creates a new Access List",
"href": "/nginx/access-list",
"access": "private",
"method": "POST",
"rel": "create",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"schema": {
"type": "object",
"additionalProperties": false,
"required": [
"name"
],
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"satify_any": {
"$ref": "#/definitions/satify_any"
},
"items": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {
"type": "string",
"minLength": 1
},
"password": {
"type": "string",
"minLength": 1
}
}
}
},
"clients": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"address": {
"$ref": "#/definitions/address"
},
"directive": {
"$ref": "#/definitions/directive"
}
}
}
},
"meta": {
"$ref": "#/definitions/meta"
}
}
},
"targetSchema": {
"properties": {
"$ref": "#/properties"
}
}
},
{
"title": "Update",
"description": "Updates a existing Access List",
"href": "/nginx/access-list/{definitions.identity.example}",
"access": "private",
"method": "PUT",
"rel": "update",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"satify_any": {
"$ref": "#/definitions/satify_any"
},
"items": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {
"type": "string",
"minLength": 1
},
"password": {
"type": "string",
"minLength": 0
}
}
}
},
"clients": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"address": {
"$ref": "#/definitions/address"
},
"directive": {
"$ref": "#/definitions/directive"
}
}
}
}
}
},
"targetSchema": {
"properties": {
"$ref": "#/properties"
}
}
},
{
"title": "Delete",
"description": "Deletes a existing Access List",
"href": "/nginx/access-list/{definitions.identity.example}",
"access": "private",
"method": "DELETE",
"rel": "delete",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "boolean"
}
}
]
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "endpoints/access-lists",
"title": "Access Lists",
"description": "Endpoints relating to Access Lists",
"stability": "stable",
"type": "object",
"definitions": {
"id": {
"$ref": "../definitions.json#/definitions/id"
},
"created_on": {
"$ref": "../definitions.json#/definitions/created_on"
},
"modified_on": {
"$ref": "../definitions.json#/definitions/modified_on"
},
"name": {
"type": "string",
"description": "Name of the Access List"
},
"directive": {
"type": "string",
"enum": ["allow", "deny"]
},
"address": {
"oneOf": [
{
"type": "string",
"pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
},
{
"type": "string",
"pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
},
{
"type": "string",
"pattern": "^all$"
}
]
},
"satisfy_any": {
"type": "boolean"
},
"meta": {
"type": "object"
}
},
"properties": {
"id": {
"$ref": "#/definitions/id"
},
"created_on": {
"$ref": "#/definitions/created_on"
},
"modified_on": {
"$ref": "#/definitions/modified_on"
},
"name": {
"$ref": "#/definitions/name"
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"links": [
{
"title": "List",
"description": "Returns a list of Access Lists",
"href": "/nginx/access-lists",
"access": "private",
"method": "GET",
"rel": "self",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "array",
"items": {
"$ref": "#/properties"
}
}
},
{
"title": "Create",
"description": "Creates a new Access List",
"href": "/nginx/access-list",
"access": "private",
"method": "POST",
"rel": "create",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["name"],
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"satisfy_any": {
"$ref": "#/definitions/satisfy_any"
},
"items": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {
"type": "string",
"minLength": 1
},
"password": {
"type": "string",
"minLength": 1
}
}
}
},
"clients": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"address": {
"$ref": "#/definitions/address"
},
"directive": {
"$ref": "#/definitions/directive"
}
}
}
},
"meta": {
"$ref": "#/definitions/meta"
}
}
},
"targetSchema": {
"properties": {
"$ref": "#/properties"
}
}
},
{
"title": "Update",
"description": "Updates a existing Access List",
"href": "/nginx/access-list/{definitions.identity.example}",
"access": "private",
"method": "PUT",
"rel": "update",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"satisfy_any": {
"$ref": "#/definitions/satisfy_any"
},
"items": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {
"type": "string",
"minLength": 1
},
"password": {
"type": "string",
"minLength": 0
}
}
}
},
"clients": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"address": {
"$ref": "#/definitions/address"
},
"directive": {
"$ref": "#/definitions/directive"
}
}
}
}
}
},
"targetSchema": {
"properties": {
"$ref": "#/properties"
}
}
},
{
"title": "Delete",
"description": "Deletes a existing Access List",
"href": "/nginx/access-list/{definitions.identity.example}",
"access": "private",
"method": "DELETE",
"rel": "delete",
"http_header": {
"$ref": "../examples.json#/definitions/auth_header"
},
"targetSchema": {
"type": "boolean"
}
}
]
}

View File

@ -25,7 +25,7 @@
"forward_host": {
"type": "string",
"minLength": 1,
"maxLength": 50
"maxLength": 255
},
"forward_port": {
"type": "integer",

View File

@ -5,9 +5,15 @@ const logger = require('./logger').setup;
const userModel = require('./models/user');
const userPermissionModel = require('./models/user_permission');
const authModel = require('./models/auth');
const settingModel = require('./models/setting');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
module.exports = function () {
/**
* Creates a new JWT RSA Keypair if not alread set on the config
*
* @returns {Promise}
*/
const setupJwt = () => {
return new Promise((resolve, reject) => {
// Now go and check if the jwt gpg keys have been created and if not, create them
if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) {
@ -27,12 +33,12 @@ module.exports = function () {
}
// Now create the keys and save them in the config.
let key = new NodeRSA({b: 2048});
let key = new NodeRSA({ b: 2048 });
key.generateKeyPair();
config_data.jwt = {
key: key.exportKey('private').toString(),
pub: key.exportKey('public').toString()
pub: key.exportKey('public').toString(),
};
// Write config
@ -47,7 +53,6 @@ module.exports = function () {
process.exit(0);
}
});
} else {
// JWT key pair exists
if (debug_mode) {
@ -56,14 +61,20 @@ module.exports = function () {
resolve();
}
})
.then(() => {
return userModel
.query()
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first();
})
});
};
/**
* Creates a default admin users if one doesn't already exist in the database
*
* @returns {Promise}
*/
const setupDefaultUser = () => {
return userModel
.query()
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first()
.then((row) => {
if (!row.count) {
// Create a new user and set password
@ -75,7 +86,7 @@ module.exports = function () {
name: 'Administrator',
nickname: 'Admin',
avatar: '',
roles: ['admin']
roles: ['admin'],
};
return userModel
@ -88,28 +99,64 @@ module.exports = function () {
user_id: user.id,
type: 'password',
secret: 'changeme',
meta: {}
meta: {},
})
.then(() => {
return userPermissionModel
.query()
.insert({
user_id: user.id,
visibility: 'all',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage',
certificates: 'manage'
});
return userPermissionModel.query().insert({
user_id: user.id,
visibility: 'all',
proxy_hosts: 'manage',
redirection_hosts: 'manage',
dead_hosts: 'manage',
streams: 'manage',
access_lists: 'manage',
certificates: 'manage',
});
});
})
.then(() => {
logger.info('Initial setup completed');
logger.info('Initial admin setup completed');
});
} else if (debug_mode) {
logger.debug('Admin user setup not required');
}
});
};
/**
* Creates default settings if they don't already exist in the database
*
* @returns {Promise}
*/
const setupDefaultSettings = () => {
return settingModel
.query()
.select(settingModel.raw('COUNT(`id`) as `count`'))
.where({id: 'default-site'})
.first()
.then((row) => {
if (!row.count) {
settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {},
})
.then(() => {
logger.info('Default settings added');
});
}
if (debug_mode) {
logger.debug('Default setting setup not required');
}
});
};
module.exports = function () {
return setupJwt()
.then(setupDefaultUser)
.then(setupDefaultSettings);
};

View File

@ -2,6 +2,10 @@
server {
listen 80;
{% if ipv6 -%}
listen [::]:80;
{% endif %}
server_name {{ domain_names | join: " " }};
access_log /data/logs/letsencrypt-requests.log standard;

View File

@ -23,9 +23,11 @@ server {
location / {
{% if access_list_id > 0 %}
{% if access_list.items.length > 0 %}
# Authorization
auth_basic "Authorization required";
auth_basic_user_file /data/access/{{ access_list_id }};
{% endif %}
# Access Rules
{% for client in access_list.clients %}

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@ ENV S6_FIX_ATTRS_HIDDEN=1
ENV NODE_ENV=production
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& rm -rf /etc/nginx \
&& apk update \
&& apk add python2 certbot jq \
&& rm -rf /var/cache/apk/*

View File

@ -6,7 +6,6 @@ ENV SUPPRESS_NO_CONFIG_WARNING=1
ENV S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& rm -rf /etc/nginx \
&& apk update \
&& apk add python2 certbot jq \
&& rm -rf /var/cache/apk/*

View File

@ -2,14 +2,14 @@
version: "3"
services:
fullstack:
fullstack-mysql:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
- NODE_ENV=development
- FORCE_COLOR=1
volumes:
- npm_data:/data
- ../.jenkins/config.json:/app/config/production.json
- ../.jenkins/config-mysql.json:/app/config/development.json
expose:
- 81
- 80
@ -17,6 +17,19 @@ services:
depends_on:
- db
fullstack-sqlite:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
- NODE_ENV=development
- FORCE_COLOR=1
volumes:
- npm_data:/data
- ../.jenkins/config-sqlite.json:/app/config/development.json
expose:
- 81
- 80
- 443
db:
image: jc21/mariadb-aria
environment:
@ -27,13 +40,24 @@ services:
volumes:
- db_data:/var/lib/mysql
cypress:
cypress-mysql:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../
dockerfile: test/cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack:81"
CYPRESS_baseUrl: "http://fullstack-mysql:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../
dockerfile: test/cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-sqlite:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}

View File

@ -26,12 +26,15 @@ http {
tcp_nopush on;
tcp_nodelay on;
client_body_temp_path /tmp/nginx/body 1 2;
keepalive_timeout 65;
keepalive_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
ssl_prefer_server_ciphers on;
gzip on;
proxy_ignore_client_abort off;
client_max_body_size 2000m;
server_names_hash_bucket_size 64;
server_names_hash_bucket_size 1024;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View File

@ -16,5 +16,5 @@ alias h='cd ~;clear;'
echo -e -n '\E[1;34m'
figlet -w 120 "NginxProxyManager"
echo -e "\E[1;36mVersion \E[1;32m${NPM_BUILD_VERSION:-2.0.0-dev}\E[1;36m (${NPM_BUILD_COMMIT:-dev}) ${NPM_BUILD_DATE:-0000-00-00}, Nginx \E[1;32m${NGINX_VERSION:-unknown}\E[1;36m, Alpine \E[1;32m${VERSION_ID:-unknown}\E[1;36m, Kernel \E[1;32m$(uname -r)\E[0m"
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, Alpine \E[1;32m${VERSION_ID:-unknown}\E[1;36m, Kernel \E[1;32m$(uname -r)\E[0m"
echo

View File

@ -47,6 +47,7 @@ module.exports = {
["/screenshots/", "Screenshots"],
["/setup/", "Setup Instructions"],
["/advanced-config/", "Advanced Configuration"],
["/faq/", "Frequently Asked Questions"],
["/third-party/", "Third Party"]
]
}

View File

@ -1,6 +1,6 @@
# Advanced Configuration
### Disabling IPv6
## Disabling IPv6
On some docker hosts IPv6 may not be enabled. In these cases, the following message may be seen in the log:
@ -14,7 +14,7 @@ The easy fix is to add a Docker environment variable to the Nginx Proxy Manager
```
### Custom Nginx Configurations
## Custom Nginx Configurations
If you are a more advanced user, you might be itching for extra Nginx customizability.
@ -33,7 +33,7 @@ You can add your custom configuration snippet files at `/data/nginx/custom` as f
Every file is optional.
### X-FRAME-OPTIONS Header
## X-FRAME-OPTIONS Header
You can configure the [`X-FRAME-OPTIONS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) header
value by specifying it as a Docker environment variable. The default if not specified is `deny`.

16
docs/faq/README.md Normal file
View File

@ -0,0 +1,16 @@
# FAQ
## Do I have to use Docker?
Yes, that's how this project is packaged.
This makes it easier to support the project when I have control over the version of Nginx and NodeJS
being used. In future this could change if the backend was no longer using NodeJS and it's long list
of dependencies.
## Can I run it on a Raspberry Pi?
Yes! The docker image is multi-arch and is built for a variety of architectures. If yours is
[not listed](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags) please open a
[GitHub issue](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).

View File

@ -4,15 +4,15 @@
"description": "",
"main": "index.js",
"dependencies": {
"@vuepress/plugin-google-analytics": "^1.4.0",
"@vuepress/plugin-google-analytics": "^1.5.3",
"abbrev": "^1.1.1",
"accepts": "^1.3.7",
"acorn": "^7.1.1",
"agentkeepalive": "^4.1.0",
"ajv": "^6.12.0",
"acorn": "^7.4.0",
"agentkeepalive": "^4.1.3",
"ajv": "^6.12.3",
"ajv-errors": "^1.0.1",
"ajv-keywords": "^3.4.1",
"algoliasearch": "^4.1.0",
"ajv-keywords": "^3.5.2",
"algoliasearch": "^4.3.1",
"alphanum-sort": "^1.0.2",
"ansi-colors": "^4.1.1",
"ansi-escapes": "^4.3.1",
@ -30,7 +30,7 @@
"array-uniq": "^2.1.0",
"array-unique": "^0.3.2",
"asn1": "^0.2.4",
"asn1.js": "^5.3.0",
"asn1.js": "^5.4.1",
"assert": "^2.0.0",
"assert-plus": "^1.0.0",
"assign-symbols": "^2.0.2",
@ -40,11 +40,11 @@
"asynckit": "^0.4.0",
"atob": "^2.1.2",
"autocomplete.js": "^0.37.1",
"autoprefixer": "^9.7.6",
"autoprefixer": "^9.8.6",
"aws-sign2": "^0.7.0",
"aws4": "^1.9.1",
"aws4": "^1.10.0",
"babel-loader": "^8.1.0",
"babel-plugin-dynamic-import-node": "^2.3.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-module-resolver": "^4.0.0",
"balanced-match": "^1.0.0",
"base": "^3.0.0",
@ -52,9 +52,9 @@
"batch": "^0.6.1",
"bcrypt-pbkdf": "^1.0.2",
"big.js": "^5.2.2",
"binary-extensions": "^2.0.0",
"binary-extensions": "^2.1.0",
"bluebird": "^3.7.2",
"bn.js": "^5.1.1",
"bn.js": "^5.1.2",
"body-parser": "^1.19.0",
"bonjour": "^3.5.0",
"boolbase": "^1.0.0",
@ -65,18 +65,18 @@
"browserify-cipher": "^1.0.1",
"browserify-des": "^1.0.2",
"browserify-rsa": "^4.0.1",
"browserify-sign": "^4.0.4",
"browserify-sign": "^4.2.1",
"browserify-zlib": "^0.2.0",
"browserslist": "^4.11.1",
"buffer": "^5.5.0",
"browserslist": "^4.13.0",
"buffer": "^5.6.0",
"buffer-from": "^1.1.1",
"buffer-indexof": "^1.1.1",
"buffer-json": "^2.0.0",
"buffer-xor": "^2.0.2",
"builtin-status-codes": "^3.0.0",
"bytes": "^3.1.0",
"cac": "^6.5.8",
"cacache": "^15.0.0",
"cac": "^6.6.1",
"cacache": "^15.0.5",
"cache-base": "^4.0.0",
"cache-loader": "^4.1.0",
"call-me-maybe": "^1.0.1",
@ -84,12 +84,12 @@
"caller-path": "^3.0.0",
"callsites": "^3.1.0",
"camel-case": "^4.1.1",
"camelcase": "^5.3.1",
"camelcase": "^6.0.0",
"caniuse-api": "^3.0.0",
"caniuse-lite": "^1.0.30001039",
"caniuse-lite": "^1.0.30001111",
"caseless": "^0.12.0",
"chalk": "^4.0.0",
"chokidar": "^3.3.1",
"chalk": "^4.1.0",
"chokidar": "^3.4.1",
"chownr": "^2.0.0",
"chrome-trace-event": "^1.0.2",
"ci-info": "^2.0.0",
@ -106,7 +106,7 @@
"color-name": "^1.1.4",
"color-string": "^1.5.3",
"combined-stream": "^1.0.8",
"commander": "^5.0.0",
"commander": "^6.0.0",
"commondir": "^1.0.1",
"component-emitter": "^1.3.0",
"compressible": "^2.0.18",
@ -114,36 +114,36 @@
"concat-map": "^0.0.1",
"concat-stream": "^2.0.0",
"connect-history-api-fallback": "^1.6.0",
"consola": "^2.11.3",
"consola": "^2.15.0",
"console-browserify": "^1.2.0",
"consolidate": "^0.15.1",
"constants-browserify": "^1.0.0",
"content-disposition": "^0.5.3",
"content-type": "^1.0.4",
"convert-source-map": "^1.7.0",
"cookie": "^0.4.0",
"cookie": "^0.4.1",
"cookie-signature": "^1.1.0",
"copy-concurrently": "^1.0.5",
"copy-descriptor": "^0.1.1",
"copy-webpack-plugin": "^5.1.1",
"core-js": "^3.6.4",
"copy-webpack-plugin": "^6.0.3",
"core-js": "^3.6.5",
"core-util-is": "^1.0.2",
"cosmiconfig": "^6.0.0",
"create-ecdh": "^4.0.3",
"cosmiconfig": "^7.0.0",
"create-ecdh": "^4.0.4",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"cross-spawn": "^7.0.2",
"cross-spawn": "^7.0.3",
"crypto-browserify": "^3.12.0",
"css": "^2.2.4",
"css": "^3.0.0",
"css-color-names": "^1.0.1",
"css-declaration-sorter": "^5.1.2",
"css-loader": "^3.5.0",
"css-loader": "^4.2.0",
"css-parse": "^2.0.0",
"css-select": "^2.1.0",
"css-select-base-adapter": "^0.1.1",
"css-tree": "^1.0.0-alpha.39",
"css-unit-converter": "^1.1.1",
"css-what": "^3.2.1",
"css-unit-converter": "^1.1.2",
"css-what": "^3.3.0",
"cssesc": "^3.0.0",
"cssnano": "^4.1.10",
"cssnano-preset-default": "^4.0.7",
@ -158,9 +158,9 @@
"debug": "^4.1.1",
"decamelize": "^4.0.0",
"decode-uri-component": "^0.2.0",
"deep-equal": "^2.0.2",
"deep-equal": "^2.0.3",
"deepmerge": "^4.2.2",
"default-gateway": "^6.0.0",
"default-gateway": "^6.0.1",
"define-properties": "^1.1.3",
"define-property": "^2.0.2",
"del": "^5.1.0",
@ -178,52 +178,52 @@
"dns-txt": "^2.0.2",
"docsearch.js": "^2.6.3",
"dom-converter": "^0.2.0",
"dom-serializer": "^0.2.2",
"dom-serializer": "^1.0.1",
"dom-walk": "^0.1.2",
"domain-browser": "^4.0.0",
"domain-browser": "^4.16.0",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.0.0",
"domutils": "^2.1.0",
"dot-prop": "^5.2.0",
"duplexify": "^4.1.1",
"ecc-jsbn": "^0.2.0",
"ee-first": "^1.1.1",
"electron-to-chromium": "^1.3.397",
"elliptic": "^6.5.2",
"emoji-regex": "^8.0.0",
"electron-to-chromium": "^1.3.522",
"elliptic": "^6.5.3",
"emoji-regex": "^9.0.0",
"emojis-list": "^3.0.0",
"encodeurl": "^1.0.2",
"end-of-stream": "^1.4.4",
"enhanced-resolve": "^4.1.1",
"entities": "^2.0.0",
"enhanced-resolve": "^4.3.0",
"entities": "^2.0.3",
"envify": "^4.1.0",
"envinfo": "^7.5.0",
"envinfo": "^7.7.2",
"errno": "^0.1.7",
"error-ex": "^1.3.2",
"es-abstract": "^1.17.5",
"es-abstract": "^1.17.6",
"es-to-primitive": "^1.2.1",
"es6-promise": "^4.2.8",
"escape-html": "^1.0.3",
"escape-string-regexp": "^2.0.0",
"eslint-scope": "^5.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^5.1.0",
"esprima": "^4.0.1",
"esrecurse": "^4.2.1",
"estraverse": "^5.0.0",
"estraverse": "^5.2.0",
"esutils": "^2.0.3",
"etag": "^1.8.1",
"eventemitter3": "^4.0.0",
"events": "^3.1.0",
"eventemitter3": "^4.0.4",
"events": "^3.2.0",
"eventsource": "^1.0.7",
"evp_bytestokey": "^1.0.3",
"execa": "^4.0.0",
"execa": "^4.0.3",
"expand-brackets": "^4.0.0",
"express": "^4.17.1",
"extend": "^3.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^3.0.0",
"extsprintf": "^1.4.0",
"fast-deep-equal": "^3.1.1",
"fast-glob": "^3.2.2",
"fast-deep-equal": "^3.1.3",
"fast-glob": "^3.2.4",
"fast-json-stable-stringify": "^2.1.0",
"faye-websocket": "^0.11.3",
"figgy-pudding": "^3.5.2",
@ -235,7 +235,7 @@
"find-cache-dir": "^3.3.1",
"find-up": "^4.1.0",
"flush-write-stream": "^2.0.0",
"follow-redirects": "^1.11.0",
"follow-redirects": "^1.12.1",
"for-in": "^1.0.2",
"foreach": "^2.0.5",
"forever-agent": "^0.6.1",
@ -244,7 +244,7 @@
"fragment-cache": "^0.2.1",
"fresh": "^0.5.2",
"from2": "^2.3.0",
"fs-extra": "^9.0.0",
"fs-extra": "^9.0.1",
"fs-write-stream-atomic": "^1.0.10",
"fs.realpath": "^1.0.0",
"function-bind": "^1.1.1",
@ -257,21 +257,21 @@
"glob-parent": "^5.1.1",
"glob-to-regexp": "^0.4.1",
"global": "^4.4.0",
"globals": "^12.4.0",
"globby": "^11.0.0",
"globals": "^13.1.0",
"globby": "^11.0.1",
"good-listener": "^1.2.2",
"graceful-fs": "^4.2.3",
"graceful-fs": "^4.2.4",
"gray-matter": "^4.0.2",
"handle-thing": "^2.0.1",
"har-schema": "^2.0.0",
"har-validator": "^5.1.3",
"har-validator": "^5.1.5",
"has": "^1.0.3",
"has-ansi": "^4.0.0",
"has-flag": "^4.0.0",
"has-symbols": "^1.0.1",
"has-value": "^2.0.2",
"has-values": "^2.0.1",
"hash-base": "^3.0.4",
"hash-base": "^3.1.0",
"hash-sum": "^2.0.0",
"hash.js": "^1.1.7",
"he": "^1.2.0",
@ -282,24 +282,24 @@
"hsl-regex": "^1.0.0",
"hsla-regex": "^1.0.0",
"html-comment-regex": "^1.1.2",
"html-entities": "^1.2.1",
"html-entities": "^1.3.1",
"html-minifier": "^4.0.0",
"html-tags": "^3.1.0",
"htmlparser2": "^4.1.0",
"http-deceiver": "^1.2.7",
"http-errors": "^1.7.3",
"http-errors": "^1.8.0",
"http-parser-js": "^0.5.2",
"http-proxy": "^1.18.0",
"http-proxy-middleware": "^1.0.3",
"http-proxy": "^1.18.1",
"http-proxy-middleware": "^1.0.5",
"http-signature": "^1.3.4",
"https-browserify": "^1.0.0",
"iconv-lite": "^0.5.1",
"iconv-lite": "^0.6.2",
"icss-replace-symbols": "^1.1.0",
"icss-utils": "^4.1.1",
"ieee754": "^1.1.13",
"iferr": "^1.0.2",
"ignore": "^5.1.4",
"immediate": "^3.2.3",
"ignore": "^5.1.8",
"immediate": "^3.3.0",
"import-cwd": "^3.0.0",
"import-fresh": "^3.2.1",
"import-from": "^3.0.0",
@ -309,9 +309,9 @@
"infer-owner": "^1.0.4",
"inflight": "^1.0.6",
"inherits": "^2.0.4",
"internal-ip": "^6.0.0",
"internal-ip": "^6.1.0",
"invariant": "^2.2.4",
"invert-kv": "^3.0.0",
"invert-kv": "^3.0.1",
"ip": "^1.1.5",
"ip-regex": "^4.1.0",
"ipaddr.js": "^1.9.1",
@ -321,7 +321,7 @@
"is-arrayish": "^0.3.2",
"is-binary-path": "^2.1.0",
"is-buffer": "^2.0.4",
"is-callable": "^1.1.5",
"is-callable": "^1.2.0",
"is-color-stop": "^1.1.0",
"is-data-descriptor": "^2.0.0",
"is-date-object": "^1.0.2",
@ -337,25 +337,25 @@
"is-path-in-cwd": "^3.0.0",
"is-path-inside": "^3.0.2",
"is-plain-obj": "^2.1.0",
"is-plain-object": "^3.0.0",
"is-regex": "^1.0.5",
"is-plain-object": "^4.1.1",
"is-regex": "^1.1.1",
"is-resolvable": "^1.1.0",
"is-stream": "^2.0.0",
"is-svg": "^4.2.1",
"is-symbol": "^1.0.3",
"is-typedarray": "^1.0.0",
"is-windows": "^1.0.2",
"is-wsl": "^2.1.1",
"is-wsl": "^2.2.0",
"isarray": "^2.0.5",
"isexe": "^2.0.0",
"isobject": "^4.0.0",
"isstream": "^0.1.2",
"javascript-stringify": "^2.0.1",
"js-levenshtein": "^1.1.6",
"js-tokens": "^5.0.0",
"js-yaml": "^3.13.1",
"js-tokens": "^6.0.0",
"js-yaml": "^3.14.0",
"jsbn": "^1.1.0",
"jsesc": "^2.5.2",
"jsesc": "^3.0.1",
"json-parse-better-errors": "^1.0.2",
"json-schema": "^0.2.5",
"json-schema-traverse": "^0.4.1",
@ -368,12 +368,12 @@
"kind-of": "^6.0.3",
"last-call-webpack-plugin": "^3.0.0",
"lcid": "^3.1.1",
"linkify-it": "^2.2.0",
"linkify-it": "^3.0.2",
"load-script": "^1.0.0",
"loader-runner": "^3.1.0",
"loader-runner": "^4.0.0",
"loader-utils": "^2.0.0",
"locate-path": "^5.0.0",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"lodash._reinterpolate": "^3.0.0",
"lodash.chunk": "^4.2.0",
"lodash.clonedeep": "^4.5.0",
@ -385,37 +385,37 @@
"lodash.template": "^4.5.0",
"lodash.templatesettings": "^4.2.0",
"lodash.uniq": "^4.5.0",
"loglevel": "^1.6.7",
"loglevel": "^1.6.8",
"loose-envify": "^1.4.0",
"lower-case": "^2.0.1",
"lru-cache": "^5.1.1",
"make-dir": "^3.0.2",
"lru-cache": "^6.0.0",
"make-dir": "^3.1.0",
"mamacro": "^0.0.7",
"map-age-cleaner": "^0.1.3",
"map-cache": "^0.2.2",
"map-visit": "^1.0.0",
"markdown-it": "^10.0.0",
"markdown-it-anchor": "^5.2.7",
"markdown-it": "^11.0.0",
"markdown-it-anchor": "^5.3.0",
"markdown-it-chain": "^1.3.0",
"markdown-it-container": "^2.0.0",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^1.4.0",
"markdown-it-table-of-contents": "^0.4.4",
"md5.js": "^1.3.5",
"mdn-data": "^2.0.8",
"mdn-data": "^2.0.11",
"mdurl": "^1.0.1",
"media-typer": "^1.1.0",
"mem": "^6.0.1",
"mem": "^6.1.0",
"memory-fs": "^0.5.0",
"merge-descriptors": "^1.0.1",
"merge-source-map": "^1.1.0",
"merge2": "^1.3.0",
"merge2": "^1.4.1",
"methods": "^1.1.2",
"micromatch": "^4.0.2",
"miller-rabin": "^4.0.1",
"mime": "^2.4.4",
"mime-db": "^1.43.0",
"mime-types": "^2.1.26",
"mimic-fn": "^3.0.0",
"mime": "^2.4.6",
"mime-db": "^1.44.0",
"mime-types": "^2.1.27",
"mimic-fn": "^3.1.0",
"min-document": "^2.19.0",
"mini-css-extract-plugin": "^0.9.0",
"minimalistic-assert": "^1.0.1",
@ -431,16 +431,16 @@
"multicast-dns-service-types": "^1.1.0",
"nanomatch": "^1.2.13",
"negotiator": "^0.6.2",
"neo-async": "^2.6.1",
"neo-async": "^2.6.2",
"nice-try": "^2.0.1",
"no-case": "^3.0.3",
"node-forge": "^0.9.1",
"node-libs-browser": "^2.2.1",
"node-releases": "^1.1.53",
"node-releases": "^1.1.60",
"nopt": "^4.0.3",
"normalize-path": "^3.0.0",
"normalize-range": "^0.1.2",
"normalize-url": "^5.0.0",
"normalize-url": "^5.1.0",
"npm-run-path": "^4.0.1",
"nprogress": "^0.2.0",
"nth-check": "^1.0.2",
@ -449,8 +449,8 @@
"oauth-sign": "^0.9.0",
"object-assign": "^4.1.1",
"object-copy": "^1.0.0",
"object-inspect": "^1.7.0",
"object-is": "^1.0.2",
"object-inspect": "^1.8.0",
"object-is": "^1.1.2",
"object-keys": "^1.1.1",
"object-visit": "^1.0.1",
"object.assign": "^4.1.0",
@ -461,7 +461,7 @@
"on-finished": "^2.3.0",
"on-headers": "^1.0.2",
"once": "^1.4.0",
"opencollective-postinstall": "^2.0.2",
"opencollective-postinstall": "^2.0.3",
"opn": "^6.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"original": "^1.0.2",
@ -470,7 +470,7 @@
"p-defer": "^3.0.0",
"p-finally": "^2.0.1",
"p-is-promise": "^3.0.0",
"p-limit": "^2.3.0",
"p-limit": "^3.0.2",
"p-locate": "^4.1.0",
"p-map": "^4.0.0",
"p-retry": "^4.2.0",
@ -479,7 +479,7 @@
"parallel-transform": "^1.2.0",
"param-case": "^3.0.3",
"parse-asn1": "^5.1.5",
"parse-json": "^5.0.0",
"parse-json": "^5.0.1",
"parseurl": "^1.3.3",
"pascalcase": "^1.0.0",
"path-browserify": "^1.0.1",
@ -491,16 +491,16 @@
"path-parse": "^1.0.6",
"path-to-regexp": "^6.1.0",
"path-type": "^4.0.0",
"pbkdf2": "^3.0.17",
"pbkdf2": "^3.1.1",
"performance-now": "^2.1.0",
"pify": "^5.0.0",
"pinkie": "^2.0.4",
"pinkie-promise": "^2.0.1",
"pkg-dir": "^4.2.0",
"pkg-up": "^3.1.0",
"portfinder": "^1.0.25",
"portfinder": "^1.0.28",
"posix-character-classes": "^1.0.0",
"postcss": "^7.0.27",
"postcss": "^7.0.32",
"postcss-calc": "^7.0.2",
"postcss-colormin": "^4.0.3",
"postcss-convert-values": "^4.0.1",
@ -517,7 +517,7 @@
"postcss-minify-params": "^4.0.2",
"postcss-minify-selectors": "^4.0.2",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2",
"postcss-modules-local-by-default": "^3.0.3",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"postcss-normalize-charset": "^4.0.1",
@ -536,9 +536,9 @@
"postcss-selector-parser": "^6.0.2",
"postcss-svgo": "^4.0.2",
"postcss-unique-selectors": "^4.0.1",
"postcss-value-parser": "^4.0.3",
"postcss-value-parser": "^4.1.0",
"prepend-http": "^3.0.1",
"prettier": "^2.0.4",
"prettier": "^2.0.5",
"pretty-error": "^2.1.1",
"pretty-time": "^1.1.0",
"prismjs": "^1.20.0",
@ -555,8 +555,8 @@
"pumpify": "^2.0.1",
"punycode": "^2.1.1",
"q": "^1.5.1",
"qs": "^6.9.3",
"query-string": "^6.12.0",
"qs": "^6.9.4",
"query-string": "^6.13.1",
"querystring": "^0.2.0",
"querystring-es3": "^0.2.1",
"querystringify": "^2.1.1",
@ -567,14 +567,14 @@
"readable-stream": "^3.6.0",
"readdirp": "^3.4.0",
"reduce": "^1.0.2",
"regenerate": "^1.4.0",
"regenerate": "^1.4.1",
"regenerate-unicode-properties": "^8.2.0",
"regenerator-runtime": "^0.13.5",
"regenerator-transform": "^0.14.4",
"regenerator-runtime": "^0.13.7",
"regenerator-transform": "^0.14.5",
"regex-not": "^1.0.2",
"regexp.prototype.flags": "^1.3.0",
"regexpu-core": "^4.7.0",
"regjsgen": "^0.5.1",
"regjsgen": "^0.5.2",
"regjsparser": "^0.6.4",
"relateurl": "^0.2.7",
"remove-trailing-separator": "^1.1.0",
@ -586,7 +586,7 @@
"require-main-filename": "^2.0.0",
"requires-port": "^1.0.0",
"reselect": "^4.0.0",
"resolve": "^1.15.1",
"resolve": "^1.17.0",
"resolve-cwd": "^3.0.0",
"resolve-from": "^5.0.0",
"resolve-url": "^0.2.1",
@ -597,18 +597,18 @@
"rimraf": "^3.0.2",
"ripemd160": "^2.0.2",
"run-queue": "^2.0.1",
"safe-buffer": "^5.2.0",
"safe-buffer": "^5.2.1",
"safe-regex": "^2.1.1",
"safer-buffer": "^2.1.2",
"sax": "^1.2.4",
"schema-utils": "^2.6.5",
"schema-utils": "^2.7.0",
"section-matter": "^1.0.0",
"select": "^1.1.2",
"select-hose": "^2.0.0",
"selfsigned": "^1.10.7",
"semver": "^7.2.1",
"semver": "^7.3.2",
"send": "^0.17.1",
"serialize-javascript": "^3.0.0",
"serialize-javascript": "^4.0.0",
"serve-index": "^1.9.1",
"serve-static": "^1.14.1",
"set-blocking": "^2.0.0",
@ -620,19 +620,19 @@
"shebang-regex": "^3.0.0",
"signal-exit": "^3.0.3",
"simple-swizzle": "^0.2.2",
"sitemap": "^6.1.0",
"sitemap": "^6.2.0",
"slash": "^3.0.0",
"smoothscroll-polyfill": "^0.4.4",
"snapdragon": "^0.12.0",
"snapdragon-node": "^3.0.0",
"snapdragon-util": "^5.0.1",
"sockjs": "^0.3.20",
"sockjs-client": "^1.4.0",
"sockjs": "^0.3.21",
"sockjs-client": "^1.5.0",
"sort-keys": "^4.0.0",
"source-list-map": "^2.0.1",
"source-map": "^0.7.3",
"source-map-resolve": "^0.6.0",
"source-map-support": "^0.5.16",
"source-map-support": "^0.5.19",
"source-map-url": "^0.4.0",
"spdy": "^4.0.2",
"spdy-transport": "^3.0.0",
@ -641,13 +641,13 @@
"sshpk": "^1.16.1",
"ssri": "^8.0.0",
"stable": "^0.1.8",
"stack-utils": "^2.0.1",
"stack-utils": "^2.0.2",
"static-extend": "^0.1.2",
"statuses": "^1.5.0",
"statuses": "^2.0.0",
"std-env": "^2.2.1",
"stream-browserify": "^2.0.2",
"stream-browserify": "^3.0.0",
"stream-each": "^1.2.3",
"stream-http": "^3.1.0",
"stream-http": "^3.1.1",
"stream-shift": "^1.0.1",
"strict-uri-encode": "^2.0.0",
"string-width": "^4.2.0",
@ -658,17 +658,17 @@
"strip-bom-string": "^1.0.0",
"strip-eof": "^2.0.0",
"stylehacks": "^4.0.3",
"stylus": "^0.54.7",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"supports-color": "^7.1.0",
"svg-tags": "^1.0.0",
"svgo": "^1.3.2",
"tapable": "^1.1.3",
"terser": "^4.6.10",
"terser-webpack-plugin": "^2.3.5",
"terser": "^5.0.0",
"terser-webpack-plugin": "^4.0.0",
"text-table": "^0.2.0",
"through": "^2.3.8",
"through2": "^3.0.1",
"through2": "^4.0.2",
"thunky": "^1.1.0",
"timers-browserify": "^2.0.11",
"timsort": "^0.3.0",
@ -684,15 +684,15 @@
"toposort": "^2.0.2",
"tough-cookie": "^4.0.0",
"tr46": "^2.0.2",
"tslib": "^1.11.1",
"tslib": "^2.0.0",
"tty-browserify": "^0.0.1",
"tunnel-agent": "^0.6.0",
"tweetnacl": "^1.0.3",
"type-fest": "^0.13.0",
"type-fest": "^0.16.0",
"type-is": "^1.6.18",
"typedarray": "^0.0.6",
"uc.micro": "^1.0.6",
"uglify-js": "^3.8.1",
"uglify-js": "^3.10.1",
"unicode-canonical-property-names-ecmascript": "^1.0.4",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.2.0",
@ -702,7 +702,7 @@
"uniqs": "^2.0.0",
"unique-filename": "^1.1.1",
"unique-slug": "^2.0.2",
"universalify": "^1.0.0",
"universalify": "^2.0.0",
"unpipe": "^1.0.0",
"unquote": "^1.1.1",
"unset-value": "^1.0.0",
@ -711,60 +711,60 @@
"uri-js": "^4.2.2",
"urix": "^0.1.0",
"url": "^0.11.0",
"url-loader": "^4.0.0",
"url-loader": "^4.1.0",
"url-parse": "^1.4.7",
"use": "^3.1.1",
"util": "^0.12.2",
"util": "^0.12.3",
"util-deprecate": "^1.0.2",
"util.promisify": "^1.0.1",
"utila": "^0.4.0",
"utils-merge": "^1.0.1",
"uuid": "^7.0.3",
"uuid": "^8.3.0",
"vary": "^1.1.2",
"vendors": "^1.0.4",
"verror": "^1.10.0",
"vm-browserify": "^1.1.2",
"vue": "^2.6.11",
"vue-hot-reload-api": "^2.3.4",
"vue-loader": "^15.9.1",
"vue-router": "^3.1.6",
"vue-loader": "^15.9.3",
"vue-router": "^3.4.0",
"vue-server-renderer": "^2.6.11",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"vue-template-es2015-compiler": "^1.9.1",
"vuepress": "^1.4.0",
"vuepress": "^1.5.3",
"vuepress-html-webpack-plugin": "^3.2.0",
"vuepress-plugin-container": "^2.1.2",
"vuepress-plugin-container": "^2.1.4",
"vuepress-plugin-sitemap": "^2.3.1",
"vuepress-plugin-smooth-scroll": "^0.0.9",
"vuepress-plugin-zooming": "^1.1.7",
"watchpack": "^1.6.1",
"watchpack": "^1.7.4",
"wbuf": "^1.7.3",
"webidl-conversions": "^6.0.0",
"webpack": "^4.42.1",
"webpack-chain": "^6.4.0",
"webidl-conversions": "^6.1.0",
"webpack": "^4.44.1",
"webpack-chain": "^6.5.1",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.10.3",
"webpack-dev-server": "^3.11.0",
"webpack-log": "^3.0.1",
"webpack-merge": "^4.2.2",
"webpack-merge": "^5.1.1",
"webpack-sources": "^1.4.3",
"webpackbar": "^4.0.0",
"websocket-driver": "^0.7.3",
"websocket-extensions": "^0.1.3",
"whatwg-url": "^8.0.0",
"websocket-driver": "^0.7.4",
"websocket-extensions": "^0.1.4",
"whatwg-url": "^8.1.0",
"when": "^3.7.8",
"which": "^2.0.2",
"which-module": "^2.0.0",
"worker-farm": "^1.7.0",
"wrap-ansi": "^6.2.0",
"wrap-ansi": "^7.0.0",
"wrappy": "^1.0.2",
"ws": "^7.2.3",
"xmlbuilder": "^15.1.0",
"ws": "^7.3.1",
"xmlbuilder": "^15.1.1",
"xtend": "^4.0.2",
"y18n": "^4.0.0",
"yallist": "^4.0.0",
"yargs": "^15.3.1",
"yargs-parser": "^18.1.2",
"yargs": "^15.4.1",
"yargs-parser": "^18.1.3",
"zepto": "^1.2.0"
},
"devDependencies": {},

View File

@ -23,15 +23,31 @@ Here's an example configuration for `mysql` (or mariadb) that is compatible with
}
```
Alternatively if you would like to use a Sqlite database file:
```json
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
}
}
}
}
```
Once you've created your configuration file it's easy to mount it in the docker container.
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys
affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
### Database
### MySQL Database
This app doesn't come with a database, you have to provide one yourself. Currently only `mysql/mariadb` is supported for the minimum versions:
If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
- MySQL v5.7.8+
- MariaDB v10.2.7+
@ -103,7 +119,7 @@ The docker images support the following architectures:
The docker images are a manifest of all the architecture docker builds supported, so this means
you don't have to worry about doing anything special and you can follow the common instructions above.
Check out the [dockerhub tags](https://cloud.docker.com/repository/registry-1.docker.io/jc21/nginx-proxy-manager/tags)
Check out the [dockerhub tags](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags)
for a list of supported architectures and if you want one that doesn't exist,
[create a feature request](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
<div class="col-sm-6 col-md-6">
<div class="form-group">
<label class="custom-switch">
<input type="checkbox" class="custom-switch-input" name="satify_any" value="1"<%- typeof satify_any !== 'undefined' && satify_any ? ' checked' : '' %>>
<input type="checkbox" class="custom-switch-input" name="satisfy_any" value="1"<%- typeof satisfy_any !== 'undefined' && satisfy_any ? ' checked' : '' %>>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description"><%- i18n('access-lists', 'satisfy-any') %></span>
</label>
@ -48,7 +48,7 @@
</div>
</div>
</div>
<div class="items"><!-- items --></div>
</div>

View File

@ -72,7 +72,7 @@ module.exports = Mn.View.extend({
let data = {
name: form_data.name,
satify_any: !!form_data.satify_any,
satisfy_any: !!form_data.satisfy_any,
items: items_data,
clients: clients_data
};

View File

@ -18,7 +18,7 @@
<%- i18n('access-lists', 'client-count', {count: clients.length || 0}) %>
</td>
<td>
<% if (satify_any) { %>
<% if (satisfy_any) { %>
<%- i18n('str', 'any') %>
<%} else { %>
<%- i18n('str', 'all') %>

View File

@ -44,7 +44,7 @@
<div class="col-sm-5 col-md-5">
<div class="form-group">
<label class="form-label"><%- i18n('proxy-hosts', 'forward-host') %><span class="form-required">*</span></label>
<input type="text" name="forward_host" class="form-control text-monospace" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="50" required>
<input type="text" name="forward_host" class="form-control text-monospace" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="255" required>
</div>
</div>
<div class="col-sm-4 col-md-4">

View File

@ -38,7 +38,7 @@
<div class="col-sm-5 col-md-5">
<div class="form-group">
<label class="form-label"><%- i18n('proxy-hosts', 'forward-host') %><span class="form-required">*</span></label>
<input type="text" name="forward_host" class="form-control text-monospace model" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="50" required>
<input type="text" name="forward_host" class="form-control text-monospace model" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="200" required>
<span style="font-size: 9px;"><%- i18n('proxy-hosts', 'custom-forward-host-help') %></span>
</div>
</div>
@ -61,4 +61,4 @@
<i class="fa fa-trash"></i> <%- i18n('locations', 'delete') %>
</a>
</div>
</div>
</div>

View File

@ -195,7 +195,7 @@
"authorization": "Authorization",
"access": "Access",
"satisfy": "Satisfy",
"satisfy-any": "Satify Any"
"satisfy-any": "Satisfy Any"
},
"users": {
"title": "Users",

View File

@ -19,7 +19,7 @@
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.0.4",
"imports-loader": "^0.8.0",
"jquery": "^3.4.1",
"jquery": "^3.5.0",
"jquery-mask-plugin": "^1.14.16",
"jquery-serializejson": "^2.9.0",
"marionette.approuter": "^1.0.2",

File diff suppressed because it is too large Load Diff

17
scripts/.common.sh Normal file
View File

@ -0,0 +1,17 @@
#!/bin/bash
# Colors
BLUE='\E[1;34m'
CYAN='\E[1;36m'
GREEN='\E[1;32m'
RED='\E[1;31m'
RESET='\E[0m'
YELLOW='\E[1;33m'
export BLUE CYAN GREEN RED RESET YELLOW
# Docker Compose
COMPOSE_PROJECT_NAME="npmdev"
COMPOSE_FILE="docker/docker-compose.dev.yml"
export COMPOSE_FILE COMPOSE_PROJECT_NAME

View File

@ -1,10 +1,7 @@
#!/bin/bash
CYAN='\E[1;36m'
YELLOW='\E[1;33m'
BLUE='\E[1;34m'
GREEN='\E[1;32m'
RESET='\E[0m'
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/.common.sh"
echo -e "${BLUE} ${CYAN}Building docker multiarch: ${YELLOW}${*}${RESET}"

View File

@ -1,15 +1,7 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
RED='\E[1;31m'
RESET='\E[0m'
COMPOSE_PROJECT_NAME="npmdev"
COMPOSE_FILE="docker/docker-compose.dev.yml"
export COMPOSE_FILE COMPOSE_PROJECT_NAME
. "$DIR/.common.sh"
# Ensure docker-compose exists
# Make sure docker exists

View File

@ -1,12 +1,7 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
RED='\E[1;31m'
GREEN='\E[1;32m'
RESET='\E[0m'
. "$DIR/.common.sh"
# Ensure docker-compose exists
if hash docker 2>/dev/null; then

View File

@ -2,11 +2,8 @@
# Note: This script is designed to be run inside CI builds
CYAN='\E[1;36m'
YELLOW='\E[1;33m'
BLUE='\E[1;34m'
GREEN='\E[1;32m'
RESET='\E[0m'
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/.common.sh"
echo -e "${BLUE} ${CYAN}Uploading docs in: ${YELLOW}$1${RESET}"

View File

@ -1,17 +1,13 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
RED='\E[1;31m'
GREEN='\E[1;32m'
RESET='\E[0m'
. "$DIR/.common.sh"
DOCKER_IMAGE=jc21/alpine-nginx-full:node
# Ensure docker exists
if hash docker 2>/dev/null; then
docker pull "${DOCKER_IMAGE}"
cd "${DIR}/.."
echo -e "${BLUE} ${CYAN}Building Frontend ...${RESET}"
docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend"

View File

@ -1,16 +1,7 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
COMPOSE_PROJECT_NAME="npmdev"
COMPOSE_FILE="docker/docker-compose.dev.yml"
export COMPOSE_FILE COMPOSE_PROJECT_NAME
. "$DIR/.common.sh"
# Ensure docker-compose exists
if hash docker-compose 2>/dev/null; then

View File

@ -1,15 +1,7 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
RED='\E[1;31m'
RESET='\E[0m'
COMPOSE_PROJECT_NAME="npmdev"
COMPOSE_FILE="docker/docker-compose.dev.yml"
export COMPOSE_FILE COMPOSE_PROJECT_NAME
. "$DIR/.common.sh"
# Ensure docker-compose exists
# Make sure docker exists

View File

@ -1,15 +1,7 @@
#!/bin/bash -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CYAN='\E[1;36m'
BLUE='\E[1;34m'
RED='\E[1;31m'
RESET='\E[0m'
COMPOSE_PROJECT_NAME="npmdev"
COMPOSE_FILE="docker/docker-compose.dev.yml"
export COMPOSE_FILE COMPOSE_PROJECT_NAME
. "$DIR/.common.sh"
# Ensure docker-compose exists
if hash docker-compose 2>/dev/null; then

View File

@ -1,11 +1,7 @@
#!/bin/bash
CYAN='\E[1;36m'
YELLOW='\E[1;33m'
BLUE='\E[1;34m'
GREEN='\E[1;32m'
RED='\E[1;31m'
RESET='\E[0m'
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/.common.sh"
if [ "$1" == "" ]; then
echo "Waits for a docker container to be healthy."

3
test/.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode
node_modules
results
cypress/videos

View File

@ -1,4 +1,4 @@
FROM cypress/included:4.0.2
FROM cypress/included:4.12.1
COPY --chown=1000 ./test /test

View File

@ -1,15 +1,12 @@
{
"requestTimeout": 30000,
"defaultCommandTimeout": 20000,
"reporter": "mocha-junit-reporter",
"reporter": "cypress-multi-reporters",
"reporterOptions": {
"jenkinsMode": true,
"rootSuiteTitle": "Cypress",
"jenkinsClassnamePrefix": "Cypress.",
"mochaFile": "/results/junit/my-test-output-[hash].xml"
"configFile": "multi-reporter.json"
},
"videosFolder": "/results/videos",
"screenshotsFolder": "/results/screenshots",
"videosFolder": "results/videos",
"screenshotsFolder": "results/screenshots",
"env": {
"swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 4

View File

@ -1,13 +1,14 @@
{
"requestTimeout": 30000,
"defaultCommandTimeout": 20000,
"reporter": "junit",
"reporter": "cypress-multi-reporters",
"reporterOptions": {
"mochaFile": "results/junit/my-test-output-[hash].xml"
"configFile": "multi-reporter.json"
},
"video": false,
"screenshotsFolder": "cypress/results/screenshots",
"videos": false,
"screenshotsFolder": "results/screenshots",
"env": {
"swaggerBase": "{{baseUrl}}/api/schema"
"swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 0
}
}

View File

@ -2,17 +2,15 @@
describe('Basic API checks', () => {
it('Should return a valid health payload', function () {
cy.wait(2000);
cy.task('backendApiGet', {
path: '/api/',
}).then((data) => {
// Check the swagger schema:
cy.validateSwaggerSchema('get', '/', data);
cy.validateSwaggerSchema('get', 200, '/', data);
});
});
it('Should return a valid schema payload', function () {
cy.wait(2000);
cy.task('backendApiGet', {
path: '/api/schema',
}).then((data) => {

View File

@ -0,0 +1,48 @@
/// <reference types="Cypress" />
describe('Users endpoints', () => {
let token;
before(() => {
cy.getToken().then((tok) => {
token = tok;
});
});
it('Should be able to get yourself', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users/me'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
});
});
it('Should be able to get all users', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users', data);
expect(data.length).to.be.greaterThan(0);
});
});
it('Should be able to update yourself', function() {
cy.task('backendApiPut', {
token: token,
path: '/api/users/me',
data: {
name: 'changed name'
}
}).then((data) => {
cy.validateSwaggerSchema('put', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
expect(data.name).to.be.equal('changed name');
});
});
});

View File

@ -13,82 +13,30 @@
* Check the swagger schema:
*
* @param {string} method API Method in swagger doc, "get", "put", "post", "delete"
* @param {number} statusCode API status code in swagger doc
* @param {string} path Swagger doc endpoint path, exactly as defined in swagger doc
* @param {*} data The API response data to check against the swagger schema
*/
Cypress.Commands.add('validateSwaggerSchema', (method, path, data) => {
Cypress.Commands.add('validateSwaggerSchema', (method, statusCode, path, data) => {
cy.task('validateSwaggerSchema', {
file: Cypress.env('swaggerBase'),
endpoint: path,
method: method,
statusCode: 200,
statusCode: statusCode,
responseSchema: data,
verbose: true
}).should('equal', null);
});
Cypress.Commands.add('getToken', () => {
cy.task('backendApiGet', {
path: '/api/',
}).then((data) => {
// Check the swagger schema:
cy.task('validateSwaggerSchema', {
endpoint: '/',
method: 'get',
statusCode: 200,
responseSchema: data,
verbose: true,
}).should('equal', null);
if (!data.result.setup) {
cy.log('Setup = false');
// create a new user
cy.createInitialUser().then(() => {
return cy.getToken();
});
} else {
cy.log('Setup = true');
// login with existing user
cy.task('backendApiPost', {
path: '/api/tokens',
data: {
type: 'password',
identity: 'jc@jc21.com',
secret: 'changeme'
}
}).then(res => {
cy.wrap(res.result.token);
});
}
});
});
Cypress.Commands.add('createInitialUser', () => {
return cy.task('backendApiPost', {
path: '/api/users',
// login with existing user
cy.task('backendApiPost', {
path: '/api/tokens',
data: {
name: 'Jamie Curnow',
nickname: 'James',
email: 'jc@jc21.com',
roles: [],
is_disabled: false,
auth: {
type: 'password',
secret: 'changeme'
}
identity: 'admin@example.com',
secret: 'changeme'
}
}).then((data) => {
// Check the swagger schema:
cy.task('validateSwaggerSchema', {
endpoint: '/users',
method: 'post',
statusCode: 201,
responseSchema: data,
verbose: true
}).should('equal', null);
expect(data.result).to.have.property('id');
expect(data.result.id).to.be.greaterThan(0);
cy.wrap(data.result);
}).then(res => {
cy.wrap(res.token);
});
});

9
test/multi-reporter.json Normal file
View File

@ -0,0 +1,9 @@
{
"reporterEnabled": "spec, mocha-junit-reporter",
"mochaJunitReporterReporterOptions": {
"jenkinsMode": true,
"rootSuiteTitle": "Cypress.npm",
"jenkinsClassnamePrefix": "Cypress.npm.",
"mochaFile": "results/junit/cypress.npm.[hash].xml"
}
}

View File

@ -4,21 +4,23 @@
"description": "",
"main": "index.js",
"dependencies": {
"@jc21/cypress-swagger-validation": "^0.0.5",
"@jc21/cypress-swagger-validation": "^0.0.9",
"@jc21/restler": "^3.4.0",
"chalk": "^3.0.0",
"cypress": "^4.0.2",
"chalk": "^4.1.0",
"cypress": "^4.12.1",
"cypress-multi-reporters": "^1.4.0",
"cypress-plugin-retries": "^1.5.2",
"eslint": "^6.7.2",
"eslint": "^7.6.0",
"eslint-plugin-align-assignments": "^1.1.2",
"eslint-plugin-chai-friendly": "^0.5.0",
"eslint-plugin-cypress": "^2.8.0",
"lodash": "^4.17.15",
"mocha": "^6.2.2",
"mocha-junit-reporter": "^1.23.1"
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-cypress": "^2.11.1",
"lodash": "^4.17.19",
"mocha": "^8.1.1",
"mocha-junit-reporter": "^2.0.0"
},
"scripts": {
"cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=http://127.0.0.1:3081"
"cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}",
"cypress:headless": "cypress run --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}"
},
"author": "",
"license": "ISC"

File diff suppressed because it is too large Load Diff