upgraded. Now works.

This commit is contained in:
baudneo
2022-10-07 15:26:13 -06:00
parent 8b5c3847e3
commit 0de3769298
44 changed files with 4082 additions and 3576 deletions

3
.gitignore vendored
View File

@@ -4,3 +4,6 @@
.vscode .vscode
certbot-help.txt certbot-help.txt
frontend/images/* frontend/images/*
frontend/dist
frontend/node_modules
backend/node_modules

View File

@@ -477,7 +477,7 @@ const internalCertificate = {
// Query is used for searching // Query is used for searching
if (typeof search_query === 'string') { if (typeof search_query === 'string') {
query.where(function () { query.where(function () {
this.where('name', 'like', '%' + search_query + '%'); this.where('nice_name', 'like', '%' + search_query + '%');
}); });
} }

View File

@@ -12,14 +12,14 @@
"compression": "^1.7.4", "compression": "^1.7.4",
"config": "^3.3.1", "config": "^3.3.1",
"express": "^4.17.1", "express": "^4.17.1",
"express-fileupload": "^1.1.9", "express-fileupload": "^1.1.10",
"gravatar": "^1.8.0", "gravatar": "^1.8.0",
"json-schema-ref-parser": "^8.0.0", "json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"knex": "^0.20.13", "knex": "^0.20.13",
"liquidjs": "^9.11.10", "liquidjs": "^9.11.10",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.24.0", "moment": "^2.29.4",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-rsa": "^1.0.8", "node-rsa": "^1.0.8",
"nodemon": "^2.0.2", "nodemon": "^2.0.2",
@@ -33,7 +33,7 @@
"displayDate": true, "displayDate": true,
"displayTimestamp": true "displayTimestamp": true
}, },
"author": "Jamie Curnow <jc@jc21.com>", "author": "Baudneo <baudneo@protonmail.com>",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"eslint": "^6.8.0", "eslint": "^6.8.0",

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
# This file assumes that the frontend has been built using ./scripts/frontend-build # This file assumes that the frontend has been built using ./scripts/frontend-build
FROM nginxproxymanager/nginx-full:local_certbot-node FROM baudneo/nginx-full:certbot-node
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG BUILD_VERSION ARG BUILD_VERSION
@@ -25,7 +25,7 @@ ENV SUPPRESS_NO_CONFIG_WARNING=1 \
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends jq logrotate \ && apt-get install -y --no-install-recommends jq logrotate gettext-base \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*

View File

@@ -1,7 +1,9 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
set -e set -e
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
mkdir -p /data/logs mkdir -p /data/logs
echo "Changing ownership of /data/logs to $(id -u):$(id -g)" log "Changing ownership of /data/logs to $(id -u):$(id -g)"
chown -R "$(id -u):$(id -g)" /data/logs chown -R "$(id -u):$(id -g)" /data/logs

View File

@@ -1,10 +1,13 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash
# ref: https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/cont-init.d/01-envfile # ref: https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/cont-init.d/01-envfile
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
# in s6, environmental variables are written as text files for s6 to monitor # in s6, environmental variables are written as text files for s6 to monitor
# seach through full-path filenames for files ending in "__FILE" # seach through full-path filenames for files ending in "__FILE"
for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do
echo "[secret-init] Evaluating ${FILENAME##*/} ..." log "Evaluating ${FILENAME##*/} ..."
# set SECRETFILE to the contents of the full-path textfile # set SECRETFILE to the contents of the full-path textfile
SECRETFILE=$(cat ${FILENAME}) SECRETFILE=$(cat ${FILENAME})
@@ -21,9 +24,9 @@ for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do
# since s6 uses text files, this is effectively "export ..." # since s6 uses text files, this is effectively "export ..."
printf $(cat ${SECRETFILE}) > ${STRIPFILE} printf $(cat ${SECRETFILE}) > ${STRIPFILE}
# echo "[secret-init] Set ${STRIPFILE##*/} to $(cat ${STRIPFILE})" # DEBUG - rm for prod!" # echo "[secret-init] Set ${STRIPFILE##*/} to $(cat ${STRIPFILE})" # DEBUG - rm for prod!"
echo "[secret-init] Success! ${STRIPFILE##*/} set from ${FILENAME##*/}" echo "Success! ${STRIPFILE##*/} set from ${FILENAME##*/}"
else else
echo "[secret-init] cannot find secret in ${FILENAME}" echo "cannot find secret in ${FILENAME}"
fi fi
done done

View File

@@ -0,0 +1,13 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
if [ -n "${TZ}" ]; then
log "Setting timezone to ${TZ}"
echo "${TZ}" > /etc/timezone
ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime
fi

View File

@@ -0,0 +1,38 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
if [[ -f /etc/nginx/conf.d/production.conf ]]; then
admin_log=$(grep "<ADMIN_ACCESS_LOG>" /etc/nginx/conf.d/production.conf)
if [[ ${ADMIN_PANEL_LOG} == "1" ]] || [[ ${ADMIN_PANEL_LOG} -eq 1 ]]; then
if [[ -n "${admin_log}" ]]; then
log "Enabling admin dashboard logging"
sed -i 's|<ADMIN_ACCESS_LOG>|/data/logs/admin-panel_access.log standard|' /etc/nginx/conf.d/production.conf
sed -i 's|<ADMIN_ERROR_LOG>|/data/logs/admin-panel_error.log warn|' /etc/nginx/conf.d/production.conf
fi
else
if [[ -n "${admin_log}" ]]; then
log "Leaving admin dashboard logging off (default behavior)"
sed -i 's|<ADMIN_ACCESS_LOG>|/dev/null|' /etc/nginx/conf.d/production.conf
sed -i 's|<ADMIN_ERROR_LOG>|/dev/null|' /etc/nginx/conf.d/production.conf
fi
fi
fi
default_log=$(grep "<ERROR_LOG_LEVEL>" /etc/nginx/nginx.conf)
if [[ ${OPENRESTY_DEBUG} == "1" ]] || [[ ${OPENRESTY_DEBUG} -eq 1 ]]; then
if [[ -n "${default_log}" ]]; then
log "Changing OpenResty ERROR (fallback_error.log) logging to level: DEBUG"
sed -i 's|<ERROR_LOG_LEVEL>|debug|' /etc/nginx/nginx.conf
fi
else
if [[ -n "${default_log}" ]]; then
log "Leaving OpenResty ERROR (fallback_error.log) logging at level: WARN (default behavior)"
sed -i 's|<ERROR_LOG_LEVEL>|warn|' /etc/nginx/nginx.conf
fi
fi

View File

@@ -0,0 +1,89 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
if [[ -n "${GEOLITE2_DB_GRAB}" ]]; then
if [[ "${GEOLITE2_DB_GRAB}" == "1" ]] || [[ "${GEOLITE2_DB_GRAB}" -eq 1 ]]; then
log "GeoLite2 DB Grab configured, installing/updating GeoLite2 Database's"
geo2="${GEOIP_DIR:-/geoip}/2"
mkdir -p "$geo2/tmp"
GEOIP2_DB_URLS=(
"https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb"
"https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb"
"https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-ASN.mmdb"
)
# download new dbs and diff them, update if different
for db in "${GEOIP2_DB_URLS[@]}"; do
log "Downloading ${db##*/} from ${db%/*}..."
curl -s -L -o "${geo2}/tmp/${db##*/}" "$db"
if [ "$?" -ne 0 ]; then
log "Failed to download ${db##*/} from ${db%/*}!"
exit 1
fi
if [ -f "${geo2}/${db##*/}" ]; then
log "Diffing ${db##*/}..."
diff "${geo2}/${db##*/}" "${geo2}/tmp/${db##*/}"
if [ "$?" -eq 0 ]; then
log "${db##*/} is up to date..."
else
log "${db##*/} is different, updating db..."
mv "${geo2}/tmp/${db##*/}" "${geo2}/${db##*/}"
fi
else
log "${db##*/} does not exist, installing..."
mv "${geo2}/tmp/${db##*/}" "${geo2}/${db##*/}"
fi
done
rm -rf "${geo2}/tmp/"
fi
fi
if [[ -n "${GEOLITE_DB_GRAB}" ]]; then
if [ "${GEOLITE_DB_GRAB}" == "1" ] || [ "${GEOLITE2_DB_GRAB}" -eq 1 ]; then
log "GeoLite LEGACY DB Grab configured, downloading GeoLite LEGACY Database's"
geo1="${GEOIP_DIR:-/geoip}/1"
mkdir -p "$geo1"
# If http proxy needed
#https_proxy="http://foo.bar:3128"
export https_proxy
for f in $GeoIP_1_FILES; do
# Make sure .gz is stripped
f=${f%*.gz}
# Make sure .dat exists
if [[ ! "$f" =~ \.csv ]]; then f=${f%*.dat}.dat; fi
wget -nv -T 30 --max-redirect 0 "https://mailfud.org/geoip-legacy/$f.gz"
RET=$?
if [ $RET -ne 0 ]; then
log "wget $f.gz failed: $RET" >&2
continue
fi
# Unpack and replace files atomically
if gzip -dc "$f.gz" >"$f.tmp"; then
if [[ -f "${geo1}/${f}" ]]; then
if ! diff "${geo1}/${f}" "$f".tmp >/dev/null 2>&1; then
log "${geo1}/${f} is different, updating db..."
chmod 644 "$f.tmp"
/bin/mv -f "$f.tmp" "${geo1}/${f}"
else
log "${geo1}/${f} is up to date..."
fi
else
log "${geo1}/${f} does not exist, installing..."
chmod 644 "$f.tmp"
/bin/mv -f "$f.tmp" "${geo1}/${f}"
fi
else
log "gunzip $f failed" >&2
rm -f "$f.gz"
fi
rm -f "$f.tmp"
done
fi
fi

13
docker/rootfs/etc/cont-init.d/97_modsecurity.sh Executable file → Normal file
View File

@@ -5,11 +5,14 @@ set -e # Exit immediately if a command exits with a non-zero status.
set -u # Treat unset variables as an error. set -u # Treat unset variables as an error.
log() { log() {
echo "[cont-init.d] $(basename "$0"): $*" echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
} }
mkdir -p /data/modsec/ruleset mkdir -p /data/modsec/ruleset
ln -s /data/modsec/ /etc/nginx if [ ! -L /etc/nginx/modsec ]; then
log "Symbolically Linking /data/modsec into /etc/nginx"
ln -s /data/modsec/ /etc/nginx
fi
[ ! -f /data/modsec/main.conf ] && MODSEC_CREATE="1" [ ! -f /data/modsec/main.conf ] && MODSEC_CREATE="1"
@@ -20,7 +23,11 @@ if [ "${MODSEC_CREATE}" == "1" ] || [ "${MODSEC_CREATE}" -eq 1 ]; then
cp /usr/local/modsecurity/templates/unicode.mapping /data/modsec/unicode.mapping cp /usr/local/modsecurity/templates/unicode.mapping /data/modsec/unicode.mapping
cp -r /usr/local/modsecurity/templates/* /data/modsec/ cp -r /usr/local/modsecurity/templates/* /data/modsec/
cp -r /usr/local/modsecurity/templates/ruleset/* /data/modsec/ruleset/ cp -r /usr/local/modsecurity/templates/ruleset/* /data/modsec/ruleset/
mv /data/modsec/ruleset/crs-setup.conf.example /data/modsec/ruleset/crs-setup.conf if [ -f /data/modsec/ruleset/crs-setup.conf.example ]; then
mv /data/modsec/ruleset/crs-setup.conf.example /data/modsec/ruleset/crs-setup.conf
elif [ -f /data/modsec/ruleset/crs-setup.conf ]; then
mv /data/modsec/ruleset/crs-setup.conf /data/modsec/ruleset/crs-setup.conf
fi
fi fi
# Enable modsecurity in the server block of :80 and :443 # Enable modsecurity in the server block of :80 and :443

View File

@@ -0,0 +1,52 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# Update CrowdSec OpenResty bouncer, allows for overriding the 99 init file and crowdsec_openresty.conf
log() {
echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
}
if [ -n "${CROWDSEC_UPDATE_DIR}" ]; then
mkdir -p "${CROWDSEC_UPDATE_DIR:-/cs-update}"
log "Evaluating Crowdsec update files located at ${CROWDSEC_UPDATE_DIR}"
for entry in "${CROWDSEC_UPDATE_DIR}"/*; do
if [[ "$entry" == "$CROWDSEC_UPDATE_DIR"'/*' ]]; then
log "Nothing found in the upgrade directory, using current release"
break
fi
basepath_=${entry##*/}
ext_=${entry##*.}
dest_="/etc/nginx/lualib/"
type_=""
succ=0
log_msg=""
# File
if [[ -f "$entry" ]]; then
type_="file"
[[ $ext_ == "lua" ]] && succ=1
[[ $basepath_ == "crowdsec_openresty.conf" ]] && dest_="/etc/nginx/conf.d/" && succ=1
[[ $basepath_ == "99_crowdsec-openresty-bouncer.sh" ]] && dest_="/etc/cont-init.d/" && succ=1
# Directory
elif [[ -d "$entry" ]]; then
type_="directory"
[[ $basepath_ == "plugins" ]] && succ=1
else
log "IDK WTF MAN, its not a file or a directory?"
continue
fi
# log "Found ${type_}: $entry | extension: $ext_ | success: $succ | basepath: $basepath_"
log_msg="UPGRADED! Copied '$type_' $entry to $dest_"
if [[ "${succ}" -eq 2 ]]; then
cp '-r' "${entry}" "${dest_}"
elif [[ "${succ}" -eq 1 ]]; then
cp "${entry}" "${dest_}"
elif [[ "${succ}" -eq 0 ]]; then
log_msg="Ignoring $type_ -> $entry"
else
log_msg="ERROR> something is wrong! value: $succ should be between 0 and 2"
fi
log "$log_msg"
done
fi

View File

@@ -1,29 +0,0 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
set -e # Exit immediately if a command exits with a non-zero status.
set -u # Treat unset variables as an error.
log() {
echo "[cont-init.d] $(basename "$0"): $*"
}
# Redirect admin panel logs from /dev/null to log files if enabled
if [[ ${ADMIN_PANEL_LOG} == "1" ]] || [[ ${ADMIN_PANEL_LOG} -eq 1 ]]; then
log "Enabling admin dashboard logging"
sed-patch 's|<ADMIN_ACCESS_LOG>|/data/logs/admin-panel_access.log standard|' /etc/nginx/conf.d/production.conf
sed-patch 's|<ADMIN_ERROR_LOG>|/data/logs/admin-panel_error.log warn|' /etc/nginx/conf.d/production.conf
else
log "Leaving admin dashboard logging off (default behavior)"
sed-patch 's|<ADMIN_ACCESS_LOG>|/dev/null|' /etc/nginx/conf.d/production.conf
sed-patch 's|<ADMIN_ERROR_LOG>|/dev/null|' /etc/nginx/conf.d/production.conf
fi
if [[ ${OPENRESTY_DEBUG} == "1" ]] || [[ ${OPENRESTY_DEBUG} -eq 1 ]]; then
log "Changing OpenResty ERROR (fallback_error.log) logging to level: DEBUG"
sed-patch 's|<ERROR_LOG_LEVEL>|debug|' /etc/nginx/nginx.conf
else
log "Leaving OpenResty ERROR (fallback_error.log) logging at level: WARN (default behavior)"
sed-patch 's|<ERROR_LOG_LEVEL>|warn|' /etc/nginx/nginx.conf
fi

View File

@@ -5,20 +5,24 @@ set -e # Exit immediately if a command exits with a non-zero status.
set -u # Treat unset variables as an error. set -u # Treat unset variables as an error.
log() { log() {
echo "[cont-init.d] $(basename "$0"): $*" echo -e "${BLUE}[cont-init.d] ${RED}$(basename "$0")${CYAN}>>>${RESET} $*"
} }
if [ "${CROWDSEC_BOUNCER}" == "1" ] || [ "${CROWDSEC_BOUNCER}" -eq 1 ]; then if [ "${CROWDSEC_BOUNCER}" == "1" ] || [ "${CROWDSEC_BOUNCER}" -eq 1 ]; then
log "Enabling CrowdSec OpenResty Bouncer" log "Enabling CrowdSec OpenResty Bouncer"
mkdir -p /data/crowdsec mkdir -p /data/crowdsec
if [ -f /data/crowdsec/crowdsec-openresty-bouncer.conf ]; then if [ ! -f /data/crowdsec/crowdsec-openresty-bouncer.conf ]; then
#Install Crowdsec Bouncer Config. #Install Crowdsec Bouncer Config.
cp /crowdsec/crowdsec-openresty-bouncer.conf.template /data/crowdsec/crowdsec-openresty-bouncer.conf cp /crowdsec/crowdsec-openresty-bouncer.conf.template /data/crowdsec/crowdsec-openresty-bouncer.conf
log "Crowdsec OpenResty Bouncer Config copied to /data/crowdsec/crowdsec-openresty-bouncer.conf" log "Crowdsec OpenResty Bouncer Config copied to /data/crowdsec/crowdsec-openresty-bouncer.conf"
fi fi
# Create lualib plugin directory for crowdsec and move crowdsec lua libs into it # Create lualib plugin directory for crowdsec and move crowdsec lua libs into it
mkdir -p /etc/nginx/lualib/plugins/crowdsec/ mkdir -p /etc/nginx/lualib/plugins/crowdsec/
cp /crowdsec/lua/* /etc/nginx/lualib/plugins/crowdsec/ cp -r /crowdsec/lua/lib/* /etc/nginx/lualib/
# This initilizes crowdsec as /etc/nginx/conf.d/* is included in nginx.conf # This initilizes crowdsec as /etc/nginx/conf.d/* is included in nginx.conf
cp /crowdsec/crowdsec_openresty.conf /etc/nginx/conf.d/ # Fixes -> SSL_CTX_load_verify_locations("/etc/nginx/${SSL_CERTS_PATH}") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/nginx/${SSL_CERTS_PATH}','r') error:2006D080:BIO routines:BIO_new_file:no such file error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib)
SSL_CERTS_PATH=${SSL_CERTS_PATH} envsubst < /crowdsec/crowdsec_openresty.conf > /etc/nginx/conf.d/crowdsec_openresty.conf
# cp /crowdsec/crowdsec_openresty.conf /etc/nginx/conf.d/
else
log "CrowdSec OpenResty Bouncer Disabled"
fi fi

View File

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

View File

@@ -2,6 +2,16 @@
<div class="card-status bg-teal"></div> <div class="card-status bg-teal"></div>
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('audit-log', 'title') %></h3> <h3 class="card-title"><%- i18n('audit-log', 'title') %></h3>
<div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('audit-log', 'search') %>" aria-label="<%- i18n('audit-log', 'search') %>">
</div>
</form>
</div>
</div> </div>
<div class="card-body no-padding min-100"> <div class="card-body no-padding min-100">
<div class="dimmer active"> <div class="dimmer active">

View File

@@ -12,39 +12,68 @@ module.exports = Mn.View.extend({
ui: { ui: {
list_region: '.list-region', list_region: '.list-region',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.AuditLog.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new AuditLogModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showAuditLog();
}
}));
console.error(err);
},
showEmpty: function() {
this.showChildView('list_region', new EmptyView({
title: App.i18n('audit-log', 'empty'),
subtitle: App.i18n('audit-log', 'empty-subtitle')
}));
}, },
regions: { regions: {
list_region: '@ui.list_region' list_region: '@ui.list_region'
}, },
events: {
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['user'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
}
},
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.AuditLog.getAll(['user']) view.fetch(['user'])
.then(response => { .then(response => {
if (!view.isDestroyed() && response && response.length) { if (!view.isDestroyed() && response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new AuditLogModel.Collection(response)
}));
} else { } else {
view.showChildView('list_region', new EmptyView({ view.showEmpty();
title: App.i18n('audit-log', 'empty'),
subtitle: App.i18n('audit-log', 'empty-subtitle')
}));
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showAuditLog();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('access-lists', 'title') %></h3> <h3 class="card-title"><%- i18n('access-lists', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('access-lists', 'search') %>" aria-label="<%- i18n('access-lists', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('access-lists', 'add') %></a> <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('access-lists', 'add') %></a>

View File

@@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.AccessLists.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new AccessListModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxAccess();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('access_lists');
this.showChildView('list_region', new EmptyView({
title: App.i18n('access-lists', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('access-lists', 'add') : null,
btn_color: 'teal',
permission: 'access_lists',
action: function () {
App.Controller.showNginxAccessListForm();
}
}));
}, },
regions: { regions: {
@@ -30,6 +67,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('access-lists', 'help-title'), App.i18n('access-lists', 'help-content')); App.Controller.showHelp(App.i18n('access-lists', 'help-title'), App.i18n('access-lists', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner', 'items', 'clients'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -40,39 +88,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.AccessLists.getAll(['owner', 'items', 'clients']) view.fetch(['owner', 'items', 'clients'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new AccessListModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('access_lists'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('access-lists', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('access-lists', 'add') : null,
btn_color: 'teal',
permission: 'access_lists',
action: function () {
App.Controller.showNginxAccessListForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxAccess();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('certificates', 'title') %></h3> <h3 class="card-title"><%- i18n('certificates', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('certificates', 'search') %>" aria-label="<%- i18n('certificates', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<div class="dropdown"> <div class="dropdown">

View File

@@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.Certificates.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new CertificateModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxCertificates();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('certificates');
this.showChildView('list_region', new EmptyView({
title: App.i18n('certificates', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('certificates', 'add') : null,
btn_color: 'pink',
permission: 'certificates',
action: function () {
App.Controller.showNginxCertificateForm();
}
}));
}, },
regions: { regions: {
@@ -31,6 +68,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('certificates', 'help-title'), App.i18n('certificates', 'help-content')); App.Controller.showHelp(App.i18n('certificates', 'help-title'), App.i18n('certificates', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -41,39 +89,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.Certificates.getAll(['owner']) view.fetch(['owner'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new CertificateModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('certificates'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('certificates', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('certificates', 'add') : null,
btn_color: 'pink',
permission: 'certificates',
action: function () {
App.Controller.showNginxCertificateForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxCertificates();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -7,7 +7,7 @@
<form> <form>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<%= i18n('dead-hosts', 'delete-confirm', {domains: domain_names.join(', ')}) %> <%= i18n('dead-hosts', 'delete-confirm', {domains: domain_names.join(', ').toHtmlEntities()}) %>
<% if (certificate_id) { %> <% if (certificate_id) { %>
<br><br> <br><br>
<%- i18n('ssl', 'delete-ssl') %> <%- i18n('ssl', 'delete-ssl') %>

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('dead-hosts', 'title') %></h3> <h3 class="card-title"><%- i18n('dead-hosts', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('dead-hosts', 'search') %>" aria-label="<%- i18n('dead-hosts', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-danger btn-sm ml-2 add-item"><%- i18n('dead-hosts', 'add') %></a> <a href="#" class="btn btn-outline-danger btn-sm ml-2 add-item"><%- i18n('dead-hosts', 'add') %></a>

View File

@@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.DeadHosts.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new DeadHostModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxDead();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('dead_hosts');
this.showChildView('list_region', new EmptyView({
title: App.i18n('dead-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('dead-hosts', 'add') : null,
btn_color: 'danger',
permission: 'dead_hosts',
action: function () {
App.Controller.showNginxDeadForm();
}
}));
}, },
regions: { regions: {
@@ -30,6 +67,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('dead-hosts', 'help-title'), App.i18n('dead-hosts', 'help-content')); App.Controller.showHelp(App.i18n('dead-hosts', 'help-title'), App.i18n('dead-hosts', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner', 'certificate'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -40,39 +88,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.DeadHosts.getAll(['owner', 'certificate']) view.fetch(['owner', 'certificate'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new DeadHostModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('dead_hosts'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('dead-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('dead-hosts', 'add') : null,
btn_color: 'danger',
permission: 'dead_hosts',
action: function () {
App.Controller.showNginxDeadForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxDead();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -7,7 +7,7 @@
<form> <form>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<%= i18n('proxy-hosts', 'delete-confirm', {domains: domain_names.join(', ')}) %> <%= i18n('proxy-hosts', 'delete-confirm', {domains: domain_names.join(', ').toHtmlEntities()}) %>
<% if (certificate_id) { %> <% if (certificate_id) { %>
<br><br> <br><br>
<%- i18n('ssl', 'delete-ssl') %> <%- i18n('ssl', 'delete-ssl') %>

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('proxy-hosts', 'title') %></h3> <h3 class="card-title"><%- i18n('proxy-hosts', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('proxy-hosts', 'search') %>" aria-label="<%- i18n('proxy-hosts', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-success btn-sm ml-2 add-item"><%- i18n('proxy-hosts', 'add') %></a> <a href="#" class="btn btn-outline-success btn-sm ml-2 add-item"><%- i18n('proxy-hosts', 'add') %></a>

View File

@@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.ProxyHosts.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new ProxyHostModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxProxy();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('proxy_hosts');
this.showChildView('list_region', new EmptyView({
title: App.i18n('proxy-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('proxy-hosts', 'add') : null,
btn_color: 'success',
permission: 'proxy_hosts',
action: function () {
App.Controller.showNginxProxyForm();
}
}));
}, },
regions: { regions: {
@@ -30,6 +67,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('proxy-hosts', 'help-title'), App.i18n('proxy-hosts', 'help-content')); App.Controller.showHelp(App.i18n('proxy-hosts', 'help-title'), App.i18n('proxy-hosts', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner', 'access_list', 'certificate'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -40,39 +88,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.ProxyHosts.getAll(['owner', 'access_list', 'certificate']) view.fetch(['owner', 'access_list', 'certificate'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new ProxyHostModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('proxy_hosts'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('proxy-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('proxy-hosts', 'add') : null,
btn_color: 'success',
permission: 'proxy_hosts',
action: function () {
App.Controller.showNginxProxyForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxProxy();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -7,7 +7,7 @@
<form> <form>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<%= i18n('redirection-hosts', 'delete-confirm', {domains: domain_names.join(', ')}) %> <%= i18n('redirection-hosts', 'delete-confirm', {domains: domain_names.join(', ').toHtmlEntities()}) %>
<% if (certificate_id) { %> <% if (certificate_id) { %>
<br><br> <br><br>
<%- i18n('ssl', 'delete-ssl') %> <%- i18n('ssl', 'delete-ssl') %>

View File

@@ -1,11 +1,19 @@
<div class="card"> <div class="card">
<div class="card-status bg-yellow"></div> <div class="card-status bg-yellow"></div>
<div class="card-header"> <div class="card-header">
<h3 class="card-title">Redirection Hosts</h3> <h3 class="card-title"><%- i18n('redirection-hosts', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('redirection-hosts', 'search') %>" aria-label="<%- i18n('redirection-hosts', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-yellow btn-sm ml-2 add-item">Add Redirection Host</a> <a href="#" class="btn btn-outline-yellow btn-sm ml-2 add-item"><%- i18n('redirection-hosts', 'add') %></a>
<% } %> <% } %>
</div> </div>
</div> </div>

View File

@@ -14,7 +14,43 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.RedirectionHosts.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new RedirectionHostModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxRedirection();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('redirection_hosts');
this.showChildView('list_region', new EmptyView({
title: App.i18n('redirection-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('redirection-hosts', 'add') : null,
btn_color: 'yellow',
permission: 'redirection_hosts',
action: function () {
App.Controller.showNginxRedirectionForm();
}
}));
}, },
regions: { regions: {
@@ -30,6 +66,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('redirection-hosts', 'help-title'), App.i18n('redirection-hosts', 'help-content')); App.Controller.showHelp(App.i18n('redirection-hosts', 'help-title'), App.i18n('redirection-hosts', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner', 'certificate'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -40,39 +87,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.RedirectionHosts.getAll(['owner', 'certificate']) view.fetch(['owner', 'certificate'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new RedirectionHostModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('redirection_hosts'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('redirection-hosts', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('redirection-hosts', 'add') : null,
btn_color: 'yellow',
permission: 'redirection_hosts',
action: function () {
App.Controller.showNginxRedirectionForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxRedirection();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('streams', 'title') %></h3> <h3 class="card-title"><%- i18n('streams', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('streams', 'search') %>" aria-label="<%- i18n('streams', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a> <a href="#" class="btn btn-outline-secondary btn-sm ml-2 help"><i class="fe fe-help-circle"></i></a>
<% if (showAddButton) { %> <% if (showAddButton) { %>
<a href="#" class="btn btn-outline-blue btn-sm ml-2 add-item"><%- i18n('streams', 'add') %></a> <a href="#" class="btn btn-outline-blue btn-sm ml-2 add-item"><%- i18n('streams', 'add') %></a>

View File

@@ -14,7 +14,44 @@ module.exports = Mn.View.extend({
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
help: '.help', help: '.help',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Nginx.Streams.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new StreamModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxStream();
}
}));
console.error(err);
},
showEmpty: function() {
let manage = App.Cache.User.canManage('streams');
this.showChildView('list_region', new EmptyView({
title: App.i18n('streams', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('streams', 'add') : null,
btn_color: 'blue',
permission: 'streams',
action: function () {
App.Controller.showNginxStreamForm();
}
}));
}, },
regions: { regions: {
@@ -30,6 +67,17 @@ module.exports = Mn.View.extend({
'click @ui.help': function (e) { 'click @ui.help': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showHelp(App.i18n('streams', 'help-title'), App.i18n('streams', 'help-content')); App.Controller.showHelp(App.i18n('streams', 'help-title'), App.i18n('streams', 'help-content'));
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['owner'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
@@ -40,39 +88,18 @@ module.exports = Mn.View.extend({
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Nginx.Streams.getAll(['owner']) view.fetch(['owner'])
.then(response => { .then(response => {
if (!view.isDestroyed()) { if (!view.isDestroyed()) {
if (response && response.length) { if (response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new StreamModel.Collection(response)
}));
} else { } else {
let manage = App.Cache.User.canManage('streams'); view.showEmpty();
view.showChildView('list_region', new EmptyView({
title: App.i18n('streams', 'empty'),
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
link: manage ? App.i18n('streams', 'add') : null,
btn_color: 'blue',
permission: 'streams',
action: function () {
App.Controller.showNginxStreamForm();
}
}));
} }
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showNginxStream();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -3,7 +3,7 @@
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col-auto"> <div class="col-auto">
<ul class="list-inline list-inline-dots mb-0"> <ul class="list-inline list-inline-dots mb-0">
<li class="list-inline-item"><a href="https://github.com/jc21/nginx-proxy-manager?utm_source=nginx-proxy-manager"><%- i18n('footer', 'fork-me') %></a></li> <li class="list-inline-item"><a href="https://github.com/jc21/nginx-proxy-manager?utm_source=nginx-proxy-manager" target="_blank"><%- i18n('footer', 'fork-me') %></a></li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@
<form> <form>
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<%= i18n('users', 'delete-confirm', {name: name}) %> <%= i18n('users', 'delete-confirm', {name: name.toHtmlEntities()}) %>
</div> </div>
</div> </div>
</form> </form>

View File

@@ -3,6 +3,14 @@
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><%- i18n('users', 'title') %></h3> <h3 class="card-title"><%- i18n('users', 'title') %></h3>
<div class="card-options"> <div class="card-options">
<form class="search-form" role="search">
<div class="input-icon">
<span class="input-icon-addon">
<i class="fe fe-search"></i>
</span>
<input name="source-query" type="text" value="" class="form-control form-control-sm" placeholder="<%- i18n('users', 'search') %>" aria-label="<%- i18n('users', 'search') %>">
</div>
</form>
<a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('users', 'add') %></a> <a href="#" class="btn btn-outline-teal btn-sm ml-2 add-item"><%- i18n('users', 'add') %></a>
</div> </div>
</div> </div>

View File

@@ -12,7 +12,29 @@ module.exports = Mn.View.extend({
ui: { ui: {
list_region: '.list-region', list_region: '.list-region',
add: '.add-item', add: '.add-item',
dimmer: '.dimmer' dimmer: '.dimmer',
search: '.search-form',
query: 'input[name="source-query"]'
},
fetch: App.Api.Users.getAll,
showData: function(response) {
this.showChildView('list_region', new ListView({
collection: new UserModel.Collection(response)
}));
},
showError: function(err) {
this.showChildView('list_region', new ErrorView({
code: err.code,
message: err.message,
retry: function () {
App.Controller.showUsers();
}
}));
console.error(err);
}, },
regions: { regions: {
@@ -23,30 +45,31 @@ module.exports = Mn.View.extend({
'click @ui.add': function (e) { 'click @ui.add': function (e) {
e.preventDefault(); e.preventDefault();
App.Controller.showUserForm(new UserModel.Model()); App.Controller.showUserForm(new UserModel.Model());
},
'submit @ui.search': function (e) {
e.preventDefault();
let query = this.ui.query.val();
this.fetch(['permissions'], query)
.then(response => this.showData(response))
.catch(err => {
this.showError(err);
});
} }
}, },
onRender: function () { onRender: function () {
let view = this; let view = this;
App.Api.Users.getAll(['permissions']) view.fetch(['permissions'])
.then(response => { .then(response => {
if (!view.isDestroyed() && response && response.length) { if (!view.isDestroyed() && response && response.length) {
view.showChildView('list_region', new ListView({ view.showData(response);
collection: new UserModel.Collection(response)
}));
} }
}) })
.catch(err => { .catch(err => {
view.showChildView('list_region', new ErrorView({ view.showError(err);
code: err.code,
message: err.message,
retry: function () {
App.Controller.showUsers();
}
}));
console.error(err);
}) })
.then(() => { .then(() => {
view.ui.dimmer.removeClass('active'); view.ui.dimmer.removeClass('active');

View File

@@ -60,7 +60,7 @@
}, },
"footer": { "footer": {
"fork-me": "Fork me on Github", "fork-me": "Fork me on Github",
"copy": "&copy; 2021 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.", "copy": "&copy; 2022 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>" "theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
}, },
"dashboard": { "dashboard": {
@@ -132,7 +132,8 @@
"access-list": "Access List", "access-list": "Access List",
"allow-websocket-upgrade": "Websockets Support", "allow-websocket-upgrade": "Websockets Support",
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL", "ignore-invalid-upstream-ssl": "Ignore Invalid SSL",
"custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path" "custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/",
"search": "Search Host…"
}, },
"redirection-hosts": { "redirection-hosts": {
"title": "Redirection Hosts", "title": "Redirection Hosts",
@@ -146,7 +147,8 @@
"delete": "Delete Redirection Host", "delete": "Delete Redirection Host",
"delete-confirm": "Are you sure you want to delete the Redirection host for: <strong>{domains}</strong>?", "delete-confirm": "Are you sure you want to delete the Redirection host for: <strong>{domains}</strong>?",
"help-title": "What is a Redirection Host?", "help-title": "What is a Redirection Host?",
"help-content": "A Redirection Host will redirect requests from the incoming domain and push the viewer to another domain.\nThe most common reason to use this type of host is when your website changes domains but you still have search engine or referrer links pointing to the old domain." "help-content": "A Redirection Host will redirect requests from the incoming domain and push the viewer to another domain.\nThe most common reason to use this type of host is when your website changes domains but you still have search engine or referrer links pointing to the old domain.",
"search": "Search Host…"
}, },
"dead-hosts": { "dead-hosts": {
"title": "404 Hosts", "title": "404 Hosts",
@@ -156,7 +158,8 @@
"delete": "Delete 404 Host", "delete": "Delete 404 Host",
"delete-confirm": "Are you sure you want to delete this 404 Host?", "delete-confirm": "Are you sure you want to delete this 404 Host?",
"help-title": "What is a 404 Host?", "help-title": "What is a 404 Host?",
"help-content": "A 404 Host is simply a host setup that shows a 404 page.\nThis can be useful when your domain is listed in search engines and you want to provide a nicer error page or specifically to tell the search indexers that the domain pages no longer exist.\nAnother benefit of having this host is to track the logs for hits to it and view the referrers." "help-content": "A 404 Host is simply a host setup that shows a 404 page.\nThis can be useful when your domain is listed in search engines and you want to provide a nicer error page or specifically to tell the search indexers that the domain pages no longer exist.\nAnother benefit of having this host is to track the logs for hits to it and view the referrers.",
"search": "Search Host…"
}, },
"streams": { "streams": {
"title": "Streams", "title": "Streams",
@@ -175,7 +178,8 @@
"delete": "Delete Stream", "delete": "Delete Stream",
"delete-confirm": "Are you sure you want to delete this Stream?", "delete-confirm": "Are you sure you want to delete this Stream?",
"help-title": "What is a Stream?", "help-title": "What is a Stream?",
"help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy." "help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.",
"search": "Search Incoming Port…"
}, },
"certificates": { "certificates": {
"title": "SSL Certificates", "title": "SSL Certificates",
@@ -201,7 +205,8 @@
"reachability-wrong-data": "There is a server found at this domain but it returned an unexpected data. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.", "reachability-wrong-data": "There is a server found at this domain but it returned an unexpected data. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.",
"reachability-other": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.", "reachability-other": "There is a server found at this domain but it returned an unexpected status code {code}. Is it the NPM server? Please make sure your domain points to the IP where your NPM instance is running.",
"download": "Download", "download": "Download",
"renew-title": "Renew Let'sEncrypt Certificate" "renew-title": "Renew Let's Encrypt Certificate",
"search": "Search Certificate…"
}, },
"access-lists": { "access-lists": {
"title": "Access Lists", "title": "Access Lists",
@@ -225,7 +230,8 @@
"satisfy-any": "Satisfy Any", "satisfy-any": "Satisfy Any",
"pass-auth": "Pass Auth to Host", "pass-auth": "Pass Auth to Host",
"access-add": "Add", "access-add": "Add",
"auth-add": "Add" "auth-add": "Add",
"search": "Search Access…"
}, },
"users": { "users": {
"title": "Users", "title": "Users",
@@ -251,7 +257,8 @@
"perms-visibility-all": "All Items", "perms-visibility-all": "All Items",
"perm-manage": "Manage", "perm-manage": "Manage",
"perm-view": "View Only", "perm-view": "View Only",
"perm-hidden": "Hidden" "perm-hidden": "Hidden",
"search": "Search User…"
}, },
"audit-log": { "audit-log": {
"title": "Audit Log", "title": "Audit Log",
@@ -272,7 +279,8 @@
"renewed": "Renewed {name}", "renewed": "Renewed {name}",
"meta-title": "Details for Event", "meta-title": "Details for Event",
"view-meta": "View Details", "view-meta": "View Details",
"date": "Date" "date": "Date",
"search": "Search Log…"
}, },
"settings": { "settings": {
"title": "Settings", "title": "Settings",

View File

@@ -103,6 +103,13 @@ window.tabler = {
} }
}; };
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
// return "&#" + s.charCodeAt(0) + ";";
return (s.match(/[a-z0-9\s]+/i)) ? s : "&#" + s.charCodeAt(0) + ";";
});
};
require('tabler-core'); require('tabler-core');
const App = require('./app/main'); const App = require('./app/main');

View File

@@ -17,7 +17,7 @@
<div class="card-title"><%- i18n('login', 'title') %></div> <div class="card-title"><%- i18n('login', 'title') %></div>
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('str', 'email-address') %></label> <label class="form-label"><%- i18n('str', 'email-address') %></label>
<input name="identity" type="email" class="form-control" placeholder="<%- i18n('str', 'email-address') %>" required autofocus> <input name="identity" type="email" class="form-control" placeholder="<%- i18n('str', 'email-address') %>" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('str', 'password') %></label> <label class="form-label"><%- i18n('str', 'password') %></label>

View File

@@ -26,7 +26,7 @@
"messageformat": "^2.3.0", "messageformat": "^2.3.0",
"messageformat-loader": "^0.8.1", "messageformat-loader": "^0.8.1",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"moment": "^2.24.0", "moment": "^2.29.4",
"node-sass": "^6.0.1", "node-sass": "^6.0.1",
"nodemon": "^2.0.2", "nodemon": "^2.0.2",
"numeral": "^2.0.6", "numeral": "^2.0.6",

View File

@@ -1501,9 +1501,9 @@ browserslist@^3.2.6:
electron-to-chromium "^1.3.47" electron-to-chromium "^1.3.47"
buffer-from@^1.0.0: buffer-from@^1.0.0:
version "1.1.1" version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer-xor@^1.0.3: buffer-xor@^1.0.3:
version "1.0.3" version "1.0.3"
@@ -4433,10 +4433,10 @@ mkdirp@^1.0.3:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
moment@^2.24.0: moment@^2.29.4:
version "2.27.0" version "2.29.4"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
move-concurrently@^1.0.1: move-concurrently@^1.0.1:
version "1.0.1" version "1.0.1"
@@ -5863,9 +5863,9 @@ source-map-support@^0.4.15:
source-map "^0.5.6" source-map "^0.5.6"
source-map-support@~0.5.12: source-map-support@~0.5.12:
version "0.5.19" version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies: dependencies:
buffer-from "^1.0.0" buffer-from "^1.0.0"
source-map "^0.6.0" source-map "^0.6.0"
@@ -6214,9 +6214,9 @@ terser-webpack-plugin@^1.4.3:
worker-farm "^1.7.0" worker-farm "^1.7.0"
terser@^4.1.2, terser@^4.6.3: terser@^4.1.2, terser@^4.6.3:
version "4.8.0" version "4.8.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f"
integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==
dependencies: dependencies:
commander "^2.20.0" commander "^2.20.0"
source-map "~0.6.1" source-map "~0.6.1"

View File

@@ -147,7 +147,7 @@ dns_desec_endpoint = https://desec.io/api/v1/`,
duckdns: { duckdns: {
display_name: 'DuckDNS', display_name: 'DuckDNS',
package_name: 'certbot-dns-duckdns', package_name: 'certbot-dns-duckdns',
version_requirement: '~=0.6', version_requirement: '~=0.9',
dependencies: '', dependencies: '',
credentials: 'dns_duckdns_token=your-duckdns-token', credentials: 'dns_duckdns_token=your-duckdns-token',
full_plugin_name: 'dns-duckdns', full_plugin_name: 'dns-duckdns',
@@ -202,15 +202,6 @@ dns_dnspod_api_token = "id,key"`,
full_plugin_name: 'dns-dnspod', full_plugin_name: 'dns-dnspod',
}, },
//####################################################// //####################################################//
domeneshop: {
display_name: 'Domeneshop',
package_name: 'certbot-dns-domeneshop',
version_requirement: '~=0.2.8',
dependencies: '',
credentials: `dns_domeneshop_client_token=YOUR_DOMENESHOP_CLIENT_TOKEN
dns_domeneshop_client_secret=YOUR_DOMENESHOP_CLIENT_SECRET`,
full_plugin_name: 'dns-domeneshop',
},
dynu: { dynu: {
display_name: 'Dynu', display_name: 'Dynu',
package_name: 'certbot-dns-dynu', package_name: 'certbot-dns-dynu',
@@ -485,7 +476,7 @@ aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,
transip: { transip: {
display_name: 'TransIP', display_name: 'TransIP',
package_name: 'certbot-dns-transip', package_name: 'certbot-dns-transip',
version_requirement: '~=0.3.3', version_requirement: '~=0.4.3',
dependencies: '', dependencies: '',
credentials: `dns_transip_username = my_username credentials: `dns_transip_username = my_username
dns_transip_key_file = /etc/letsencrypt/transip-rsa.key`, dns_transip_key_file = /etc/letsencrypt/transip-rsa.key`,

View File

@@ -12,7 +12,7 @@ cd "${DIR}"
export DOCKER_IMAGE=baudneo/nginx-proxy-manager export DOCKER_IMAGE=baudneo/nginx-proxy-manager
export MAINTAINER="baudneo <baudneo@protonmail.com>" export MAINTAINER="baudneo <baudneo@protonmail.com>"
export REPO_OWNER="baudneo" export REPO_OWNER="baudneo"
export BASE_TAG='local_latest' export BASE_TAG='latest'
export TARGETPLATFORM=amd64 export TARGETPLATFORM=amd64
export BUILD_VERSION=dev export BUILD_VERSION=dev

View File

@@ -1,12 +1,13 @@
#!/bin/bash -e #!/bin/bash
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/.common.sh" . "$DIR/.common.sh"
DOCKER_IMAGE=baudneo/nginx-full:local_certbot-node DOCKER_IMAGE='baudneo/nginx-full:certbot-node'
# Ensure docker exists # Ensure docker exists
if hash docker 2>/dev/null; then if hash docker 2>/dev/null; then
docker pull "${DOCKER_IMAGE}" docker pull "${DOCKER_IMAGE}"
cd "${DIR}/.." cd "${DIR}/.."
echo -e "${BLUE} ${CYAN}Building Frontend ...${RESET}" echo -e "${BLUE} ${CYAN}Building Frontend ...${RESET}"