Merge branch 'master' into vnstat-multi-interface

This commit is contained in:
Ben Smithurst 2025-11-03 22:41:54 +00:00
commit 4c62ca8a17
860 changed files with 50743 additions and 13525 deletions

23
LICENSE
View file

@ -1,4 +1,4 @@
Copyright (c) 2023 A. Kulikov <kulikov.a@gmail.com>
Copyright (c) 2023-2025 A. Kulikov <kulikov.a@gmail.com>
Copyright (c) 2015-2025 Ad Schellevis <ad@opnsense.org>
Copyright (c) 2022 agh1467 <agh1467@protonmail.com>
Copyright (c) 2024 Alex Smith
@ -8,6 +8,7 @@ Copyright (c) 2021 Axelrtgs
Copyright (c) 2023 Bernhard Frenking <bernhard@frenking.eu>
Copyright (c) 2023 Cannon Matthews <cannonmatthews@google.com>
Copyright (c) 2023-2025 Cedrik Pischem
Copyright (c) 2025 Christopher Linn, BackendMedia IT-Services GmbH
Copyright (c) 2019 Cloudfence - Julio Camargo (JCC)
Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com>
Copyright (c) 2021 Dan Lundqvist
@ -19,7 +20,7 @@ Copyright (c) 2020 devNan0 <nan0@nan0.dev>
Copyright (c) 2023 Dmitry Shinkaruk
Copyright (c) 2024 DollarSign23
Copyright (c) 2006 Eric Friesen
Copyright (c) 2008-2010 Ermal Luçi
Copyright (c) 2008-2014 Ermal Luçi
Copyright (c) 2016-2019 EURO-LOG AG
Copyright (c) 2017-2020 Fabian Franz
Copyright (c) 2019 Felix Matouschek <felix@matouschek.org>
@ -41,24 +42,32 @@ Copyright (c) 2024 laraveluser
Copyright (c) 2023 Liam Steckler <liam@liamsteckler.com>
Copyright (c) 2020-2021 Manuel Faux
Copyright (c) 2021 Manuel Hofmann
Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>
Copyright (c) 2003-2005 Manuel Kasper <mk@neon1.net>
Copyright (c) 2023 Marc Bartelt
Copyright (c) 2021 Marcel Koepfli
Copyright (c) 2021 Markus Peter <mpeter@one-it.de>
Copyright (c) 2022 Markus Reiter <me@reitermark.us>
Copyright (c) 2020 Martin Wasley
Copyright (c) 2022 Marvo2011
Copyright (c) 2017-2024 Michael Muenz <m.muenz@gmail.com>
Copyright (c) 2025 Matthias Valvekens <dev@mvalvekens.be>
Copyright (c) 2025 Maxime Thiebaut
Copyright (c) 2017-2025 Michael Muenz <m.muenz@gmail.com>
Copyright (c) 2024 Michał Brzeziński
Copyright (c) 2024 Mike Shuey
Copyright (c) 2023-2024 Mikhail Kharisov
Copyright (c) 2023 mleinart
Copyright (c) 2024 MVZ Labor Ludwigsburg GbR
Copyright (c) 2025 Neil Merchant
Copyright (c) 2025 NetBird GmbH
Copyright (c) 2025 Nick Card
Copyright (c) 2021-2024 Nicola Pellegrini
Copyright (c) 2022 Nikolaj Brinch Jørgensen
Copyright (c) 2021 Nim G
Copyright (c) 2023 Oliver Hartl
Copyright (c) 2025 Oliver Traber <hi@bluemedia.dev>
Copyright (c) 2024 Olly Baker <ilumos@gmail.com>
Copyright (c) 2019 Pascal Mathis <mail@pascalmathis.com>
Copyright (c) 2025 Ralph Moser, PJ Monitoring GmbH
Copyright (c) 2024 realizelol
Copyright (c) 2022 Robbert Rijkse
Copyright (c) 2023 sattamjh
@ -66,14 +75,16 @@ Copyright (c) 2004-2012 Scott Ullrich <sullrich@gmail.com>
Copyright (c) 2010 Seth Mos <seth.mos@dds.nl>
Copyright (c) 2024 Sheridan Computers
Copyright (c) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
Copyright (c) 2017-2019 Smart-Soft
Copyright (c) 2013 Stanley P. Miller \ stan-qaz
Copyright (c) 2017-2018 Smart-Soft
Copyright (c) 2025 squared GmbH
Copyright (c) 2020 Starkstromkonsument
Copyright (c) 2023-2024 Thomas Cekal <thomas@cekal.org>
Copyright (c) 2020 Tobias Boehnert
Copyright (c) 2024 txr13
Copyright (c) 2024 W516
Copyright (c) 2022 Wouter Deurholt
Copyright (c) 2025 Yann Bayart
Copyright (c) 2025 Yann Demoulin
Copyright (c) 2015 YoungJoo.Kim <vozltx@gmail.com>
All rights reserved.

View file

@ -1,4 +1,4 @@
# Copyright (c) 2015-2024 Franco Fichtner <franco@opnsense.org>
# Copyright (c) 2015-2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@ -23,19 +23,23 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
all:
@cat ${.CURDIR}/README.md | ${PAGER}
PLUGINSDIR?= ${.CURDIR}
.include "Mk/defaults.mk"
CATEGORIES!= ls -1d [a-z0-9]*
CATEGORIES:= ${CATEGORIES:Nruleset.xml}
_CATEGORIES!= ls -1d [a-z0-9]*
CATEGORIES?= ${_CATEGORIES}
.for CATEGORY in ${CATEGORIES}
_${CATEGORY}!= ls -1d ${CATEGORY}/*
PLUGIN_DIRS+= ${_${CATEGORY}}
.endfor
all:
@cat ${.CURDIR}/README.md | ${PAGER}
.include "Mk/defaults.mk"
.include "Mk/common.mk"
.include "Mk/git.mk"
list:
.for PLUGIN_DIR in ${PLUGIN_DIRS}
@echo ${PLUGIN_DIR} -- $$(${MAKE} -C ${PLUGIN_DIR} -v PLUGIN_COMMENT) \
@ -44,7 +48,7 @@ list:
.endfor
# shared targets that are sane to run from the root directory
TARGETS= clean glint lint plist-fix revision style style-fix style-python sweep test
TARGETS= clean glint lint revision style sweep test
.for TARGET in ${TARGETS}
${TARGET}:

26
Mk/common.mk Normal file
View file

@ -0,0 +1,26 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
.-include "${PLUGINSDIR}/../core/Mk/common.mk"

46
Mk/contrib.mk Normal file
View file

@ -0,0 +1,46 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
.for TARGET in ${PLUGIN_CONTRIB}
.if "${ROOT_${TARGET}}" == ""
.error "No ROOT directory set for target: ${TARGET}"
.endif
# fixup root target dir
ROOT_${TARGET}:=${ROOT_${TARGET}:S/^\/$//}
install-${TARGET}:
@mkdir -p ${DESTDIR}${ROOT_${TARGET}}/${TARGET}
@tar -C ${TARGET} -cf - . | tar -C ${DESTDIR}${ROOT_${TARGET}}/${TARGET} -xf -
install: install-${TARGET}
plist-${TARGET}:
@(cd ${TARGET}; find * -type f) | while read FILE; do \
echo "${ROOT_${TARGET}}/${TARGET}/$${FILE}"; \
done
plist: plist-${TARGET}
.endfor

View file

@ -34,6 +34,9 @@ PKG= true
.endif
GIT!= which git || echo true
SCRIPTSDIR= ${PLUGINSDIR}/Scripts
TEMPLATESDIR= ${PLUGINSDIR}/Templates
GITVERSION= ${SCRIPTSDIR}/version.sh
_PLUGIN_ARCH!= uname -p
@ -43,11 +46,13 @@ VERSIONBIN= ${LOCALBASE}/sbin/opnsense-version
.if exists(${VERSIONBIN})
_PLUGIN_ABI!= ${VERSIONBIN} -a
PLUGIN_ABI?= ${_PLUGIN_ABI}
PLUGIN_ABIS?= ${_PLUGIN_ABI}
.else
PLUGIN_ABI?= 25.1
PLUGIN_ABIS?= 25.7
.endif
PLUGIN_ABI?= ${PLUGIN_ABIS:[1]}
PLUGIN_MAINS= master main
PLUGIN_MAIN?= ${PLUGIN_MAINS:[1]}
PLUGIN_STABLE?= stable/${PLUGIN_ABI}
@ -66,7 +71,6 @@ _PLUGIN_PYTHON!=${PYTHONLINK} -V
PLUGIN_PYTHON?= ${_PLUGIN_PYTHON:[2]:S/./ /g:[1..2]:tW:S/ //}
.endif
.for REPLACEMENT in ABI PHP PYTHON
. if empty(PLUGIN_${REPLACEMENT})
. warning Cannot build without PLUGIN_${REPLACEMENT} set
@ -91,78 +95,8 @@ SED_REPLACE= # empty
SED_REPLACE+= -e "s=%%${REPLACEMENT}%%=${${REPLACEMENT}}=g"
.endfor
ARGS= diff feed mfc
# handle argument expansion for required targets
.for TARGET in ${.TARGETS}
_TARGET= ${TARGET:C/\-.*//}
.if ${_TARGET} != ${TARGET}
.for ARGUMENT in ${ARGS}
.if ${_TARGET} == ${ARGUMENT}
${_TARGET}_ARGS+= ${TARGET:C/^[^\-]*(\-|\$)//:S/,/ /g}
${TARGET}: ${_TARGET}
.endif
.endfor
${_TARGET}_ARG= ${${_TARGET}_ARGS:[0]}
.endif
.endfor
ensure-stable:
@if ! git show-ref --verify --quiet refs/heads/${PLUGIN_STABLE}; then \
git update-ref refs/heads/${PLUGIN_STABLE} refs/remotes/origin/${PLUGIN_STABLE}; \
git config branch.${PLUGIN_STABLE}.merge refs/heads/${PLUGIN_STABLE}; \
git config branch.${PLUGIN_STABLE}.remote origin; \
fi
diff_ARGS?= .
diff: ensure-stable
@git diff --stat -p ${PLUGIN_STABLE} ${.CURDIR}/${diff_ARGS:[1]}
feed: ensure-stable
@git log --stat -p --reverse ${PLUGIN_STABLE}...${feed_ARGS:[1]}~1
mfc_ARGS?= .
mfc: ensure-stable
.for MFC in ${mfc_ARGS}
.if exists(${MFC})
@git diff --stat -p ${PLUGIN_STABLE} ${.CURDIR}/${MFC} > /tmp/mfc.diff
@git checkout ${PLUGIN_STABLE}
@git apply /tmp/mfc.diff
@git add ${.CURDIR}/${MFC}
@if ! git diff --quiet HEAD; then \
git commit -m "${MFC:S/^.$/${PLUGIN_DIR}/}: sync with ${PLUGIN_MAIN}"; \
fi
.else
@git checkout ${PLUGIN_STABLE}
@if ! git cherry-pick -x ${MFC}; then \
git cherry-pick --abort; \
fi
.endif
@git checkout ${PLUGIN_MAIN}
.endfor
stable:
@git checkout ${PLUGIN_STABLE}
${PLUGIN_MAINS}:
@git checkout ${PLUGIN_MAIN}
rebase:
@git checkout ${PLUGIN_STABLE}
@git rebase -i
@git checkout ${PLUGIN_MAIN}
log:
@git log --stat -p ${PLUGIN_STABLE}
push:
@git checkout ${PLUGIN_STABLE}
@git push
@git checkout ${PLUGIN_MAIN}
reset:
@git checkout ${PLUGIN_STABLE}
@git reset --hard HEAD~1
@git checkout ${PLUGIN_MAIN}
WRKDIR?= ${.CURDIR}/work
MFCDIR?= /tmp/mfc.dir
PKGDIR?= ${WRKDIR}/pkg
WRKSRC?= ${WRKDIR}/src
TESTDIR?= ${.CURDIR}/src/opnsense/mvc/tests

28
Mk/devel.mk Normal file
View file

@ -0,0 +1,28 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# This file merely exists on the development
# branch to force plugins to development mode:
PLUGIN_DEVEL?= yes

32
Mk/git.mk Normal file
View file

@ -0,0 +1,32 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
CORE_ABI= ${PLUGIN_ABI}
CORE_ABIS= ${PLUGIN_ABIS}
CORE_MAIN= ${PLUGIN_MAIN}
CORE_MAINS= ${PLUGIN_MAINS}
CORE_STABLE= ${PLUGIN_STABLE}
.-include "${PLUGINSDIR}/../core/Mk/git.mk"

26
Mk/lint.mk Normal file
View file

@ -0,0 +1,26 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
.-include "${PLUGINSDIR}/../core/Mk/lint.mk"

View file

@ -1,4 +1,4 @@
# Copyright (c) 2015-2024 Franco Fichtner <franco@opnsense.org>
# Copyright (c) 2015-2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@ -23,14 +23,13 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
PLUGINSDIR?= ${.CURDIR}/../..
all: check
@cat ${.CURDIR}/${PLUGIN_DESC} | ${PAGER}
.include "defaults.mk"
PLUGINSDIR?= ${.CURDIR}/../..
SCRIPTSDIR= ${PLUGINSDIR}/Scripts
TEMPLATESDIR= ${PLUGINSDIR}/Templates
.if exists(${GIT}) && exists(${GITVERSION})
PLUGIN_COMMIT!= ${GITVERSION}
.else
@ -51,6 +50,12 @@ PLUGIN_REVISION?= 0
PLUGIN_REQUIRES= PLUGIN_NAME PLUGIN_VERSION PLUGIN_COMMENT \
PLUGIN_MAINTAINER
.include "common.mk"
.include "git.mk"
.include "lint.mk"
.include "style.mk"
.include "sweep.mk"
check:
.for PLUGIN_REQUIRE in ${PLUGIN_REQUIRES}
. if "${${PLUGIN_REQUIRE}}" == ""
@ -63,7 +68,7 @@ _PLUGIN_COMMENT:= ${PLUGIN_COMMENT}
.if defined(_PLUGIN_DEVEL)
PLUGIN_DEVEL?:= ${_PLUGIN_DEVEL}
.else
PLUGIN_DEVEL?= yes
.-include "devel.mk"
.endif
PLUGIN_PREFIX?= os-
@ -100,6 +105,7 @@ PLUGIN_DIR?= ${.CURDIR:S/\// /g:[-2]}/${.CURDIR:S/\// /g:[-1]}
.if "${PLUGIN_DEVEL}" != ""
PLUGIN_CONFLICTS+= ${PLUGIN_NAME}
PLUGIN_PKGSUFFIX= ${PLUGIN_SUFFIX}
PLUGIN_TIER= 4
.else
PLUGIN_CONFLICTS+= ${PLUGIN_NAME}${PLUGIN_SUFFIX}
PLUGIN_PKGSUFFIX= # empty
@ -146,13 +152,26 @@ manifest: check
echo "annotations $$(cat ${WRKSRC}${LOCALBASE}/opnsense/version/${PLUGIN_NAME})"; \
fi
scripts: check scripts-pre scripts-auto scripts-manual scripts-post
# Package scripts generation handling 101:
#
# "auto" generates automatic hooks that a plugin may need in order to
# reload on the fly. ".pre" and ".post" suffixed files can be used to
# extend the auto-generated content.
#
# "manual" overwrites the automatic script and also ignores ".pre" and
# ".post" files since they do not make sense in manual mode.
#
# Furthermore, variable replacement via %%PLUGIN_VAR%% takes place in
# "manual" as well as ".pre" and ".post" scripts provided.
scripts: check scripts-pre scripts-auto scripts-post scripts-manual
scripts-pre:
@for SCRIPT in ${PLUGIN_SCRIPTS}; do \
rm -f ${DESTDIR}/$${SCRIPT}; \
if [ -f ${.CURDIR}/$${SCRIPT}.pre ]; then \
cp ${.CURDIR}/$${SCRIPT}.pre ${DESTDIR}/$${SCRIPT}; \
sed ${SED_REPLACE} -- ${.CURDIR}/$${SCRIPT}.pre > \
${DESTDIR}/$${SCRIPT}; \
fi; \
done
@ -203,22 +222,25 @@ scripts-auto:
done \
fi
scripts-manual:
@for SCRIPT in ${PLUGIN_SCRIPTS}; do \
if [ -f ${.CURDIR}/$${SCRIPT} ]; then \
cp ${.CURDIR}/$${SCRIPT} ${DESTDIR}/$${SCRIPT}; \
fi; \
done
scripts-post:
@for SCRIPT in ${PLUGIN_SCRIPTS}; do \
if [ -f ${.CURDIR}/$${SCRIPT}.post ]; then \
cat ${.CURDIR}/$${SCRIPT}.post >> ${DESTDIR}/$${SCRIPT}; \
sed ${SED_REPLACE} -- ${.CURDIR}/$${SCRIPT}.post >> \
${DESTDIR}/$${SCRIPT}; \
fi; \
done
scripts-manual:
@for SCRIPT in ${PLUGIN_SCRIPTS}; do \
if [ -f ${.CURDIR}/$${SCRIPT} ]; then \
sed ${SED_REPLACE} -- ${.CURDIR}/$${SCRIPT} > \
${DESTDIR}/$${SCRIPT}; \
fi; \
done
install: check
@mkdir -p ${DESTDIR}${LOCALBASE}/opnsense/version
@if [ -d ${.CURDIR}/contrib ]; then ${MAKE} DESTDIR=$$(readlink -f ${DESTDIR}) -C ${.CURDIR}/contrib install; fi
@(cd ${.CURDIR}/src 2> /dev/null && find * -type f) | while read FILE; do \
tar -C ${.CURDIR}/src -cpf - "$${FILE}" | \
tar -C ${DESTDIR}${LOCALBASE} -xpf -; \
@ -240,7 +262,10 @@ install: check
@cat ${TEMPLATESDIR}/version | sed ${SED_REPLACE} > "${DESTDIR}${LOCALBASE}/opnsense/version/${PLUGIN_NAME}"
plist: check
@(cd ${.CURDIR}/src 2> /dev/null && find * -type f) | while read FILE; do \
@(if [ -d ${.CURDIR}/contrib ]; then \
${MAKE} -C ${.CURDIR}/contrib plist; \
fi; \
(cd ${.CURDIR}/src 2> /dev/null && find * -type f) | while read FILE; do \
if [ -f "$${FILE}.in" ]; then continue; fi; \
FILE="$${FILE%%.in}"; PREFIX=""; \
if [ "$${FILE%%.sample}" != "$${FILE}" ]; then \
@ -253,8 +278,9 @@ plist: check
FILE="$${FILE}.gz"; \
fi; \
echo "$${PREFIX}${LOCALBASE}/$${FILE}"; \
done
@echo "${LOCALBASE}/opnsense/version/${PLUGIN_NAME}"
done; \
echo "${LOCALBASE}/opnsense/version/${PLUGIN_NAME}" \
) | sort
description: check
@if [ -f ${.CURDIR}/${PLUGIN_DESC} ]; then \
@ -284,13 +310,6 @@ remove: check
fi; \
done
WRKDIR?=${.CURDIR}/work
WRKSRC?=${WRKDIR}/src
PKGDIR?=${WRKDIR}/pkg
ensure-workdirs:
@mkdir -p ${WRKSRC} ${PKGDIR}
package: check
@rm -rf ${WRKSRC}
@mkdir -p ${WRKSRC} ${PKGDIR}
@ -334,142 +353,20 @@ clean: check
fi
@rm -rf ${.CURDIR}/work
lint-desc: check
@if [ ! -f ${.CURDIR}/${PLUGIN_DESC} ]; then \
echo ">>> Missing ${PLUGIN_DESC}"; exit 1; \
fi
lint-shell:
@for FILE in $$(find ${.CURDIR}/src -name "*.sh" -type f); do \
if [ "$$(head $${FILE} | grep -c '^#!\/')" == "0" ]; then \
echo "Missing shebang in $${FILE}"; exit 1; \
fi; \
sh -n "$${FILE}" || exit 1; \
done
lint-xml:
@find ${.CURDIR}/src \
-name "*.xml" -type f -print0 | xargs -0 -n1 xmllint --noout
lint-model:
@if [ -d ${.CURDIR}/src/opnsense/mvc/app/models ]; then for MODEL in $$(find ${.CURDIR}/src/opnsense/mvc/app/models -depth 3 \
-name "*.xml"); do \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and (not(Required) or Required="N") and Default]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} has a spurious default value set"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and Default=""]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} has an empty default value set"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and BlankDesc="None"]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} blank description is the default"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and BlankDesc and Required="Y"]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} blank description not applicable on required field"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and BlankDesc and Multiple="Y"]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} blank description not applicable on multiple field"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and Multiple="N"]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} Multiple=N is the default"; \
done; \
(xmllint $${MODEL} --xpath '//*[@type and not(@type="ArrayField") and OptionValues[default[not(@value)] or multiple[not(@value)] or required[not(@value)]]]' 2> /dev/null | grep '^<' || true) | while read LINE; do \
echo "$${MODEL}: $${LINE} option element default/multiple/required without value attribute"; \
done; \
done; fi
ACLBIN?= ${.CURDIR}/../../../core/Scripts/dashboard-acl.sh
lint-acl: check
.if exists(${ACLBIN})
@${ACLBIN} ${.CURDIR}/../../../core
.else
@echo "Did not find ACLBIN, please provide a core repository"; exit 1
.endif
lint-exec: check
.for DIR in ${.CURDIR}/src/opnsense/scripts ${.CURDIR}/src/etc/rc.d ${.CURDIR}/src/etc/rc.syshook.d
.if exists(${DIR})
@find ${DIR} -type f ! -name "*.xml" -print0 | \
xargs -0 -t -n1 test -x || \
(echo "Missing executable permission in ${DIR}"; exit 1)
.endif
.endfor
LINTBIN?= ${.CURDIR}/../../../core/contrib/parallel-lint/parallel-lint
lint-php: check
.if exists(${LINTBIN})
@if [ -d ${.CURDIR}/src ]; then ${LINTBIN} src; fi
.else
@echo "Did not find LINTBIN, please provide a core repository"; exit 1
.endif
lint: lint-desc lint-shell lint-xml lint-model lint-acl lint-exec lint-php
plist-fix:
sweep: check
find ${.CURDIR}/src -type f -name "*.map" -print0 | \
xargs -0 -n1 rm
find ${.CURDIR}/src ! -name "*.min.*" ! -name "*.svg" \
! -name "*.ser" -type f -print0 | \
xargs -0 -n1 ${SCRIPTSDIR}/cleanfile
find ${.CURDIR} -type f -depth 1 -print0 | \
xargs -0 -n1 ${SCRIPTSDIR}/cleanfile
glint: sweep style-fix plist-fix lint
glint: sweep lint
revision:
@MAKE=${MAKE} ${SCRIPTSDIR}/revbump.sh ${.CURDIR}
STYLEDIRS?= src/etc/inc src/opnsense
style: check
@: > ${.CURDIR}/.style.out
.for STYLEDIR in ${STYLEDIRS}
@if [ -d ${.CURDIR}/${STYLEDIR} ]; then \
(phpcs --standard=${PLUGINSDIR}/ruleset.xml \
${.CURDIR}/${STYLEDIR} || true) > \
${.CURDIR}/.style.out; \
fi
.endfor
@echo -n "Total number of style warnings: "
@grep '| WARNING' ${.CURDIR}/.style.out | wc -l
@echo -n "Total number of style errors: "
@grep '| ERROR' ${.CURDIR}/.style.out | wc -l
@cat ${.CURDIR}/.style.out
@rm ${.CURDIR}/.style.out
style-fix: check
.for STYLEDIR in ${STYLEDIRS}
@if [ -d ${.CURDIR}/${STYLEDIR} ]; then \
phpcbf --standard=${PLUGINSDIR}/ruleset.xml \
${.CURDIR}/${STYLEDIR} || true; \
fi
.endfor
style-python: check
@if [ -d ${.CURDIR}/src ]; then \
pycodestyle --ignore=E501 ${.CURDIR}/src || true; \
fi
style-model:
@for MODEL in $$(find ${.CURDIR}/src/opnsense/mvc/app/models -depth 3 \
-name "*.xml"); do \
perl -i -pe 's/<default>(.*?)<\/default>/<Default>$$1<\/Default>/g' $${MODEL}; \
perl -i -pe 's/<multiple>(.*?)<\/multiple>/<Multiple>$$1<\/Multiple>/g' $${MODEL}; \
perl -i -pe 's/<required>(.*?)<\/required>/<Required>$$1<\/Required>/g' $${MODEL}; \
done
test: check
@if [ -d ${.CURDIR}/src/opnsense/mvc/tests ]; then \
cd ${LOCALBASE}/opnsense/mvc/tests && \
phpunit --configuration PHPunit.xml \
${.CURDIR}/src/opnsense/mvc/tests; \
fi
.if exists(${TESTDIR})
@cd ${TESTDIR} && phpunit || true; \
rm -rf ${TESTDIR}/.phpunit.result.cache
.endif
commit: ensure-workdirs
commit:
@mkdir -p ${MFCDIR}
@/bin/echo -n "${.CURDIR:C/\// /g:[-2]}/${.CURDIR:C/\// /g:[-1]}: " > \
${WRKDIR}/.commitmsg && git commit -eF ${WRKDIR}/.commitmsg .
${MFCDIR}/.commitmsg && git commit -eF ${MFCDIR}/.commitmsg .
.PHONY: check plist-fix
.PHONY: check

