Sfoglia il codice sorgente

Merge pull request #1111 from jc21/develop

v2.9.3
jc21 4 anni fa
parent
commit
92eec95dad
37 ha cambiato i file con 346 aggiunte e 122 eliminazioni
  1. 23 9
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 18 0
      .github/ISSUE_TEMPLATE/dns_challenge_request.md
  3. 13 6
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 1 1
      .version
  5. 79 2
      README.md
  6. 0 72
      docs/README.md
  7. 1 1
      docs/package.json
  8. 60 6
      docs/setup/README.md
  9. 18 4
      docs/yarn.lock
  10. 0 1
      frontend/fonts
  11. 1 0
      frontend/fonts/feather
  12. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff
  13. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff2
  14. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff
  15. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff2
  16. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff
  17. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff2
  18. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff
  19. BIN
      frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff2
  20. 0 1
      frontend/html/partials/header.ejs
  21. 1 0
      frontend/js/app/nginx/access/list/item.ejs
  22. 10 1
      frontend/js/app/nginx/certificates/form.js
  23. 1 0
      frontend/js/app/nginx/certificates/list/item.ejs
  24. 1 0
      frontend/js/app/nginx/dead/list/item.ejs
  25. 1 0
      frontend/js/app/nginx/proxy/list/item.ejs
  26. 1 0
      frontend/js/app/nginx/redirection/list/item.ejs
  27. 1 0
      frontend/js/app/nginx/stream/list/item.ejs
  28. 2 1
      frontend/js/app/user/password.ejs
  29. 20 9
      frontend/js/app/user/password.js
  30. 1 0
      frontend/js/app/users/list/item.ejs
  31. 1 1
      frontend/js/i18n/messages.json
  32. 4 0
      frontend/scss/custom.scss
  33. 39 0
      frontend/scss/fonts.scss
  34. 1 0
      frontend/scss/styles.scss
  35. 13 1
      frontend/webpack.config.js
  36. 3 3
      frontend/yarn.lock
  37. 32 3
      global/certbot-dns-plugins.js

+ 23 - 9
.github/ISSUE_TEMPLATE/bug_report.md

@@ -6,20 +6,30 @@ labels: bug
 assignees: ''
 
 ---
-
-**Are you in the right place?**
+<!--
+ 
+Are you in the right place?
 - If you are looking for support on how to get your upstream server forwarding, please consider asking the community on Reddit.
 - If you are writing code changes to contribute and need to ask about the internals of the software, Gitter is the best place to ask.
 - If you think you found a bug with NPM (not Nginx, or your upstream server or MySql) then you are in the *right place.*
 
+-->
+
 **Checklist**
 - Have you pulled and found the error with `jc21/nginx-proxy-manager:latest` docker image?
+  - Yes / No
 - 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?
+  - Yes / No
+- Have you searched for similar issues (both open and closed)?
+  - Yes / No
 
 **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?
+<!-- A clear and concise description of what the bug is. -->
+
+
+**Nginx Proxy Manager Version**
+<!-- What version of Nginx Proxy Manager is reported on the login page? -->
+
 
 **To Reproduce**
 Steps to reproduce the behavior:
@@ -28,14 +38,18 @@ Steps to reproduce the behavior:
 3. Scroll down to '....'
 4. See error
 
+
 **Expected behavior**
-A clear and concise description of what you expected to happen.
+<!-- A clear and concise description of what you expected to happen. -->
+
 
 **Screenshots**
-If applicable, add screenshots to help explain your problem.
+<!-- 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.
+<!-- 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.
+<!-- Add any other context about the problem here, docker version, browser version, logs if applicable to the problem. Too much info is better than too little. -->

+ 18 - 0
.github/ISSUE_TEMPLATE/dns_challenge_request.md

@@ -0,0 +1,18 @@
+---
+name: DNS challenge provider request
+about: Suggest a new provider to be available for a certificate DNS challenge
+title: ''
+labels: dns provider request
+assignees: ''
+
+---
+
+**What provider would you like to see added to NPM?**
+<!-- What is this provider called? -->
+
+
+**Have you checked if a certbot plugin exists?**
+<!-- 
+Currently NPM only supports DNS challenge providers for which a certbot plugin exists. 
+You can visit pypi.org, and search for a package with the name `certbot-dns-<privider>`.
+-->

