Merge pull request #1 from jc21/master

update
This commit is contained in:
OhHeyAlan 2019-05-24 17:05:55 -05:00 committed by GitHub
commit 5bdb72ce19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 377 additions and 438 deletions

36
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,36 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Checklist**
- Have you pulled and found the error with `jc21/nginx-proxy-manager:latest` docker image?
- Are you sure you're not using someone else's docker image?
- If having problems with Lets Encrypt, have you made absolutely sure your site is accessible from outside of your network?
**Describe the bug**
- A clear and concise description of what the bug is.
- What version of Nginx Proxy Manager is reported on the login page?
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Operating System**
- Please specify if using a Rpi, Mac, orchestration tool or any other setups that might affect the reproduction of this error.
**Additional context**
Add any other context about the problem here, docker version, browser version if applicable to the problem. Too much info is better than too little.

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -2,7 +2,7 @@
# Nginx Proxy Manager # Nginx Proxy Manager
![Version](https://img.shields.io/badge/version-2.0.12-green.svg?style=for-the-badge) ![Version](https://img.shields.io/badge/version-2.0.13-green.svg?style=for-the-badge)
![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge)
![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge)

View file

@ -1,8 +1,8 @@
![Nginx Proxy Manager](https://public.jc21.com/nginx-proxy-manager/github.png "Nginx Proxy Manager") ![Nginx Proxy Manager](https://public.jc21.com/nginx-proxy-manager/github.png "Nginx Proxy Manager")
# Nginx Proxy Manager # [Nginx Proxy Manager](https://nginxproxymanager.jc21.com)
![Version](https://img.shields.io/badge/version-2.0.12-green.svg?style=for-the-badge) ![Version](https://img.shields.io/badge/version-2.0.13-green.svg?style=for-the-badge)
![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge)
![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge)
@ -15,16 +15,18 @@ running at home or otherwise, including free SSL, without having to know too muc
## Tags ## Tags
* latest 2, 2.x.x ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile)) * latest 2, 2.x.x ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile))
* latest-armhf, 2-armhf, 2.x.x-armhf ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile.armhf))
* latest-arm64, 2-arm64, 2.x.x-arm64 ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile.arm64)) * latest-arm64, 2-arm64, 2.x.x-arm64 ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile.arm64))
* 1, 1.x.x ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/1.1.2/Dockerfile)) * latest-arm7l, 2-arm7l, 2.x.x-arm7l ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/master/Dockerfile.arm7l))
* 1-armhf, 1.x.x-armhf ([Dockerfile](https://github.com/jc21/nginx-proxy-manager/blob/1.1.2/Dockerfile.armhf))
## Getting started ## Getting started
Please consult the [installation instructions](https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md) for a complete guide or Please consult the [installation instructions](https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md) for a complete guide or
if you just want to get up and running in the quickest time possible, grab all the files in the [doc/example/](https://github.com/jc21/nginx-proxy-manager/tree/master/doc/example) folder and run `docker-compose up -d` if you just want to get up and running in the quickest time possible, grab all the files in the [doc/example/](https://github.com/jc21/nginx-proxy-manager/tree/master/doc/example) folder and run:
```bash
docker-compose up -d
```
## Screenshots ## Screenshots

View file

@ -1,9 +1,13 @@
## Installation and Configuration ## Installation and Configuration
There's a few ways to configure this app depending on: If you just want to get up and running in the quickest time possible, grab all the files in
the [doc/example/](https://github.com/jc21/nginx-proxy-manager/tree/master/doc/example)
folder and run:
```bash
docker-compose up -d
```
- Whether you use `docker-compose` or vanilla docker
- Which architecture you're running it on (raspberry pi also supported - Testers wanted!)
### Configuration File ### Configuration File
@ -13,22 +17,22 @@ Don't worry, this is easy to do.
The app requires a configuration file to let it know what database you're using. The app requires a configuration file to let it know what database you're using.
Here's an example configuration for `mysql` (or mariadb): Here's an example configuration for `mysql` (or mariadb) that is compatible with the docker-compose example below:
```json ```json
{ {
"database": { "database": {
"engine": "mysql", "engine": "mysql",
"host": "127.0.0.1", "host": "db",
"name": "nginxproxymanager", "name": "npm",
"user": "nginxproxymanager", "user": "npm",
"password": "password123", "password": "npm",
"port": 3306 "port": 3306
} }
} }
``` ```
Once you've created your configuration file it's easy to mount it in the docker container, examples below. Once you've created your configuration file it's easy to mount it in the docker container.
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys **Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys
affect the login and session management of the application. If these keys change for any reason, all users will be logged out. affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
@ -36,37 +40,13 @@ affect the login and session management of the application. If these keys change
### Database ### Database
This app doesn't come with a database, you have to provide one yourself. Currently only `mysql/mariadb` is supported. This app doesn't come with a database, you have to provide one yourself. Currently only `mysql/mariadb` is supported for the minimum versions:
It's easy to use another docker container for your database also and link it as part of the docker stack. Here's an example: - MySQL v5.7.8+
- MariaDB v10.2.7+
```yml It's easy to use another docker container for your database also and link it as part of the docker stack, so that's what the following examples
version: "3" are going to use.
services:
app:
image: jc21/nginx-proxy-manager:latest
restart: always
ports:
- 80:80
- 81:81
- 443:443
volumes:
- ./config.json:/app/config/production.json
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
depends_on:
- db
db:
image: jc21/mariadb-aria
restart: always
environment:
MYSQL_ROOT_PASSWORD: "password123"
MYSQL_DATABASE: "nginxproxymanager"
MYSQL_USER: "nginxproxymanager"
MYSQL_PASSWORD: "password123"
volumes:
- ./data/mysql:/var/lib/mysql
```
### Running the App ### Running the App
@ -80,48 +60,51 @@ services:
image: jc21/nginx-proxy-manager:latest image: jc21/nginx-proxy-manager:latest
restart: always restart: always
ports: ports:
# Public HTTP Port:
- 80:80 - 80:80
- 81:81 # Public HTTPS Port:
- 443:443 - 443:443
# Admin Web Port:
- 81:81
volumes: volumes:
# Make sure this config.json file exists as per instructions above:
- ./config.json:/app/config/production.json - ./config.json:/app/config/production.json
- ./data:/data - ./data:/data
- ./letsencrypt:/etc/letsencrypt - ./letsencrypt:/etc/letsencrypt
depends_on:
- db
db:
image: mariadb
restart: always
environment:
MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm"
volumes:
- ./data/mysql:/var/lib/mysql
``` ```
Vanilla Docker: Then:
```bash ```bash
docker run -d \ docker-compose up -d
--name nginx-proxy-manager \
-p 80:80 \
-p 81:81 \
-p 443:443 \
-v /path/to/config.json:/app/config/production.json \
-v /path/to/data:/data \
-v /path/to/letsencrypt:/etc/letsencrypt \
jc21/nginx-proxy-manager:latest
``` ```
### Running on Raspberry PI / `armhf` ### Running on Raspberry PI / ARM devices
I have created `armhf` and `arm64` docker containers just for you. There may be issues with it, There are docker images for all versions of the Rasberry Pi with the exception of the really old `armv6l` versions.
if you have issues please report them here.
Note: Rpi v2 and below won't work with these images. The `latest` docker image is a manifest of all the different architecture docker builds supported, so this means
you don't have to worry about doing anything special and you can follow the common instructions above.
```bash Check out the [dockerhub tags](https://cloud.docker.com/repository/registry-1.docker.io/jc21/nginx-proxy-manager/tags)
docker run -d \ for a list of supported architectures and if you want one that doesn't exist,
--name nginx-proxy-manager-app \ [create a feature request](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
-p 80:80 \
-p 81:81 \ Also, if you don't know how to already, follow [this guide to install docker and docker-compose](https://manre-universe.net/how-to-run-docker-and-docker-compose-on-raspbian/)
-p 443:443 \ on Raspbian.
-v /path/to/config.json:/app/config/production.json \
-v /path/to/data:/data \
-v /path/to/letsencrypt:/etc/letsencrypt \
jc21/nginx-proxy-manager:latest-armhf
```
### Initial Run ### Initial Run
@ -162,4 +145,3 @@ value by specifying it as a Docker environment variable. The default if not spec
``` ```
... -e "X_FRAME_OPTIONS=sameorigin" ... ... -e "X_FRAME_OPTIONS=sameorigin" ...
``` ```

View file

@ -2,9 +2,9 @@
"database": { "database": {
"engine": "mysql", "engine": "mysql",
"host": "db", "host": "db",
"name": "nginxproxymanager", "name": "npm",
"user": "nginxproxymanager", "user": "npm",
"password": "password123", "password": "npm",
"port": 3306 "port": 3306
} }
} }

View file

@ -1,7 +1,7 @@
version: "3" version: "3"
services: services:
app: app:
image: jc21/nginx-proxy-manager:2 image: jc21/nginx-proxy-manager:latest
restart: always restart: always
ports: ports:
- 80:80 - 80:80
@ -17,12 +17,12 @@ services:
# if you want pretty colors in your docker logs: # if you want pretty colors in your docker logs:
- FORCE_COLOR=1 - FORCE_COLOR=1
db: db:
image: jc21/mariadb-aria image: mariadb:latest
restart: always restart: always
environment: environment:
MYSQL_ROOT_PASSWORD: "password123" MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "nginxproxymanager" MYSQL_DATABASE: "npm"
MYSQL_USER: "nginxproxymanager" MYSQL_USER: "npm"
MYSQL_PASSWORD: "password123" MYSQL_PASSWORD: "npm"
volumes: volumes:
- ./data/mysql:/var/lib/mysql - ./data/mysql:/var/lib/mysql

View file

@ -4,9 +4,9 @@ services:
app: app:
image: jc21/nginx-proxy-manager-base:latest image: jc21/nginx-proxy-manager-base:latest
ports: ports:
- 8080:80 - 80:80
- 8081:81 - 81:81
- 8443:443 - 43:443
environment: environment:
- NODE_ENV=development - NODE_ENV=development
- FORCE_COLOR=1 - FORCE_COLOR=1
@ -22,7 +22,7 @@ services:
- db - db
command: node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js command: node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js
db: db:
image: mariadb:10.3.7 image: jc21/mariadb-aria
environment: environment:
MYSQL_ROOT_PASSWORD: "npm" MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "npm" MYSQL_DATABASE: "npm"

View file

@ -1,6 +1,6 @@
{ {
"name": "nginx-proxy-manager", "name": "nginx-proxy-manager",
"version": "2.0.12", "version": "2.0.13",
"description": "A beautiful interface for creating Nginx endpoints", "description": "A beautiful interface for creating Nginx endpoints",
"main": "src/backend/index.js", "main": "src/backend/index.js",
"devDependencies": { "devDependencies": {
@ -28,7 +28,7 @@
"numeral": "^2.0.6", "numeral": "^2.0.6",
"sass-loader": "^7.0.3", "sass-loader": "^7.0.3",
"style-loader": "^0.22.1", "style-loader": "^0.22.1",
"tabler-ui": "git+https://github.com/tabler/tabler.git", "tabler-ui": "git+https://github.com/tabler/tabler.git#00f78ad823311bc3ad974ac3e5b0126198f0a813",
"underscore": "^1.8.3", "underscore": "^1.8.3",
"webpack": "^4.25.1", "webpack": "^4.25.1",
"webpack-cli": "^3.1.2", "webpack-cli": "^3.1.2",

View file

@ -2,8 +2,8 @@ ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m; ssl_session_cache shared:SSL:50m;
# intermediate configuration. tweak to your needs. # intermediate configuration. tweak to your needs.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE- ssl_ciphers 'EECDH+AESGCM:AES256+EECDH:AES256+EDH:EDH+AESGCM:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-
ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AE ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AE
S128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; S128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES';
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;

View file

@ -1,5 +1,3 @@
'use strict';
const path = require('path'); const path = require('path');
const express = require('express'); const express = require('express');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
@ -48,7 +46,7 @@ app.use(function (req, res, next) {
res.set({ res.set({
'Strict-Transport-Security': 'includeSubDomains; max-age=631138519; preload', 'Strict-Transport-Security': 'includeSubDomains; max-age=631138519; preload',
'X-XSS-Protection': '0', 'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff', 'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': x_frame_options, 'X-Frame-Options': x_frame_options,
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',

View file

@ -1,5 +1,3 @@
'use strict';
const config = require('config'); const config = require('config');
if (!config.has('database')) { if (!config.has('database')) {

View file

@ -1,10 +1,8 @@
'use strict';
const fs = require('fs'); const fs = require('fs');
const logger = require('./logger').import; const logger = require('./logger').import;
const utils = require('./lib/utils'); const utils = require('./lib/utils');
const batchflow = require('batchflow'); const batchflow = require('batchflow');
const debug_mode = process.env.NODE_ENV !== 'production'; const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
const internalProxyHost = require('./internal/proxy-host'); const internalProxyHost = require('./internal/proxy-host');
const internalRedirectionHost = require('./internal/redirection-host'); const internalRedirectionHost = require('./internal/redirection-host');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const fs = require('fs'); const fs = require('fs');
const batchflow = require('batchflow'); const batchflow = require('batchflow');

View file

@ -1,5 +1,3 @@
'use strict';
const error = require('../lib/error'); const error = require('../lib/error');
const auditLogModel = require('../models/audit-log'); const auditLogModel = require('../models/audit-log');
@ -46,9 +44,9 @@ const internalAuditLog = {
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {String} data.action * @param {String} data.action
* @param {Integer} [data.user_id] * @param {Number} [data.user_id]
* @param {Integer} [data.object_id] * @param {Number} [data.object_id]
* @param {Integer} [data.object_type] * @param {Number} [data.object_type]
* @param {Object} [data.meta] * @param {Object} [data.meta]
* @returns {Promise} * @returns {Promise}
*/ */

View file

@ -1,5 +1,3 @@
'use strict';
const fs = require('fs'); const fs = require('fs');
const _ = require('lodash'); const _ = require('lodash');
const logger = require('../logger').ssl; const logger = require('../logger').ssl;
@ -9,19 +7,20 @@ const internalAuditLog = require('./audit-log');
const tempWrite = require('temp-write'); const tempWrite = require('temp-write');
const utils = require('../lib/utils'); const utils = require('../lib/utils');
const moment = require('moment'); const moment = require('moment');
const debug_mode = process.env.NODE_ENV !== 'production'; const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
const le_staging = process.env.NODE_ENV !== 'production';
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
const internalHost = require('./host'); const internalHost = require('./host');
const certbot_command = '/usr/bin/certbot'; const certbot_command = '/usr/bin/certbot';
function omissions () { function omissions() {
return ['is_deleted']; return ['is_deleted'];
} }
const internalCertificate = { const internalCertificate = {
allowed_ssl_files: ['certificate', 'certificate_key', 'intermediate_certificate'], allowed_ssl_files: ['certificate', 'certificate_key', 'intermediate_certificate'],
interval_timeout: 1000 * 60 * 60 * 12, // 12 hours interval_timeout: 1000 * 60 * 60, // 1 hour
interval: null, interval: null,
interval_processing: false, interval_processing: false,
@ -38,7 +37,7 @@ const internalCertificate = {
internalCertificate.interval_processing = true; internalCertificate.interval_processing = true;
logger.info('Renewing SSL certs close to expiry...'); logger.info('Renewing SSL certs close to expiry...');
return utils.exec(certbot_command + ' renew -q ' + (debug_mode ? '--staging' : '')) return utils.exec(certbot_command + ' renew -q ' + (le_staging ? '--staging' : ''))
.then(result => { .then(result => {
logger.info(result); logger.info(result);
@ -205,7 +204,7 @@ const internalCertificate = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {String} [data.email] * @param {String} [data.email]
* @param {String} [data.name] * @param {String} [data.name]
* @return {Promise} * @return {Promise}
@ -251,7 +250,7 @@ const internalCertificate = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {Array} [data.expand] * @param {Array} [data.expand]
* @param {Array} [data.omit] * @param {Array} [data.omit]
* @return {Promise} * @return {Promise}
@ -297,7 +296,7 @@ const internalCertificate = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {String} [data.reason] * @param {String} [data.reason]
* @returns {Promise} * @returns {Promise}
*/ */
@ -381,7 +380,7 @@ const internalCertificate = {
/** /**
* Report use * Report use
* *
* @param {Integer} user_id * @param {Number} user_id
* @param {String} visibility * @param {String} visibility
* @returns {Promise} * @returns {Promise}
*/ */
@ -522,7 +521,7 @@ const internalCertificate = {
/** /**
* @param {Access} access * @param {Access} access
* @param {Object} data * @param {Object} data
* @param {Integer} data.id * @param {Number} data.id
* @param {Object} data.files * @param {Object} data.files
* @returns {Promise} * @returns {Promise}
*/ */
@ -719,9 +718,9 @@ const internalCertificate = {
let cmd = certbot_command + ' certonly --cert-name "npm-' + certificate.id + '" --agree-tos ' + let cmd = certbot_command + ' certonly --cert-name "npm-' + certificate.id + '" --agree-tos ' +
'--email "' + certificate.meta.letsencrypt_email + '" ' + '--email "' + certificate.meta.letsencrypt_email + '" ' +
'--preferred-challenges "http" ' + '--preferred-challenges "dns,http" ' +
'-n -a webroot -d "' + certificate.domain_names.join(',') + '" ' + '-n -a webroot -d "' + certificate.domain_names.join(',') + '" ' +
(debug_mode ? '--staging' : ''); (le_staging ? '--staging' : '');
if (debug_mode) { if (debug_mode) {
logger.info('Command:', cmd); logger.info('Command:', cmd);
@ -734,6 +733,48 @@ const internalCertificate = {
}); });
}, },
/**
* @param {Access} access
* @param {Object} data
* @param {Number} data.id
* @returns {Promise}
*/
renew: (access, data) => {
return access.can('certificates:update', data)
.then(() => {
return internalCertificate.get(access, data);
})
.then((certificate) => {
if (certificate.provider === 'letsencrypt') {
return internalCertificate.renewLetsEncryptSsl(certificate)
.then(() => {
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
})
.then(cert_info => {
return certificateModel
.query()
.patchAndFetchById(certificate.id, {
expires_on: certificateModel.raw('FROM_UNIXTIME(' + cert_info.dates.to + ')')
});
})
.then((updated_certificate) => {
// Add to audit log
return internalAuditLog.add(access, {
action: 'renewed',
object_type: 'certificate',
object_id: updated_certificate.id,
meta: updated_certificate
})
.then(() => {
return updated_certificate;
});
})
} else {
throw new error.ValidationError('Only Let\'sEncrypt certificates can be renewed');
}
})
},
/** /**
* @param {Object} certificate the certificate row * @param {Object} certificate the certificate row
* @returns {Promise} * @returns {Promise}
@ -741,7 +782,7 @@ const internalCertificate = {
renewLetsEncryptSsl: certificate => { renewLetsEncryptSsl: certificate => {
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(', '));
let cmd = certbot_command + ' renew -n --force-renewal --disable-hook-validation --cert-name "npm-' + certificate.id + '" ' + (debug_mode ? '--staging' : ''); let cmd = certbot_command + ' renew -n --force-renewal --disable-hook-validation --cert-name "npm-' + certificate.id + '" ' + (le_staging ? '--staging' : '');
if (debug_mode) { if (debug_mode) {
logger.info('Command:', cmd); logger.info('Command:', cmd);
@ -762,17 +803,29 @@ const internalCertificate = {
revokeLetsEncryptSsl: (certificate, throw_errors) => { revokeLetsEncryptSsl: (certificate, throw_errors) => {
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(', '));
let cmd = certbot_command + ' revoke --cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' + (debug_mode ? '--staging' : ''); let revoke_cmd = certbot_command + ' revoke --cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' + (le_staging ? '--staging' : '');
let delete_cmd = certbot_command + ' delete --cert-name "npm-' + certificate.id + '" ' + (le_staging ? '--staging' : '');
if (debug_mode) { if (debug_mode) {
logger.info('Command:', cmd); logger.info('Command:', revoke_cmd);
} }
return utils.exec(cmd) return utils.exec(revoke_cmd)
.then(result => { .then((result) => {
logger.info(result); logger.info(result);
return result; return result;
}) })
.then(() => {
if (debug_mode) {
logger.info('Command:', delete_cmd);
}
return utils.exec(delete_cmd)
.then((result) => {
logger.info(result);
return result;
})
})
.catch(err => { .catch(err => {
if (debug_mode) { if (debug_mode) {
logger.error(err.message); logger.error(err.message);
@ -796,7 +849,7 @@ const internalCertificate = {
/** /**
* @param {Object} in_use_result * @param {Object} in_use_result
* @param {Integer} in_use_result.total_count * @param {Number} in_use_result.total_count
* @param {Array} in_use_result.proxy_hosts * @param {Array} in_use_result.proxy_hosts
* @param {Array} in_use_result.redirection_hosts * @param {Array} in_use_result.redirection_hosts
* @param {Array} in_use_result.dead_hosts * @param {Array} in_use_result.dead_hosts
@ -826,7 +879,7 @@ const internalCertificate = {
/** /**
* @param {Object} in_use_result * @param {Object} in_use_result
* @param {Integer} in_use_result.total_count * @param {Number} in_use_result.total_count
* @param {Array} in_use_result.proxy_hosts * @param {Array} in_use_result.proxy_hosts
* @param {Array} in_use_result.redirection_hosts * @param {Array} in_use_result.redirection_hosts
* @param {Array} in_use_result.dead_hosts * @param {Array} in_use_result.dead_hosts

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const deadHostModel = require('../models/dead_host'); const deadHostModel = require('../models/dead_host');

View file

@ -1,8 +1,5 @@
'use strict';
const https = require('https'); const https = require('https');
const fs = require('fs'); const fs = require('fs');
const _ = require('lodash');
const logger = require('../logger').ip_ranges; const logger = require('../logger').ip_ranges;
const error = require('../lib/error'); const error = require('../lib/error');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');

View file

@ -4,7 +4,7 @@ const Liquid = require('liquidjs');
const logger = require('../logger').nginx; const logger = require('../logger').nginx;
const utils = require('../lib/utils'); const utils = require('../lib/utils');
const error = require('../lib/error'); const error = require('../lib/error');
const debug_mode = process.env.NODE_ENV !== 'production'; const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
const internalNginx = { const internalNginx = {
@ -162,7 +162,7 @@ const internalNginx = {
renderedLocations += await renderer.parseAndRender(template, locationCopy); renderedLocations += await renderer.parseAndRender(template, locationCopy);
} }
} };
locationRendering().then(() => resolve(renderedLocations)); locationRendering().then(() => resolve(renderedLocations));
}); });
@ -211,6 +211,14 @@ const internalNginx = {
locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => { locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => {
host.locations = renderedLocations; host.locations = renderedLocations;
}); });
// Allow someone who is using / custom location path to use it, and skip the default / location
_.map(host.locations, (location) => {
if (location.path === '/') {
host.use_default_location = false;
}
});
} else { } else {
locationsPromise = Promise.resolve(); locationsPromise = Promise.resolve();
} }

View file

@ -25,7 +25,7 @@ const internalProxyHost = {
} }
return access.can('proxy_hosts:create', data) return access.can('proxy_hosts:create', data)
.then(access_data => { .then(() => {
// Get a list of the domain names and check each of them against existing records // Get a list of the domain names and check each of them against existing records
let domain_name_check_promises = []; let domain_name_check_promises = [];
@ -52,7 +52,7 @@ const internalProxyHost = {
.omit(omissions()) .omit(omissions())
.insertAndFetch(data); .insertAndFetch(data);
}) })
.then(row => { .then((row) => {
if (create_certificate) { if (create_certificate) {
return internalCertificate.createQuickCertificate(access, data) return internalCertificate.createQuickCertificate(access, data)
.then(cert => { .then(cert => {
@ -69,21 +69,21 @@ const internalProxyHost = {
return row; return row;
} }
}) })
.then(row => { .then((row) => {
// re-fetch with cert // re-fetch with cert
return internalProxyHost.get(access, { return internalProxyHost.get(access, {
id: row.id, id: row.id,
expand: ['certificate', 'owner', 'access_list'] expand: ['certificate', 'owner', 'access_list']
}); });
}) })
.then(row => { .then((row) => {
// Configure nginx // Configure nginx
return internalNginx.configure(proxyHostModel, 'proxy_host', row) return internalNginx.configure(proxyHostModel, 'proxy_host', row)
.then(() => { .then(() => {
return row; return row;
}); });
}) })
.then(row => { .then((row) => {
// Audit log // Audit log
data.meta = _.assign({}, data.meta || {}, row.meta); data.meta = _.assign({}, data.meta || {}, row.meta);

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const redirectionHostModel = require('../models/redirection_host'); const redirectionHostModel = require('../models/redirection_host');

View file

@ -1,5 +1,3 @@
'use strict';
const internalProxyHost = require('./proxy-host'); const internalProxyHost = require('./proxy-host');
const internalRedirectionHost = require('./redirection-host'); const internalRedirectionHost = require('./redirection-host');
const internalDeadHost = require('./dead-host'); const internalDeadHost = require('./dead-host');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const streamModel = require('../models/stream'); const streamModel = require('../models/stream');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const userModel = require('../models/user'); const userModel = require('../models/user');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../lib/error'); const error = require('../lib/error');
const userModel = require('../models/user'); const userModel = require('../models/user');

View file

@ -1,5 +1,3 @@
'use strict';
/** /**
* Some Notes: This is a friggin complicated piece of code. * Some Notes: This is a friggin complicated piece of code.
* *

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const util = require('util'); const util = require('util');

View file

@ -1,5 +1,3 @@
'use strict';
const validator = require('../validator'); const validator = require('../validator');
module.exports = function (req, res, next) { module.exports = function (req, res, next) {

View file

@ -1,5 +1,3 @@
'use strict';
const Access = require('../access'); const Access = require('../access');
module.exports = () => { module.exports = () => {

View file

@ -1,5 +1,3 @@
'use strict';
module.exports = function () { module.exports = function () {
return function (req, res, next) { return function (req, res, next) {
if (req.headers.authorization) { if (req.headers.authorization) {

View file

@ -1,5 +1,3 @@
'use strict';
let _ = require('lodash'); let _ = require('lodash');
module.exports = function (default_sort, default_offset, default_limit, max_limit) { module.exports = function (default_sort, default_offset, default_limit, max_limit) {

View file

@ -1,5 +1,3 @@
'use strict';
module.exports = (req, res, next) => { module.exports = (req, res, next) => {
if (req.params.user_id === 'me' && res.locals.access) { if (req.params.user_id === 'me' && res.locals.access) {
req.params.user_id = res.locals.access.token.get('attrs').id; req.params.user_id = res.locals.access.token.get('attrs').id;

View file

@ -1,7 +1,4 @@
'use strict';
const moment = require('moment'); const moment = require('moment');
const _ = require('lodash');
module.exports = { module.exports = {

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'identifier_for_migrate'; const migrate_name = 'identifier_for_migrate';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const exec = require('child_process').exec; const exec = require('child_process').exec;
module.exports = { module.exports = {

View file

@ -1,5 +1,3 @@
'use strict';
const error = require('../error'); const error = require('../error');
const path = require('path'); const path = require('path');
const parser = require('json-schema-ref-parser'); const parser = require('json-schema-ref-parser');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const error = require('../error'); const error = require('../error');
const definitions = require('../../schema/definitions.json'); const definitions = require('../../schema/definitions.json');

View file

@ -1,5 +1,3 @@
'use strict';
const db = require('./db'); const db = require('./db');
const logger = require('./logger').migrate; const logger = require('./logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'initial-schema'; const migrate_name = 'initial-schema';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'websockets'; const migrate_name = 'websockets';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'forward_host'; const migrate_name = 'forward_host';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'http2_support'; const migrate_name = 'http2_support';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'forward_scheme'; const migrate_name = 'forward_scheme';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'disabled'; const migrate_name = 'disabled';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'custom_locations'; const migrate_name = 'custom_locations';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,5 +1,3 @@
'use strict';
const migrate_name = 'hsts'; const migrate_name = 'hsts';
const logger = require('../logger').migrate; const logger = require('../logger').migrate;

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt');
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');

View file

@ -3,8 +3,6 @@
and then has abilities after that. and then has abilities after that.
*/ */
'use strict';
const _ = require('lodash'); const _ = require('lodash');
const config = require('config'); const config = require('config');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const UserPermission = require('./user_permission'); const UserPermission = require('./user_permission');

View file

@ -1,8 +1,6 @@
// Objection Docs: // Objection Docs:
// http://vincit.github.io/objection.js/ // http://vincit.github.io/objection.js/
'use strict';
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../lib/validator'); const validator = require('../../lib/validator');
const jwtdecode = require('../../lib/express/jwt-decode'); const jwtdecode = require('../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const pjson = require('../../../../package.json'); const pjson = require('../../../../package.json');
const error = require('../../lib/error'); const error = require('../../lib/error');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');
@ -181,6 +179,34 @@ router
} }
}); });
/**
* Renew LE Certs
*
* /api/nginx/certificates/123/renew
*/
router
.route('/:certificate_id/renew')
.options((req, res) => {
res.sendStatus(204);
})
.all(jwtdecode())
/**
* POST /api/nginx/certificates/123/renew
*
* Renew certificate
*/
.post((req, res, next) => {
internalCertificate.renew(res.locals.access, {
id: parseInt(req.params.certificate_id, 10)
})
.then(result => {
res.status(200)
.send(result);
})
.catch(next);
});
/** /**
* Validate Certs before saving * Validate Certs before saving
* *

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../../lib/validator'); const validator = require('../../../lib/validator');
const jwtdecode = require('../../../lib/express/jwt-decode'); const jwtdecode = require('../../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const jwtdecode = require('../../lib/express/jwt-decode'); const jwtdecode = require('../../lib/express/jwt-decode');
const internalReport = require('../../internal/report'); const internalReport = require('../../internal/report');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const jwtdecode = require('../../lib/express/jwt-decode'); const jwtdecode = require('../../lib/express/jwt-decode');
const internalToken = require('../../internal/token'); const internalToken = require('../../internal/token');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const validator = require('../../lib/validator'); const validator = require('../../lib/validator');
const jwtdecode = require('../../lib/express/jwt-decode'); const jwtdecode = require('../../lib/express/jwt-decode');

View file

@ -1,5 +1,3 @@
'use strict';
const express = require('express'); const express = require('express');
const fs = require('fs'); const fs = require('fs');
const PACKAGE = require('../../../package.json'); const PACKAGE = require('../../../package.json');

View file

@ -1,5 +1,3 @@
'use strict';
const fs = require('fs'); const fs = require('fs');
const NodeRSA = require('node-rsa'); const NodeRSA = require('node-rsa');
const config = require('config'); const config = require('config');
@ -7,7 +5,7 @@ const logger = require('./logger').setup;
const userModel = require('./models/user'); const userModel = require('./models/user');
const userPermissionModel = require('./models/user_permission'); const userPermissionModel = require('./models/user_permission');
const authModel = require('./models/auth'); const authModel = require('./models/auth');
const debug_mode = process.env.NODE_ENV !== 'production'; const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
module.exports = function () { module.exports = function () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View file

@ -1,5 +1,3 @@
'use strict';
const $ = require('jquery'); const $ = require('jquery');
const _ = require('underscore'); const _ = require('underscore');
const Tokens = require('./tokens'); const Tokens = require('./tokens');
@ -35,7 +33,7 @@ ApiError.prototype = Object.create(Error.prototype, {
* @param {Object} [options] * @param {Object} [options]
* @returns {Promise} * @returns {Promise}
*/ */
function fetch (verb, path, data, options) { function fetch(verb, path, data, options) {
options = options || {}; options = options || {};
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
@ -55,7 +53,7 @@ function fetch (verb, path, data, options) {
contentType: options.contentType || 'application/json; charset=UTF-8', contentType: options.contentType || 'application/json; charset=UTF-8',
processData: options.processData || true, processData: options.processData || true,
crossDomain: true, crossDomain: true,
timeout: options.timeout ? options.timeout : 15000, timeout: options.timeout ? options.timeout : 30000,
xhrFields: { xhrFields: {
withCredentials: true withCredentials: true
}, },
@ -99,7 +97,7 @@ function fetch (verb, path, data, options) {
* @param {Array} expand * @param {Array} expand
* @returns {String} * @returns {String}
*/ */
function makeExpansionString (expand) { function makeExpansionString(expand) {
let items = []; let items = [];
_.forEach(expand, function (exp) { _.forEach(expand, function (exp) {
items.push(encodeURIComponent(exp)); items.push(encodeURIComponent(exp));
@ -114,7 +112,7 @@ function makeExpansionString (expand) {
* @param {String} [query] * @param {String} [query]
* @returns {Promise} * @returns {Promise}
*/ */
function getAllObjects (path, expand, query) { function getAllObjects(path, expand, query) {
let params = []; let params = [];
if (typeof expand === 'object' && expand !== null && expand.length) { if (typeof expand === 'object' && expand !== null && expand.length) {
@ -128,20 +126,7 @@ function getAllObjects (path, expand, query) {
return fetch('get', path + (params.length ? '?' + params.join('&') : '')); return fetch('get', path + (params.length ? '?' + params.join('&') : ''));
} }
/** function FileUpload(path, fd) {
* @param {String} path
* @param {FormData} form_data
* @returns {Promise}
*/
function upload (path, form_data) {
console.log('UPLOAD:', path, form_data);
return fetch('post', path, form_data, {
contentType: 'multipart/form-data',
processData: false
});
}
function FileUpload (path, fd) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
let token = Tokens.getTopToken(); let token = Tokens.getTopToken();
@ -214,7 +199,7 @@ module.exports = {
Users: { Users: {
/** /**
* @param {Integer|String} user_id * @param {Number|String} user_id
* @param {Array} [expand] * @param {Array} [expand]
* @returns {Promise} * @returns {Promise}
*/ */
@ -639,6 +624,14 @@ module.exports = {
*/ */
validate: function (form_data) { validate: function (form_data) {
return FileUpload('nginx/certificates/validate', form_data); return FileUpload('nginx/certificates/validate', form_data);
},
/**
* @param {Number} id
* @returns {Promise}
*/
renew: function (id) {
return fetch('post', 'nginx/certificates/' + id + '/renew');
} }
} }
}, },

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const Controller = require('../../controller'); const Controller = require('../../controller');
const template = require('./item.ejs'); const template = require('./item.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const ItemView = require('./item'); const ItemView = require('./item');
const template = require('./main.ejs'); const template = require('./main.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../main'); const App = require('../main');
const AuditLogModel = require('../../models/audit-log'); const AuditLogModel = require('../../models/audit-log');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const template = require('./meta.ejs'); const template = require('./meta.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const UserModel = require('../models/user'); const UserModel = require('../models/user');
let cache = { let cache = {

View file

@ -1,5 +1,3 @@
'use strict';
const Backbone = require('backbone'); const Backbone = require('backbone');
const Cache = require('./cache'); const Cache = require('./cache');
const Tokens = require('./tokens'); const Tokens = require('./tokens');
@ -342,6 +340,19 @@ module.exports = {
} }
}, },
/**
* Certificate Renew
*
* @param model
*/
showNginxCertificateRenew: function (model) {
if (Cache.User.isAdmin() || Cache.User.canManage('certificates')) {
require(['./main', './nginx/certificates/renew'], function (App, View) {
App.UI.showModalDialog(new View({model: model}));
});
}
},
/** /**
* Certificate Delete Confirm * Certificate Delete Confirm
* *

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const Cache = require('../cache'); const Cache = require('../cache');
const Controller = require('../controller'); const Controller = require('../controller');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const template = require('./main.ejs'); const template = require('./main.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const template = require('./main.ejs'); const template = require('./main.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const template = require('./main.ejs'); const template = require('./main.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Cache = ('./cache'); const Cache = ('./cache');
const messages = require('../i18n/messages.json'); const messages = require('../i18n/messages.json');

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('underscore'); const _ = require('underscore');
const Backbone = require('backbone'); const Backbone = require('backbone');
const Mn = require('../lib/marionette'); const Mn = require('../lib/marionette');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const template = require('./delete.ejs'); const template = require('./delete.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const AccessListModel = require('../../../models/access-list'); const AccessListModel = require('../../../models/access-list');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const template = require('./item.ejs'); const template = require('./item.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../../main'); const App = require('../../../main');
const template = require('./item.ejs'); const template = require('./item.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../../main'); const App = require('../../../main');
const ItemView = require('./item'); const ItemView = require('./item');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const AccessListModel = require('../../../models/access-list'); const AccessListModel = require('../../../models/access-list');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const template = require('./delete.ejs'); const template = require('./delete.ejs');
@ -16,7 +14,6 @@ module.exports = Mn.View.extend({
}, },
events: { events: {
'click @ui.save': function (e) { 'click @ui.save': function (e) {
e.preventDefault(); e.preventDefault();

View file

@ -1,5 +1,3 @@
'use strict';
const _ = require('underscore'); const _ = require('underscore');
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');

View file

@ -5,16 +5,23 @@
</td> </td>
<td> <td>
<div> <div>
<% if (provider === 'letsencrypt') { %> <%
<% domain_names.map(function(host) { if (provider === 'letsencrypt') {
domain_names.map(function(host) {
if (host.indexOf('*') === -1) {
%>
<span class="tag host-link hover-pink" rel="https://<%- host %>"><%- host %></span>
<%
} else {
%> %>
<span class="tag"><%- host %></span> <span class="tag"><%- host %></span>
<% <%
}
}); });
} else {
%><%- nice_name %><%
}
%> %>
<% } else { %>
<%- nice_name %>
<% } %>
</div> </div>
<div class="small text-muted"> <div class="small text-muted">
<%- i18n('str', 'created-on', {date: formatDbDate(created_on, 'Do MMMM YYYY')}) %> <%- i18n('str', 'created-on', {date: formatDbDate(created_on, 'Do MMMM YYYY')}) %>
@ -31,6 +38,10 @@
<div class="item-action dropdown"> <div class="item-action dropdown">
<a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a> <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
<div class="dropdown-menu dropdown-menu-right"> <div class="dropdown-menu dropdown-menu-right">
<% if (provider === 'letsencrypt') { %>
<a href="#" class="renew dropdown-item"><i class="dropdown-icon fe fe-refresh-cw"></i> <%- i18n('certificates', 'force-renew') %></a>
<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>
</div> </div>
</div> </div>

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const moment = require('moment'); const moment = require('moment');
const App = require('../../../main'); const App = require('../../../main');
@ -10,13 +8,26 @@ module.exports = Mn.View.extend({
tagName: 'tr', tagName: 'tr',
ui: { ui: {
host_link: '.host-link',
renew: 'a.renew',
delete: 'a.delete' delete: 'a.delete'
}, },
events: { events: {
'click @ui.renew': function (e) {
e.preventDefault();
App.Controller.showNginxCertificateRenew(this.model);
},
'click @ui.delete': function (e) { 'click @ui.delete': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showNginxCertificateDeleteConfirm(this.model); App.Controller.showNginxCertificateDeleteConfirm(this.model);
},
'click @ui.host_link': function (e) {
e.preventDefault();
let win = window.open($(e.currentTarget).attr('rel'), '_blank');
win.focus();
} }
}, },

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../../main'); const App = require('../../../main');
const ItemView = require('./item'); const ItemView = require('./item');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const CertificateModel = require('../../../models/certificate'); const CertificateModel = require('../../../models/certificate');

View file

@ -0,0 +1,14 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><%- i18n('certificates', 'renew-title') %></h5>
</div>
<div class="modal-body">
<div class="waiting text-center">
<%= i18n('str', 'please-wait') %>
</div>
<div class="alert alert-danger error" role="alert"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal" disabled><%- i18n('str', 'close') %></button>
</div>
</div>

View file

@ -0,0 +1,31 @@
const Mn = require('backbone.marionette');
const App = require('../../main');
const template = require('./renew.ejs');
module.exports = Mn.View.extend({
template: template,
className: 'modal-dialog',
ui: {
waiting: '.waiting',
error: '.error',
close: 'button.cancel'
},
onRender: function () {
this.ui.error.hide();
App.Api.Nginx.Certificates.renew(this.model.get('id'))
.then((result) => {
this.model.set(result);
setTimeout(() => {
App.UI.closeModal();
}, 1000);
})
.catch((err) => {
this.ui.waiting.hide();
this.ui.error.text(err.message).show();
this.ui.close.prop('disabled', false);
});
}
});

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const template = require('./delete.ejs'); const template = require('./delete.ejs');

View file

@ -1,5 +1,3 @@
'use strict';
const Mn = require('backbone.marionette'); const Mn = require('backbone.marionette');
const App = require('../../main'); const App = require('../../main');
const DeadHostModel = require('../../../models/dead-host'); const DeadHostModel = require('../../../models/dead-host');

Some files were not shown because too many files have changed in this diff Show more