28
Mk/style.mk Normal file
View file

@ -0,0 +1,28 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
CORE_PYTHON_DOT=${PLUGIN_PYTHON:C/./&./1}
.-include "${PLUGINSDIR}/../core/Mk/style.mk"

26
Mk/sweep.mk Normal file
View file

@ -0,0 +1,26 @@
# Copyright (c) 2025 Franco Fichtner <franco@opnsense.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
.-include "${PLUGINSDIR}/../core/Mk/sweep.mk"

View file

@ -42,8 +42,9 @@ emulators/qemu-guest-agent -- QEMU Guest Agent for OPNsense
ftp/tftp -- TFTP server
mail/postfix -- SMTP mail relay
mail/rspamd -- Protect your network from spam
misc/theme-advanced -- OPNsense theme based on AdvancedTomato GUI
misc/theme-advanced -- Theme based on AdvancedTomato GUI
misc/theme-cicada -- The cicada theme - dark grey onyx
misc/theme-flexcolor -- Theme with 3 different color schemes: black as default, light and dark-light
misc/theme-rebellion -- A suitably dark theme
misc/theme-tukan -- The tukan theme - blue/white
misc/theme-vicuna -- The vicuna theme - blue sapphire
@ -55,6 +56,7 @@ net/google-cloud-sdk -- Google Cloud SDK
net/haproxy -- Reliable, high performance TCP/HTTP load balancer
net/igmp-proxy -- IGMP-Proxy Service
net/mdns-repeater -- Proxy multicast DNS between networks
net/ndp-proxy-go -- IPv6 Neighbor Discovery Protocol Proxy
net/ndproxy -- Neighbor Discovery Proxy
net/ntopng -- Traffic Analysis and Flow Collection
net/radsecproxy -- RADIUS proxy provides both RADIUS UDP and TCP/TLS (RadSec) transport
@ -64,8 +66,9 @@ net/shadowsocks -- Secure socks5 proxy
net/siproxd -- Siproxd is a proxy daemon for the SIP protocol
net/sslh -- sslh configuration front-end
net/tayga -- Tayga NAT64
net/turnserver -- The coturn STUN/TURN Server
net/udpbroadcastrelay -- Control udpbroadcastrelay processes
net/upnp -- Universal Plug and Play (UPnP IGD & PCP/NAT-PMP) Service
net/upnp -- UPnP IGD & PCP/NAT-PMP Service
net/vnstat -- Network traffic monitor
net/wol -- Wake on LAN Service
net/zerotier -- Virtual Networks That Just Work
@ -83,10 +86,14 @@ security/crowdsec -- Lightweight and collaborative security engine
security/etpro-telemetry -- ET Pro Telemetry Edition
security/intrusion-detection-content-et-open -- IDS Proofpoint full ET open ruleset complementary subset for ET Pro Telemetry edition
security/intrusion-detection-content-et-pro -- IDS Proofpoint ET Pro ruleset (needs a valid subscription)
security/intrusion-detection-content-pt-open -- IDS Positive Technologies ESC ruleset
security/intrusion-detection-content-snort-vrt -- IDS Snort VRT ruleset (needs registration or subscription)
security/maltrail -- Malicious traffic detection system
security/netbird -- Peer-to-peer VPN that seamlessly connects your devices
security/openconnect -- OpenConnect Client
security/softether -- Cross-platform Multi-protocol VPN Program (development only)
security/openvpn-legacy -- OpenVPN legacy support
security/q-feeds-connector -- Connector for Q-Feeds threat intel
security/strongswan-legacy -- IPsec legacy support
security/stunnel -- Stunnel TLS proxy
security/tailscale -- VPN mesh securely connecting clients using WireGuard
security/tinc -- Tinc VPN
@ -94,9 +101,11 @@ security/tor -- The Onion Router
security/wazuh-agent -- Agent for the open source security platform Wazuh
sysutils/apcupsd -- APCUPSD - APC UPS daemon
sysutils/apuled -- PC Engine APU LED control (development only)
sysutils/beats -- Send logs, network, metrics and heartbeat to Elasticsearch
sysutils/cpu-microcode -- CPU microcode updates
sysutils/dec-hw -- Deciso hardware specific information
sysutils/dmidecode -- Display hardware information on the dashboard
sysutils/gdrive-backup -- Backup configurations using Google Drive
sysutils/git-backup -- Track config changes using git
sysutils/hw-probe -- Collect hardware diagnostics
sysutils/lcdproc-sdeclcd -- LCDProc for SDEC LCD devices
@ -106,11 +115,12 @@ sysutils/nextcloud-backup -- Track config changes using NextCloud
sysutils/node_exporter -- Prometheus exporter for machine metrics
sysutils/nut -- Network UPS Tools
sysutils/puppet-agent -- Manage Puppet Agent
sysutils/sftp-backup -- Backup configurations using SFTP
sysutils/smart -- SMART tools
sysutils/virtualbox -- VirtualBox guest additions
sysutils/vmware -- VMware tools
sysutils/xen -- Xen guest utilities
vendor/sunnyvalley -- Vendor Repository for Zenarmor (a.k.a Sensei, Next Generation Firewall Extensions)
vendor/sunnyvalley -- Vendor Repository for Zenarmor (Enterprise Security Modules - NGFW, SSE, SASE, f.k.a Sensei)
www/OPNProxy -- OPNsense proxy additions
www/c-icap -- c-icap connects the web proxy with a virus scanner
www/cache -- Webserver cache
@ -142,9 +152,8 @@ The make targets for the root directory:
* clean: remove all changes and unknown files
* lint: run syntax checks
* list: print a list of all plugin directories with comments
* style-fix: apply style fixes
* style: run style checks
* sweep: apply whitespace fixes
* sweep: apply style fixes
The make targets for any plugin directory:
@ -155,6 +164,5 @@ The make targets for any plugin directory:
* package: creates a package
* upgrade: upgrades existing package
* remove: remove known files from target directory
* style-fix: apply style fixes
* style: run style checks
* sweep: apply whitespace fixes
* sweep: apply style fixes

View file

@ -1,185 +0,0 @@
#!/usr/bin/env perl
#
# Clean a text file -- or directory of text files -- of stealth whitespace.
# WARNING: this can be a highly destructive operation. Use with caution.
#
use bytes;
use File::Basename;
# Default options
$max_width = 0;
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
{
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($lo) = '';
my $pos = 0;
my $nsp = 0;
my($i, $c);
for ($i = 0; $i < length($li); $i++) {
$c = substr($li, $i, 1);
if ($c eq "\t") {
my $npos = ($pos+$nsp+8) & ~7;
my $ntab = ($npos >> 3) - ($pos >> 3);
$lo .= "\t" x $ntab;
$pos = $npos;
$nsp = 0;
} elsif ($c eq "\n" || $c eq "\r") {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos = 0;
} elsif ($c eq " ") {
$nsp++;
} else {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos++;
}
}
$lo .= " " x $nsp;
return $lo;
}
# Compute the visual width of a string
sub strwidth($) {
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($c, $i);
my $pos = 0;
my $mlen = 0;
for ($i = 0; $i < length($li); $i++) {
$c = substr($li,$i,1);
if ($c eq "\t") {
$pos = ($pos+8) & ~7;
} elsif ($c eq "\n") {
$mlen = $pos if ($pos > $mlen);
$pos = 0;
} else {
$pos++;
}
}
$mlen = $pos if ($pos > $mlen);
return $mlen;
}
$name = basename($0);
@files = ();
while (defined($a = shift(@ARGV))) {
if ($a =~ /^-/) {
if ($a eq '-width' || $a eq '-w') {
$max_width = shift(@ARGV)+0;
} else {
print STDERR "Usage: $name [-width #] files...\n";
exit 1;
}
} else {
push(@files, $a);
}
}
foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
print STDERR "$f: not a file\n";
next;
}
if (!open(FILE, '+<', $f)) {
print STDERR "$name: Cannot open file: $f: $!\n";
next;
}
binmode FILE;
# First, verify that it is not a binary file; consider any file
# with a zero byte to be a binary file. Is there any better, or
# additional, heuristic that should be applied?
$is_binary = 0;
while (read(FILE, $data, 65536) > 0) {
if ($data =~ /\0/) {
$is_binary = 1;
last;
}
}
if ($is_binary) {
print STDERR "$name: $f: binary file\n";
next;
}
seek(FILE, 0, 0);
$in_bytes = 0;
$out_bytes = 0;
$blank_bytes = 0;
@blanks = ();
@lines = ();
$last = "\n";
$lineno = 0;
while ( defined($line = <FILE>) ) {
$lineno++;
$in_bytes += length($line);
$line =~ s/[ \t\r]*$//; # Remove trailing spaces
$line = clean_space_tabs($line);
$last = $line;
if ( $line eq "\n" ) {
push(@blanks, $line);
$blank_bytes += length($line);
} else {
push(@lines, @blanks);
$out_bytes += $blank_bytes;
push(@lines, $line);
$out_bytes += length($line);
@blanks = ();
$blank_bytes = 0;
}
$l_width = strwidth($line);
if ($max_width && $l_width > $max_width) {
print STDERR
"$f:$lineno: line exceeds $max_width characters ($l_width)\n";
}
}
if ( chop($last) ne "\n" ) {
# fix missing newline at EOF
push(@lines, "\n");
# increment input bytes to signal character append
$in_bytes += 1;
}
# Any blanks at the end of the file are discarded
if ($in_bytes != $out_bytes) {
# Only write to the file if changed
seek(FILE, 0, 0);
print FILE @lines;
if ( !defined($where = tell(FILE)) ||
!truncate(FILE, $where) ) {
die "$name: Failed to truncate modified file: $f: $!\n";
}
}
close(FILE);
}

View file

@ -67,6 +67,7 @@ sub process_file
my $filename = $File::Find::name;
return if not -f "$cwd/$filename";
return if $filename =~ /\/Private\//;
my @lines = read_file( "$cwd/$filename" );
my $possibly_bsd;

View file

@ -3,9 +3,9 @@
<description>Fake model for the API - will be never stored to config (only used for defaults, validation etc.).</description>
<items>
<interface type="InterfaceField">
<default>lan</default>
<Default>lan</Default>
<Required>Y</Required>
<multiple>N</multiple>
<Multiple>N</Multiple>
</interface>
</items>
</model>

View file

@ -4,27 +4,27 @@
<items>
<general>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<listen type="InterfaceField">
<Required>N</Required>
<multiple>Y</multiple>
<Multiple>Y</Multiple>
</listen>
<protected_mode type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</protected_mode>
<port type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>65536</MaximumValue>
<Required>N</Required>
<default>6379</default>
<Default>6379</Default>
<ValidationMessage>This must be a valid port number.</ValidationMessage>
</port>
<log_level type="OptionField">
<Required>Y</Required>
<default>warning</default>
<Default>warning</Default>
<OptionValues>
<debug>Debug</debug>
<verbose>Verbose</verbose>
@ -33,12 +33,12 @@
</OptionValues>
</log_level>
<syslog_enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</syslog_enabled>
<syslog_facility type="OptionField">
<Required>Y</Required>
<default>LOCAL0</default>
<Default>LOCAL0</Default>
<OptionValues>
<USER>USER</USER>
<LOCAL0>LOCAL0</LOCAL0>
@ -54,7 +54,7 @@
<databases type="IntegerField">
<MinimumValue>0</MinimumValue>
<Required>Y</Required>
<default>16</default>
<Default>16</Default>
</databases>
</general>
<security>
@ -68,7 +68,7 @@
<maxclients type="IntegerField">
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<default>10000</default>
<Default>10000</Default>
</maxclients>
<maxmemory type="IntegerField">
<MinimumValue>0</MinimumValue>
@ -76,7 +76,7 @@
</maxmemory>
<maxmemory_policy type="OptionField">
<Required>Y</Required>
<default>noeviction</default>
<Default>noeviction</Default>
<OptionValues>
<noeviction>noeviction</noeviction>
<volatile-ttl>volatile-ttl</volatile-ttl>
@ -89,19 +89,19 @@
<maxmemory_samples type="IntegerField">
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<default>5</default>
<Default>5</Default>
</maxmemory_samples>
</limits>
<slowlog>
<slower_than type="IntegerField">
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<default>10000</default>
<Default>10000</Default>
</slower_than>
<max_len type="IntegerField">
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<default>128</default>
<Default>128</Default>
</max_len>
</slowlog>
</items>

View file

@ -1,6 +1,5 @@
PLUGIN_NAME= grid_example
PLUGIN_VERSION= 1.0
PLUGIN_REVISION= 1
PLUGIN_VERSION= 1.1
PLUGIN_COMMENT= A sample framework application
PLUGIN_MAINTAINER= ad@opnsense.org

View file

@ -0,0 +1,49 @@
<?php
/**
* Copyright (C) 2015-2025 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\GridExample\Api;
use OPNsense\Base\ApiControllerBase;
/**
* Class ServiceController
* @package OPNsense\GridExample
*/
class ServiceController extends ApiControllerBase
{
/**
* non operational reconfigure for base_apply_button
*/
public function reconfigureAction()
{
sleep(1); // simulate something happening
return ["status" => "ok"];
}
}

View file

@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2019 Deciso B.V.
* Copyright (C) 2019-2025 Deciso B.V.
*
* All rights reserved.
*
@ -43,7 +43,7 @@ class SettingsController extends ApiMutableModelControllerBase
public function searchItemAction()
{
return $this->searchBase("addresses.address", array('enabled', 'email'), "email");
return $this->searchBase("addresses.address", null, "email");
}
public function setItemAction($uuid)

View file

@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2019 Deciso B.V.
* Copyright (C) 2019-2025 Deciso B.V.
*
* All rights reserved.
*
@ -40,5 +40,7 @@ class IndexController extends \OPNsense\Base\IndexController
{
$this->view->pick('OPNsense/GridExample/index');
$this->view->formDialogAddress = $this->getForm("dialogAddress");
// convert dialog for grid table
$this->view->formGridAddress = $this->getFormGrid("dialogAddress");
}
}

View file

@ -1,13 +1,30 @@
<form>
<field>
<id>address.enabled</id>
<label>enabled</label>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable this address</help>
<!-- Format the grid column for enabled button-->
<grid_view>
<width>6em</width>
<type>boolean</type>
<formatter>rowtoggle</formatter>
</grid_view>
</field>
<field>
<id>address.email</id>
<label>Email</label>
<type>text</type>
<help>Enter the email address</help>
</field>
<field>
<id>address.description</id>
<label>Description</label>
<type>text</type>
<help>Enter an optional description</help>
<!-- Hide this grid column per default -->
<grid_view>
<visible>false</visible>
</grid_view>
</field>
</form>

View file

@ -7,12 +7,13 @@
<addresses>
<address type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<email type="EmailField">
<Required>Y</Required>
</email>
<description type="DescriptionField"/>
</address>
</addresses>
</items>

View file

