mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-10-06 21:00:10 +00:00
Compare commits
157 Commits
03fbebc281
...
v2.12.5
Author | SHA1 | Date | |
---|---|---|---|
|
307cb94e84 | ||
|
63ae924fbc | ||
|
1710a263c0 | ||
|
1357774f21 | ||
|
5f54490d86 | ||
|
c97b8a339d | ||
|
ed1d90ee7f | ||
|
70894e55b8 | ||
|
817021a43d | ||
|
36e3449a56 | ||
|
db9f25638f | ||
|
ddd3355d95 | ||
|
aade8b42fc | ||
|
3735f3c11d | ||
|
b84762b5b9 | ||
|
953faeac15 | ||
|
c58f3f3ec9 | ||
|
0ee4d04d5f | ||
|
94f6756250 | ||
|
27e3f73854 | ||
|
d98f4b43dc | ||
|
ff3116a626 | ||
|
7047750b04 | ||
|
0792fc0768 | ||
|
9758c12ca3 | ||
|
ccd69c8867 | ||
|
23fd1fec6c | ||
|
6f04543744 | ||
|
cbb1fe44ca | ||
|
4c23f22d5b | ||
|
af5d3eccd6 | ||
|
a87283b030 | ||
|
97dbbdd60f | ||
|
ec81f2489a | ||
|
d0ec8e89aa | ||
|
9a96fbb5f4 | ||
|
a573450bb8 | ||
|
60a25ffbd5 | ||
|
7d2369b380 | ||
|
64f00e8dba | ||
|
c99143f548 | ||
|
cc4ee6919a | ||
|
8a69c65b40 | ||
|
95ee5ca958 | ||
|
40f22d30c4 | ||
|
30dfa9e3de | ||
|
b873499feb | ||
|
ef69be2036 | ||
|
7580e65dd4 | ||
|
f11dc5d7c1 | ||
|
77061a7bd6 | ||
|
b6afc19135 | ||
|
09ba400d09 | ||
|
0291cfc270 | ||
|
34267e0af9 | ||
|
f327c1e825 | ||
|
6f539979ec | ||
|
3d8079a137 | ||
|
6d6d83c0d0 | ||
|
100a4888d0 | ||
|
34a46bd733 | ||
|
7f8adc7e50 | ||
|
98d118cb74 | ||
|
4fb93542c3 | ||
|
4fe305520a | ||
|
76be31cf76 | ||
|
55dadb2004 | ||
|
d9cdb3dc2c | ||
|
0cab720f23 | ||
|
f5879dff6c | ||
|
5e66d677f1 | ||
|
18830f81b0 | ||
|
341ac65587 | ||
|
078baa255a | ||
|
bf9d9bd43b | ||
|
a394b25e61 | ||
|
1c47fc2ba4 | ||
|
312e2ab80c | ||
|
d147ccd88d | ||
|
03fd292c61 | ||
|
79d28f03d0 | ||
|
b09147eca8 | ||
|
c5a319cb20 | ||
|
c4df89df1f | ||
|
34c703f8b4 | ||
|
0a05d8f0ad | ||
|
0a9141fad5 | ||
|
42836774b7 | ||
|
2a07544f58 | ||
|
dc9d884743 | ||
|
0d5d2b1b7c | ||
|
df48b835c4 | ||
|
8a1557154a | ||
|
a6af5ec2c7 | ||
|
14d7c35fd7 | ||
|
cfcf78aaee | ||
|
3a01b2c84f | ||
|
e1c84a5c10 | ||
|
c56c95a59a | ||
|
6a60627833 | ||
|
b4793d3c16 | ||
|
68a7803513 | ||
|
2657af97cf | ||
|
4452f014b9 | ||
|
cd80cc8e4d | ||
|
ee4250d770 | ||
|
3dbc70faa6 | ||
|
3091c21cae | ||
|
57cd2a1919 | ||
|
ad5936c530 | ||
|
498109addb | ||
|
3f3aacd7ec | ||
|
bb4ecf812d | ||
|
c05f9695d0 | ||
|
6343b398f0 | ||
|
59362b7477 | ||
|
aedaaa18e0 | ||
|
080bd0b749 | ||
|
9687e9e450 | ||
|
5a234bb88c | ||
|
4de4b65036 | ||
|
f1c97c7c36 | ||
|
b4f49969d6 | ||
|
ec12d8f9bf | ||
|
e50e3def9d | ||
|
6415f284f9 | ||
|
98e5997f0a | ||
|
fc30a92bd4 | ||
|
e2011ee45c | ||
|
1406e75c2c | ||
|
ca3ee98c68 | ||
|
f90d839ebe | ||
|
be5278f31e | ||
|
73110d5e1e | ||
|
356b98bf7e | ||
|
3eecf7a38b | ||
|
7f9240dda7 | ||
|
f537619ffe | ||
|
805968aac6 | ||
|
2a4093c1b8 | ||
|
ae2ac8a733 | ||
|
5d087f1256 | ||
|
c6eca2578e | ||
|
56033bee9c | ||
|
c6630e87bb | ||
|
d6b98f51b0 | ||
|
1e322804ce | ||
|
151160a834 | ||
|
126d3d44ca | ||
|
2cee211fb0 | ||
|
a56342c76a | ||
|
4c89379671 | ||
|
10b9a49274 | ||
|
595a742c40 | ||
|
c171752137 | ||
|
5084cb7296 | ||
|
e677bfa2e8 |
57
Jenkinsfile
vendored
57
Jenkinsfile
vendored
@@ -128,7 +128,7 @@ pipeline {
|
|||||||
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
}
|
}
|
||||||
unstable {
|
unstable {
|
||||||
dir(path: 'testing/results') {
|
dir(path: 'test/results') {
|
||||||
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,45 @@ pipeline {
|
|||||||
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
}
|
}
|
||||||
unstable {
|
unstable {
|
||||||
dir(path: 'testing/results') {
|
dir(path: 'test/results') {
|
||||||
|
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Test Postgres') {
|
||||||
|
environment {
|
||||||
|
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_postgres"
|
||||||
|
COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.postgres.yml'
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
not {
|
||||||
|
equals expected: 'UNSTABLE', actual: currentBuild.result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh 'rm -rf ./test/results/junit/*'
|
||||||
|
sh './scripts/ci/fulltest-cypress'
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
// Dumps to analyze later
|
||||||
|
sh 'mkdir -p debug/postgres'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/postgres/docker_fullstack.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q stepca) > debug/postgres/docker_stepca.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q db-postgres) > debug/postgres/docker_db-postgres.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik) > debug/postgres/docker_authentik.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik-redis) > debug/postgres/docker_authentik-redis.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik-ldap) > debug/postgres/docker_authentik-ldap.log 2>&1'
|
||||||
|
|
||||||
|
junit 'test/results/junit/*'
|
||||||
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
|
}
|
||||||
|
unstable {
|
||||||
|
dir(path: 'test/results') {
|
||||||
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,12 +241,17 @@ pipeline {
|
|||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on
|
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev):
|
||||||
[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev)
|
```
|
||||||
as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
|
nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}
|
||||||
|
```
|
||||||
|
|
||||||
**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
|
> [!NOTE]
|
||||||
**Note:** this is a different docker image namespace than the official image
|
> Ensure you backup your NPM instance before testing this image! Especially if there are database changes.
|
||||||
|
> This is a different docker image namespace than the official image.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Changes and additions to DNS Providers require verification by at least 2 members of the community!
|
||||||
""", true)
|
""", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://nginxproxymanager.com/github.png">
|
<img src="https://nginxproxymanager.com/github.png">
|
||||||
<br><br>
|
<br><br>
|
||||||
<img src="https://img.shields.io/badge/version-2.12.1-green.svg?style=for-the-badge">
|
<img src="https://img.shields.io/badge/version-2.12.5-green.svg?style=for-the-badge">
|
||||||
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
||||||
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
const schema = require('./schema');
|
const schema = require('./schema');
|
||||||
const logger = require('./logger').global;
|
const logger = require('./logger').global;
|
||||||
|
|
||||||
|
const IP_RANGES_FETCH_ENABLED = process.env.IP_RANGES_FETCH_ENABLED !== 'false';
|
||||||
|
|
||||||
async function appStart () {
|
async function appStart () {
|
||||||
const migrate = require('./migrate');
|
const migrate = require('./migrate');
|
||||||
const setup = require('./setup');
|
const setup = require('./setup');
|
||||||
@@ -13,7 +15,16 @@ async function appStart () {
|
|||||||
return migrate.latest()
|
return migrate.latest()
|
||||||
.then(setup)
|
.then(setup)
|
||||||
.then(schema.getCompiledSchema)
|
.then(schema.getCompiledSchema)
|
||||||
.then(internalIpRanges.fetch)
|
.then(() => {
|
||||||
|
if (IP_RANGES_FETCH_ENABLED) {
|
||||||
|
logger.info('IP Ranges fetch is enabled');
|
||||||
|
return internalIpRanges.fetch().catch((err) => {
|
||||||
|
logger.error('IP Ranges fetch failed, continuing anyway:', err.message);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.info('IP Ranges fetch is disabled by environment variable');
|
||||||
|
}
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
internalCertificate.initTimer();
|
internalCertificate.initTimer();
|
||||||
internalIpRanges.initTimer();
|
internalIpRanges.initTimer();
|
||||||
|
@@ -81,7 +81,7 @@ const internalAccessList = {
|
|||||||
|
|
||||||
return internalAccessList.build(row)
|
return internalAccessList.build(row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (row.proxy_host_count) {
|
if (parseInt(row.proxy_host_count, 10)) {
|
||||||
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -223,7 +223,7 @@ const internalAccessList = {
|
|||||||
.then((row) => {
|
.then((row) => {
|
||||||
return internalAccessList.build(row)
|
return internalAccessList.build(row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (row.proxy_host_count) {
|
if (parseInt(row.proxy_host_count, 10)) {
|
||||||
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
||||||
}
|
}
|
||||||
}).then(internalNginx.reload)
|
}).then(internalNginx.reload)
|
||||||
@@ -252,9 +252,13 @@ const internalAccessList = {
|
|||||||
let query = accessListModel
|
let query = accessListModel
|
||||||
.query()
|
.query()
|
||||||
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
||||||
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
.leftJoin('proxy_host', function() {
|
||||||
|
this.on('proxy_host.access_list_id', '=', 'access_list.id')
|
||||||
|
.andOn('proxy_host.is_deleted', '=', 0);
|
||||||
|
})
|
||||||
.where('access_list.is_deleted', 0)
|
.where('access_list.is_deleted', 0)
|
||||||
.andWhere('access_list.id', data.id)
|
.andWhere('access_list.id', data.id)
|
||||||
|
.groupBy('access_list.id')
|
||||||
.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
|
.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
@@ -373,7 +377,10 @@ const internalAccessList = {
|
|||||||
let query = accessListModel
|
let query = accessListModel
|
||||||
.query()
|
.query()
|
||||||
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
||||||
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
.leftJoin('proxy_host', function() {
|
||||||
|
this.on('proxy_host.access_list_id', '=', 'access_list.id')
|
||||||
|
.andOn('proxy_host.is_deleted', '=', 0);
|
||||||
|
})
|
||||||
.where('access_list.is_deleted', 0)
|
.where('access_list.is_deleted', 0)
|
||||||
.groupBy('access_list.id')
|
.groupBy('access_list.id')
|
||||||
.allowGraph('[owner,items,clients]')
|
.allowGraph('[owner,items,clients]')
|
||||||
@@ -501,8 +508,13 @@ const internalAccessList = {
|
|||||||
if (typeof item.password !== 'undefined' && item.password.length) {
|
if (typeof item.password !== 'undefined' && item.password.length) {
|
||||||
logger.info('Adding: ' + item.username);
|
logger.info('Adding: ' + item.username);
|
||||||
|
|
||||||
utils.execFile('/usr/bin/htpasswd', ['-b', htpasswd_file, item.username, item.password])
|
utils.execFile('openssl', ['passwd', '-apr1', item.password])
|
||||||
.then((/*result*/) => {
|
.then((res) => {
|
||||||
|
try {
|
||||||
|
fs.appendFileSync(htpasswd_file, item.username + ':' + res + '\n', {encoding: 'utf8'});
|
||||||
|
} catch (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
const auditLogModel = require('../models/audit-log');
|
const auditLogModel = require('../models/audit-log');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
const internalAuditLog = {
|
const internalAuditLog = {
|
||||||
|
|
||||||
@@ -22,9 +23,9 @@ const internalAuditLog = {
|
|||||||
.allowGraph('[user]');
|
.allowGraph('[user]');
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string' && search_query.length > 0) {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where('meta', 'like', '%' + search_query + '%');
|
this.where(castJsonIfNeed('meta'), 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -313,6 +313,9 @@ const internalCertificate = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowGraph('[owner]')
|
.allowGraph('[owner]')
|
||||||
|
.allowGraph('[proxy_hosts]')
|
||||||
|
.allowGraph('[redirection_hosts]')
|
||||||
|
.allowGraph('[dead_hosts]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@@ -464,6 +467,9 @@ const internalCertificate = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner]')
|
.allowGraph('[owner]')
|
||||||
|
.allowGraph('[proxy_hosts]')
|
||||||
|
.allowGraph('[redirection_hosts]')
|
||||||
|
.allowGraph('[dead_hosts]')
|
||||||
.orderBy('nice_name', 'ASC');
|
.orderBy('nice_name', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
|
@@ -6,6 +6,7 @@ const internalHost = require('./host');
|
|||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
const internalCertificate = require('./certificate');
|
const internalCertificate = require('./certificate');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
function omissions () {
|
function omissions () {
|
||||||
return ['is_deleted'];
|
return ['is_deleted'];
|
||||||
@@ -409,16 +410,16 @@ const internalDeadHost = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy(castJsonIfNeed('domain_names'), 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string' && search_query.length > 0) {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where('domain_names', 'like', '%' + search_query + '%');
|
this.where(castJsonIfNeed('domain_names'), 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ const _ = require('lodash');
|
|||||||
const proxyHostModel = require('../models/proxy_host');
|
const proxyHostModel = require('../models/proxy_host');
|
||||||
const redirectionHostModel = require('../models/redirection_host');
|
const redirectionHostModel = require('../models/redirection_host');
|
||||||
const deadHostModel = require('../models/dead_host');
|
const deadHostModel = require('../models/dead_host');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
const internalHost = {
|
const internalHost = {
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ const internalHost = {
|
|||||||
cleanSslHstsData: function (data, existing_data) {
|
cleanSslHstsData: function (data, existing_data) {
|
||||||
existing_data = existing_data === undefined ? {} : existing_data;
|
existing_data = existing_data === undefined ? {} : existing_data;
|
||||||
|
|
||||||
let combined_data = _.assign({}, existing_data, data);
|
const combined_data = _.assign({}, existing_data, data);
|
||||||
|
|
||||||
if (!combined_data.certificate_id) {
|
if (!combined_data.certificate_id) {
|
||||||
combined_data.ssl_forced = false;
|
combined_data.ssl_forced = false;
|
||||||
@@ -73,7 +74,7 @@ const internalHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getHostsWithDomains: function (domain_names) {
|
getHostsWithDomains: function (domain_names) {
|
||||||
let promises = [
|
const promises = [
|
||||||
proxyHostModel
|
proxyHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0),
|
.where('is_deleted', 0),
|
||||||
@@ -125,19 +126,19 @@ const internalHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
isHostnameTaken: function (hostname, ignore_type, ignore_id) {
|
isHostnameTaken: function (hostname, ignore_type, ignore_id) {
|
||||||
let promises = [
|
const promises = [
|
||||||
proxyHostModel
|
proxyHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('domain_names', 'like', '%' + hostname + '%'),
|
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
|
||||||
redirectionHostModel
|
redirectionHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('domain_names', 'like', '%' + hostname + '%'),
|
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
|
||||||
deadHostModel
|
deadHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('domain_names', 'like', '%' + hostname + '%')
|
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%')
|
||||||
];
|
];
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
|
@@ -6,6 +6,7 @@ const internalHost = require('./host');
|
|||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
const internalCertificate = require('./certificate');
|
const internalCertificate = require('./certificate');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
function omissions () {
|
function omissions () {
|
||||||
return ['is_deleted', 'owner.is_deleted'];
|
return ['is_deleted', 'owner.is_deleted'];
|
||||||
@@ -416,16 +417,16 @@ const internalProxyHost = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,access_list,certificate]')
|
.allowGraph('[owner,access_list,certificate]')
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy(castJsonIfNeed('domain_names'), 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string' && search_query.length > 0) {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where('domain_names', 'like', '%' + search_query + '%');
|
this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ const internalHost = require('./host');
|
|||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
const internalCertificate = require('./certificate');
|
const internalCertificate = require('./certificate');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
function omissions () {
|
function omissions () {
|
||||||
return ['is_deleted'];
|
return ['is_deleted'];
|
||||||
@@ -409,16 +410,16 @@ const internalRedirectionHost = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.orderBy('domain_names', 'ASC');
|
.orderBy(castJsonIfNeed('domain_names'), 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string' && search_query.length > 0) {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where('domain_names', 'like', '%' + search_query + '%');
|
this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
const utils = require('../lib/utils');
|
const utils = require('../lib/utils');
|
||||||
const streamModel = require('../models/stream');
|
const streamModel = require('../models/stream');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
|
const internalCertificate = require('./certificate');
|
||||||
|
const internalHost = require('./host');
|
||||||
|
const {castJsonIfNeed} = require('../lib/helpers');
|
||||||
|
|
||||||
function omissions () {
|
function omissions () {
|
||||||
return ['is_deleted'];
|
return ['is_deleted', 'owner.is_deleted', 'certificate.is_deleted'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalStream = {
|
const internalStream = {
|
||||||
@@ -17,6 +20,12 @@ const internalStream = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create: (access, data) => {
|
create: (access, data) => {
|
||||||
|
const create_certificate = data.certificate_id === 'new';
|
||||||
|
|
||||||
|
if (create_certificate) {
|
||||||
|
delete data.certificate_id;
|
||||||
|
}
|
||||||
|
|
||||||
return access.can('streams:create', data)
|
return access.can('streams:create', data)
|
||||||
.then((/*access_data*/) => {
|
.then((/*access_data*/) => {
|
||||||
// TODO: At this point the existing ports should have been checked
|
// TODO: At this point the existing ports should have been checked
|
||||||
@@ -26,16 +35,44 @@ const internalStream = {
|
|||||||
data.meta = {};
|
data.meta = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// streams aren't routed by domain name so don't store domain names in the DB
|
||||||
|
let data_no_domains = structuredClone(data);
|
||||||
|
delete data_no_domains.domain_names;
|
||||||
|
|
||||||
return streamModel
|
return streamModel
|
||||||
.query()
|
.query()
|
||||||
.insertAndFetch(data)
|
.insertAndFetch(data_no_domains)
|
||||||
.then(utils.omitRow(omissions()));
|
.then(utils.omitRow(omissions()));
|
||||||
})
|
})
|
||||||
|
.then((row) => {
|
||||||
|
if (create_certificate) {
|
||||||
|
return internalCertificate.createQuickCertificate(access, data)
|
||||||
|
.then((cert) => {
|
||||||
|
// update host with cert id
|
||||||
|
return internalStream.update(access, {
|
||||||
|
id: row.id,
|
||||||
|
certificate_id: cert.id
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((row) => {
|
||||||
|
// re-fetch with cert
|
||||||
|
return internalStream.get(access, {
|
||||||
|
id: row.id,
|
||||||
|
expand: ['certificate', 'owner']
|
||||||
|
});
|
||||||
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
// Configure nginx
|
// Configure nginx
|
||||||
return internalNginx.configure(streamModel, 'stream', row)
|
return internalNginx.configure(streamModel, 'stream', row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return internalStream.get(access, {id: row.id, expand: ['owner']});
|
return row;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
@@ -59,6 +96,12 @@ const internalStream = {
|
|||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
update: (access, data) => {
|
update: (access, data) => {
|
||||||
|
const create_certificate = data.certificate_id === 'new';
|
||||||
|
|
||||||
|
if (create_certificate) {
|
||||||
|
delete data.certificate_id;
|
||||||
|
}
|
||||||
|
|
||||||
return access.can('streams:update', data.id)
|
return access.can('streams:update', data.id)
|
||||||
.then((/*access_data*/) => {
|
.then((/*access_data*/) => {
|
||||||
// TODO: at this point the existing streams should have been checked
|
// TODO: at this point the existing streams should have been checked
|
||||||
@@ -70,16 +113,32 @@ const internalStream = {
|
|||||||
throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (create_certificate) {
|
||||||
|
return internalCertificate.createQuickCertificate(access, {
|
||||||
|
domain_names: data.domain_names || row.domain_names,
|
||||||
|
meta: _.assign({}, row.meta, data.meta)
|
||||||
|
})
|
||||||
|
.then((cert) => {
|
||||||
|
// update host with cert id
|
||||||
|
data.certificate_id = cert.id;
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((row) => {
|
||||||
|
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
|
||||||
|
data = _.assign({}, {
|
||||||
|
domain_names: row.domain_names
|
||||||
|
}, data);
|
||||||
|
|
||||||
return streamModel
|
return streamModel
|
||||||
.query()
|
.query()
|
||||||
.patchAndFetchById(row.id, data)
|
.patchAndFetchById(row.id, data)
|
||||||
.then(utils.omitRow(omissions()))
|
.then(utils.omitRow(omissions()))
|
||||||
.then((saved_row) => {
|
|
||||||
return internalNginx.configure(streamModel, 'stream', saved_row)
|
|
||||||
.then(() => {
|
|
||||||
return internalStream.get(access, {id: row.id, expand: ['owner']});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then((saved_row) => {
|
.then((saved_row) => {
|
||||||
// Add to audit log
|
// Add to audit log
|
||||||
return internalAuditLog.add(access, {
|
return internalAuditLog.add(access, {
|
||||||
@@ -92,6 +151,17 @@ const internalStream = {
|
|||||||
return saved_row;
|
return saved_row;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return internalStream.get(access, {id: data.id, expand: ['owner', 'certificate']})
|
||||||
|
.then((row) => {
|
||||||
|
return internalNginx.configure(streamModel, 'stream', row)
|
||||||
|
.then((new_meta) => {
|
||||||
|
row.meta = new_meta;
|
||||||
|
row = internalHost.cleanRowCertificateMeta(row);
|
||||||
|
return _.omit(row, omissions());
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -114,7 +184,7 @@ const internalStream = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowGraph('[owner]')
|
.allowGraph('[owner,certificate]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@@ -131,6 +201,7 @@ const internalStream = {
|
|||||||
if (!row || !row.id) {
|
if (!row || !row.id) {
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
}
|
}
|
||||||
|
row = internalHost.cleanRowCertificateMeta(row);
|
||||||
// Custom omissions
|
// Custom omissions
|
||||||
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
if (typeof data.omit !== 'undefined' && data.omit !== null) {
|
||||||
row = _.omit(row, data.omit);
|
row = _.omit(row, data.omit);
|
||||||
@@ -196,14 +267,14 @@ const internalStream = {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
return internalStream.get(access, {
|
return internalStream.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ['owner']
|
expand: ['certificate', 'owner']
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row || !row.id) {
|
if (!row || !row.id) {
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
} else if (row.enabled) {
|
} else if (row.enabled) {
|
||||||
throw new error.ValidationError('Host is already enabled');
|
throw new error.ValidationError('Stream is already enabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
row.enabled = 1;
|
row.enabled = 1;
|
||||||
@@ -249,7 +320,7 @@ const internalStream = {
|
|||||||
if (!row || !row.id) {
|
if (!row || !row.id) {
|
||||||
throw new error.ItemNotFoundError(data.id);
|
throw new error.ItemNotFoundError(data.id);
|
||||||
} else if (!row.enabled) {
|
} else if (!row.enabled) {
|
||||||
throw new error.ValidationError('Host is already disabled');
|
throw new error.ValidationError('Stream is already disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
row.enabled = 0;
|
row.enabled = 0;
|
||||||
@@ -293,11 +364,11 @@ const internalStream = {
|
|||||||
getAll: (access, expand, search_query) => {
|
getAll: (access, expand, search_query) => {
|
||||||
return access.can('streams:list')
|
return access.can('streams:list')
|
||||||
.then((access_data) => {
|
.then((access_data) => {
|
||||||
let query = streamModel
|
const query = streamModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner]')
|
.allowGraph('[owner,certificate]')
|
||||||
.orderBy('incoming_port', 'ASC');
|
.orderBy('incoming_port', 'ASC');
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@@ -305,9 +376,9 @@ const internalStream = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string') {
|
if (typeof search_query === 'string' && search_query.length > 0) {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where('incoming_port', 'like', '%' + search_query + '%');
|
this.where(castJsonIfNeed('incoming_port'), 'like', `%${search_query}%`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,6 +387,13 @@ const internalStream = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return query.then(utils.omitRows(omissions()));
|
return query.then(utils.omitRows(omissions()));
|
||||||
|
})
|
||||||
|
.then((rows) => {
|
||||||
|
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
|
||||||
|
return internalHost.cleanAllRowsCertificateMeta(rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -327,9 +405,9 @@ const internalStream = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getCount: (user_id, visibility) => {
|
getCount: (user_id, visibility) => {
|
||||||
let query = streamModel
|
const query = streamModel
|
||||||
.query()
|
.query()
|
||||||
.count('id as count')
|
.count('id AS count')
|
||||||
.where('is_deleted', 0);
|
.where('is_deleted', 0);
|
||||||
|
|
||||||
if (visibility !== 'all') {
|
if (visibility !== 'all') {
|
||||||
|
@@ -84,47 +84,6 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} data
|
|
||||||
* @param {String} data.identity
|
|
||||||
* @param {String} [issuer]
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
getTokenFromOAuthClaim: (data) => {
|
|
||||||
let Token = new TokenModel();
|
|
||||||
|
|
||||||
data.scope = 'user';
|
|
||||||
data.expiry = '1d';
|
|
||||||
|
|
||||||
return userModel
|
|
||||||
.query()
|
|
||||||
.where('email', data.identity)
|
|
||||||
.andWhere('is_deleted', 0)
|
|
||||||
.andWhere('is_disabled', 0)
|
|
||||||
.first()
|
|
||||||
.then((user) => {
|
|
||||||
if (!user) {
|
|
||||||
throw new error.AuthError(`A user with the email ${data.identity} does not exist. Please contact your administrator.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a moment of the expiry expression
|
|
||||||
let expiry = helpers.parseDatePeriod(data.expiry);
|
|
||||||
if (expiry === null) {
|
|
||||||
throw new error.AuthError('Invalid expiry time: ' + data.expiry);
|
|
||||||
}
|
|
||||||
|
|
||||||
let iss = 'api',
|
|
||||||
attrs = { id: user.id },
|
|
||||||
scope = [ data.scope ],
|
|
||||||
expiresIn = data.expiry;
|
|
||||||
|
|
||||||
return Token.create({ iss, attrs, scope, expiresIn })
|
|
||||||
.then((signed) => {
|
|
||||||
return { token: signed.token, expires: expiry.toISOString() };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Access} access
|
* @param {Access} access
|
||||||
* @param {Object} [data]
|
* @param {Object} [data]
|
||||||
|
@@ -11,7 +11,7 @@ const certbot = {
|
|||||||
/**
|
/**
|
||||||
* @param {array} pluginKeys
|
* @param {array} pluginKeys
|
||||||
*/
|
*/
|
||||||
installPlugins: async function (pluginKeys) {
|
installPlugins: async (pluginKeys) => {
|
||||||
let hasErrors = false;
|
let hasErrors = false;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -21,7 +21,7 @@ const certbot = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
batchflow(pluginKeys).sequential()
|
batchflow(pluginKeys).sequential()
|
||||||
.each((i, pluginKey, next) => {
|
.each((_i, pluginKey, next) => {
|
||||||
certbot.installPlugin(pluginKey)
|
certbot.installPlugin(pluginKey)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
next();
|
next();
|
||||||
@@ -51,7 +51,7 @@ const certbot = {
|
|||||||
* @param {string} pluginKey
|
* @param {string} pluginKey
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
installPlugin: async function (pluginKey) {
|
installPlugin: async (pluginKey) => {
|
||||||
if (typeof dnsPlugins[pluginKey] === 'undefined') {
|
if (typeof dnsPlugins[pluginKey] === 'undefined') {
|
||||||
// throw Error(`Certbot plugin ${pluginKey} not found`);
|
// throw Error(`Certbot plugin ${pluginKey} not found`);
|
||||||
throw new error.ItemNotFoundError(pluginKey);
|
throw new error.ItemNotFoundError(pluginKey);
|
||||||
@@ -63,8 +63,15 @@ const certbot = {
|
|||||||
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||||
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||||
|
|
||||||
const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate';
|
// SETUPTOOLS_USE_DISTUTILS is required for certbot plugins to install correctly
|
||||||
return utils.exec(cmd)
|
// in new versions of Python
|
||||||
|
let env = Object.assign({}, process.env, {SETUPTOOLS_USE_DISTUTILS: 'stdlib'});
|
||||||
|
if (typeof plugin.env === 'object') {
|
||||||
|
env = Object.assign(env, plugin.env);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmd = `. /opt/certbot/bin/activate && pip install --no-cache-dir ${plugin.dependencies} ${plugin.package_name}${plugin.version} && deactivate`;
|
||||||
|
return utils.exec(cmd, {env})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
logger.complete(`Installed ${pluginKey}`);
|
logger.complete(`Installed ${pluginKey}`);
|
||||||
return result;
|
return result;
|
||||||
|
@@ -2,7 +2,10 @@ const fs = require('fs');
|
|||||||
const NodeRSA = require('node-rsa');
|
const NodeRSA = require('node-rsa');
|
||||||
const logger = require('../logger').global;
|
const logger = require('../logger').global;
|
||||||
|
|
||||||
const keysFile = '/data/keys.json';
|
const keysFile = '/data/keys.json';
|
||||||
|
const mysqlEngine = 'mysql2';
|
||||||
|
const postgresEngine = 'pg';
|
||||||
|
const sqliteClientName = 'sqlite3';
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
@@ -14,7 +17,7 @@ const configure = () => {
|
|||||||
let configData;
|
let configData;
|
||||||
try {
|
try {
|
||||||
configData = require(filename);
|
configData = require(filename);
|
||||||
} catch (err) {
|
} catch (_) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ const configure = () => {
|
|||||||
logger.info('Using MySQL configuration');
|
logger.info('Using MySQL configuration');
|
||||||
instance = {
|
instance = {
|
||||||
database: {
|
database: {
|
||||||
engine: 'mysql2',
|
engine: mysqlEngine,
|
||||||
host: envMysqlHost,
|
host: envMysqlHost,
|
||||||
port: process.env.DB_MYSQL_PORT || 3306,
|
port: process.env.DB_MYSQL_PORT || 3306,
|
||||||
user: envMysqlUser,
|
user: envMysqlUser,
|
||||||
@@ -46,13 +49,33 @@ const configure = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const envPostgresHost = process.env.DB_POSTGRES_HOST || null;
|
||||||
|
const envPostgresUser = process.env.DB_POSTGRES_USER || null;
|
||||||
|
const envPostgresName = process.env.DB_POSTGRES_NAME || null;
|
||||||
|
if (envPostgresHost && envPostgresUser && envPostgresName) {
|
||||||
|
// we have enough postgres creds to go with postgres
|
||||||
|
logger.info('Using Postgres configuration');
|
||||||
|
instance = {
|
||||||
|
database: {
|
||||||
|
engine: postgresEngine,
|
||||||
|
host: envPostgresHost,
|
||||||
|
port: process.env.DB_POSTGRES_PORT || 5432,
|
||||||
|
user: envPostgresUser,
|
||||||
|
password: process.env.DB_POSTGRES_PASSWORD,
|
||||||
|
name: envPostgresName,
|
||||||
|
},
|
||||||
|
keys: getKeys(),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
|
const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
|
||||||
logger.info(`Using Sqlite: ${envSqliteFile}`);
|
logger.info(`Using Sqlite: ${envSqliteFile}`);
|
||||||
instance = {
|
instance = {
|
||||||
database: {
|
database: {
|
||||||
engine: 'knex-native',
|
engine: 'knex-native',
|
||||||
knex: {
|
knex: {
|
||||||
client: 'sqlite3',
|
client: sqliteClientName,
|
||||||
connection: {
|
connection: {
|
||||||
filename: envSqliteFile
|
filename: envSqliteFile
|
||||||
},
|
},
|
||||||
@@ -143,7 +166,27 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
isSqlite: function () {
|
isSqlite: function () {
|
||||||
instance === null && configure();
|
instance === null && configure();
|
||||||
return instance.database.knex && instance.database.knex.client === 'sqlite3';
|
return instance.database.knex && instance.database.knex.client === sqliteClientName;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a mysql configuration?
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isMysql: function () {
|
||||||
|
instance === null && configure();
|
||||||
|
return instance.database.engine === mysqlEngine;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a postgres configuration?
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isPostgres: function () {
|
||||||
|
instance === null && configure();
|
||||||
|
return instance.database.engine === postgresEngine;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -4,14 +4,7 @@ module.exports = () => {
|
|||||||
return function (req, res, next) {
|
return function (req, res, next) {
|
||||||
res.locals.access = null;
|
res.locals.access = null;
|
||||||
let access = new Access(res.locals.token || null);
|
let access = new Access(res.locals.token || null);
|
||||||
|
access.load()
|
||||||
// Allow unauthenticated access to get the oidc configuration
|
|
||||||
let oidc_access =
|
|
||||||
req.url === '/oidc-config' &&
|
|
||||||
req.method === 'GET' &&
|
|
||||||
!access.token.getUserId();
|
|
||||||
|
|
||||||
access.load(oidc_access)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.locals.access = access;
|
res.locals.access = access;
|
||||||
next();
|
next();
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const {isPostgres} = require('./config');
|
||||||
|
const {ref} = require('objection');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
@@ -45,6 +47,16 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return obj;
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts a column to json if using postgres
|
||||||
|
*
|
||||||
|
* @param {string} colName
|
||||||
|
* @returns {string|Objection.ReferenceBuilder}
|
||||||
|
*/
|
||||||
|
castJsonIfNeed: function (colName) {
|
||||||
|
return isPostgres() ? ref(colName).castText() : colName;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const exec = require('child_process').exec;
|
const exec = require('node:child_process').exec;
|
||||||
const execFile = require('child_process').execFile;
|
const execFile = require('node:child_process').execFile;
|
||||||
const { Liquid } = require('liquidjs');
|
const { Liquid } = require('liquidjs');
|
||||||
const logger = require('../logger').global;
|
const logger = require('../logger').global;
|
||||||
const error = require('./error');
|
const error = require('./error');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
exec: async function(cmd, options = {}) {
|
exec: async (cmd, options = {}) => {
|
||||||
logger.debug('CMD:', cmd);
|
logger.debug('CMD:', cmd);
|
||||||
|
|
||||||
const { stdout, stderr } = await new Promise((resolve, reject) => {
|
const { stdout, stderr } = await new Promise((resolve, reject) => {
|
||||||
@@ -31,11 +31,11 @@ module.exports = {
|
|||||||
* @param {Array} args
|
* @param {Array} args
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
execFile: function (cmd, args) {
|
execFile: (cmd, args) => {
|
||||||
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
|
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
execFile(cmd, args, function (err, stdout, /*stderr*/) {
|
execFile(cmd, args, (err, stdout, /*stderr*/) => {
|
||||||
if (err && typeof err === 'object') {
|
if (err && typeof err === 'object') {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
@@ -51,7 +51,7 @@ module.exports = {
|
|||||||
* @param {Array} omissions
|
* @param {Array} omissions
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
omitRow: function (omissions) {
|
omitRow: (omissions) => {
|
||||||
/**
|
/**
|
||||||
* @param {Object} row
|
* @param {Object} row
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@@ -67,7 +67,7 @@ module.exports = {
|
|||||||
* @param {Array} omissions
|
* @param {Array} omissions
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
omitRows: function (omissions) {
|
omitRows: (omissions) => {
|
||||||
/**
|
/**
|
||||||
* @param {Array} rows
|
* @param {Array} rows
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@@ -83,9 +83,9 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* @returns {Object} Liquid render engine
|
* @returns {Object} Liquid render engine
|
||||||
*/
|
*/
|
||||||
getRenderEngine: function () {
|
getRenderEngine: () => {
|
||||||
const renderEngine = new Liquid({
|
const renderEngine = new Liquid({
|
||||||
root: __dirname + '/../templates/'
|
root: `${__dirname}/../templates/`
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -10,6 +10,5 @@ module.exports = {
|
|||||||
certbot: new Signale({scope: 'Certbot '}),
|
certbot: new Signale({scope: 'Certbot '}),
|
||||||
import: new Signale({scope: 'Importer '}),
|
import: new Signale({scope: 'Importer '}),
|
||||||
setup: new Signale({scope: 'Setup '}),
|
setup: new Signale({scope: 'Setup '}),
|
||||||
ip_ranges: new Signale({scope: 'IP Ranges'}),
|
ip_ranges: new Signale({scope: 'IP Ranges'})
|
||||||
oidc: new Signale({scope: 'OIDC '})
|
|
||||||
};
|
};
|
||||||
|
38
backend/migrations/20240427161436_stream_ssl.js
Normal file
38
backend/migrations/20240427161436_stream_ssl.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const migrate_name = 'stream_ssl';
|
||||||
|
const logger = require('../logger').migrate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate
|
||||||
|
*
|
||||||
|
* @see http://knexjs.org/#Schema
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.up = function (knex) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Up...');
|
||||||
|
|
||||||
|
return knex.schema.table('stream', (table) => {
|
||||||
|
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] stream Table altered');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo Migrate
|
||||||
|
*
|
||||||
|
* @param {Object} knex
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
exports.down = function (knex) {
|
||||||
|
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||||
|
|
||||||
|
return knex.schema.table('stream', (table) => {
|
||||||
|
table.dropColumn('certificate_id');
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
logger.info('[' + migrate_name + '] stream Table altered');
|
||||||
|
});
|
||||||
|
};
|
@@ -4,7 +4,6 @@
|
|||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const helpers = require('../lib/helpers');
|
const helpers = require('../lib/helpers');
|
||||||
const Model = require('objection').Model;
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
|
||||||
const now = require('./now_helper');
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
@@ -68,6 +67,11 @@ class Certificate extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get relationMappings () {
|
static get relationMappings () {
|
||||||
|
const ProxyHost = require('./proxy_host');
|
||||||
|
const DeadHost = require('./dead_host');
|
||||||
|
const User = require('./user');
|
||||||
|
const RedirectionHost = require('./redirection_host');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
owner: {
|
owner: {
|
||||||
relation: Model.HasOneRelation,
|
relation: Model.HasOneRelation,
|
||||||
@@ -79,6 +83,39 @@ class Certificate extends Model {
|
|||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
proxy_hosts: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: ProxyHost,
|
||||||
|
join: {
|
||||||
|
from: 'certificate.id',
|
||||||
|
to: 'proxy_host.certificate_id'
|
||||||
|
},
|
||||||
|
modify: function (qb) {
|
||||||
|
qb.where('proxy_host.is_deleted', 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dead_hosts: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: DeadHost,
|
||||||
|
join: {
|
||||||
|
from: 'certificate.id',
|
||||||
|
to: 'dead_host.certificate_id'
|
||||||
|
},
|
||||||
|
modify: function (qb) {
|
||||||
|
qb.where('dead_host.is_deleted', 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
redirection_hosts: {
|
||||||
|
relation: Model.HasManyRelation,
|
||||||
|
modelClass: RedirectionHost,
|
||||||
|
join: {
|
||||||
|
from: 'certificate.id',
|
||||||
|
to: 'redirection_host.certificate_id'
|
||||||
|
},
|
||||||
|
modify: function (qb) {
|
||||||
|
qb.where('redirection_host.is_deleted', 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,11 @@ Model.knex(db);
|
|||||||
|
|
||||||
const boolFields = [
|
const boolFields = [
|
||||||
'is_deleted',
|
'is_deleted',
|
||||||
|
'ssl_forced',
|
||||||
|
'http2_support',
|
||||||
'enabled',
|
'enabled',
|
||||||
|
'hsts_enabled',
|
||||||
|
'hsts_subdomains',
|
||||||
];
|
];
|
||||||
|
|
||||||
class DeadHost extends Model {
|
class DeadHost extends Model {
|
||||||
|
@@ -17,6 +17,9 @@ const boolFields = [
|
|||||||
'preserve_path',
|
'preserve_path',
|
||||||
'ssl_forced',
|
'ssl_forced',
|
||||||
'block_exploits',
|
'block_exploits',
|
||||||
|
'hsts_enabled',
|
||||||
|
'hsts_subdomains',
|
||||||
|
'http2_support',
|
||||||
];
|
];
|
||||||
|
|
||||||
class RedirectionHost extends Model {
|
class RedirectionHost extends Model {
|
||||||
|
@@ -1,16 +1,15 @@
|
|||||||
// Objection Docs:
|
const Model = require('objection').Model;
|
||||||
// http://vincit.github.io/objection.js/
|
const db = require('../db');
|
||||||
|
const helpers = require('../lib/helpers');
|
||||||
const db = require('../db');
|
const User = require('./user');
|
||||||
const helpers = require('../lib/helpers');
|
const Certificate = require('./certificate');
|
||||||
const Model = require('objection').Model;
|
const now = require('./now_helper');
|
||||||
const User = require('./user');
|
|
||||||
const now = require('./now_helper');
|
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
const boolFields = [
|
const boolFields = [
|
||||||
'is_deleted',
|
'is_deleted',
|
||||||
|
'enabled',
|
||||||
'tcp_forwarding',
|
'tcp_forwarding',
|
||||||
'udp_forwarding',
|
'udp_forwarding',
|
||||||
];
|
];
|
||||||
@@ -64,6 +63,17 @@ class Stream extends Model {
|
|||||||
modify: function (qb) {
|
modify: function (qb) {
|
||||||
qb.where('user.is_deleted', 0);
|
qb.where('user.is_deleted', 0);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
certificate: {
|
||||||
|
relation: Model.HasOneRelation,
|
||||||
|
modelClass: Certificate,
|
||||||
|
join: {
|
||||||
|
from: 'stream.certificate_id',
|
||||||
|
to: 'certificate.id'
|
||||||
|
},
|
||||||
|
modify: function (qb) {
|
||||||
|
qb.where('certificate.is_deleted', 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -21,9 +21,9 @@
|
|||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"mysql2": "^3.11.1",
|
"mysql2": "^3.11.1",
|
||||||
"node-rsa": "^1.0.8",
|
"node-rsa": "^1.0.8",
|
||||||
"openid-client": "^5.4.0",
|
|
||||||
"objection": "3.0.1",
|
"objection": "3.0.1",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"pg": "^8.13.1",
|
||||||
"signale": "1.4.0",
|
"signale": "1.4.0",
|
||||||
"sqlite3": "5.1.6",
|
"sqlite3": "5.1.6",
|
||||||
"temp-write": "^4.0.0"
|
"temp-write": "^4.0.0"
|
||||||
@@ -45,4 +45,4 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"validate-schema": "node validate-schema.js"
|
"validate-schema": "node validate-schema.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,6 @@ router.get('/', (req, res/*, next*/) => {
|
|||||||
|
|
||||||
router.use('/schema', require('./schema'));
|
router.use('/schema', require('./schema'));
|
||||||
router.use('/tokens', require('./tokens'));
|
router.use('/tokens', require('./tokens'));
|
||||||
router.use('/oidc', require('./oidc'));
|
|
||||||
router.use('/users', require('./users'));
|
router.use('/users', require('./users'));
|
||||||
router.use('/audit-log', require('./audit-log'));
|
router.use('/audit-log', require('./audit-log'));
|
||||||
router.use('/reports', require('./reports'));
|
router.use('/reports', require('./reports'));
|
||||||
|
@@ -1,168 +0,0 @@
|
|||||||
const crypto = require('crypto');
|
|
||||||
const error = require('../lib/error');
|
|
||||||
const express = require('express');
|
|
||||||
const jwtdecode = require('../lib/express/jwt-decode');
|
|
||||||
const logger = require('../logger').oidc;
|
|
||||||
const oidc = require('openid-client');
|
|
||||||
const settingModel = require('../models/setting');
|
|
||||||
const internalToken = require('../internal/token');
|
|
||||||
|
|
||||||
let router = express.Router({
|
|
||||||
caseSensitive: true,
|
|
||||||
strict: true,
|
|
||||||
mergeParams: true
|
|
||||||
});
|
|
||||||
|
|
||||||
router
|
|
||||||
.route('/')
|
|
||||||
.options((req, res) => {
|
|
||||||
res.sendStatus(204);
|
|
||||||
})
|
|
||||||
.all(jwtdecode())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/oidc
|
|
||||||
*
|
|
||||||
* OAuth Authorization Code flow initialisation
|
|
||||||
*/
|
|
||||||
.get(jwtdecode(), async (req, res) => {
|
|
||||||
logger.info('Initializing OAuth flow');
|
|
||||||
settingModel
|
|
||||||
.query()
|
|
||||||
.where({id: 'oidc-config'})
|
|
||||||
.first()
|
|
||||||
.then((row) => getInitParams(req, row))
|
|
||||||
.then((params) => redirectToAuthorizationURL(res, params))
|
|
||||||
.catch((err) => redirectWithError(res, err));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
router
|
|
||||||
.route('/callback')
|
|
||||||
.options((req, res) => {
|
|
||||||
res.sendStatus(204);
|
|
||||||
})
|
|
||||||
.all(jwtdecode())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/oidc/callback
|
|
||||||
*
|
|
||||||
* Oauth Authorization Code flow callback
|
|
||||||
*/
|
|
||||||
.get(jwtdecode(), async (req, res) => {
|
|
||||||
logger.info('Processing callback');
|
|
||||||
settingModel
|
|
||||||
.query()
|
|
||||||
.where({id: 'oidc-config'})
|
|
||||||
.first()
|
|
||||||
.then((settings) => validateCallback(req, settings))
|
|
||||||
.then((token) => redirectWithJwtToken(res, token))
|
|
||||||
.catch((err) => redirectWithError(res, err));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes discovery and returns the configured `openid-client` client
|
|
||||||
*
|
|
||||||
* @param {Setting} row
|
|
||||||
* */
|
|
||||||
let getClient = async (row) => {
|
|
||||||
let issuer;
|
|
||||||
try {
|
|
||||||
issuer = await oidc.Issuer.discover(row.meta.issuerURL);
|
|
||||||
} catch (err) {
|
|
||||||
throw new error.AuthError(`Discovery failed for the specified URL with message: ${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new issuer.Client({
|
|
||||||
client_id: row.meta.clientID,
|
|
||||||
client_secret: row.meta.clientSecret,
|
|
||||||
redirect_uris: [row.meta.redirectURL],
|
|
||||||
response_types: ['code'],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates state, nonce and authorization url.
|
|
||||||
*
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Setting} row
|
|
||||||
* @return { {String}, {String}, {String} } state, nonce and url
|
|
||||||
* */
|
|
||||||
let getInitParams = async (req, row) => {
|
|
||||||
let client = await getClient(row),
|
|
||||||
state = crypto.randomUUID(),
|
|
||||||
nonce = crypto.randomUUID(),
|
|
||||||
url = client.authorizationUrl({
|
|
||||||
scope: 'openid email profile',
|
|
||||||
resource: `${req.protocol}://${req.get('host')}${req.originalUrl}`,
|
|
||||||
state,
|
|
||||||
nonce,
|
|
||||||
});
|
|
||||||
|
|
||||||
return { state, nonce, url };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses state and nonce from cookie during the callback phase.
|
|
||||||
*
|
|
||||||
* @param {Request} req
|
|
||||||
* @return { {String}, {String} } state and nonce
|
|
||||||
* */
|
|
||||||
let parseStateFromCookie = (req) => {
|
|
||||||
let state, nonce;
|
|
||||||
let cookies = req.headers.cookie.split(';');
|
|
||||||
for (let cookie of cookies) {
|
|
||||||
if (cookie.split('=')[0].trim() === 'npm_oidc') {
|
|
||||||
let raw = cookie.split('=')[1],
|
|
||||||
val = raw.split('--');
|
|
||||||
state = val[0].trim();
|
|
||||||
nonce = val[1].trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { state, nonce };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes validation of callback parameters.
|
|
||||||
*
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Setting} settings
|
|
||||||
* @return {Promise} a promise resolving to a jwt token
|
|
||||||
* */
|
|
||||||
let validateCallback = async (req, settings) => {
|
|
||||||
let client = await getClient(settings);
|
|
||||||
let { state, nonce } = parseStateFromCookie(req);
|
|
||||||
|
|
||||||
const params = client.callbackParams(req);
|
|
||||||
const tokenSet = await client.callback(settings.meta.redirectURL, params, { state, nonce });
|
|
||||||
let claims = tokenSet.claims();
|
|
||||||
|
|
||||||
if (!claims.email) {
|
|
||||||
throw new error.AuthError('The Identity Provider didn\'t send the \'email\' claim');
|
|
||||||
} else {
|
|
||||||
logger.info('Successful authentication for email ' + claims.email);
|
|
||||||
}
|
|
||||||
|
|
||||||
return internalToken.getTokenFromOAuthClaim({ identity: claims.email });
|
|
||||||
};
|
|
||||||
|
|
||||||
let redirectToAuthorizationURL = (res, params) => {
|
|
||||||
logger.info('Authorization URL: ' + params.url);
|
|
||||||
res.cookie('npm_oidc', params.state + '--' + params.nonce);
|
|
||||||
res.redirect(params.url);
|
|
||||||
};
|
|
||||||
|
|
||||||
let redirectWithJwtToken = (res, token) => {
|
|
||||||
res.cookie('npm_oidc', token.token + '---' + token.expires);
|
|
||||||
res.redirect('/login');
|
|
||||||
};
|
|
||||||
|
|
||||||
let redirectWithError = (res, error) => {
|
|
||||||
logger.error('Callback error: ' + error.message);
|
|
||||||
res.cookie('npm_oidc_error', error.message);
|
|
||||||
res.redirect('/login');
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = router;
|
|
@@ -71,18 +71,6 @@ router
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (row.id === 'oidc-config') {
|
|
||||||
// Redact oidc configuration via api (unauthenticated get call)
|
|
||||||
let m = row.meta;
|
|
||||||
row.meta = {
|
|
||||||
name: m.name,
|
|
||||||
enabled: m.enabled === true && !!(m.clientID && m.clientSecret && m.issuerURL && m.redirectURL && m.name)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove these temporary cookies used during oidc authentication
|
|
||||||
res.clearCookie('npm_oidc');
|
|
||||||
res.clearCookie('npm_oidc_error');
|
|
||||||
}
|
|
||||||
res.status(200)
|
res.status(200)
|
||||||
.send(row);
|
.send(row);
|
||||||
})
|
})
|
||||||
|
@@ -29,8 +29,6 @@ router
|
|||||||
scope: (typeof req.query.scope !== 'undefined' ? req.query.scope : null)
|
scope: (typeof req.query.scope !== 'undefined' ? req.query.scope : null)
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
// clear this temporary cookie following a successful oidc authentication
|
|
||||||
res.clearCookie('npm_oidc');
|
|
||||||
res.status(200)
|
res.status(200)
|
||||||
.send(data);
|
.send(data);
|
||||||
})
|
})
|
||||||
|
@@ -181,7 +181,7 @@ router
|
|||||||
return internalUser.setPassword(res.locals.access, payload);
|
return internalUser.setPassword(res.locals.access, payload);
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
res.status(201)
|
res.status(200)
|
||||||
.send(result);
|
.send(result);
|
||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
@@ -212,7 +212,7 @@ router
|
|||||||
return internalUser.setPermissions(res.locals.access, payload);
|
return internalUser.setPermissions(res.locals.access, payload);
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
res.status(201)
|
res.status(200)
|
||||||
.send(result);
|
.send(result);
|
||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
@@ -238,7 +238,7 @@ router
|
|||||||
.post((req, res, next) => {
|
.post((req, res, next) => {
|
||||||
internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
|
internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
res.status(201)
|
res.status(200)
|
||||||
.send(result);
|
.send(result);
|
||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
|
@@ -22,8 +22,7 @@
|
|||||||
"enabled",
|
"enabled",
|
||||||
"locations",
|
"locations",
|
||||||
"hsts_enabled",
|
"hsts_enabled",
|
||||||
"hsts_subdomains",
|
"hsts_subdomains"
|
||||||
"certificate"
|
|
||||||
],
|
],
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Proxy Hosts list",
|
"description": "Streams list",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "./proxy-host-object.json"
|
"$ref": "./stream-object.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,9 +19,7 @@
|
|||||||
"incoming_port": {
|
"incoming_port": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"maximum": 65535,
|
"maximum": 65535
|
||||||
"if": {"properties": {"tcp_forwarding": {"const": true}}},
|
|
||||||
"then": {"not": {"oneOf": [{"const": 80}, {"const": 443}]}}
|
|
||||||
},
|
},
|
||||||
"forwarding_host": {
|
"forwarding_host": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
@@ -55,8 +53,24 @@
|
|||||||
"enabled": {
|
"enabled": {
|
||||||
"$ref": "../common.json#/properties/enabled"
|
"$ref": "../common.json#/properties/enabled"
|
||||||
},
|
},
|
||||||
|
"certificate_id": {
|
||||||
|
"$ref": "../common.json#/properties/certificate_id"
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
},
|
||||||
|
"owner": {
|
||||||
|
"$ref": "./user-object.json"
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "./certificate-object.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,10 +5,9 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"expires": {
|
"expires": {
|
||||||
"description": "Token Expiry Unix Time",
|
"description": "Token Expiry ISO Time String",
|
||||||
"example": 1566540249,
|
"example": "2025-02-04T20:40:46.340Z",
|
||||||
"minimum": 1,
|
"type": "string"
|
||||||
"type": "number"
|
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"description": "JWT Token",
|
"description": "JWT Token",
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
"description": "Expansions",
|
"description": "Expansions",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["access_list", "owner", "certificate"]
|
"enum": ["owner", "certificate"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -40,7 +40,8 @@
|
|||||||
"nginx_online": true,
|
"nginx_online": true,
|
||||||
"nginx_err": null
|
"nginx_err": null
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true,
|
||||||
|
"certificate_id": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,9 @@
|
|||||||
"udp_forwarding": {
|
"udp_forwarding": {
|
||||||
"$ref": "../../../components/stream-object.json#/properties/udp_forwarding"
|
"$ref": "../../../components/stream-object.json#/properties/udp_forwarding"
|
||||||
},
|
},
|
||||||
|
"certificate_id": {
|
||||||
|
"$ref": "../../../components/stream-object.json#/properties/certificate_id"
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"$ref": "../../../components/stream-object.json#/properties/meta"
|
"$ref": "../../../components/stream-object.json#/properties/meta"
|
||||||
}
|
}
|
||||||
@@ -73,7 +76,8 @@
|
|||||||
"nickname": "Admin",
|
"nickname": "Admin",
|
||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
}
|
},
|
||||||
|
"certificate_id": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -40,7 +40,8 @@
|
|||||||
"nginx_online": true,
|
"nginx_online": true,
|
||||||
"nginx_err": null
|
"nginx_err": null
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true,
|
||||||
|
"certificate_id": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -29,56 +29,26 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"properties": {
|
"properties": {
|
||||||
"domain_names": {
|
"incoming_port": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/domain_names"
|
"$ref": "../../../../components/stream-object.json#/properties/incoming_port"
|
||||||
},
|
},
|
||||||
"forward_scheme": {
|
"forwarding_host": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_scheme"
|
"$ref": "../../../../components/stream-object.json#/properties/forwarding_host"
|
||||||
},
|
},
|
||||||
"forward_host": {
|
"forwarding_port": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_host"
|
"$ref": "../../../../components/stream-object.json#/properties/forwarding_port"
|
||||||
},
|
},
|
||||||
"forward_port": {
|
"tcp_forwarding": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_port"
|
"$ref": "../../../../components/stream-object.json#/properties/tcp_forwarding"
|
||||||
|
},
|
||||||
|
"udp_forwarding": {
|
||||||
|
"$ref": "../../../../components/stream-object.json#/properties/udp_forwarding"
|
||||||
},
|
},
|
||||||
"certificate_id": {
|
"certificate_id": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/certificate_id"
|
"$ref": "../../../../components/stream-object.json#/properties/certificate_id"
|
||||||
},
|
|
||||||
"ssl_forced": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/ssl_forced"
|
|
||||||
},
|
|
||||||
"hsts_enabled": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/hsts_enabled"
|
|
||||||
},
|
|
||||||
"hsts_subdomains": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains"
|
|
||||||
},
|
|
||||||
"http2_support": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/http2_support"
|
|
||||||
},
|
|
||||||
"block_exploits": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/block_exploits"
|
|
||||||
},
|
|
||||||
"caching_enabled": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/caching_enabled"
|
|
||||||
},
|
|
||||||
"allow_websocket_upgrade": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade"
|
|
||||||
},
|
|
||||||
"access_list_id": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/access_list_id"
|
|
||||||
},
|
|
||||||
"advanced_config": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/advanced_config"
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/enabled"
|
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/meta"
|
"$ref": "../../../../components/stream-object.json#/properties/meta"
|
||||||
},
|
|
||||||
"locations": {
|
|
||||||
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,42 +64,32 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"created_on": "2024-10-08T23:23:03.000Z",
|
"created_on": "2024-10-09T02:33:45.000Z",
|
||||||
"modified_on": "2024-10-08T23:26:37.000Z",
|
"modified_on": "2024-10-09T02:33:45.000Z",
|
||||||
"owner_user_id": 1,
|
"owner_user_id": 1,
|
||||||
"domain_names": ["test.example.com"],
|
"incoming_port": 9090,
|
||||||
"forward_host": "192.168.0.10",
|
"forwarding_host": "router.internal",
|
||||||
"forward_port": 8989,
|
"forwarding_port": 80,
|
||||||
"access_list_id": 0,
|
"tcp_forwarding": true,
|
||||||
"certificate_id": 0,
|
"udp_forwarding": false,
|
||||||
"ssl_forced": false,
|
|
||||||
"caching_enabled": false,
|
|
||||||
"block_exploits": false,
|
|
||||||
"advanced_config": "",
|
|
||||||
"meta": {
|
"meta": {
|
||||||
"nginx_online": true,
|
"nginx_online": true,
|
||||||
"nginx_err": null
|
"nginx_err": null
|
||||||
},
|
},
|
||||||
"allow_websocket_upgrade": false,
|
|
||||||
"http2_support": false,
|
|
||||||
"forward_scheme": "http",
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"hsts_enabled": false,
|
|
||||||
"hsts_subdomains": false,
|
|
||||||
"owner": {
|
"owner": {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"created_on": "2024-10-07T22:43:55.000Z",
|
"created_on": "2024-10-09T02:33:16.000Z",
|
||||||
"modified_on": "2024-10-08T12:52:54.000Z",
|
"modified_on": "2024-10-09T02:33:16.000Z",
|
||||||
"is_deleted": false,
|
"is_deleted": false,
|
||||||
"is_disabled": false,
|
"is_disabled": false,
|
||||||
"email": "admin@example.com",
|
"email": "admin@example.com",
|
||||||
"name": "Administrator",
|
"name": "Administrator",
|
||||||
"nickname": "some guy",
|
"nickname": "Admin",
|
||||||
"avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"certificate": null,
|
"certificate_id": 0
|
||||||
"access_list": null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"enum": ["default-site", "oidc-config"]
|
"enum": ["default-site"]
|
||||||
},
|
},
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Setting ID",
|
"description": "Setting ID",
|
||||||
@@ -27,69 +27,28 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"oneOf": [
|
"type": "object",
|
||||||
{
|
"additionalProperties": false,
|
||||||
"type": "object",
|
"minProperties": 1,
|
||||||
"additionalProperties": false,
|
"properties": {
|
||||||
"minProperties": 1,
|
"value": {
|
||||||
"properties": {
|
"type": "string",
|
||||||
"value": {
|
"minLength": 1,
|
||||||
"type": "string",
|
"enum": ["congratulations", "404", "444", "redirect", "html"]
|
||||||
"minLength": 1,
|
|
||||||
"enum": [
|
|
||||||
"congratulations",
|
|
||||||
"404",
|
|
||||||
"444",
|
|
||||||
"redirect",
|
|
||||||
"html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"redirect": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"html": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
"meta": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"minProperties": 1,
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"meta": {
|
"redirect": {
|
||||||
"type": "object",
|
"type": "string"
|
||||||
"additionalProperties": false,
|
},
|
||||||
"properties": {
|
"html": {
|
||||||
"clientID": {
|
"type": "string"
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"clientSecret": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"issuerURL": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"redirectURL": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
"examples": {
|
"examples": {
|
||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"expires": 1566540510,
|
"expires": "2025-02-04T20:40:46.340Z",
|
||||||
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"result": {
|
"result": {
|
||||||
"expires": 1566540510,
|
"expires": "2025-02-04T20:40:46.340Z",
|
||||||
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,15 @@
|
|||||||
"url": "http://127.0.0.1:81/api"
|
"url": "http://127.0.0.1:81/api"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"bearerAuth": {
|
||||||
|
"type": "http",
|
||||||
|
"scheme": "bearer",
|
||||||
|
"bearerFormat": "JWT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
|
@@ -15,18 +15,18 @@ const certbot = require('./lib/certbot');
|
|||||||
const setupDefaultUser = () => {
|
const setupDefaultUser = () => {
|
||||||
return userModel
|
return userModel
|
||||||
.query()
|
.query()
|
||||||
.select(userModel.raw('COUNT(`id`) as `count`'))
|
.select('id', )
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.first()
|
.first()
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row.count) {
|
if (!row || !row.id) {
|
||||||
// Create a new user and set password
|
// Create a new user and set password
|
||||||
let email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
const email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
||||||
let password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
|
const password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
|
||||||
|
|
||||||
logger.info('Creating a new user: ' + email + ' with password: ' + password);
|
logger.info('Creating a new user: ' + email + ' with password: ' + password);
|
||||||
|
|
||||||
let data = {
|
const data = {
|
||||||
is_deleted: 0,
|
is_deleted: 0,
|
||||||
email: email,
|
email: email,
|
||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
@@ -75,56 +75,30 @@ const setupDefaultUser = () => {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const setupDefaultSettings = () => {
|
const setupDefaultSettings = () => {
|
||||||
return Promise.all([
|
return settingModel
|
||||||
settingModel
|
.query()
|
||||||
.query()
|
.select('id')
|
||||||
.select(settingModel.raw('COUNT(`id`) as `count`'))
|
.where({id: 'default-site'})
|
||||||
.where({id: 'default-site'})
|
.first()
|
||||||
.first()
|
.then((row) => {
|
||||||
.then((row) => {
|
if (!row || !row.id) {
|
||||||
if (!row.count) {
|
settingModel
|
||||||
settingModel
|
.query()
|
||||||
.query()
|
.insert({
|
||||||
.insert({
|
id: 'default-site',
|
||||||
id: 'default-site',
|
name: 'Default Site',
|
||||||
name: 'Default Site',
|
description: 'What to show when Nginx is hit with an unknown Host',
|
||||||
description: 'What to show when Nginx is hit with an unknown Host',
|
value: 'congratulations',
|
||||||
value: 'congratulations',
|
meta: {},
|
||||||
meta: {},
|
})
|
||||||
})
|
.then(() => {
|
||||||
.then(() => {
|
logger.info('Default settings added');
|
||||||
logger.info('Added default-site setting');
|
});
|
||||||
});
|
}
|
||||||
}
|
if (config.debug()) {
|
||||||
if (config.debug()) {
|
logger.info('Default setting setup not required');
|
||||||
logger.info('Default setting setup not required');
|
}
|
||||||
}
|
});
|
||||||
}),
|
|
||||||
settingModel
|
|
||||||
.query()
|
|
||||||
.select(settingModel.raw('COUNT(`id`) as `count`'))
|
|
||||||
.where({id: 'oidc-config'})
|
|
||||||
.first()
|
|
||||||
.then((row) => {
|
|
||||||
if (!row.count) {
|
|
||||||
settingModel
|
|
||||||
.query()
|
|
||||||
.insert({
|
|
||||||
id: 'oidc-config',
|
|
||||||
name: 'Open ID Connect',
|
|
||||||
description: 'Sign in to Nginx Proxy Manager with an external Identity Provider',
|
|
||||||
value: 'metadata',
|
|
||||||
meta: {},
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
logger.info('Added oidc-config setting');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (config.debug()) {
|
|
||||||
logger.info('Default setting setup not required');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
{% if certificate.provider == "letsencrypt" %}
|
{% if certificate.provider == "letsencrypt" %}
|
||||||
# Let's Encrypt SSL
|
# Let's Encrypt SSL
|
||||||
include conf.d/include/letsencrypt-acme-challenge.conf;
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
include conf.d/include/ssl-cache.conf;
|
||||||
include conf.d/include/ssl-ciphers.conf;
|
include conf.d/include/ssl-ciphers.conf;
|
||||||
ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
|
ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
|
||||||
ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
|
||||||
|
13
backend/templates/_certificates_stream.conf
Normal file
13
backend/templates/_certificates_stream.conf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% if certificate and certificate_id > 0 %}
|
||||||
|
{% if certificate.provider == "letsencrypt" %}
|
||||||
|
# Let's Encrypt SSL
|
||||||
|
include conf.d/include/ssl-cache-stream.conf;
|
||||||
|
include conf.d/include/ssl-ciphers.conf;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
|
||||||
|
{%- else %}
|
||||||
|
# Custom SSL
|
||||||
|
ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem;
|
||||||
|
ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem;
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endif -%}
|
@@ -22,5 +22,7 @@ server {
|
|||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
include /data/nginx/custom/server_dead[.]conf;
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -5,12 +5,10 @@
|
|||||||
{% if enabled %}
|
{% if enabled %}
|
||||||
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
|
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
|
||||||
server {
|
server {
|
||||||
listen {{ incoming_port }};
|
listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %};
|
||||||
{% if ipv6 -%}
|
{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %};
|
||||||
listen [::]:{{ incoming_port }};
|
|
||||||
{% else -%}
|
{%- include "_certificates_stream.conf" %}
|
||||||
#listen [::]:{{ incoming_port }};
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
@@ -19,14 +17,12 @@ server {
|
|||||||
include /data/nginx/custom/server_stream_tcp[.]conf;
|
include /data/nginx/custom/server_stream_tcp[.]conf;
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if udp_forwarding == 1 or udp_forwarding == true %}
|
|
||||||
|
{% if udp_forwarding == 1 or udp_forwarding == true -%}
|
||||||
server {
|
server {
|
||||||
listen {{ incoming_port }} udp;
|
listen {{ incoming_port }} udp;
|
||||||
{% if ipv6 -%}
|
{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp;
|
||||||
listen [::]:{{ incoming_port }} udp;
|
|
||||||
{% else -%}
|
|
||||||
#listen [::]:{{ incoming_port }} udp;
|
|
||||||
{% endif %}
|
|
||||||
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
# Custom
|
# Custom
|
||||||
|
1886
backend/yarn.lock
1886
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
8
docker/ci.env
Normal file
8
docker/ci.env
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
AUTHENTIK_SECRET_KEY=gl8woZe8L6IIX8SC0c5Ocsj0xPkX5uJo5DVZCFl+L/QGbzuplfutYuua2ODNLEiDD3aFd9H2ylJmrke0
|
||||||
|
AUTHENTIK_REDIS__HOST=authentik-redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST=db-postgres
|
||||||
|
AUTHENTIK_POSTGRESQL__USER=authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME=authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD=07EKS5NLI6Tpv68tbdvrxfvj
|
||||||
|
AUTHENTIK_BOOTSTRAP_PASSWORD=admin
|
||||||
|
AUTHENTIK_BOOTSTRAP_EMAIL=admin@example.com
|
BIN
docker/ci/postgres/authentik.sql.gz
Normal file
BIN
docker/ci/postgres/authentik.sql.gz
Normal file
Binary file not shown.
@@ -29,7 +29,8 @@ COPY scripts/install-s6 /tmp/install-s6
|
|||||||
RUN rm -f /etc/nginx/conf.d/production.conf \
|
RUN rm -f /etc/nginx/conf.d/production.conf \
|
||||||
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager \
|
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager \
|
||||||
&& /tmp/install-s6 "${TARGETPLATFORM}" \
|
&& /tmp/install-s6 "${TARGETPLATFORM}" \
|
||||||
&& rm -f /tmp/install-s6
|
&& rm -f /tmp/install-s6 \
|
||||||
|
&& chmod 644 -R /root/.cache
|
||||||
|
|
||||||
# Certs for testing purposes
|
# Certs for testing purposes
|
||||||
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
||||||
|
@@ -18,6 +18,7 @@ services:
|
|||||||
MYSQL_DATABASE: 'npm'
|
MYSQL_DATABASE: 'npm'
|
||||||
MYSQL_USER: 'npm'
|
MYSQL_USER: 'npm'
|
||||||
MYSQL_PASSWORD: 'npmpass'
|
MYSQL_PASSWORD: 'npmpass'
|
||||||
|
MARIADB_AUTO_UPGRADE: '1'
|
||||||
volumes:
|
volumes:
|
||||||
- mysql_vol:/var/lib/mysql
|
- mysql_vol:/var/lib/mysql
|
||||||
networks:
|
networks:
|
||||||
|
78
docker/docker-compose.ci.postgres.yml
Normal file
78
docker/docker-compose.ci.postgres.yml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
|
||||||
|
services:
|
||||||
|
|
||||||
|
cypress:
|
||||||
|
environment:
|
||||||
|
CYPRESS_stack: 'postgres'
|
||||||
|
|
||||||
|
fullstack:
|
||||||
|
environment:
|
||||||
|
DB_POSTGRES_HOST: 'db-postgres'
|
||||||
|
DB_POSTGRES_PORT: '5432'
|
||||||
|
DB_POSTGRES_USER: 'npm'
|
||||||
|
DB_POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
DB_POSTGRES_NAME: 'npm'
|
||||||
|
depends_on:
|
||||||
|
- db-postgres
|
||||||
|
- authentik
|
||||||
|
- authentik-worker
|
||||||
|
- authentik-ldap
|
||||||
|
|
||||||
|
db-postgres:
|
||||||
|
image: postgres:latest
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: 'npm'
|
||||||
|
POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
POSTGRES_DB: 'npm'
|
||||||
|
volumes:
|
||||||
|
- psql_vol:/var/lib/postgresql/data
|
||||||
|
- ./ci/postgres:/docker-entrypoint-initdb.d
|
||||||
|
networks:
|
||||||
|
- fulltest
|
||||||
|
|
||||||
|
authentik-redis:
|
||||||
|
image: 'redis:alpine'
|
||||||
|
command: --save 60 1 --loglevel warning
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 3s
|
||||||
|
volumes:
|
||||||
|
- redis_vol:/data
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.10.1
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-worker:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.10.1
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-ldap:
|
||||||
|
image: ghcr.io/goauthentik/ldap:2024.10.1
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_HOST: 'http://authentik:9000'
|
||||||
|
AUTHENTIK_INSECURE: 'true'
|
||||||
|
AUTHENTIK_TOKEN: 'wKYZuRcI0ETtb8vWzMCr04oNbhrQUUICy89hSpDln1OEKLjiNEuQ51044Vkp'
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- authentik
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
psql_vol:
|
||||||
|
redis_vol:
|
@@ -22,6 +22,10 @@ services:
|
|||||||
test: ["CMD", "/usr/bin/check-health"]
|
test: ["CMD", "/usr/bin/check-health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 3s
|
timeout: 3s
|
||||||
|
expose:
|
||||||
|
- '80-81/tcp'
|
||||||
|
- '443/tcp'
|
||||||
|
- '1500-1503/tcp'
|
||||||
networks:
|
networks:
|
||||||
fulltest:
|
fulltest:
|
||||||
aliases:
|
aliases:
|
||||||
@@ -40,7 +44,7 @@ services:
|
|||||||
- ca.internal
|
- ca.internal
|
||||||
|
|
||||||
pdns:
|
pdns:
|
||||||
image: pschiffe/pdns-mysql
|
image: pschiffe/pdns-mysql:4.8
|
||||||
volumes:
|
volumes:
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
environment:
|
environment:
|
||||||
@@ -97,7 +101,7 @@ services:
|
|||||||
HTTP_PROXY: 'squid:3128'
|
HTTP_PROXY: 'squid:3128'
|
||||||
HTTPS_PROXY: 'squid:3128'
|
HTTPS_PROXY: 'squid:3128'
|
||||||
volumes:
|
volumes:
|
||||||
- 'cypress_logs:/results'
|
- 'cypress_logs:/test/results'
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
command: cypress run --browser chrome --config-file=cypress/config/ci.js
|
command: cypress run --browser chrome --config-file=cypress/config/ci.js
|
||||||
|
@@ -2,8 +2,8 @@
|
|||||||
services:
|
services:
|
||||||
|
|
||||||
fullstack:
|
fullstack:
|
||||||
image: nginxproxymanager:dev
|
image: npm2dev:core
|
||||||
container_name: npm_core
|
container_name: npm2dev.core
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: ./dev/Dockerfile
|
dockerfile: ./dev/Dockerfile
|
||||||
@@ -26,11 +26,17 @@ services:
|
|||||||
DEVELOPMENT: 'true'
|
DEVELOPMENT: 'true'
|
||||||
LE_STAGING: 'true'
|
LE_STAGING: 'true'
|
||||||
# db:
|
# db:
|
||||||
DB_MYSQL_HOST: 'db'
|
# DB_MYSQL_HOST: 'db'
|
||||||
DB_MYSQL_PORT: '3306'
|
# DB_MYSQL_PORT: '3306'
|
||||||
DB_MYSQL_USER: 'npm'
|
# DB_MYSQL_USER: 'npm'
|
||||||
DB_MYSQL_PASSWORD: 'npm'
|
# DB_MYSQL_PASSWORD: 'npm'
|
||||||
DB_MYSQL_NAME: 'npm'
|
# DB_MYSQL_NAME: 'npm'
|
||||||
|
# db-postgres:
|
||||||
|
DB_POSTGRES_HOST: 'db-postgres'
|
||||||
|
DB_POSTGRES_PORT: '5432'
|
||||||
|
DB_POSTGRES_USER: 'npm'
|
||||||
|
DB_POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
DB_POSTGRES_NAME: 'npm'
|
||||||
# DB_SQLITE_FILE: "/data/database.sqlite"
|
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||||
# DISABLE_IPV6: "true"
|
# DISABLE_IPV6: "true"
|
||||||
# Required for DNS Certificate provisioning testing:
|
# Required for DNS Certificate provisioning testing:
|
||||||
@@ -49,11 +55,15 @@ services:
|
|||||||
timeout: 3s
|
timeout: 3s
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
|
- db-postgres
|
||||||
|
- authentik
|
||||||
|
- authentik-worker
|
||||||
|
- authentik-ldap
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: jc21/mariadb-aria
|
image: jc21/mariadb-aria
|
||||||
container_name: npm_db
|
container_name: npm2dev.db
|
||||||
ports:
|
ports:
|
||||||
- 33306:3306
|
- 33306:3306
|
||||||
networks:
|
networks:
|
||||||
@@ -66,8 +76,22 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- db_data:/var/lib/mysql
|
- db_data:/var/lib/mysql
|
||||||
|
|
||||||
|
db-postgres:
|
||||||
|
image: postgres:latest
|
||||||
|
container_name: npm2dev.db-postgres
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: 'npm'
|
||||||
|
POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
POSTGRES_DB: 'npm'
|
||||||
|
volumes:
|
||||||
|
- psql_data:/var/lib/postgresql/data
|
||||||
|
- ./ci/postgres:/docker-entrypoint-initdb.d
|
||||||
|
|
||||||
stepca:
|
stepca:
|
||||||
image: jc21/testca
|
image: jc21/testca
|
||||||
|
container_name: npm2dev.stepca
|
||||||
volumes:
|
volumes:
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
@@ -78,6 +102,7 @@ services:
|
|||||||
|
|
||||||
dnsrouter:
|
dnsrouter:
|
||||||
image: jc21/dnsrouter
|
image: jc21/dnsrouter
|
||||||
|
container_name: npm2dev.dnsrouter
|
||||||
volumes:
|
volumes:
|
||||||
- ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
|
- ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
|
||||||
networks:
|
networks:
|
||||||
@@ -85,7 +110,7 @@ services:
|
|||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
image: swaggerapi/swagger-ui:latest
|
image: swaggerapi/swagger-ui:latest
|
||||||
container_name: npm_swagger
|
container_name: npm2dev.swagger
|
||||||
ports:
|
ports:
|
||||||
- 3082:80
|
- 3082:80
|
||||||
environment:
|
environment:
|
||||||
@@ -96,7 +121,7 @@ services:
|
|||||||
|
|
||||||
squid:
|
squid:
|
||||||
image: ubuntu/squid
|
image: ubuntu/squid
|
||||||
container_name: npm_squid
|
container_name: npm2dev.squid
|
||||||
volumes:
|
volumes:
|
||||||
- './dev/squid.conf:/etc/squid/squid.conf:ro'
|
- './dev/squid.conf:/etc/squid/squid.conf:ro'
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
||||||
@@ -107,7 +132,8 @@ services:
|
|||||||
- 8128:3128
|
- 8128:3128
|
||||||
|
|
||||||
pdns:
|
pdns:
|
||||||
image: pschiffe/pdns-mysql
|
image: pschiffe/pdns-mysql:4.8
|
||||||
|
container_name: npm2dev.pdns
|
||||||
volumes:
|
volumes:
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
environment:
|
environment:
|
||||||
@@ -136,6 +162,7 @@ services:
|
|||||||
|
|
||||||
pdns-db:
|
pdns-db:
|
||||||
image: mariadb
|
image: mariadb
|
||||||
|
container_name: npm2dev.pdns-db
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: 'pdns'
|
MYSQL_ROOT_PASSWORD: 'pdns'
|
||||||
MYSQL_DATABASE: 'pdns'
|
MYSQL_DATABASE: 'pdns'
|
||||||
@@ -149,7 +176,8 @@ services:
|
|||||||
- nginx_proxy_manager
|
- nginx_proxy_manager
|
||||||
|
|
||||||
cypress:
|
cypress:
|
||||||
image: "npm_dev_cypress"
|
image: npm2dev:cypress
|
||||||
|
container_name: npm2dev.cypress
|
||||||
build:
|
build:
|
||||||
context: ../
|
context: ../
|
||||||
dockerfile: test/cypress/Dockerfile
|
dockerfile: test/cypress/Dockerfile
|
||||||
@@ -164,16 +192,77 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- nginx_proxy_manager
|
- nginx_proxy_manager
|
||||||
|
|
||||||
|
authentik-redis:
|
||||||
|
image: 'redis:alpine'
|
||||||
|
container_name: npm2dev.authentik-redis
|
||||||
|
command: --save 60 1 --loglevel warning
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 3s
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.10.1
|
||||||
|
container_name: npm2dev.authentik
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
ports:
|
||||||
|
- 9000:9000
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-worker:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.10.1
|
||||||
|
container_name: npm2dev.authentik-worker
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-ldap:
|
||||||
|
image: ghcr.io/goauthentik/ldap:2024.10.1
|
||||||
|
container_name: npm2dev.authentik-ldap
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_HOST: 'http://authentik:9000'
|
||||||
|
AUTHENTIK_INSECURE: 'true'
|
||||||
|
AUTHENTIK_TOKEN: 'wKYZuRcI0ETtb8vWzMCr04oNbhrQUUICy89hSpDln1OEKLjiNEuQ51044Vkp'
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- authentik
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
npm_data:
|
npm_data:
|
||||||
name: npm_core_data
|
name: npm2dev_core_data
|
||||||
le_data:
|
le_data:
|
||||||
name: npm_le_data
|
name: npm2dev_le_data
|
||||||
db_data:
|
db_data:
|
||||||
name: npm_db_data
|
name: npm2dev_db_data
|
||||||
pdns_mysql:
|
pdns_mysql:
|
||||||
name: npm_pdns_mysql
|
name: npnpm2dev_pdns_mysql
|
||||||
|
psql_data:
|
||||||
|
name: npm2dev_psql_data
|
||||||
|
redis_data:
|
||||||
|
name: npm2dev_redis_data
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
nginx_proxy_manager:
|
nginx_proxy_manager:
|
||||||
name: npm_network
|
name: npm2dev_network
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_session_cache shared:SSL_stream:50m;
|
2
docker/rootfs/etc/nginx/conf.d/include/ssl-cache.conf
Normal file
2
docker/rootfs/etc/nginx/conf.d/include/ssl-cache.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_session_cache shared:SSL:50m;
|
@@ -1,6 +1,3 @@
|
|||||||
ssl_session_timeout 5m;
|
|
||||||
ssl_session_cache shared:SSL:50m;
|
|
||||||
|
|
||||||
# intermediate configuration. tweak to your needs.
|
# intermediate configuration. tweak to your needs.
|
||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
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';
|
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';
|
||||||
|
@@ -23,6 +23,22 @@ chown -R "$PUID:$PGID" /etc/nginx/nginx
|
|||||||
chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
|
chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
|
||||||
chown -R "$PUID:$PGID" /etc/nginx/conf.d
|
chown -R "$PUID:$PGID" /etc/nginx/conf.d
|
||||||
|
|
||||||
# Prevents errors when installing python certbot plugins when non-root
|
# Certbot directories - optimized approach
|
||||||
chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
|
CERT_INIT_FLAG="/opt/certbot/.ownership_initialized"
|
||||||
find /opt/certbot/lib/python*/site-packages -not -user "$PUID" -execdir chown "$PUID:$PGID" {} \+
|
|
||||||
|
if [ ! -f "$CERT_INIT_FLAG" ]; then
|
||||||
|
# Prevents errors when installing python certbot plugins when non-root
|
||||||
|
if [ "$SKIP_CERTBOT_OWNERSHIP" != "true" ]; then
|
||||||
|
log_info 'Changing ownership of /opt/certbot directories ...'
|
||||||
|
chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle all site-packages directories efficiently
|
||||||
|
find /opt/certbot/lib -type d -name "site-packages" | while read -r SITE_PACKAGES_DIR; do
|
||||||
|
chown -R "$PUID:$PGID" "$SITE_PACKAGES_DIR"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create a flag file to skip this step on subsequent runs
|
||||||
|
touch "$CERT_INIT_FLAG"
|
||||||
|
chown "$PUID:$PGID" "$CERT_INIT_FLAG"
|
||||||
|
fi
|
||||||
|
@@ -8,7 +8,7 @@ BLUE='\E[1;34m'
|
|||||||
GREEN='\E[1;32m'
|
GREEN='\E[1;32m'
|
||||||
RESET='\E[0m'
|
RESET='\E[0m'
|
||||||
|
|
||||||
S6_OVERLAY_VERSION=3.1.5.0
|
S6_OVERLAY_VERSION=3.2.1.0
|
||||||
TARGETPLATFORM=${1:-linux/amd64}
|
TARGETPLATFORM=${1:-linux/amd64}
|
||||||
|
|
||||||
# Determine the correct binary file for the architecture given
|
# Determine the correct binary file for the architecture given
|
||||||
|
@@ -161,6 +161,14 @@ The easy fix is to add a Docker environment variable to the Nginx Proxy Manager
|
|||||||
DISABLE_IPV6: 'true'
|
DISABLE_IPV6: 'true'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Disabling IP Ranges Fetch
|
||||||
|
|
||||||
|
By default, NPM fetches IP ranges from CloudFront and Cloudflare during application startup. In environments with limited internet access or to speed up container startup, this fetch can be disabled:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
environment:
|
||||||
|
IP_RANGES_FETCH_ENABLED: 'false'
|
||||||
|
```
|
||||||
|
|
||||||
## Custom Nginx Configurations
|
## Custom Nginx Configurations
|
||||||
|
|
||||||
@@ -181,6 +189,7 @@ You can add your custom configuration snippet files at `/data/nginx/custom` as f
|
|||||||
- `/data/nginx/custom/server_stream.conf`: Included at the end of every stream server block
|
- `/data/nginx/custom/server_stream.conf`: Included at the end of every stream server block
|
||||||
- `/data/nginx/custom/server_stream_tcp.conf`: Included at the end of every TCP stream server block
|
- `/data/nginx/custom/server_stream_tcp.conf`: Included at the end of every TCP stream server block
|
||||||
- `/data/nginx/custom/server_stream_udp.conf`: Included at the end of every UDP stream server block
|
- `/data/nginx/custom/server_stream_udp.conf`: Included at the end of every UDP stream server block
|
||||||
|
- `/data/nginx/custom/server_dead.conf`: Included at the end of every 404 server block
|
||||||
|
|
||||||
Every file is optional.
|
Every file is optional.
|
||||||
|
|
||||||
|
@@ -21,8 +21,7 @@ services:
|
|||||||
# Add any other Stream port you want to expose
|
# Add any other Stream port you want to expose
|
||||||
# - '21:21' # FTP
|
# - '21:21' # FTP
|
||||||
|
|
||||||
# Uncomment the next line if you uncomment anything in the section
|
#environment:
|
||||||
# environment:
|
|
||||||
# Uncomment this if you want to change the location of
|
# Uncomment this if you want to change the location of
|
||||||
# the SQLite DB file within the container
|
# the SQLite DB file within the container
|
||||||
# DB_SQLITE_FILE: "/data/database.sqlite"
|
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||||
@@ -99,6 +98,53 @@ Please note, that `DB_MYSQL_*` environment variables will take precedent over `D
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## Using Postgres database
|
||||||
|
|
||||||
|
Similar to the MySQL server setup:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: 'jc21/nginx-proxy-manager:latest'
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
# These ports are in format <host-port>:<container-port>
|
||||||
|
- '80:80' # Public HTTP Port
|
||||||
|
- '443:443' # Public HTTPS Port
|
||||||
|
- '81:81' # Admin Web Port
|
||||||
|
# Add any other Stream port you want to expose
|
||||||
|
# - '21:21' # FTP
|
||||||
|
environment:
|
||||||
|
# Postgres parameters:
|
||||||
|
DB_POSTGRES_HOST: 'db'
|
||||||
|
DB_POSTGRES_PORT: '5432'
|
||||||
|
DB_POSTGRES_USER: 'npm'
|
||||||
|
DB_POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
DB_POSTGRES_NAME: 'npm'
|
||||||
|
# Uncomment this if IPv6 is not enabled on your host
|
||||||
|
# DISABLE_IPV6: 'true'
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:latest
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: 'npm'
|
||||||
|
POSTGRES_PASSWORD: 'npmpass'
|
||||||
|
POSTGRES_DB: 'npm'
|
||||||
|
volumes:
|
||||||
|
- ./postgres:/var/lib/postgresql/data
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
|
||||||
|
Custom Postgres schema is not supported, as such `public` will be used.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## Running on Raspberry PI / ARM devices
|
## Running on Raspberry PI / ARM devices
|
||||||
|
|
||||||
The docker images support the following architectures:
|
The docker images support the following architectures:
|
||||||
@@ -144,43 +190,4 @@ Immediately after logging in with this default user you will be asked to modify
|
|||||||
INITIAL_ADMIN_PASSWORD: mypassword1
|
INITIAL_ADMIN_PASSWORD: mypassword1
|
||||||
```
|
```
|
||||||
|
|
||||||
## OpenID Connect - Single Sign-On (SSO)
|
|
||||||
|
|
||||||
Nginx Proxy Manager supports single sign-on (SSO) with OpenID Connect. This feature allows you to use an external OpenID Connect provider log in.
|
|
||||||
|
|
||||||
::: warning
|
|
||||||
|
|
||||||
Please note, that this feature requires a user to have an existing account to have been created via the "Users" page in the admin interface.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
### Provider Configuration
|
|
||||||
However, before you configure this feature, you need to have an OpenID Connect provider.
|
|
||||||
If you don't have one, you can use Authentik, which is an open-source OpenID Connect provider. Auth0 is another popular OpenID Connect provider that offers a free tier.
|
|
||||||
|
|
||||||
Each provider is a little different, so you will need to refer to the provider's documentation to get the necessary information to configure a new application.
|
|
||||||
You will need the `Client ID`, `Client Secret`, and `Issuer URL` from the provider. When you create the application in the provider, you will also need to include the `Redirect URL` in the list of allowed redirect URLs for the application.
|
|
||||||
Nginx Proxy Manager uses the `/api/oidc/callback` endpoint for the redirect URL.
|
|
||||||
The scopes requested by Nginx Proxy Manager are `openid`, `email`, and `profile` - make sure your auth provider supports these scopes.
|
|
||||||
|
|
||||||
We have confirmed that the following providers work with Nginx Proxy Manager. If you have success with another provider, make a pull request to add it to the list!
|
|
||||||
- Authentik
|
|
||||||
- Authelia
|
|
||||||
- Auth0
|
|
||||||
|
|
||||||
### Nginx Proxy Manager Configuration
|
|
||||||
To enable SSO, log into the management interface as an Administrator and navigate to the "Settings" page.
|
|
||||||
The setting to configure OpenID Connect is named "OpenID Connect Configuration".
|
|
||||||
Click the 3 dots on the far right side of the table and then click "Edit".
|
|
||||||
In the modal that appears, you will see a form with the following fields:
|
|
||||||
|
|
||||||
| Field | Description | Example Value | Notes |
|
|
||||||
|---------------|-----------------------------------------------------------|---------------------------------------------|---------------------------------------------------------------------|
|
|
||||||
| Name | The name of the OpenID Connect provider | Authentik | This will be shown on the login page (eg: "Sign in with Authentik") |
|
|
||||||
| Client ID | The client ID provided by the OpenID Connect provider | `xyz...456` | |
|
|
||||||
| Client Secret | The client secret provided by the OpenID Connect provider | `abc...123` |
|
|
||||||
| Issuer URL | The issuer URL provided by the OpenID Connect provider | `https://authentik.example.com` | This is the URL that the provider uses to identify itself |
|
|
||||||
| Redirect URL | The redirect URL to use for the OpenID Connect provider | `https://npm.example.com/api/oidc/callback` | |
|
|
||||||
|
|
||||||
After filling in the fields, click "Save" to save the settings. You can now use the "Sign in with Authentik" button on the login page to sign in with your OpenID Connect provider.
|
|
||||||
|
|
||||||
|
1
docs/src/third-party/index.md
vendored
1
docs/src/third-party/index.md
vendored
@@ -12,6 +12,7 @@ Known integrations:
|
|||||||
- [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager)
|
- [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager)
|
||||||
- [UnRaid / Synology](https://github.com/jlesage/docker-nginx-proxy-manager)
|
- [UnRaid / Synology](https://github.com/jlesage/docker-nginx-proxy-manager)
|
||||||
- [Proxmox Scripts](https://github.com/ej52/proxmox-scripts/tree/main/apps/nginx-proxy-manager)
|
- [Proxmox Scripts](https://github.com/ej52/proxmox-scripts/tree/main/apps/nginx-proxy-manager)
|
||||||
|
- [Proxmox VE Helper-Scripts](https://community-scripts.github.io/ProxmoxVE/scripts?id=nginxproxymanager)
|
||||||
- [nginxproxymanagerGraf](https://github.com/ma-karai/nginxproxymanagerGraf)
|
- [nginxproxymanagerGraf](https://github.com/ma-karai/nginxproxymanagerGraf)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -873,9 +873,9 @@ mitt@^3.0.1:
|
|||||||
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
||||||
|
|
||||||
nanoid@^3.3.7:
|
nanoid@^3.3.7:
|
||||||
version "3.3.7"
|
version "3.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
|
||||||
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
|
integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
|
||||||
|
|
||||||
oniguruma-to-js@0.4.3:
|
oniguruma-to-js@0.4.3:
|
||||||
version "0.4.3"
|
version "0.4.3"
|
||||||
@@ -1065,9 +1065,9 @@ vfile@^6.0.0:
|
|||||||
vfile-message "^4.0.0"
|
vfile-message "^4.0.0"
|
||||||
|
|
||||||
vite@^5.4.8:
|
vite@^5.4.8:
|
||||||
version "5.4.8"
|
version "5.4.19"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.19.tgz#20efd060410044b3ed555049418a5e7d1998f959"
|
||||||
integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==
|
integrity sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.21.3"
|
esbuild "^0.21.3"
|
||||||
postcss "^8.4.43"
|
postcss "^8.4.43"
|
||||||
|
@@ -59,11 +59,6 @@ function fetch(verb, path, data, options) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeSend: function (xhr) {
|
beforeSend: function (xhr) {
|
||||||
// Allow unauthenticated access to get the oidc configuration
|
|
||||||
if (path === 'settings/oidc-config' && verb === "get") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.setRequestHeader('Authorization', 'Bearer ' + (token ? token.t : null));
|
xhr.setRequestHeader('Authorization', 'Bearer ' + (token ? token.t : null));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -4,449 +4,438 @@ const Tokens = require('./tokens');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} route
|
* @param {String} route
|
||||||
* @param {Object} [options]
|
* @param {Object} [options]
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
navigate: function (route, options) {
|
navigate: function (route, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
Backbone.history.navigate(route.toString(), options);
|
Backbone.history.navigate(route.toString(), options);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login
|
* Login
|
||||||
*/
|
*/
|
||||||
showLogin: function () {
|
showLogin: function () {
|
||||||
window.location = '/login';
|
window.location = '/login';
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users
|
* Users
|
||||||
*/
|
*/
|
||||||
showUsers: function () {
|
showUsers: function () {
|
||||||
let controller = this;
|
const controller = this;
|
||||||
if (Cache.User.isAdmin()) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './users/main'], (App, View) => {
|
require(['./main', './users/main'], (App, View) => {
|
||||||
controller.navigate('/users');
|
controller.navigate('/users');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.showDashboard();
|
this.showDashboard();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Form
|
* User Form
|
||||||
*
|
*
|
||||||
* @param [model]
|
* @param [model]
|
||||||
*/
|
*/
|
||||||
showUserForm: function (model) {
|
showUserForm: function (model) {
|
||||||
if (Cache.User.isAdmin()) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './user/form'], function (App, View) {
|
require(['./main', './user/form'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Permissions Form
|
* User Permissions Form
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showUserPermissions: function (model) {
|
showUserPermissions: function (model) {
|
||||||
if (Cache.User.isAdmin()) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './user/permissions'], function (App, View) {
|
require(['./main', './user/permissions'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Password Form
|
* User Password Form
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showUserPasswordForm: function (model) {
|
showUserPasswordForm: function (model) {
|
||||||
if (Cache.User.isAdmin() || model.get('id') === Cache.User.get('id')) {
|
if (Cache.User.isAdmin() || model.get('id') === Cache.User.get('id')) {
|
||||||
require(['./main', './user/password'], function (App, View) {
|
require(['./main', './user/password'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Delete Confirm
|
* User Delete Confirm
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showUserDeleteConfirm: function (model) {
|
showUserDeleteConfirm: function (model) {
|
||||||
if (Cache.User.isAdmin() && model.get('id') !== Cache.User.get('id')) {
|
if (Cache.User.isAdmin() && model.get('id') !== Cache.User.get('id')) {
|
||||||
require(['./main', './user/delete'], function (App, View) {
|
require(['./main', './user/delete'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard
|
* Dashboard
|
||||||
*/
|
*/
|
||||||
showDashboard: function () {
|
showDashboard: function () {
|
||||||
let controller = this;
|
const controller = this;
|
||||||
|
require(['./main', './dashboard/main'], (App, View) => {
|
||||||
|
controller.navigate('/');
|
||||||
|
App.UI.showAppContent(new View());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './dashboard/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/');
|
* Nginx Proxy Hosts
|
||||||
App.UI.showAppContent(new View());
|
*/
|
||||||
});
|
showNginxProxy: function () {
|
||||||
},
|
if (Cache.User.isAdmin() || Cache.User.canView('proxy_hosts')) {
|
||||||
|
const controller = this;
|
||||||
|
|
||||||
/**
|
require(['./main', './nginx/proxy/main'], (App, View) => {
|
||||||
* Nginx Proxy Hosts
|
controller.navigate('/nginx/proxy');
|
||||||
*/
|
App.UI.showAppContent(new View());
|
||||||
showNginxProxy: function () {
|
});
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('proxy_hosts')) {
|
}
|
||||||
let controller = this;
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/proxy/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/proxy');
|
* Nginx Proxy Host Form
|
||||||
App.UI.showAppContent(new View());
|
*
|
||||||
});
|
* @param [model]
|
||||||
}
|
*/
|
||||||
},
|
showNginxProxyForm: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('proxy_hosts')) {
|
||||||
|
require(['./main', './nginx/proxy/form'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Proxy Host Form
|
* Proxy Host Delete Confirm
|
||||||
*
|
*
|
||||||
* @param [model]
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxProxyForm: function (model) {
|
showNginxProxyDeleteConfirm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('proxy_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('proxy_hosts')) {
|
||||||
require(['./main', './nginx/proxy/form'], function (App, View) {
|
require(['./main', './nginx/proxy/delete'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy Host Delete Confirm
|
* Nginx Redirection Hosts
|
||||||
*
|
*/
|
||||||
* @param model
|
showNginxRedirection: function () {
|
||||||
*/
|
if (Cache.User.isAdmin() || Cache.User.canView('redirection_hosts')) {
|
||||||
showNginxProxyDeleteConfirm: function (model) {
|
const controller = this;
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('proxy_hosts')) {
|
require(['./main', './nginx/redirection/main'], (App, View) => {
|
||||||
require(['./main', './nginx/proxy/delete'], function (App, View) {
|
controller.navigate('/nginx/redirection');
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showAppContent(new View());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Redirection Hosts
|
* Nginx Redirection Host Form
|
||||||
*/
|
*
|
||||||
showNginxRedirection: function () {
|
* @param [model]
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('redirection_hosts')) {
|
*/
|
||||||
let controller = this;
|
showNginxRedirectionForm: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('redirection_hosts')) {
|
||||||
|
require(['./main', './nginx/redirection/form'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/redirection/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/redirection');
|
* Proxy Redirection Delete Confirm
|
||||||
App.UI.showAppContent(new View());
|
*
|
||||||
});
|
* @param model
|
||||||
}
|
*/
|
||||||
},
|
showNginxRedirectionDeleteConfirm: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('redirection_hosts')) {
|
||||||
|
require(['./main', './nginx/redirection/delete'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Redirection Host Form
|
* Nginx Stream Hosts
|
||||||
*
|
*/
|
||||||
* @param [model]
|
showNginxStream: function () {
|
||||||
*/
|
if (Cache.User.isAdmin() || Cache.User.canView('streams')) {
|
||||||
showNginxRedirectionForm: function (model) {
|
const controller = this;
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('redirection_hosts')) {
|
require(['./main', './nginx/stream/main'], (App, View) => {
|
||||||
require(['./main', './nginx/redirection/form'], function (App, View) {
|
controller.navigate('/nginx/stream');
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showAppContent(new View());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy Redirection Delete Confirm
|
* Stream Form
|
||||||
*
|
*
|
||||||
* @param model
|
* @param [model]
|
||||||
*/
|
*/
|
||||||
showNginxRedirectionDeleteConfirm: function (model) {
|
showNginxStreamForm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('redirection_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('streams')) {
|
||||||
require(['./main', './nginx/redirection/delete'], function (App, View) {
|
require(['./main', './nginx/stream/form'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Stream Hosts
|
* Stream Delete Confirm
|
||||||
*/
|
*
|
||||||
showNginxStream: function () {
|
* @param model
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('streams')) {
|
*/
|
||||||
let controller = this;
|
showNginxStreamDeleteConfirm: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('streams')) {
|
||||||
|
require(['./main', './nginx/stream/delete'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/stream/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/stream');
|
* Nginx Dead Hosts
|
||||||
App.UI.showAppContent(new View());
|
*/
|
||||||
});
|
showNginxDead: function () {
|
||||||
}
|
if (Cache.User.isAdmin() || Cache.User.canView('dead_hosts')) {
|
||||||
},
|
const controller = this;
|
||||||
|
require(['./main', './nginx/dead/main'], (App, View) => {
|
||||||
|
controller.navigate('/nginx/404');
|
||||||
|
App.UI.showAppContent(new View());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream Form
|
* Dead Host Form
|
||||||
*
|
*
|
||||||
* @param [model]
|
* @param [model]
|
||||||
*/
|
*/
|
||||||
showNginxStreamForm: function (model) {
|
showNginxDeadForm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('streams')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('dead_hosts')) {
|
||||||
require(['./main', './nginx/stream/form'], function (App, View) {
|
require(['./main', './nginx/dead/form'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream Delete Confirm
|
* Dead Host Delete Confirm
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxStreamDeleteConfirm: function (model) {
|
showNginxDeadDeleteConfirm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('streams')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('dead_hosts')) {
|
||||||
require(['./main', './nginx/stream/delete'], function (App, View) {
|
require(['./main', './nginx/dead/delete'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Dead Hosts
|
* Help Dialog
|
||||||
*/
|
*
|
||||||
showNginxDead: function () {
|
* @param {String} title
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('dead_hosts')) {
|
* @param {String} content
|
||||||
let controller = this;
|
*/
|
||||||
|
showHelp: function (title, content) {
|
||||||
|
require(['./main', './help/main'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({title: title, content: content}));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/dead/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/404');
|
* Nginx Access
|
||||||
App.UI.showAppContent(new View());
|
*/
|
||||||
});
|
showNginxAccess: function () {
|
||||||
}
|
if (Cache.User.isAdmin() || Cache.User.canView('access_lists')) {
|
||||||
},
|
const controller = this;
|
||||||
|
require(['./main', './nginx/access/main'], (App, View) => {
|
||||||
|
controller.navigate('/nginx/access');
|
||||||
|
App.UI.showAppContent(new View());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dead Host Form
|
* Nginx Access List Form
|
||||||
*
|
*
|
||||||
* @param [model]
|
* @param [model]
|
||||||
*/
|
*/
|
||||||
showNginxDeadForm: function (model) {
|
showNginxAccessListForm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('dead_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('access_lists')) {
|
||||||
require(['./main', './nginx/dead/form'], function (App, View) {
|
require(['./main', './nginx/access/form'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dead Host Delete Confirm
|
* Access List Delete Confirm
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxDeadDeleteConfirm: function (model) {
|
showNginxAccessListDeleteConfirm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('dead_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('access_lists')) {
|
||||||
require(['./main', './nginx/dead/delete'], function (App, View) {
|
require(['./main', './nginx/access/delete'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Help Dialog
|
* Nginx Certificates
|
||||||
*
|
*/
|
||||||
* @param {String} title
|
showNginxCertificates: function () {
|
||||||
* @param {String} content
|
if (Cache.User.isAdmin() || Cache.User.canView('certificates')) {
|
||||||
*/
|
const controller = this;
|
||||||
showHelp: function (title, content) {
|
require(['./main', './nginx/certificates/main'], (App, View) => {
|
||||||
require(['./main', './help/main'], function (App, View) {
|
controller.navigate('/nginx/certificates');
|
||||||
App.UI.showModalDialog(new View({title: title, content: content}));
|
App.UI.showAppContent(new View());
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Access
|
* Nginx Certificate Form
|
||||||
*/
|
*
|
||||||
showNginxAccess: function () {
|
* @param [model]
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('access_lists')) {
|
*/
|
||||||
let controller = this;
|
showNginxCertificateForm: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
||||||
|
require(['./main', './nginx/certificates/form'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/access/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/access');
|
* Certificate Renew
|
||||||
App.UI.showAppContent(new View());
|
*
|
||||||
});
|
* @param model
|
||||||
}
|
*/
|
||||||
},
|
showNginxCertificateRenew: function (model) {
|
||||||
|
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
||||||
|
require(['./main', './nginx/certificates/renew'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Access List Form
|
* Certificate Delete Confirm
|
||||||
*
|
*
|
||||||
* @param [model]
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxAccessListForm: function (model) {
|
showNginxCertificateDeleteConfirm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('access_lists')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
||||||
require(['./main', './nginx/access/form'], function (App, View) {
|
require(['./main', './nginx/certificates/delete'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access List Delete Confirm
|
* Certificate Test Reachability
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxAccessListDeleteConfirm: function (model) {
|
showNginxCertificateTestReachability: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('access_lists')) {
|
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
||||||
require(['./main', './nginx/access/delete'], function (App, View) {
|
require(['./main', './nginx/certificates/test'], function (App, View) {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Certificates
|
* Audit Log
|
||||||
*/
|
*/
|
||||||
showNginxCertificates: function () {
|
showAuditLog: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('certificates')) {
|
const controller = this;
|
||||||
let controller = this;
|
if (Cache.User.isAdmin()) {
|
||||||
|
require(['./main', './audit-log/main'], (App, View) => {
|
||||||
|
controller.navigate('/audit-log');
|
||||||
|
App.UI.showAppContent(new View());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.showDashboard();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
require(['./main', './nginx/certificates/main'], (App, View) => {
|
/**
|
||||||
controller.navigate('/nginx/certificates');
|
* Audit Log Metadata
|
||||||
App.UI.showAppContent(new View());
|
*
|
||||||
});
|
* @param model
|
||||||
}
|
*/
|
||||||
},
|
showAuditMeta: function (model) {
|
||||||
|
if (Cache.User.isAdmin()) {
|
||||||
|
require(['./main', './audit-log/meta'], function (App, View) {
|
||||||
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nginx Certificate Form
|
* Settings
|
||||||
*
|
*/
|
||||||
* @param [model]
|
showSettings: function () {
|
||||||
*/
|
const controller = this;
|
||||||
showNginxCertificateForm: function (model) {
|
if (Cache.User.isAdmin()) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
require(['./main', './settings/main'], (App, View) => {
|
||||||
require(['./main', './nginx/certificates/form'], function (App, View) {
|
controller.navigate('/settings');
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
App.UI.showAppContent(new View());
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
},
|
this.showDashboard();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate Renew
|
* Settings Item Form
|
||||||
*
|
*
|
||||||
* @param model
|
* @param model
|
||||||
*/
|
*/
|
||||||
showNginxCertificateRenew: function (model) {
|
showSettingForm: function (model) {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './nginx/certificates/renew'], function (App, View) {
|
if (model.get('id') === 'default-site') {
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
require(['./main', './settings/default-site/main'], function (App, View) {
|
||||||
});
|
App.UI.showModalDialog(new View({model: model}));
|
||||||
}
|
});
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Certificate Delete Confirm
|
* Logout
|
||||||
*
|
*/
|
||||||
* @param model
|
logout: function () {
|
||||||
*/
|
Tokens.dropTopToken();
|
||||||
showNginxCertificateDeleteConfirm: function (model) {
|
this.showLogin();
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
}
|
||||||
require(['./main', './nginx/certificates/delete'], function (App, View) {
|
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Certificate Test Reachability
|
|
||||||
*
|
|
||||||
* @param model
|
|
||||||
*/
|
|
||||||
showNginxCertificateTestReachability: function (model) {
|
|
||||||
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
|
|
||||||
require(['./main', './nginx/certificates/test'], function (App, View) {
|
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Audit Log
|
|
||||||
*/
|
|
||||||
showAuditLog: function () {
|
|
||||||
let controller = this;
|
|
||||||
if (Cache.User.isAdmin()) {
|
|
||||||
require(['./main', './audit-log/main'], (App, View) => {
|
|
||||||
controller.navigate('/audit-log');
|
|
||||||
App.UI.showAppContent(new View());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.showDashboard();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Audit Log Metadata
|
|
||||||
*
|
|
||||||
* @param model
|
|
||||||
*/
|
|
||||||
showAuditMeta: function (model) {
|
|
||||||
if (Cache.User.isAdmin()) {
|
|
||||||
require(['./main', './audit-log/meta'], function (App, View) {
|
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings
|
|
||||||
*/
|
|
||||||
showSettings: function () {
|
|
||||||
let controller = this;
|
|
||||||
if (Cache.User.isAdmin()) {
|
|
||||||
require(['./main', './settings/main'], (App, View) => {
|
|
||||||
controller.navigate('/settings');
|
|
||||||
App.UI.showAppContent(new View());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.showDashboard();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings Item Form
|
|
||||||
*
|
|
||||||
* @param model
|
|
||||||
*/
|
|
||||||
showSettingForm: function (model) {
|
|
||||||
if (Cache.User.isAdmin()) {
|
|
||||||
if (model.get('id') === 'default-site') {
|
|
||||||
require(['./main', './settings/default-site/main'], function (App, View) {
|
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (model.get('id') === 'oidc-config') {
|
|
||||||
require(['./main', './settings/oidc-config/main'], function (App, View) {
|
|
||||||
App.UI.showModalDialog(new View({model: model}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logout
|
|
||||||
*/
|
|
||||||
logout: function () {
|
|
||||||
Tokens.dropTopToken();
|
|
||||||
this.showLogin();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1 class="page-title" data-cy="page-title"><%- i18n('dashboard', 'title', {name: getUserName()}) %></h1>
|
<h1 class="page-title"><%- i18n('dashboard', 'title', {name: getUserName()}) %></h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% if (columns) { %>
|
<% if (columns) { %>
|
||||||
|
@@ -6,85 +6,85 @@ const Helpers = require('../../lib/helpers');
|
|||||||
const template = require('./main.ejs');
|
const template = require('./main.ejs');
|
||||||
|
|
||||||
module.exports = Mn.View.extend({
|
module.exports = Mn.View.extend({
|
||||||
template: template,
|
template: template,
|
||||||
id: 'dashboard',
|
id: 'dashboard',
|
||||||
columns: 0,
|
columns: 0,
|
||||||
|
|
||||||
stats: {},
|
stats: {},
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
links: 'a'
|
links: 'a'
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'click @ui.links': function (e) {
|
'click @ui.links': function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
Controller.navigate($(e.currentTarget).attr('href'), true);
|
Controller.navigate($(e.currentTarget).attr('href'), true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
templateContext: function () {
|
templateContext: function () {
|
||||||
let view = this;
|
const view = this;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUserName: function () {
|
getUserName: function () {
|
||||||
return Cache.User.get('nickname') || Cache.User.get('name');
|
return Cache.User.get('nickname') || Cache.User.get('name');
|
||||||
},
|
},
|
||||||
|
|
||||||
getHostStat: function (type) {
|
getHostStat: function (type) {
|
||||||
if (view.stats && typeof view.stats.hosts !== 'undefined' && typeof view.stats.hosts[type] !== 'undefined') {
|
if (view.stats && typeof view.stats.hosts !== 'undefined' && typeof view.stats.hosts[type] !== 'undefined') {
|
||||||
return Helpers.niceNumber(view.stats.hosts[type]);
|
return Helpers.niceNumber(view.stats.hosts[type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '-';
|
return '-';
|
||||||
},
|
},
|
||||||
|
|
||||||
canShow: function (perm) {
|
canShow: function (perm) {
|
||||||
return Cache.User.isAdmin() || Cache.User.canView(perm);
|
return Cache.User.isAdmin() || Cache.User.canView(perm);
|
||||||
},
|
},
|
||||||
|
|
||||||
columns: view.columns
|
columns: view.columns
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
onRender: function () {
|
onRender: function () {
|
||||||
let view = this;
|
const view = this;
|
||||||
|
if (typeof view.stats.hosts === 'undefined') {
|
||||||
|
Api.Reports.getHostStats()
|
||||||
|
.then(response => {
|
||||||
|
if (!view.isDestroyed()) {
|
||||||
|
view.stats.hosts = response;
|
||||||
|
view.render();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
Api.Reports.getHostStats()
|
/**
|
||||||
.then(response => {
|
* @param {Object} [model]
|
||||||
if (!view.isDestroyed()) {
|
*/
|
||||||
view.stats.hosts = response;
|
preRender: function (model) {
|
||||||
view.render();
|
this.columns = 0;
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
// calculate the available columns based on permissions for the objects
|
||||||
* @param {Object} [model]
|
// and store as a variable
|
||||||
*/
|
const perms = ['proxy_hosts', 'redirection_hosts', 'streams', 'dead_hosts'];
|
||||||
preRender: function (model) {
|
|
||||||
this.columns = 0;
|
|
||||||
|
|
||||||
// calculate the available columns based on permissions for the objects
|
perms.map(perm => {
|
||||||
// and store as a variable
|
this.columns += Cache.User.isAdmin() || Cache.User.canView(perm) ? 1 : 0;
|
||||||
//let view = this;
|
});
|
||||||
let perms = ['proxy_hosts', 'redirection_hosts', 'streams', 'dead_hosts'];
|
|
||||||
|
|
||||||
perms.map(perm => {
|
// Prevent double rendering on initial calls
|
||||||
this.columns += Cache.User.isAdmin() || Cache.User.canView(perm) ? 1 : 0;
|
if (typeof model !== 'undefined') {
|
||||||
});
|
this.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Prevent double rendering on initial calls
|
initialize: function () {
|
||||||
if (typeof model !== 'undefined') {
|
this.preRender();
|
||||||
this.render();
|
this.listenTo(Cache.User, 'change', this.preRender);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function () {
|
|
||||||
this.preRender();
|
|
||||||
this.listenTo(Cache.User, 'change', this.preRender);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@@ -33,6 +33,13 @@
|
|||||||
<td class="<%- isExpired() ? 'text-danger' : '' %>">
|
<td class="<%- isExpired() ? 'text-danger' : '' %>">
|
||||||
<%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
|
<%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<% if (active_domain_names().length > 0) { %>
|
||||||
|
<span class="status-icon bg-success"></span> <%- i18n('certificates', 'in-use') %>
|
||||||
|
<% } else { %>
|
||||||
|
<span class="status-icon bg-danger"></span> <%- i18n('certificates', 'inactive') %>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
<% if (canManage) { %>
|
<% if (canManage) { %>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<div class="item-action dropdown">
|
<div class="item-action dropdown">
|
||||||
@@ -48,7 +55,14 @@
|
|||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
|
<a href="#" class="delete dropdown-item"><i class="dropdown-icon fe fe-trash-2"></i> <%- i18n('str', 'delete') %></a>
|
||||||
|
<% if (active_domain_names().length > 0) { %>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<span class="dropdown-header"><%- i18n('certificates', 'active-domain_names') %></span>
|
||||||
|
<% active_domain_names().forEach(function(host) { %>
|
||||||
|
<a href="https://<%- host %>" class="dropdown-item" target="_blank"><%- host %></a>
|
||||||
|
<% }); %>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<% } %>
|
<% } %>
|
@@ -44,14 +44,24 @@ module.exports = Mn.View.extend({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
templateContext: {
|
templateContext: function () {
|
||||||
canManage: App.Cache.User.canManage('certificates'),
|
return {
|
||||||
isExpired: function () {
|
canManage: App.Cache.User.canManage('certificates'),
|
||||||
return moment(this.expires_on).isBefore(moment());
|
isExpired: function () {
|
||||||
},
|
return moment(this.expires_on).isBefore(moment());
|
||||||
dns_providers: dns_providers
|
},
|
||||||
|
dns_providers: dns_providers,
|
||||||
|
active_domain_names: function () {
|
||||||
|
const { proxy_hosts = [], redirect_hosts = [], dead_hosts = [] } = this;
|
||||||
|
return [...proxy_hosts, ...redirect_hosts, ...dead_hosts].reduce((acc, host) => {
|
||||||
|
acc.push(...(host.domain_names || []));
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
this.listenTo(this.model, 'change', this.render);
|
this.listenTo(this.model, 'change', this.render);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
<th><%- i18n('str', 'name') %></th>
|
<th><%- i18n('str', 'name') %></th>
|
||||||
<th><%- i18n('all-hosts', 'cert-provider') %></th>
|
<th><%- i18n('all-hosts', 'cert-provider') %></th>
|
||||||
<th><%- i18n('str', 'expires') %></th>
|
<th><%- i18n('str', 'expires') %></th>
|
||||||
|
<th><%- i18n('str', 'status') %></th>
|
||||||
<% if (canManage) { %>
|
<% if (canManage) { %>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
@@ -74,7 +74,7 @@ module.exports = Mn.View.extend({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let query = this.ui.query.val();
|
let query = this.ui.query.val();
|
||||||
|
|
||||||
this.fetch(['owner'], query)
|
this.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'], query)
|
||||||
.then(response => this.showData(response))
|
.then(response => this.showData(response))
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.showError(err);
|
this.showError(err);
|
||||||
@@ -89,7 +89,7 @@ module.exports = Mn.View.extend({
|
|||||||
onRender: function () {
|
onRender: function () {
|
||||||
let view = this;
|
let view = this;
|
||||||
|
|
||||||
view.fetch(['owner'])
|
view.fetch(['owner','proxy_hosts', 'dead_hosts', 'redirection_hosts'])
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!view.isDestroyed()) {
|
if (!view.isDestroyed()) {
|
||||||
if (response && response.length) {
|
if (response && response.length) {
|
||||||
|
@@ -3,48 +3,187 @@
|
|||||||
<h5 class="modal-title"><%- i18n('streams', 'form-title', {id: id}) %></h5>
|
<h5 class="modal-title"><%- i18n('streams', 'form-title', {id: id}) %></h5>
|
||||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body has-tabs">
|
||||||
|
<div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
|
||||||
<form>
|
<form>
|
||||||
<div class="row">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<div class="col-sm-12 col-md-12">
|
<li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
|
||||||
<div class="form-group">
|
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
|
||||||
<label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
|
</ul>
|
||||||
<input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" min="1" max="65535" value="<%- incoming_port %>" required>
|
<div class="tab-content">
|
||||||
|
<!-- Details -->
|
||||||
|
<div role="tabpanel" class="tab-pane active" id="details">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
|
||||||
|
<input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" min="1" max="65535" value="<%- incoming_port %>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8 col-md-8">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('streams', 'forwarding-host') %><span class="form-required">*</span></label>
|
||||||
|
<input type="text" name="forwarding_host" class="form-control text-monospace" placeholder="example.com or 10.0.0.1 or 2001:db8:3333:4444:5555:6666:7777:8888" value="<%- forwarding_host %>" autocomplete="off" maxlength="255" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-md-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
|
||||||
|
<input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" min="1" max="65535" value="<%- forwarding_port %>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="custom-switch">
|
||||||
|
<input type="checkbox" class="custom-switch-input" name="tcp_forwarding" value="1"<%- tcp_forwarding ? ' checked' : '' %>>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
<span class="custom-switch-description"><%- i18n('streams', 'tcp-forwarding') %></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="custom-switch">
|
||||||
|
<input type="checkbox" class="custom-switch-input" name="udp_forwarding" value="1"<%- udp_forwarding ? ' checked' : '' %>>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
<span class="custom-switch-description"><%- i18n('streams', 'udp-forwarding') %></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 col-md-8">
|
|
||||||
<div class="form-group">
|
<!-- SSL -->
|
||||||
<label class="form-label"><%- i18n('streams', 'forwarding-host') %><span class="form-required">*</span></label>
|
<div role="tabpanel" class="tab-pane" id="ssl-options">
|
||||||
<input type="text" name="forwarding_host" class="form-control text-monospace" placeholder="example.com or 10.0.0.1 or 2001:db8:3333:4444:5555:6666:7777:8888" value="<%- forwarding_host %>" autocomplete="off" maxlength="255" required>
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('streams', 'ssl-certificate') %></label>
|
||||||
|
<select name="certificate_id" class="form-control custom-select" placeholder="<%- i18n('all-hosts', 'none') %>">
|
||||||
|
<option selected value="0" data-data="{"id":0}" <%- certificate_id ? '' : 'selected' %>><%- i18n('all-hosts', 'none') %></option>
|
||||||
|
<option selected value="new" data-data="{"id":"new"}"><%- i18n('all-hosts', 'new-cert') %></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DNS challenge -->
|
||||||
|
<div class="col-sm-12 col-md-12 letsencrypt">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('all-hosts', 'domain-names') %> <span class="form-required">*</span></label>
|
||||||
|
<input type="text" name="domain_names" class="form-control" id="input-domains" value="<%- domain_names.join(',') %>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="custom-switch">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="custom-switch-input"
|
||||||
|
name="meta[dns_challenge]"
|
||||||
|
value="1"
|
||||||
|
checked
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
<span class="custom-switch-description"><%= i18n('ssl', 'dns-challenge') %></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 letsencrypt">
|
||||||
|
<fieldset class="form-fieldset dns-challenge">
|
||||||
|
<div class="text-red mb-4"><i class="fe fe-alert-triangle"></i> <%= i18n('ssl', 'certbot-warning') %></div>
|
||||||
|
|
||||||
|
<!-- Certbot DNS plugin selection -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
|
||||||
|
<select
|
||||||
|
name="meta[dns_provider]"
|
||||||
|
id="dns_provider"
|
||||||
|
class="form-control custom-select"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
value=""
|
||||||
|
disabled
|
||||||
|
hidden
|
||||||
|
<%- getDnsProvider() === null ? 'selected' : '' %>
|
||||||
|
>Please Choose...</option>
|
||||||
|
<% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
|
||||||
|
<option
|
||||||
|
value="<%- plugin_name %>"
|
||||||
|
<%- getDnsProvider() === plugin_name ? 'selected' : '' %>
|
||||||
|
><%- plugin_info.name %></option>
|
||||||
|
<% }); %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Certbot credentials file content -->
|
||||||
|
<div class="row credentials-file-content">
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
|
||||||
|
<textarea
|
||||||
|
name="meta[dns_provider_credentials]"
|
||||||
|
class="form-control text-monospace"
|
||||||
|
id="dns_provider_credentials"
|
||||||
|
><%- getDnsProviderCredentials() %></textarea>
|
||||||
|
<div class="text-secondary small">
|
||||||
|
<i class="fe fe-info"></i>
|
||||||
|
<%= i18n('ssl', 'credentials-file-content-info') %>
|
||||||
|
</div>
|
||||||
|
<div class="text-red small">
|
||||||
|
<i class="fe fe-alert-triangle"></i>
|
||||||
|
<%= i18n('ssl', 'stored-as-plaintext-info') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- DNS propagation delay -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-12">
|
||||||
|
<div class="form-group mb-0">
|
||||||
|
<label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
name="meta[propagation_seconds]"
|
||||||
|
class="form-control"
|
||||||
|
id="propagation_seconds"
|
||||||
|
value="<%- getPropagationSeconds() %>"
|
||||||
|
>
|
||||||
|
<div class="text-secondary small">
|
||||||
|
<i class="fe fe-info"></i>
|
||||||
|
<%= i18n('ssl', 'propagation-seconds-info') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Lets encrypt -->
|
||||||
|
<div class="col-sm-12 col-md-12 letsencrypt">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('ssl', 'letsencrypt-email') %> <span class="form-required">*</span></label>
|
||||||
|
<input name="meta[letsencrypt_email]" type="email" class="form-control" placeholder="" value="<%- getLetsencryptEmail() %>" required disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 letsencrypt">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="custom-switch">
|
||||||
|
<input type="checkbox" class="custom-switch-input" name="meta[letsencrypt_agree]" value="1" required disabled>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
<span class="custom-switch-description"><%= i18n('ssl', 'letsencrypt-agree', {url: 'https://letsencrypt.org/repository/'}) %> <span class="form-required">*</span></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 col-md-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
|
|
||||||
<input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" min="1" max="65535" value="<%- forwarding_port %>" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="custom-switch">
|
|
||||||
<input type="checkbox" class="custom-switch-input" name="tcp_forwarding" value="1"<%- tcp_forwarding ? ' checked' : '' %>>
|
|
||||||
<span class="custom-switch-indicator"></span>
|
|
||||||
<span class="custom-switch-description"><%- i18n('streams', 'tcp-forwarding') %></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-md-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="custom-switch">
|
|
||||||
<input type="checkbox" class="custom-switch-input" name="udp_forwarding" value="1"<%- udp_forwarding ? ' checked' : '' %>>
|
|
||||||
<span class="custom-switch-indicator"></span>
|
|
||||||
<span class="custom-switch-description"><%- i18n('streams', 'udp-forwarding') %></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-12">
|
|
||||||
<div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,24 +1,38 @@
|
|||||||
const Mn = require('backbone.marionette');
|
const Mn = require('backbone.marionette');
|
||||||
const App = require('../../main');
|
const App = require('../../main');
|
||||||
const StreamModel = require('../../../models/stream');
|
const StreamModel = require('../../../models/stream');
|
||||||
const template = require('./form.ejs');
|
const template = require('./form.ejs');
|
||||||
|
const dns_providers = require('../../../../../global/certbot-dns-plugins');
|
||||||
|
|
||||||
require('jquery-serializejson');
|
require('jquery-serializejson');
|
||||||
require('jquery-mask-plugin');
|
require('jquery-mask-plugin');
|
||||||
require('selectize');
|
require('selectize');
|
||||||
|
const Helpers = require("../../../lib/helpers");
|
||||||
|
const certListItemTemplate = require("../certificates-list-item.ejs");
|
||||||
|
const i18n = require("../../i18n");
|
||||||
|
|
||||||
module.exports = Mn.View.extend({
|
module.exports = Mn.View.extend({
|
||||||
template: template,
|
template: template,
|
||||||
className: 'modal-dialog',
|
className: 'modal-dialog',
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
form: 'form',
|
form: 'form',
|
||||||
forwarding_host: 'input[name="forwarding_host"]',
|
forwarding_host: 'input[name="forwarding_host"]',
|
||||||
type_error: '.forward-type-error',
|
type_error: '.forward-type-error',
|
||||||
buttons: '.modal-footer button',
|
buttons: '.modal-footer button',
|
||||||
switches: '.custom-switch-input',
|
switches: '.custom-switch-input',
|
||||||
cancel: 'button.cancel',
|
cancel: 'button.cancel',
|
||||||
save: 'button.save'
|
save: 'button.save',
|
||||||
|
le_error_info: '#le-error-info',
|
||||||
|
certificate_select: 'select[name="certificate_id"]',
|
||||||
|
domain_names: 'input[name="domain_names"]',
|
||||||
|
dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
|
||||||
|
dns_challenge_content: '.dns-challenge',
|
||||||
|
dns_provider: 'select[name="meta[dns_provider]"]',
|
||||||
|
credentials_file_content: '.credentials-file-content',
|
||||||
|
dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
|
||||||
|
propagation_seconds: 'input[name="meta[propagation_seconds]"]',
|
||||||
|
letsencrypt: '.letsencrypt'
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
@@ -48,6 +62,35 @@ module.exports = Mn.View.extend({
|
|||||||
data.tcp_forwarding = !!data.tcp_forwarding;
|
data.tcp_forwarding = !!data.tcp_forwarding;
|
||||||
data.udp_forwarding = !!data.udp_forwarding;
|
data.udp_forwarding = !!data.udp_forwarding;
|
||||||
|
|
||||||
|
if (typeof data.meta === 'undefined') data.meta = {};
|
||||||
|
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
|
||||||
|
data.meta.dns_challenge = true;
|
||||||
|
|
||||||
|
if (data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
|
||||||
|
|
||||||
|
if (typeof data.domain_names === 'string' && data.domain_names) {
|
||||||
|
data.domain_names = data.domain_names.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for any domain names containing wildcards, which are not allowed with letsencrypt
|
||||||
|
if (data.certificate_id === 'new') {
|
||||||
|
let domain_err = false;
|
||||||
|
if (!data.meta.dns_challenge) {
|
||||||
|
data.domain_names.map(function (name) {
|
||||||
|
if (name.match(/\*/im)) {
|
||||||
|
domain_err = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain_err) {
|
||||||
|
alert(i18n('ssl', 'no-wildcard-without-dns'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.certificate_id = parseInt(data.certificate_id, 10);
|
||||||
|
}
|
||||||
|
|
||||||
let method = App.Api.Nginx.Streams.create;
|
let method = App.Api.Nginx.Streams.create;
|
||||||
let is_new = true;
|
let is_new = true;
|
||||||
|
|
||||||
@@ -70,10 +113,108 @@ module.exports = Mn.View.extend({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
alert(err.message);
|
let more_info = '';
|
||||||
|
if (err.code === 500 && err.debug) {
|
||||||
|
try {
|
||||||
|
more_info = JSON.parse(err.debug).debug.stack.join("\n");
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ui.le_error_info[0].innerHTML = `${err.message}${more_info !== '' ? `<pre class="mt-3">${more_info}</pre>` : ''}`;
|
||||||
|
this.ui.le_error_info.show();
|
||||||
|
this.ui.le_error_info[0].scrollIntoView();
|
||||||
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
|
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
|
||||||
|
this.ui.save.removeClass('btn-loading');
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
'change @ui.certificate_select': function () {
|
||||||
|
let id = this.ui.certificate_select.val();
|
||||||
|
if (id === 'new') {
|
||||||
|
this.ui.letsencrypt.show().find('input').prop('disabled', false);
|
||||||
|
this.ui.domain_names.prop('required', 'required');
|
||||||
|
|
||||||
|
this.ui.dns_challenge_switch
|
||||||
|
.prop('disabled', true)
|
||||||
|
.parents('.form-group')
|
||||||
|
.css('opacity', 0.5);
|
||||||
|
|
||||||
|
this.ui.dns_provider.prop('required', 'required');
|
||||||
|
const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value;
|
||||||
|
if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) {
|
||||||
|
this.ui.dns_provider_credentials.prop('required', 'required');
|
||||||
|
}
|
||||||
|
this.ui.dns_challenge_content.show();
|
||||||
|
} else {
|
||||||
|
this.ui.letsencrypt.hide().find('input').prop('disabled', true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'change @ui.dns_provider': function () {
|
||||||
|
const selected_provider = this.ui.dns_provider[0].options[this.ui.dns_provider[0].selectedIndex].value;
|
||||||
|
if (selected_provider != '' && dns_providers[selected_provider].credentials !== false) {
|
||||||
|
this.ui.dns_provider_credentials.prop('required', 'required');
|
||||||
|
this.ui.dns_provider_credentials[0].value = dns_providers[selected_provider].credentials;
|
||||||
|
this.ui.credentials_file_content.show();
|
||||||
|
} else {
|
||||||
|
this.ui.dns_provider_credentials.prop('required', false);
|
||||||
|
this.ui.credentials_file_content.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
templateContext: {
|
||||||
|
getLetsencryptEmail: function () {
|
||||||
|
return App.Cache.User.get('email');
|
||||||
|
},
|
||||||
|
getDnsProvider: function () {
|
||||||
|
return typeof this.meta.dns_provider !== 'undefined' && this.meta.dns_provider != '' ? this.meta.dns_provider : null;
|
||||||
|
},
|
||||||
|
getDnsProviderCredentials: function () {
|
||||||
|
return typeof this.meta.dns_provider_credentials !== 'undefined' ? this.meta.dns_provider_credentials : '';
|
||||||
|
},
|
||||||
|
getPropagationSeconds: function () {
|
||||||
|
return typeof this.meta.propagation_seconds !== 'undefined' ? this.meta.propagation_seconds : '';
|
||||||
|
},
|
||||||
|
dns_plugins: dns_providers,
|
||||||
|
},
|
||||||
|
|
||||||
|
onRender: function () {
|
||||||
|
let view = this;
|
||||||
|
|
||||||
|
// Certificates
|
||||||
|
this.ui.le_error_info.hide();
|
||||||
|
this.ui.dns_challenge_content.hide();
|
||||||
|
this.ui.credentials_file_content.hide();
|
||||||
|
this.ui.letsencrypt.hide();
|
||||||
|
this.ui.certificate_select.selectize({
|
||||||
|
valueField: 'id',
|
||||||
|
labelField: 'nice_name',
|
||||||
|
searchField: ['nice_name', 'domain_names'],
|
||||||
|
create: false,
|
||||||
|
preload: true,
|
||||||
|
allowEmptyOption: true,
|
||||||
|
render: {
|
||||||
|
option: function (item) {
|
||||||
|
item.i18n = App.i18n;
|
||||||
|
item.formatDbDate = Helpers.formatDbDate;
|
||||||
|
return certListItemTemplate(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
load: function (query, callback) {
|
||||||
|
App.Api.Nginx.Certificates.getAll()
|
||||||
|
.then(rows => {
|
||||||
|
callback(rows);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLoad: function () {
|
||||||
|
view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function (options) {
|
initialize: function (options) {
|
||||||
|
@@ -16,7 +16,10 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div>
|
<div>
|
||||||
<% if (tcp_forwarding) { %>
|
<% if (certificate) { %>
|
||||||
|
<span class="tag"><%- i18n('streams', 'tcp+ssl') %></span>
|
||||||
|
<% }
|
||||||
|
else if (tcp_forwarding) { %>
|
||||||
<span class="tag"><%- i18n('streams', 'tcp') %></span>
|
<span class="tag"><%- i18n('streams', 'tcp') %></span>
|
||||||
<% }
|
<% }
|
||||||
if (udp_forwarding) { %>
|
if (udp_forwarding) { %>
|
||||||
@@ -24,6 +27,9 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<div><%- certificate && certificate_id ? i18n('ssl', certificate.provider) : i18n('all-hosts', 'none') %></div>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<%
|
<%
|
||||||
var o = isOnline();
|
var o = isOnline();
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
<th><%- i18n('streams', 'incoming-port') %></th>
|
<th><%- i18n('streams', 'incoming-port') %></th>
|
||||||
<th><%- i18n('str', 'destination') %></th>
|
<th><%- i18n('str', 'destination') %></th>
|
||||||
<th><%- i18n('streams', 'protocol') %></th>
|
<th><%- i18n('streams', 'protocol') %></th>
|
||||||
|
<th><%- i18n('str', 'ssl') %></th>
|
||||||
<th><%- i18n('str', 'status') %></th>
|
<th><%- i18n('str', 'status') %></th>
|
||||||
<% if (canManage) { %>
|
<% if (canManage) { %>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
|
@@ -88,7 +88,7 @@ module.exports = Mn.View.extend({
|
|||||||
onRender: function () {
|
onRender: function () {
|
||||||
let view = this;
|
let view = this;
|
||||||
|
|
||||||
view.fetch(['owner'])
|
view.fetch(['owner', 'certificate'])
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!view.isDestroyed()) {
|
if (!view.isDestroyed()) {
|
||||||
if (response && response.length) {
|
if (response && response.length) {
|
||||||
|
@@ -1,19 +1,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<div>
|
<div><%- i18n('settings', 'default-site') %></div>
|
||||||
<% if (id === 'default-site') { %>
|
|
||||||
<%- i18n('settings', 'default-site') %>
|
|
||||||
<% } %>
|
|
||||||
<% if (id === 'oidc-config') { %>
|
|
||||||
<%- i18n('settings', 'oidc-config') %>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
<% if (id === 'default-site') { %>
|
<%- i18n('settings', 'default-site-description') %>
|
||||||
<%- i18n('settings', 'default-site-description') %>
|
|
||||||
<% } %>
|
|
||||||
<% if (id === 'oidc-config') { %>
|
|
||||||
<%- i18n('settings', 'oidc-config-description') %>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -21,14 +9,6 @@
|
|||||||
<% if (id === 'default-site') { %>
|
<% if (id === 'default-site') { %>
|
||||||
<%- i18n('settings', 'default-site-' + value) %>
|
<%- i18n('settings', 'default-site-' + value) %>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% if (id === 'oidc-config' && meta && meta.name && meta.clientID && meta.clientSecret && meta.issuerURL && meta.redirectURL) { %>
|
|
||||||
<%- meta.name %>
|
|
||||||
<% if (!meta.enabled) { %>
|
|
||||||
(<%- i18n('str', 'disabled') %>)
|
|
||||||
<% } %>
|
|
||||||
<% } else if (id === 'oidc-config') { %>
|
|
||||||
<%- i18n('settings', 'oidc-not-configured') %>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title"><%- i18n('settings', id) %></h5>
|
|
||||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12">
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-label"><%- description %></div>
|
|
||||||
<div>
|
|
||||||
<p><%- i18n('settings', 'oidc-config-hint-1') %></p>
|
|
||||||
<p><%- i18n('settings', 'oidc-config-hint-2') %></p>
|
|
||||||
</div>
|
|
||||||
<div class="custom-controls-stacked">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label"><%- i18n('str', 'name') %> <span class="form-required">*</span>
|
|
||||||
<input class="form-control name-input" name="meta[name]" required type="text" value="<%- meta && typeof meta.name !== 'undefined' ? meta.name : '' %>">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">Client ID <span class="form-required">*</span>
|
|
||||||
<input class="form-control id-input" name="meta[clientID]" required type="text" value="<%- meta && typeof meta.clientID !== 'undefined' ? meta.clientID : '' %>">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">Client Secret <span class="form-required">*</span>
|
|
||||||
<input class="form-control secret-input" name="meta[clientSecret]" required type="text" value="<%- meta && typeof meta.clientSecret !== 'undefined' ? meta.clientSecret : '' %>">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">Issuer URL <span class="form-required">*</span>
|
|
||||||
<input class="form-control issuer-input" name="meta[issuerURL]" required placeholder="https://" type="url" value="<%- meta && typeof meta.issuerURL !== 'undefined' ? meta.issuerURL : '' %>">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">Redirect URL <span class="form-required">*</span>
|
|
||||||
<input class="form-control redirect-url-input" name="meta[redirectURL]" required placeholder="https://" type="url" value="<%- meta && typeof meta.redirectURL !== 'undefined' ? meta.redirectURL : document.location.origin + '/api/oidc/callback' %>">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-label"><%- i18n('str', 'enable') %></div>
|
|
||||||
<input class="form-check enabled-input" name="meta[enabled]" placeholder="" type="checkbox" <%- meta && (typeof meta.enabled !== 'undefined' && meta.enabled === true) || (JSON.stringify(meta) === '{}') ? 'checked="checked"' : '' %> >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
|
|
||||||
<button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@@ -1,46 +0,0 @@
|
|||||||
const Mn = require('backbone.marionette');
|
|
||||||
const App = require('../../main');
|
|
||||||
const template = require('./main.ejs');
|
|
||||||
|
|
||||||
require('jquery-serializejson');
|
|
||||||
|
|
||||||
module.exports = Mn.View.extend({
|
|
||||||
template: template,
|
|
||||||
className: 'modal-dialog wide',
|
|
||||||
|
|
||||||
ui: {
|
|
||||||
form: 'form',
|
|
||||||
buttons: '.modal-footer button',
|
|
||||||
cancel: 'button.cancel',
|
|
||||||
save: 'button.save',
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'click @ui.save': function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (!this.ui.form[0].checkValidity()) {
|
|
||||||
$('<input type="submit">').hide().appendTo(this.ui.form).click().remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let view = this;
|
|
||||||
let data = this.ui.form.serializeJSON();
|
|
||||||
data.id = this.model.get('id');
|
|
||||||
if (data.meta.enabled) {
|
|
||||||
data.meta.enabled = data.meta.enabled === 'on' || data.meta.enabled === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
|
|
||||||
App.Api.Settings.update(data)
|
|
||||||
.then((result) => {
|
|
||||||
view.model.set(result);
|
|
||||||
App.UI.closeModal();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
alert(err.message);
|
|
||||||
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@@ -5,7 +5,6 @@
|
|||||||
"username": "Username",
|
"username": "Username",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"sign-in": "Sign in",
|
"sign-in": "Sign in",
|
||||||
"sign-in-with": "Sign in with",
|
|
||||||
"sign-out": "Sign out",
|
"sign-out": "Sign out",
|
||||||
"try-again": "Try again",
|
"try-again": "Try again",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@@ -61,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"fork-me": "Fork me on Github",
|
"fork-me": "Fork me on Github",
|
||||||
"copy": "© 2024 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
|
"copy": "© 2025 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
|
||||||
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
|
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
@@ -180,7 +179,9 @@
|
|||||||
"delete-confirm": "Are you sure you want to delete this Stream?",
|
"delete-confirm": "Are you sure you want to delete this Stream?",
|
||||||
"help-title": "What is a Stream?",
|
"help-title": "What is a Stream?",
|
||||||
"help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.",
|
"help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.",
|
||||||
"search": "Search Incoming Port…"
|
"search": "Search Incoming Port…",
|
||||||
|
"ssl-certificate": "SSL Certificate for TCP Forwarding",
|
||||||
|
"tcp+ssl": "TCP+SSL"
|
||||||
},
|
},
|
||||||
"certificates": {
|
"certificates": {
|
||||||
"title": "SSL Certificates",
|
"title": "SSL Certificates",
|
||||||
@@ -207,7 +208,10 @@
|
|||||||
"reachability-other": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.",
|
"reachability-other": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"renew-title": "Renew Let's Encrypt Certificate",
|
"renew-title": "Renew Let's Encrypt Certificate",
|
||||||
"search": "Search Certificate…"
|
"search": "Search Certificate…",
|
||||||
|
"in-use" : "In use",
|
||||||
|
"inactive": "Inactive",
|
||||||
|
"active-domain_names": "Active domain names"
|
||||||
},
|
},
|
||||||
"access-lists": {
|
"access-lists": {
|
||||||
"title": "Access Lists",
|
"title": "Access Lists",
|
||||||
@@ -291,12 +295,7 @@
|
|||||||
"default-site-404": "404 Page",
|
"default-site-404": "404 Page",
|
||||||
"default-site-444": "No Response (444)",
|
"default-site-444": "No Response (444)",
|
||||||
"default-site-html": "Custom Page",
|
"default-site-html": "Custom Page",
|
||||||
"default-site-redirect": "Redirect",
|
"default-site-redirect": "Redirect"
|
||||||
"oidc-config": "Open ID Conncect Configuration",
|
|
||||||
"oidc-config-description": "Sign in to Nginx Proxy Manager with an external Identity Provider",
|
|
||||||
"oidc-not-configured": "Not configured",
|
|
||||||
"oidc-config-hint-1": "Provide configuration for an IdP that supports Open ID Connect Discovery.",
|
|
||||||
"oidc-config-hint-2": "The 'Redirect URL' must be set to '[base URL]/api/oidc/callback', the IdP must send the 'email' claim and a user with matching email address must exist in Nginx Proxy Manager."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<div class="card-body p-6">
|
<div class="card-body p-6">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-6 margin-auto">
|
<div class="col-sm-12 col-md-6">
|
||||||
<div class="text-center p-6">
|
<div class="text-center p-6">
|
||||||
<img src="/images/logo-text-vertical-grey.png" alt="Logo" />
|
<img src="/images/logo-text-vertical-grey.png" alt="Logo" />
|
||||||
<div class="text-center text-muted mt-5">
|
<div class="text-center text-muted mt-5">
|
||||||
@@ -17,22 +17,15 @@
|
|||||||
<div class="card-title"><%- i18n('login', 'title') %></div>
|
<div class="card-title"><%- i18n('login', 'title') %></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label"><%- i18n('str', 'email-address') %></label>
|
<label class="form-label"><%- i18n('str', 'email-address') %></label>
|
||||||
<input name="identity" type="email" class="form-control" placeholder="<%- i18n('str', 'email-address') %>" data-cy="identity" required autofocus>
|
<input name="identity" type="email" class="form-control" placeholder="<%- i18n('str', 'email-address') %>" required autofocus>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label"><%- i18n('str', 'password') %></label>
|
<label class="form-label"><%- i18n('str', 'password') %></label>
|
||||||
<input name="secret" type="password" class="form-control" placeholder="<%- i18n('str', 'password') %>" data-cy="password" required>
|
<input name="secret" type="password" class="form-control" placeholder="<%- i18n('str', 'password') %>" required>
|
||||||
<div class="invalid-feedback secret-error" data-cy="password-error"></div>
|
<div class="invalid-feedback secret-error"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-footer">
|
<div class="form-footer">
|
||||||
<button type="submit" class="btn btn-teal btn-block" data-cy="sign-in"><%- i18n('str', 'sign-in') %></button>
|
<button type="submit" class="btn btn-teal btn-block"><%- i18n('str', 'sign-in') %></button>
|
||||||
</div>
|
|
||||||
<div class="form-footer login-oidc">
|
|
||||||
<div class="separator"><slot>OR</slot></div>
|
|
||||||
<button type="button" id="login-oidc" class="btn btn-teal btn-block" data-cy="oidc-login">
|
|
||||||
<%- i18n('str', 'sign-in-with') %> <span class="oidc-provider"></span>
|
|
||||||
</button>
|
|
||||||
<div class="invalid-feedback oidc-error"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,22 +3,17 @@ const Mn = require('backbone.marionette');
|
|||||||
const template = require('./login.ejs');
|
const template = require('./login.ejs');
|
||||||
const Api = require('../../app/api');
|
const Api = require('../../app/api');
|
||||||
const i18n = require('../../app/i18n');
|
const i18n = require('../../app/i18n');
|
||||||
const Tokens = require('../../app/tokens');
|
|
||||||
|
|
||||||
module.exports = Mn.View.extend({
|
module.exports = Mn.View.extend({
|
||||||
template: template,
|
template: template,
|
||||||
className: 'page-single',
|
className: 'page-single',
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
form: 'form',
|
form: 'form',
|
||||||
identity: 'input[name="identity"]',
|
identity: 'input[name="identity"]',
|
||||||
secret: 'input[name="secret"]',
|
secret: 'input[name="secret"]',
|
||||||
error: '.secret-error',
|
error: '.secret-error',
|
||||||
button: 'button[type=submit]',
|
button: 'button'
|
||||||
oidcLogin: 'div.login-oidc',
|
|
||||||
oidcButton: 'button#login-oidc',
|
|
||||||
oidcError: '.oidc-error',
|
|
||||||
oidcProvider: 'span.oidc-provider'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
@@ -31,56 +26,10 @@ module.exports = Mn.View.extend({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
window.location = '/';
|
window.location = '/';
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(err => {
|
||||||
this.ui.error.text(err.message).show();
|
this.ui.error.text(err.message).show();
|
||||||
this.ui.button.removeClass('btn-loading').prop('disabled', false);
|
this.ui.button.removeClass('btn-loading').prop('disabled', false);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
'click @ui.oidcButton': function() {
|
|
||||||
this.ui.identity.prop('disabled', true);
|
|
||||||
this.ui.secret.prop('disabled', true);
|
|
||||||
this.ui.button.prop('disabled', true);
|
|
||||||
this.ui.oidcButton.addClass('btn-loading').prop('disabled', true);
|
|
||||||
// redirect to initiate oauth flow
|
|
||||||
document.location.replace('/api/oidc/');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
async onRender() {
|
|
||||||
// read oauth callback state cookies
|
|
||||||
let cookies = document.cookie.split(';'),
|
|
||||||
token, expiry, error;
|
|
||||||
for (cookie of cookies) {
|
|
||||||
let raw = cookie.split('='),
|
|
||||||
name = raw[0].trim(),
|
|
||||||
value = raw[1];
|
|
||||||
if (name === 'npm_oidc') {
|
|
||||||
let v = value.split('---');
|
|
||||||
token = v[0];
|
|
||||||
expiry = v[1];
|
|
||||||
}
|
|
||||||
if (name === 'npm_oidc_error') {
|
|
||||||
error = decodeURIComponent(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register a newly acquired jwt token following successful oidc authentication
|
|
||||||
if (token && expiry && (new Date(Date.parse(decodeURIComponent(expiry)))) > new Date() ) {
|
|
||||||
Tokens.addToken(token);
|
|
||||||
document.location.replace('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// show error message following a failed oidc authentication
|
|
||||||
if (error) {
|
|
||||||
this.ui.oidcError.html(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch oidc configuration and show alternative action button if enabled
|
|
||||||
let response = await Api.Settings.getById('oidc-config');
|
|
||||||
if (response && response.meta && response.meta.enabled === true) {
|
|
||||||
this.ui.oidcProvider.html(response.meta.name);
|
|
||||||
this.ui.oidcLogin.show();
|
|
||||||
this.ui.oidcError.show();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -15,8 +15,11 @@ const model = Backbone.Model.extend({
|
|||||||
udp_forwarding: false,
|
udp_forwarding: false,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
meta: {},
|
meta: {},
|
||||||
|
certificate_id: 0,
|
||||||
|
domain_names: [],
|
||||||
// The following are expansions:
|
// The following are expansions:
|
||||||
owner: null
|
owner: null,
|
||||||
|
certificate: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -39,34 +39,4 @@ a:hover {
|
|||||||
|
|
||||||
.col-login {
|
.col-login {
|
||||||
max-width: 48rem;
|
max-width: 48rem;
|
||||||
}
|
|
||||||
|
|
||||||
.margin-auto {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator::before, .separator::after {
|
|
||||||
content: "";
|
|
||||||
flex: 1 1 0%;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator:not(:empty)::before {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separator:not(:empty)::after {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-oidc {
|
|
||||||
display: none;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
@@ -167,4 +167,5 @@ $pink: #f66d9b;
|
|||||||
|
|
||||||
textarea.form-control.text-monospace {
|
textarea.form-control.text-monospace {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
@@ -907,6 +907,13 @@ atob@^2.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||||
|
|
||||||
|
available-typed-arrays@^1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
|
||||||
|
integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
|
||||||
|
dependencies:
|
||||||
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
babel-code-frame@^6.26.0:
|
babel-code-frame@^6.26.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||||
@@ -1790,6 +1797,32 @@ cacheable-request@^6.0.0:
|
|||||||
normalize-url "^4.1.0"
|
normalize-url "^4.1.0"
|
||||||
responselike "^1.0.2"
|
responselike "^1.0.2"
|
||||||
|
|
||||||
|
call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
|
||||||
|
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
|
||||||
|
call-bind@^1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
|
||||||
|
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.0"
|
||||||
|
es-define-property "^1.0.0"
|
||||||
|
get-intrinsic "^1.2.4"
|
||||||
|
set-function-length "^1.2.2"
|
||||||
|
|
||||||
|
call-bound@^1.0.3, call-bound@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
|
||||||
|
integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.2"
|
||||||
|
get-intrinsic "^1.3.0"
|
||||||
|
|
||||||
callsites@^3.0.0:
|
callsites@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||||
@@ -2232,7 +2265,7 @@ create-ecdh@^4.0.0:
|
|||||||
bn.js "^4.1.0"
|
bn.js "^4.1.0"
|
||||||
elliptic "^6.5.3"
|
elliptic "^6.5.3"
|
||||||
|
|
||||||
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
|
create-hash@^1.1.0, create-hash@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
|
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
|
||||||
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
|
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
|
||||||
@@ -2243,7 +2276,17 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
|
|||||||
ripemd160 "^2.0.1"
|
ripemd160 "^2.0.1"
|
||||||
sha.js "^2.4.0"
|
sha.js "^2.4.0"
|
||||||
|
|
||||||
create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
|
create-hash@~1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
|
||||||
|
integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==
|
||||||
|
dependencies:
|
||||||
|
cipher-base "^1.0.1"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
ripemd160 "^2.0.0"
|
||||||
|
sha.js "^2.4.0"
|
||||||
|
|
||||||
|
create-hmac@^1.1.0, create-hmac@^1.1.7:
|
||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
|
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
|
||||||
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
|
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
|
||||||
@@ -2414,6 +2457,15 @@ defer-to-connect@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
|
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
|
||||||
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
|
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
|
||||||
|
|
||||||
|
define-data-property@^1.1.4:
|
||||||
|
version "1.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
|
||||||
|
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
|
||||||
|
dependencies:
|
||||||
|
es-define-property "^1.0.0"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
gopd "^1.0.1"
|
||||||
|
|
||||||
define-properties@^1.1.2, define-properties@^1.1.3:
|
define-properties@^1.1.2, define-properties@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||||
@@ -2579,6 +2631,15 @@ dot-prop@^5.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-obj "^2.0.0"
|
is-obj "^2.0.0"
|
||||||
|
|
||||||
|
dunder-proto@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
||||||
|
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.1"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
gopd "^1.2.0"
|
||||||
|
|
||||||
duplexer3@^0.1.4:
|
duplexer3@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||||
@@ -2648,9 +2709,9 @@ electron-to-chromium@^1.3.47:
|
|||||||
integrity sha512-67V62Z4CFOiAtox+o+tosGfVk0QX4DJgH609tjT8QymbJZVAI/jWnAthnr8c5hnRNziIRwkc9EMQYejiVz3/9Q==
|
integrity sha512-67V62Z4CFOiAtox+o+tosGfVk0QX4DJgH609tjT8QymbJZVAI/jWnAthnr8c5hnRNziIRwkc9EMQYejiVz3/9Q==
|
||||||
|
|
||||||
elliptic@^6.5.3, elliptic@^6.5.4:
|
elliptic@^6.5.3, elliptic@^6.5.4:
|
||||||
version "6.6.0"
|
version "6.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
|
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06"
|
||||||
integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
|
integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==
|
||||||
dependencies:
|
dependencies:
|
||||||
bn.js "^4.11.9"
|
bn.js "^4.11.9"
|
||||||
brorand "^1.1.0"
|
brorand "^1.1.0"
|
||||||
@@ -2762,6 +2823,23 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
|
|||||||
string.prototype.trimend "^1.0.1"
|
string.prototype.trimend "^1.0.1"
|
||||||
string.prototype.trimstart "^1.0.1"
|
string.prototype.trimstart "^1.0.1"
|
||||||
|
|
||||||
|
es-define-property@^1.0.0, es-define-property@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
|
||||||
|
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
||||||
|
|
||||||
|
es-errors@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||||
|
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||||
|
|
||||||
|
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
|
||||||
|
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
|
||||||
|
dependencies:
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
|
||||||
es-to-primitive@^1.2.1:
|
es-to-primitive@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||||
@@ -3131,6 +3209,13 @@ flush-write-stream@^1.0.0:
|
|||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
|
for-each@^0.3.5:
|
||||||
|
version "0.3.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47"
|
||||||
|
integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==
|
||||||
|
dependencies:
|
||||||
|
is-callable "^1.2.7"
|
||||||
|
|
||||||
for-in@^1.0.2:
|
for-in@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||||
@@ -3191,6 +3276,11 @@ function-bind@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||||
|
|
||||||
|
function-bind@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||||
|
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||||
|
|
||||||
functional-red-black-tree@^1.0.1:
|
functional-red-black-tree@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
||||||
@@ -3227,6 +3317,30 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
|||||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||||
|
|
||||||
|
get-intrinsic@^1.2.4, get-intrinsic@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
|
||||||
|
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
|
||||||
|
dependencies:
|
||||||
|
call-bind-apply-helpers "^1.0.2"
|
||||||
|
es-define-property "^1.0.1"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
es-object-atoms "^1.1.1"
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
get-proto "^1.0.1"
|
||||||
|
gopd "^1.2.0"
|
||||||
|
has-symbols "^1.1.0"
|
||||||
|
hasown "^2.0.2"
|
||||||
|
math-intrinsics "^1.1.0"
|
||||||
|
|
||||||
|
get-proto@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
|
||||||
|
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
|
||||||
|
dependencies:
|
||||||
|
dunder-proto "^1.0.1"
|
||||||
|
es-object-atoms "^1.0.0"
|
||||||
|
|
||||||
get-stdin@^4.0.1:
|
get-stdin@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||||
@@ -3393,6 +3507,11 @@ globule@^1.0.0:
|
|||||||
lodash "~4.17.10"
|
lodash "~4.17.10"
|
||||||
minimatch "~3.0.2"
|
minimatch "~3.0.2"
|
||||||
|
|
||||||
|
gopd@^1.0.1, gopd@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
|
||||||
|
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
||||||
|
|
||||||
got@^9.6.0:
|
got@^9.6.0:
|
||||||
version "9.6.0"
|
version "9.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
|
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
|
||||||
@@ -3442,11 +3561,30 @@ has-flag@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
||||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||||
|
|
||||||
|
has-property-descriptors@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
|
||||||
|
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
|
||||||
|
dependencies:
|
||||||
|
es-define-property "^1.0.0"
|
||||||
|
|
||||||
has-symbols@^1.0.0, has-symbols@^1.0.1:
|
has-symbols@^1.0.0, has-symbols@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
|
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
|
||||||
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
|
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
|
||||||
|
|
||||||
|
has-symbols@^1.0.3, has-symbols@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
|
||||||
|
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
|
||||||
|
|
||||||
|
has-tostringtag@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
||||||
|
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
|
||||||
|
dependencies:
|
||||||
|
has-symbols "^1.0.3"
|
||||||
|
|
||||||
has-unicode@^2.0.1:
|
has-unicode@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||||
@@ -3495,6 +3633,13 @@ has@^1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind "^1.1.1"
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
|
hash-base@^2.0.0:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
|
||||||
|
integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==
|
||||||
|
dependencies:
|
||||||
|
inherits "^2.0.1"
|
||||||
|
|
||||||
hash-base@^3.0.0:
|
hash-base@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
|
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
|
||||||
@@ -3512,6 +3657,13 @@ hash.js@^1.0.0, hash.js@^1.0.3:
|
|||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
minimalistic-assert "^1.0.1"
|
minimalistic-assert "^1.0.1"
|
||||||
|
|
||||||
|
hasown@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||||
|
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||||
|
dependencies:
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
|
||||||
he@1.2.x, he@^1.2.0:
|
he@1.2.x, he@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
@@ -3856,6 +4008,11 @@ is-callable@^1.1.4, is-callable@^1.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
|
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
|
||||||
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
|
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
|
||||||
|
|
||||||
|
is-callable@^1.2.7:
|
||||||
|
version "1.2.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
|
||||||
|
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
|
||||||
|
|
||||||
is-ci@^2.0.0:
|
is-ci@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
|
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
|
||||||
@@ -4019,6 +4176,13 @@ is-symbol@^1.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols "^1.0.1"
|
has-symbols "^1.0.1"
|
||||||
|
|
||||||
|
is-typed-array@^1.1.14:
|
||||||
|
version "1.1.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b"
|
||||||
|
integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==
|
||||||
|
dependencies:
|
||||||
|
which-typed-array "^1.1.16"
|
||||||
|
|
||||||
is-typedarray@^1.0.0:
|
is-typedarray@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||||
@@ -4044,6 +4208,11 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||||
|
|
||||||
|
isarray@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
|
||||||
|
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
|
||||||
|
|
||||||
isexe@^2.0.0:
|
isexe@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||||
@@ -4436,6 +4605,11 @@ marionette.templatecache@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
backbone.marionette "^4.0.0, 4.0.0-beta.1"
|
backbone.marionette "^4.0.0, 4.0.0-beta.1"
|
||||||
|
|
||||||
|
math-intrinsics@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||||
|
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
||||||
|
|
||||||
md5.js@^1.3.4:
|
md5.js@^1.3.4:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||||
@@ -5289,15 +5463,16 @@ path-type@^4.0.0:
|
|||||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||||
|
|
||||||
pbkdf2@^3.0.3:
|
pbkdf2@^3.0.3:
|
||||||
version "3.1.1"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
|
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b"
|
||||||
integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==
|
integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==
|
||||||
dependencies:
|
dependencies:
|
||||||
create-hash "^1.1.2"
|
create-hash "~1.1.3"
|
||||||
create-hmac "^1.1.4"
|
create-hmac "^1.1.7"
|
||||||
ripemd160 "^2.0.1"
|
ripemd160 "=2.0.1"
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.2.1"
|
||||||
sha.js "^2.4.8"
|
sha.js "^2.4.11"
|
||||||
|
to-buffer "^1.2.0"
|
||||||
|
|
||||||
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
|
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
@@ -5326,6 +5501,11 @@ posix-character-classes@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||||
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
||||||
|
|
||||||
|
possible-typed-array-names@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae"
|
||||||
|
integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==
|
||||||
|
|
||||||
postcss-modules-extract-imports@^2.0.0:
|
postcss-modules-extract-imports@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
|
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
|
||||||
@@ -5886,6 +6066,14 @@ rimraf@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
|
ripemd160@=2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
|
||||||
|
integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==
|
||||||
|
dependencies:
|
||||||
|
hash-base "^2.0.0"
|
||||||
|
inherits "^2.0.1"
|
||||||
|
|
||||||
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
||||||
@@ -6037,6 +6225,18 @@ set-blocking@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||||
|
|
||||||
|
set-function-length@^1.2.2:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||||
|
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||||
|
dependencies:
|
||||||
|
define-data-property "^1.1.4"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
function-bind "^1.1.2"
|
||||||
|
get-intrinsic "^1.2.4"
|
||||||
|
gopd "^1.0.1"
|
||||||
|
has-property-descriptors "^1.0.2"
|
||||||
|
|
||||||
set-value@^2.0.0, set-value@^2.0.1:
|
set-value@^2.0.0, set-value@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
||||||
@@ -6052,7 +6252,7 @@ setimmediate@^1.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||||
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
||||||
|
|
||||||
sha.js@^2.4.0, sha.js@^2.4.8:
|
sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
|
||||||
version "2.4.11"
|
version "2.4.11"
|
||||||
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
||||||
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
|
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
|
||||||
@@ -6592,6 +6792,15 @@ to-arraybuffer@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||||
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
||||||
|
|
||||||
|
to-buffer@^1.2.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0"
|
||||||
|
integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==
|
||||||
|
dependencies:
|
||||||
|
isarray "^2.0.5"
|
||||||
|
safe-buffer "^5.2.1"
|
||||||
|
typed-array-buffer "^1.0.3"
|
||||||
|
|
||||||
to-fast-properties@^1.0.3:
|
to-fast-properties@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||||
@@ -6698,6 +6907,15 @@ type-fest@^0.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||||
|
|
||||||
|
typed-array-buffer@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536"
|
||||||
|
integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==
|
||||||
|
dependencies:
|
||||||
|
call-bound "^1.0.3"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
is-typed-array "^1.1.14"
|
||||||
|
|
||||||
typedarray-to-buffer@^3.1.5:
|
typedarray-to-buffer@^3.1.5:
|
||||||
version "3.1.5"
|
version "3.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||||
@@ -7024,6 +7242,19 @@ which-module@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
||||||
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
|
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
|
||||||
|
|
||||||
|
which-typed-array@^1.1.16:
|
||||||
|
version "1.1.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956"
|
||||||
|
integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==
|
||||||
|
dependencies:
|
||||||
|
available-typed-arrays "^1.0.7"
|
||||||
|
call-bind "^1.0.8"
|
||||||
|
call-bound "^1.0.4"
|
||||||
|
for-each "^0.3.5"
|
||||||
|
get-proto "^1.0.1"
|
||||||
|
gopd "^1.2.0"
|
||||||
|
has-tostringtag "^1.0.2"
|
||||||
|
|
||||||
which@^1.2.14, which@^1.2.9, which@^1.3.1:
|
which@^1.2.14, which@^1.2.9, which@^1.3.1:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||||
|
@@ -7,18 +7,18 @@
|
|||||||
"credentials": "dns_acmedns_api_url = http://acmedns-server/\ndns_acmedns_registration_file = /data/acme-registration.json",
|
"credentials": "dns_acmedns_api_url = http://acmedns-server/\ndns_acmedns_registration_file = /data/acme-registration.json",
|
||||||
"full_plugin_name": "dns-acmedns"
|
"full_plugin_name": "dns-acmedns"
|
||||||
},
|
},
|
||||||
"active24":{
|
"active24": {
|
||||||
"name": "Active24",
|
"name": "Active24",
|
||||||
"package_name": "certbot-dns-active24",
|
"package_name": "certbot-dns-active24",
|
||||||
"version": "~=1.5.1",
|
"version": "~=2.0.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_active24_token=\"TOKEN\"",
|
"credentials": "dns_active24_api_key = <identifier>\ndns_active24_secret = <secret>",
|
||||||
"full_plugin_name": "dns-active24"
|
"full_plugin_name": "dns-active24"
|
||||||
},
|
},
|
||||||
"aliyun": {
|
"aliyun": {
|
||||||
"name": "Aliyun",
|
"name": "Aliyun",
|
||||||
"package_name": "certbot-dns-aliyun",
|
"package_name": "certbot-dns-aliyun",
|
||||||
"version": "~=0.38.1",
|
"version": "~=2.0.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef",
|
"credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef",
|
||||||
"full_plugin_name": "dns-aliyun"
|
"full_plugin_name": "dns-aliyun"
|
||||||
@@ -31,6 +31,22 @@
|
|||||||
"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
|
"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
|
||||||
"full_plugin_name": "dns-azure"
|
"full_plugin_name": "dns-azure"
|
||||||
},
|
},
|
||||||
|
"baidu": {
|
||||||
|
"name": "baidu",
|
||||||
|
"package_name": "certbot-dns-baidu",
|
||||||
|
"version": "~=0.1.1",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_baidu_access_key = 12345678\ndns_baidu_secret_key = 1234567890abcdef1234567890abcdef",
|
||||||
|
"full_plugin_name": "dns-baidu"
|
||||||
|
},
|
||||||
|
"beget": {
|
||||||
|
"name":"Beget",
|
||||||
|
"package_name": "certbot-beget-plugin",
|
||||||
|
"version": "~=1.0.0.dev9",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "# Beget API credentials used by Certbot\nbeget_plugin_username = username\nbeget_plugin_password = password",
|
||||||
|
"full_plugin_name": "beget-plugin"
|
||||||
|
},
|
||||||
"bunny": {
|
"bunny": {
|
||||||
"name": "bunny.net",
|
"name": "bunny.net",
|
||||||
"package_name": "certbot-dns-bunny",
|
"package_name": "certbot-dns-bunny",
|
||||||
@@ -39,11 +55,19 @@
|
|||||||
"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
|
"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
|
||||||
"full_plugin_name": "dns-bunny"
|
"full_plugin_name": "dns-bunny"
|
||||||
},
|
},
|
||||||
|
"cdmon": {
|
||||||
|
"name": "cdmon",
|
||||||
|
"package_name": "certbot-dns-cdmon",
|
||||||
|
"version": "~=0.4.1",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_cdmon_api_key=your-cdmon-api-token\ndns_cdmon_domain=your_domain_is_optional",
|
||||||
|
"full_plugin_name": "dns-cdmon"
|
||||||
|
},
|
||||||
"cloudflare": {
|
"cloudflare": {
|
||||||
"name": "Cloudflare",
|
"name": "Cloudflare",
|
||||||
"package_name": "certbot-dns-cloudflare",
|
"package_name": "certbot-dns-cloudflare",
|
||||||
"version": "=={{certbot-version}}",
|
"version": "=={{certbot-version}}",
|
||||||
"dependencies": "cloudflare==2.19.* acme=={{certbot-version}}",
|
"dependencies": "acme=={{certbot-version}}",
|
||||||
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567",
|
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567",
|
||||||
"full_plugin_name": "dns-cloudflare"
|
"full_plugin_name": "dns-cloudflare"
|
||||||
},
|
},
|
||||||
@@ -82,11 +106,19 @@
|
|||||||
"cpanel": {
|
"cpanel": {
|
||||||
"name": "cPanel",
|
"name": "cPanel",
|
||||||
"package_name": "certbot-dns-cpanel",
|
"package_name": "certbot-dns-cpanel",
|
||||||
"version": "~=0.2.2",
|
"version": "~=0.4.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = user\ncpanel_password = hunter2",
|
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = your_username\ncpanel_password = your_password\ncpanel_token = your_api_token",
|
||||||
"full_plugin_name": "cpanel"
|
"full_plugin_name": "cpanel"
|
||||||
},
|
},
|
||||||
|
"ddnss": {
|
||||||
|
"name": "DDNSS",
|
||||||
|
"package_name": "certbot-dns-ddnss",
|
||||||
|
"version": "~=1.1.0",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_ddnss_token = YOUR_DDNSS_API_TOKEN",
|
||||||
|
"full_plugin_name": "dns-ddnss"
|
||||||
|
},
|
||||||
"desec": {
|
"desec": {
|
||||||
"name": "deSEC",
|
"name": "deSEC",
|
||||||
"package_name": "certbot-dns-desec",
|
"package_name": "certbot-dns-desec",
|
||||||
@@ -153,11 +185,11 @@
|
|||||||
},
|
},
|
||||||
"domainoffensive": {
|
"domainoffensive": {
|
||||||
"name": "DomainOffensive (do.de)",
|
"name": "DomainOffensive (do.de)",
|
||||||
"package_name": "certbot-dns-do",
|
"package_name": "certbot-dns-domainoffensive",
|
||||||
"version": "~=0.31.0",
|
"version": "~=2.0.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
"credentials": "dns_domainoffensive_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
||||||
"full_plugin_name": "dns-do"
|
"full_plugin_name": "dns-domainoffensive"
|
||||||
},
|
},
|
||||||
"domeneshop": {
|
"domeneshop": {
|
||||||
"name": "Domeneshop",
|
"name": "Domeneshop",
|
||||||
@@ -191,6 +223,14 @@
|
|||||||
"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
|
"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
|
||||||
"full_plugin_name": "dns-eurodns"
|
"full_plugin_name": "dns-eurodns"
|
||||||
},
|
},
|
||||||
|
"firstdomains": {
|
||||||
|
"name": "First Domains",
|
||||||
|
"package_name": "certbot-dns-firstdomains",
|
||||||
|
"version": ">=1.0",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_firstdomains_username = myremoteuser\ndns_firstdomains_password = verysecureremoteuserpassword",
|
||||||
|
"full_plugin_name": "dns-firstdomains"
|
||||||
|
},
|
||||||
"freedns": {
|
"freedns": {
|
||||||
"name": "FreeDNS",
|
"name": "FreeDNS",
|
||||||
"package_name": "certbot-dns-freedns",
|
"package_name": "certbot-dns-freedns",
|
||||||
@@ -201,12 +241,20 @@
|
|||||||
},
|
},
|
||||||
"gandi": {
|
"gandi": {
|
||||||
"name": "Gandi Live DNS",
|
"name": "Gandi Live DNS",
|
||||||
"package_name": "certbot_plugin_gandi",
|
"package_name": "certbot-dns-gandi",
|
||||||
"version": "~=1.5.0",
|
"version": "~=1.6.1",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
|
"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
|
||||||
"full_plugin_name": "dns-gandi"
|
"full_plugin_name": "dns-gandi"
|
||||||
},
|
},
|
||||||
|
"gcore": {
|
||||||
|
"name": "Gcore DNS",
|
||||||
|
"package_name": "certbot-dns-gcore",
|
||||||
|
"version": "~=0.1.8",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_gcore_apitoken = 0123456789abcdef0123456789abcdef01234567",
|
||||||
|
"full_plugin_name": "dns-gcore"
|
||||||
|
},
|
||||||
"godaddy": {
|
"godaddy": {
|
||||||
"name": "GoDaddy",
|
"name": "GoDaddy",
|
||||||
"package_name": "certbot-dns-godaddy",
|
"package_name": "certbot-dns-godaddy",
|
||||||
@@ -247,6 +295,14 @@
|
|||||||
"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
|
"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
|
||||||
"full_plugin_name": "dns-hetzner"
|
"full_plugin_name": "dns-hetzner"
|
||||||
},
|
},
|
||||||
|
"hostingnl": {
|
||||||
|
"name": "Hosting.nl",
|
||||||
|
"package_name": "certbot-dns-hostingnl",
|
||||||
|
"version": "~=0.1.5",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_hostingnl_api_key = 0123456789abcdef0123456789abcdef",
|
||||||
|
"full_plugin_name": "dns-hostingnl"
|
||||||
|
},
|
||||||
"hover": {
|
"hover": {
|
||||||
"name": "Hover",
|
"name": "Hover",
|
||||||
"package_name": "certbot-dns-hover",
|
"package_name": "certbot-dns-hover",
|
||||||
@@ -340,7 +396,7 @@
|
|||||||
"package_name": "certbot-dns-mijn-host",
|
"package_name": "certbot-dns-mijn-host",
|
||||||
"version": "~=0.0.4",
|
"version": "~=0.0.4",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns-mijn-host-credentials = /etc/letsencrypt/mijnhost-credentials.ini",
|
"credentials": "dns_mijn_host_api_key=0123456789abcdef0123456789abcdef",
|
||||||
"full_plugin_name": "dns-mijn-host"
|
"full_plugin_name": "dns-mijn-host"
|
||||||
},
|
},
|
||||||
"namecheap": {
|
"namecheap": {
|
||||||
@@ -359,6 +415,14 @@
|
|||||||
"credentials": "dns_netcup_customer_id = 123456\ndns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
|
"credentials": "dns_netcup_customer_id = 123456\ndns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
|
||||||
"full_plugin_name": "dns-netcup"
|
"full_plugin_name": "dns-netcup"
|
||||||
},
|
},
|
||||||
|
"nicru": {
|
||||||
|
"name": "nic.ru",
|
||||||
|
"package_name": "certbot-dns-nicru",
|
||||||
|
"version": "~=1.0.3",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_nicru_client_id = application-id\ndns_nicru_client_secret = application-token\ndns_nicru_username = 0001110/NIC-D\ndns_nicru_password = password\ndns_nicru_scope = .+:.+/zones/example.com(/.+)?\ndns_nicru_service = DNS_SERVICE_NAME\ndns_nicru_zone = example.com",
|
||||||
|
"full_plugin_name": "dns-nicru"
|
||||||
|
},
|
||||||
"njalla": {
|
"njalla": {
|
||||||
"name": "Njalla",
|
"name": "Njalla",
|
||||||
"package_name": "certbot-dns-njalla",
|
"package_name": "certbot-dns-njalla",
|
||||||
@@ -402,7 +466,7 @@
|
|||||||
"porkbun": {
|
"porkbun": {
|
||||||
"name": "Porkbun",
|
"name": "Porkbun",
|
||||||
"package_name": "certbot-dns-porkbun",
|
"package_name": "certbot-dns-porkbun",
|
||||||
"version": "~=0.2",
|
"version": "~=0.9",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_porkbun_key=your-porkbun-api-key\ndns_porkbun_secret=your-porkbun-api-secret",
|
"credentials": "dns_porkbun_key=your-porkbun-api-key\ndns_porkbun_secret=your-porkbun-api-secret",
|
||||||
"full_plugin_name": "dns-porkbun"
|
"full_plugin_name": "dns-porkbun"
|
||||||
@@ -447,14 +511,30 @@
|
|||||||
"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||||
"full_plugin_name": "dns-route53"
|
"full_plugin_name": "dns-route53"
|
||||||
},
|
},
|
||||||
|
"spaceship": {
|
||||||
|
"name": "Spaceship",
|
||||||
|
"package_name": "certbot-dns-spaceship",
|
||||||
|
"version": "~=1.0.4",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "[spaceship]\napi_key=your_api_key\napi_secret=your_api_secret",
|
||||||
|
"full_plugin_name": "dns-spaceship"
|
||||||
|
},
|
||||||
"strato": {
|
"strato": {
|
||||||
"name": "Strato",
|
"name": "Strato",
|
||||||
"package_name": "certbot-dns-strato",
|
"package_name": "certbot-dns-strato",
|
||||||
"version": "~=0.2.1",
|
"version": "~=0.2.2",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
|
"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
|
||||||
"full_plugin_name": "dns-strato"
|
"full_plugin_name": "dns-strato"
|
||||||
},
|
},
|
||||||
|
"selectelv2": {
|
||||||
|
"name": "Selectel api v2",
|
||||||
|
"package_name": "certbot-dns-selectel-api-v2",
|
||||||
|
"version": "~=0.3.0",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_selectel_api_v2_account_id = your_account_id\ndns_selectel_api_v2_project_name = your_project\ndns_selectel_api_v2_username = your_username\ndns_selectel_api_v2_password = your_password",
|
||||||
|
"full_plugin_name": "dns-selectel-api-v2"
|
||||||
|
},
|
||||||
"timeweb": {
|
"timeweb": {
|
||||||
"name": "Timeweb Cloud",
|
"name": "Timeweb Cloud",
|
||||||
"package_name": "certbot-dns-timeweb",
|
"package_name": "certbot-dns-timeweb",
|
||||||
@@ -495,7 +575,7 @@
|
|||||||
"credentials": "dns_websupport_identifier = <api_key>\ndns_websupport_secret_key = <secret>",
|
"credentials": "dns_websupport_identifier = <api_key>\ndns_websupport_secret_key = <secret>",
|
||||||
"full_plugin_name": "dns-websupport"
|
"full_plugin_name": "dns-websupport"
|
||||||
},
|
},
|
||||||
"wedos":{
|
"wedos": {
|
||||||
"name": "Wedos",
|
"name": "Wedos",
|
||||||
"package_name": "certbot-dns-wedos",
|
"package_name": "certbot-dns-wedos",
|
||||||
"version": "~=2.2",
|
"version": "~=2.2",
|
||||||
@@ -510,5 +590,13 @@
|
|||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "edgedns_client_secret = as3d1asd5d1a32sdfsdfs2d1asd5=\nedgedns_host = sdflskjdf-dfsdfsdf-sdfsdfsdf.luna.akamaiapis.net\nedgedns_access_token = kjdsi3-34rfsdfsdf-234234fsdfsdf\nedgedns_client_token = dkfjdf-342fsdfsd-23fsdfsdfsdf",
|
"credentials": "edgedns_client_secret = as3d1asd5d1a32sdfsdfs2d1asd5=\nedgedns_host = sdflskjdf-dfsdfsdf-sdfsdfsdf.luna.akamaiapis.net\nedgedns_access_token = kjdsi3-34rfsdfsdf-234234fsdfsdf\nedgedns_client_token = dkfjdf-342fsdfsd-23fsdfsdfsdf",
|
||||||
"full_plugin_name": "edgedns"
|
"full_plugin_name": "edgedns"
|
||||||
}
|
},
|
||||||
|
"zoneedit": {
|
||||||
|
"name": "ZoneEdit",
|
||||||
|
"package_name": "certbot-dns-zoneedit",
|
||||||
|
"version": "~=0.3.2",
|
||||||
|
"dependencies": "--no-deps dnspython",
|
||||||
|
"credentials": "dns_zoneedit_user = <login-user-id>\ndns_zoneedit_token = <dyn-authentication-token>",
|
||||||
|
"full_plugin_name": "dns-zoneedit"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ YELLOW='\E[1;33m'
|
|||||||
export BLUE CYAN GREEN RED RESET YELLOW
|
export BLUE CYAN GREEN RED RESET YELLOW
|
||||||
|
|
||||||
# Docker Compose
|
# Docker Compose
|
||||||
COMPOSE_PROJECT_NAME="npmdev"
|
COMPOSE_PROJECT_NAME="npm2dev"
|
||||||
COMPOSE_FILE="docker/docker-compose.dev.yml"
|
COMPOSE_FILE="docker/docker-compose.dev.yml"
|
||||||
|
|
||||||
export COMPOSE_FILE COMPOSE_PROJECT_NAME
|
export COMPOSE_FILE COMPOSE_PROJECT_NAME
|
||||||
|
@@ -67,6 +67,8 @@ printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}"
|
|||||||
# bring up all remaining containers, except cypress!
|
# bring up all remaining containers, except cypress!
|
||||||
docker-compose up -d --remove-orphans stepca squid
|
docker-compose up -d --remove-orphans stepca squid
|
||||||
docker-compose pull db-mysql || true # ok to fail
|
docker-compose pull db-mysql || true # ok to fail
|
||||||
|
docker-compose pull db-postgres || true # ok to fail
|
||||||
|
docker-compose pull authentik authentik-redis authentik-ldap || true # ok to fail
|
||||||
docker-compose up -d --remove-orphans --pull=never fullstack
|
docker-compose up -d --remove-orphans --pull=never fullstack
|
||||||
|
|
||||||
# wait for main container to be healthy
|
# wait for main container to be healthy
|
||||||
|
@@ -36,12 +36,11 @@ if hash docker-compose 2>/dev/null; then
|
|||||||
|
|
||||||
# bring up all remaining containers, except cypress!
|
# bring up all remaining containers, except cypress!
|
||||||
docker-compose up -d --remove-orphans stepca squid
|
docker-compose up -d --remove-orphans stepca squid
|
||||||
docker-compose pull db
|
docker-compose pull db db-postgres authentik-redis authentik authentik-worker authentik-ldap
|
||||||
docker-compose up -d --remove-orphans --pull=never fullstack
|
docker-compose build --pull --parallel fullstack
|
||||||
|
docker-compose up -d --remove-orphans fullstack
|
||||||
docker-compose up -d --remove-orphans swagger
|
docker-compose up -d --remove-orphans swagger
|
||||||
|
|
||||||
# docker-compose up -d --remove-orphans --force-recreate --build
|
|
||||||
|
|
||||||
# wait for main container to be healthy
|
# wait for main container to be healthy
|
||||||
bash "$DIR/wait-healthy" "$(docker-compose ps --all -q fullstack)" 120
|
bash "$DIR/wait-healthy" "$(docker-compose ps --all -q fullstack)" 120
|
||||||
|
|
||||||
@@ -53,10 +52,10 @@ if hash docker-compose 2>/dev/null; then
|
|||||||
|
|
||||||
if [ "$1" == "-f" ]; then
|
if [ "$1" == "-f" ]; then
|
||||||
echo -e "${BLUE}❯ ${YELLOW}Following Backend Container:${RESET}"
|
echo -e "${BLUE}❯ ${YELLOW}Following Backend Container:${RESET}"
|
||||||
docker logs -f npm_core
|
docker logs -f npm2dev.core
|
||||||
else
|
else
|
||||||
echo -e "${YELLOW}Hint:${RESET} You can follow the output of some of the containers with:"
|
echo -e "${YELLOW}Hint:${RESET} You can follow the output of some of the containers with:"
|
||||||
echo " docker logs -f npm_core"
|
echo " docker logs -f npm2dev.core"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${RED}❯ docker-compose command is not available${RESET}"
|
echo -e "${RED}❯ docker-compose command is not available${RESET}"
|
||||||
|
@@ -1,11 +1,22 @@
|
|||||||
FROM cypress/included:13.9.0
|
FROM cypress/included:14.0.1
|
||||||
|
|
||||||
COPY --chown=1000 ./test /test
|
|
||||||
|
|
||||||
# Disable Cypress CLI colors
|
# Disable Cypress CLI colors
|
||||||
ENV FORCE_COLOR=0
|
ENV FORCE_COLOR=0
|
||||||
ENV NO_COLOR=1
|
ENV NO_COLOR=1
|
||||||
|
|
||||||
|
# testssl.sh and mkcert
|
||||||
|
RUN wget "https://github.com/testssl/testssl.sh/archive/refs/tags/v3.2rc4.tar.gz" -O /tmp/testssl.tgz -q \
|
||||||
|
&& tar -xzf /tmp/testssl.tgz -C /tmp \
|
||||||
|
&& mv /tmp/testssl.sh-3.2rc4 /testssl \
|
||||||
|
&& rm /tmp/testssl.tgz \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y bsdmainutils curl dnsutils \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& wget "https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64" -O /bin/mkcert \
|
||||||
|
&& chmod +x /bin/mkcert
|
||||||
|
|
||||||
|
COPY --chown=1000 ./test /test
|
||||||
WORKDIR /test
|
WORKDIR /test
|
||||||
RUN yarn install && yarn cache clean
|
RUN yarn install && yarn cache clean
|
||||||
ENTRYPOINT []
|
ENTRYPOINT []
|
||||||
|
@@ -10,7 +10,7 @@ describe('Certificates endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Validate custom certificate', function() {
|
it('Validate custom certificate', () => {
|
||||||
cy.task('backendApiPostFiles', {
|
cy.task('backendApiPostFiles', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/nginx/certificates/validate',
|
path: '/api/nginx/certificates/validate',
|
||||||
@@ -25,7 +25,7 @@ describe('Certificates endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Custom certificate lifecycle', function() {
|
it('Custom certificate lifecycle', () => {
|
||||||
// Create custom cert
|
// Create custom cert
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
@@ -73,7 +73,7 @@ describe('Certificates endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
|
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', () => {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/nginx/certificates',
|
path: '/api/nginx/certificates',
|
||||||
|
25
test/cypress/e2e/api/Dashboard.cy.js
Normal file
25
test/cypress/e2e/api/Dashboard.cy.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
describe('Dashboard endpoints', () => {
|
||||||
|
let token;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
cy.getToken().then((tok) => {
|
||||||
|
token = tok;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should be able to get host counts', () => {
|
||||||
|
cy.task('backendApiGet', {
|
||||||
|
token: token,
|
||||||
|
path: '/api/reports/hosts'
|
||||||
|
}).then((data) => {
|
||||||
|
cy.validateSwaggerSchema('get', 200, '/reports/hosts', data);
|
||||||
|
expect(data).to.have.property('dead');
|
||||||
|
expect(data).to.have.property('proxy');
|
||||||
|
expect(data).to.have.property('redirection');
|
||||||
|
expect(data).to.have.property('stream');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@@ -9,7 +9,7 @@ describe('Full Certificate Provisions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to create new http certificate', function() {
|
it('Should be able to create new http certificate', () => {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/nginx/certificates',
|
path: '/api/nginx/certificates',
|
||||||
@@ -32,7 +32,7 @@ describe('Full Certificate Provisions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to create new DNS certificate with Powerdns', function() {
|
it('Should be able to create new DNS certificate with Powerdns', () => {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/nginx/certificates',
|
path: '/api/nginx/certificates',
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Basic API checks', () => {
|
describe('Basic API checks', () => {
|
||||||
it('Should return a valid health payload', function () {
|
it('Should return a valid health payload', () => {
|
||||||
cy.task('backendApiGet', {
|
cy.task('backendApiGet', {
|
||||||
path: '/api/',
|
path: '/api/',
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
@@ -10,9 +10,9 @@ describe('Basic API checks', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should return a valid schema payload', function () {
|
it('Should return a valid schema payload', () => {
|
||||||
cy.task('backendApiGet', {
|
cy.task('backendApiGet', {
|
||||||
path: '/api/schema?ts=' + Date.now(),
|
path: `/api/schema?ts=${Date.now()}`,
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
expect(data.openapi).to.be.equal('3.1.0');
|
expect(data.openapi).to.be.equal('3.1.0');
|
||||||
});
|
});
|
||||||
|
64
test/cypress/e2e/api/Ldap.cy.js
Normal file
64
test/cypress/e2e/api/Ldap.cy.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
describe('LDAP with Authentik', () => {
|
||||||
|
let _token;
|
||||||
|
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
cy.getToken().then((tok) => {
|
||||||
|
_token = tok;
|
||||||
|
|
||||||
|
// cy.task('backendApiPut', {
|
||||||
|
// token: token,
|
||||||
|
// path: '/api/settings/ldap-auth',
|
||||||
|
// data: {
|
||||||
|
// value: {
|
||||||
|
// host: 'authentik-ldap:3389',
|
||||||
|
// base_dn: 'ou=users,DC=ldap,DC=goauthentik,DC=io',
|
||||||
|
// user_dn: 'cn={{USERNAME}},ou=users,DC=ldap,DC=goauthentik,DC=io',
|
||||||
|
// email_property: 'mail',
|
||||||
|
// name_property: 'sn',
|
||||||
|
// self_filter: '(&(cn={{USERNAME}})(ak-active=TRUE))',
|
||||||
|
// auto_create_user: true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }).then((data) => {
|
||||||
|
// cy.validateSwaggerSchema('put', 200, '/settings/{name}', data);
|
||||||
|
// expect(data.result).to.have.property('id');
|
||||||
|
// expect(data.result.id).to.be.greaterThan(0);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// cy.task('backendApiPut', {
|
||||||
|
// token: token,
|
||||||
|
// path: '/api/settings/auth-methods',
|
||||||
|
// data: {
|
||||||
|
// value: [
|
||||||
|
// 'local',
|
||||||
|
// 'ldap'
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }).then((data) => {
|
||||||
|
// cy.validateSwaggerSchema('put', 200, '/settings/{name}', data);
|
||||||
|
// expect(data.result).to.have.property('id');
|
||||||
|
// expect(data.result.id).to.be.greaterThan(0);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('Should log in with LDAP', () => {
|
||||||
|
// cy.task('backendApiPost', {
|
||||||
|
// token: token,
|
||||||
|
// path: '/api/auth',
|
||||||
|
// data: {
|
||||||
|
// // Authentik LDAP creds:
|
||||||
|
// type: 'ldap',
|
||||||
|
// identity: 'cypress',
|
||||||
|
// secret: 'fqXBfUYqHvYqiwBHWW7f'
|
||||||
|
// }
|
||||||
|
// }).then((data) => {
|
||||||
|
// cy.validateSwaggerSchema('post', 200, '/auth', data);
|
||||||
|
// expect(data.result).to.have.property('token');
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
97
test/cypress/e2e/api/OAuth.cy.js
Normal file
97
test/cypress/e2e/api/OAuth.cy.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
|
describe('OAuth with Authentik', () => {
|
||||||
|
let _token;
|
||||||
|
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
cy.getToken().then((tok) => {
|
||||||
|
_token = tok;
|
||||||
|
|
||||||
|
// cy.task('backendApiPut', {
|
||||||
|
// token: token,
|
||||||
|
// path: '/api/settings/oauth-auth',
|
||||||
|
// data: {
|
||||||
|
// value: {
|
||||||
|
// client_id: '7iO2AvuUp9JxiSVkCcjiIbQn4mHmUMBj7yU8EjqU',
|
||||||
|
// client_secret: 'VUMZzaGTrmXJ8PLksyqzyZ6lrtz04VvejFhPMBP9hGZNCMrn2LLBanySs4ta7XGrDr05xexPyZT1XThaf4ubg00WqvHRVvlu4Naa1aMootNmSRx3VAk6RSslUJmGyHzq',
|
||||||
|
// authorization_url: 'http://authentik:9000/application/o/authorize/',
|
||||||
|
// resource_url: 'http://authentik:9000/application/o/userinfo/',
|
||||||
|
// token_url: 'http://authentik:9000/application/o/token/',
|
||||||
|
// logout_url: 'http://authentik:9000/application/o/npm/end-session/',
|
||||||
|
// identifier: 'preferred_username',
|
||||||
|
// scopes: [],
|
||||||
|
// auto_create_user: true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }).then((data) => {
|
||||||
|
// cy.validateSwaggerSchema('put', 200, '/settings/{name}', data);
|
||||||
|
// expect(data.result).to.have.property('id');
|
||||||
|
// expect(data.result.id).to.be.greaterThan(0);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// cy.task('backendApiPut', {
|
||||||
|
// token: token,
|
||||||
|
// path: '/api/settings/auth-methods',
|
||||||
|
// data: {
|
||||||
|
// value: [
|
||||||
|
// 'local',
|
||||||
|
// 'oauth'
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }).then((data) => {
|
||||||
|
// cy.validateSwaggerSchema('put', 200, '/settings/{name}', data);
|
||||||
|
// expect(data.result).to.have.property('id');
|
||||||
|
// expect(data.result.id).to.be.greaterThan(0);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('Should log in with OAuth', () => {
|
||||||
|
// cy.task('backendApiGet', {
|
||||||
|
// path: '/oauth/login?redirect_base=' + encodeURI(Cypress.config('baseUrl')),
|
||||||
|
// }).then((data) => {
|
||||||
|
// expect(data).to.have.property('result');
|
||||||
|
|
||||||
|
// cy.origin('http://authentik:9000', {args: data.result}, (url) => {
|
||||||
|
// cy.visit(url);
|
||||||
|
// cy.get('ak-flow-executor')
|
||||||
|
// .shadow()
|
||||||
|
// .find('ak-stage-identification')
|
||||||
|
// .shadow()
|
||||||
|
// .find('input[name="uidField"]', { visible: true })
|
||||||
|
// .type('cypress');
|
||||||
|
|
||||||
|
// cy.get('ak-flow-executor')
|
||||||
|
// .shadow()
|
||||||
|
// .find('ak-stage-identification')
|
||||||
|
// .shadow()
|
||||||
|
// .find('button[type="submit"]', { visible: true })
|
||||||
|
// .click();
|
||||||
|
|
||||||
|
// cy.get('ak-flow-executor')
|
||||||
|
// .shadow()
|
||||||
|
// .find('ak-stage-password')
|
||||||
|
// .shadow()
|
||||||
|
// .find('input[name="password"]', { visible: true })
|
||||||
|
// .type('fqXBfUYqHvYqiwBHWW7f');
|
||||||
|
|
||||||
|
// cy.get('ak-flow-executor')
|
||||||
|
// .shadow()
|
||||||
|
// .find('ak-stage-password')
|
||||||
|
// .shadow()
|
||||||
|
// .find('button[type="submit"]', { visible: true })
|
||||||
|
// .click();
|
||||||
|
// })
|
||||||
|
|
||||||
|
// // we should be logged in
|
||||||
|
// cy.get('#root p.chakra-text')
|
||||||
|
// .first()
|
||||||
|
// .should('have.text', 'Nginx Proxy Manager');
|
||||||
|
|
||||||
|
// // logout:
|
||||||
|
// cy.clearLocalStorage();
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
@@ -9,7 +9,7 @@ describe('Proxy Hosts endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be able to create a http host', function() {
|
it('Should be able to create a http host', () => {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/nginx/proxy-hosts',
|
path: '/api/nginx/proxy-hosts',
|
||||||
|
@@ -9,7 +9,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Get all settings', function() {
|
it('Get all settings', () => {
|
||||||
cy.task('backendApiGet', {
|
cy.task('backendApiGet', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings',
|
path: '/api/settings',
|
||||||
@@ -19,52 +19,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Get oidc-config setting', function() {
|
it('Get default-site setting', () => {
|
||||||
cy.task('backendApiGet', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/settings/oidc-config',
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('get', 200, '/settings/{settingID}', data);
|
|
||||||
expect(data).to.have.property('id');
|
|
||||||
expect(data.id).to.be.equal('oidc-config');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('OIDC settings can be updated', function() {
|
|
||||||
cy.task('backendApiPut', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/settings/oidc-config',
|
|
||||||
data: {
|
|
||||||
meta: {
|
|
||||||
name: 'Some OIDC Provider',
|
|
||||||
clientID: 'clientID',
|
|
||||||
clientSecret: 'clientSecret',
|
|
||||||
issuerURL: 'https://oidc.example.com',
|
|
||||||
redirectURL: 'https://redirect.example.com/api/oidc/callback',
|
|
||||||
enabled: true,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
|
||||||
expect(data).to.have.property('id');
|
|
||||||
expect(data.id).to.be.equal('oidc-config');
|
|
||||||
expect(data).to.have.property('meta');
|
|
||||||
expect(data.meta).to.have.property('name');
|
|
||||||
expect(data.meta.name).to.be.equal('Some OIDC Provider');
|
|
||||||
expect(data.meta).to.have.property('clientID');
|
|
||||||
expect(data.meta.clientID).to.be.equal('clientID');
|
|
||||||
expect(data.meta).to.have.property('clientSecret');
|
|
||||||
expect(data.meta.clientSecret).to.be.equal('clientSecret');
|
|
||||||
expect(data.meta).to.have.property('issuerURL');
|
|
||||||
expect(data.meta.issuerURL).to.be.equal('https://oidc.example.com');
|
|
||||||
expect(data.meta).to.have.property('redirectURL');
|
|
||||||
expect(data.meta.redirectURL).to.be.equal('https://redirect.example.com/api/oidc/callback');
|
|
||||||
expect(data.meta).to.have.property('enabled');
|
|
||||||
expect(data.meta.enabled).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Get default-site setting', function() {
|
|
||||||
cy.task('backendApiGet', {
|
cy.task('backendApiGet', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
@@ -75,7 +30,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Default Site congratulations', function() {
|
it('Default Site congratulations', () => {
|
||||||
cy.task('backendApiPut', {
|
cy.task('backendApiPut', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
@@ -91,7 +46,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Default Site 404', function() {
|
it('Default Site 404', () => {
|
||||||
cy.task('backendApiPut', {
|
cy.task('backendApiPut', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
@@ -107,7 +62,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Default Site 444', function() {
|
it('Default Site 444', () => {
|
||||||
cy.task('backendApiPut', {
|
cy.task('backendApiPut', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
@@ -123,7 +78,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Default Site redirect', function() {
|
it('Default Site redirect', () => {
|
||||||
cy.task('backendApiPut', {
|
cy.task('backendApiPut', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
@@ -145,7 +100,7 @@ describe('Settings endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Default Site html', function() {
|
it('Default Site html', () => {
|
||||||
cy.task('backendApiPut', {
|
cy.task('backendApiPut', {
|
||||||
token: token,
|
token: token,
|
||||||
path: '/api/settings/default-site',
|
path: '/api/settings/default-site',
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user