mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-06-18 10:06:26 +00:00
Compare commits
2 Commits
master
...
b0b234ff7d
Author | SHA1 | Date | |
---|---|---|---|
b0b234ff7d | |||
10f61595e1 |
67
Jenkinsfile
vendored
67
Jenkinsfile
vendored
@ -43,7 +43,7 @@ pipeline {
|
|||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
// Defaults to the Branch name, which is applies to all branches AND pr's
|
// Defaults to the Branch name, which is applies to all branches AND pr's
|
||||||
buildxPushTags = "-t docker.io/nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}"
|
buildxPushTags = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,11 +127,6 @@ pipeline {
|
|||||||
junit 'test/results/junit/*'
|
junit 'test/results/junit/*'
|
||||||
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
}
|
}
|
||||||
unstable {
|
|
||||||
dir(path: 'test/results') {
|
|
||||||
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Test Mysql') {
|
stage('Test Mysql') {
|
||||||
@ -160,49 +155,6 @@ pipeline {
|
|||||||
junit 'test/results/junit/*'
|
junit 'test/results/junit/*'
|
||||||
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
}
|
}
|
||||||
unstable {
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('MultiArch Build') {
|
stage('MultiArch Build') {
|
||||||
@ -241,13 +193,7 @@ 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/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
|
||||||
[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev)
|
|
||||||
as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
|
|
||||||
|
|
||||||
**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
|
|
||||||
**Note:** this is a different docker image namespace than the official image
|
|
||||||
""", true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,13 +204,20 @@ as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
|
|||||||
always {
|
always {
|
||||||
sh 'echo Reverting ownership'
|
sh 'echo Reverting ownership'
|
||||||
sh 'docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data'
|
sh 'docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data'
|
||||||
printResult(true)
|
}
|
||||||
|
success {
|
||||||
|
juxtapose event: 'success'
|
||||||
|
sh 'figlet "SUCCESS"'
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
||||||
|
juxtapose event: 'failure'
|
||||||
|
sh 'figlet "FAILURE"'
|
||||||
}
|
}
|
||||||
unstable {
|
unstable {
|
||||||
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
|
||||||
|
juxtapose event: 'unstable'
|
||||||
|
sh 'figlet "UNSTABLE"'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.3-green.svg?style=for-the-badge">
|
<img src="https://img.shields.io/badge/version-2.12.0-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>
|
||||||
|
@ -9,6 +9,22 @@ function generateDbConfig() {
|
|||||||
if (cfg.engine === 'knex-native') {
|
if (cfg.engine === 'knex-native') {
|
||||||
return cfg.knex;
|
return cfg.knex;
|
||||||
}
|
}
|
||||||
|
if (cfg.engine === 'pg') {
|
||||||
|
|
||||||
|
return {
|
||||||
|
client: cfg.engine,
|
||||||
|
connection: {
|
||||||
|
host: cfg.host,
|
||||||
|
user: cfg.user,
|
||||||
|
password: cfg.password,
|
||||||
|
database: cfg.name,
|
||||||
|
port: cfg.port
|
||||||
|
},
|
||||||
|
migrations: {
|
||||||
|
tableName: 'migrations'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
client: cfg.engine,
|
client: cfg.engine,
|
||||||
connection: {
|
connection: {
|
||||||
|
@ -81,7 +81,7 @@ const internalAccessList = {
|
|||||||
|
|
||||||
return internalAccessList.build(row)
|
return internalAccessList.build(row)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (parseInt(row.proxy_host_count, 10)) {
|
if (row.proxy_host_count) {
|
||||||
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 (parseInt(row.proxy_host_count, 10)) {
|
if (row.proxy_host_count) {
|
||||||
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
|
||||||
}
|
}
|
||||||
}).then(internalNginx.reload)
|
}).then(internalNginx.reload)
|
||||||
@ -252,13 +252,9 @@ 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'))
|
||||||
.leftJoin('proxy_host', function() {
|
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
||||||
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();
|
||||||
|
|
||||||
@ -377,10 +373,7 @@ 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'))
|
||||||
.leftJoin('proxy_host', function() {
|
.joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0')
|
||||||
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]')
|
||||||
@ -508,13 +501,8 @@ 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('openssl', ['passwd', '-apr1', item.password])
|
utils.execFile('/usr/bin/htpasswd', ['-b', htpasswd_file, item.username, item.password])
|
||||||
.then((res) => {
|
.then((/*result*/) => {
|
||||||
try {
|
|
||||||
fs.appendFileSync(htpasswd_file, item.username + ':' + res + '\n', {encoding: 'utf8'});
|
|
||||||
} catch (err) {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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 = {
|
||||||
|
|
||||||
@ -23,9 +22,9 @@ const internalAuditLog = {
|
|||||||
.allowGraph('[user]');
|
.allowGraph('[user]');
|
||||||
|
|
||||||
// Query is used for searching
|
// Query is used for searching
|
||||||
if (typeof search_query === 'string' && search_query.length > 0) {
|
if (typeof search_query === 'string') {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where(castJsonIfNeed('meta'), 'like', '%' + search_query + '%');
|
this.where('meta', 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,29 +3,27 @@ const fs = require('fs');
|
|||||||
const https = require('https');
|
const https = require('https');
|
||||||
const tempWrite = require('temp-write');
|
const tempWrite = require('temp-write');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const archiver = require('archiver');
|
|
||||||
const path = require('path');
|
|
||||||
const { isArray } = require('lodash');
|
|
||||||
const logger = require('../logger').ssl;
|
const logger = require('../logger').ssl;
|
||||||
const config = require('../lib/config');
|
const config = require('../lib/config');
|
||||||
const error = require('../lib/error');
|
const error = require('../lib/error');
|
||||||
const utils = require('../lib/utils');
|
const utils = require('../lib/utils');
|
||||||
const certbot = require('../lib/certbot');
|
|
||||||
const certificateModel = require('../models/certificate');
|
const certificateModel = require('../models/certificate');
|
||||||
const tokenModel = require('../models/token');
|
const tokenModel = require('../models/token');
|
||||||
const dnsPlugins = require('../global/certbot-dns-plugins.json');
|
const dnsPlugins = require('../global/certbot-dns-plugins.json');
|
||||||
const internalAuditLog = require('./audit-log');
|
const internalAuditLog = require('./audit-log');
|
||||||
const internalNginx = require('./nginx');
|
const internalNginx = require('./nginx');
|
||||||
const internalHost = require('./host');
|
const internalHost = require('./host');
|
||||||
|
const certbot = require('../lib/certbot');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
const path = require('path');
|
||||||
|
const { isArray } = require('lodash');
|
||||||
|
|
||||||
const letsencryptStaging = config.useLetsencryptStaging();
|
const letsencryptStaging = config.useLetsencryptStaging();
|
||||||
const letsencryptServer = config.useLetsencryptServer();
|
|
||||||
const letsencryptConfig = '/etc/letsencrypt.ini';
|
const letsencryptConfig = '/etc/letsencrypt.ini';
|
||||||
const certbotCommand = 'certbot';
|
const certbotCommand = 'certbot';
|
||||||
|
|
||||||
function omissions() {
|
function omissions() {
|
||||||
return ['is_deleted', 'owner.is_deleted'];
|
return ['is_deleted'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalCertificate = {
|
const internalCertificate = {
|
||||||
@ -209,7 +207,6 @@ const internalCertificate = {
|
|||||||
.patchAndFetchById(certificate.id, {
|
.patchAndFetchById(certificate.id, {
|
||||||
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
|
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
|
||||||
})
|
})
|
||||||
.then(utils.omitRow(omissions()))
|
|
||||||
.then((saved_row) => {
|
.then((saved_row) => {
|
||||||
// Add cert data for audit log
|
// Add cert data for audit log
|
||||||
saved_row.meta = _.assign({}, saved_row.meta, {
|
saved_row.meta = _.assign({}, saved_row.meta, {
|
||||||
@ -313,9 +310,6 @@ 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') {
|
||||||
@ -467,9 +461,6 @@ 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') {
|
||||||
@ -739,29 +730,29 @@ const internalCertificate = {
|
|||||||
|
|
||||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -subject -noout')
|
return utils.exec('openssl x509 -in ' + certificate_file + ' -subject -noout')
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
// Examples:
|
|
||||||
// subject=CN = *.jc21.com
|
|
||||||
// subject=CN = something.example.com
|
// subject=CN = something.example.com
|
||||||
const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
|
const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
|
||||||
const match = regex.exec(result);
|
const match = regex.exec(result);
|
||||||
if (match && typeof match[1] !== 'undefined') {
|
|
||||||
certData['cn'] = match[1];
|
if (typeof match[1] === 'undefined') {
|
||||||
|
throw new error.ValidationError('Could not determine subject from certificate: ' + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
certData['cn'] = match[1];
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -issuer -noout');
|
return utils.exec('openssl x509 -in ' + certificate_file + ' -issuer -noout');
|
||||||
})
|
})
|
||||||
|
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
// Examples:
|
|
||||||
// issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
|
// issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
|
||||||
// issuer=C = US, O = Let's Encrypt, CN = E5
|
|
||||||
// issuer=O = NginxProxyManager, CN = NginxProxyManager Intermediate CA","O = NginxProxyManager, CN = NginxProxyManager Intermediate CA
|
|
||||||
const regex = /^(?:issuer=)?(.*)$/gim;
|
const regex = /^(?:issuer=)?(.*)$/gim;
|
||||||
const match = regex.exec(result);
|
const match = regex.exec(result);
|
||||||
if (match && typeof match[1] !== 'undefined') {
|
|
||||||
certData['issuer'] = match[1];
|
if (typeof match[1] === 'undefined') {
|
||||||
|
throw new error.ValidationError('Could not determine issuer from certificate: ' + result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
certData['issuer'] = match[1];
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -dates -noout');
|
return utils.exec('openssl x509 -in ' + certificate_file + ' -dates -noout');
|
||||||
@ -836,18 +827,17 @@ const internalCertificate = {
|
|||||||
requestLetsEncryptSsl: (certificate) => {
|
requestLetsEncryptSsl: (certificate) => {
|
||||||
logger.info('Requesting Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
logger.info('Requesting Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||||
|
|
||||||
const cmd = `${certbotCommand} certonly ` +
|
const cmd = certbotCommand + ' certonly ' +
|
||||||
`--config '${letsencryptConfig}' ` +
|
'--config "' + letsencryptConfig + '" ' +
|
||||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||||
`--cert-name "npm-${certificate.id}" ` +
|
'--cert-name "npm-' + certificate.id + '" ' +
|
||||||
'--agree-tos ' +
|
'--agree-tos ' +
|
||||||
'--authenticator webroot ' +
|
'--authenticator webroot ' +
|
||||||
`--email '${certificate.meta.letsencrypt_email}' ` +
|
'--email "' + certificate.meta.letsencrypt_email + '" ' +
|
||||||
'--preferred-challenges "dns,http" ' +
|
'--preferred-challenges "dns,http" ' +
|
||||||
`--domains "${certificate.domain_names.join(',')}" ` +
|
'--domains "' + certificate.domain_names.join(',') + '" ' +
|
||||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
(letsencryptStaging ? '--staging' : '');
|
||||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
|
||||||
|
|
||||||
logger.info('Command:', cmd);
|
logger.info('Command:', cmd);
|
||||||
|
|
||||||
@ -878,26 +868,25 @@ const internalCertificate = {
|
|||||||
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
|
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
|
||||||
|
|
||||||
let mainCmd = certbotCommand + ' certonly ' +
|
let mainCmd = certbotCommand + ' certonly ' +
|
||||||
`--config '${letsencryptConfig}' ` +
|
'--config "' + letsencryptConfig + '" ' +
|
||||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||||
`--cert-name 'npm-${certificate.id}' ` +
|
'--cert-name "npm-' + certificate.id + '" ' +
|
||||||
'--agree-tos ' +
|
'--agree-tos ' +
|
||||||
`--email '${certificate.meta.letsencrypt_email}' ` +
|
'--email "' + certificate.meta.letsencrypt_email + '" ' +
|
||||||
`--domains '${certificate.domain_names.join(',')}' ` +
|
'--domains "' + certificate.domain_names.join(',') + '" ' +
|
||||||
`--authenticator '${dnsPlugin.full_plugin_name}' ` +
|
'--authenticator ' + dnsPlugin.full_plugin_name + ' ' +
|
||||||
(
|
(
|
||||||
hasConfigArg
|
hasConfigArg
|
||||||
? `--${dnsPlugin.full_plugin_name}-credentials '${credentialsLocation}' `
|
? '--' + dnsPlugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
|
||||||
: ''
|
: ''
|
||||||
) +
|
) +
|
||||||
(
|
(
|
||||||
certificate.meta.propagation_seconds !== undefined
|
certificate.meta.propagation_seconds !== undefined
|
||||||
? `--${dnsPlugin.full_plugin_name}-propagation-seconds '${certificate.meta.propagation_seconds}' `
|
? ' --' + dnsPlugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds
|
||||||
: ''
|
: ''
|
||||||
) +
|
) +
|
||||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
(letsencryptStaging ? ' --staging' : '');
|
||||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
|
||||||
|
|
||||||
// Prepend the path to the credentials file as an environment variable
|
// Prepend the path to the credentials file as an environment variable
|
||||||
if (certificate.meta.dns_provider === 'route53') {
|
if (certificate.meta.dns_provider === 'route53') {
|
||||||
@ -974,15 +963,14 @@ const internalCertificate = {
|
|||||||
logger.info('Renewing Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
logger.info('Renewing Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||||
|
|
||||||
const cmd = certbotCommand + ' renew --force-renewal ' +
|
const cmd = certbotCommand + ' renew --force-renewal ' +
|
||||||
`--config '${letsencryptConfig}' ` +
|
'--config "' + letsencryptConfig + '" ' +
|
||||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||||
`--cert-name 'npm-${certificate.id}' ` +
|
'--cert-name "npm-' + certificate.id + '" ' +
|
||||||
'--preferred-challenges "dns,http" ' +
|
'--preferred-challenges "dns,http" ' +
|
||||||
'--no-random-sleep-on-renew ' +
|
'--no-random-sleep-on-renew ' +
|
||||||
'--disable-hook-validation ' +
|
'--disable-hook-validation ' +
|
||||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
(letsencryptStaging ? '--staging' : '');
|
||||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
|
||||||
|
|
||||||
logger.info('Command:', cmd);
|
logger.info('Command:', cmd);
|
||||||
|
|
||||||
@ -1007,14 +995,13 @@ const internalCertificate = {
|
|||||||
logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||||
|
|
||||||
let mainCmd = certbotCommand + ' renew --force-renewal ' +
|
let mainCmd = certbotCommand + ' renew --force-renewal ' +
|
||||||
`--config "${letsencryptConfig}" ` +
|
'--config "' + letsencryptConfig + '" ' +
|
||||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||||
`--cert-name 'npm-${certificate.id}' ` +
|
'--cert-name "npm-' + certificate.id + '" ' +
|
||||||
'--disable-hook-validation ' +
|
'--disable-hook-validation ' +
|
||||||
'--no-random-sleep-on-renew ' +
|
'--no-random-sleep-on-renew ' +
|
||||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
(letsencryptStaging ? ' --staging' : '');
|
||||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
|
||||||
|
|
||||||
// Prepend the path to the credentials file as an environment variable
|
// Prepend the path to the credentials file as an environment variable
|
||||||
if (certificate.meta.dns_provider === 'route53') {
|
if (certificate.meta.dns_provider === 'route53') {
|
||||||
@ -1040,13 +1027,12 @@ const internalCertificate = {
|
|||||||
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||||
|
|
||||||
const mainCmd = certbotCommand + ' revoke ' +
|
const mainCmd = certbotCommand + ' revoke ' +
|
||||||
`--config '${letsencryptConfig}' ` +
|
'--config "' + letsencryptConfig + '" ' +
|
||||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||||
`--cert-path '/etc/letsencrypt/live/npm-${certificate.id}/fullchain.pem' ` +
|
'--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
|
||||||
'--delete-after-revoke ' +
|
'--delete-after-revoke ' +
|
||||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
(letsencryptStaging ? '--staging' : '');
|
||||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
|
||||||
|
|
||||||
// Don't fail command if file does not exist
|
// Don't fail command if file does not exist
|
||||||
const delete_credentialsCmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
|
const delete_credentialsCmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
|
||||||
|
@ -6,7 +6,6 @@ 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'];
|
||||||
@ -410,16 +409,16 @@ const internalDeadHost = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.orderBy(castJsonIfNeed('domain_names'), 'ASC');
|
.orderBy('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' && search_query.length > 0) {
|
if (typeof search_query === 'string') {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where(castJsonIfNeed('domain_names'), 'like', '%' + search_query + '%');
|
this.where('domain_names', 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ 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 = {
|
||||||
|
|
||||||
@ -18,7 +17,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;
|
||||||
|
|
||||||
const combined_data = _.assign({}, existing_data, data);
|
let 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;
|
||||||
@ -74,7 +73,7 @@ const internalHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getHostsWithDomains: function (domain_names) {
|
getHostsWithDomains: function (domain_names) {
|
||||||
const promises = [
|
let promises = [
|
||||||
proxyHostModel
|
proxyHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0),
|
.where('is_deleted', 0),
|
||||||
@ -126,19 +125,19 @@ const internalHost = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
isHostnameTaken: function (hostname, ignore_type, ignore_id) {
|
isHostnameTaken: function (hostname, ignore_type, ignore_id) {
|
||||||
const promises = [
|
let promises = [
|
||||||
proxyHostModel
|
proxyHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
|
.andWhere('domain_names', 'like', '%' + hostname + '%'),
|
||||||
redirectionHostModel
|
redirectionHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
|
.andWhere('domain_names', 'like', '%' + hostname + '%'),
|
||||||
deadHostModel
|
deadHostModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%')
|
.andWhere('domain_names', 'like', '%' + hostname + '%')
|
||||||
];
|
];
|
||||||
|
|
||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
|
@ -181,9 +181,7 @@ const internalNginx = {
|
|||||||
* @param {Object} host
|
* @param {Object} host
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
generateConfig: (host_type, host_row) => {
|
generateConfig: (host_type, host) => {
|
||||||
// Prevent modifying the original object:
|
|
||||||
let host = JSON.parse(JSON.stringify(host_row));
|
|
||||||
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
|
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
|
||||||
|
|
||||||
if (config.debug()) {
|
if (config.debug()) {
|
||||||
|
@ -6,7 +6,6 @@ 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'];
|
||||||
@ -417,16 +416,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(castJsonIfNeed('domain_names'), 'ASC');
|
.orderBy('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' && search_query.length > 0) {
|
if (typeof search_query === 'string') {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
|
this.where('domain_names', 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ 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'];
|
||||||
@ -410,16 +409,16 @@ const internalRedirectionHost = {
|
|||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner,certificate]')
|
||||||
.orderBy(castJsonIfNeed('domain_names'), 'ASC');
|
.orderBy('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' && search_query.length > 0) {
|
if (typeof search_query === 'string') {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
|
this.where('domain_names', 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,9 @@ 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', 'owner.is_deleted', 'certificate.is_deleted'];
|
return ['is_deleted'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalStream = {
|
const internalStream = {
|
||||||
@ -20,12 +17,6 @@ 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
|
||||||
@ -35,44 +26,16 @@ 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_no_domains)
|
.insertAndFetch(data)
|
||||||
.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 row;
|
return internalStream.get(access, {id: row.id, expand: ['owner']});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
@ -96,12 +59,6 @@ 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
|
||||||
@ -113,32 +70,16 @@ 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, {
|
||||||
@ -151,17 +92,6 @@ 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());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -184,7 +114,7 @@ const internalStream = {
|
|||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.andWhere('id', data.id)
|
.andWhere('id', data.id)
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner]')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (access_data.permission_visibility !== 'all') {
|
if (access_data.permission_visibility !== 'all') {
|
||||||
@ -201,7 +131,6 @@ 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);
|
||||||
@ -267,14 +196,14 @@ const internalStream = {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
return internalStream.get(access, {
|
return internalStream.get(access, {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
expand: ['certificate', 'owner']
|
expand: ['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('Stream is already enabled');
|
throw new error.ValidationError('Host is already enabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
row.enabled = 1;
|
row.enabled = 1;
|
||||||
@ -320,7 +249,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('Stream is already disabled');
|
throw new error.ValidationError('Host is already disabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
row.enabled = 0;
|
row.enabled = 0;
|
||||||
@ -364,21 +293,21 @@ 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) => {
|
||||||
const query = streamModel
|
let query = streamModel
|
||||||
.query()
|
.query()
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.groupBy('id')
|
.groupBy('id')
|
||||||
.allowGraph('[owner,certificate]')
|
.allowGraph('[owner]')
|
||||||
.orderByRaw('CAST(incoming_port AS INTEGER) ASC');
|
.orderBy('incoming_port', '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' && search_query.length > 0) {
|
if (typeof search_query === 'string') {
|
||||||
query.where(function () {
|
query.where(function () {
|
||||||
this.where(castJsonIfNeed('incoming_port'), 'like', `%${search_query}%`);
|
this.where('incoming_port', 'like', '%' + search_query + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,13 +316,6 @@ 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;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -405,9 +327,9 @@ const internalStream = {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getCount: (user_id, visibility) => {
|
getCount: (user_id, visibility) => {
|
||||||
const query = streamModel
|
let 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') {
|
||||||
|
@ -5,8 +5,6 @@ const authModel = require('../models/auth');
|
|||||||
const helpers = require('../lib/helpers');
|
const helpers = require('../lib/helpers');
|
||||||
const TokenModel = require('../models/token');
|
const TokenModel = require('../models/token');
|
||||||
|
|
||||||
const ERROR_MESSAGE_INVALID_AUTH = 'Invalid email or password';
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,15 +69,15 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
throw new error.AuthError('Invalid password');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
throw new error.AuthError('No password auth for user');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
throw new error.AuthError('No relevant user found');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -3,9 +3,6 @@ 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;
|
||||||
|
|
||||||
@ -17,7 +14,7 @@ const configure = () => {
|
|||||||
let configData;
|
let configData;
|
||||||
try {
|
try {
|
||||||
configData = require(filename);
|
configData = require(filename);
|
||||||
} catch (_) {
|
} catch (err) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +34,7 @@ const configure = () => {
|
|||||||
logger.info('Using MySQL configuration');
|
logger.info('Using MySQL configuration');
|
||||||
instance = {
|
instance = {
|
||||||
database: {
|
database: {
|
||||||
engine: mysqlEngine,
|
engine: 'mysql2',
|
||||||
host: envMysqlHost,
|
host: envMysqlHost,
|
||||||
port: process.env.DB_MYSQL_PORT || 3306,
|
port: process.env.DB_MYSQL_PORT || 3306,
|
||||||
user: envMysqlUser,
|
user: envMysqlUser,
|
||||||
@ -48,21 +45,20 @@ const configure = () => {
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const envPostgresqlHost = process.env.DB_POSTGRESQL_HOST || null;
|
||||||
const envPostgresHost = process.env.DB_POSTGRES_HOST || null;
|
const envPostgresqlUser = process.env.DB_POSTGRESQL_USER || null;
|
||||||
const envPostgresUser = process.env.DB_POSTGRES_USER || null;
|
const envPostgresqlName = process.env.DB_POSTGRESQL_NAME || null;
|
||||||
const envPostgresName = process.env.DB_POSTGRES_NAME || null;
|
if (envPostgresqlHost && envPostgresqlUser && envPostgresqlName) {
|
||||||
if (envPostgresHost && envPostgresUser && envPostgresName) {
|
// we have enough mysql creds to go with mysql
|
||||||
// we have enough postgres creds to go with postgres
|
logger.info('Using POSTGRESQL configuration');
|
||||||
logger.info('Using Postgres configuration');
|
|
||||||
instance = {
|
instance = {
|
||||||
database: {
|
database: {
|
||||||
engine: postgresEngine,
|
engine: 'pg',
|
||||||
host: envPostgresHost,
|
host: envPostgresqlHost,
|
||||||
port: process.env.DB_POSTGRES_PORT || 5432,
|
port: process.env.DB_POSTGRESQL_PORT || 3306,
|
||||||
user: envPostgresUser,
|
user: envPostgresqlUser,
|
||||||
password: process.env.DB_POSTGRES_PASSWORD,
|
password: process.env.DB_POSTGRESQL_PASSWORD,
|
||||||
name: envPostgresName,
|
name: envPostgresqlName,
|
||||||
},
|
},
|
||||||
keys: getKeys(),
|
keys: getKeys(),
|
||||||
};
|
};
|
||||||
@ -75,7 +71,7 @@ const configure = () => {
|
|||||||
database: {
|
database: {
|
||||||
engine: 'knex-native',
|
engine: 'knex-native',
|
||||||
knex: {
|
knex: {
|
||||||
client: sqliteClientName,
|
client: 'sqlite3',
|
||||||
connection: {
|
connection: {
|
||||||
filename: envSqliteFile
|
filename: envSqliteFile
|
||||||
},
|
},
|
||||||
@ -166,27 +162,7 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
isSqlite: function () {
|
isSqlite: function () {
|
||||||
instance === null && configure();
|
instance === null && configure();
|
||||||
return instance.database.knex && instance.database.knex.client === sqliteClientName;
|
return instance.database.knex && instance.database.knex.client === 'sqlite3';
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,15 +199,5 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
useLetsencryptStaging: function () {
|
useLetsencryptStaging: function () {
|
||||||
return !!process.env.LE_STAGING;
|
return !!process.env.LE_STAGING;
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
|
||||||
useLetsencryptServer: function () {
|
|
||||||
if (process.env.LE_SERVER) {
|
|
||||||
return process.env.LE_SERVER;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const {isPostgres} = require('./config');
|
|
||||||
const {ref} = require('objection');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
@ -47,16 +45,6 @@ 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,38 +0,0 @@
|
|||||||
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,6 +4,7 @@
|
|||||||
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);
|
||||||
@ -67,11 +68,6 @@ 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,
|
||||||
@ -83,39 +79,6 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,6 @@ 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,14 +1,15 @@
|
|||||||
const Model = require('objection').Model;
|
// Objection Docs:
|
||||||
|
// http://vincit.github.io/objection.js/
|
||||||
|
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const helpers = require('../lib/helpers');
|
const helpers = require('../lib/helpers');
|
||||||
|
const Model = require('objection').Model;
|
||||||
const User = require('./user');
|
const User = require('./user');
|
||||||
const Certificate = require('./certificate');
|
|
||||||
const now = require('./now_helper');
|
const now = require('./now_helper');
|
||||||
|
|
||||||
Model.knex(db);
|
Model.knex(db);
|
||||||
|
|
||||||
const boolFields = [
|
const boolFields = [
|
||||||
'enabled',
|
|
||||||
'is_deleted',
|
'is_deleted',
|
||||||
'tcp_forwarding',
|
'tcp_forwarding',
|
||||||
'udp_forwarding',
|
'udp_forwarding',
|
||||||
@ -63,17 +64,6 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
"node-rsa": "^1.0.8",
|
"node-rsa": "^1.0.8",
|
||||||
"objection": "3.0.1",
|
"objection": "3.0.1",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.0",
|
||||||
"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"
|
||||||
|
@ -24,34 +24,22 @@
|
|||||||
"description": "Nice Name for the custom certificate"
|
"description": "Nice Name for the custom certificate"
|
||||||
},
|
},
|
||||||
"domain_names": {
|
"domain_names": {
|
||||||
"description": "Domain Names separated by a comma",
|
"$ref": "../common.json#/properties/domain_names"
|
||||||
"type": "array",
|
|
||||||
"maxItems": 100,
|
|
||||||
"uniqueItems": true,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"expires_on": {
|
"expires_on": {
|
||||||
"description": "Date and time of expiration",
|
"description": "Date and time of expiration",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"owner": {
|
|
||||||
"$ref": "./user-object.json"
|
|
||||||
},
|
|
||||||
"meta": {
|
"meta": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"certificate": {
|
"letsencrypt_email": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"minLength": 1
|
|
||||||
},
|
},
|
||||||
"certificate_key": {
|
"letsencrypt_agree": {
|
||||||
"type": "string",
|
"type": "boolean"
|
||||||
"minLength": 1
|
|
||||||
},
|
},
|
||||||
"dns_challenge": {
|
"dns_challenge": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -62,19 +50,14 @@
|
|||||||
"dns_provider_credentials": {
|
"dns_provider_credentials": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"letsencrypt_agree": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"letsencrypt_certificate": {
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"letsencrypt_email": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"propagation_seconds": {
|
"propagation_seconds": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"minimum": 0
|
"minimum": 0
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
"locations",
|
"locations",
|
||||||
"hsts_enabled",
|
"hsts_enabled",
|
||||||
"hsts_subdomains",
|
"hsts_subdomains",
|
||||||
"certificate"
|
"certificate",
|
||||||
|
"use_default_location",
|
||||||
|
"ipv6"
|
||||||
],
|
],
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -149,6 +151,12 @@
|
|||||||
"$ref": "./access-list-object.json"
|
"$ref": "./access-list-object.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"use_default_location": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"ipv6": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"forward_scheme": {
|
"forward_scheme": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["auto", "http", "https"]
|
"enum": ["http", "https"]
|
||||||
},
|
},
|
||||||
"forward_domain_name": {
|
"forward_domain_name": {
|
||||||
"description": "Domain Name",
|
"description": "Domain Name",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"value": {
|
"value": {
|
||||||
"description": "Value in almost any form",
|
"description": "Value in almost any form",
|
||||||
"example": "congratulations",
|
"example": "congratulations",
|
||||||
"anyOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1
|
"minLength": 1
|
||||||
@ -46,10 +46,7 @@
|
|||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"description": "Extra metadata",
|
"description": "Extra metadata",
|
||||||
"example": {
|
"example": {},
|
||||||
"redirect": "http://example.com",
|
|
||||||
"html": "<h1>404</h1>"
|
|
||||||
},
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,24 +53,8 @@
|
|||||||
"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,9 +5,10 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"expires": {
|
"expires": {
|
||||||
"description": "Token Expiry ISO Time String",
|
"description": "Token Expiry Unix Time",
|
||||||
"example": "2025-02-04T20:40:46.340Z",
|
"example": 1566540249,
|
||||||
"type": "string"
|
"minimum": 1,
|
||||||
|
"type": "number"
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"description": "JWT Token",
|
"description": "JWT Token",
|
||||||
|
@ -49,7 +49,8 @@
|
|||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"minLength": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,25 +55,6 @@
|
|||||||
"certificate_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd\nqACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w\nrbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge\nYz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ\noxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z\nEo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X\nzGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU\nia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6\nYHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe\na0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu\nW0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw\no72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW\nH8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+\nN+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh\nELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU\nMDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31\nqjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq\ncMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9\nvMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO\nutTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V\ng0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1\nmJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq\nYatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8\nEQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk\n8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM\nRrKmPK/msHKK/sVHiL+NFqo=\n-----END PRIVATE KEY-----\n"
|
"certificate_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd\nqACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w\nrbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge\nYz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ\noxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z\nEo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X\nzGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU\nia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6\nYHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe\na0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu\nW0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw\no72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW\nH8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+\nN+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh\nELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU\nMDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31\nqjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq\ncMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9\nvMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO\nutTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V\ng0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1\nmJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq\nYatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8\nEQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk\n8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM\nRrKmPK/msHKK/sVHiL+NFqo=\n-----END PRIVATE KEY-----\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": ["certificate", "certificate_key"],
|
|
||||||
"properties": {
|
|
||||||
"certificate": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 1
|
|
||||||
},
|
|
||||||
"certificate_key": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 1
|
|
||||||
},
|
|
||||||
"intermediate_certificate": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,9 @@
|
|||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"certificate": null
|
"certificate": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -79,7 +79,9 @@
|
|||||||
"nickname": "Admin",
|
"nickname": "Admin",
|
||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
}
|
},
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -129,7 +129,9 @@
|
|||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"certificate": null,
|
"certificate": null,
|
||||||
"access_list": null
|
"access_list": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -114,7 +114,9 @@
|
|||||||
"avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
|
"avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"access_list": null
|
"access_list": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -114,7 +114,9 @@
|
|||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"certificate": null
|
"certificate": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -99,7 +99,9 @@
|
|||||||
"nickname": "Admin",
|
"nickname": "Admin",
|
||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
}
|
},
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"description": "Expansions",
|
"description": "Expansions",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["owner", "certificate"]
|
"enum": ["access_list", "owner", "certificate"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -40,8 +40,7 @@
|
|||||||
"nginx_online": true,
|
"nginx_online": true,
|
||||||
"nginx_err": null
|
"nginx_err": null
|
||||||
},
|
},
|
||||||
"enabled": true,
|
"enabled": true
|
||||||
"certificate_id": 0
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,6 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
@ -76,8 +73,7 @@
|
|||||||
"nickname": "Admin",
|
"nickname": "Admin",
|
||||||
"avatar": "",
|
"avatar": "",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
}
|
||||||
"certificate_id": 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -40,8 +40,7 @@
|
|||||||
"nginx_online": true,
|
"nginx_online": true,
|
||||||
"nginx_err": null
|
"nginx_err": null
|
||||||
},
|
},
|
||||||
"enabled": true,
|
"enabled": true
|
||||||
"certificate_id": 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -29,26 +29,56 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"properties": {
|
"properties": {
|
||||||
"incoming_port": {
|
"domain_names": {
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/incoming_port"
|
"$ref": "../../../../components/proxy-host-object.json#/properties/domain_names"
|
||||||
},
|
},
|
||||||
"forwarding_host": {
|
"forward_scheme": {
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/forwarding_host"
|
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_scheme"
|
||||||
},
|
},
|
||||||
"forwarding_port": {
|
"forward_host": {
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/forwarding_port"
|
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_host"
|
||||||
},
|
},
|
||||||
"tcp_forwarding": {
|
"forward_port": {
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/tcp_forwarding"
|
"$ref": "../../../../components/proxy-host-object.json#/properties/forward_port"
|
||||||
},
|
|
||||||
"udp_forwarding": {
|
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/udp_forwarding"
|
|
||||||
},
|
},
|
||||||
"certificate_id": {
|
"certificate_id": {
|
||||||
"$ref": "../../../../components/stream-object.json#/properties/certificate_id"
|
"$ref": "../../../../components/proxy-host-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/stream-object.json#/properties/meta"
|
"$ref": "../../../../components/proxy-host-object.json#/properties/meta"
|
||||||
|
},
|
||||||
|
"locations": {
|
||||||
|
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,32 +94,44 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"created_on": "2024-10-09T02:33:45.000Z",
|
"created_on": "2024-10-08T23:23:03.000Z",
|
||||||
"modified_on": "2024-10-09T02:33:45.000Z",
|
"modified_on": "2024-10-08T23:26:37.000Z",
|
||||||
"owner_user_id": 1,
|
"owner_user_id": 1,
|
||||||
"incoming_port": 9090,
|
"domain_names": ["test.example.com"],
|
||||||
"forwarding_host": "router.internal",
|
"forward_host": "192.168.0.10",
|
||||||
"forwarding_port": 80,
|
"forward_port": 8989,
|
||||||
"tcp_forwarding": true,
|
"access_list_id": 0,
|
||||||
"udp_forwarding": false,
|
"certificate_id": 0,
|
||||||
|
"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-09T02:33:16.000Z",
|
"created_on": "2024-10-07T22:43:55.000Z",
|
||||||
"modified_on": "2024-10-09T02:33:16.000Z",
|
"modified_on": "2024-10-08T12:52:54.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": "Admin",
|
"nickname": "some guy",
|
||||||
"avatar": "",
|
"avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
|
||||||
"roles": ["admin"]
|
"roles": ["admin"]
|
||||||
},
|
},
|
||||||
"certificate_id": 0
|
"certificate": null,
|
||||||
|
"access_list": null,
|
||||||
|
"use_default_location": true,
|
||||||
|
"ipv6": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
"name": "settingID",
|
"name": "settingID",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1
|
||||||
"enum": ["default-site"]
|
|
||||||
},
|
},
|
||||||
"required": true,
|
"required": true,
|
||||||
"description": "Setting ID",
|
"description": "Setting ID",
|
||||||
@ -32,21 +31,10 @@
|
|||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"properties": {
|
"properties": {
|
||||||
"value": {
|
"value": {
|
||||||
"type": "string",
|
"$ref": "../../../components/setting-object.json#/properties/value"
|
||||||
"minLength": 1,
|
|
||||||
"enum": ["congratulations", "404", "444", "redirect", "html"]
|
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"type": "object",
|
"$ref": "../../../components/setting-object.json#/properties/meta"
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"redirect": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"html": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"examples": {
|
"examples": {
|
||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"expires": "2025-02-04T20:40:46.340Z",
|
"expires": 1566540510,
|
||||||
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"value": {
|
"value": {
|
||||||
"result": {
|
"result": {
|
||||||
"expires": "2025-02-04T20:40:46.340Z",
|
"expires": 1566540510,
|
||||||
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,18 +15,17 @@ const certbot = require('./lib/certbot');
|
|||||||
const setupDefaultUser = () => {
|
const setupDefaultUser = () => {
|
||||||
return userModel
|
return userModel
|
||||||
.query()
|
.query()
|
||||||
.select('id', )
|
.select('id')
|
||||||
.where('is_deleted', 0)
|
.where('is_deleted', 0)
|
||||||
.first()
|
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row || !row.id) {
|
if (!row.length || !row[0].id) {
|
||||||
// Create a new user and set password
|
// Create a new user and set password
|
||||||
const email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
let email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
||||||
const password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
|
let 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);
|
||||||
|
|
||||||
const data = {
|
let data = {
|
||||||
is_deleted: 0,
|
is_deleted: 0,
|
||||||
email: email,
|
email: email,
|
||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
@ -79,9 +78,8 @@ const setupDefaultSettings = () => {
|
|||||||
.query()
|
.query()
|
||||||
.select('id')
|
.select('id')
|
||||||
.where({id: 'default-site'})
|
.where({id: 'default-site'})
|
||||||
.first()
|
|
||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row || !row.id) {
|
if (!row.length || !row[0].id) {
|
||||||
settingModel
|
settingModel
|
||||||
.query()
|
.query()
|
||||||
.insert({
|
.insert({
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
auth_basic "Authorization required";
|
auth_basic "Authorization required";
|
||||||
auth_basic_user_file /data/access/{{ access_list_id }};
|
auth_basic_user_file /data/access/{{ access_list_id }};
|
||||||
|
|
||||||
{% if access_list.pass_auth == 0 or access_list.pass_auth == true %}
|
{% if access_list.pass_auth == 0 %}
|
||||||
proxy_set_header Authorization "";
|
proxy_set_header Authorization "";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
deny all;
|
deny all;
|
||||||
|
|
||||||
# Access checks must...
|
# Access checks must...
|
||||||
{% if access_list.satisfy_any == 1 or access_list.satisfy_any == true %}
|
{% if access_list.satisfy_any == 1 %}
|
||||||
satisfy any;
|
satisfy any;
|
||||||
{% else %}
|
{% else %}
|
||||||
satisfy all;
|
satisfy all;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
{% 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;
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
{% 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 -%}
|
|
@ -5,16 +5,11 @@
|
|||||||
#listen [::]:80;
|
#listen [::]:80;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if certificate -%}
|
{% if certificate -%}
|
||||||
listen 443 ssl;
|
listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||||
{% if ipv6 -%}
|
{% if ipv6 -%}
|
||||||
listen [::]:443 ssl;
|
listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||||
{% else -%}
|
{% else -%}
|
||||||
#listen [::]:443;
|
#listen [::]:443;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
server_name {{ domain_names | join: " " }};
|
server_name {{ domain_names | join: " " }};
|
||||||
{% if http2_support == 1 or http2_support == true %}
|
|
||||||
http2 on;
|
|
||||||
{% else -%}
|
|
||||||
http2 off;
|
|
||||||
{% endif %}
|
|
@ -7,7 +7,11 @@
|
|||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
||||||
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
|
set $proxy_forward_scheme {{ forward_scheme }};
|
||||||
|
set $proxy_server "{{ forward_host }}";
|
||||||
|
set $proxy_port {{ forward_port }};
|
||||||
|
|
||||||
|
proxy_pass $proxy_forward_scheme://$proxy_server:$proxy_port{{ forward_path }};
|
||||||
|
|
||||||
{% include "_access.conf" %}
|
{% include "_access.conf" %}
|
||||||
{% include "_assets.conf" %}
|
{% include "_assets.conf" %}
|
||||||
|
@ -22,7 +22,5 @@ server {
|
|||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# Custom
|
|
||||||
include /data/nginx/custom/server_dead[.]conf;
|
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -5,10 +5,12 @@
|
|||||||
{% 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 }} {%- if certificate %} ssl {%- endif %};
|
listen {{ incoming_port }};
|
||||||
{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %};
|
{% if ipv6 -%}
|
||||||
|
listen [::]:{{ incoming_port }};
|
||||||
{%- include "_certificates_stream.conf" %}
|
{% else -%}
|
||||||
|
#listen [::]:{{ incoming_port }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
@ -17,12 +19,14 @@ 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;
|
||||||
{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp;
|
{% if ipv6 -%}
|
||||||
|
listen [::]:{{ incoming_port }} udp;
|
||||||
|
{% else -%}
|
||||||
|
#listen [::]:{{ incoming_port }} udp;
|
||||||
|
{% endif %}
|
||||||
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
|
||||||
|
|
||||||
# Custom
|
# Custom
|
||||||
|
@ -830,9 +830,9 @@ crc32-stream@^4.0.2:
|
|||||||
readable-stream "^3.4.0"
|
readable-stream "^3.4.0"
|
||||||
|
|
||||||
cross-spawn@^7.0.2:
|
cross-spawn@^7.0.2:
|
||||||
version "7.0.6"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key "^3.1.0"
|
path-key "^3.1.0"
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
@ -2776,10 +2776,10 @@ pg-types@^2.1.0:
|
|||||||
postgres-date "~1.0.4"
|
postgres-date "~1.0.4"
|
||||||
postgres-interval "^1.1.0"
|
postgres-interval "^1.1.0"
|
||||||
|
|
||||||
pg@^8.13.1:
|
pg@^8.13.0:
|
||||||
version "8.13.1"
|
version "8.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/pg/-/pg-8.13.1.tgz#6498d8b0a87ff76c2df7a32160309d3168c0c080"
|
resolved "https://registry.yarnpkg.com/pg/-/pg-8.13.0.tgz#e3d245342eb0158112553fcc1890a60720ae2a3d"
|
||||||
integrity sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==
|
integrity sha512-34wkUTh3SxTClfoHB3pQ7bIMvw9dpFU1audQQeZG837fmHfHpr14n/AELVDoOYVDW2h5RDWU78tFjkD+erSBsw==
|
||||||
dependencies:
|
dependencies:
|
||||||
pg-connection-string "^2.7.0"
|
pg-connection-string "^2.7.0"
|
||||||
pg-pool "^3.7.0"
|
pg-pool "^3.7.0"
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
# This file assumes that the frontend has been built using ./scripts/frontend-build
|
# This file assumes that the frontend has been built using ./scripts/frontend-build
|
||||||
|
|
||||||
FROM nginxproxymanager/testca AS testca
|
|
||||||
FROM letsencrypt/pebble AS pebbleca
|
|
||||||
FROM nginxproxymanager/nginx-full:certbot-node
|
FROM nginxproxymanager/nginx-full:certbot-node
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
@ -47,8 +45,6 @@ RUN yarn install \
|
|||||||
|
|
||||||
# add late to limit cache-busting by modifications
|
# add late to limit cache-busting by modifications
|
||||||
COPY docker/rootfs /
|
COPY docker/rootfs /
|
||||||
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
|
||||||
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
|
|
||||||
|
|
||||||
# Remove frontend service not required for prod, dev nginx config as well
|
# Remove frontend service not required for prod, dev nginx config as well
|
||||||
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
|
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
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
|
|
Binary file not shown.
@ -1,10 +1,7 @@
|
|||||||
FROM nginxproxymanager/testca AS testca
|
|
||||||
FROM letsencrypt/pebble AS pebbleca
|
|
||||||
FROM nginxproxymanager/nginx-full:certbot-node
|
FROM nginxproxymanager/nginx-full:certbot-node
|
||||||
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
|
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
|
||||||
|
|
||||||
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
|
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
|
||||||
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
|
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
|
||||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||||
@ -20,21 +17,18 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
|
|||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Task
|
# Task
|
||||||
WORKDIR /usr
|
RUN cd /usr \
|
||||||
RUN curl -sL https://taskfile.dev/install.sh | sh
|
&& curl -sL https://taskfile.dev/install.sh | sh \
|
||||||
WORKDIR /root
|
&& cd /root
|
||||||
|
|
||||||
COPY rootfs /
|
COPY rootfs /
|
||||||
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 \
|
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
|
||||||
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager \
|
|
||||||
&& /tmp/install-s6 "${TARGETPLATFORM}" \
|
|
||||||
&& rm -f /tmp/install-s6 \
|
|
||||||
&& chmod 644 -R /root/.cache
|
|
||||||
|
|
||||||
# Certs for testing purposes
|
# s6 overlay
|
||||||
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
COPY scripts/install-s6 /tmp/install-s6
|
||||||
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
|
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
|
||||||
|
RUN chmod 644 -R /root/.cache
|
||||||
|
|
||||||
EXPOSE 80 81 443
|
EXPOSE 80 81 443
|
||||||
ENTRYPOINT [ "/init" ]
|
ENTRYPOINT [ "/init" ]
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
# 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:
|
|
29
docker/docker-compose.ci.postgresql.yml
Normal file
29
docker/docker-compose.ci.postgresql.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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:
|
||||||
|
|
||||||
|
fullstack:
|
||||||
|
environment:
|
||||||
|
DB_POSTGRESQL_HOST: 'db'
|
||||||
|
DB_POSTGRESQL_PORT: '5432'
|
||||||
|
DB_POSTGRESQL_USER: 'npm'
|
||||||
|
DB_POSTGRESQL_PASSWORD: 'npmpass'
|
||||||
|
DB_POSTGRESQL_NAME: 'npm'
|
||||||
|
depends_on:
|
||||||
|
- db-postgresql
|
||||||
|
|
||||||
|
db-postgresql:
|
||||||
|
image: postgres:14.2-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: "npmpass"
|
||||||
|
POSTGRES_USER: "npm"
|
||||||
|
POSTGRES_DB: "npm"
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
volumes:
|
||||||
|
- postgres_vol:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- fulltest
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_vol:
|
@ -9,9 +9,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DEBUG: 'true'
|
DEBUG: 'true'
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
# Required for DNS Certificate provisioning in CI
|
|
||||||
LE_SERVER: 'https://ca.internal/acme/acme/directory'
|
|
||||||
REQUESTS_CA_BUNDLE: '/etc/ssl/certs/NginxProxyManager.crt'
|
|
||||||
volumes:
|
volumes:
|
||||||
- 'npm_data_ci:/data'
|
- 'npm_data_ci:/data'
|
||||||
- 'npm_le_ci:/etc/letsencrypt'
|
- 'npm_le_ci:/etc/letsencrypt'
|
||||||
@ -22,10 +19,6 @@ 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:
|
||||||
@ -44,7 +37,7 @@ services:
|
|||||||
- ca.internal
|
- ca.internal
|
||||||
|
|
||||||
pdns:
|
pdns:
|
||||||
image: pschiffe/pdns-mysql:4.8
|
image: pschiffe/pdns-mysql
|
||||||
volumes:
|
volumes:
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
environment:
|
environment:
|
||||||
@ -101,7 +94,7 @@ services:
|
|||||||
HTTP_PROXY: 'squid:3128'
|
HTTP_PROXY: 'squid:3128'
|
||||||
HTTPS_PROXY: 'squid:3128'
|
HTTPS_PROXY: 'squid:3128'
|
||||||
volumes:
|
volumes:
|
||||||
- 'cypress_logs:/test/results'
|
- 'cypress_logs:/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
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
|
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
|
||||||
services:
|
services:
|
||||||
|
|
||||||
fullstack:
|
npm:
|
||||||
image: npm2dev:core
|
image: nginxproxymanager:dev
|
||||||
container_name: npm2dev.core
|
container_name: npm_core
|
||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: ./dev/Dockerfile
|
dockerfile: ./dev/Dockerfile
|
||||||
@ -26,44 +26,26 @@ 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:
|
|
||||||
LE_SERVER: 'https://ca.internal/acme/acme/directory'
|
|
||||||
REQUESTS_CA_BUNDLE: '/etc/ssl/certs/NginxProxyManager.crt'
|
|
||||||
volumes:
|
volumes:
|
||||||
- npm_data:/data
|
- npm_data:/data
|
||||||
- le_data:/etc/letsencrypt
|
- le_data:/etc/letsencrypt
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
|
||||||
- ../backend:/app
|
- ../backend:/app
|
||||||
- ../frontend:/app/frontend
|
- ../frontend:/app/frontend
|
||||||
- ../global:/app/global
|
- ../global:/app/global
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "/usr/bin/check-health"]
|
|
||||||
interval: 10s
|
|
||||||
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: npm2dev.db
|
container_name: npm_db
|
||||||
ports:
|
ports:
|
||||||
- 33306:3306
|
- 33306:3306
|
||||||
networks:
|
networks:
|
||||||
@ -76,193 +58,36 @@ 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:
|
|
||||||
image: jc21/testca
|
|
||||||
container_name: npm2dev.stepca
|
|
||||||
volumes:
|
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
|
||||||
networks:
|
|
||||||
nginx_proxy_manager:
|
|
||||||
aliases:
|
|
||||||
- ca.internal
|
|
||||||
|
|
||||||
dnsrouter:
|
|
||||||
image: jc21/dnsrouter
|
|
||||||
container_name: npm2dev.dnsrouter
|
|
||||||
volumes:
|
|
||||||
- ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
|
|
||||||
networks:
|
|
||||||
- nginx_proxy_manager
|
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
image: swaggerapi/swagger-ui:latest
|
image: swaggerapi/swagger-ui:latest
|
||||||
container_name: npm2dev.swagger
|
container_name: npm_swagger
|
||||||
ports:
|
ports:
|
||||||
- 3082:80
|
- 3082:80
|
||||||
environment:
|
environment:
|
||||||
URL: "http://npm:81/api/schema"
|
URL: "http://npm:81/api/schema"
|
||||||
PORT: '80'
|
PORT: '80'
|
||||||
depends_on:
|
depends_on:
|
||||||
- fullstack
|
- npm
|
||||||
|
|
||||||
squid:
|
squid:
|
||||||
image: ubuntu/squid
|
image: ubuntu/squid
|
||||||
container_name: npm2dev.squid
|
container_name: npm_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'
|
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
- '/etc/localtime:/etc/localtime:ro'
|
||||||
networks:
|
networks:
|
||||||
- nginx_proxy_manager
|
- nginx_proxy_manager
|
||||||
ports:
|
ports:
|
||||||
- 8128:3128
|
- 8128:3128
|
||||||
|
|
||||||
pdns:
|
|
||||||
image: pschiffe/pdns-mysql:4.8
|
|
||||||
container_name: npm2dev.pdns
|
|
||||||
volumes:
|
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
|
||||||
environment:
|
|
||||||
PDNS_master: 'yes'
|
|
||||||
PDNS_api: 'yes'
|
|
||||||
PDNS_api_key: 'npm'
|
|
||||||
PDNS_webserver: 'yes'
|
|
||||||
PDNS_webserver_address: '0.0.0.0'
|
|
||||||
PDNS_webserver_password: 'npm'
|
|
||||||
PDNS_webserver-allow-from: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
|
|
||||||
PDNS_version_string: 'anonymous'
|
|
||||||
PDNS_default_ttl: 1500
|
|
||||||
PDNS_allow_axfr_ips: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
|
|
||||||
PDNS_gmysql_host: pdns-db
|
|
||||||
PDNS_gmysql_port: 3306
|
|
||||||
PDNS_gmysql_user: pdns
|
|
||||||
PDNS_gmysql_password: pdns
|
|
||||||
PDNS_gmysql_dbname: pdns
|
|
||||||
depends_on:
|
|
||||||
- pdns-db
|
|
||||||
networks:
|
|
||||||
nginx_proxy_manager:
|
|
||||||
aliases:
|
|
||||||
- ns1.pdns
|
|
||||||
- ns2.pdns
|
|
||||||
|
|
||||||
pdns-db:
|
|
||||||
image: mariadb
|
|
||||||
container_name: npm2dev.pdns-db
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: 'pdns'
|
|
||||||
MYSQL_DATABASE: 'pdns'
|
|
||||||
MYSQL_USER: 'pdns'
|
|
||||||
MYSQL_PASSWORD: 'pdns'
|
|
||||||
volumes:
|
|
||||||
- 'pdns_mysql:/var/lib/mysql'
|
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
|
||||||
- './dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro'
|
|
||||||
networks:
|
|
||||||
- nginx_proxy_manager
|
|
||||||
|
|
||||||
cypress:
|
|
||||||
image: npm2dev:cypress
|
|
||||||
container_name: npm2dev.cypress
|
|
||||||
build:
|
|
||||||
context: ../
|
|
||||||
dockerfile: test/cypress/Dockerfile
|
|
||||||
environment:
|
|
||||||
HTTP_PROXY: 'squid:3128'
|
|
||||||
HTTPS_PROXY: 'squid:3128'
|
|
||||||
volumes:
|
|
||||||
- '../test/results:/results'
|
|
||||||
- './dev/resolv.conf:/etc/resolv.conf:ro'
|
|
||||||
- '/etc/localtime:/etc/localtime:ro'
|
|
||||||
command: cypress run --browser chrome --config-file=cypress/config/ci.js
|
|
||||||
networks:
|
|
||||||
- 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: npm2dev_core_data
|
name: npm_core_data
|
||||||
le_data:
|
le_data:
|
||||||
name: npm2dev_le_data
|
name: npm_le_data
|
||||||
db_data:
|
db_data:
|
||||||
name: npm2dev_db_data
|
name: npm_db_data
|
||||||
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: npm2dev_network
|
name: npm_network
|
||||||
|
91
docker/docker-compose.dev2.yml
Normal file
91
docker/docker-compose.dev2.yml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
|
||||||
|
services:
|
||||||
|
|
||||||
|
npm:
|
||||||
|
image: nginxproxymanager:dev
|
||||||
|
container_name: npm_core
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: ./dev/Dockerfile
|
||||||
|
ports:
|
||||||
|
- 3080:80
|
||||||
|
- 3081:81
|
||||||
|
- 3443:443
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
environment:
|
||||||
|
PUID: 1000
|
||||||
|
PGID: 1000
|
||||||
|
FORCE_COLOR: 1
|
||||||
|
# specifically for dev:
|
||||||
|
DEBUG: 'true'
|
||||||
|
DEVELOPMENT: 'true'
|
||||||
|
LE_STAGING: 'true'
|
||||||
|
# db:
|
||||||
|
DB_POSTGRESQL_HOST: 'db'
|
||||||
|
DB_POSTGRESQL_PORT: '5432'
|
||||||
|
DB_POSTGRESQL_USER: 'npm'
|
||||||
|
DB_POSTGRESQL_PASSWORD: 'npmpass'
|
||||||
|
DB_POSTGRESQL_NAME: 'npm'
|
||||||
|
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||||
|
# DISABLE_IPV6: "true"
|
||||||
|
volumes:
|
||||||
|
- npm_data:/data
|
||||||
|
- le_data:/etc/letsencrypt
|
||||||
|
- ../backend:/app
|
||||||
|
- ../frontend:/app/frontend
|
||||||
|
- ../global:/app/global
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
working_dir: /app
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:14.2-alpine
|
||||||
|
container_name: npm_db
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: "npmpass"
|
||||||
|
POSTGRES_USER: "npm"
|
||||||
|
POSTGRES_DB: "npm"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4
|
||||||
|
environment:
|
||||||
|
PGADMIN_DEFAULT_EMAIL: "admin@example.com"
|
||||||
|
PGADMIN_DEFAULT_PASSWORD: "changeme"
|
||||||
|
ports:
|
||||||
|
- 5080:80
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
image: swaggerapi/swagger-ui:latest
|
||||||
|
container_name: npm_swagger
|
||||||
|
ports:
|
||||||
|
- 3082:80
|
||||||
|
environment:
|
||||||
|
URL: "http://npm:81/api/schema"
|
||||||
|
PORT: '80'
|
||||||
|
depends_on:
|
||||||
|
- npm
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
npm_data:
|
||||||
|
name: npm_core_data
|
||||||
|
le_data:
|
||||||
|
name: npm_le_data
|
||||||
|
db_data:
|
||||||
|
name: npm_db_data
|
||||||
|
db_data1:
|
||||||
|
name: npm_db_data1
|
||||||
|
|
||||||
|
networks:
|
||||||
|
nginx_proxy_manager:
|
||||||
|
name: npm_network
|
@ -1,4 +1,4 @@
|
|||||||
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|woff2|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
||||||
if_modified_since off;
|
if_modified_since off;
|
||||||
|
|
||||||
# use the public cache
|
# use the public cache
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
ssl_session_timeout 5m;
|
|
||||||
ssl_session_cache shared:SSL_stream:50m;
|
|
@ -1,2 +0,0 @@
|
|||||||
ssl_session_timeout 5m;
|
|
||||||
ssl_session_cache shared:SSL:50m;
|
|
@ -1,3 +1,6 @@
|
|||||||
|
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';
|
||||||
|
@ -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.2.0.2
|
S6_OVERLAY_VERSION=3.1.5.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
|
||||||
|
@ -50,6 +50,7 @@ networks:
|
|||||||
Let's look at a Portainer example:
|
Let's look at a Portainer example:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
|
|
||||||
portainer:
|
portainer:
|
||||||
@ -91,6 +92,8 @@ This image supports the use of Docker secrets to import from files and keep sens
|
|||||||
You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name.
|
You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
# Secrets are single-line text files where the sole content is the secret
|
# Secrets are single-line text files where the sole content is the secret
|
||||||
# Paths in this example assume that secrets are kept in local folder called ".secrets"
|
# Paths in this example assume that secrets are kept in local folder called ".secrets"
|
||||||
@ -181,7 +184,6 @@ 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.
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ outline: deep
|
|||||||
Create a `docker-compose.yml` file:
|
Create a `docker-compose.yml` file:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: 'jc21/nginx-proxy-manager:latest'
|
image: 'jc21/nginx-proxy-manager:latest'
|
||||||
@ -21,7 +22,8 @@ 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
|
||||||
|
|
||||||
environment:
|
# Uncomment the next line if you uncomment anything in the section
|
||||||
|
# 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"
|
||||||
@ -53,6 +55,7 @@ are going to use.
|
|||||||
Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container:
|
Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: 'jc21/nginx-proxy-manager:latest'
|
image: 'jc21/nginx-proxy-manager:latest'
|
||||||
@ -98,53 +101,6 @@ 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:
|
||||||
@ -181,13 +137,5 @@ Email: admin@example.com
|
|||||||
Password: changeme
|
Password: changeme
|
||||||
```
|
```
|
||||||
|
|
||||||
Immediately after logging in with this default user you will be asked to modify your details and change your password. You can change defaults with:
|
Immediately after logging in with this default user you will be asked to modify your details and change your password.
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
environment:
|
|
||||||
INITIAL_ADMIN_EMAIL: my@example.com
|
|
||||||
INITIAL_ADMIN_PASSWORD: mypassword1
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
1
docs/src/third-party/index.md
vendored
1
docs/src/third-party/index.md
vendored
@ -12,7 +12,6 @@ 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.8"
|
version "3.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
|
||||||
integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
|
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
|
||||||
|
|
||||||
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.14"
|
version "5.4.8"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.14.tgz#ff8255edb02134df180dcfca1916c37a6abe8408"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8"
|
||||||
integrity sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==
|
integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.21.3"
|
esbuild "^0.21.3"
|
||||||
postcss "^8.4.43"
|
postcss "^8.4.43"
|
||||||
|
@ -26,7 +26,7 @@ module.exports = {
|
|||||||
* Users
|
* Users
|
||||||
*/
|
*/
|
||||||
showUsers: function () {
|
showUsers: function () {
|
||||||
const controller = this;
|
let 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');
|
||||||
@ -93,7 +93,8 @@ module.exports = {
|
|||||||
* Dashboard
|
* Dashboard
|
||||||
*/
|
*/
|
||||||
showDashboard: function () {
|
showDashboard: function () {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './dashboard/main'], (App, View) => {
|
require(['./main', './dashboard/main'], (App, View) => {
|
||||||
controller.navigate('/');
|
controller.navigate('/');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -105,7 +106,7 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxProxy: function () {
|
showNginxProxy: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('proxy_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('proxy_hosts')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/proxy/main'], (App, View) => {
|
require(['./main', './nginx/proxy/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/proxy');
|
controller.navigate('/nginx/proxy');
|
||||||
@ -145,7 +146,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxRedirection: function () {
|
showNginxRedirection: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('redirection_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('redirection_hosts')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/redirection/main'], (App, View) => {
|
require(['./main', './nginx/redirection/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/redirection');
|
controller.navigate('/nginx/redirection');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -184,7 +186,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxStream: function () {
|
showNginxStream: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('streams')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('streams')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/stream/main'], (App, View) => {
|
require(['./main', './nginx/stream/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/stream');
|
controller.navigate('/nginx/stream');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -223,7 +226,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxDead: function () {
|
showNginxDead: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('dead_hosts')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('dead_hosts')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/dead/main'], (App, View) => {
|
require(['./main', './nginx/dead/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/404');
|
controller.navigate('/nginx/404');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -274,7 +278,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxAccess: function () {
|
showNginxAccess: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('access_lists')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('access_lists')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/access/main'], (App, View) => {
|
require(['./main', './nginx/access/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/access');
|
controller.navigate('/nginx/access');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -313,7 +318,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
showNginxCertificates: function () {
|
showNginxCertificates: function () {
|
||||||
if (Cache.User.isAdmin() || Cache.User.canView('certificates')) {
|
if (Cache.User.isAdmin() || Cache.User.canView('certificates')) {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
|
|
||||||
require(['./main', './nginx/certificates/main'], (App, View) => {
|
require(['./main', './nginx/certificates/main'], (App, View) => {
|
||||||
controller.navigate('/nginx/certificates');
|
controller.navigate('/nginx/certificates');
|
||||||
App.UI.showAppContent(new View());
|
App.UI.showAppContent(new View());
|
||||||
@ -377,7 +383,7 @@ module.exports = {
|
|||||||
* Audit Log
|
* Audit Log
|
||||||
*/
|
*/
|
||||||
showAuditLog: function () {
|
showAuditLog: function () {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
if (Cache.User.isAdmin()) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './audit-log/main'], (App, View) => {
|
require(['./main', './audit-log/main'], (App, View) => {
|
||||||
controller.navigate('/audit-log');
|
controller.navigate('/audit-log');
|
||||||
@ -405,7 +411,7 @@ module.exports = {
|
|||||||
* Settings
|
* Settings
|
||||||
*/
|
*/
|
||||||
showSettings: function () {
|
showSettings: function () {
|
||||||
const controller = this;
|
let controller = this;
|
||||||
if (Cache.User.isAdmin()) {
|
if (Cache.User.isAdmin()) {
|
||||||
require(['./main', './settings/main'], (App, View) => {
|
require(['./main', './settings/main'], (App, View) => {
|
||||||
controller.navigate('/settings');
|
controller.navigate('/settings');
|
||||||
|
@ -24,7 +24,7 @@ module.exports = Mn.View.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
templateContext: function () {
|
templateContext: function () {
|
||||||
const view = this;
|
let view = this;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUserName: function () {
|
getUserName: function () {
|
||||||
@ -48,7 +48,8 @@ module.exports = Mn.View.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onRender: function () {
|
onRender: function () {
|
||||||
const view = this;
|
let view = this;
|
||||||
|
|
||||||
if (typeof view.stats.hosts === 'undefined') {
|
if (typeof view.stats.hosts === 'undefined') {
|
||||||
Api.Reports.getHostStats()
|
Api.Reports.getHostStats()
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@ -71,7 +72,8 @@ module.exports = Mn.View.extend({
|
|||||||
|
|
||||||
// calculate the available columns based on permissions for the objects
|
// calculate the available columns based on permissions for the objects
|
||||||
// and store as a variable
|
// and store as a variable
|
||||||
const perms = ['proxy_hosts', 'redirection_hosts', 'streams', 'dead_hosts'];
|
//let view = this;
|
||||||
|
let perms = ['proxy_hosts', 'redirection_hosts', 'streams', 'dead_hosts'];
|
||||||
|
|
||||||
perms.map(perm => {
|
perms.map(perm => {
|
||||||
this.columns += Cache.User.isAdmin() || Cache.User.canView(perm) ? 1 : 0;
|
this.columns += Cache.User.isAdmin() || Cache.User.canView(perm) ? 1 : 0;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -33,13 +33,6 @@
|
|||||||
<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">
|
||||||
@ -55,13 +48,6 @@
|
|||||||
<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,24 +44,14 @@ module.exports = Mn.View.extend({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
templateContext: function () {
|
templateContext: {
|
||||||
return {
|
|
||||||
canManage: App.Cache.User.canManage('certificates'),
|
canManage: App.Cache.User.canManage('certificates'),
|
||||||
isExpired: function () {
|
isExpired: function () {
|
||||||
return moment(this.expires_on).isBefore(moment());
|
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,7 +3,6 @@
|
|||||||
<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','proxy_hosts', 'dead_hosts', 'redirection_hosts'], query)
|
this.fetch(['owner'], 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','proxy_hosts', 'dead_hosts', 'redirection_hosts'])
|
view.fetch(['owner'])
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!view.isDestroyed()) {
|
if (!view.isDestroyed()) {
|
||||||
if (response && response.length) {
|
if (response && response.length) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -3,16 +3,8 @@
|
|||||||
<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 has-tabs">
|
<div class="modal-body">
|
||||||
<div class="alert alert-danger mb-0 rounded-0" id="le-error-info" role="alert"></div>
|
|
||||||
<form>
|
<form>
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</ul>
|
|
||||||
<div class="tab-content">
|
|
||||||
<!-- Details -->
|
|
||||||
<div role="tabpanel" class="tab-pane active" id="details">
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-12">
|
<div class="col-sm-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -54,137 +46,6 @@
|
|||||||
<div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
|
<div class="forward-type-error invalid-feedback"><%- i18n('streams', 'forward-type-error') %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- SSL -->
|
|
||||||
<div role="tabpanel" class="tab-pane" id="ssl-options">
|
|
||||||
<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>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
@ -2,14 +2,10 @@ 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,
|
||||||
@ -22,17 +18,7 @@ module.exports = Mn.View.extend({
|
|||||||
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: {
|
||||||
@ -62,35 +48,6 @@ 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;
|
||||||
|
|
||||||
@ -113,108 +70,10 @@ module.exports = Mn.View.extend({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
let more_info = '';
|
alert(err.message);
|
||||||
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) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -16,10 +16,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div>
|
<div>
|
||||||
<% if (certificate) { %>
|
<% if (tcp_forwarding) { %>
|
||||||
<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) { %>
|
||||||
@ -27,9 +24,6 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
</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,7 +3,6 @@
|
|||||||
<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', 'certificate'])
|
view.fetch(['owner'])
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!view.isDestroyed()) {
|
if (!view.isDestroyed()) {
|
||||||
if (response && response.length) {
|
if (response && response.length) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<form>
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title"><%- i18n('users', 'form-title', {id: id}) %></h5>
|
<h5 class="modal-title"><%- i18n('users', '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">
|
||||||
|
<form>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 col-md-6">
|
<div class="col-sm-6 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -49,10 +49,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<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-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
|
||||||
<button type="submit" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
|
<button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@ module.exports = Mn.View.extend({
|
|||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
|
||||||
'submit @ui.form': function (e) {
|
'click @ui.save': function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.ui.error.hide();
|
this.ui.error.hide();
|
||||||
let view = this;
|
let view = this;
|
||||||
|
@ -179,9 +179,7 @@
|
|||||||
"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",
|
||||||
@ -208,10 +206,7 @@
|
|||||||
"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",
|
||||||
|
@ -15,11 +15,8 @@ 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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2648,9 +2648,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.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
|
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
|
||||||
integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
|
integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
bn.js "^4.11.9"
|
bn.js "^4.11.9"
|
||||||
brorand "^1.1.0"
|
brorand "^1.1.0"
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"aliyun": {
|
"aliyun": {
|
||||||
"name": "Aliyun",
|
"name": "Aliyun",
|
||||||
"package_name": "certbot-dns-aliyun",
|
"package_name": "certbot-dns-aliyun",
|
||||||
"version": "~=2.0.0",
|
"version": "~=0.38.1",
|
||||||
"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,14 +31,6 @@
|
|||||||
"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"
|
||||||
},
|
},
|
||||||
"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",
|
||||||
@ -161,11 +153,11 @@
|
|||||||
},
|
},
|
||||||
"domainoffensive": {
|
"domainoffensive": {
|
||||||
"name": "DomainOffensive (do.de)",
|
"name": "DomainOffensive (do.de)",
|
||||||
"package_name": "certbot-dns-domainoffensive",
|
"package_name": "certbot-dns-do",
|
||||||
"version": "~=2.0.0",
|
"version": "~=0.31.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
||||||
"full_plugin_name": "dns-domainoffensive"
|
"full_plugin_name": "dns-do"
|
||||||
},
|
},
|
||||||
"domeneshop": {
|
"domeneshop": {
|
||||||
"name": "Domeneshop",
|
"name": "Domeneshop",
|
||||||
@ -215,14 +207,6 @@
|
|||||||
"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",
|
||||||
@ -263,14 +247,6 @@
|
|||||||
"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",
|
||||||
@ -327,14 +303,6 @@
|
|||||||
"credentials": "dns_joker_username = <Dynamic DNS Authentication Username>\ndns_joker_password = <Dynamic DNS Authentication Password>\ndns_joker_domain = <Dynamic DNS Domain>",
|
"credentials": "dns_joker_username = <Dynamic DNS Authentication Username>\ndns_joker_password = <Dynamic DNS Authentication Password>\ndns_joker_domain = <Dynamic DNS Domain>",
|
||||||
"full_plugin_name": "dns-joker"
|
"full_plugin_name": "dns-joker"
|
||||||
},
|
},
|
||||||
"leaseweb": {
|
|
||||||
"name": "LeaseWeb",
|
|
||||||
"package_name": "certbot-dns-leaseweb",
|
|
||||||
"version": "~=1.0.1",
|
|
||||||
"dependencies": "",
|
|
||||||
"credentials": "dns_leaseweb_api_token = 01234556789",
|
|
||||||
"full_plugin_name": "dns-leaseweb"
|
|
||||||
},
|
|
||||||
"linode": {
|
"linode": {
|
||||||
"name": "Linode",
|
"name": "Linode",
|
||||||
"package_name": "certbot-dns-linode",
|
"package_name": "certbot-dns-linode",
|
||||||
@ -364,7 +332,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_api_key=0123456789abcdef0123456789abcdef",
|
"credentials": "dns-mijn-host-credentials = /etc/letsencrypt/mijnhost-credentials.ini",
|
||||||
"full_plugin_name": "dns-mijn-host"
|
"full_plugin_name": "dns-mijn-host"
|
||||||
},
|
},
|
||||||
"namecheap": {
|
"namecheap": {
|
||||||
@ -426,7 +394,7 @@
|
|||||||
"porkbun": {
|
"porkbun": {
|
||||||
"name": "Porkbun",
|
"name": "Porkbun",
|
||||||
"package_name": "certbot-dns-porkbun",
|
"package_name": "certbot-dns-porkbun",
|
||||||
"version": "~=0.9",
|
"version": "~=0.2",
|
||||||
"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"
|
||||||
@ -524,7 +492,7 @@
|
|||||||
"package_name": "certbot-dns-wedos",
|
"package_name": "certbot-dns-wedos",
|
||||||
"version": "~=2.2",
|
"version": "~=2.2",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_wedos_user = <wedos_registration>\ndns_wedos_auth = <wapi_password>",
|
"credentials": "dns_wedos_user = <wedos_registration>\ndns_wedos_auth = <wapi_sha256_password>",
|
||||||
"full_plugin_name": "dns-wedos"
|
"full_plugin_name": "dns-wedos"
|
||||||
},
|
},
|
||||||
"edgedns": {
|
"edgedns": {
|
||||||
@ -534,13 +502,5 @@
|
|||||||
"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,17 +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="npm2dev"
|
COMPOSE_PROJECT_NAME="npmdev"
|
||||||
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
|
||||||
|
|
||||||
# $1: container_name
|
|
||||||
get_container_ip () {
|
|
||||||
local container_name=$1
|
|
||||||
local container
|
|
||||||
local ip
|
|
||||||
container=$(docker-compose ps --all -q "${container_name}" | tail -n1)
|
|
||||||
ip=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container")
|
|
||||||
echo "$ip"
|
|
||||||
}
|
|
||||||
|
@ -65,10 +65,8 @@ rm -rf "${LOCAL_RESOLVE}"
|
|||||||
printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}"
|
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
|
||||||
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
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash -e
|
|
||||||
|
|
||||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
. "$DIR/.common.sh"
|
|
||||||
|
|
||||||
# Ensure docker-compose exists
|
|
||||||
if hash docker-compose 2>/dev/null; then
|
|
||||||
cd "${DIR}/.."
|
|
||||||
rm -rf "$DIR/../test/results"
|
|
||||||
docker-compose up --build cypress
|
|
||||||
else
|
|
||||||
echo -e "${RED}❯ docker-compose command is not available${RESET}"
|
|
||||||
fi
|
|
@ -7,42 +7,8 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
if hash docker-compose 2>/dev/null; then
|
if hash docker-compose 2>/dev/null; then
|
||||||
cd "${DIR}/.."
|
cd "${DIR}/.."
|
||||||
echo -e "${BLUE}❯ ${CYAN}Starting Dev Stack ...${RESET}"
|
echo -e "${BLUE}❯ ${CYAN}Starting Dev Stack ...${RESET}"
|
||||||
echo -e "${BLUE}❯ $(docker-compose config)${RESET}"
|
|
||||||
|
|
||||||
# Bring up a stack, in steps so we can inject IPs everywhere
|
docker-compose up -d --remove-orphans --force-recreate --build
|
||||||
docker-compose up -d pdns pdns-db
|
|
||||||
PDNS_IP=$(get_container_ip "pdns")
|
|
||||||
echo -e "${BLUE}❯ ${YELLOW}PDNS IP is ${PDNS_IP}${RESET}"
|
|
||||||
|
|
||||||
# adjust the dnsrouter config
|
|
||||||
LOCAL_DNSROUTER_CONFIG="$DIR/../docker/dev/dnsrouter-config.json"
|
|
||||||
rm -rf "$LOCAL_DNSROUTER_CONFIG.tmp"
|
|
||||||
# IMPORTANT: changes to dnsrouter-config.json will affect this line:
|
|
||||||
jq --arg a "$PDNS_IP" '.servers[0].upstreams[1].upstream = $a' "$LOCAL_DNSROUTER_CONFIG" > "$LOCAL_DNSROUTER_CONFIG.tmp"
|
|
||||||
|
|
||||||
docker-compose up -d dnsrouter
|
|
||||||
DNSROUTER_IP=$(get_container_ip "dnsrouter")
|
|
||||||
echo -e "${BLUE}❯ ${YELLOW}DNS Router IP is ${DNSROUTER_IP}"
|
|
||||||
|
|
||||||
if [ "${DNSROUTER_IP:-}" = "" ]; then
|
|
||||||
echo -e "${RED}❯ ERROR: DNS Router IP is not set${RESET}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# mount the resolver
|
|
||||||
LOCAL_RESOLVE="$DIR/../docker/dev/resolv.conf"
|
|
||||||
rm -rf "${LOCAL_RESOLVE}"
|
|
||||||
printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}"
|
|
||||||
|
|
||||||
# bring up all remaining containers, except cypress!
|
|
||||||
docker-compose up -d --remove-orphans stepca squid
|
|
||||||
docker-compose pull db db-postgres authentik-redis authentik authentik-worker authentik-ldap
|
|
||||||
docker-compose build --pull --parallel fullstack
|
|
||||||
docker-compose up -d --remove-orphans fullstack
|
|
||||||
docker-compose up -d --remove-orphans swagger
|
|
||||||
|
|
||||||
# wait for main container to be healthy
|
|
||||||
bash "$DIR/wait-healthy" "$(docker-compose ps --all -q fullstack)" 120
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}Admin UI: http://127.0.0.1:3081${RESET}"
|
echo -e "${CYAN}Admin UI: http://127.0.0.1:3081${RESET}"
|
||||||
@ -52,10 +18,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 npm2dev.core
|
docker logs -f npm_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 npm2dev.core"
|
echo " docker logs -f npm_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,22 +1,11 @@
|
|||||||
FROM cypress/included:14.0.1
|
FROM cypress/included:13.9.0
|
||||||
|
|
||||||
|
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 []
|
||||||
|
@ -15,7 +15,7 @@ module.exports = defineConfig({
|
|||||||
return require("../plugins/index.js")(on, config);
|
return require("../plugins/index.js")(on, config);
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
swaggerBase: '{{baseUrl}}/api/schema?ts=' + Date.now(),
|
swaggerBase: 'http://fullstack:81/api/schema',
|
||||||
},
|
},
|
||||||
baseUrl: 'http://fullstack:81',
|
baseUrl: 'http://fullstack:81',
|
||||||
}
|
}
|
||||||
|
22
test/cypress/config/dev.js
Normal file
22
test/cypress/config/dev.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const { defineConfig } = require('cypress');
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
requestTimeout: 30000,
|
||||||
|
defaultCommandTimeout: 20000,
|
||||||
|
reporter: 'cypress-multi-reporters',
|
||||||
|
reporterOptions: {
|
||||||
|
configFile: 'multi-reporter.json'
|
||||||
|
},
|
||||||
|
video: false,
|
||||||
|
videosFolder: 'results/videos',
|
||||||
|
screenshotsFolder: 'results/screenshots',
|
||||||
|
e2e: {
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
return require("../plugins/index.js")(on, config);
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
swaggerBase: 'http://npm:81/api/schema',
|
||||||
|
},
|
||||||
|
baseUrl: 'http://npm:81',
|
||||||
|
}
|
||||||
|
});
|
@ -1,8 +1,7 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="Cypress" />
|
||||||
|
|
||||||
describe('Certificates endpoints', () => {
|
describe('Certificates endpoints', () => {
|
||||||
let token;
|
let token;
|
||||||
let certID;
|
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.getToken().then((tok) => {
|
cy.getToken().then((tok) => {
|
||||||
@ -25,54 +24,6 @@ describe('Certificates endpoints', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Custom certificate lifecycle', function() {
|
|
||||||
// Create custom cert
|
|
||||||
cy.task('backendApiPost', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/nginx/certificates',
|
|
||||||
data: {
|
|
||||||
provider: "other",
|
|
||||||
nice_name: "Test Certificate",
|
|
||||||
},
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('post', 201, '/nginx/certificates', data);
|
|
||||||
expect(data).to.have.property('id');
|
|
||||||
certID = data.id;
|
|
||||||
|
|
||||||
// Upload files
|
|
||||||
cy.task('backendApiPostFiles', {
|
|
||||||
token: token,
|
|
||||||
path: `/api/nginx/certificates/${certID}/upload`,
|
|
||||||
files: {
|
|
||||||
certificate: 'test.example.com.pem',
|
|
||||||
certificate_key: 'test.example.com-key.pem',
|
|
||||||
},
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('post', 200, '/nginx/certificates/{certID}/upload', data);
|
|
||||||
expect(data).to.have.property('certificate');
|
|
||||||
expect(data).to.have.property('certificate_key');
|
|
||||||
|
|
||||||
// Get all certs
|
|
||||||
cy.task('backendApiGet', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/nginx/certificates?expand=owner'
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('get', 200, '/nginx/certificates', data);
|
|
||||||
expect(data.length).to.be.greaterThan(0);
|
|
||||||
|
|
||||||
// Delete cert
|
|
||||||
cy.task('backendApiDelete', {
|
|
||||||
token: token,
|
|
||||||
path: `/api/nginx/certificates/${certID}`
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('delete', 200, '/nginx/certificates/{certID}', data);
|
|
||||||
expect(data).to.be.equal(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
|
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
token: token,
|
token: token,
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
/// <reference types="cypress" />
|
|
||||||
|
|
||||||
describe('Full Certificate Provisions', () => {
|
|
||||||
let token;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
cy.getToken().then((tok) => {
|
|
||||||
token = tok;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to create new http certificate', function() {
|
|
||||||
cy.task('backendApiPost', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/nginx/certificates',
|
|
||||||
data: {
|
|
||||||
domain_names: [
|
|
||||||
'website1.example.com'
|
|
||||||
],
|
|
||||||
meta: {
|
|
||||||
letsencrypt_email: 'admin@example.com',
|
|
||||||
letsencrypt_agree: true,
|
|
||||||
dns_challenge: false
|
|
||||||
},
|
|
||||||
provider: 'letsencrypt'
|
|
||||||
}
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('post', 201, '/nginx/certificates', data);
|
|
||||||
expect(data).to.have.property('id');
|
|
||||||
expect(data.id).to.be.greaterThan(0);
|
|
||||||
expect(data.provider).to.be.equal('letsencrypt');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should be able to create new DNS certificate with Powerdns', function() {
|
|
||||||
cy.task('backendApiPost', {
|
|
||||||
token: token,
|
|
||||||
path: '/api/nginx/certificates',
|
|
||||||
data: {
|
|
||||||
domain_names: [
|
|
||||||
'website2.example.com'
|
|
||||||
],
|
|
||||||
meta: {
|
|
||||||
letsencrypt_email: "admin@example.com",
|
|
||||||
dns_challenge: true,
|
|
||||||
dns_provider: 'powerdns',
|
|
||||||
dns_provider_credentials: 'dns_powerdns_api_url = http://ns1.pdns:8081\r\ndns_powerdns_api_key = npm',
|
|
||||||
letsencrypt_agree: true,
|
|
||||||
propagation_seconds: 5,
|
|
||||||
},
|
|
||||||
provider: 'letsencrypt'
|
|
||||||
}
|
|
||||||
}).then((data) => {
|
|
||||||
cy.validateSwaggerSchema('post', 201, '/nginx/certificates', data);
|
|
||||||
expect(data).to.have.property('id');
|
|
||||||
expect(data.id).to.be.greaterThan(0);
|
|
||||||
expect(data.provider).to.be.equal('letsencrypt');
|
|
||||||
expect(data.meta.dns_provider).to.be.equal('powerdns');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,4 +1,4 @@
|
|||||||
/// <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', function () {
|
||||||
@ -12,7 +12,7 @@ describe('Basic API checks', () => {
|
|||||||
|
|
||||||
it('Should return a valid schema payload', function () {
|
it('Should return a valid schema payload', function () {
|
||||||
cy.task('backendApiGet', {
|
cy.task('backendApiGet', {
|
||||||
path: '/api/schema?ts=' + Date.now(),
|
path: '/api/schema',
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
expect(data.openapi).to.be.equal('3.1.0');
|
expect(data.openapi).to.be.equal('3.1.0');
|
||||||
});
|
});
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user