+ 13 - 6
.github/ISSUE_TEMPLATE/feature_request.md

@@ -7,19 +7,26 @@ assignees: ''
 
 ---
 
-**Are you in the right place?**
+<!--
+
+Are you in the right place?
 - If you are looking for support on how to get your upstream server forwarding, please consider asking the community on Reddit.
 - If you are writing code changes to contribute and need to ask about the internals of the software, Gitter is the best place to ask.
-- If you have a feature request for NPM then you are in the *right place.*
+- If you think you found a bug with NPM (not Nginx, or your upstream server or MySql) then you are in the *right place.*
+
+-->
 
 **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 [...]
+<!-- 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.
+<!-- 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.
+<!-- 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.
+<!-- Add any other context or screenshots about the feature request here. -->

+ 1 - 1
.version

@@ -1 +1 @@
-2.9.2
+2.9.3

+ 79 - 2
README.md

@@ -1,7 +1,7 @@
 <p align="center">
 	<img src="https://nginxproxymanager.com/github.png">
 	<br><br>
-	<img src="https://img.shields.io/badge/version-2.9.2-green.svg?style=for-the-badge">
+	<img src="https://img.shields.io/badge/version-2.9.3-green.svg?style=for-the-badge">
 	<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
 		<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
 	</a>
@@ -19,7 +19,7 @@
 This project comes as a pre-built docker image that enables you to easily forward to your websites
 running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
 