@ -1,5 +1,5 @@
{#
# Copyright (c) 2019 Deciso B.V.
# Copyright (c) 2019-2025 Deciso B.V.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -25,43 +25,29 @@
#}
<script>
$( document ).ready(function() {
$("#grid-addresses").UIBootgrid(
{ search:'/api/gridexample/settings/searchItem/',
get:'/api/gridexample/settings/getItem/',
set:'/api/gridexample/settings/setItem/',
add:'/api/gridexample/settings/addItem/',
del:'/api/gridexample/settings/delItem/',
toggle:'/api/gridexample/settings/toggleItem/'
$(document).ready(function() {
// set up the UIBootgrid API endpoints for the base_bootgrid_table
$("#{{formGridAddress['table_id']}}").UIBootgrid(
{ search:'/api/gridexample/settings/search_item/',
get:'/api/gridexample/settings/get_item/',
set:'/api/gridexample/settings/set_item/',
add:'/api/gridexample/settings/add_item/',
del:'/api/gridexample/settings/del_item/',
toggle:'/api/gridexample/settings/toggle_item/'
}
);
// use SimpleActionButton() to call /api/gridexample/service/reconfigure as example
$("#reconfigureAct").SimpleActionButton();
});
</script>
<table id="grid-addresses" class="table table-condensed table-hover table-striped" data-editDialog="DialogAddress">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="email" data-type="string">{{ lang._('Email') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
{{ partial("layout_partials/base_dialog",['fields':formDialogAddress,'id':'DialogAddress','label':lang._('Edit address')])}}
<div class="content-box">
<!-- auto creates a bootgrid from the data in formGridAddress -->
{{ partial('layout_partials/base_bootgrid_table', formGridAddress) }}
</div>
<!-- general purpose apply button, used to trigger reconfigureAct -->
{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/gridexample/service/reconfigure'}) }}
<!-- base_dialog used by the base_bootgrid_table -->
{{ partial("layout_partials/base_dialog",['fields':formDialogAddress,'id':formGridAddress['edit_dialog_id'],'label':lang._('Edit address')])}}

View file

@ -1,5 +1,6 @@
PLUGIN_NAME= helloworld
PLUGIN_VERSION= 1.4
PLUGIN_REVISION= 1
PLUGIN_COMMENT= A sample framework application
PLUGIN_MAINTAINER= ad@opnsense.org

View file

@ -8,14 +8,14 @@
<general>
<!-- fields -->
<Enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</Enabled>
<SMTPHost type="NetworkField">
<Required>Y</Required>
</SMTPHost>
<FromEmail type="EmailField">
<default>sample@example.com</default>
<Default>sample@example.com</Default>
<Required>Y</Required>
</FromEmail>
<ToEmail type="EmailField">

View file

@ -1,5 +1,5 @@
[test]
command:/usr/local/opnsense/scripts/OPNsense/HelloWorld/testConnection.py
command:/usr/local/opnsense/scripts/helloworld/testConnection.py
parameters:
type:script_output
message:hello world module test

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= bind
PLUGIN_VERSION= 1.33
PLUGIN_REVISION= 1
PLUGIN_VERSION= 1.34
PLUGIN_REVISION= 2
PLUGIN_COMMENT= BIND domain name service
PLUGIN_DEPENDS= bind920
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -9,6 +9,12 @@ WWW: https://www.isc.org
Plugin Changelog
================
1.34
* Add custom configuration include directory /usr/local/etc/namedb/named.conf.d (contributed by Nicholas Card)
* Add forward zones
* Fix primary zones grid and command column (contributed by benyamin-codez)
1.33
* Add option to allow the rndc-key for zone transfers (contributed by Naomi Rennie-Waldock)

View file

@ -0,0 +1,7 @@
# Custom BIND Configuration Directory
#
# Place your custom BIND directives in .conf files in this directory
# Files are included in alphabetical order
#
# Examples:
# server 192.168.1.100 { edns no; };

View file

@ -73,6 +73,18 @@ class DomainController extends ApiMutableModelControllerBase
);
}
public function searchForwardDomainAction()
{
return $this->searchBase(
'domains.domain',
[ 'enabled', 'type', 'domainname', 'forwardserver' ],
'domainname',
function ($record) {
return $record->type->getNodeData()['forward']['selected'] === 1;
}
);
}
public function getDomainAction($uuid = null)
{
return $this->getBase('domain', 'domains.domain', $uuid);
@ -88,6 +100,11 @@ class DomainController extends ApiMutableModelControllerBase
return $this->addBase('domain', 'domains.domain', ['type' => 'secondary']);
}
public function addForwardDomainAction($uuid = null)
{
return $this->addBase('domain', 'domains.domain', ['type' => 'forward']);
}
public function delDomainAction($uuid)
{
return $this->delBase('domains.domain', $uuid);

View file

@ -37,6 +37,7 @@ class GeneralController extends \OPNsense\Base\IndexController
$this->view->formDialogEditBindAcl = $this->getForm("dialogEditBindAcl");
$this->view->formDialogEditBindPrimaryDomain = $this->getForm("dialogEditBindPrimaryDomain");
$this->view->formDialogEditBindSecondaryDomain = $this->getForm("dialogEditBindSecondaryDomain");
$this->view->formDialogEditBindForwardDomain = $this->getForm("dialogEditBindForwardDomain");
$this->view->formDialogEditBindRecord = $this->getForm("dialogEditBindRecord");
$this->view->pick('OPNsense/Bind/general');
}

View file

@ -0,0 +1,22 @@
<form>
<field>
<id>domain.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable this zone.</help>
</field>
<field>
<id>domain.domainname</id>
<label>Zone Name</label>
<type>text</type>
<help>Set the name for this zone. Both forward and reverse zones may be specified, i.e. example.com or 0.168.192.in-addr.arpa.</help>
</field>
<field>
<id>domain.forwardserver</id>
<label>Primary IP</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>Set the IP address of server to forward requests to.</help>
</field>
</form>

View file

@ -1,7 +1,8 @@
<?php
/*
* Copyright (C) 2019 Smart-Soft
* Copyright (C) 2025 Nick Card
* Copyright (C) 2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,27 +27,31 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("widgets/include/dmidecode.inc");
namespace OPNsense\System\Status;
$hardwareData = parse_ini_string(configd_run("dmidecode system"), FALSE, INI_SCANNER_RAW);
$biosData = parse_ini_string(configd_run("dmidecode bios"), FALSE, INI_SCANNER_RAW);
use OPNsense\System\AbstractStatus;
use OPNsense\System\SystemStatusCode;
?>
<table class="table table-striped table-condensed">
<tbody>
<tr><th colspan="2"><?=gettext("Platform");?></th></tr>
<?php foreach($hardwareData as $key => $val) { ?>
<tr>
<td style="width: 30%;"><?=gettext($key);?></td>
<td><?=html_safe($val);?></td>
</tr>
<?php } ?>
<tr><th colspan="2"><?=gettext("BIOS");?></th></tr>
<?php foreach($biosData as $key => $val) { ?>
<tr>
<td style="width: 30%;"><?=gettext($key);?></td>
<td><?=html_safe($val);?></td>
</tr>
<?php } ?>
</tbody>
</table>
class BindOverrideStatus extends AbstractStatus
{
public function __construct()
{
$this->internalPriority = 2;
$this->internalPersistent = true;
$this->internalIsBanner = true;
$this->internalTitle = gettext('BIND config override');
$this->internalScope = [
'/ui/bind/general/index'
];
}
public function collectStatus()
{
if (count(glob('/usr/local/etc/namedb/named.conf.d/*')) > 1) {
$this->internalMessage = gettext(
'The configuration contains manual overwrites, these may interfere with the settings configured here.'
);
$this->internalStatus = SystemStatusCode::NOTICE;
}
}
}

View file

@ -11,7 +11,7 @@
</enabled>
<name type="TextField">
<Required>Y</Required>
<mask>/^(?!any$|localhost$|localnets$|none$)[0-9a-zA-Z_\-]{1,32}$/u</mask>
<Mask>/^(?!any$|localhost$|localnets$|none$)[0-9a-zA-Z_\-]{1,32}$/u</Mask>
<ValidationMessage>Should be a string between 1 and 32 characters. Allowed characters are 0-9, a-z, A-Z, _ and -. Built-in ACL names must not be used: any, localhost, localnets, none.</ValidationMessage>
<Constraints>
<check001>
@ -21,9 +21,8 @@
</Constraints>
</name>
<networks type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
<AsList>Y</AsList>
</networks>
</acl>
</acls>

View file

@ -1,7 +1,7 @@
<model>
<mount>//OPNsense/bind/domain</mount>
<description>BIND domain configuration</description>
<version>1.1.1</version>
<version>1.1.2</version>
<items>
<domains>
<domain type="ArrayField">
@ -15,12 +15,15 @@
<OptionValues>
<primary>primary</primary>
<secondary>secondary</secondary>
<forward>forward</forward>
</OptionValues>
</type>
<primaryip type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<AsList>Y</AsList>
</primaryip>
<forwardserver type="NetworkField">
<AsList>Y</AsList>
</forwardserver>
<transferkeyalgo type="OptionField">
<OptionValues>
<hmac-sha512>HMAC-SHA512</hmac-sha512>
@ -34,8 +37,7 @@
<transferkeyname type="TextField"/>
<transferkey type="TextField"/>
<allownotifysecondary type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<AsList>Y</AsList>
</allownotifysecondary>
<domainname type="TextField">
<Required>Y</Required>

View file

@ -17,15 +17,13 @@
</enablerpz>
<listenv4 type="NetworkField">
<Default>0.0.0.0</Default>
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
<AsList>Y</AsList>
</listenv4>
<listenv6 type="NetworkField">
<Default>::</Default>
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
<AsList>Y</AsList>
</listenv6>
<querysource type="NetworkField">
<AddressFamily>ipv4</AddressFamily>
@ -48,8 +46,7 @@
<Required>Y</Required>
</port>
<forwarders type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<AsList>Y</AsList>
</forwarders>
<filteraaaav4 type="BooleanField">
<Default>0</Default>
@ -60,8 +57,7 @@
<Required>Y</Required>
</filteraaaav6>
<filteraaaaacl type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<AsList>Y</AsList>
</filteraaaaacl>
<logsize type="IntegerField">
<Default>5</Default>
@ -152,9 +148,8 @@
</ratelimitcount>
<ratelimitexcept type="NetworkField">
<Default>0.0.0.0,::</Default>
<FieldSeparator>,</FieldSeparator>
<Required>Y</Required>
<asList>Y</asList>
<AsList>Y</AsList>
</ratelimitexcept>
<rndcalgo type="OptionField">
<Required>Y</Required>

View file

@ -33,6 +33,7 @@
<li><a data-toggle="tab" href="#acls">{{ lang._('ACLs') }}</a></li>
<li><a data-toggle="tab" href="#primary-domains">{{ lang._('Primary Zones') }}</a></li>
<li><a data-toggle="tab" href="#secondary-domains">{{ lang._('Secondary Zones') }}</a></li>
<li><a data-toggle="tab" href="#forward-domains">{{ lang._('Forward Zones') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
@ -99,7 +100,7 @@
<th data-column-id="expire" data-type="string" data-visible="true">{{ lang._('Expire') }}</th>
<th data-column-id="negative" data-type="string" data-visible="true">{{ lang._('Negative TTL') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
<th data-column-id="commands" data-width="9em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
@ -189,11 +190,48 @@
<br /><br />
</div>
</div>
<div id="forward-domains" class="tab-pane fade in">
<div class="col-md-12">
<h2>{{ lang._('Zones') }}</h2>
</div>
<div id="forward-domains-area" class="table-responsive">
<table id="grid-forward-domains" class="table table-condensed table-hover table-striped" data-editAlert="ChangeMessage" data-editDialog="dialogEditBindForwardDomain">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="domainname" data-type="string" data-visible="true">{{ lang._('Zone') }}</th>
<th data-column-id="forwardserver" data-type="string" data-visible="true">{{ lang._('Forwarder IPs') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<hr/>
<div class="col-md-12">
<div id="ChangeMessage" class="alert alert-info" style="display: none" role="alert">
{{ lang._('After changing settings, please remember to apply them with the button below') }}
</div>
<button class="btn btn-primary saveAct_domain" type="button"><b>{{ lang._('Save') }}</b> <i class="saveAct_domain_progress"></i></button>
<br /><br />
</div>
</div>
</div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindAcl,'id':'dialogEditBindAcl','label':lang._('Edit ACL')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindPrimaryDomain,'id':'dialogEditBindPrimaryDomain','label':lang._('Edit Primary Zone')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindSecondaryDomain,'id':'dialogEditBindSecondaryDomain','label':lang._('Edit Secondary Zone')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindForwardDomain,'id':'dialogEditBindForwardDomain','label':lang._('Edit Forward Zone')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindRecord,'id':'dialogEditBindRecord','label':lang._('Edit Record')])}}
<style>
@ -354,21 +392,21 @@ $(document).ready(function() {
updateServiceControlUI('bind');
$("#grid-acls").UIBootgrid({
'search': '/api/bind/acl/searchAcl',
'get': '/api/bind/acl/getAcl/',
'set': '/api/bind/acl/setAcl/',
'add': '/api/bind/acl/addAcl/',
'del': '/api/bind/acl/delAcl/',
'toggle': '/api/bind/acl/toggleAcl/'
'search': '/api/bind/acl/search_acl',
'get': '/api/bind/acl/get_acl/',
'set': '/api/bind/acl/set_acl/',
'add': '/api/bind/acl/add_acl/',
'del': '/api/bind/acl/del_acl/',
'toggle': '/api/bind/acl/toggle_acl/'
});
$("#grid-primary-domains").UIBootgrid({
'search': '/api/bind/domain/searchPrimaryDomain',
'get': '/api/bind/domain/getDomain/',
'set': '/api/bind/domain/setDomain/',
'add': '/api/bind/domain/addPrimaryDomain/',
'del': '/api/bind/domain/delDomain/',
'toggle': '/api/bind/domain/toggleDomain/',
'search': '/api/bind/domain/search_primary_domain',
'get': '/api/bind/domain/get_domain/',
'set': '/api/bind/domain/set_domain/',
'add': '/api/bind/domain/add_primary_domain/',
'del': '/api/bind/domain/del_domain/',
'toggle': '/api/bind/domain/toggle_domain/',
commands: {
'bind-checkzone': {
'title': "Check & preview",
@ -389,8 +427,8 @@ $(document).ready(function() {
}).on("loaded.rs.jquery.bootgrid", function(e) {
// Checkzone button
$("#grid-primary-domains").find(".command-bind-checkzone").off("click").on("click", function(ev) {
if (!$(this).closest("tr").hasClass("text-muted")) {
let zonename = $(this).closest('tr').find('td.zonename').text();
if (!$(this).closest(".tabulator-row").hasClass("text-muted")) {
let zonename = $(this).closest(".tabulator-row").find("[tabulator-field='domainname']").text();
zone_test(zonename);
} else {
BootstrapDialog.show({
@ -414,12 +452,12 @@ $(document).ready(function() {
});
$("#grid-secondary-domains").UIBootgrid({
'search': '/api/bind/domain/searchSecondaryDomain',
'get': '/api/bind/domain/getDomain/',
'set': '/api/bind/domain/setDomain/',
'add': '/api/bind/domain/addSecondaryDomain/',
'del': '/api/bind/domain/delDomain/',
'toggle': '/api/bind/domain/toggleDomain/',
'search': '/api/bind/domain/search_secondary_domain',
'get': '/api/bind/domain/get_domain/',
'set': '/api/bind/domain/set_domain/',
'add': '/api/bind/domain/add_secondary_domain/',
'del': '/api/bind/domain/del_domain/',
'toggle': '/api/bind/domain/toggle_domain/',
options: {
selection: false,
multiSelect: false,
@ -433,13 +471,33 @@ $(document).ready(function() {
}
});
$("#grid-forward-domains").UIBootgrid({
'search': '/api/bind/domain/search_forward_domain',
'get': '/api/bind/domain/get_domain/',
'set': '/api/bind/domain/set_domain/',
'add': '/api/bind/domain/add_forward_domain/',
'del': '/api/bind/domain/del_domain/',
'toggle': '/api/bind/domain/toggle_domain/',
options: {
selection: false,
multiSelect: false,
rowSelect: false,
rowCount: [7, 14, 20, 50, 100, -1]
}
}).on("loaded.rs.jquery.bootgrid", function(e) {
let ids = $("#grid-forward-domains").bootgrid("getCurrentRows");
if (ids.length > 0) {
$("#grid-forward-domains").bootgrid('select', [ids[0].uuid]);
}
});
$("#grid-primary-records").UIBootgrid({
'search': '/api/bind/record/searchRecord',
'get': '/api/bind/record/getRecord/',
'set': '/api/bind/record/setRecord/',
'add': '/api/bind/record/addRecord/',
'del': '/api/bind/record/delRecord/',
'toggle': '/api/bind/record/toggleRecord/',
'search': '/api/bind/record/search_record',
'get': '/api/bind/record/get_record/',
'set': '/api/bind/record/set_record/',
'add': '/api/bind/record/add_record/',
'del': '/api/bind/record/del_record/',
'toggle': '/api/bind/record/toggle_record/',
options: {
useRequestHandlerOnGet: true,
requestHandler: function(request) {

View file

@ -34,7 +34,6 @@
sorting:false,
rowSelect: false,
selection: false,
rowCount:[20,50,100,200,500,1000,-1],
},
search:'/api/diagnostics/log/named/query'
});
@ -45,7 +44,6 @@
sorting:false,
rowSelect: false,
selection: false,
rowCount:[20,50,100,200,500,1000,-1],
},
search:'/api/diagnostics/log/named/rpz'
});

View file

@ -112,6 +112,8 @@ controls {
};
{% endif %}
include "/usr/local/etc/namedb/named.conf.d/*.conf";
zone "." { type hint; file "/usr/local/etc/namedb/named.root"; };
zone "localhost" { type primary; file "/usr/local/etc/namedb/primary/localhost-forward.db"; };
@ -151,7 +153,9 @@ zone "rpzbing" { type primary; file "/usr/local/etc/namedb/primary/bing.db"; not
{% if domain.enabled == '1' %}
zone "{{ domain.domainname }}" {
type {{ domain.type }};
{% if domain.type == 'secondary' %}
{% if domain.type == 'forward' %}
forwarders { {{ domain.forwardserver.replace(',', '; ') }}; };
{% elif domain.type == 'secondary' %}
{% if domain.transferkey is defined %}
primaries { {{ domain.primaryip.replace(',', ' key "' ~ domain.transferkeyname ~ '"; ') }} key "{{ domain.transferkeyname }}"; };
{% else %}
@ -161,7 +165,7 @@ zone "{{ domain.domainname }}" {
allow-notify { {{ domain.allownotifysecondary.replace(',', '; ') }}; };
{% endif %}
file "/usr/local/etc/namedb/secondary/{{ domain.domainname }}.db";
{% else %}
{% elif domain.type == 'primary' %}
file "/usr/local/etc/namedb/primary/{{ domain.domainname }}.db";
{% endif %}
{% if domain.allowtransfer is defined or (domain.allowrndctransfer is defined and domain.allowrndctransfer == "1") %}
@ -185,7 +189,7 @@ zone "{{ domain.domainname }}" {
{% endfor %}
};
{% endif %}
{% if domain.allowrndcupdate is defined and domain.allowrndcupdate == "1" and domain.type != 'secondary' %}
{% if domain.allowrndcupdate is defined and domain.allowrndcupdate == "1" and domain.type == 'primary' %}
update-policy {
grant rndc-key zonesub ANY;
};

View file

@ -1,6 +1,5 @@
PLUGIN_NAME= ddclient
PLUGIN_VERSION= 1.26
PLUGIN_REVISION= 1
PLUGIN_VERSION= 1.28
PLUGIN_DEPENDS= ddclient py${PLUGIN_PYTHON}-boto3
PLUGIN_COMMENT= Dynamic DNS client
PLUGIN_MAINTAINER= ad@opnsense.org

View file

@ -6,6 +6,18 @@ WWW: https://github.com/ddclient/ddclient
Plugin Changelog
================
1.28
* Add native backend support for PowerDNS API (contributed by Oliver Traber)
1.27
* Add support for altering IPv6 addresses in native backend (contributed by SaarLAN-Pissbeutel)
* Add Akamai to checkip providers (contributed by Rajiv Aaron Manglani)
* Fix Netcup host/domain recognition (contributed by SaarLAN-Pissbeutel)
* Empty IP send to DNS provider and replace dyndns by dynu (contributed by Meliox)
* Removed defunct ip4only.me and ip6only.me
1.26
* Add ddclient TTL configuration in Gandi and GoDaddy (contributed by David PHAM-VAN)

View file

@ -31,7 +31,7 @@
When a URI is provided, the tag __MYIP__ will be replaced with the current detected address for this service
and __HOSTNAME__ will contain the (comma separated) list of hostnames provided.
</help>
<style>optional_setting service_custom</style>
<style>optional_setting service_custom service_powerdns</style>
</field>
<field>
<id>account.resourceId</id>

View file

@ -52,6 +52,16 @@ class DynDNS extends BaseModel
}
}
foreach ($validate_servers as $key => $node) {
if ((string)$node->service == 'powerdns') {
if (empty($srv) || filter_var($srv, FILTER_VALIDATE_URL) === false) {
$messages->appendMessage(
new Message(
gettext("A valid URI is required."),
$key . ".server"
)
);
}
}
if ((string)$node->service != 'custom') {
continue;
}

View file

@ -105,16 +105,16 @@
</server>
<username type="TextField">
<Required>N</Required>
<mask>/^([a-zA-Z0-9\-.@_:+\%])*$/u</mask>
<Mask>/^([a-zA-Z0-9\-.@_:+\%])*$/u</Mask>
<ValidationMessage>The username contains invalid characters.</ValidationMessage>
</username>
<password type="UpdateOnlyTextField">
<Required>N</Required>
<mask>/^[^\n]*$/</mask>
<Mask>/^[^\n]*$/</Mask>
</password>
<resourceId type="TextField">
<Required>N</Required>
<mask>/^[^\n]*$/</mask>
<Mask>/^[^\n]*$/</Mask>
<ValidationMessage>resourceId contains invalid characters.</ValidationMessage>
</resourceId>
<hostnames type="HostnameField">
@ -139,15 +139,17 @@
<Default>web_dyndns</Default>
<ValidationMessage>An IP service type is required.</ValidationMessage>
<OptionValues>
<web_akamai>akamai</web_akamai>
<web_akamai_ipv4 value="akamai-ipv4">akamai-ipv4</web_akamai_ipv4>
<web_akamai_ipv6 value="akamai-ipv6">akamai-ipv6</web_akamai_ipv6>
<web_cloudflare>cloudflare</web_cloudflare>
<web_cloudflare_ipv4 value="cloudflare-ipv4">cloudflare-ipv4</web_cloudflare_ipv4>
<web_cloudflare_ipv6 value="cloudflare-ipv6">cloudflare-ipv6</web_cloudflare_ipv6>
<web_dyndns>dyndns</web_dyndns>
<web_dynu_ipv4 value="dynu-ipv4">dynu-ipv4</web_dynu_ipv4>
<web_dynu_ipv6 value="dynu-ipv6">dynu-ipv6</web_dynu_ipv6>
<web_freedns>freedns</web_freedns>
<web_he>he</web_he>
<web_icanhazip>icanhazip</web_icanhazip>
<web_ip4only_me value="web_ip4only.me">ip4only.me</web_ip4only_me>
<web_ip6only_me value="web_ip6only.me">ip6only.me</web_ip6only_me>
<web_ipify_ipv4 value="web_ipify-ipv4">ipify-ipv4</web_ipify_ipv4>
<web_ipify_ipv6 value="web_ipify-ipv6">ipify-ipv6</web_ipify_ipv6>
<web_loopia>loopia</web_loopia>
@ -167,7 +169,7 @@
</checkip>
<dynipv6host type="TextField">
<Required>N</Required>
<mask>/^::(([0-9a-fA-F]{1,4}:){0,3}[0-9a-fA-F]{1,4})?$/u</mask>
<Mask>/^::(([0-9a-fA-F]{1,4}:){0,3}[0-9a-fA-F]{1,4})?$/u</Mask>
<ValidationMessage>Entry is not a valid partial ipv6 address definition (e.g. ::1000).</ValidationMessage>
</dynipv6host>
<checkip_timeout type="IntegerField">
@ -199,9 +201,11 @@
</interface>
<description type="TextField">
<Required>N</Required>
<mask>/^(.){1,255}$/u</mask>
<Mask>/^(.){1,255}$/u</Mask>
<ValidationMessage>Description should be a string between 1 and 255 characters</ValidationMessage>
</description>
<current_ip type="TextField" volatile="true"/>
<current_mtime type="TextField" volatile="true"/>
</account>
</accounts>
</items>

View file

@ -40,29 +40,22 @@ class AccountField extends ArrayField
private function addStatsFields($node)
{
// generate new unattached fields, which are only usable to read data from (not synched to config.xml)
$current_ip = new TextField();
$current_ip->setInternalIsVirtual();
$current_mtime = new TextField();
$current_mtime->setInternalIsVirtual();
if (isset(self::$current_stats[$node->getAttribute('uuid')])) {
$stats = self::$current_stats[$node->getAttribute('uuid')];
if (!empty($stats)) {
$current_ip->setValue($stats['ip']);
$current_mtime->setValue(date('c', (int)$stats['mtime']));
$node->current_ip->setValue($stats['ip']);
$node->current_mtime->setValue(date('c', (int)$stats['mtime']));
}
} elseif (!empty((string)$node->hostnames)) {
foreach (explode(",", (string)$node->hostnames) as $hostname) {
if (!empty(self::$current_stats[$hostname]) && !empty(self::$current_stats[$hostname]['ip'])) {
$stats = self::$current_stats[$hostname];
$current_ip->setValue($stats['ip']);
$current_mtime->setValue(date('c', $stats['mtime']));
$node->current_ip->setValue($stats['ip']);
$node->current_mtime->setValue(date('c', $stats['mtime']));
break;
}
}
}
$node->addChildNode('current_ip', $current_ip);
$node->addChildNode('current_mtime', $current_mtime);
}
protected function actionPostLoadingEvent()

View file

@ -122,7 +122,7 @@ class BaseAccount:
dynipv6host = self.settings['dynipv6host'] if self.settings.get('dynipv6host' ,'').strip() != '' else None
)
if self._current_address == None:
if not self._current_address:
syslog.syslog(
syslog.LOG_WARNING,
"Account %s no global IP address detected, check config if warning persists" % (self.description)

View file

@ -0,0 +1,209 @@
"""
Copyright (c) 2023 Ad Schellevis <ad@opnsense.org>
Copyright (c) 2024 Olly Baker <ilumos@gmail.com>
Copyright (c) 2025 Oliver Traber <hi@bluemedia.dev>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
"""
import syslog
import requests
from . import BaseAccount
class PowerDNS(BaseAccount):
def __init__(self, account: dict):
super().__init__(account)
# min TTL set to 300
self.settings['ttl'] = max(int(self.settings["ttl"]) if self.settings.get("ttl", "").isdigit() else 0, 300)
@staticmethod
def known_services():
return {"powerdns": "PowerDNS API"}
@staticmethod
def match(account):
return account.get("service") in ['powerdns']
def _send_request(self, method, url, params=None, json=None):
headers = {
"User-Agent": "OPNsense-dyndns",
"X-API-Key": self.settings.get("password"),
}
base_url = "%s/api/v1/servers/%s" % (
self.settings.get('server'),
self.settings.get("server_id", "localhost")
)
url = base_url + url
return requests.request(method=method, url=url, headers=headers, params=params, json=json)
def _find_zone_id(self, hostname):
# Get the zone that a record belongs to
if self.is_verbose:
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s trying to get zone ID for hostname %s"
% (self.description, hostname),
)
zone = hostname
while (True):
if self.is_verbose:
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s checking if zone %s exists"
% (self.description, zone),
)
response = self._send_request(method="GET", url="/zones", params={"zone": zone})
if response.status_code == 200:
try:
payload = response.json()
# Check if a zone was found
if len(payload) == 0:
# Move one up in hierarchy
zone = '.'.join(zone.split('.')[1:])
# Fail if root is reached
if zone == "":
syslog.syslog(
syslog.LOG_ERR,
"Account %s error getting zone ID for hostname %s - No matching zone found on server"
% (self.description, hostname),
)
return None
else:
continue
else:
if self.is_verbose:
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s found zone %s for hostname %s"
% (self.description, zone, hostname),
)
return payload[0].get("id")
except requests.exceptions.JSONDecodeError:
syslog.syslog(
syslog.LOG_ERR,
"Account %s error getting zone ID for hostname %s - Failed to decode response as JSON. Response: %s"
% (self.description, hostname, response.text),
)
return None
else:
syslog.syslog(
syslog.LOG_ERR,
"Account %s error getting zone ID for hostname %s HTTP %s. Response: %s"
% (
self.description,
hostname,
response.status_code,
response.text,
),
)
return None
def _replace_rrset(self, hostname, zone_id, record_type, content):
# Replace or create rrset for record
payload = {
"rrsets": [
{
"name": hostname,
"type": record_type,
"ttl": int(self.settings.get("ttl")),
"changetype": "REPLACE",
"records": [
{"content": content}
]
}
]
}
response = self._send_request(method="PATCH", url=("/zones/" + zone_id), json=payload)
if response.status_code == 204:
# Success
return True
else:
# Failure
syslog.syslog(
syslog.LOG_ERR,
"Account %s error updating hostname %s in zone %s - HTTP %s Response: %s"
% (
self.description,
hostname,
zone_id,
response.status_code,
response.text,
),
)
return False
def execute(self):
if super().execute():
record_type = "AAAA" if str(self.current_address).find(":") > 1 else "A"
if self.is_verbose:
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s current IP is %s (%s)"
% (self.description, self.current_address, record_type),
)
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s updating hostnames %s"
% (self.description, self.settings.get("hostnames", "")),
)
# Update each hostname
for hostname in self.settings.get("hostnames", "").split(","):
# Make hostname absolute
if not hostname.endswith("."):
hostname = hostname + "."
# Get id of zone the hostname belongs to
zone_id = self._find_zone_id(hostname)
# If zone can't be found, skip
if zone_id == None:
continue
# Update record set
if self._replace_rrset(hostname, zone_id, record_type, content=self.current_address) and self.is_verbose:
syslog.syslog(
syslog.LOG_NOTICE,
"Account %s successfully updated hostname %s (%s) to IP %s"
% (
self.description,
hostname,
record_type,
self.current_address,
),
)
self.update_state(address=self.current_address)
return True
return False

View file

@ -29,15 +29,17 @@ import ipaddress
from urllib.parse import urlparse
checkip_service_list = {
'akamai': '%s://whatismyip.akamai.com',
'akamai-ipv4': '%s://ipv4.whatismyip.akamai.com',
'akamai-ipv6': '%s://ipv6.whatismyip.akamai.com',
'cloudflare': '%s://one.one.one.one/cdn-cgi/trace',
'cloudflare-ipv4': '%s://1.1.1.1/cdn-cgi/trace',
'cloudflare-ipv6': '%s://[2606:4700:4700::1111]/cdn-cgi/trace',
'dyndns': '%s://checkip.dyndns.org/',
'dynu-ipv4': '%s://ipcheck.dynu.com/',
'dynu-ipv6': '%s://ipcheckv6.dynu.com/',
'freedns': '%s://freedns.afraid.org/dynamic/check.php',
'he': '%s://checkip.dns.he.net/',
'icanhazip': '%s://icanhazip.com/',
'ip4only.me': '%s://ip4only.me/api/',
'ip6only.me': '%s://ip6only.me/api/',
'ipify-ipv4': '%s://api.ipify.org/',
'ipify-ipv6': '%s://api6.ipify.org/',
'loopia': '%s://dns.loopia.se/checkip/checkip.php',

View file

@ -6,7 +6,8 @@ type:script
message:starting ddclient
[stop]
command:pkill -F /var/run/ddclient.pid 2> /dev/null; /usr/local/etc/rc.d/ddclient_opn onestop 2> /dev/null; exit 0
command:pkill -F /var/run/ddclient.pid 2> /dev/null; /usr/local/etc/rc.d/ddclient_opn onestop 2> /dev/null
errors:no
type:script
message:stopping ddclient

View file

@ -1,6 +1,5 @@
PLUGIN_NAME= dnscrypt-proxy
PLUGIN_VERSION= 1.15
PLUGIN_REVISION= 2
PLUGIN_VERSION= 1.16
PLUGIN_COMMENT= Flexible DNS proxy supporting DNSCrypt and DoH
PLUGIN_DEPENDS= dnscrypt-proxy2
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -1,10 +1,13 @@
A flexible DNS proxy, with support for modern encrypted DNS protocols
such as DNSCrypt v2 and DNS-over-HTTPS.
Plugin Changelog
================
1.16
* Fix ODoH servers not working (contributed by Pascal Herget)
1.15
* Update plugin for dnscrypt-proxy 2.1 (contributed by Adrian Fedoreanu and Michael Muenz)

View file

@ -49,6 +49,12 @@
<type>checkbox</type>
<help>Let DNSCrypt-Proxy use servers with DNS-over-HTTPS protocol enabled.</help>
</field>
<field>
<id>general.odoh_servers</id>
<label>Use Oblivious-DNS-over-HTTPS Servers</label>
<type>checkbox</type>
<help>Let DNSCrypt-Proxy use servers with Oblivious-DNS-over-HTTPS protocol enabled. Note: If checked you must provide ODoH target and relay servers manually!</help>
</field>
<field>
<id>general.require_dnssec</id>
<label>Require DNSSEC</label>

View file

@ -6,7 +6,7 @@
<cloaks>
<cloak type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<name type="TextField">

View file

@ -4,11 +4,10 @@
<version>1.0.0</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<type type="OptionField">
<Required>N</Required>
<Multiple>Y</Multiple>
<OptionValues>
<aa>AdAway List</aa>

View file

@ -6,7 +6,7 @@
<forwards>
<forward type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<domain type="HostnameField">

View file

@ -1,153 +1,149 @@
<model>
<mount>//OPNsense/dnscryptproxy/general</mount>
<description>dnscrypt-proxy configuration</description>
<version>0.1.2</version>
<version>0.1.3</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<listen_addresses type="CSVListField">
<default>0.0.0.0:5353</default>
<Default>0.0.0.0:5353</Default>
<Required>Y</Required>
</listen_addresses>
<allowprivileged type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</allowprivileged>
<max_clients type="IntegerField">
<default>250</default>
<Default>250</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>10000</MaximumValue>
<ValidationMessage>Choose a number between 1 and 10000.</ValidationMessage>
</max_clients>
<ipv4_servers type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</ipv4_servers>
<ipv6_servers type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</ipv6_servers>
<dnscrypt_servers type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</dnscrypt_servers>
<doh_servers type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</doh_servers>
<odoh_servers type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</odoh_servers>
<require_dnssec type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</require_dnssec>
<require_nolog type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</require_nolog>
<require_nofilter type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</require_nofilter>
<force_tcp type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</force_tcp>
<proxy type="TextField">
<Required>N</Required>
</proxy>
<proxy type="TextField"/>
<timeout type="IntegerField">
<default>2500</default>
<Default>2500</Default>
<Required>Y</Required>
<MinimumValue>100</MinimumValue>
<MaximumValue>10000</MaximumValue>
<ValidationMessage>Choose a number between 100 and 10000.</ValidationMessage>
</timeout>
<keepalive type="IntegerField">
<default>30</default>
<Default>30</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>600</MaximumValue>
<ValidationMessage>Choose a number between 1 and 600.</ValidationMessage>
</keepalive>
<cert_refresh_delay type="IntegerField">
<default>240</default>
<Default>240</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>3600</MaximumValue>
<ValidationMessage>Choose a number between 1 and 3600.</ValidationMessage>
</cert_refresh_delay>
<dnscrypt_ephemeral_keys type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</dnscrypt_ephemeral_keys>
<tls_disable_session_tickets type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</tls_disable_session_tickets>
<fallback_resolver type="TextField">
<default>9.9.9.9:53</default>
<Default>9.9.9.9:53</Default>
<Required>Y</Required>
</fallback_resolver>
<block_ipv6 type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</block_ipv6>
<cache type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</cache>
<cache_size type="IntegerField">
<default>512</default>
<Default>512</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>20480</MaximumValue>
<ValidationMessage>Choose a number between 1 and 20480.</ValidationMessage>
</cache_size>
<cache_min_ttl type="IntegerField">
<default>600</default>
<Default>600</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>3600</MaximumValue>
<ValidationMessage>Choose a number between 1 and 3600.</ValidationMessage>
</cache_min_ttl>
<cache_max_ttl type="IntegerField">
<default>86400</default>
<Default>86400</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Choose a number between 1 and 86400.</ValidationMessage>
</cache_max_ttl>
<cache_neg_min_ttl type="IntegerField">
<default>60</default>
<Default>60</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>3600</MaximumValue>
<ValidationMessage>Choose a number between 1 and 3600.</ValidationMessage>
</cache_neg_min_ttl>
<cache_neg_max_ttl type="IntegerField">
<default>600</default>
<Default>600</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Choose a number between 1 and 86400.</ValidationMessage>
</cache_neg_max_ttl>
<serverlist type="CSVListField">
<Required>N</Required>
</serverlist>
<serverlist type="CSVListField"/>
<query_logs type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</query_logs>
<disabled_serverlist type="CSVListField">
<mask>/^[A-Za-z0-9\._\-]{1,70}(,[A-Za-z0-9\._\-]{1,70})*$/</mask>
<default></default>
<Required>N</Required>
<Mask>/^[A-Za-z0-9\._\-]{1,70}(,[A-Za-z0-9\._\-]{1,70})*$/</Mask>
<ValidationMessage>Please use valid server names.</ValidationMessage>
</disabled_serverlist>
<relaylist type="CSVListField">
<Required>N</Required>
</relaylist>
<relaylist type="CSVListField"/>
</items>
</model>

View file

@ -6,7 +6,7 @@
<servers>
<server type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<name type="TextField">

View file

@ -6,15 +6,13 @@
<whitelists>
<whitelist type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<Required>Y</Required>
</name>
<description type="TextField">
<Required>N</Required>
</description>
<description type="TextField"/>
</whitelist>
</whitelists>
</items>

View file

@ -186,42 +186,42 @@ $( document ).ready(function() {
});
$("#grid-forwards").UIBootgrid(
{ 'search':'/api/dnscryptproxy/forward/searchForward',
'get':'/api/dnscryptproxy/forward/getForward/',
'set':'/api/dnscryptproxy/forward/setForward/',
'add':'/api/dnscryptproxy/forward/addForward/',
'del':'/api/dnscryptproxy/forward/delForward/',
'toggle':'/api/dnscryptproxy/forward/toggleForward/'
{ 'search':'/api/dnscryptproxy/forward/search_forward',
'get':'/api/dnscryptproxy/forward/get_forward/',
'set':'/api/dnscryptproxy/forward/set_forward/',
'add':'/api/dnscryptproxy/forward/add_forward/',
'del':'/api/dnscryptproxy/forward/del_forward/',
'toggle':'/api/dnscryptproxy/forward/toggle_forward/'
}
);
$("#grid-cloaks").UIBootgrid(
{ 'search':'/api/dnscryptproxy/cloak/searchCloak',
'get':'/api/dnscryptproxy/cloak/getCloak/',
'set':'/api/dnscryptproxy/cloak/setCloak/',
'add':'/api/dnscryptproxy/cloak/addCloak/',
'del':'/api/dnscryptproxy/cloak/delCloak/',
'toggle':'/api/dnscryptproxy/cloak/toggleCloak/'
{ 'search':'/api/dnscryptproxy/cloak/search_cloak',
'get':'/api/dnscryptproxy/cloak/get_cloak/',
'set':'/api/dnscryptproxy/cloak/set_cloak/',
'add':'/api/dnscryptproxy/cloak/add_cloak/',
'del':'/api/dnscryptproxy/cloak/del_cloak/',
'toggle':'/api/dnscryptproxy/cloak/toggle_cloak/'
}
);
$("#grid-whitelists").UIBootgrid(
{ 'search':'/api/dnscryptproxy/whitelist/searchWhitelist',
'get':'/api/dnscryptproxy/whitelist/getWhitelist/',
'set':'/api/dnscryptproxy/whitelist/setWhitelist/',
'add':'/api/dnscryptproxy/whitelist/addWhitelist/',
'del':'/api/dnscryptproxy/whitelist/delWhitelist/',
'toggle':'/api/dnscryptproxy/whitelist/toggleWhitelist/'
{ 'search':'/api/dnscryptproxy/whitelist/search_whitelist',
'get':'/api/dnscryptproxy/whitelist/get_whitelist/',
'set':'/api/dnscryptproxy/whitelist/set_whitelist/',
'add':'/api/dnscryptproxy/whitelist/add_whitelist/',
'del':'/api/dnscryptproxy/whitelist/del_whitelist/',
'toggle':'/api/dnscryptproxy/whitelist/toggle_whitelist/'
}
);
$("#grid-servers").UIBootgrid(
{ 'search':'/api/dnscryptproxy/server/searchServer',
'get':'/api/dnscryptproxy/server/getServer/',
'set':'/api/dnscryptproxy/server/setServer/',
'add':'/api/dnscryptproxy/server/addServer/',
'del':'/api/dnscryptproxy/server/delServer/',
'toggle':'/api/dnscryptproxy/server/toggleServer/'
{ 'search':'/api/dnscryptproxy/server/search_server',
'get':'/api/dnscryptproxy/server/get_server/',
'set':'/api/dnscryptproxy/server/set_server/',
'add':'/api/dnscryptproxy/server/add_server/',
'del':'/api/dnscryptproxy/server/del_server/',
'toggle':'/api/dnscryptproxy/server/toggle_server/'
}
);

View file

@ -40,6 +40,12 @@ doh_servers = true
doh_servers = false
{% endif %}
{% if helpers.exists('OPNsense.dnscryptproxy.general.odoh_servers') and OPNsense.dnscryptproxy.general.odoh_servers == '1' %}
odoh_servers = true
{% else %}
odoh_servers = false
{% endif %}
{% if helpers.exists('OPNsense.dnscryptproxy.general.require_dnssec') and OPNsense.dnscryptproxy.general.require_dnssec == '1' %}
require_dnssec = true
{% else %}
@ -146,7 +152,7 @@ cache = false
[sources]
[sources.'public-resolvers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md', 'https://ipv6.download.dnscrypt.info/resolvers-list/v3/public-resolvers.md']
cache_file = 'public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
@ -155,12 +161,30 @@ cache = false
## Anonymized DNS relays
[sources.'relays']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md', 'https://ipv6.download.dnscrypt.info/resolvers-list/v3/relays.md', 'https://download.dnscrypt.net/resolvers-list/v3/relays.md']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md', 'https://ipv6.download.dnscrypt.info/resolvers-list/v3/relays.md']
cache_file = 'relays.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
## Oblivious DoH servers
[sources.'odoh-servers']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/odoh-servers.md', 'https://download.dnscrypt.info/resolvers-list/v3/odoh-servers.md', 'https://ipv6.download.dnscrypt.info/resolvers-list/v3/odoh-servers.md']
cache_file = 'odoh-servers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
## Oblivious DoH relays
[sources.'odoh-relays']
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/odoh-relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/odoh-relays.md', 'https://ipv6.download.dnscrypt.info/resolvers-list/v3/odoh-relays.md']
cache_file = 'odoh-relays.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
prefix = ''
[anonymized_dns]
{% if helpers.exists('OPNsense.dnscryptproxy.general.relaylist') and OPNsense.dnscryptproxy.general.relaylist != '' %}

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= rfc2136
PLUGIN_VERSION= 1.9
PLUGIN_REVISION= 3
PLUGIN_REVISION= 4
PLUGIN_COMMENT= RFC-2136 Support
PLUGIN_MAINTAINER= franco@opnsense.org
PLUGIN_DEPENDS= bind-tools

View file

@ -198,16 +198,15 @@ function rfc2136_configure_do($verbose = false, $int = null, $updatehost = '', $
$upinst .= "\n"; /* mind that trailing newline! */
if ($need_update) {
@file_put_contents("/var/etc/nsupdatecmds{$i}", $upinst);
unset($upinst);
/* invoke nsupdate */
$cmd = "/usr/local/bin/nsupdate -k {$keyfile}";
$cmds = "/var/etc/nsupdatecmds{$i}";
file_safe($cmds, $upinst);
$args = [];
$args[] = exec_safe('-k %s', $keyfile);
if (isset($dnsupdate['usetcp'])) {
$cmd .= " -v";
$args[] = '-v';
}
$cmd .= " /var/etc/nsupdatecmds{$i}";
mwexec_bg($cmd);
unset($cmd);
$args[] = exec_safe('%s', $cmds);
mwexecf_bg('/usr/local/bin/nsupdate ' . join(' ', $args));
}
}
@ -222,7 +221,7 @@ function get_rfc2136_ip_address($int, $ipver = 4)
return 'down';
}
if ($ipver != 6 && is_private_ip($ip_address)) {
if ($ipver != 6 && is_private_ipv4($ip_address)) {
$ip_ch = curl_init('http://checkip.dyndns.org');
curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);

View file

@ -1,4 +0,0 @@
<?php
$rfc2136_title = gettext('RFC 2136');
$rfc2136_title_link = 'services_rfc2136.php';

View file

@ -1,156 +0,0 @@
<?php
/*
* Copyright (C) 2017 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2014-2016 Deciso B.V.
* Copyright (C) 2008 Ermal Luçi
* Copyright (C) 2013 Stanley P. Miller \ stan-qaz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("guiconfig.inc");
require_once("widgets/include/rfc2136.inc");
require_once("interfaces.inc");
require_once("plugins.inc.d/rfc2136.inc");
$a_rfc2136 = &config_read_array('dnsupdates', 'dnsupdate');
if (!empty($_REQUEST['getrfc2136status'])) {
$first_entry = true;
foreach ($a_rfc2136 as $rfc2136) {
if ($first_entry) {
$first_entry = false;
} else {
// Put a vertical bar delimiter between the echoed HTML for each entry processed.
echo '|';
}
$filename = rfc2136_cache_file($rfc2136, 4);
$fdata = '';
if (!empty($rfc2136['enable']) && (empty($rfc2136['recordtype']) || $rfc2136['recordtype'] == 'A') && file_exists($filename)) {
$ipaddr = get_rfc2136_ip_address($rfc2136['interface'], 4);
$fdata = @file_get_contents($filename);
}
$filename_v6 = rfc2136_cache_file($rfc2136, 6);
$fdata6 = '';
if (!empty($rfc2136['enable']) && (empty($rfc2136['recordtype']) || $rfc2136['recordtype'] == 'AAAA') && file_exists($filename_v6)) {
$ipv6addr = get_rfc2136_ip_address($rfc2136['interface'], 6);
$fdata6 = @file_get_contents($filename_v6);
}
if (!empty($fdata)) {
$cached_ip_s = explode('|', $fdata);
$cached_ip = $cached_ip_s[0];
echo sprintf(
'IPv4: <font color="%s">%s</font>',
$ipaddr != $cached_ip ? 'red' : 'green',
htmlspecialchars($cached_ip)
);
} else {
echo 'IPv4: ' . gettext('N/A');
}
echo '<br />';
if (!empty($fdata6)) {
$cached_ipv6_s = explode('|', $fdata6);
$cached_ipv6 = $cached_ipv6_s[0];
echo sprintf(
'IPv6: <font color="%s">%s</font>',
$ipv6addr != $cached_ipv6 ? 'red' : 'green',
htmlspecialchars($cached_ipv6)
);
} else {
echo 'IPv6: ' . gettext('N/A');
}
}
exit;
}
?>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th style="word-break:break-word;"><?=gettext("Interface");?></th>
<th style="word-break:break-word;"><?=gettext("Server");?></th>
<th style="word-break:break-word;"><?=gettext("Hostname");?></th>
<th style="word-break:break-word;"><?=gettext("Cached IP");?></th>
</tr>
</thead>
<tbody>
<?php
$iflist = get_configured_interface_with_descr();
foreach ($a_rfc2136 as $i => $rfc2136) :?>
<tr ondblclick="document.location='services_rfc2136_edit.php?id=<?=$i;?>'">
<td style="word-break:break-word;" <?= isset($rfc2136['enable']) ? '' : 'class="text-muted"' ?>>
<?php
foreach ($iflist as $if => $ifdesc) {
if ($rfc2136['interface'] == $if) {
echo "{$ifdesc}";
break;
}
}?>
</td>
<td style="word-break:break-word;" <?= isset($rfc2136['enable']) ? '' : 'class="text-muted"' ?>>
<?= htmlspecialchars($rfc2136['server']) ?>
</td>
<td style="word-break:break-word;" <?= isset($rfc2136['enable']) ? '' : 'class="text-muted"' ?>>
<?= htmlspecialchars($rfc2136['host']) ?>
</td>
<td style="word-break:break-word;" <?= isset($rfc2136['enable']) ? '' : 'class="text-muted"' ?>>
<div id='rfc2136status<?=$i;?>'>
<?= gettext('Checking...') ?>
</div>
</td>
</tr>
<?php
endforeach;?>
</tbody>
</table>
<script>
function rfc2136_getstatus()
{
scroll(0,0);
var url = "/widgets/widgets/rfc2136.widget.php";
var pars = 'getrfc2136status=yes';
jQuery.ajax(url, {type: 'get', data: pars, complete: rfc2136callback});
// Refresh the status every 5 minutes
setTimeout('rfc2136_getstatus()', 5*60*1000);
}
function rfc2136callback(transport)
{
// The server returns a string of statuses separated by vertical bars
var responseStrings = transport.responseText.split("|");
for (var count=0; count<responseStrings.length; count++) {
var divlabel = '#rfc2136status' + count;
jQuery(divlabel).prop('innerHTML',responseStrings[count]);
}
}
$(window).on("load", function() {
// Do the first status check 2 seconds after the dashboard opens
setTimeout('rfc2136_getstatus()', 2000);
});
</script>

View file

@ -5,16 +5,11 @@
<items>
<general>
<Enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</Enabled>
<LogDebug type="BooleanField">
<default>0</default>
<Required>N</Required>
</LogDebug>
<LogDebug type="BooleanField"/>
<DisabledRPCs type="OptionField">
<Required>N</Required>
<default></default>
<Sorted>Y</Sorted>
<Multiple>Y</Multiple>
<OptionValues>

View file

@ -4,11 +4,11 @@
<version>0.0.1</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<listen type="HostnameField">
<default>127.0.0.1</default>
<Default>127.0.0.1</Default>
<Required>Y</Required>
</listen>
</items>

View file

@ -1,6 +1,5 @@
PLUGIN_NAME= postfix
PLUGIN_VERSION= 1.23
PLUGIN_REVISION= 4
PLUGIN_VERSION= 1.24
PLUGIN_COMMENT= SMTP mail relay
PLUGIN_DEPENDS= postfix
PLUGIN_MAINTAINER= m.muenz@gmail.com

View file

@ -6,6 +6,10 @@ is completely different.
Plugin Changelog
================
1.24
* Disable broken, insecure, legacy NTLM authentication (contributed by Alfred Egger)
1.23
* Add support for Opportunistic DANE as SMTP client security level

View file

@ -6,7 +6,7 @@
<addresses>
<address type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<from type="TextField">

View file

@ -4,11 +4,11 @@
<version>1.0.2</version>
<items>
<enable_rspamd type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_rspamd>
<default_action type="OptionField">
<default>accept</default>
<Default>accept</Default>
<Required>Y</Required>
<OptionValues>
<accept>accept</accept>

View file

@ -6,17 +6,17 @@
<domains>
<domain type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<domainname type="TextField">
<default></default>
<Default></Default>
<Required>Y</Required>
</domainname>
<destination type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
<mask>/^([0-9a-zA-Z.:\-\[\]]){1,64}$/u</mask>
<Mask>/^([0-9a-zA-Z.:\-\[\]]){1,64}$/u</Mask>
<ValidationMessage>Only 64 of the following characters are allowed: 0-9a-zA-Z.:-[]</ValidationMessage>
</destination>
</domain>

View file

@ -4,31 +4,31 @@
<version>1.2.7</version>
<items>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<myhostname type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</myhostname>
<mydomain type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</mydomain>
<myorigin type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</myorigin>
<inet_interfaces type="TextField">
<default>all</default>
<Default>all</Default>
<Required>Y</Required>
</inet_interfaces>
<inet_port type="PortField">
<default>25</default>
<Default>25</Default>
<Required>Y</Required>
</inet_port>
<ip_version type="OptionField">
<default>all</default>
<Default>all</Default>
<Required>Y</Required>
<OptionValues>
<all>All</all>
@ -45,24 +45,24 @@
<AddressFamily>ipv6</AddressFamily>
</bind_address6>
<mynetworks type="CSVListField">
<default>127.0.0.0/8,[::ffff:127.0.0.0]/104,[::1]/128</default>
<Default>127.0.0.0/8,[::ffff:127.0.0.0]/104,[::1]/128</Default>
<Required>Y</Required>
</mynetworks>
<banner type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</banner>
<message_size_limit type="IntegerField">
<default>51200000</default>
<Default>51200000</Default>
<Required>Y</Required>
</message_size_limit>
<masquerade_domains type="CSVListField">
<Required>N</Required>
<mask>/^([0-9a-z\.\-\_]{1,128})(,[0-9a-z\.\-\_]{1,128})*$/ui</mask>
<Mask>/^([0-9a-z\.\-\_]{1,128})(,[0-9a-z\.\-\_]{1,128})*$/ui</Mask>
<ValidationMessage>Only up to 128 of the following characters are allowed: 0-9a-zA-Z.-_</ValidationMessage>
</masquerade_domains>
<tls_server_compatibility type="OptionField">
<default>intermediate</default>
<Default>intermediate</Default>
<Required>Y</Required>
<OptionValues>
<modern>Modern</modern>
@ -71,7 +71,7 @@
</OptionValues>
</tls_server_compatibility>
<tls_client_compatibility type="OptionField">
<default>intermediate</default>
<Default>intermediate</Default>
<Required>Y</Required>
<OptionValues>
<modern>Modern</modern>
@ -80,7 +80,7 @@
</OptionValues>
</tls_client_compatibility>
<tlswrappermode type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</tlswrappermode>
<certificate type="CertificateField">
@ -92,7 +92,7 @@
<Required>N</Required>
</ca>
<smtpclient_security type="OptionField">
<default>may</default>
<Default>may</Default>
<Required>Y</Required>
<OptionValues>
<none>none</none>
@ -103,91 +103,91 @@
</smtpclient_security>
<relayhost type="TextField">
<Required>N</Required>
<mask>/^([0-9a-zA-Z.:\-\[\]]){1,64}$/u</mask>
<Mask>/^([0-9a-zA-Z.:\-\[\]]){1,64}$/u</Mask>
<ValidationMessage>Only 64 of the following characters are allowed: 0-9a-zA-Z.:-[]</ValidationMessage>
</relayhost>
<smtpauth_enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</smtpauth_enabled>
<smtpauth_user type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</smtpauth_user>
<smtpauth_password type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</smtpauth_password>
<enforce_recipient_check type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enforce_recipient_check>
<extensive_helo_restrictions type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</extensive_helo_restrictions>
<extensive_sender_restrictions type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</extensive_sender_restrictions>
<reject_unknown_client_hostname type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</reject_unknown_client_hostname>
<reject_non_fqdn_helo_hostname type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</reject_non_fqdn_helo_hostname>
<reject_invalid_helo_hostname type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</reject_invalid_helo_hostname>
<reject_unknown_helo_hostname type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</reject_unknown_helo_hostname>
<reject_unauth_pipelining type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_unauth_pipelining>
<reject_unknown_sender_domain type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_unknown_sender_domain>
<reject_unknown_recipient_domain type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_unknown_recipient_domain>
<reject_non_fqdn_sender type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_non_fqdn_sender>
<reject_non_fqdn_recipient type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_non_fqdn_recipient>
<permit_sasl_authenticated type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</permit_sasl_authenticated>
<permit_tls_clientcerts type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</permit_tls_clientcerts>
<permit_mynetworks type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</permit_mynetworks>
<reject_unauth_destination type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</reject_unauth_destination>
<reject_unverified_recipient type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</reject_unverified_recipient>
<delay_warning_time type="IntegerField">
<default>0</default>
<Default>0</Default>
<Required>N</Required>
<MinimumValue>0</MinimumValue>
<MaximumValue>24</MaximumValue>

View file

@ -6,7 +6,7 @@
<headerchecks>
<headercheck type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<expression type="TextField">

View file

@ -6,7 +6,7 @@
<recipients>
<recipient type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<address type="TextField">

View file

@ -6,7 +6,7 @@
<recipientbccs>
<recipientbcc type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<from type="TextField">

View file

@ -6,7 +6,7 @@
<senders>
<sender type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<address type="TextField">

View file

@ -6,7 +6,7 @@
<senderbccs>
<senderbcc type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<from type="TextField">

View file

@ -6,7 +6,7 @@
<sendercanonicals>
<sendercanonical type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</enabled>
<from type="TextField">

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-addresses").UIBootgrid(
{ 'search':'/api/postfix/address/searchAddress',
'get':'/api/postfix/address/getAddress/',
'set':'/api/postfix/address/setAddress/',
'add':'/api/postfix/address/addAddress/',
'del':'/api/postfix/address/delAddress/',
'toggle':'/api/postfix/address/toggleAddress/'
{ 'search':'/api/postfix/address/search_address',
'get':'/api/postfix/address/get_address/',
'set':'/api/postfix/address/set_address/',
'add':'/api/postfix/address/add_address/',
'del':'/api/postfix/address/del_address/',
'toggle':'/api/postfix/address/toggle_address/'
}
);

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-domains").UIBootgrid(
{ 'search':'/api/postfix/domain/searchDomain',
'get':'/api/postfix/domain/getDomain/',
'set':'/api/postfix/domain/setDomain/',
'add':'/api/postfix/domain/addDomain/',
'del':'/api/postfix/domain/delDomain/',
'toggle':'/api/postfix/domain/toggleDomain/'
{ 'search':'/api/postfix/domain/search_domain',
'get':'/api/postfix/domain/get_domain/',
'set':'/api/postfix/domain/set_domain/',
'add':'/api/postfix/domain/add_domain/',
'del':'/api/postfix/domain/del_domain/',
'toggle':'/api/postfix/domain/toggle_domain/'
}
);

View file

@ -34,12 +34,12 @@
*************************************************************************************************************/
$("#grid-headerchecks").UIBootgrid(
{ 'search':'/api/postfix/headerchecks/searchHeaderchecks',
'get':'/api/postfix/headerchecks/getHeadercheck/',
'set':'/api/postfix/headerchecks/setHeadercheck/',
'add':'/api/postfix/headerchecks/addHeadercheck/',
'del':'/api/postfix/headerchecks/delHeadercheck/',
'toggle':'/api/postfix/headerchecks/toggleHeadercheck/'
{ 'search':'/api/postfix/headerchecks/search_headerchecks',
'get':'/api/postfix/headerchecks/get_headercheck/',
'set':'/api/postfix/headerchecks/set_headercheck/',
'add':'/api/postfix/headerchecks/add_headercheck/',
'del':'/api/postfix/headerchecks/del_headercheck/',
'toggle':'/api/postfix/headerchecks/toggle_headercheck/'
}
);

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-recipients").UIBootgrid(
{ 'search':'/api/postfix/recipient/searchRecipient',
'get':'/api/postfix/recipient/getRecipient/',
'set':'/api/postfix/recipient/setRecipient/',
'add':'/api/postfix/recipient/addRecipient/',
'del':'/api/postfix/recipient/delRecipient/',
'toggle':'/api/postfix/recipient/toggleRecipient/'
{ 'search':'/api/postfix/recipient/search_recipient',
'get':'/api/postfix/recipient/get_recipient/',
'set':'/api/postfix/recipient/set_recipient/',
'add':'/api/postfix/recipient/add_recipient/',
'del':'/api/postfix/recipient/del_recipient/',
'toggle':'/api/postfix/recipient/toggle_recipient/'
}
);

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-recipientbccs").UIBootgrid(
{ 'search':'/api/postfix/recipientbcc/searchRecipientbcc',
'get':'/api/postfix/recipientbcc/getRecipientbcc/',
'set':'/api/postfix/recipientbcc/setRecipientbcc/',
'add':'/api/postfix/recipientbcc/addRecipientbcc/',
'del':'/api/postfix/recipientbcc/delRecipientbcc/',
'toggle':'/api/postfix/recipientbcc/toggleRecipientbcc/'
{ 'search':'/api/postfix/recipientbcc/search_recipientbcc',
'get':'/api/postfix/recipientbcc/get_recipientbcc/',
'set':'/api/postfix/recipientbcc/set_recipientbcc/',
'add':'/api/postfix/recipientbcc/add_recipientbcc/',
'del':'/api/postfix/recipientbcc/del_recipientbcc/',
'toggle':'/api/postfix/recipientbcc/toggle_recipientbcc/'
}
);

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-senders").UIBootgrid(
{ 'search':'/api/postfix/sender/searchSender',
'get':'/api/postfix/sender/getSender/',
'set':'/api/postfix/sender/setSender/',
'add':'/api/postfix/sender/addSender/',
'del':'/api/postfix/sender/delSender/',
'toggle':'/api/postfix/sender/toggleSender/'
{ 'search':'/api/postfix/sender/search_sender',
'get':'/api/postfix/sender/get_sender/',
'set':'/api/postfix/sender/set_sender/',
'add':'/api/postfix/sender/add_sender/',
'del':'/api/postfix/sender/del_sender/',
'toggle':'/api/postfix/sender/toggle_sender/'
}
);

View file

@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-senderbccs").UIBootgrid(
{ 'search':'/api/postfix/senderbcc/searchSenderbcc',
'get':'/api/postfix/senderbcc/getSenderbcc/',
'set':'/api/postfix/senderbcc/setSenderbcc/',
'add':'/api/postfix/senderbcc/addSenderbcc/',
'del':'/api/postfix/senderbcc/delSenderbcc/',
'toggle':'/api/postfix/senderbcc/toggleSenderbcc/'
{ 'search':'/api/postfix/senderbcc/search_senderbcc',
'get':'/api/postfix/senderbcc/get_senderbcc/',
'set':'/api/postfix/senderbcc/set_senderbcc/',
'add':'/api/postfix/senderbcc/add_senderbcc/',
'del':'/api/postfix/senderbcc/del_senderbcc/',
'toggle':'/api/postfix/senderbcc/toggle_senderbcc/'
}
);

View file

@ -36,12 +36,12 @@ POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************************************/
$("#grid-sendercanonicals").UIBootgrid(
{ 'search':'/api/postfix/sendercanonical/searchSendercanonical',
'get':'/api/postfix/sendercanonical/getSendercanonical/',
'set':'/api/postfix/sendercanonical/setSendercanonical/',
'add':'/api/postfix/sendercanonical/addSendercanonical/',
'del':'/api/postfix/sendercanonical/delSendercanonical/',
'toggle':'/api/postfix/sendercanonical/toggleSendercanonical/'
{ 'search':'/api/postfix/sendercanonical/search_sendercanonical',
'get':'/api/postfix/sendercanonical/get_sendercanonical/',
'set':'/api/postfix/sendercanonical/set_sendercanonical/',
'add':'/api/postfix/sendercanonical/add_sendercanonical/',
'del':'/api/postfix/sendercanonical/del_sendercanonical/',
'toggle':'/api/postfix/sendercanonical/toggle_sendercanonical/'
}
);

View file

@ -157,7 +157,7 @@ relayhost = {{ OPNsense.postfix.general.relayhost }}
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/usr/local/etc/postfix/smtp_auth
smtp_sasl_security_options =
smtp_sasl_mechanism_filter = !gssapi, !external, static:all
smtp_sasl_mechanism_filter = !gssapi, !ntlm, !external, static:all
{% endif %}
{% if helpers.exists('OPNsense.postfix.general.permit_sasl_authenticated') and OPNsense.postfix.general.permit_sasl_authenticated == '1' %}

View file

@ -5,15 +5,15 @@
<items>
<general>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<enable_redis_plugin type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_redis_plugin>
<enable_bayes_autolearn type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_bayes_autolearn>
<rejectscore type="IntegerField">
@ -120,47 +120,47 @@
<Required>N</Required>
</rewritesubject>
<historyrows type="IntegerField">
<default>200</default>
<Default>200</Default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>100000</MaximumValue>
<ValidationMessage>Choose a value between 1 and 100000.</ValidationMessage>
</historyrows>
<nameserver type="HostnameField">
<default>127.0.0.1</default>
<Default>127.0.0.1</Default>
<Required>Y</Required>
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<AsList>Y</AsList>
</nameserver>
</general>
<milter_headers>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<enable_extended_spam_headers type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_extended_spam_headers>
<enable_authentication_results type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_authentication_results>
<enable_spamd_bar type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enable_spamd_bar>
<skip_local type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</skip_local>
<skip_authenticated type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</skip_authenticated>
<extended_headers_rcpt type="CSVListField">
<mask>/[a-z0-9\.\-_@,]+/i</mask>
<Mask>/[a-z0-9\.\-_@,]+/i</Mask>
<Required>N</Required>
</extended_headers_rcpt>
</milter_headers>
@ -182,18 +182,18 @@
<Required>N</Required>
<MaximumValue>32</MaximumValue>
<ValidationMessage>A valid IPv4 mask must be between 1 and 32 bits.</ValidationMessage>
<default>19</default>
<Default>19</Default>
</ipv4mask>
<ipv6mask type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>N</Required>
<MaximumValue>128</MaximumValue>
<default>64</default>
<Default>64</Default>
<ValidationMessage>A valid IPv6 mask must be between 1 and 128 bits. 64 bits are recommended as this is the recommended subnet size in IPv6.</ValidationMessage>
</ipv6mask>
<whitelist_ip type="CSVListField">
<Required>N</Required>
<mask>/^([a-fA-F0-9\.:\[\]\/]*?,)*([a-fA-F0-9\.:\[\]\/]*)$/</mask>
<Mask>/^([a-fA-F0-9\.:\[\]\/]*?,)*([a-fA-F0-9\.:\[\]\/]*)$/</Mask>
</whitelist_ip>
</graylist>
@ -214,44 +214,44 @@
<ValidationMessage>A valid time jitter must be set.</ValidationMessage>
</time_jitter>
<trusted_only type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</trusted_only>
<skip_multi type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</skip_multi>
<!-- dkim signing -->
<allow_envfrom_empty type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</allow_envfrom_empty>
<allow_hdrfrom_mismatch type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</allow_hdrfrom_mismatch>
<allow_hdrfrom_multiple type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</allow_hdrfrom_multiple>
<allow_username_mismatch type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</allow_username_mismatch>
<auth_only type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</auth_only>
<sign_local type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</sign_local>
<try_fallback type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</try_fallback>
<use_domain type="OptionField">
<default>header</default>
<Default>header</Default>
<Required>Y</Required>
<OptionValues>
<header>Header</header>
@ -259,43 +259,43 @@
</OptionValues>
</use_domain>
<use_esld type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</use_esld>
</dkim>
<mx-check>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<expire type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>N</Required>
<default>86400</default>
<Default>86400</Default>
<ValidationMessage>A valid cache expiration must be set.</ValidationMessage>
</expire>
</mx-check>
<phishing>
<openphish_enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</openphish_enabled>
<openphish_map type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</openphish_map>
<openphish_premium_enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</openphish_premium_enabled>
<phishtank_enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</phishtank_enabled>
<phishtank_map type="TextField">
<default></default>
<Default></Default>
<Required>N</Required>
</phishtank_map>
<exclusion type="CSVListField">
@ -316,7 +316,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -337,7 +337,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -358,7 +358,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -379,7 +379,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -400,7 +400,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -421,7 +421,7 @@
<ValidationMessage>The time must be a positive integer.</ValidationMessage>
</time>
<time_unit type="OptionField">
<default>m</default>
<Default>m</Default>
<Required>Y</Required>
<OptionValues>
<s>Seconds</s>
@ -431,26 +431,26 @@
</time_unit>
</user>
<whitelisted_rcpts type="CSVListField">
<default>postmaster,mailer-daemon</default>
<Default>postmaster,mailer-daemon</Default>
</whitelisted_rcpts>
<max_rcpt type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>Y</Required>
<default>20</default>
<Default>20</Default>
</max_rcpt>
</rate_limit>
<spamtrap>
<enabled type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</enabled>
<fuzzy_learning type="BooleanField">
<default>0</default>
<Default>0</Default>
<Required>Y</Required>
</fuzzy_learning>
<spam_learning type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</spam_learning>
<spam_recipients type="CSVListField">
@ -462,7 +462,7 @@
<spf_cache_size type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>N</Required>
<default>2</default>
<Default>2</Default>
<ValidationMessage>A valid cache size in kilobytes must be set.</ValidationMessage>
</spf_cache_size>
<spf_cache_expire type="IntegerField">
@ -474,16 +474,16 @@
<av>
<force-reject type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</force-reject>
<attachments-only type="BooleanField">
<default>1</default>
<Default>1</Default>
<Required>Y</Required>
</attachments-only>
<max-size type="IntegerField">
<MinimumValue>1</MinimumValue>
<default>20000000</default>
<Default>20000000</Default>
<Required>N</Required>
<ValidationMessage>A valid maximum size in bytes must be set.</ValidationMessage>
</max-size>
@ -504,7 +504,7 @@
<multimap>
<badfileextension type="CSVListField">
<Required>N</Required>
<default>exe,dll,scr,com,cmd,js,bat,vbs,ps1,bat,cpl,lnk,msi,msp,reg</default>
<Default>exe,dll,scr,com,cmd,js,bat,vbs,ps1,bat,cpl,lnk,msi,msp,reg</Default>
</badfileextension>
<whitelistsender type="CSVListField">
<Required>N</Required>

View file

@ -1,6 +1,6 @@
PLUGIN_NAME= theme-advanced
PLUGIN_VERSION= 1.0
PLUGIN_COMMENT= OPNsense theme based on AdvancedTomato GUI
PLUGIN_VERSION= 1.1
PLUGIN_COMMENT= Theme based on AdvancedTomato GUI
PLUGIN_MAINTAINER= jacky@prahec.com
PLUGIN_WWW= https://prahec.com/
PLUGIN_NO_ABI= yes

View file

@ -13,7 +13,6 @@ th {
// Baseline styles
.table {
width: 100%;
max-width: 100%;

View file

@ -149,10 +149,6 @@ body {
touch-action: manipulation;
}
.widget-sort-handle {
touch-action: none;
}
.page-head {
position: fixed;
z-index: map-get($zindex, header);
@ -198,7 +194,7 @@ body {
font-size: 12px;
font-weight: 400;
display: inline-block;
content: "AdvancedOPN Theme";
content: "Advanced Theme";
color: #fafafa;
}
@ -1090,11 +1086,6 @@ select {
appearance: none;
}
#grid-log th[data-column-id="__timestamp__"],
#filter-log-entries th[data-column-id="__timestamp__"] {
min-width: 3.5em;
}
.table-responsive {
@media screen and (max-width: $screen-xs-max) {
margin-bottom: 0;
@ -1268,3 +1259,29 @@ div[data-for*="help_for"] {
margin-bottom: -4px;
}
}
/**
* HACKS
*/
.widget-sort-handle {
touch-action: none;
}
.bootgrid-table {
table-layout: auto !important;
}
table#tunable.bootgrid-table td {
white-space: normal !important;
}
@media (min-width: $screen-lg-desktop) {
table#grid-leases tr td:nth-child(3) {
width: 15% !important;
}
}
#grid-log th[data-column-id="__timestamp__"],
#filter-log-entries th[data-column-id="__timestamp__"] {
min-width: 3.5em;
}

View file

@ -0,0 +1,488 @@
$colors: (
default: #536270,
primary: #51aded,
navbg: #263238,
lightgrey: #f7f7f7,
lightergrey: #fbfbfb,
darkgrey: #3c3c3b,
bordergrey: #eaeaea,
);
@import "bootstrap/variables";
/**
* Customized
*/
@mixin button-variant($color, $background, $border) {
color: $color;
background-color: $background;
border-color: $border;
&:hover,
&:focus,
&:active,
&.active,
.open > &.dropdown-toggle,
:not(disabled):hover {
color: $color !important;
background-color: darken($background, 10%) !important;
border-color: darken($border, 12%) !important;
}
&:active,
&.active,
.open > &.dropdown-toggle {
background-image: none;
}
&.disabled,
&[disabled],
fieldset[disabled] & {
&,
&:hover,
&:focus,
&:active,
&.active {
background-color: $background;
border-color: $border;
}
}
.badge {
color: $background;
background-color: $color;
}
}
// Button sizes
@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
padding: $padding-vertical $padding-horizontal;
font-size: $font-size;
line-height: $line-height;
border-radius: $border-radius;
}
/**
* Main theming elements
*/
.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
background-color: #FBFBFB;
}
.tabulator .tabulator-headers {
height: 100% !important; /* make sure the border below appears */
}
/*------------*/
/* theme: body */
.tabulator .tabulator-tableholder .tabulator-table {
background-color: transparent;
}
.tabulator-row {
background-color: transparent;
color: #373736;
}
.tabulator-row.tabulator-row-odd {
background-color: #FBFBFB;
}
.tabulator-row.tabulator-row-odd.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: $table-bg-hover;
}
.tabulator-row.tabulator-row-even.tabulator-selectable:hover:not(.tabulator-selected) {
background-color: $table-bg-hover;
}
.tabulator .tabulator-tableholder {
background-color: transparent;
}
.tabulator-row.tabulator-selected {
background-color: #e3e8f0;
}
.tabulator-row.tabulator-selected:hover {
cursor: pointer;
background-color: #e3e8f0;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
color: #373736; /* spinner icon */
}
/* Command column styles */
.tabulator-col.tabulator-frozen.tabulator-frozen-right {
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right {
}
/* Tabulator groupBy row styles */
.tabulator-row.tabulator-group {
border: none;
pointer-events: none;
}
.tabulator-row.tabulator-group span {
margin-left: 0;
color: #373736;
}
.tabulator-row .badge.chip {
background-color: #31708f;
color: #FFF;
font-size: 10px;
padding: 2px 4px;
position: relative;
top: -1px;
}
.tabulator-row.tabulator-group .tabulator-group-toggle,
.tabulator-row.tabulator-group .tabulator-group-toggle * {
pointer-events: auto;
}
.tabulator-row.tabulator-group:has(> .tabulator-group-toggle:only-child) {
display: none; /* Trick to hide empty groupBy header rows */
}
/*------------*/
/* theme: cells */
.tabulator-row .tabulator-cell {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
vertical-align: top;
}
/*-------------*/
/* theme: footer */
.tabulator .tabulator-footer {
border-top: none;
background-color: transparent;
}
.tabulator-page-counter {
color: #373736;
}
.tabulator .tabulator-footer .tabulator-paginator {
color: #373736;
}
.tabulator .tabulator-footer .tabulator-page {
}
/*----------*/
/* end of main theming elements */
.tabulator-paginator {
flex: 0 !important;
}
.tabulator-page-counter {
flex: 1;
text-align: right;
}
.tabulator-col-sorter i {
display: flex;
justify-content: center;
align-items: center;
}
.tabulator .tabulator-header .tabulator-col {
padding: 5px;
}
.tabulator .tabulator-headers > :first-child {
padding-left: 10px;
}
.opnsense-bootgrid-responsive {
white-space: wrap !important;
text-overflow: inherit !important;
overflow: visible !important;
word-break: break-word !important;
}
.opnsense-bootgrid-ellipsis {
overflow: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
.tabulator-row > :first-child {
padding-left: 10px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 0px;
}
.tabulator-page-counter {
padding-right: 20px;
}
.bootgrid-footer-commands {
width: 90px;
padding-left: 8px;
}
.tabulator-tableholder::after {
content: "";
display: block;
width: 1px;
height: 1px;
min-width: 100%;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:first-child {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.tabulator .tabulator-footer .tabulator-paginator .tabulator-page:last-child {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
/* border line corrections and hover/selection behavior */
.tabulator-row:first-child > .tabulator-cell {
border-top: none;
}
.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title {
padding: 0px;
}
/* Row highlight behavior */
@keyframes highlight {
0% {
background: #ffff99;
}
100% {
background: none;
}
}
.highlight-bg {
animation: highlight 2s;
}
/* Tabulator "loading" and "error" overrides */
.tabulator .tabulator-alert {
background: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
border: none;
}
.tabulator .tabulator-alert .tabulator-alert-msg {
background: initial;
font-size: 18px;
}
.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
border: none;
}
.bootgrid-placeholder {
font-size: 15px;
text-align: center;
white-space: normal;
font-weight: 400;
margin: 10px;
}
.bootgrid-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
}
.overlay > i {
font-size: 20px;
color: black;
}
/**
* Main theming elements for tabulator
/* Base */
.tabulator {
width: 100%;
font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
font-size: 13px;
background: #fff;
border: 1px solid $table-border-color; /* .table-bordered */
border-radius: 0;
}
/* Header */
.tabulator .tabulator-header {
background: #fff;
border-bottom: 1px solid $table-border-color; /* thead bottom border */
border-top: 0;
border-left: 0;
border-right: 0;
}
.tabulator .tabulator-header .tabulator-col {
background: transparent;
color: #333;
border-right: 1px solid $table-border-color; /* col separators */
}
.tabulator .tabulator-header .tabulator-col:last-child {
border-right: 0;
}
/* Header cell inner (align/padding like Bootstrap) */
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
padding: 10px 0 10px 20px; /* th padding */
line-height: 1.428571429;
}
/* Sort hover (subtle) */
.tabulator .tabulator-header .tabulator-col.tabulator-sortable:hover {
background: #f5f5f5;
}
/* Body */
.tabulator .tabulator-tableholder {
background: #fff;
}
.tabulator-row {
background: #fff;
color: #333;
border-top: 1px solid $table-border-color; /* row top border like Bootstrap */
}
/* Cells */
.tabulator-row .tabulator-cell {
padding: 10px 0 10px 20px; /* td padding */
line-height: 1.428571429;
vertical-align: top;
border-right: 1px solid $table-border-color; /* col separators */
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left,
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left,
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left,
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left,
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right,
.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right {
border-color: $table-border-color;
border-width: 1px;
}
.tabulator-row .tabulator-cell:last-child {
border-right: 0;
}
.tabulator-header {
.tabulator-row-header input,
.tabulator-cell input {
margin-left: -24px;
}
}
.tabulator-table {
.tabulator-row-header input,
.tabulator-cell input {
margin-left: -18px;
}
}
/* Striped (.table-striped) */
.tabulator.tabulator-striped .tabulator-row:nth-child(odd) {
background: #fbfbfb;
}
/* Hover (.table-hover) */
.tabulator.tabulator-hover .tabulator-row:hover {
background: $table-bg-hover !important;
}
/* Active state (matches .active bg) */
.tabulator-row.tabulator-selected {
background: $table-bg-hover !important;
}
.tabulator-row.tabulator-selected:hover {
background: $table-bg-hover !important;
}
/* Footer (pagination) */
.tabulator .tabulator-footer {
background: #fff;
border-top: 1px solid $table-border-color;
color: #555;
}
.tabulator .tabulator-footer .tabulator-page {
border: 1px solid $table-border-color;
background: #fff;
color: #333;
border-radius: 0;
margin: 0;
padding: 6px 12px; /* Bootstrap-like pager */
@include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
}
@media (hover: hover) and (pointer: fine) {
.tabulator .tabulator-footer .tabulator-page:not(disabled):hover {
}
}
.tabulator-row.tabulator-row-even {
background-color: $table-bg
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
overflow: visible;
}
.tabulator-row.tabulator-selected {
background-color: #9abcea
}
.tabulator .tabulator-alert {
align-items: center;
background: rgba(#fff, .5);
display: flex;
height: 100%;
left: 0;
position: absolute;
text-align: center;
top: 0;
width: 100%;
z-index: 100;
}
/**
* jQuery Bootstrap Grid
*/
.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item.dropdown-item-checkbox,
.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item.dropdown-item-checkbox,
.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item .dropdown-item-checkbox,
.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item .dropdown-item-checkbox {
margin: 0 8px 4px -8px !important;
}

View file

@ -1 +1 @@
:root{--chart-js-background-color: #f7e2d6;--chart-js-border-color: #f6f6f6;--chart-js-font-color: #4b4b64}.btn-pressed,.btn-pressed:hover{color:white;background-color:#0086d9}#save-grid{position:relative;display:inline-flex;align-items:center;justify-content:center;width:50px;height:33px;margin-right:10px;transition:opacity 0.3s ease}#save-btn-text,#icon-container{position:absolute}#icon-container{display:inline-flex;align-items:center;justify-content:center}#save-spinner,#save-check{transition:opacity 0.3s ease, transform 0.3s ease}.transition-spinner,transition-check{transition:opacity 0.3s ease, transform 0.3s ease}.grid-stack-item-content{text-align:center;border:none !important;border-radius:0.5em 0.5em 0.5em 0.5em;background-color:#fff;box-shadow:0 2px 4px rgba(40,40,50,0.15),0 0 1px rgba(40,40,50,0.35)}.widget-error{margin:50px;color:#721c24}.widget-content{position:relative;width:100%;height:100%;padding:1px;cursor:grab}.widget-header{font-size:14px;display:flex;align-items:center;justify-content:space-between;margin-top:0.5em;margin-right:1em;margin-left:1em}.widget-spinner{margin-top:20px}.fa-stack.small{font-size:0.5em}.close-handle,.edit-handle{padding:.2rem .5rem;cursor:pointer;text-align:right;vertical-align:middle}.close-handle>i,.edit-handle>i{font-size:1.2rem !important}.widget-header-left{display:flex;align-items:center;flex:1;justify-content:flex-start}.widget-command-container{display:flex;align-items:center;flex:1;justify-content:flex-end}.widget-title{display:flex;align-items:center;justify-content:center}.panel-divider{width:100%;height:8px;margin-bottom:10px;text-align:center}.panel-divider .line{display:none}td{word-break:break-all}.canvas-container{position:relative}.cpu-canvas-container{display:flex;flex-direction:column}.smoothie-container{width:100%}.smoothie-chart-tooltip{font-size:13px;z-index:1;padding-right:15px;padding-left:15px;pointer-events:none;color:white;border-radius:0.5em 0.5em 0.5em 0.5em;background:rgba(50,50,50,0.9)}.flex-container{display:flex;flex-wrap:nowrap;white-space:nowrap}.gateway-info{font-size:13px;margin:5px;padding:5px}.gateway-detail-container{display:none;margin:5px}.interface-info{display:flex;align-items:center;flex-wrap:wrap;height:100%}.nowrap{flex-wrap:nowrap}.gateway-graph{display:none}.flex-container>.gateway-graph{font-size:13px}.vertical-center-row{display:inline;height:100%}.interfaces-info{font-size:.8rem;margin:5px}.interface-descr{font-size:1em;margin-left:.8em;cursor:pointer;text-decoration:underline}.interfaces-detail-container{display:none;margin:5px}.d-flex{display:flex}.d-flex>.justify-content-start{justify-content:start}.d-flex>.justify-content-end{justify-content:end}#chartjs-toolip{z-index:20}.cpu-type{margin-top:10px;margin-bottom:10px}div{box-sizing:border-box}.flextable-container{display:block;width:95%;max-width:1200px;margin:2em auto}.flextable-header{display:flex;flex-flow:row wrap;padding:0.5em 0.5em;transition:0.5s;border-top:solid 1px rgba(0,119,217,0.15) !important}.flextable-row{display:flex;align-items:center;flex-flow:row wrap;padding:0.5em 0.5em;transition:0.5s;border-top:solid 1px #e8eaef !important}.flextable-header .flex-cell{font-weight:bold}.flextable-row:hover{transition:500ms;background:#f5f5f5}.flex-cell{padding:4px 0;text-align:left;word-break:break-word}.column{display:flex;flex-flow:column wrap;width:50%;padding:0}.column .flex-cell{display:flex;flex-flow:row wrap;width:100%;padding:4px 0;border:0;border-top:#e8eaef}.column .flex-cell:hover{transition:500ms;background:#f5f5f5}.flex-subcell{width:100%;text-align:left}.column .flex-cell:not(:last-child){border-bottom:solid 1px #e8eaef !important}.grid-header-container{display:grid;grid-template-columns:repeat(auto-fit, minmax(100px, 1fr))}.grid-row{display:grid;transition:0.5s;opacity:0.4;border-top:1px solid #eff3f8;background-color:#d6e5f7;grid-template-columns:repeat(auto-fit, minmax(100px, 1fr))}.grid-row:hover{transition:500ms;background:#f5f5f5 !important}.grid-header{font-weight:bold;border-top:1px solid #eff3f8}.grid-item{padding:4px;text-align:center}.ovpn-common-name{display:flex;align-items:center;justify-content:center}
:root{--chart-js-background-color: #f7e2d6;--chart-js-border-color: #f6f6f6;--chart-js-font-color: #4b4b64}.btn-pressed,.btn-pressed:hover{color:#fff;background-color:#0086d9}#save-grid{position:relative;display:inline-flex;align-items:center;justify-content:center;width:50px;height:33px;margin-right:10px;transition:opacity .3s ease}#save-btn-text,#icon-container{position:absolute}#icon-container{display:inline-flex;align-items:center;justify-content:center}#save-spinner,#save-check{transition:opacity .3s ease,transform .3s ease}.transition-spinner,transition-check{transition:opacity .3s ease,transform .3s ease}.grid-stack-item-content{text-align:center;border:none !important;border-radius:.5em .5em .5em .5em;background-color:#fff;box-shadow:0 2px 4px rgba(40,40,50,.15),0 0 1px rgba(40,40,50,.35)}.widget-error{margin:50px;color:#721c24}.widget-content{position:relative;width:100%;height:100%;padding:1px;cursor:grab}.widget-header{font-size:14px;display:flex;align-items:center;justify-content:space-between;margin-top:.5em;margin-right:1em;margin-left:1em}.widget-spinner{margin-top:20px}.fa-stack.small{font-size:.5em}.close-handle,.edit-handle{padding:.2rem .5rem;cursor:pointer;text-align:right;vertical-align:middle}.close-handle>i,.edit-handle>i{font-size:1.2rem !important}.widget-header-left{display:flex;align-items:center;flex:1;justify-content:flex-start}.widget-command-container{display:flex;align-items:center;flex:1;justify-content:flex-end}.widget-title{display:flex;align-items:center;justify-content:center}.panel-divider{width:100%;height:8px;margin-bottom:10px;text-align:center}.panel-divider .line{display:none}td{word-break:break-all}.canvas-container{position:relative}.cpu-canvas-container{display:flex;flex-direction:column}.smoothie-container{width:100%}.smoothie-chart-tooltip{font-size:13px;z-index:1;padding-right:15px;padding-left:15px;pointer-events:none;color:#fff;border-radius:.5em .5em .5em .5em;background:rgba(50,50,50,.9)}.flex-container{display:flex;flex-wrap:nowrap;white-space:nowrap}.gateway-info{font-size:13px;margin:5px;padding:5px}.gateway-detail-container{display:none;margin:5px}.interface-info{display:flex;align-items:center;flex-wrap:wrap;height:100%}.nowrap{flex-wrap:nowrap}.gateway-graph{display:none}.flex-container>.gateway-graph{font-size:13px}.vertical-center-row{display:inline;height:100%}.interfaces-info{font-size:.8rem;margin:5px}.interface-descr{font-size:1em;margin-left:.8em;cursor:pointer;text-decoration:underline}.interfaces-detail-container{display:none;margin:5px}.d-flex{display:flex}.d-flex>.justify-content-start{justify-content:start}.d-flex>.justify-content-end{justify-content:end}#chartjs-toolip{z-index:20}.cpu-type{margin-top:10px;margin-bottom:10px}div{box-sizing:border-box}.flextable-container{display:block;width:95%;max-width:1200px;margin:2em auto}.flextable-header{display:flex;flex-flow:row wrap;padding:.5em .5em;transition:.5s;border-top:solid 1px rgba(0,119,217,.15) !important}.flextable-row{display:flex;align-items:center;flex-flow:row wrap;padding:.5em .5em;transition:.5s;border-top:solid 1px #e8eaef !important}.flextable-header .flex-cell{font-weight:bold}.flextable-row:hover{transition:500ms;background:#f5f5f5}.flex-cell{padding:4px 0;text-align:left;word-break:break-word}.column{display:flex;flex-flow:column wrap;width:50%;padding:0}.column .flex-cell{display:flex;flex-flow:row wrap;width:100%;padding:4px 0;border:0;border-top:#e8eaef}.column .flex-cell:hover{transition:500ms;background:#f5f5f5}.flex-subcell{width:100%;text-align:left}.column .flex-cell:not(:last-child){border-bottom:solid 1px #e8eaef !important}.grid-header-container{display:grid;grid-template-columns:repeat(auto-fit, minmax(100px, 1fr))}.grid-row{display:grid;transition:.5s;opacity:.4;border-top:1px solid #eff3f8;background-color:#d6e5f7;grid-template-columns:repeat(auto-fit, minmax(100px, 1fr))}.grid-row:hover{transition:500ms;background:#f5f5f5 !important}.grid-header{font-weight:bold;border-top:1px solid #eff3f8}.grid-item{padding:4px;text-align:center}.ovpn-common-name{display:flex;align-items:center;justify-content:center}/*# sourceMappingURL=dashboard.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,95 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW X8 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="171.889mm" height="34.3477mm" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 21856 4367"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil0 {fill:#EBECEC;fill-rule:nonzero}
.fil2 {fill:#E3E4E5;fill-rule:nonzero}
.fil8 {fill:#AAABAB;fill-rule:nonzero}
.fil5 {fill:#939292;fill-rule:nonzero}
.fil1 {fill:#D94F00;fill-rule:nonzero}
.fil11 {fill:url(#id0);fill-rule:nonzero}
.fil7 {fill:url(#id1);fill-rule:nonzero}
.fil10 {fill:url(#id2);fill-rule:nonzero}
.fil15 {fill:url(#id3);fill-rule:nonzero}
.fil14 {fill:url(#id4);fill-rule:nonzero}
.fil16 {fill:url(#id5);fill-rule:nonzero}
.fil9 {fill:url(#id6);fill-rule:nonzero}
.fil12 {fill:url(#id7);fill-rule:nonzero}
.fil13 {fill:url(#id8);fill-rule:nonzero}
.fil3 {fill:url(#id9);fill-rule:nonzero}
.fil4 {fill:url(#id10);fill-rule:nonzero}
.fil6 {fill:url(#id11);fill-rule:nonzero}
]]>
</style>
<linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="2258.18" y1="2586.09" x2="4329.89" y2="3125.08">
<stop offset="0" style="stop-opacity:1; stop-color:#AAABAB"/>
<stop offset="0.101961" style="stop-opacity:1; stop-color:#AAABAB"/>
<stop offset="1" style="stop-opacity:1; stop-color:#4E4E4E"/>
</linearGradient>
<linearGradient id="id1" gradientUnits="userSpaceOnUse" x1="4003.85" y1="4057.41" x2="4106.63" y2="3796.38">
<stop offset="0" style="stop-opacity:1; stop-color:#E4E4E4"/>
<stop offset="1" style="stop-opacity:1; stop-color:#A2A2A2"/>
</linearGradient>
<linearGradient id="id2" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="2258.16" y1="1781.29" x2="4329.9" y2="1242.3">
</linearGradient>
<linearGradient id="id3" gradientUnits="userSpaceOnUse" x1="4249.51" y1="3279.41" x2="2665.39" y2="3279.41">
<stop offset="0" style="stop-opacity:1; stop-color:#FEFEFE"/>
<stop offset="0.231373" style="stop-opacity:1; stop-color:#FEFEFE"/>
<stop offset="1" style="stop-opacity:1; stop-color:#B0B0B0"/>
</linearGradient>
<linearGradient id="id4" gradientUnits="userSpaceOnUse" xlink:href="#id3" x1="4249.51" y1="1087.97" x2="2665.39" y2="1087.97">
</linearGradient>
<linearGradient id="id5" gradientUnits="userSpaceOnUse" xlink:href="#id3" x1="-0.0127153" y1="3279.41" x2="1584.11" y2="3279.41">
</linearGradient>
<linearGradient id="id6" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="1991.34" y1="1781.31" x2="-80.3479" y2="1242.28">
</linearGradient>
<linearGradient id="id7" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="1991.33" y1="2586.07" x2="-80.3352" y2="3125.09">
</linearGradient>
<linearGradient id="id8" gradientUnits="userSpaceOnUse" xlink:href="#id3" x1="-0.0127153" y1="1087.97" x2="1584.11" y2="1087.97">
</linearGradient>
<linearGradient id="id9" gradientUnits="userSpaceOnUse" xlink:href="#id1" x1="4048.89" y1="285.509" x2="4123.28" y2="547.495">
</linearGradient>
<linearGradient id="id10" gradientUnits="userSpaceOnUse" xlink:href="#id1" x1="245.672" y1="309.973" x2="142.882" y2="571.018">
</linearGradient>
<linearGradient id="id11" gradientUnits="userSpaceOnUse" xlink:href="#id1" x1="200.647" y1="4081.86" x2="126.237" y2="3819.93">
</linearGradient>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_1932602954816">
<path class="fil0" d="M7629 276l-1838 0c-270,0 -491,221 -491,491l0 3135 0 166 166 0 1838 0c270,0 491,-220 491,-490l0 -3136 0 -166 -166 0zm4077 14l0 0 1838 0 165 0 0 166 0 3135c0,432 -348,500 -681,500 -56,0 -125,-3 -189,-6 -42,-2 -80,-4 -126,-4l0 -165 0 -166c32,0 84,3 140,5 50,3 105,5 175,5 171,0 350,-23 350,-169l0 -2970 -1590 0 -82 0 -6 0 0 0 -2 0 0 0 -2 1 -1 0 -1 0 0 0 -2 0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 -2 1 0 0 -2 0 0 0 -1 0 -1 0 -1 0 -1 1 -1 0 -1 0 -1 0 -1 0 -1 1 -1 0 -1 0 -1 0 -1 0 -1 1 0 0 -2 0 0 0 -2 1 0 0 -2 0 0 0 -2 1 -1 0 0 0 -2 1 0 0 -2 0 0 1 -2 0 0 0 -1 1 -1 0 -1 0 -1 1 -1 0 0 0 -1 1 -1 0 -1 0 -1 1 -1 0 -1 1 -1 0 0 0 -1 1 -1 0 -1 0 -1 1 0 0 -2 1 0 0 -3 2 0 0 -2 0 0 1 -1 0 -1 1 -1 0 0 0 -2 1 -1 1 0 0 -2 1 0 0 -1 1 -1 0 -1 1 0 0 -2 1 0 0 -1 1 -2 1 0 1 -1 0 -1 1 -1 0 0 1 -1 1 -1 0 0 1 -1 0 -1 1 -1 0 0 1 -1 1 -1 0 -1 1 0 0 -1 1 0 0 -1 1 -1 1 -1 1 0 0 -1 1 0 0 -2 1 0 0 -1 2 0 0 -1 1c-29,29 -47,68 -47,112l0 3136 -3 0 0 165 -163 0 -165 0 0 -165 0 -3136c0,-135 55,-258 143,-346 89,-89 212,-144 347,-144zm-1190 -9l0 0 -1741 0c-252,0 -458,206 -458,458l0 1655 0 166 0 0 0 1502 333 0 0 -1502 1574 0c253,0 458,-206 458,-458l0 -1655 0 -166 -166 0zm-1741 333l0 0 1575 0 0 1488c0,6 -1,12 -2,18l0 0 0 4 0 0 -1 2 0 0 0 2 0 1 -1 0 0 2 0 1 -1 4 0 1 -1 1 0 2 -1 1 0 1 -1 3 0 0 -1 3 0 0 -1 3 -1 0 -1 3 0 0 -1 2 1 -1 -3 4 0 1 -1 2 0 1 -1 0 0 1 -2 4 -1 0 0 1 -1 0 -1 2 0 1 -1 1 0 1 -2 2 -2 3 -1 1 -3 3 0 1 -5 5 -6 5 -2 3 -6 5 -1 0 0 1 -4 2 0 0 -1 1 -1 1 -4 2 -1 1 -1 0 0 0 -3 2 0 0 -6 3 0 0 -5 2 0 0 -3 2 0 0c-3,1 -7,3 -12,4l-3 1 0 0 -4 1 -2 0 -3 1 0 0 -4 0 0 0c-6,1 -12,1 -18,1l-1575 0 0 -1488c0,-6 1,-12 2,-18l0 -3 0 0 1 -3 1 -3 0 0 0 -3 0 -1 1 -3 3 -8 0 0 0 1 0 -1 1 -4 0 1 2 -4 0 0 2 -4 0 0 3 -6 0 -1 2 -3 0 0 0 0 1 -1 2 -4 1 -1 1 -2 0 0 2 -3 3 -3 3 -4 0 -1 3 -2 0 0 5 -6 5 -5 1 0 3 -3 1 0 3 -2 0 -1 3 -1 1 -1 3 -2 0 0 1 -1 0 0 4 -3 1 0 0 0 1 0 2 -2 1 0 4 -2 -1 0 2 -1 0 0 3 -1 0 0 3 -1 3 -1 4 -2 -1 1 5 -2 5 -1 1 -1 2 0 0 0 1 0 0 0 2 -1 0 0 2 0 0 0 4 -1c6,-1 12,-1 18,-1zm1573 1506l0 0 0 0 0 0zm0 4l0 0 0 0 0 0zm-1 2l0 0 0 0 0 0zm0 3l0 0 -1 0 1 0zm-1 2l0 0 0 1 0 -1zm-1 5l0 0 0 1 0 -1zm-1 2l0 0 0 2 0 -2zm-1 3l0 0 0 1 0 -1zm-1 4l0 0 0 0 0 0zm-1 3l0 0 0 0 0 0zm-1 3l0 0 -1 0 1 0zm-2 3l0 0 0 0 0 0zm-3 5l0 0 0 1 0 -1zm-1 3l0 0 0 1 0 -1zm-1 1l0 0 0 1 0 -1zm-2 5l0 0 -1 0 1 0zm-1 1l0 0 -1 0 1 0zm-2 2l0 0 0 1 0 -1zm-1 2l0 0 0 1 0 -1zm-4 6l0 0 -1 1 1 -1zm-4 4l0 0 0 1 0 -1zm-20 19l0 0 0 1 0 -1zm-4 3l0 0 0 0 0 0zm-1 1l0 0 -1 1 1 -1zm-5 3l0 0 -1 1 1 -1zm-2 1l0 0 0 0 0 0zm-3 2l0 0 0 0 0 0zm-11 5l0 0 0 0 0 0zm-18 7l0 0 0 0 0 0zm-9 2l0 0 0 0 0 0zm-4 0l0 0 0 0 0 0zm-1591 -1505l0 0 0 -3 0 0 0 0 0 3zm2 -9l0 0 0 0 0 0zm0 -3l0 0 0 -1 0 1zm7 -19l0 0 0 0 0 0zm5 -10l0 0 0 -1 0 1zm2 -4l0 0 0 0 0 0zm0 0l0 0 1 -1 -1 1zm3 -5l0 0 1 -1 -1 1zm2 -3l0 0 0 0 0 0zm8 -10l0 0 0 -1 0 1zm3 -3l0 0 0 0 0 0zm10 -11l0 0 1 0 -1 0zm4 -3l0 0 1 0 -1 0zm4 -2l0 0 0 -1 0 1zm7 -5l0 0 0 0 0 0zm1 -1l0 0 0 0 0 0zm4 -3l0 0 1 0 -1 0zm1 0l0 0 1 0 -1 0zm3 -2l0 0 1 0 -1 0zm6 -3l0 0 0 0 0 0zm3 -1l0 0 0 0 0 0zm19 -6l0 0 1 -1 -1 1zm3 -1l0 0 0 0 0 0zm1 0l0 0 0 0 0 0zm2 -1l0 0 0 0 0 0zm2 0l0 0 0 0 0 0zm4 -1l0 0 -2966 -7 1672 0 0 2970c0,13 -5,40 -5,40l-6 18 0 0 0 -1 0 1 -1 1 0 1 -1 3 0 0 -1 3 -1 0 -6 13 0 0 -2 3 0 0 -4 6 0 0 -4 5 0 0 -2 3 0 0 -2 3 0 0 -1 1 0 0 -2 3 0 0 -2 2 -2 2 -1 1 -1 1 0 0 -5 5 0 0 -2 2 0 0 -2 2 -3 2 0 0 -2 2 -1 1 -1 1 0 0 -3 2 0 0 -2 2 -1 0 -5 4 0 0 -5 3 0 0 -3 2 -1 0 -12 7 -4 1 -2 2 -2 0 -18 6 -1 0 1 0 0 0 -1 0 0 1c-14,3 -25,5 -40,5l-1672 0 0 -2970c0,-13 5,-40 5,-40l6 -18 0 0 0 1 0 -1 1 -2 0 -1 1 -2 0 0 1 -3 1 -1 6 -12 0 0 2 -4 0 0 4 -5 0 0 4 -5 0 -1 2 -2 0 0 2 -3 0 0 1 -1 0 -1 2 -2 0 0 2 -2 2 -3 1 0 1 -2 0 0 5 -5 0 0 2 -1 0 -1 2 -1 3 -3 0 0 2 -2 1 0 1 -1 0 0 3 -2 0 0 2 -2 1 0 5 -4 0 0 5 -4 0 0 4 -2 0 0 12 -6 4 -2 0 0 2 -1 3 -1 18 -6 0 0 -1 0 1 0 0 0 0 0c14,-3 25,-5 40,-5l2966 7zm-1306 3022l0 0 0 1 0 -1zm-1 4l0 0 0 0 0 0zm-1 3l0 0 -1 0 1 0zm-7 13l0 0 0 0 0 0zm-2 3l0 0 0 0 0 0zm-4 6l0 0 0 0 0 0zm-4 5l0 0 0 0 0 0zm-2 3l0 0 0 0 0 0zm-2 3l0 0 0 0 0 0zm-1 1l0 0 0 0 0 0zm-6 7l0 0 -1 1 1 -1zm-2 2l0 0 0 0 0 0zm-5 5l0 0 0 0 0 0zm-2 2l0 0 0 0 0 0zm-7 6l0 0 -1 1 1 -1zm-2 2l0 0 0 0 0 0zm-3 2l0 0 0 0 0 0zm-2 2l0 0 -1 0 1 0zm-6 4l0 0 0 0 0 0zm-5 3l0 0 0 0 0 0zm-3 2l0 0 -1 0 1 0zm-17 8l0 0 -23 8 0 1 0 -1 23 -8zm-1723 -3016l0 0 0 -1 0 1zm1 -3l0 0 0 0 0 0zm1 -3l0 0 1 -1 -1 1zm7 -13l0 0 0 0 0 0zm2 -4l0 0 0 0 0 0zm4 -5l0 0 0 0 0 0zm4 -5l0 0 0 -1 0 1zm2 -3l0 0 0 0 0 0zm2 -3l0 0 0 0 0 0zm1 -1l0 0 0 -1 0 1zm6 -8l0 0 1 0 -1 0zm2 -2l0 0 0 0 0 0zm5 -5l0 0 0 0 0 0zm2 -1l0 0 0 -1 0 1zm7 -7l0 0 1 0 -1 0zm2 -1l0 0 0 0 0 0zm3 -2l0 0 0 0 0 0zm2 -2l0 0 1 0 -1 0zm6 -4l0 0 0 0 0 0zm5 -4l0 0 0 0 0 0zm4 -2l0 0 0 0 0 0zm16 -8l0 0 0 0 0 0zm23 -8l0 0 0 0 0 0z"/>
</g>
<g id="_1932602954464">
<path class="fil0" d="M21552 1415c51,0 101,13 150,39 48,27 86,64 113,113 28,49 41,100 41,152 0,53 -13,103 -40,152 -27,48 -64,85 -112,112 -49,27 -99,40 -152,40 -52,0 -103,-13 -151,-40 -48,-27 -86,-64 -113,-112 -26,-49 -40,-99 -40,-152 0,-52 14,-103 41,-152 27,-49 65,-86 114,-113 48,-26 98,-39 149,-39zm0 51l0 0c-42,0 -84,11 -125,32 -40,22 -72,54 -94,94 -23,41 -35,83 -35,127 0,44 12,86 34,126 22,41 54,72 94,94 40,23 82,34 126,34 44,0 86,-11 126,-34 41,-22 72,-53 94,-94 23,-40 34,-82 34,-126 0,-44 -12,-86 -34,-127 -23,-40 -55,-72 -95,-94 -41,-21 -82,-32 -125,-32z"/>
<path class="fil0" d="M21674 1822c-16,-29 -35,-51 -49,-64 -7,-7 -16,-14 -27,-18 28,-3 51,-13 68,-30 17,-18 26,-39 26,-63 0,-17 -5,-32 -16,-48 -10,-15 -23,-25 -41,-31 -17,-6 -45,-9 -83,-9l-113 0 0 327 53 0 0 -139 31 0c19,0 32,8 42,16 14,10 39,40 52,66 11,20 18,57 18,57l64 0c0,0 -9,-36 -25,-64zm-118 -120l0 0 -64 0 0 -99 60 0c26,0 44,2 53,6 10,4 17,9 23,17 5,8 8,16 8,26 0,15 -6,27 -17,36 -11,9 -32,14 -63,14z"/>
</g>
<path class="fil1" d="M15312 2714l-531 0 0 -107c0,-92 -5,-149 -16,-174 -10,-24 -36,-36 -78,-36 -34,0 -59,11 -76,33 -17,23 -25,56 -25,101 0,61 4,105 12,133 8,29 34,60 76,93 42,35 128,84 259,149 175,85 289,165 343,241 55,76 82,186 82,330 0,161 -21,283 -62,364 -42,82 -112,146 -210,190 -98,45 -215,66 -354,66 -152,0 -284,-23 -392,-71 -109,-48 -184,-112 -225,-194 -40,-81 -61,-204 -61,-369l0 -95 535 0 0 124c0,106 6,175 20,207 13,31 40,47 79,47 43,0 72,-10 89,-32 17,-21 25,-66 25,-135 0,-94 -10,-153 -32,-177 -23,-24 -140,-95 -350,-212 -176,-100 -284,-190 -323,-271 -39,-81 -58,-177 -58,-289 0,-158 21,-275 63,-349 41,-76 112,-134 212,-174 100,-41 216,-62 347,-62 132,0 243,17 335,50 92,34 162,78 212,133 48,54 78,105 89,152 10,47 15,120 15,219l0 115zm1572 391l0 0 -782 0 0 429c0,90 7,148 20,174 13,26 38,38 75,38 46,0 77,-17 93,-51 15,-35 23,-101 23,-200l0 -249 571 0 0 134c0,123 -8,217 -23,282 -16,66 -52,136 -108,211 -57,75 -129,131 -216,168 -87,38 -196,56 -327,56 -128,0 -240,-18 -338,-55 -97,-37 -173,-87 -227,-151 -55,-64 -92,-135 -113,-212 -21,-77 -31,-189 -31,-337l0 -577c0,-173 23,-310 70,-410 47,-100 123,-177 229,-230 107,-53 229,-80 368,-80 169,0 308,32 418,97 110,64 188,149 232,255 44,105 66,254 66,446l0 262zm-602 -321l0 0 0 -144c0,-103 -5,-169 -16,-199 -12,-30 -34,-44 -69,-44 -43,0 -69,12 -79,38 -11,25 -16,93 -16,205l0 144 180 0zm1409 -702l0 0 -10 151c61,-71 92,-98 155,-136 63,-36 142,-52 225,-52 103,0 187,25 253,74 66,48 108,110 127,184 19,74 28,197 28,370l0 1388 -601 0 0 -1372c0,-136 -5,-220 -14,-249 -9,-30 -34,-45 -75,-45 -43,0 -70,17 -81,51 -11,35 -17,127 -17,276l0 1339 -601 0 0 -1979 611 0zm2217 632l0 0 -532 0 0 -107c0,-92 -5,-149 -16,-174 -10,-24 -36,-36 -78,-36 -33,0 -59,11 -76,33 -16,23 -25,56 -25,101 0,61 4,105 13,133 8,29 33,60 75,93 42,35 129,84 259,149 175,85 289,165 343,241 55,76 82,186 82,330 0,161 -20,283 -62,364 -42,82 -112,146 -209,190 -99,45 -216,66 -355,66 -152,0 -284,-23 -392,-71 -109,-48 -184,-112 -224,-194 -41,-81 -61,-204 -61,-369l0 -95 534 0 0 124c0,106 7,175 20,207 14,31 40,47 79,47 43,0 72,-10 89,-32 17,-21 26,-66 26,-135 0,-94 -11,-153 -33,-177 -23,-24 -139,-95 -350,-212 -176,-100 -284,-190 -323,-271 -38,-81 -58,-177 -58,-289 0,-158 21,-275 63,-349 42,-76 112,-134 212,-174 100,-41 216,-62 348,-62 131,0 242,17 334,50 92,34 162,78 212,133 49,54 79,105 89,152 11,47 16,120 16,219l0 115zm1571 391l0 0 -781 0 0 429c0,90 6,148 19,174 13,26 38,38 75,38 46,0 78,-17 93,-51 16,-35 23,-101 23,-200l0 -249 571 0 0 134c0,123 -7,217 -23,282 -15,66 -51,136 -108,211 -57,75 -129,131 -216,168 -87,38 -196,56 -327,56 -127,0 -240,-18 -338,-55 -97,-37 -173,-87 -227,-151 -55,-64 -92,-135 -112,-212 -21,-77 -32,-189 -32,-337l0 -577c0,-173 23,-310 70,-410 47,-100 123,-177 230,-230 107,-53 229,-80 367,-80 169,0 309,32 419,97 109,64 187,149 231,255 44,105 66,254 66,446l0 262zm-601 -321l0 0 0 -144c0,-103 -6,-169 -17,-199 -11,-30 -34,-44 -69,-44 -43,0 -69,12 -79,38 -10,25 -15,93 -15,205l0 144 180 0z"/>
<path class="fil2" d="M4250 404l-327 0 0 -68 -3440 0c-14,0 -25,2 -39,5l0 0 0 0 -1 0 -17 6 -3 1 -2 1 -3 2 -13 7 0 0 -3 1 0 1 -6 3 0 0 -5 4 0 0 -2 2 0 0 -3 2 0 0 -2 1 0 1 -2 2 0 0 -3 2 -2 2 0 0 -2 2 0 0 -5 5 0 0 -1 2 0 0 -3 3 -2 1 1 0 -3 3 0 0 -1 1 0 1 -2 2 0 1 -2 2 0 0 -1 2 -343 0 0 -23c51,-218 243,-381 470,-381l0 0 3767 0 0 333 0 3 0 68z"/>
<polygon class="fil3" points="3923,337 4250,161 4250,333 4250,336 4250,497 3924,672 3923,672 "/>
<path class="fil4" d="M90 209l299 160 -3 2 0 0 -2 1 0 1 -2 2 0 0 -3 2 -2 2 0 0 -2 2 0 0 -5 5 0 0 -1 2 0 0 -3 3 -2 1 1 0 -3 3 0 0 -1 1 0 1 -2 2 0 1 -2 2 0 0 -3 5 -1 1 -3 5 0 0 -2 3 0 1 -7 12 0 1 -1 3 0 0 -1 2 -1 2 0 1 -6 19c0,-1 -5,26 -5,39l0 0 0 176 -327 -175 0 -1c0,-107 33,-206 90,-287z"/>
<polygon class="fil5" points="3596,1008 654,1008 654,672 3596,672 "/>
<path class="fil2" d="M0 3964l327 0 0 67 3440 0 0 0c14,0 25,-1 38,-5l1 0 0 0 0 0 18 -6 2 -1 2 -1 4 -1 12 -7 0 0 3 -2 1 0 5 -4 0 0 5 -3 0 -1 3 -2 0 0 3 -2 0 0 1 -1 0 0 3 -2 0 0 3 -3 1 -1 0 -1 2 -1 0 0 5 -5 0 -1 2 -1 0 0 2 -3 2 -2 0 0 2 -3 0 0 1 -1 0 0 2 -3 0 0 2 -3 1 0 1 -1 342 0 0 23c-51,218 -242,380 -469,380l0 0 -3767 0 0 -332 0 -4 0 -67z"/>
<polygon class="fil6" points="327,4031 0,4206 0,4035 0,4031 0,3870 325,3695 327,3695 "/>
<path class="fil7" d="M4160 4158l-299 -160 3 -2 0 0 1 -1 0 0 3 -2 0 0 3 -3 1 -1 0 -1 2 -1 0 0 5 -5 0 -1 2 -1 0 0 2 -3 2 -2 0 0 2 -3 0 0 1 -1 0 0 2 -3 0 0 2 -3 1 0 3 -5 0 0 4 -6 0 0 2 -3 0 0 6 -13 1 -1 1 -2 0 -1 1 -2 0 -1 1 -1 6 -19c0,0 5,-27 5,-40l0 0 0 -175 327 174 0 1c-1,107 -34,206 -90,287z"/>
<polygon class="fil8" points="1584,1680 327,1680 327,1344 1584,1344 "/>
<polygon class="fil9" points="949,1680 327,1346 327,1344 960,1344 1584,1678 1584,1680 "/>
<polygon class="fil8" points="2665,1680 3923,1680 3923,1344 2665,1344 "/>
<polygon class="fil10" points="3300,1680 3923,1346 3923,1344 3289,1344 2665,1678 2665,1680 "/>
<polygon class="fil8" points="2665,2688 3923,2688 3923,3024 2665,3024 "/>
<polygon class="fil11" points="3300,2688 3923,3021 3923,3024 3289,3024 2665,2689 2665,2688 "/>
<polygon class="fil8" points="1584,2688 327,2688 327,3024 1584,3024 "/>
<polygon class="fil12" points="949,2688 327,3021 327,3024 960,3024 1584,2689 1584,2688 "/>
<polygon class="fil13" points="1584,1680 0,832 0,496 1584,1344 "/>
<polygon class="fil14" points="2665,1680 4250,832 4250,496 2665,1344 "/>
<polygon class="fil5" points="3602,3695 660,3695 660,3360 3602,3360 "/>
<polygon class="fil15" points="2665,2688 4250,3535 4250,3871 2665,3024 "/>
<polygon class="fil16" points="1584,2688 0,3535 0,3871 1584,3024 "/>
<polygon class="fil1" points="4250,2016 3293,2016 3595,1854 3595,1518 2665,2016 2665,2016 2665,2016 2665,2351 2665,2352 2665,2352 2666,2352 3596,2849 3596,2513 3294,2352 4250,2352 "/>
<polygon class="fil1" points="654,1518 654,1854 957,2016 0,2016 0,2352 956,2352 654,2513 654,2849 1584,2352 1584,2352 1584,2352 1584,2351 1584,2016 1584,2016 1584,2016 "/>
</g>
<svg width="100%" height="100%" viewBox="0 0 1200 359" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(4.16667,0,0,4.16667,0,0)">
<path d="M18.602,0.961L18.602,19.563L66.437,19.563L66.437,67.398L85.039,67.398L85.039,27.536L58.464,0.961L18.602,0.961Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M66.437,86L66.437,67.398L18.602,67.398L18.602,19.563L0,19.563L0,59.426L26.574,86L66.437,86Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M105.6,69.491C104.445,69.128 103.467,68.564 103.467,67.338C103.467,65.828 104.61,64.875 106.54,64.875C107.53,64.875 108.38,65.073 109.079,65.345L108.971,66.317C108.298,66.005 107.39,65.828 106.628,65.828C105.366,65.828 104.579,66.323 104.579,67.243C104.579,68.145 105.333,68.348 106.089,68.595L107.441,69.027C108.85,69.491 109.51,70.106 109.51,71.281C109.51,72.759 108.298,73.749 106.407,73.749C105.391,73.749 104.198,73.515 103.449,73.16L103.55,72.169C104.287,72.518 105.422,72.791 106.324,72.791C107.581,72.791 108.418,72.251 108.418,71.312C108.418,70.62 108.038,70.258 107.054,69.948L105.6,69.491Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M115.705,70.118C115.634,69.077 114.917,68.341 113.755,68.341C112.607,68.341 111.762,69.077 111.667,70.118L115.705,70.118ZM116.352,73.153C115.641,73.566 114.873,73.749 114.054,73.749C112.003,73.749 110.588,72.454 110.588,70.576C110.588,68.76 111.896,67.402 113.724,67.402C115.787,67.402 116.955,69.072 116.624,70.944L111.642,70.944C111.813,72.144 112.829,72.804 114.009,72.804C114.72,72.804 115.355,72.683 116.174,72.239L116.352,73.153Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M121.212,67.402C122.038,67.402 122.743,67.643 123.04,67.808L122.933,68.716C122.527,68.519 121.917,68.348 121.212,68.348C119.785,68.348 118.807,69.243 118.807,70.557C118.807,71.883 119.79,72.804 121.225,72.804C121.841,72.804 122.533,72.645 122.984,72.416L123.149,73.337C122.609,73.578 121.898,73.749 121.225,73.749C119.181,73.749 117.785,72.454 117.785,70.557C117.785,68.684 119.175,67.402 121.212,67.402Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M129.044,67.529L130.039,67.529L130.039,71.147C130.039,72.677 128.961,73.749 127.28,73.749C125.597,73.749 124.518,72.69 124.518,71.185L124.518,67.529L125.521,67.529L125.521,71.001C125.521,72.144 126.226,72.804 127.28,72.804C128.339,72.804 129.044,72.144 129.044,71.001L129.044,67.529Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M133.003,68.43C133.346,67.726 133.95,67.402 134.648,67.402C135.08,67.402 135.397,67.51 135.511,67.561L135.41,68.493C135.238,68.43 135.003,68.341 134.61,68.341C133.797,68.341 133.003,68.874 133.003,70.24L133.003,73.622L131.988,73.622L131.988,67.529L133.003,67.529L133.003,68.43Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M136.753,67.529L137.762,67.529L137.762,73.622L136.753,73.622L136.753,67.529ZM136.632,65.485C136.632,65.117 136.886,64.863 137.254,64.863C137.623,64.863 137.889,65.117 137.889,65.485C137.889,65.853 137.623,66.114 137.254,66.114C136.886,66.114 136.632,65.853 136.632,65.485Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M145.429,69.915L145.429,73.622L144.426,73.622L144.426,70.163C144.426,68.976 143.804,68.354 142.7,68.354C141.659,68.354 140.814,69.072 140.814,70.182L140.814,73.622L139.805,73.622L139.805,67.529L140.821,67.529L140.821,68.443C141.164,67.878 141.887,67.402 142.858,67.402C144.464,67.402 145.429,68.348 145.429,69.915Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M147.928,70.557C147.928,71.82 148.83,72.835 150.099,72.835C151.401,72.835 152.359,71.82 152.359,70.557C152.359,69.3 151.401,68.316 150.099,68.316C148.83,68.316 147.928,69.3 147.928,70.557ZM149.998,73.749C148.252,73.749 146.925,72.391 146.925,70.557C146.925,68.729 148.252,67.402 149.998,67.402C151.089,67.402 151.889,67.871 152.346,68.526L152.346,67.529L153.356,67.529L153.356,73.216C153.356,74.988 152.143,76.288 149.909,76.288C149.154,76.288 148.151,76.118 147.509,75.781L147.668,74.861C148.347,75.197 149.154,75.374 149.903,75.374C151.318,75.374 152.346,74.658 152.346,73.292L152.346,72.619C151.902,73.261 151.089,73.749 149.998,73.749Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M164.023,69.915L164.023,73.622L163.02,73.622L163.02,70.163C163.02,68.976 162.398,68.354 161.293,68.354C160.252,68.354 159.409,69.072 159.409,70.182L159.409,73.622L158.399,73.622L158.399,67.529L159.415,67.529L159.415,68.443C159.757,67.878 160.481,67.402 161.453,67.402C163.058,67.402 164.023,68.348 164.023,69.915Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M170.629,70.118C170.56,69.077 169.842,68.341 168.681,68.341C167.532,68.341 166.688,69.077 166.592,70.118L170.629,70.118ZM171.277,73.153C170.566,73.566 169.798,73.749 168.979,73.749C166.929,73.749 165.513,72.454 165.513,70.576C165.513,68.76 166.821,67.402 168.649,67.402C170.712,67.402 171.88,69.072 171.55,70.944L166.567,70.944C166.739,72.144 167.754,72.804 168.935,72.804C169.646,72.804 170.281,72.683 171.099,72.239L171.277,73.153Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M174.456,68.399L174.456,71.693C174.456,72.493 174.887,72.842 175.509,72.842C175.839,72.842 176.258,72.779 176.55,72.67L176.684,73.54C176.423,73.655 175.897,73.749 175.402,73.749C174.227,73.749 173.447,73.102 173.447,71.858L173.447,68.399L172.323,68.399L172.323,67.529L173.453,67.529L173.453,65.574L174.45,65.574L174.45,67.529L176.398,67.529L176.398,68.399L174.456,68.399Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M182.42,67.592L184.071,72.664L185.588,67.529L186.655,67.529L184.756,73.622L183.405,73.622L181.887,69.001L180.371,73.622L179.018,73.622L177.114,67.529L178.187,67.529L179.698,72.658L181.348,67.592L182.42,67.592Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M190.614,72.81C191.896,72.81 192.841,71.832 192.841,70.576C192.841,69.319 191.896,68.341 190.614,68.341C189.332,68.341 188.385,69.319 188.385,70.576C188.385,71.832 189.332,72.81 190.614,72.81ZM190.614,67.402C192.467,67.402 193.851,68.792 193.851,70.576C193.851,72.36 192.467,73.749 190.614,73.749C188.76,73.749 187.376,72.36 187.376,70.576C187.376,68.792 188.76,67.402 190.614,67.402Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M196.433,68.43C196.776,67.726 197.378,67.402 198.077,67.402C198.508,67.402 198.826,67.51 198.94,67.561L198.838,68.493C198.667,68.43 198.432,68.341 198.039,68.341C197.226,68.341 196.433,68.874 196.433,70.24L196.433,73.622L195.417,73.622L195.417,67.529L196.433,67.529L196.433,68.43Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M200.183,64.685L201.192,64.685L201.192,70.036L202.494,70.036L204.131,67.529L205.254,67.529L203.281,70.499L205.572,73.622L204.391,73.622L202.43,70.906L201.192,70.906L201.192,73.622L200.183,73.622L200.183,64.685Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M209.169,70.189C210.382,70.43 211.023,70.976 211.023,71.928C211.023,73.115 210.078,73.749 208.598,73.749C207.735,73.749 206.884,73.578 206.313,73.292L206.453,72.391C207.011,72.677 207.792,72.848 208.529,72.848C209.506,72.848 210.033,72.543 210.033,71.979C210.033,71.433 209.563,71.204 208.707,71.039L207.913,70.88C206.904,70.684 206.256,70.151 206.256,69.211C206.256,68.125 207.214,67.402 208.732,67.402C209.468,67.402 210.21,67.541 210.687,67.739L210.56,68.62C210.065,68.424 209.392,68.297 208.795,68.297C207.805,68.297 207.259,68.627 207.259,69.186C207.259,69.712 207.678,69.897 208.535,70.062L209.169,70.189Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M225.538,69.897L225.538,73.622L224.528,73.622L224.528,70.144C224.528,69.021 223.906,68.354 222.846,68.354C221.856,68.354 221.037,69.046 221.037,70.125L221.037,73.622L220.028,73.622L220.028,70.144C220.028,69.021 219.406,68.354 218.383,68.354C217.362,68.354 216.549,69.059 216.549,70.163L216.549,73.622L215.54,73.622L215.54,67.529L216.549,67.529L216.549,68.437C216.885,67.871 217.596,67.402 218.548,67.402C219.627,67.402 220.409,67.884 220.777,68.684C221.189,67.891 222.014,67.402 223.004,67.402C224.591,67.402 225.538,68.405 225.538,69.897Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M228.037,70.557C228.037,71.82 228.938,72.835 230.207,72.835C231.509,72.835 232.467,71.82 232.467,70.557C232.467,69.3 231.509,68.316 230.207,68.316C228.938,68.316 228.037,69.3 228.037,70.557ZM233.464,73.622L232.455,73.622L232.455,72.619C231.998,73.274 231.198,73.749 230.106,73.749C228.361,73.749 227.034,72.391 227.034,70.557C227.034,68.729 228.361,67.402 230.106,67.402C231.198,67.402 231.998,67.871 232.455,68.526L232.455,67.529L233.464,67.529L233.464,73.622Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M240.477,70.563C240.477,69.3 239.518,68.316 238.217,68.316C236.948,68.316 236.046,69.3 236.046,70.563C236.046,71.82 236.948,72.835 238.217,72.835C239.518,72.835 240.477,71.82 240.477,70.563ZM240.464,72.632C240.007,73.28 239.207,73.749 238.116,73.749C236.37,73.749 235.043,72.391 235.043,70.563C235.043,68.735 236.37,67.402 238.116,67.402C239.207,67.402 240.007,67.878 240.464,68.532L240.464,64.685L241.473,64.685L241.473,73.622L240.464,73.622L240.464,72.632Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M248.162,70.118C248.092,69.077 247.374,68.341 246.213,68.341C245.064,68.341 244.22,69.077 244.124,70.118L248.162,70.118ZM248.809,73.153C248.098,73.566 247.331,73.749 246.511,73.749C244.461,73.749 243.045,72.454 243.045,70.576C243.045,68.76 244.353,67.402 246.181,67.402C248.245,67.402 249.413,69.072 249.082,70.944L244.099,70.944C244.271,72.144 245.287,72.804 246.467,72.804C247.178,72.804 247.813,72.683 248.631,72.239L248.809,73.153Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M258.359,70.118C258.29,69.077 257.573,68.341 256.411,68.341C255.262,68.341 254.417,69.077 254.323,70.118L258.359,70.118ZM259.006,73.153C258.295,73.566 257.528,73.749 256.709,73.749C254.659,73.749 253.244,72.454 253.244,70.576C253.244,68.76 254.551,67.402 256.379,67.402C258.441,67.402 259.609,69.072 259.28,70.944L254.297,70.944C254.468,72.144 255.484,72.804 256.665,72.804C257.375,72.804 258.01,72.683 258.829,72.239L259.006,73.153Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M261.45,70.557C261.45,71.82 262.351,72.835 263.621,72.835C264.921,72.835 265.88,71.82 265.88,70.557C265.88,69.3 264.921,68.316 263.621,68.316C262.351,68.316 261.45,69.3 261.45,70.557ZM266.876,73.622L265.868,73.622L265.868,72.619C265.411,73.274 264.611,73.749 263.519,73.749C261.773,73.749 260.446,72.391 260.446,70.557C260.446,68.729 261.773,67.402 263.519,67.402C264.611,67.402 265.411,67.871 265.868,68.526L265.868,67.529L266.876,67.529L266.876,73.622Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M271.37,70.189C272.582,70.43 273.223,70.976 273.223,71.928C273.223,73.115 272.277,73.749 270.798,73.749C269.935,73.749 269.084,73.578 268.513,73.292L268.653,72.391C269.211,72.677 269.992,72.848 270.728,72.848C271.706,72.848 272.233,72.543 272.233,71.979C272.233,71.433 271.763,71.204 270.906,71.039L270.113,70.88C269.103,70.684 268.456,70.151 268.456,69.211C268.456,68.125 269.415,67.402 270.931,67.402C271.667,67.402 272.411,67.541 272.886,67.739L272.759,68.62C272.264,68.424 271.591,68.297 270.995,68.297C270.004,68.297 269.458,68.627 269.458,69.186C269.458,69.712 269.877,69.897 270.735,70.062L271.37,70.189Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M278.992,67.529L280.102,67.529L277.227,74.397C276.707,75.61 276.135,76.288 274.904,76.288C274.415,76.288 274.034,76.168 273.863,76.079L273.983,75.222C274.193,75.318 274.529,75.387 274.846,75.387C275.539,75.387 275.951,74.95 276.306,74.079L276.415,73.794L273.78,67.529L274.878,67.529L276.954,72.632L278.992,67.529Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
<path d="M140.024,37.345L140.024,43.579L144.106,43.579C146.277,43.579 147.668,42.503 147.668,40.462C147.668,38.309 146.351,37.345 144.106,37.345L140.024,37.345ZM140.024,49.665L140.024,56.437L132.621,56.437L132.621,31.24L145.368,31.24C151.658,31.24 155.183,35.229 155.183,40.313C155.183,45.453 151.658,49.665 145.368,49.665L140.024,49.665Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M164.994,56.437L157.794,56.437L157.794,31.24L163.825,31.24L175.31,44.692L175.31,31.24L182.509,31.24L182.509,56.437L176.739,56.437L164.994,43.134L164.994,56.437Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M195.603,45.527C199.332,46.177 200.854,47.809 200.854,50.927C200.854,54.601 197.848,56.809 192.82,56.809C190.074,56.809 187.309,56.4 185.398,55.732L186.047,50.389C187.272,50.815 189.74,51.446 192.003,51.446C193.488,51.446 194.36,51.279 194.36,50.834C194.36,50.426 193.729,50.296 192.133,50.073L190.964,49.906C186.938,49.331 185.12,47.754 185.12,44.358C185.12,40.536 188.33,38.254 193.673,38.254C195.974,38.254 198.683,38.718 199.926,39.182L199.24,44.6C198.331,44.21 195.918,43.765 194.249,43.765C192.337,43.765 191.484,43.987 191.484,44.488C191.484,44.896 192.263,44.952 194.434,45.323L195.603,45.527Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M214.468,45.713C214.468,44.655 213.578,43.431 212.093,43.431C210.405,43.431 209.551,44.544 209.44,45.713L214.468,45.713ZM220.294,55.25C219.033,55.955 216.435,56.809 213.411,56.809C206.675,56.809 202.779,53.098 202.779,47.494C202.779,41.909 206.527,38.254 212.186,38.254C217.827,38.254 221.872,41.668 220.74,49.09L209.44,49.09C209.57,50.463 211.555,51.279 213.745,51.279C216.101,51.279 218.346,50.76 219.497,50.203L220.294,55.25Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M242.054,44.488L242.054,56.437L234.929,56.437L234.929,46.603C234.929,45.342 234.039,44.47 232.758,44.47C231.478,44.47 230.606,45.342 230.606,46.603L230.606,56.437L223.481,56.437L223.481,38.625L229.975,38.625L230.142,40.332C231.144,39.107 233.129,38.254 235.671,38.254C239.457,38.254 242.054,40.777 242.054,44.488Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M254.999,45.527C258.729,46.177 260.25,47.809 260.25,50.927C260.25,54.601 257.245,56.809 252.216,56.809C249.47,56.809 246.706,56.4 244.794,55.732L245.444,50.389C246.668,50.815 249.136,51.446 251.4,51.446C252.884,51.446 253.756,51.279 253.756,50.834C253.756,50.426 253.125,50.296 251.53,50.073L250.361,49.906C246.334,49.331 244.516,47.754 244.516,44.358C244.516,40.536 247.726,38.254 253.07,38.254C255.371,38.254 258.079,38.718 259.323,39.182L258.635,44.6C257.726,44.21 255.315,43.765 253.645,43.765C251.734,43.765 250.88,43.987 250.88,44.488C250.88,44.896 251.66,44.952 253.831,45.323L254.999,45.527Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M273.865,45.713C273.865,44.655 272.974,43.431 271.49,43.431C269.801,43.431 268.948,44.544 268.836,45.713L273.865,45.713ZM279.691,55.25C278.429,55.955 275.832,56.809 272.807,56.809C266.072,56.809 262.175,53.098 262.175,47.494C262.175,41.909 265.923,38.254 271.582,38.254C277.223,38.254 281.268,41.668 280.136,49.09L268.836,49.09C268.966,50.463 270.952,51.279 273.141,51.279C275.498,51.279 277.743,50.76 278.893,50.203L279.691,55.25Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M283.51,32.01L283.51,33.063L284.174,33.063C284.519,33.063 284.731,32.827 284.731,32.533C284.731,32.216 284.505,32.01 284.174,32.01L283.51,32.01ZM283.51,35.029L282.543,35.029L282.543,31.141L284.308,31.141C285.112,31.141 285.733,31.708 285.733,32.533C285.733,33.033 285.458,33.49 285.063,33.733L286.016,35.029L284.865,35.029L284.068,33.924L283.51,33.924L283.51,35.029ZM284.145,35.949C285.747,35.949 287.046,34.815 287.046,33.107C287.046,31.435 285.719,30.25 284.145,30.25C282.564,30.25 281.308,31.435 281.308,33.107C281.308,34.815 282.55,35.949 284.145,35.949ZM284.145,29.308C286.206,29.308 287.978,30.957 287.978,33.107C287.978,35.345 286.298,36.921 284.145,36.921C282.099,36.921 280.362,35.367 280.362,33.107C280.369,30.913 282.056,29.308 284.145,29.308Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
<path d="M116.372,50.222C112.753,50.222 110.323,47.624 110.323,43.82C110.323,40.072 112.753,37.512 116.372,37.512C119.915,37.512 122.272,40.072 122.272,43.82C122.272,47.624 119.915,50.222 116.372,50.222ZM116.334,30.869C115.277,30.869 114.267,30.968 113.303,31.146L113.303,38.254L103.958,38.254C103.23,39.902 102.827,41.766 102.827,43.802C102.827,51.465 108.337,56.809 116.334,56.809C124.294,56.809 129.768,51.483 129.768,43.82C129.768,36.194 124.294,30.869 116.334,30.869Z" style="fill:rgb(64,63,65);fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,84 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 95 98" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M94.747,9.011L87.457,9.011L87.457,7.495L10.768,7.495C10.456,7.495 10.21,7.539 9.898,7.606L9.876,7.606L9.497,7.74L9.43,7.762L9.386,7.785L9.319,7.829L9.029,7.985L8.962,8.007L8.962,8.03L8.828,8.097L8.717,8.186L8.672,8.23L8.605,8.275L8.561,8.297L8.561,8.32L8.516,8.364L8.449,8.409L8.405,8.453L8.36,8.498L8.249,8.609L8.226,8.654L8.159,8.721L8.115,8.743L8.137,8.743L8.07,8.81L8.048,8.832L8.048,8.855L8.003,8.899L8.003,8.922L7.959,8.966L7.936,9.011L0.29,9.011L0.29,8.498C1.427,3.638 5.707,0.004 10.768,0.004L94.747,0.004L94.747,9.011Z" style="fill:rgb(227,228,229);fill-rule:nonzero;"/>
<svg width="100%" height="100%" viewBox="0 0 355 355" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(4.16667,0,0,4.16667,0,-4.00417)">
<path d="M18.602,0.961L18.602,19.563L66.437,19.563L66.437,67.398L85.039,67.398L85.039,27.536L58.464,0.961L18.602,0.961Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M87.457,7.517L94.747,3.593L94.747,11.084L87.479,14.985L87.457,14.985L87.457,7.517Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
<g transform="matrix(4.16667,0,0,4.16667,0,-4.00417)">
<path d="M66.437,86L66.437,67.398L18.602,67.398L18.602,19.563L0,19.563L0,59.426L26.574,86L66.437,86Z" style="fill:rgb(228,74,32);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M2.006,4.663L8.672,8.23L8.605,8.275L8.561,8.297L8.561,8.32L8.516,8.364L8.449,8.409L8.405,8.453L8.36,8.498L8.249,8.609L8.226,8.654L8.159,8.721L8.115,8.743L8.137,8.743L8.07,8.81L8.048,8.832L8.048,8.855L8.003,8.899L8.003,8.922L7.959,8.966L7.892,9.078L7.87,9.1L7.803,9.211L7.758,9.278L7.758,9.3L7.602,9.568L7.602,9.59L7.58,9.657L7.557,9.702L7.535,9.746L7.535,9.769L7.401,10.192C7.401,10.17 7.29,10.772 7.29,11.062L7.29,14.985L0,11.084L0,11.062C0,8.676 0.736,6.469 2.006,4.663Z" style="fill:url(#_Linear2);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="14.58" y="14.985" width="65.587" height="7.491" style="fill:rgb(147,146,146);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M0,88.375L7.29,88.375L7.29,89.869L83.979,89.869C84.291,89.869 84.537,89.847 84.826,89.757L84.849,89.757L85.25,89.624L85.295,89.601L85.339,89.579L85.428,89.557L85.696,89.401L85.763,89.356L85.785,89.356L85.896,89.267L86.008,89.2L86.008,89.178L86.075,89.133L86.142,89.089L86.164,89.066L86.231,89.022L86.298,88.955L86.32,88.933L86.32,88.91L86.365,88.888L86.476,88.776L86.476,88.754L86.521,88.732L86.565,88.665L86.61,88.62L86.654,88.554L86.677,88.531L86.721,88.464L86.766,88.397L86.788,88.397L86.81,88.375L94.435,88.375L94.435,88.888C93.298,93.748 89.04,97.359 83.979,97.359L0,97.359L0,89.958L0,89.869L0,88.375Z" style="fill:rgb(227,228,229);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M7.29,89.869L0,93.77L0,89.958L0,89.869L0,86.28L7.245,82.378L7.29,82.378L7.29,89.869Z" style="fill:url(#_Linear3);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M92.741,92.7L86.075,89.133L86.142,89.089L86.164,89.066L86.231,89.022L86.298,88.955L86.32,88.933L86.32,88.91L86.365,88.888L86.476,88.776L86.476,88.754L86.521,88.732L86.565,88.665L86.61,88.62L86.654,88.554L86.677,88.531L86.721,88.464L86.766,88.397L86.788,88.397L86.855,88.286L86.944,88.152L86.989,88.085L87.123,87.796L87.145,87.773L87.167,87.729L87.167,87.706L87.189,87.662L87.189,87.639L87.212,87.617L87.346,87.194C87.346,87.194 87.457,86.592 87.457,86.302L87.457,82.401L94.747,86.28L94.747,86.302C94.725,88.687 93.989,90.894 92.741,92.7Z" style="fill:url(#_Linear4);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="7.29" y="29.966" width="28.023" height="7.491" style="fill:rgb(170,171,171);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M21.156,37.457L7.29,30.011L7.29,29.966L21.402,29.966L35.313,37.412L35.313,37.457L21.156,37.457Z" style="fill:url(#_Linear5);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="59.412" y="29.966" width="28.045" height="7.491" style="fill:rgb(170,171,171);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M73.568,37.457L87.457,30.011L87.457,29.966L73.323,29.966L59.412,37.412L59.412,37.457L73.568,37.457Z" style="fill:url(#_Linear6);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="59.412" y="59.929" width="28.045" height="7.491" style="fill:rgb(170,171,171);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M73.568,59.929L87.457,67.352L87.457,67.419L73.323,67.419L59.412,59.951L59.412,59.929L73.568,59.929Z" style="fill:url(#_Linear7);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="7.29" y="59.929" width="28.023" height="7.491" style="fill:rgb(170,171,171);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M21.156,59.929L7.29,67.352L7.29,67.419L21.402,67.419L35.313,59.951L35.313,59.929L21.156,59.929Z" style="fill:url(#_Linear8);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M35.313,37.457L0,18.552L0,11.062L35.313,29.966L35.313,37.457Z" style="fill:url(#_Linear9);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M59.412,37.457L94.747,18.552L94.747,11.062L59.412,29.966L59.412,37.457Z" style="fill:url(#_Linear10);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<rect x="14.714" y="74.91" width="65.587" height="7.468" style="fill:rgb(147,146,146);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M59.412,59.929L94.747,78.811L94.747,86.302L59.412,67.419L59.412,59.929Z" style="fill:url(#_Linear11);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M35.313,59.929L0,78.811L0,86.302L35.313,67.419L35.313,59.929Z" style="fill:url(#_Linear12);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M94.747,44.948L73.412,44.948L80.145,41.336L80.145,33.846L59.412,44.948L59.412,52.438L59.434,52.438L80.167,63.518L80.167,56.027L73.434,52.438L94.747,52.438L94.747,44.948Z" style="fill:rgb(217,79,0);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,0,-0.00415471)">
<path d="M14.58,33.846L14.58,41.336L21.335,44.948L0,44.948L0,52.438L21.312,52.438L14.58,56.027L14.58,63.518L35.313,52.438L35.313,52.416L35.313,44.948L14.58,33.846Z" style="fill:rgb(217,79,0);fill-rule:nonzero;"/>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.65841,5.84056,-5.84056,1.65841,90.2635,6.36912)"><stop offset="0" style="stop-color:rgb(228,228,228);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(162,162,162);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-2.29154,5.81958,-5.81958,-2.29154,5.47686,6.9145)"><stop offset="0" style="stop-color:rgb(228,228,228);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(162,162,162);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-1.65885,-5.83931,5.83931,-1.65885,4.4731,91.0027)"><stop offset="0" style="stop-color:rgb(228,228,228);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(162,162,162);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.29131,-5.81924,5.81924,2.29131,89.2594,90.4576)"><stop offset="0" style="stop-color:rgb(228,228,228);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(162,162,162);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-46.185,-12.0168,12.0168,-46.185,44.3937,39.7156)"><stop offset="0" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="0.1" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(78,78,78);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(46.1861,-12.0159,12.0159,46.1861,50.342,39.7152)"><stop offset="0" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="0.1" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(78,78,78);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear7" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(46.1854,12.0159,-12.0159,46.1854,50.3425,57.6569)"><stop offset="0" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="0.1" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(78,78,78);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear8" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-46.1844,12.0166,-12.0166,-46.1844,44.3935,57.6564)"><stop offset="0" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="0.1" style="stop-color:rgb(170,171,171);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(78,78,78);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear9" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(35.3155,0,0,35.3155,-0.000283467,24.2587)"><stop offset="0" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="0.23" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(176,176,176);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear10" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-35.3154,4.32489e-15,-4.32489e-15,-35.3154,94.736,24.2587)"><stop offset="0" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="0.23" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(176,176,176);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear11" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-35.3154,4.32489e-15,-4.32489e-15,-35.3154,94.736,73.1133)"><stop offset="0" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="0.23" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(176,176,176);stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear12" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(35.3155,0,0,35.3155,-0.000283467,73.1133)"><stop offset="0" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="0.23" style="stop-color:rgb(254,254,254);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(176,176,176);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 925 B

View file

@ -1,5 +1,5 @@
PLUGIN_NAME= theme-cicada
PLUGIN_VERSION= 1.38
PLUGIN_VERSION= 1.40
PLUGIN_COMMENT= The cicada theme - dark grey onyx
PLUGIN_MAINTAINER= rene@team-rebellion.net
PLUGIN_NO_ABI= yes

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