-- [Quick Setup](https://nginxproxymanager.com#quick-setup)
+- [Quick Setup](#quick-setup)
 - [Full Setup](https://nginxproxymanager.com/setup/)
 - [Screenshots](https://nginxproxymanager.com/screenshots/)
 
@@ -52,6 +52,65 @@ I won't go in to too much detail here but here are the basics for someone new to
 3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
 4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
 
+## Quick Setup
+
+1. Install Docker and Docker-Compose
+
+- [Docker Install documentation](https://docs.docker.com/install/)
+- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
+
+2. Create a docker-compose.yml file similar to this:
+
+```yml
+version: '3'
+services:
+  app:
+    image: 'jc21/nginx-proxy-manager:latest'
+    ports:
+      - '80:80'
+      - '81:81'
+      - '443:443'
+    environment:
+      DB_MYSQL_HOST: "db"
+      DB_MYSQL_PORT: 3306
+      DB_MYSQL_USER: "npm"
+      DB_MYSQL_PASSWORD: "npm"
+      DB_MYSQL_NAME: "npm"
+    volumes:
+      - ./data:/data
+      - ./letsencrypt:/etc/letsencrypt
+  db:
+    image: 'jc21/mariadb-aria:latest'
+    environment:
+      MYSQL_ROOT_PASSWORD: 'npm'
+      MYSQL_DATABASE: 'npm'
+      MYSQL_USER: 'npm'
+      MYSQL_PASSWORD: 'npm'
+    volumes:
+      - ./data/mysql:/var/lib/mysql
+```
+
+3. Bring up your stack
+
+```bash
+docker-compose up -d
+```
+
+4. Log in to the Admin UI
+
+When your docker container is running, connect to it on port `81` for the admin interface.
+Sometimes this can take a little bit because of the entropy of keys.
+
+[http://127.0.0.1:81](http://127.0.0.1:81)
+
+Default Admin User:
+```
+Email:    [email protected]
+Password: changeme
+```
+
+Immediately after logging in with this default user you will be asked to modify your details and change your password.
+
 
 ## Contributors
 
@@ -331,6 +390,24 @@ Special thanks to the following contributors:
 				<br /><sub><b>Filippo Baruffaldi</b></sub>
 			</a>
 		</td>
+		<td align="center">
+			<a href="https://github.com/bikram990">
+				<img src="https://avatars.githubusercontent.com/u/6782131?v=4" width="80" alt=""/>
+				<br /><sub><b>Bikramjeet Singh</b></sub>
+			</a>
+		</td>
+		<td align="center">
+			<a href="https://github.com/razvanstoica89">
+				<img src="https://avatars.githubusercontent.com/u/28236583?v=4" width="80" alt=""/>
+				<br /><sub><b>Razvan Stoica</b></sub>
+			</a>
+		</td>
+		<td align="center">
+			<a href="https://github.com/psharma04">
+				<img src="https://avatars.githubusercontent.com/u/22587474?v=4" width="80" alt=""/>
+				<br /><sub><b>RBXII3</b></sub>
+			</a>
+		</td>
 	</tr>
 </table>
 <!-- markdownlint-enable -->

+ 0 - 72
docs/README.md

@@ -37,75 +37,3 @@ footer: MIT Licensed | Copyright © 2016-present jc21.com
     <p>Configure other users to either view or manage their own hosts. Full access permissions are available.</p>
   </div>
 </div>
-
-### Quick Setup
-
-1. Install Docker and Docker-Compose
-
-- [Docker Install documentation](https://docs.docker.com/install/)
-- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
-
-2. Create a docker-compose.yml file similar to this:
-
-```yml
-version: '3'
-services:
-  app:
-    image: 'jc21/nginx-proxy-manager:latest'
-    ports:
-      - '80:80'
-      - '81:81'
-      - '443:443'
-    environment:
-      DB_MYSQL_HOST: "db"
-      DB_MYSQL_PORT: 3306
-      DB_MYSQL_USER: "npm"
-      DB_MYSQL_PASSWORD: "npm"
-      DB_MYSQL_NAME: "npm"
-    volumes:
-      - ./data:/data
-      - ./letsencrypt:/etc/letsencrypt
-  db:
-    image: 'jc21/mariadb-aria:latest'
-    environment:
-      MYSQL_ROOT_PASSWORD: 'npm'
-      MYSQL_DATABASE: 'npm'
-      MYSQL_USER: 'npm'
-      MYSQL_PASSWORD: 'npm'
-    volumes:
-      - ./data/mysql:/var/lib/mysql
-```
-
-3. Bring up your stack
-
-```bash
-docker-compose up -d
-```
-
-4. Log in to the Admin UI
-
-When your docker container is running, connect to it on port `81` for the admin interface.
-Sometimes this can take a little bit because of the entropy of keys.
-
-[http://127.0.0.1:81](http://127.0.0.1:81)
-
-Default Admin User:
-
-```
-Email:    [email protected]
-Password: changeme
-```
-
-Immediately after logging in with this default user you will be asked to modify your details and change your password.
-
-5. Upgrading to new versions
-
-```bash
-docker-compose pull
-docker-compose up -d
-```
-
-This project will automatically update any databases or other requirements so you don't have to follow
-any crazy instructions. These steps above will pull the latest updates and recreate the docker
-containers.
-

+ 1 - 1
docs/package.json

@@ -500,7 +500,7 @@
     "pkg-up": "^3.1.0",
     "portfinder": "^1.0.28",
     "posix-character-classes": "^1.0.0",
-    "postcss": "^7.0.32",
+    "postcss": "^8.2.10",
     "postcss-calc": "^7.0.2",
     "postcss-colormin": "^4.0.3",
     "postcss-convert-values": "^4.0.1",

+ 60 - 6
docs/setup/README.md

@@ -1,6 +1,6 @@
 # Full Setup Instructions
 
-### MySQL Database
+## MySQL Database
 
 If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
 
@@ -16,7 +16,7 @@ When using a `mariadb` database, the NPM configuration file should still use the
 
 :::
 
-### Running the App
+## Running the App
 
 Via `docker-compose`:
 
@@ -72,7 +72,7 @@ Then:
 docker-compose up -d
 ```
 
-### Running on Raspberry PI / ARM devices
+## Running on Raspberry PI / ARM devices
 
 The docker images support the following architectures:
 - amd64
@@ -89,8 +89,62 @@ for a list of supported architectures and if you want one that doesn't exist,
 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/)
 on Raspbian.
 
+Via `docker-compose`:
+
+```yml
+version: "3"
+services:
+  app:
+    image: 'jc21/nginx-proxy-manager:latest'
+    restart: always
+    ports:
+      # Public HTTP Port:
+      - '80:80'
+      # Public HTTPS Port:
+      - '443:443'
+      # Admin Web Port:
+      - '81:81'
+    environment:
+      # These are the settings to access your db
+      DB_MYSQL_HOST: "db"
+      DB_MYSQL_PORT: 3306
+      DB_MYSQL_USER: "changeuser"
+      DB_MYSQL_PASSWORD: "changepass"
+      DB_MYSQL_NAME: "npm"
+      # If you would rather use Sqlite uncomment this
+      # and remove all DB_MYSQL_* lines above
+      # DB_SQLITE_FILE: "/data/database.sqlite"
+      # Uncomment this if IPv6 is not enabled on your host
+      # DISABLE_IPV6: 'true'
+    volumes:
+      - ./data/nginx-proxy-manager:/data
+      - ./letsencrypt:/etc/letsencrypt
+    depends_on:
+      - db
+  db:
+    image: ghcr.io/linuxserver/mariadb
+    restart: unless-stopped
+    environment:
+      PUID: 1001
+      PGID: 1001
+      TZ: "Europe/London"
+      MYSQL_ROOT_PASSWORD: "changeme"
+      MYSQL_DATABASE: "npm"
+      MYSQL_USER: "changeuser"
+      MYSQL_PASSWORD: "changepass"
+    volumes:
+      - ./data/mariadb:/config
+```
+
+_Please note, that `DB_MYSQL_*` environment variables will take precedent over `DB_SQLITE_*` var>
+
+Then:
+
+```bash
+docker-compose up -d
+```
 
-### Initial Run
+## Initial Run
 
 After the app is running for the first time, the following will happen:
 
@@ -101,7 +155,7 @@ After the app is running for the first time, the following will happen:
 This process can take a couple of minutes depending on your machine.
 
 
-### Default Administrator User
+## Default Administrator User
 
 ```
 Email:    [email protected]
@@ -110,7 +164,7 @@ Password: changeme
 
 Immediately after logging in with this default user you will be asked to modify your details and change your password.
 
-### Configuration File
+## Configuration File
 
 ::: warning
 

+ 18 - 4
docs/yarn.lock

@@ -2664,10 +2664,10 @@ color@^3.0.0, color@^3.1.2:
     color-convert "^1.9.1"
     color-string "^1.5.2"
 
-colorette@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
-  integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
+colorette@^1.2.1, colorette@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+  integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
 
 combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
   version "1.0.8"
@@ -6527,6 +6527,11 @@ nanoid@^2.0.3:
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
   integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
 
+nanoid@^3.1.22:
+  version "3.1.23"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
+  integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
+
 nanomatch@^1.2.13, nanomatch@^1.2.9:
   version "1.2.13"
   resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -7640,6 +7645,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.2
     source-map "^0.6.1"
     supports-color "^6.1.0"
 
+postcss@^8.2.10:
+  version "8.2.10"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b"
+  integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==
+  dependencies:
+    colorette "^1.2.2"
+    nanoid "^3.1.22"
+    source-map "^0.6.1"
+
 prepend-http@^1.0.0:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"

+ 0 - 1
frontend/fonts

@@ -1 +0,0 @@
-./node_modules/tabler-ui/dist/assets/fonts

+ 1 - 0
frontend/fonts/feather

@@ -0,0 +1 @@
+../node_modules/tabler-ui/dist/assets/fonts/feather

BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff2


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff2


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff2


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff


BIN
frontend/fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff2


+ 0 - 1
frontend/html/partials/header.ejs

@@ -20,7 +20,6 @@
 		<meta name="msapplication-TileColor" content="#333333">
 		<meta name="msapplication-config" content="/images/favicons/browserconfig.xml">
 		<meta name="theme-color" content="#ffffff">
-		<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300i,400,400i,500,500i,600,600i,700,700i&amp;subset=latin-ext">
 		<link href="/css/main.css?v=<%= version %>" rel="stylesheet">
 	</head>
 	<body>

+ 1 - 0
frontend/js/app/nginx/access/list/item.ejs

@@ -32,6 +32,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'access-list') %> #<%- id %></span>
             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></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>

+ 10 - 1
frontend/js/app/nginx/certificates/form.js

@@ -4,11 +4,20 @@ const App              = require('../../main');
 const CertificateModel = require('../../../models/certificate');
 const template         = require('./form.ejs');
 const i18n             = require('../../i18n');
-const dns_providers    = require('../../../../../global/certbot-dns-plugins');
+const dns_providers    = sortProvidersAlphabetically(require('../../../../../global/certbot-dns-plugins'));
 
 require('jquery-serializejson');
 require('selectize');
 
+function sortProvidersAlphabetically(obj) {
+    return Object.entries(obj)
+        .sort((a,b) => a[1].display_name.toLowerCase() > b[1].display_name.toLowerCase())
+        .reduce((result, entry) => {
+            result[entry[0]] = entry[1];
+            return result;
+        }, {});
+}
+
 module.exports = Mn.View.extend({
     template:      template,
     className:     'modal-dialog',

+ 1 - 0
frontend/js/app/nginx/certificates/list/item.ejs

@@ -38,6 +38,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'certificate') %> #<%- id %></span>
             <% 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>

+ 1 - 0
frontend/js/app/nginx/dead/list/item.ejs

@@ -43,6 +43,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'dead-host') %> #<%- id %></span>
             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
             <a href="#" class="able dropdown-item"><i class="dropdown-icon fe fe-power"></i> <%- i18n('str', enabled ? 'disable' : 'enable') %></a>
             <div class="dropdown-divider"></div>

+ 1 - 0
frontend/js/app/nginx/proxy/list/item.ejs

@@ -49,6 +49,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'proxy-host') %> #<%- id %></span>
             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
             <a href="#" class="able dropdown-item"><i class="dropdown-icon fe fe-power"></i> <%- i18n('str', enabled ? 'disable' : 'enable') %></a>
             <div class="dropdown-divider"></div>

+ 1 - 0
frontend/js/app/nginx/redirection/list/item.ejs

@@ -52,6 +52,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'redirection-host') %> #<%- id %></span>
             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
             <a href="#" class="able dropdown-item"><i class="dropdown-icon fe fe-power"></i> <%- i18n('str', enabled ? 'disable' : 'enable') %></a>
             <div class="dropdown-divider"></div>

+ 1 - 0
frontend/js/app/nginx/stream/list/item.ejs

@@ -42,6 +42,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'stream') %> #<%- id %></span>
             <a href="#" class="edit dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('str', 'edit') %></a>
             <a href="#" class="able dropdown-item"><i class="dropdown-icon fe fe-power"></i> <%- i18n('str', enabled ? 'disable' : 'enable') %></a>
             <div class="dropdown-divider"></div>

+ 2 - 1
frontend/js/app/user/password.ejs

@@ -4,6 +4,7 @@
         <button type="button" class="close cancel" aria-label="Close" data-dismiss="modal">&nbsp;</button>
     </div>
     <div class="modal-body">
+        <div class="alert alert-danger" id="error-info" role="alert"></div>
         <form>
             <% if (isSelf()) { %>
             <div class="form-group">
@@ -15,7 +16,7 @@
             <div class="form-group">
                 <label class="form-label"><%- i18n('users', 'new-password') %></label>
                 <input type="password" name="new_password1" class="form-control" placeholder="" minlength="8" required>
-                <div class="invalid-feedback secret-error"></div>
+                <div class="invalid-feedback new-secret-error"></div>
             </div>
             <div class="form-group">
                 <label class="form-label"><%- i18n('users', 'confirm-password') %></label>

+ 20 - 9
frontend/js/app/user/password.js

@@ -9,21 +9,23 @@ module.exports = Mn.View.extend({
     className: 'modal-dialog',
 
     ui: {
-        form:    'form',
-        buttons: '.modal-footer button',
-        cancel:  'button.cancel',
-        save:    'button.save',
-        error:   '.secret-error'
+        form:           'form',
+        buttons:        '.modal-footer button',
+        cancel:         'button.cancel',
+        save:           'button.save',
+        newSecretError: '.new-secret-error',
+        generalError:   '#error-info',
     },
 
     events: {
         'click @ui.save': function (e) {
             e.preventDefault();
-            this.ui.error.hide();
+            this.ui.newSecretError.hide();
+            this.ui.generalError.hide();
             let form = this.ui.form.serializeJSON();
 
             if (form.new_password1 !== form.new_password2) {
-                this.ui.error.text('Passwords do not match!').show();
+                this.ui.newSecretError.text('Passwords do not match!').show();
                 return;
             }
 
@@ -40,7 +42,11 @@ module.exports = Mn.View.extend({
                     App.Controller.showUsers();
                 })
                 .catch(err => {
-                    this.ui.error.text(err.message).show();
+                    // Change error message to make it a little clearer
+                    if (err.message === 'Invalid password') {
+                        err.message = 'Current password is invalid';
+                    }
+                    this.ui.generalError.text(err.message).show();
                     this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
                 });
         }
@@ -54,5 +60,10 @@ module.exports = Mn.View.extend({
         return {
             isSelf: this.isSelf.bind(this)
         };
-    }
+    },
+
+    onRender: function () {
+        this.ui.newSecretError.hide();
+        this.ui.generalError.hide();
+    },
 });

+ 1 - 0
frontend/js/app/users/list/item.ejs

@@ -29,6 +29,7 @@
     <div class="item-action dropdown">
         <a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
         <div class="dropdown-menu dropdown-menu-right">
+            <span class="dropdown-header"><%- i18n('audit-log', 'user') %> #<%- id %></span>
             <a href="#" class="edit-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> <%- i18n('users', 'edit-details') %></a>
             <a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> <%- i18n('users', 'edit-permissions') %></a>
             <a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> <%- i18n('users', 'change-password') %></a>

+ 1 - 1
frontend/js/i18n/messages.json

@@ -183,7 +183,7 @@
       "delete": "Delete SSL Certificate",
       "delete-confirm": "Are you sure you want to delete this SSL Certificate? Any hosts using it will need to be updated later.",
       "help-title": "SSL Certificates",
-      "help-content": "TODO",
+      "help-content": "SSL certificates (correctly known as TLS Certificates) are a form of encryption key which allows your site to be encrypted for the end user.\nNPM uses a service called Let's Encrypt to issue SSL certificates for free.\nIf you have any sort of personal information, passwords, or sensitive data behind NPM, it's probably a good idea to use a certificate.\nNPM also supports DNS authentication for if you're not running your site facing the internet, or if you just want a wildcard certificate.",
       "other-certificate": "Certificate",
       "other-certificate-key": "Certificate Key",
       "other-intermediate-certificate": "Intermediate Certificate",

+ 4 - 0
frontend/scss/custom.scss

@@ -12,6 +12,10 @@ a:hover {
     color: darken($primary-color, 10%);
 }
 
+.dropdown-header {
+    padding-left: 1rem;
+}
+
 .dropdown-item.active, .dropdown-item:active {
     background-color: $primary-color;
 }

+ 39 - 0
frontend/scss/fonts.scss

@@ -0,0 +1,39 @@
+/* source-sans-pro-regular - latin-ext_latin */
+@font-face {
+  font-family: 'Source Sans Pro';
+  font-style: normal;
+  font-weight: 400;
+  src: local(''),
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* source-sans-pro-italic - latin-ext_latin */
+@font-face {
+  font-family: 'Source Sans Pro';
+  font-style: italic;
+  font-weight: 400;
+  src: local(''),
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* source-sans-pro-700italic - latin-ext_latin */
+@font-face {
+  font-family: 'Source Sans Pro';
+  font-style: italic;
+  font-weight: 700;
+  src: local(''),
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* source-sans-pro-700 - latin-ext_latin */
+@font-face {
+  font-family: 'Source Sans Pro';
+  font-style: normal;
+  font-weight: 700;
+  src: local(''),
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('../fonts/source-sans-pro/source-sans-pro-v14-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}

+ 1 - 0
frontend/scss/styles.scss

@@ -1,5 +1,6 @@
 @import "~tabler-ui/dist/assets/css/dashboard";
 @import "tabler-extra";
+@import "fonts";
 @import "selectize";
 @import "custom";
 

+ 13 - 1
frontend/webpack.config.js

@@ -90,7 +90,19 @@ module.exports = {
 						}
 					}
 				]
-			}
+			},
+			{
+        test: /source-sans-pro.*\.(woff(2)?)(\?v=\d+\.\d+\.\d+)?$/,
+        use: [
+          {
+            loader: 'file-loader',
+            options: {
+              name: '[name].[ext]',
+              outputPath: 'assets/'
+            }
+          }
+        ]
+      }
 		]
 	},
 	plugins:   [

+ 3 - 3
frontend/yarn.lock

@@ -6560,9 +6560,9 @@ typedarray@^0.0.6:
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
 ua-parser-js@^0.7.9:
-  version "0.7.21"
-  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
-  integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+  version "0.7.28"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
+  integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
 
 [email protected]:
   version "3.4.10"

+ 32 - 3
global/certbot-dns-plugins.js

@@ -43,7 +43,7 @@ certbot_dns_aliyun:dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcd
 	azure: {
 		display_name:    'Azure',
 		package_name:    'certbot-dns-azure',
-		package_version: '1.1.0',
+		package_version: '1.2.0',
 		dependencies:    '',
 		credentials:     `# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.
 # Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.
@@ -126,9 +126,9 @@ certbot_dns_cpanel:cpanel_password = hunter2`,
 	duckdns: {
 		display_name:     'DuckDNS',
 		package_name:     'certbot-dns-duckdns',
-		package_version:  '0.5',
+		package_version:  '0.6',
 		dependencies:     '',
-		credentials:      'dns_duckdns_token=<your-duckdns-token>',
+		credentials:      'dns_duckdns_token=your-duckdns-token',
 		full_plugin_name: 'dns-duckdns',
 	},
 	//####################################################//
@@ -181,6 +181,15 @@ certbot_dns_dnspod:dns_dnspod_api_token = "DNSPOD-API-TOKEN"`,
 		full_plugin_name: 'certbot-dns-dnspod:dns-dnspod',
 	},
 	//####################################################//
+	dynu: {
+		display_name:     'Dynu',
+		package_name:     'certbot-dns-dynu',
+		package_version:  '0.0.1',
+		dependencies:     '',
+		credentials:      'certbot_dns_dynu:dns_dynu_auth_token = YOUR_DYNU_AUTH_TOKEN',
+		full_plugin_name: 'certbot-dns-dynu:dns-dynu',
+	},
+	//####################################################//
 	eurodns: {
 		display_name:    'EuroDNS',
 		package_name:    'certbot-dns-eurodns',
@@ -201,6 +210,16 @@ dns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy`,
 		full_plugin_name: 'certbot-plugin-gandi:dns',
 	},
 	//####################################################//
+	godaddy: {
+		display_name:    'GoDaddy',
+		package_name:    'certbot-dns-godaddy',
+		package_version: '0.2.0',
+		dependencies:    '',
+		credentials:     `dns_godaddy_secret = 0123456789abcdef0123456789abcdef01234567
+dns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123`,
+		full_plugin_name: 'dns-godaddy',
+	},
+	//####################################################//
 	google: {
 		display_name:    'Google',
 		package_name:    'certbot-dns-google',
@@ -316,6 +335,16 @@ dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`,
 		full_plugin_name: 'dns-ovh',
 	},
 	//####################################################//
+	porkbun: {
+		display_name:    'Porkbun',
+		package_name:    'certbot-dns-porkbun',
+		package_version: '0.2',
+		dependencies:    '',
+		credentials:     `dns_porkbun_key=your-porkbun-api-key
+dns_porkbun_secret=your-porkbun-api-secret`,
+		full_plugin_name: 'dns-porkbun',
+	},
+	//####################################################//
 	powerdns: {
 		display_name:    'PowerDNS',
 		package_name:    'certbot-dns-powerdns',