mirror of
https://github.com/coolsnowwolf/packages.git
synced 2025-05-01 06:30:21 +08:00
update nginx-util to 1.5-1
use UCI for server configuration
This commit is contained in:
parent
374a1e85da
commit
204bc8f478
@ -1,7 +1,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=nginx-util
|
PKG_NAME:=nginx-util
|
||||||
PKG_VERSION:=1.4
|
PKG_VERSION:=1.5
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
|
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
|
||||||
|
|
||||||
@ -12,26 +12,17 @@ CMAKE_OPTIONS+= -DUBUS=y
|
|||||||
CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION)
|
CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION)
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/default
|
define Package/nginx-ssl-util/default
|
||||||
SECTION:=net
|
SECTION:=net
|
||||||
CATEGORY:=Network
|
CATEGORY:=Network
|
||||||
SUBMENU:=Web Servers/Proxies
|
SUBMENU:=Web Servers/Proxies
|
||||||
TITLE:=Nginx configurator
|
TITLE:=Nginx configurator including SSL
|
||||||
DEPENDS:=+libstdcpp +libubus +libubox +libpthread
|
DEPENDS:=+libstdcpp +libuci +libubus +libubox +libpthread +libopenssl
|
||||||
endef
|
# TODO: remove after a transition period (together with below and pkg nginx):
|
||||||
|
# It actually removes nginx-util (replacing it by a dummy pkg) to avoid
|
||||||
|
# conflicts with nginx-ssl-util*
|
||||||
define Package/nginx-util
|
DEPENDS+= +nginx-util
|
||||||
$(Package/nginx-util/default)
|
EXTRA_DEPENDS:=nginx-util (>=1.4-2)
|
||||||
CONFLICTS:=nginx-ssl-util-nopcre nginx-ssl-util
|
|
||||||
endef
|
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util/default
|
|
||||||
$(Package/nginx-util/default)
|
|
||||||
TITLE+= including SSL
|
|
||||||
DEPENDS+= +libopenssl
|
|
||||||
CONFLICTS:=nginx-util,
|
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
@ -39,25 +30,22 @@ define Package/nginx-ssl-util
|
|||||||
$(Package/nginx-ssl-util/default)
|
$(Package/nginx-ssl-util/default)
|
||||||
TITLE+= (using PCRE)
|
TITLE+= (using PCRE)
|
||||||
DEPENDS+= +libpcre
|
DEPENDS+= +libpcre
|
||||||
CONFLICTS+= nginx-ssl-util-nopcre,
|
CONFLICTS:=nginx-ssl-util-nopcre,
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util-nopcre
|
define Package/nginx-ssl-util-nopcre
|
||||||
$(Package/nginx-ssl-util/default)
|
$(Package/nginx-ssl-util/default)
|
||||||
TITLE+= (using <regex>)
|
TITLE+= (using <regex>)
|
||||||
CONFLICTS+= nginx-ssl-util
|
CONFLICTS:=nginx-ssl-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/description
|
define Package/nginx-ssl-util/default/description
|
||||||
Utility that builds dynamically LAN listen directives for Nginx.
|
Utility that builds dynamically LAN listen directives for Nginx.
|
||||||
endef
|
Furthermore, it manages SSL directives for its server parts and can create
|
||||||
|
|
||||||
|
|
||||||
Package/nginx-ssl-util/default/description = $(Package/nginx-util/description)\
|
|
||||||
Furthermore, it manages SSL directives for its server parts and can create \
|
|
||||||
corresponding (self-signed) certificates.
|
corresponding (self-signed) certificates.
|
||||||
|
endef
|
||||||
|
|
||||||
|
|
||||||
Package/nginx-ssl-util/description = \
|
Package/nginx-ssl-util/description = \
|
||||||
@ -70,25 +58,78 @@ Package/nginx-ssl-util-nopcre/description = \
|
|||||||
It uses the standard regex library of C++.
|
It uses the standard regex library of C++.
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-util/install
|
define Package/nginx-ssl-util/install/default
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/etc/nginx/conf.d/
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-util $(1)/usr/bin/nginx-util
|
|
||||||
|
$(INSTALL_CONF) ./files/uci.conf.template $(1)/etc/nginx/
|
||||||
|
$(LN) /var/lib/nginx/uci.conf $(1)/etc/nginx/uci.conf
|
||||||
|
|
||||||
|
$(INSTALL_CONF) ./files/restrict_locally $(1)/etc/nginx/
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/etc/config/
|
||||||
|
$(INSTALL_CONF) ./files/nginx.config $(1)/etc/config/nginx
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_IPV6),y) # the used IPv6 directives have `::` in them:
|
||||||
|
$(SED) "/::/d" $(1)/etc/nginx/restrict_locally
|
||||||
|
$(SED) "/::/d" $(1)/etc/config/nginx
|
||||||
|
endif
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util/install
|
define Package/nginx-ssl-util/install
|
||||||
|
$(call Package/nginx-ssl-util/install/default, $(1))
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util $(1)/usr/bin/nginx-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
define Package/nginx-ssl-util-nopcre/install
|
define Package/nginx-ssl-util-nopcre/install
|
||||||
|
$(call Package/nginx-ssl-util/install/default, $(1))
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \
|
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nginx-ssl-util-nopcre \
|
||||||
$(1)/usr/bin/nginx-util
|
$(1)/usr/bin/nginx-util
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
$(eval $(call BuildPackage,nginx-util))
|
define Package/nginx-ssl-util/prerm
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
[ -n "$${IPKG_INSTROOT}" ] && exit 0
|
||||||
|
[ "$${PKG_UPGRADE}" = "1" ] && exit 0
|
||||||
|
case "$$(/sbin/uci get "nginx.global.uci_enable" 2>/dev/null)" in
|
||||||
|
1|on|true|yes|enabled) ;;
|
||||||
|
*) exit 0;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
eval "$$(/usr/bin/nginx-util get_env)" &&
|
||||||
|
[ "$$(/sbin/uci get "nginx.$${LAN_NAME}.$${MANAGE_SSL}" 2>/dev/null)" = \
|
||||||
|
"self-signed" ] &&
|
||||||
|
cd "/etc/nginx" &&
|
||||||
|
rm -f "$$(/sbin/uci get "nginx.$${LAN_NAME}.ssl_certificate")" \
|
||||||
|
"$$(/sbin/uci get "nginx.$${LAN_NAME}.ssl_certificate_key")"
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
endef
|
||||||
|
|
||||||
|
|
||||||
|
Package/nginx-ssl-util-nopcre/prerm = $(Package/nginx-ssl-util/prerm)
|
||||||
|
|
||||||
|
|
||||||
$(eval $(call BuildPackage,nginx-ssl-util))
|
$(eval $(call BuildPackage,nginx-ssl-util))
|
||||||
$(eval $(call BuildPackage,nginx-ssl-util-nopcre))
|
$(eval $(call BuildPackage,nginx-ssl-util-nopcre))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: remove after a transition period (together with above and pkg nginx):
|
||||||
|
# It replaces nginx-util by a dummy pkg for a smooth upgrade of nginx*
|
||||||
|
|
||||||
|
define Package/nginx-util
|
||||||
|
TITLE:=Dummy package for removing nginx-util when upgrading.
|
||||||
|
DEPENDS:=+libstdcpp +libubus +libubox +libpthread
|
||||||
|
PKGARCH:=all
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/nginx-util/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,nginx-util))
|
||||||
|
475
net/nginx-util/files/README.sh
Executable file
475
net/nginx-util/files/README.sh
Executable file
@ -0,0 +1,475 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This is a template copy it by: ./README.sh | xclip -selection c
|
||||||
|
# to https://openwrt.org/docs/guide-user/services/webserver/nginx#configuration
|
||||||
|
|
||||||
|
|
||||||
|
NGINX_UTIL="/usr/bin/nginx-util"
|
||||||
|
|
||||||
|
EXAMPLE_COM="example.com"
|
||||||
|
|
||||||
|
MSG="
|
||||||
|
/* Created by the following bash script that includes the source of some files:
|
||||||
|
* https://github.com/openwrt/packages/net/nginx-util/files/README.sh
|
||||||
|
*/"
|
||||||
|
|
||||||
|
eval $("${NGINX_UTIL}" get_env)
|
||||||
|
|
||||||
|
code() {
|
||||||
|
local file
|
||||||
|
[ $# -gt 1 ] && file="$2" || file="$(basename "$1")"
|
||||||
|
printf "<file nginx %s>\n%s</file>" "$1" "$(cat "${file}")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ifConfEcho() {
|
||||||
|
sed -nE "s/^\s*$1=\s*(\S*)\s*\\\\$/\n$2 \"\1\";/p" ../../nginx/Makefile;
|
||||||
|
}
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
===== Configuration =====${MSG}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The official Documentation contains a
|
||||||
|
[[https://docs.nginx.com/nginx/admin-guide/|Admin Guide]].
|
||||||
|
Here we will look at some often used configuration parts and how we handle them
|
||||||
|
at OpenWrt.
|
||||||
|
At different places there are references to the official
|
||||||
|
[[https://docs.nginx.com/nginx/technical-specs/|Technical Specs]]
|
||||||
|
for further reading.
|
||||||
|
|
||||||
|
**tl;dr:** When starting Nginx by ''/etc/init.d/nginx'', it creates its main
|
||||||
|
configuration dynamically based on a minimal template and the
|
||||||
|
[[docs:guide-user:base-system:uci|🡒UCI]] configuration.
|
||||||
|
|
||||||
|
The UCI ''/etc/config/nginx'' contains initially:
|
||||||
|
| ''config server '${LAN_NAME}''' | \
|
||||||
|
Default server for the LAN, which includes all ''${CONF_DIR}*.locations''. |
|
||||||
|
| ''config server '_redirect2ssl''' | \
|
||||||
|
Redirects inexistent URLs to HTTPS. |
|
||||||
|
|
||||||
|
It enables also the ''${CONF_DIR}'' directory for further configuration:
|
||||||
|
| ''${CONF_DIR}\$NAME.conf'' | \
|
||||||
|
Is included in the main configuration. \
|
||||||
|
It is prioritized over a UCI ''config server '\$NAME' ''. |
|
||||||
|
| ''${CONF_DIR}\$NAME.locations'' | \
|
||||||
|
Is include in the ''${LAN_NAME}'' server and can be re-used for others, too. |
|
||||||
|
| ''$(dirname "${CONF_DIR}")/restrict_locally'' | \
|
||||||
|
Is include in the ''${LAN_NAME}'' server and allows only accesses from LAN. |
|
||||||
|
|
||||||
|
Setup configuration (for a server ''\$NAME''):
|
||||||
|
| ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$NAME'' | \
|
||||||
|
Add/remove a self-signed certificate and corresponding directives. |
|
||||||
|
| ''uci set nginx.\$NAME.access_log='logd openwrt''' | \
|
||||||
|
Writes accesses to Openwrt’s \
|
||||||
|
[[docs:guide-user:base-system:log.essentials|🡒logd]]. |
|
||||||
|
| ''uci set nginx.\$NAME.error_log='logd' '' | \
|
||||||
|
Writes errors to Openwrt’s \
|
||||||
|
[[docs:guide-user:base-system:log.essentials|🡒logd]]. |
|
||||||
|
| ''uci [set|add_list] nginx.\$NAME.key='value' '' | \
|
||||||
|
Becomes a ''key value;'' directive if the //key// does not start with //uci_//. |
|
||||||
|
| ''uci set nginx.\$NAME=[disable|server]'' |\
|
||||||
|
Disable/enable inclusion in the dynamic conf.|
|
||||||
|
| ''uci set nginx.global.uci_enable=false'' | \
|
||||||
|
Use a custom ''${NGINX_CONF}'' rather than a dynamic conf. |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
==== Basic ====${MSG}
|
||||||
|
|
||||||
|
|
||||||
|
We modify the configuration by changing servers saved in the UCI configuration
|
||||||
|
at ''/etc/config/nginx'' and/or by creating different configuration files in the
|
||||||
|
''${CONF_DIR}'' directory.
|
||||||
|
These files use the file extensions ''.locations'' and ''.conf'' plus ''.crt''
|
||||||
|
and ''.key'' for SSL certificates and keys.((
|
||||||
|
We can disable a single configuration file in ''${CONF_DIR}'' by giving it
|
||||||
|
another extension, e.g., by adding ''.disabled''.))
|
||||||
|
For the new configuration to take effect, we must reload it by:
|
||||||
|
|
||||||
|
<code bash>service nginx reload</code>
|
||||||
|
|
||||||
|
For OpenWrt we use a special initial configuration, which is explained in the
|
||||||
|
section [[#openwrt_s_defaults|🡓OpenWrt’s Defaults]].
|
||||||
|
So, we can make a site available at a specific URL in the **LAN** by creating a
|
||||||
|
''.locations'' file in the directory ''${CONF_DIR}''.
|
||||||
|
Such a file consists just of some
|
||||||
|
[[https://nginx.org/en/docs/http/ngx_http_core_module.html#location|
|
||||||
|
location blocks]].
|
||||||
|
Under the latter link, you can find also the official documentation for all
|
||||||
|
available directives of the HTTP core of Nginx.
|
||||||
|
Look for //location// in the Context list.
|
||||||
|
|
||||||
|
The following example provides a simple template, see at the end for
|
||||||
|
different [[#locations_for_apps|🡓Locations for Apps]]((look for
|
||||||
|
[[https://github.com/search?utf8=%E2%9C%93&q=repo%3Aopenwrt%2Fpackages
|
||||||
|
+extension%3Alocations&type=Code&ref=advsearch&l=&l=|
|
||||||
|
other packages using a .locations file]], too.)):
|
||||||
|
|
||||||
|
<code nginx ${CONF_DIR}example.locations>
|
||||||
|
location /ex/am/ple {
|
||||||
|
access_log off; # default: not logging accesses.
|
||||||
|
# access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
|
||||||
|
# error_log stderr; # default: logging to logd (init forwards stderr).
|
||||||
|
error_log /dev/null; # disable error logging after config file is read.
|
||||||
|
# (state path of a file for access_log/error_log to the file instead.)
|
||||||
|
index index.html;
|
||||||
|
}
|
||||||
|
# location /eg/static { … }
|
||||||
|
</code>
|
||||||
|
|
||||||
|
All location blocks in all ''.locations'' files must use different URLs,
|
||||||
|
since they are all included in the ''${LAN_NAME}'' server that is part of the
|
||||||
|
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]].((
|
||||||
|
We reserve the ''location /'' for making LuCI available under the root URL,
|
||||||
|
e.g. [[https://192.168.1.1/|192.168.1.1/]].
|
||||||
|
All other sites shouldn’t use the root ''location /'' without suffix.))
|
||||||
|
We should use the root URL for other sites than LuCI only on **other** domain
|
||||||
|
names, e.g., we could make a site available at https://${EXAMPLE_COM}/.
|
||||||
|
In order to do that, we create [[#new_server_parts|🡓New Server Parts]] for all
|
||||||
|
domain names.
|
||||||
|
We can also activate SSL thereby, see
|
||||||
|
[[#ssl_server_parts|🡓SSL Server Parts]].
|
||||||
|
We use such server parts also for publishing sites to the internet (WAN)
|
||||||
|
instead of making them available just locally (in the LAN).
|
||||||
|
|
||||||
|
Via ''${CONF_DIR}*.conf'' files we can add directives to the //http// part of
|
||||||
|
the configuration.
|
||||||
|
If you would change the configuration ''$(basename "${UCI_CONF}").template''
|
||||||
|
instead, it is not updated to new package's versions anymore.
|
||||||
|
Although it is not recommended, you can also disable the whole UCI config and
|
||||||
|
create your own ''${NGINX_CONF}''; then invoke:
|
||||||
|
|
||||||
|
<code bash>uci set nginx.global.uci_enable=false</code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
==== New Server Parts ====${MSG}
|
||||||
|
|
||||||
|
|
||||||
|
For making the router reachable from the WAN at a registered domain name,
|
||||||
|
it is not enough letting the
|
||||||
|
[[docs:guide-user:firewall:firewall_configuration|🡒firewall]] accept requests
|
||||||
|
(typically on ports 80 and 443) and giving the name server the internet IP
|
||||||
|
address of the router (maybe updated automatically by a
|
||||||
|
[[docs:guide-user:services:ddns:client|🡒DDNS Client]]).
|
||||||
|
|
||||||
|
We also need to set up virtual hosting for this domain name by creating an
|
||||||
|
appropriate server section in ''/etc/config/nginx''
|
||||||
|
(or in a ''${CONF_DIR}*.conf'' file, which cannot be changed using UCI).
|
||||||
|
All such parts are included in the main configuration of OpenWrt
|
||||||
|
([[#openwrt_s_defaults|🡓OpenWrt’s Defaults]]).
|
||||||
|
|
||||||
|
In the server part, we state the domain as
|
||||||
|
[[https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name|
|
||||||
|
server_name]].
|
||||||
|
The link points to the same document as for the location blocks in the
|
||||||
|
[[#basic|🡑Basic Configuration]]: the official documentation for all available
|
||||||
|
directives of the HTTP core of Nginx.
|
||||||
|
This time look for //server// in the Context list, too.
|
||||||
|
The server part should also contain similar location blocks as
|
||||||
|
++before.|
|
||||||
|
We can re-include a ''.locations'' file that is included in the server part for
|
||||||
|
the LAN by default.
|
||||||
|
Then the site is reachable under the same path at both domains, e.g. by
|
||||||
|
https://192.168.1.1/ex/am/ple as well as by https://${EXAMPLE_COM}/ex/am/ple.
|
||||||
|
++
|
||||||
|
|
||||||
|
We can add directives to a server in the UCI configuration by invoking
|
||||||
|
''uci [set|add_list] nginx.${EXAMPLE_COM//./_}.key=value''.
|
||||||
|
If the //key// is not starting with //uci_//, it becomes a ''key value;''
|
||||||
|
++directive.|
|
||||||
|
Although the UCI config does not support nesting like Nginx, we can add a whole
|
||||||
|
block as //value//.
|
||||||
|
++
|
||||||
|
|
||||||
|
We cannot use dots in a //key// name other than in the //value//.
|
||||||
|
In the following example we replace the dot in //${EXAMPLE_COM}// by an
|
||||||
|
underscore for the UCI name of the server, but not for Nginx's //server_name//:
|
||||||
|
|
||||||
|
<code bash>
|
||||||
|
uci add nginx server &&
|
||||||
|
uci rename nginx.@server[-1]=${EXAMPLE_COM//./_} &&
|
||||||
|
uci add_list nginx.${EXAMPLE_COM//./_}.listen='80' &&
|
||||||
|
uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' &&
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}.server_name='${EXAMPLE_COM}' &&
|
||||||
|
uci add_list nginx.${EXAMPLE_COM//./_}.include=\
|
||||||
|
'$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations'
|
||||||
|
# uci add_list nginx.${EXAMPLE_COM//./_}.location='/ { … }' \
|
||||||
|
# root location for this server.
|
||||||
|
</code>
|
||||||
|
|
||||||
|
We can disable respective re-enable this server again by:
|
||||||
|
|
||||||
|
<code bash>
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}=disable # respective: \
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}=server
|
||||||
|
</code>
|
||||||
|
|
||||||
|
These changes are made in the RAM (and can be used until a reboot), we can save
|
||||||
|
them permanently by:
|
||||||
|
|
||||||
|
<code bash>uci commit nginx</code>
|
||||||
|
|
||||||
|
For creating a similar ''${CONF_DIR}${EXAMPLE_COM}.conf'', we can adopt the
|
||||||
|
following:
|
||||||
|
|
||||||
|
<code nginx ${CONF_DIR}${EXAMPLE_COM}.conf>
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name ${EXAMPLE_COM};
|
||||||
|
include '$(basename ${CONF_DIR})/${EXAMPLE_COM}.locations';
|
||||||
|
# location / { … } # root location for this server.
|
||||||
|
}
|
||||||
|
</code>
|
||||||
|
|
||||||
|
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include the UCI server
|
||||||
|
''config server '_redirect2ssl' ''.
|
||||||
|
It acts as //default_server// for HTTP and redirects requests for inexistent
|
||||||
|
URLs to HTTPS.
|
||||||
|
For making another domain name accessible to all addresses, the corresponding
|
||||||
|
server part should listen on port //80// and contain the FQDN as
|
||||||
|
//server_name//, cf. the official documentation on
|
||||||
|
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]].
|
||||||
|
|
||||||
|
Furthermore, there is a UCI server named ''${LAN_NAME}''.
|
||||||
|
It is the //default_server// for HTTPS and allows connections from LAN only.
|
||||||
|
It includes the file ''$(dirname "${CONF_DIR}")/restrict_locally'' with
|
||||||
|
appropriate //allow/deny// directives, cf. the official documentation on
|
||||||
|
[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
==== SSL Server Parts ====${MSG}
|
||||||
|
|
||||||
|
|
||||||
|
For enabling HTTPS for a domain we need a SSL certificate as well as its key and
|
||||||
|
add them by the directives //ssl_certificate// respective
|
||||||
|
//ssl_certificate_key// to the server part of the domain
|
||||||
|
([[https://nginx.org/en/docs/http/configuring_https_servers.html#sni|TLS SNI]]
|
||||||
|
is supported by default).
|
||||||
|
The rest of the configuration is similar as for general
|
||||||
|
[[#new_server_parts|🡑New Server Parts]].
|
||||||
|
We only have to adjust the listen directives by adding the //ssl// parameter and
|
||||||
|
changing the port from //80// to //443//.
|
||||||
|
|
||||||
|
The official documentation of the SSL module contains an
|
||||||
|
[[https://nginx.org/en/docs/http/ngx_http_ssl_module.html#example|
|
||||||
|
example]] with some optimizations.
|
||||||
|
We can extend an existing UCI server section similarly, e.g., for the above
|
||||||
|
''config server '${EXAMPLE_COM//./_}' '' we invoke:
|
||||||
|
|
||||||
|
<code bash>
|
||||||
|
# Instead of 'del_list' the listen* entries, we could use '443 ssl' beforehand.
|
||||||
|
uci del_list nginx.${EXAMPLE_COM//./_}.listen='80' &&
|
||||||
|
uci del_list nginx.${EXAMPLE_COM//./_}.listen='[::]:80' &&
|
||||||
|
uci add_list nginx.${EXAMPLE_COM//./_}.listen='443 ssl' &&
|
||||||
|
uci add_list nginx.${EXAMPLE_COM//./_}.listen='[::]:443 ssl' &&
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate=\
|
||||||
|
'${CONF_DIR}${EXAMPLE_COM}.crt' &&
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}.ssl_certificate_key=\
|
||||||
|
'${CONF_DIR}${EXAMPLE_COM}.key' &&
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}.ssl_session_cache=\
|
||||||
|
'${SSL_SESSION_CACHE_ARG}' &&
|
||||||
|
uci set nginx.${EXAMPLE_COM//./_}.ssl_session_timeout=\
|
||||||
|
'${SSL_SESSION_TIMEOUT_ARG}' &&
|
||||||
|
uci commit nginx
|
||||||
|
</code>
|
||||||
|
|
||||||
|
For making the server in ''${CONF_DIR}${EXAMPLE_COM}.conf'' available
|
||||||
|
via SSL, we can make similar changes there.
|
||||||
|
|
||||||
|
The following command creates a **self-signed** SSL certificate and changes the
|
||||||
|
corresponding configuration:
|
||||||
|
|
||||||
|
<code bash>$(basename "${NGINX_UTIL}") ${ADD_SSL_FCT} ${EXAMPLE_COM}</code>
|
||||||
|
|
||||||
|
- If a ''$(basename "${CONF_DIR}")/${EXAMPLE_COM}.conf'' file exists, it\
|
||||||
|
adds //ssl_*// directives and changes the //listen// directives there.\
|
||||||
|
Else it does that similarly to the example above for a ++selected UCI\
|
||||||
|
server.| Hereby it searches the UCI config first for a server with the\
|
||||||
|
given name and then for a server whose //server_name// contains the name.\
|
||||||
|
For //${EXAMPLE_COM}// it is the latter as a UCI key cannot have dots.++
|
||||||
|
- It checks if there is a certificate with key for '${EXAMPLE_COM}' that is\
|
||||||
|
valid for at least 13 months or tries to create a self-signed one.
|
||||||
|
- When cron is activated, it installs a cron job for renewing the self-signed\
|
||||||
|
certificate every year if needed, too. We can activate cron by: \
|
||||||
|
<code bash>service cron enable && service cron start</code>
|
||||||
|
|
||||||
|
This can be undone by invoking:
|
||||||
|
|
||||||
|
<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM}</code>
|
||||||
|
|
||||||
|
For using an SSL certificate and key that are managed otherwise, there is:
|
||||||
|
|
||||||
|
<code bash>$(basename "${NGINX_UTIL}") add_ssl ${EXAMPLE_COM} "\$MANAGER" \
|
||||||
|
"/absolute/path/to/crt" "/absolute/path/to/key"</code>
|
||||||
|
|
||||||
|
It only adds //ssl_*// directives and changes the //listen// directives in
|
||||||
|
the appropriate configuration, but does not create or change the certificate
|
||||||
|
or its key. This can be reverted by:
|
||||||
|
|
||||||
|
<code bash>$(basename "${NGINX_UTIL}") del_ssl ${EXAMPLE_COM} "\$MANAGER"</code>
|
||||||
|
|
||||||
|
For example [[https://github.com/ndilieto/uacme|uacme]] or
|
||||||
|
[[https://github.com/Neilpang/acme.sh|acme.sh]] can be used for creating an SSL
|
||||||
|
certificate signed by Let’s Encrypt and changing the config
|
||||||
|
++accordingly.|
|
||||||
|
They call ''$(basename "${NGINX_UTIL}") add_ssl \$FQDN acme \$CRT \$KEY''
|
||||||
|
internally.++
|
||||||
|
We can install them by:
|
||||||
|
|
||||||
|
<code bash>
|
||||||
|
opkg update && opkg install uacme #or: acme #and for LuCI: luci-app-acme
|
||||||
|
</code>
|
||||||
|
|
||||||
|
[[#openwrt_s_defaults|🡓OpenWrt’s Defaults]] include a UCI server for the LAN:
|
||||||
|
''config server '${LAN_NAME}' ''.
|
||||||
|
It has //ssl_*// directives prepared for a self-signed((Let’s Encrypt (and other
|
||||||
|
CAs) cannot sign certificates of a **local** server.))
|
||||||
|
SSL certificate, which is created on the first start of Nginx.
|
||||||
|
The server listens on all addresses, is the //default_server// for HTTPS and
|
||||||
|
allows connections from LAN only (by including the file ''restrict_locally''
|
||||||
|
with //allow/deny// directives, cf. the official documentation on
|
||||||
|
[[https://nginx.org/en/docs/http/ngx_http_access_module.html|limiting access]]).
|
||||||
|
|
||||||
|
For making another domain name accessible to all addresses, the corresponding
|
||||||
|
SSL server part should listen on port //443// and contain the FQDN as
|
||||||
|
//server_name//, cf. the official documentation on
|
||||||
|
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]].
|
||||||
|
|
||||||
|
Furthermore, there is also a UCI server named ''_redirect2ssl'', which listens
|
||||||
|
on all addresses, acts as //default_server// for HTTP and redirects requests for
|
||||||
|
inexistent URLs to HTTPS.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
==== OpenWrt’s Defaults ====${MSG}
|
||||||
|
|
||||||
|
|
||||||
|
Since Nginx is compiled with these presets, we can pretend that the main
|
||||||
|
configuration will always contain the following directives
|
||||||
|
(though we can overwrite them):
|
||||||
|
|
||||||
|
<code nginx>$(ifConfEcho --pid-path pid)\
|
||||||
|
$(ifConfEcho --lock-path lock_file)\
|
||||||
|
$(ifConfEcho --error-log-path error_log)\
|
||||||
|
$(false && ifConfEcho --http-log-path access_log)\
|
||||||
|
$(ifConfEcho --http-proxy-temp-path proxy_temp_path)\
|
||||||
|
$(ifConfEcho --http-client-body-temp-path client_body_temp_path)\
|
||||||
|
$(ifConfEcho --http-fastcgi-temp-path fastcgi_temp_path)\
|
||||||
|
</code>
|
||||||
|
|
||||||
|
When starting or reloading the Nginx service, the ''/etc/init.d/nginx'' script
|
||||||
|
sets also the following directives
|
||||||
|
(so we cannot change them in the used configuration file):
|
||||||
|
|
||||||
|
<code nginx>
|
||||||
|
daemon off; # procd expects services to run in the foreground
|
||||||
|
</code>
|
||||||
|
|
||||||
|
Then, the init sript creates the main configuration
|
||||||
|
''$(basename "${UCI_CONF}")'' dynamically from the template:
|
||||||
|
|
||||||
|
$(code "${UCI_CONF}.template")
|
||||||
|
|
||||||
|
So, the access log is turned off by default and we can look at the error log
|
||||||
|
by ''logread'', as init.d script forwards stderr and stdout to the
|
||||||
|
[[docs:guide-user:base-system:log.essentials|🡒runtime log]].
|
||||||
|
We can set the //error_log// and //access_log// to files, where the log
|
||||||
|
messages are forwarded to instead (after the configuration is read).
|
||||||
|
And for redirecting the access log of a //server// or //location// to the logd,
|
||||||
|
too, we insert the following directive in the corresponding block:
|
||||||
|
|
||||||
|
<code nginx> access_log /proc/self/fd/1 openwrt;</code>
|
||||||
|
|
||||||
|
If we setup a server through UCI, we can use the options //error_log// and/or
|
||||||
|
//access_log// also with the special path
|
||||||
|
++'logd'.|
|
||||||
|
When initializing the Nginx service, this special path is replaced by //stderr//
|
||||||
|
respective ///proc/self/fd/1// (which are forwarded to the runtime log).
|
||||||
|
++
|
||||||
|
|
||||||
|
For creating the configuration from the template shown above, Nginx’s init
|
||||||
|
script replaces the comment ''#UCI_HTTP_CONFIG'' by all UCI servers.
|
||||||
|
For each server section in the the UCI configuration, it basically copies all
|
||||||
|
options into a Nginx //server { … }// part, in detail:
|
||||||
|
* Options starting with ''uci_'' are skipped. Currently there is only\
|
||||||
|
the ''option ${MANAGE_SSL}=…'' in ++usage.| It is set to\
|
||||||
|
//'self-signed'// when invoking\
|
||||||
|
''$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} \$NAME''.\
|
||||||
|
Then the corresponding certificate is re-newed if it is about to expire.\
|
||||||
|
All those certificates are checked on the initialization of the Nginx service\
|
||||||
|
and if Cron is available, it is deployed for checking them annually, too.++
|
||||||
|
* All other lists or options of the form ''key='value' '' are written\
|
||||||
|
one-to-one as ''key value;'' directives to the configuration file.\
|
||||||
|
Just the path //logd// has a special meaning for the logging directives\
|
||||||
|
(described in the previous paragraph).
|
||||||
|
|
||||||
|
The init.d script of Nginx uses the //$(basename ${NGINX_UTIL})// for creating
|
||||||
|
the configuration file
|
||||||
|
++in RAM.|
|
||||||
|
The main configuration ''${UCI_CONF}'' is a symbolic link to this place
|
||||||
|
(it is a dead link if the Nginx service is not running).
|
||||||
|
++
|
||||||
|
|
||||||
|
We could use a custom configuration created at ''${NGINX_CONF}'' instead of the
|
||||||
|
dynamic configuration, too.((
|
||||||
|
For using a custom configuration at ''${NGINX_CONF}'', we execute
|
||||||
|
<code bash>uci set nginx.global.uci_enable='false' </code>
|
||||||
|
Then the rest of the UCI config is ignored and //init.d// will not create the
|
||||||
|
main configuration dynamically from the template anymore.
|
||||||
|
Invoking ''$(basename ${NGINX_UTIL}) [${ADD_SSL_FCT}|del_ssl] \$FQDN''
|
||||||
|
will still try to change a server in ''$(basename "${CONF_DIR}")/\$FQDN.conf''
|
||||||
|
(this is less reliable than for a UCI config as it uses regular expressions, not
|
||||||
|
a complete parser for the Nginx configuration).))
|
||||||
|
This is not encouraged since you cannot setup servers using UCI anymore.
|
||||||
|
Rather, we can put custom configuration parts to ''.conf'' files in the
|
||||||
|
''${CONF_DIR}'' directory.
|
||||||
|
The main configuration pulls in all ''$(basename "${CONF_DIR}")/*.conf'' files
|
||||||
|
into the //http {…}// block behind the created UCI servers.
|
||||||
|
|
||||||
|
The initial UCI config is enabled and contains two server section:
|
||||||
|
|
||||||
|
$(code "/etc/config/nginx" "nginx.config")
|
||||||
|
|
||||||
|
While the LAN server is the //default_server// for HTTPS, the server
|
||||||
|
redirecting requests for an inexistent ''server_name'' from HTTP to HTTPS acts
|
||||||
|
as //default_server// if there is ++no other|;
|
||||||
|
it uses an invalid name for that, more in the official documentation on
|
||||||
|
[[https://nginx.org/en/docs/http/request_processing.html|request_processing]]
|
||||||
|
++.
|
||||||
|
|
||||||
|
The LAN server pulls in all ''.locations'' files from the directory
|
||||||
|
''${CONF_DIR}''.
|
||||||
|
We can install the location parts of different sites there (see
|
||||||
|
[[#basic|🡑Basic Configuration]]) and re-include them into other servers.
|
||||||
|
This is needed especially for making them available to the WAN
|
||||||
|
([[#new_server_parts|🡑New Server Parts]]).
|
||||||
|
The LAN server listens for all addresses on port //443// and restricts the
|
||||||
|
access to local addresses by including:
|
||||||
|
$(code "$(dirname "${CONF_DIR}")/restrict_locally")
|
||||||
|
|
||||||
|
When starting or reloading the Nginx service, the init.d looks which UCI servers
|
||||||
|
have set ''option ${MANAGE_SSL} 'self-signed' '', e.g. the LAN server.
|
||||||
|
For all those servers it checks if there is a certificate that is still valid
|
||||||
|
for 13 months or (re-)creates a self-signed one.
|
||||||
|
If there is any such server, it installs also a cron job that checks the
|
||||||
|
corresponding certificates once a year.
|
||||||
|
The option ''${MANAGE_SSL}'' is set to //'self-signed'// respectively removed
|
||||||
|
from a UCI server named ''${EXAMPLE_COM//./_}'' by the following
|
||||||
|
(see [[#ssl_server_parts|🡑SSL Server Parts]], too):
|
||||||
|
|
||||||
|
<code bash>
|
||||||
|
$(basename ${NGINX_UTIL}) ${ADD_SSL_FCT} ${EXAMPLE_COM//./_} \
|
||||||
|
# respectively: \
|
||||||
|
$(basename ${NGINX_UTIL}) del_ssl ${EXAMPLE_COM//./_}
|
||||||
|
</code>
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
22
net/nginx-util/files/nginx.config
Normal file
22
net/nginx-util/files/nginx.config
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
config main global
|
||||||
|
option uci_enable 'true'
|
||||||
|
|
||||||
|
config server '_lan'
|
||||||
|
list listen '443 ssl default_server'
|
||||||
|
list listen '[::]:443 ssl default_server'
|
||||||
|
option server_name '_lan'
|
||||||
|
list include 'restrict_locally'
|
||||||
|
list include 'conf.d/*.locations'
|
||||||
|
option uci_manage_ssl 'self-signed'
|
||||||
|
option ssl_certificate '/etc/nginx/conf.d/_lan.crt'
|
||||||
|
option ssl_certificate_key '/etc/nginx/conf.d/_lan.key'
|
||||||
|
option ssl_session_cache 'shared:SSL:32k'
|
||||||
|
option ssl_session_timeout '64m'
|
||||||
|
option access_log 'off; # logd openwrt'
|
||||||
|
|
||||||
|
config server '_redirect2ssl'
|
||||||
|
list listen '80'
|
||||||
|
list listen '[::]:80'
|
||||||
|
option server_name '_redirect2ssl'
|
||||||
|
option return '302 https://$host$request_uri'
|
10
net/nginx-util/files/restrict_locally
Normal file
10
net/nginx-util/files/restrict_locally
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
allow ::1;
|
||||||
|
allow fc00::/7;
|
||||||
|
allow fec0::/10;
|
||||||
|
allow fe80::/10;
|
||||||
|
allow 127.0.0.0/8;
|
||||||
|
allow 10.0.0.0/8;
|
||||||
|
allow 172.16.0.0/12;
|
||||||
|
allow 192.168.0.0/16;
|
||||||
|
allow 169.254.0.0/16;
|
||||||
|
deny all;
|
32
net/nginx-util/files/uci.conf.template
Normal file
32
net/nginx-util/files/uci.conf.template
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Consider using UCI or creating files in /etc/nginx/conf.d/ for configuration.
|
||||||
|
# Parsing UCI configuration is skipped if uci set nginx.global.uci_enable=false
|
||||||
|
# For details see: https://openwrt.org/docs/guide-user/services/webserver/nginx
|
||||||
|
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
user root;
|
||||||
|
|
||||||
|
events {}
|
||||||
|
|
||||||
|
http {
|
||||||
|
access_log off;
|
||||||
|
log_format openwrt
|
||||||
|
'$request_method $scheme://$host$request_uri => $status'
|
||||||
|
' (${body_bytes_sent}B in ${request_time}s) <- $http_referer';
|
||||||
|
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
sendfile on;
|
||||||
|
|
||||||
|
client_max_body_size 128M;
|
||||||
|
large_client_header_buffers 2 1k;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
|
||||||
|
root /www;
|
||||||
|
|
||||||
|
#UCI_HTTP_CONFIG
|
||||||
|
include conf.d/*.conf;
|
||||||
|
}
|
171
net/nginx-util/src/.clang-format
Normal file
171
net/nginx-util/src/.clang-format
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: false
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
# AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: false
|
||||||
|
# BitFieldColonSpacing: After
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: MultiLine
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
# BeforeLambdaBody: true
|
||||||
|
# BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<ext/.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Never
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
|
PointerAlignment: Left
|
||||||
|
RawStringFormats:
|
||||||
|
- Language: Cpp
|
||||||
|
Delimiters:
|
||||||
|
- cc
|
||||||
|
- CC
|
||||||
|
- cpp
|
||||||
|
- Cpp
|
||||||
|
- CPP
|
||||||
|
- 'c++'
|
||||||
|
- 'C++'
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
BasedOnStyle: google
|
||||||
|
- Language: TextProto
|
||||||
|
Delimiters:
|
||||||
|
- pb
|
||||||
|
- PB
|
||||||
|
- proto
|
||||||
|
- PROTO
|
||||||
|
EnclosingFunctions:
|
||||||
|
- EqualsProto
|
||||||
|
- EquivToProto
|
||||||
|
- PARSE_PARTIAL_TEXT_PROTO
|
||||||
|
- PARSE_TEST_PROTO
|
||||||
|
- PARSE_TEXT_PROTO
|
||||||
|
- ParseTextOrDie
|
||||||
|
- ParseTextProtoOrDie
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
BasedOnStyle: google
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 4
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
|
|
407
net/nginx-util/src/.clang-tidy
Normal file
407
net/nginx-util/src/.clang-tidy
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
---
|
||||||
|
Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-fuchsia-*,-misc-definitions-in-headers,-llvm-header-guard,-*-qualified-auto,-llvm-include-order'
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
HeaderFilterRegex: '.*'
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
|
FormatStyle: file
|
||||||
|
CheckOptions:
|
||||||
|
- key: abseil-string-find-startswith.AbseilStringsMatchHeader
|
||||||
|
value: 'absl/strings/match.h'
|
||||||
|
- key: abseil-string-find-startswith.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: abseil-string-find-startswith.StringLikeClasses
|
||||||
|
value: '::std::basic_string'
|
||||||
|
- key: bugprone-argument-comment.CommentBoolLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentCharacterLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentFloatLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentIntegerLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentNullPtrs
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentStringLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.CommentUserDefinedLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.IgnoreSingleArgument
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-argument-comment.StrictMode
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-assert-side-effect.AssertMacros
|
||||||
|
value: assert
|
||||||
|
- key: bugprone-assert-side-effect.CheckFunctionCalls
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-dangling-handle.HandleClasses
|
||||||
|
value: 'std::basic_string_view;std::experimental::basic_string_view'
|
||||||
|
- key: bugprone-dynamic-static-initializers.HeaderFileExtensions
|
||||||
|
value: ',h,hh,hpp,hxx'
|
||||||
|
- key: bugprone-exception-escape.FunctionsThatShouldNotThrow
|
||||||
|
value: ''
|
||||||
|
- key: bugprone-exception-escape.IgnoredExceptions
|
||||||
|
value: ''
|
||||||
|
- key: bugprone-misplaced-widening-cast.CheckImplicitCasts
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
|
||||||
|
value: ''
|
||||||
|
- key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-sizeof-expression.WarnOnSizeOfConstant
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-sizeof-expression.WarnOnSizeOfThis
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-string-constructor.LargeLengthThreshold
|
||||||
|
value: '8388608'
|
||||||
|
- key: bugprone-string-constructor.WarnOnLargeLength
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-suspicious-enum-usage.StrictMode
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
|
||||||
|
value: '5'
|
||||||
|
- key: bugprone-suspicious-missing-comma.RatioThreshold
|
||||||
|
value: '0.200000'
|
||||||
|
- key: bugprone-suspicious-missing-comma.SizeThreshold
|
||||||
|
value: '5'
|
||||||
|
- key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
|
||||||
|
value: ''
|
||||||
|
- key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
|
||||||
|
value: '0'
|
||||||
|
- key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
|
||||||
|
value: '16'
|
||||||
|
- key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
|
||||||
|
value: '1'
|
||||||
|
- key: bugprone-unused-return-value.CheckedFunctions
|
||||||
|
value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty'
|
||||||
|
- key: cert-dcl16-c.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: cert-dcl16-c.NewSuffixes
|
||||||
|
value: 'L;LL;LU;LLU'
|
||||||
|
- key: cert-dcl59-cpp.HeaderFileExtensions
|
||||||
|
value: ',h,hh,hpp,hxx'
|
||||||
|
- key: cert-err09-cpp.CheckThrowTemporaries
|
||||||
|
value: '1'
|
||||||
|
- key: cert-err61-cpp.CheckThrowTemporaries
|
||||||
|
value: '1'
|
||||||
|
- key: cert-msc32-c.DisallowedSeedTypes
|
||||||
|
value: 'time_t,std::time_t'
|
||||||
|
- key: cert-msc51-cpp.DisallowedSeedTypes
|
||||||
|
value: 'time_t,std::time_t'
|
||||||
|
- key: cert-oop11-cpp.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
|
||||||
|
value: '1.0;100.0;'
|
||||||
|
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
|
||||||
|
value: '1;2;3;4;'
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling
|
||||||
|
value: final
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||||
|
value: '1'
|
||||||
|
- key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
|
||||||
|
value: override
|
||||||
|
- key: cppcoreguidelines-macro-usage.AllowedRegexp
|
||||||
|
value: '^DEBUG_*'
|
||||||
|
- key: cppcoreguidelines-macro-usage.CheckCapsOnly
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
|
||||||
|
value: '1'
|
||||||
|
- key: cppcoreguidelines-no-malloc.Allocations
|
||||||
|
value: '::malloc;::calloc'
|
||||||
|
- key: cppcoreguidelines-no-malloc.Deallocations
|
||||||
|
value: '::free'
|
||||||
|
- key: cppcoreguidelines-no-malloc.Reallocations
|
||||||
|
value: '::realloc'
|
||||||
|
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||||
|
value: '1'
|
||||||
|
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
|
||||||
|
value: '::free;::realloc;::freopen;::fclose'
|
||||||
|
- key: cppcoreguidelines-owning-memory.LegacyResourceProducers
|
||||||
|
value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
|
||||||
|
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
|
||||||
|
value: ''
|
||||||
|
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-pro-type-member-init.UseAssignment
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
|
||||||
|
value: '0'
|
||||||
|
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
|
||||||
|
value: '0'
|
||||||
|
- key: google-build-namespaces.HeaderFileExtensions
|
||||||
|
value: ',h,hh,hpp,hxx'
|
||||||
|
- key: google-global-names-in-headers.HeaderFileExtensions
|
||||||
|
value: ',h,hh,hpp,hxx'
|
||||||
|
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||||
|
value: '1'
|
||||||
|
- key: google-readability-function-size.BranchThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: google-readability-function-size.LineThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: google-readability-function-size.NestingThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: google-readability-function-size.ParameterThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: google-readability-function-size.StatementThreshold
|
||||||
|
value: '800'
|
||||||
|
- key: google-readability-function-size.VariableThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||||
|
value: '10'
|
||||||
|
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||||
|
value: '2'
|
||||||
|
- key: google-runtime-int.SignedTypePrefix
|
||||||
|
value: int
|
||||||
|
- key: google-runtime-int.TypeSuffix
|
||||||
|
value: ''
|
||||||
|
- key: google-runtime-int.UnsignedTypePrefix
|
||||||
|
value: uint
|
||||||
|
- key: google-runtime-references.WhiteListTypes
|
||||||
|
value: ''
|
||||||
|
- key: hicpp-braces-around-statements.ShortStatementLines
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-function-size.BranchThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: hicpp-function-size.LineThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: hicpp-function-size.NestingThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: hicpp-function-size.ParameterThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: hicpp-function-size.StatementThreshold
|
||||||
|
value: '800'
|
||||||
|
- key: hicpp-function-size.VariableThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: hicpp-member-init.IgnoreArrays
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-member-init.UseAssignment
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove
|
||||||
|
value: '1'
|
||||||
|
- key: hicpp-multiway-paths-covered.WarnOnMissingElse
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-named-parameter.IgnoreFailedSplit
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-no-malloc.Allocations
|
||||||
|
value: '::malloc;::calloc'
|
||||||
|
- key: hicpp-no-malloc.Deallocations
|
||||||
|
value: '::free'
|
||||||
|
- key: hicpp-no-malloc.Reallocations
|
||||||
|
value: '::realloc'
|
||||||
|
- key: hicpp-signed-bitwise.IgnorePositiveIntegerLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-special-member-functions.AllowMissingMoveFunctions
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-uppercase-literal-suffix.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: hicpp-uppercase-literal-suffix.NewSuffixes
|
||||||
|
value: ''
|
||||||
|
- key: hicpp-use-auto.MinTypeNameLength
|
||||||
|
value: '5'
|
||||||
|
- key: hicpp-use-auto.RemoveStars
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-use-emplace.ContainersWithPushBack
|
||||||
|
value: '::std::vector;::std::list;::std::deque'
|
||||||
|
- key: hicpp-use-emplace.SmartPointers
|
||||||
|
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
|
||||||
|
- key: hicpp-use-emplace.TupleMakeFunctions
|
||||||
|
value: '::std::make_pair;::std::make_tuple'
|
||||||
|
- key: hicpp-use-emplace.TupleTypes
|
||||||
|
value: '::std::pair;::std::tuple'
|
||||||
|
- key: hicpp-use-equals-default.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: hicpp-use-equals-delete.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: hicpp-use-noexcept.ReplacementString
|
||||||
|
value: ''
|
||||||
|
- key: hicpp-use-noexcept.UseNoexceptFalse
|
||||||
|
value: '1'
|
||||||
|
- key: hicpp-use-nullptr.NullMacros
|
||||||
|
value: ''
|
||||||
|
- key: hicpp-use-override.AllowOverrideAndFinal
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-use-override.FinalSpelling
|
||||||
|
value: final
|
||||||
|
- key: hicpp-use-override.IgnoreDestructors
|
||||||
|
value: '0'
|
||||||
|
- key: hicpp-use-override.OverrideSpelling
|
||||||
|
value: override
|
||||||
|
- key: llvm-namespace-comment.ShortNamespaceLines
|
||||||
|
value: '1'
|
||||||
|
- key: llvm-namespace-comment.SpacesBeforeComments
|
||||||
|
value: '1'
|
||||||
|
- key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries
|
||||||
|
value: '1'
|
||||||
|
- key: misc-unused-parameters.StrictMode
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-loop-convert.MaxCopySize
|
||||||
|
value: '16'
|
||||||
|
- key: modernize-loop-convert.MinConfidence
|
||||||
|
value: reasonable
|
||||||
|
- key: modernize-loop-convert.NamingStyle
|
||||||
|
value: CamelCase
|
||||||
|
- key: modernize-make-shared.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-make-shared.IncludeStyle
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-make-shared.MakeSmartPtrFunction
|
||||||
|
value: 'std::make_shared'
|
||||||
|
- key: modernize-make-shared.MakeSmartPtrFunctionHeader
|
||||||
|
value: memory
|
||||||
|
- key: modernize-make-unique.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-make-unique.IncludeStyle
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-make-unique.MakeSmartPtrFunction
|
||||||
|
value: 'std::make_unique'
|
||||||
|
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
|
||||||
|
value: memory
|
||||||
|
- key: modernize-pass-by-value.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-pass-by-value.ValuesOnly
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-raw-string-literal.ReplaceShorterLiterals
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-replace-random-shuffle.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: modernize-use-auto.MinTypeNameLength
|
||||||
|
value: '5'
|
||||||
|
- key: modernize-use-auto.RemoveStars
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-use-default-member-init.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-use-default-member-init.UseAssignment
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-use-emplace.ContainersWithPushBack
|
||||||
|
value: '::std::vector;::std::list;::std::deque'
|
||||||
|
- key: modernize-use-emplace.SmartPointers
|
||||||
|
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
|
||||||
|
- key: modernize-use-emplace.TupleMakeFunctions
|
||||||
|
value: '::std::make_pair;::std::make_tuple'
|
||||||
|
- key: modernize-use-emplace.TupleTypes
|
||||||
|
value: '::std::pair;::std::tuple'
|
||||||
|
- key: modernize-use-equals-default.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-use-equals-delete.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-use-nodiscard.ReplacementString
|
||||||
|
value: '[[nodiscard]]'
|
||||||
|
- key: modernize-use-noexcept.ReplacementString
|
||||||
|
value: ''
|
||||||
|
- key: modernize-use-noexcept.UseNoexceptFalse
|
||||||
|
value: '1'
|
||||||
|
- key: modernize-use-nullptr.NullMacros
|
||||||
|
value: 'NULL'
|
||||||
|
- key: modernize-use-override.AllowOverrideAndFinal
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-use-override.FinalSpelling
|
||||||
|
value: final
|
||||||
|
- key: modernize-use-override.IgnoreDestructors
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-use-override.OverrideSpelling
|
||||||
|
value: override
|
||||||
|
- key: modernize-use-transparent-functors.SafeMode
|
||||||
|
value: '0'
|
||||||
|
- key: modernize-use-using.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: objc-forbidden-subclassing.ForbiddenSuperClassNames
|
||||||
|
value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView'
|
||||||
|
- key: openmp-exception-escape.IgnoredExceptions
|
||||||
|
value: ''
|
||||||
|
- key: performance-faster-string-find.StringLikeClasses
|
||||||
|
value: 'std::basic_string'
|
||||||
|
- key: performance-for-range-copy.AllowedTypes
|
||||||
|
value: ''
|
||||||
|
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||||
|
value: '0'
|
||||||
|
- key: performance-inefficient-string-concatenation.StrictMode
|
||||||
|
value: '0'
|
||||||
|
- key: performance-inefficient-vector-operation.EnableProto
|
||||||
|
value: '0'
|
||||||
|
- key: performance-inefficient-vector-operation.VectorLikeClasses
|
||||||
|
value: '::std::vector'
|
||||||
|
- key: performance-move-const-arg.CheckTriviallyCopyableMove
|
||||||
|
value: '1'
|
||||||
|
- key: performance-move-constructor-init.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: performance-no-automatic-move.AllowedTypes
|
||||||
|
value: ''
|
||||||
|
- key: performance-type-promotion-in-math-fn.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: performance-unnecessary-copy-initialization.AllowedTypes
|
||||||
|
value: ''
|
||||||
|
- key: performance-unnecessary-value-param.AllowedTypes
|
||||||
|
value: ''
|
||||||
|
- key: performance-unnecessary-value-param.IncludeStyle
|
||||||
|
value: llvm
|
||||||
|
- key: portability-simd-intrinsics.Std
|
||||||
|
value: ''
|
||||||
|
- key: portability-simd-intrinsics.Suggest
|
||||||
|
value: '0'
|
||||||
|
- key: readability-braces-around-statements.ShortStatementLines
|
||||||
|
value: '0'
|
||||||
|
- key: readability-else-after-return.WarnOnUnfixable
|
||||||
|
value: '1'
|
||||||
|
- key: readability-function-size.BranchThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: readability-function-size.LineThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: readability-function-size.NestingThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: readability-function-size.ParameterThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: readability-function-size.StatementThreshold
|
||||||
|
value: '800'
|
||||||
|
- key: readability-function-size.VariableThreshold
|
||||||
|
value: '4294967295'
|
||||||
|
- key: readability-identifier-naming.IgnoreFailedSplit
|
||||||
|
value: '0'
|
||||||
|
- key: readability-implicit-bool-conversion.AllowIntegerConditions
|
||||||
|
value: '0'
|
||||||
|
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||||
|
value: '0'
|
||||||
|
- key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: readability-inconsistent-declaration-parameter-name.Strict
|
||||||
|
value: '0'
|
||||||
|
- key: readability-magic-numbers.IgnoredFloatingPointValues
|
||||||
|
value: '1.0;100.0;'
|
||||||
|
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||||
|
value: '1;2;3;4;'
|
||||||
|
- key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
|
||||||
|
value: '0'
|
||||||
|
- key: readability-redundant-smartptr-get.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: readability-redundant-string-init.StringNames
|
||||||
|
value: '::std::basic_string'
|
||||||
|
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
|
||||||
|
value: '0'
|
||||||
|
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
|
||||||
|
value: '0'
|
||||||
|
- key: readability-simplify-subscript-expr.Types
|
||||||
|
value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
|
||||||
|
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
|
||||||
|
value: '3'
|
||||||
|
- key: readability-uppercase-literal-suffix.IgnoreMacros
|
||||||
|
value: '1'
|
||||||
|
- key: readability-uppercase-literal-suffix.NewSuffixes
|
||||||
|
value: ''
|
||||||
|
- key: zircon-temporary-objects.Names
|
||||||
|
value: ''
|
||||||
|
...
|
||||||
|
|
@ -10,6 +10,13 @@ ADD_DEFINITIONS(-Wno-unused-parameter -Wmissing-declarations -Wshadow)
|
|||||||
|
|
||||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||||
|
|
||||||
|
FIND_PATH(uci_include_dir uci.h)
|
||||||
|
FIND_LIBRARY(uci NAMES uci)
|
||||||
|
INCLUDE_DIRECTORIES(${uci_include_dir})
|
||||||
|
|
||||||
|
FIND_PATH(ubox_include_dir libubox/blobmsg.h)
|
||||||
|
FIND_LIBRARY(ubox NAMES ubox)
|
||||||
|
INCLUDE_DIRECTORIES(${ubox_include_dir})
|
||||||
|
|
||||||
IF(UBUS)
|
IF(UBUS)
|
||||||
|
|
||||||
@ -19,22 +26,13 @@ FIND_PATH(ubus_include_dir libubus.h)
|
|||||||
FIND_LIBRARY(ubus NAMES ubus)
|
FIND_LIBRARY(ubus NAMES ubus)
|
||||||
INCLUDE_DIRECTORIES(${ubus_include_dir})
|
INCLUDE_DIRECTORIES(${ubus_include_dir})
|
||||||
|
|
||||||
FIND_PATH(ubox_include_dir libubox/blobmsg.h)
|
|
||||||
FIND_LIBRARY(ubox NAMES ubox)
|
|
||||||
INCLUDE_DIRECTORIES(${ubox_include_dir})
|
|
||||||
|
|
||||||
ADD_EXECUTABLE(nginx-util nginx-util.cpp)
|
|
||||||
TARGET_COMPILE_DEFINITIONS(nginx-util PUBLIC -DNO_SSL)
|
|
||||||
TARGET_LINK_LIBRARIES(nginx-util ${ubox} ${ubus} pthread)
|
|
||||||
INSTALL(TARGETS nginx-util RUNTIME DESTINATION bin)
|
|
||||||
|
|
||||||
ADD_EXECUTABLE(nginx-ssl-util nginx-util.cpp)
|
ADD_EXECUTABLE(nginx-ssl-util nginx-util.cpp)
|
||||||
TARGET_LINK_LIBRARIES(nginx-ssl-util ${ubox} ${ubus} pthread ssl crypto pcre)
|
TARGET_LINK_LIBRARIES(nginx-ssl-util ${uci} ${ubox} ${ubus} pthread ssl crypto pcre)
|
||||||
INSTALL(TARGETS nginx-ssl-util RUNTIME DESTINATION bin)
|
INSTALL(TARGETS nginx-ssl-util RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
ADD_EXECUTABLE(nginx-ssl-util-nopcre nginx-util.cpp)
|
ADD_EXECUTABLE(nginx-ssl-util-nopcre nginx-util.cpp)
|
||||||
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre PUBLIC -DNO_PCRE)
|
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre PUBLIC -DNO_PCRE)
|
||||||
TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre ${ubox} ${ubus} pthread ssl crypto)
|
TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre ${uci} ${ubox} ${ubus} pthread ssl crypto)
|
||||||
INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin)
|
INSTALL(TARGETS nginx-ssl-util-nopcre RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
ELSE()
|
ELSE()
|
||||||
@ -44,6 +42,8 @@ ADD_COMPILE_DEFINITIONS(VERSION=0)
|
|||||||
CONFIGURE_FILE(test-px5g.sh test-px5g.sh COPYONLY)
|
CONFIGURE_FILE(test-px5g.sh test-px5g.sh COPYONLY)
|
||||||
CONFIGURE_FILE(test-nginx-util.sh test-nginx-util.sh COPYONLY)
|
CONFIGURE_FILE(test-nginx-util.sh test-nginx-util.sh COPYONLY)
|
||||||
CONFIGURE_FILE(test-nginx-util-root.sh test-nginx-util-root.sh COPYONLY)
|
CONFIGURE_FILE(test-nginx-util-root.sh test-nginx-util-root.sh COPYONLY)
|
||||||
|
CONFIGURE_FILE(../files/nginx.config config-nginx-ssl COPYONLY)
|
||||||
|
CONFIGURE_FILE(../files/uci.conf.template uci.conf.template COPYONLY)
|
||||||
|
|
||||||
ADD_EXECUTABLE(px5g px5g.cpp)
|
ADD_EXECUTABLE(px5g px5g.cpp)
|
||||||
TARGET_LINK_LIBRARIES(px5g ssl crypto)
|
TARGET_LINK_LIBRARIES(px5g ssl crypto)
|
||||||
@ -51,12 +51,12 @@ INSTALL(TARGETS px5g RUNTIME DESTINATION bin)
|
|||||||
|
|
||||||
ADD_EXECUTABLE(nginx-ssl-util-noubus nginx-util.cpp)
|
ADD_EXECUTABLE(nginx-ssl-util-noubus nginx-util.cpp)
|
||||||
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-noubus PUBLIC -DNO_UBUS)
|
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-noubus PUBLIC -DNO_UBUS)
|
||||||
TARGET_LINK_LIBRARIES(nginx-ssl-util-noubus pthread ssl crypto pcre)
|
TARGET_LINK_LIBRARIES(nginx-ssl-util-noubus ${uci} ${ubox} pthread ssl crypto pcre)
|
||||||
INSTALL(TARGETS nginx-ssl-util-noubus RUNTIME DESTINATION bin)
|
INSTALL(TARGETS nginx-ssl-util-noubus RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
ADD_EXECUTABLE(nginx-ssl-util-nopcre-noubus nginx-util.cpp)
|
ADD_EXECUTABLE(nginx-ssl-util-nopcre-noubus nginx-util.cpp)
|
||||||
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre-noubus PUBLIC -DNO_PCRE -DNO_UBUS)
|
TARGET_COMPILE_DEFINITIONS(nginx-ssl-util-nopcre-noubus PUBLIC -DNO_PCRE -DNO_UBUS)
|
||||||
TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre-noubus pthread ssl crypto)
|
TARGET_LINK_LIBRARIES(nginx-ssl-util-nopcre-noubus ${uci} ${ubox} pthread ssl crypto)
|
||||||
INSTALL(TARGETS nginx-ssl-util-nopcre-noubus RUNTIME DESTINATION bin)
|
INSTALL(TARGETS nginx-ssl-util-nopcre-noubus RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
23
net/nginx-util/src/LICENSE
Normal file
23
net/nginx-util/src/LICENSE
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* Copyright 2020 Peter Stadler
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
File diff suppressed because it is too large
Load Diff
@ -1,194 +1,378 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "nginx-ssl-util.hpp"
|
||||||
#include "nginx-util.hpp"
|
#include "nginx-util.hpp"
|
||||||
|
|
||||||
#ifndef NO_SSL
|
static auto constexpr file_comment_auto_created =
|
||||||
#include "nginx-ssl-util.hpp"
|
std::string_view{"# This file is re-created when Nginx starts.\n"};
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// TODO(pst) replace it with blobmsg_get_string if upstream takes const:
|
||||||
void create_lan_listen()
|
#ifndef NO_UBUS
|
||||||
|
static inline auto _pst_get_string(const blob_attr* attr) -> char*
|
||||||
{
|
{
|
||||||
std::string listen = "# This file is re-created if Nginx starts or"
|
return static_cast<char*>(blobmsg_data(attr));
|
||||||
" a LAN address changes.\n";
|
}
|
||||||
std::string listen_default = listen;
|
#endif
|
||||||
std::string ssl_listen = listen;
|
|
||||||
std::string ssl_listen_default = listen;
|
|
||||||
|
|
||||||
auto add_listen = [&listen, &listen_default
|
void create_lan_listen() // create empty files for compatibility:
|
||||||
#ifndef NO_SSL
|
{
|
||||||
,&ssl_listen, &ssl_listen_default
|
// TODO(pst): replace by dummies after transitioning nginx config to UCI:
|
||||||
#endif
|
std::vector<std::string> ips;
|
||||||
]
|
|
||||||
(const std::string &pre, const std::string &ip, const std::string &suf)
|
|
||||||
-> void
|
|
||||||
{
|
|
||||||
if (ip.empty()) { return; }
|
|
||||||
const std::string val = pre + ip + suf;
|
|
||||||
listen += "\tlisten " + val + ":80;\n";
|
|
||||||
listen_default += "\tlisten " + val + ":80 default_server;\n";
|
|
||||||
#ifndef NO_SSL
|
|
||||||
ssl_listen += "\tlisten " + val + ":443 ssl;\n";
|
|
||||||
ssl_listen_default += "\tlisten " + val + ":443 ssl default_server;\n";
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef NO_UBUS
|
#ifndef NO_UBUS
|
||||||
try {
|
try {
|
||||||
auto loopback_status=ubus::call("network.interface.loopback", "status");
|
auto loopback_status = ubus::call("network.interface.loopback", "status");
|
||||||
|
|
||||||
for (auto ip : loopback_status.filter("ipv4-address", "", "address")) {
|
for (const auto* ip : loopback_status.filter("ipv4-address", "", "address")) {
|
||||||
add_listen("", static_cast<const char *>(blobmsg_data(ip)), "");
|
ips.emplace_back(_pst_get_string(ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto ip : loopback_status.filter("ipv6-address", "", "address")) {
|
for (const auto* ip : loopback_status.filter("ipv6-address", "", "address")) {
|
||||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]");
|
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]");
|
||||||
}
|
}
|
||||||
} catch (const std::runtime_error &) { /* do nothing about it */ }
|
}
|
||||||
|
catch (const std::runtime_error&) { /* do nothing about it */
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto lan_status = ubus::call("network.interface.lan", "status");
|
auto lan_status = ubus::call("network.interface.lan", "status");
|
||||||
|
|
||||||
for (auto ip : lan_status.filter("ipv4-address", "", "address")) {
|
for (const auto* ip : lan_status.filter("ipv4-address", "", "address")) {
|
||||||
add_listen("", static_cast<const char *>(blobmsg_data(ip)), "");
|
ips.emplace_back(_pst_get_string(ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto ip : lan_status.filter("ipv6-address", "", "address")) {
|
for (const auto* ip : lan_status.filter("ipv6-address", "", "address")) {
|
||||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]");
|
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto ip : lan_status.filter("ipv6-prefix-assignment", "",
|
for (const auto* ip :
|
||||||
"local-address", "address"))
|
lan_status.filter("ipv6-prefix-assignment", "", "local-address", "address")) {
|
||||||
{
|
ips.emplace_back(std::string{"["} + _pst_get_string(ip) + "]");
|
||||||
add_listen("[", static_cast<const char *>(blobmsg_data(ip)), "]");
|
|
||||||
}
|
}
|
||||||
} catch (const std::runtime_error &) { /* do nothing about it */ }
|
}
|
||||||
|
catch (const std::runtime_error&) { /* do nothing about it */
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
add_listen("", "127.0.0.1", "");
|
ips.emplace_back("127.0.0.1");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string listen = std::string{file_comment_auto_created};
|
||||||
|
std::string listen_default = std::string{file_comment_auto_created};
|
||||||
|
for (const auto& ip : ips) {
|
||||||
|
listen += "\tlisten " + ip + ":80;\n";
|
||||||
|
listen_default += "\tlisten " + ip + ":80 default_server;\n";
|
||||||
|
}
|
||||||
write_file(LAN_LISTEN, listen);
|
write_file(LAN_LISTEN, listen);
|
||||||
write_file(LAN_LISTEN_DEFAULT, listen_default);
|
write_file(LAN_LISTEN_DEFAULT, listen_default);
|
||||||
#ifndef NO_SSL
|
|
||||||
|
std::string ssl_listen = std::string{file_comment_auto_created};
|
||||||
|
std::string ssl_listen_default = std::string{file_comment_auto_created};
|
||||||
|
for (const auto& ip : ips) {
|
||||||
|
ssl_listen += "\tlisten " + ip + ":443 ssl;\n";
|
||||||
|
ssl_listen_default += "\tlisten " + ip + ":443 ssl default_server;\n";
|
||||||
|
}
|
||||||
write_file(LAN_SSL_LISTEN, ssl_listen);
|
write_file(LAN_SSL_LISTEN, ssl_listen);
|
||||||
write_file(LAN_SSL_LISTEN_DEFAULT, ssl_listen_default);
|
write_file(LAN_SSL_LISTEN_DEFAULT, ssl_listen_default);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto change_if_starts_with(const std::string_view& subject,
|
||||||
|
const std::string_view& prefix,
|
||||||
|
const std::string_view& substitute,
|
||||||
|
const std::string_view& seperator = " \t\n;") -> std::string
|
||||||
|
{
|
||||||
|
auto view = subject;
|
||||||
|
view = view.substr(view.find_first_not_of(seperator));
|
||||||
|
if (view.rfind(prefix, 0) == 0) {
|
||||||
|
if (view.size() == prefix.size()) {
|
||||||
|
return std::string{substitute};
|
||||||
|
}
|
||||||
|
view = view.substr(prefix.size());
|
||||||
|
if (seperator.find(view[0]) != std::string::npos) {
|
||||||
|
auto ret = std::string{substitute};
|
||||||
|
ret += view;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string{subject};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto create_server_conf(const uci::section& sec, const std::string& indent = "")
|
||||||
|
-> std::string
|
||||||
|
{
|
||||||
|
auto secname = sec.name();
|
||||||
|
|
||||||
|
auto legacypath = std::string{CONF_DIR} + secname + ".conf";
|
||||||
|
if (access(legacypath.c_str(), R_OK) == 0) {
|
||||||
|
auto message = std::string{"skipped UCI server 'nginx."} + secname;
|
||||||
|
message += "' as it could conflict with: " + legacypath + "\n";
|
||||||
|
|
||||||
|
// TODO(pst) std::cerr<<"create_server_conf notice: "<<message;
|
||||||
|
|
||||||
|
return indent + "# " + message;
|
||||||
|
} // else:
|
||||||
|
|
||||||
|
auto conf = indent + "server { #see uci show 'nginx." + secname + "'\n";
|
||||||
|
|
||||||
|
for (auto opt : sec) {
|
||||||
|
for (auto itm : opt) {
|
||||||
|
if (opt.name().rfind("uci_", 0) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// else: standard opt.name()
|
||||||
|
|
||||||
|
auto val = itm.name();
|
||||||
|
|
||||||
|
if (opt.name() == "error_log") {
|
||||||
|
val = change_if_starts_with(val, "logd", "/proc/self/fd/1");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (opt.name() == "access_log") {
|
||||||
|
val = change_if_starts_with(val, "logd", "stderr");
|
||||||
|
}
|
||||||
|
|
||||||
|
conf += indent + "\t" + opt.name() + " " + itm.name() + ";\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf += indent + "}\n";
|
||||||
|
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_uci(const uci::package& pkg)
|
||||||
|
{
|
||||||
|
auto conf = std::string{file_comment_auto_created};
|
||||||
|
|
||||||
|
static const auto uci_http_config = std::string_view{"#UCI_HTTP_CONFIG\n"};
|
||||||
|
|
||||||
|
const auto tmpl = read_file(std::string{UCI_CONF} + ".template");
|
||||||
|
auto pos = tmpl.find(uci_http_config);
|
||||||
|
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
conf += tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
const auto index = tmpl.find_last_not_of(" \t", pos - 1);
|
||||||
|
|
||||||
|
const auto before = tmpl.begin() + index + 1;
|
||||||
|
const auto middle = tmpl.begin() + pos;
|
||||||
|
const auto after = middle + uci_http_config.length();
|
||||||
|
|
||||||
|
conf.append(tmpl.begin(), before);
|
||||||
|
|
||||||
|
const auto indent = std::string{before, middle};
|
||||||
|
for (auto sec : pkg) {
|
||||||
|
if (sec.type() == std::string_view{"server"}) {
|
||||||
|
conf += create_server_conf(sec, indent) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.append(after, tmpl.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
write_file(VAR_UCI_CONF, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto is_enabled(const uci::package& pkg) -> bool
|
||||||
|
{
|
||||||
|
for (auto sec : pkg) {
|
||||||
|
if (sec.type() != std::string_view{"main"}) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (sec.name() != std::string_view{"global"}) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto opt : sec) {
|
||||||
|
if (opt.name() != "uci_enable") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto itm : opt) {
|
||||||
|
if (itm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ___________main_thread________________|______________thread_1________________
|
||||||
|
* create_lan_listen() or do nothing | config = uci::package("nginx")
|
||||||
|
* if config_enabled (set in thread_1): | config_enabled = is_enabled(config)
|
||||||
|
* then init_uci(config) | check_ssl(config, config_enabled)
|
||||||
|
*/
|
||||||
void init_lan()
|
void init_lan()
|
||||||
{
|
{
|
||||||
std::exception_ptr ex;
|
std::exception_ptr ex;
|
||||||
|
std::unique_ptr<uci::package> config;
|
||||||
|
bool config_enabled = false;
|
||||||
|
std::mutex configuring;
|
||||||
|
|
||||||
#ifndef NO_SSL
|
configuring.lock();
|
||||||
auto thrd = std::thread([]{ //&ex
|
auto thrd = std::thread([&config, &config_enabled, &configuring, &ex] {
|
||||||
try { add_ssl_if_needed(std::string{LAN_NAME}); }
|
try {
|
||||||
|
config = std::make_unique<uci::package>("nginx");
|
||||||
|
config_enabled = is_enabled(*config);
|
||||||
|
configuring.unlock();
|
||||||
|
check_ssl(*config, config_enabled);
|
||||||
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
std::cerr<<"init_lan notice: no server named "<<LAN_NAME<<std::endl;
|
std::cerr << "init_lan error: checking UCI file /etc/config/nginx\n";
|
||||||
// not: ex = std::current_exception();
|
ex = std::current_exception();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
|
||||||
|
|
||||||
try { create_lan_listen(); }
|
try {
|
||||||
|
create_lan_listen();
|
||||||
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
std::cerr<<"init_lan error: cannot create LAN listen files"<<std::endl;
|
std::cerr << "init_lan error: cannot create listen files of local IPs.\n";
|
||||||
ex = std::current_exception();
|
ex = std::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_SSL
|
configuring.lock();
|
||||||
|
if (config_enabled) {
|
||||||
|
try {
|
||||||
|
init_uci(*config);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
std::cerr << "init_lan error: cannot create " << VAR_UCI_CONF << " from ";
|
||||||
|
std::cerr << UCI_CONF << ".template using UCI file /etc/config/nginx\n";
|
||||||
|
ex = std::current_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thrd.join();
|
thrd.join();
|
||||||
#endif
|
if (ex) {
|
||||||
|
std::rethrow_exception(ex);
|
||||||
if (ex) { std::rethrow_exception(ex); }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void get_env()
|
void get_env()
|
||||||
{
|
{
|
||||||
std::cout<<"NGINX_CONF="<<"'"<<NGINX_CONF<<"'"<<std::endl;
|
std::cout << "UCI_CONF="
|
||||||
std::cout<<"CONF_DIR="<<"'"<<CONF_DIR<<"'"<<std::endl;
|
<< "'" << UCI_CONF << "'" << std::endl;
|
||||||
std::cout<<"LAN_NAME="<<"'"<<LAN_NAME<<"'"<<std::endl;
|
std::cout << "NGINX_CONF="
|
||||||
std::cout<<"LAN_LISTEN="<<"'"<<LAN_LISTEN<<"'"<<std::endl;
|
<< "'" << NGINX_CONF << "'" << std::endl;
|
||||||
#ifndef NO_SSL
|
std::cout << "CONF_DIR="
|
||||||
std::cout<<"LAN_SSL_LISTEN="<<"'"<<LAN_SSL_LISTEN<<"'"<<std::endl;
|
<< "'" << CONF_DIR << "'" << std::endl;
|
||||||
std::cout<<"SSL_SESSION_CACHE_ARG="<<"'"<<SSL_SESSION_CACHE_ARG(LAN_NAME)<<
|
std::cout << "LAN_NAME="
|
||||||
"'"<<std::endl;
|
<< "'" << LAN_NAME << "'" << std::endl;
|
||||||
std::cout<<"SSL_SESSION_TIMEOUT_ARG="<<"'"<<SSL_SESSION_TIMEOUT_ARG<<"'\n";
|
std::cout << "LAN_LISTEN="
|
||||||
std::cout<<"ADD_SSL_FCT="<<"'"<<ADD_SSL_FCT<<"'"<<std::endl;
|
<< "'" << LAN_LISTEN << "'" << std::endl;
|
||||||
#endif
|
std::cout << "LAN_SSL_LISTEN="
|
||||||
|
<< "'" << LAN_SSL_LISTEN << "'" << std::endl;
|
||||||
|
std::cout << "SSL_SESSION_CACHE_ARG="
|
||||||
|
<< "'" << SSL_SESSION_CACHE_ARG(LAN_NAME) << "'" << std::endl;
|
||||||
|
std::cout << "SSL_SESSION_TIMEOUT_ARG="
|
||||||
|
<< "'" << SSL_SESSION_TIMEOUT_ARG << "'\n";
|
||||||
|
std::cout << "ADD_SSL_FCT="
|
||||||
|
<< "'" << ADD_SSL_FCT << "'" << std::endl;
|
||||||
|
std::cout << "MANAGE_SSL="
|
||||||
|
<< "'" << MANAGE_SSL << "'" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto main(int argc, char* argv[]) -> int
|
||||||
auto main(int argc, char * argv[]) -> int
|
|
||||||
{
|
{
|
||||||
// TODO(pst): use std::span when available:
|
// TODO(pst): use std::span when available:
|
||||||
auto args = std::basic_string_view<char *>{argv, static_cast<size_t>(argc)};
|
auto args = std::basic_string_view<char*>{argv, static_cast<size_t>(argc)};
|
||||||
|
|
||||||
auto cmds = std::array{
|
auto cmds = std::array{
|
||||||
std::array<std::string_view, 2>{"init_lan", ""},
|
std::array<std::string_view, 2>{"init_lan", ""},
|
||||||
std::array<std::string_view, 2>{"get_env", ""},
|
std::array<std::string_view, 2>{"get_env", ""},
|
||||||
#ifndef NO_SSL
|
std::array<std::string_view, 2>{
|
||||||
std::array<std::string_view, 2>{ADD_SSL_FCT, " server_name" },
|
ADD_SSL_FCT, "server_name [manager /path/to/ssl_certificate /path/to/ssl_key]"},
|
||||||
std::array<std::string_view, 2>{"del_ssl", " server_name" },
|
std::array<std::string_view, 2>{"del_ssl", "server_name [manager]"},
|
||||||
#endif
|
std::array<std::string_view, 2>{"check_ssl", ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (argc == 2 && args[1] == cmds[0][0]) {
|
||||||
|
init_lan();
|
||||||
|
}
|
||||||
|
|
||||||
if (argc==2 && args[1]==cmds[0][0]) { init_lan(); }
|
else if (argc == 2 && args[1] == cmds[1][0]) {
|
||||||
|
get_env();
|
||||||
|
}
|
||||||
|
|
||||||
else if (argc==2 && args[1]==cmds[1][0]) { get_env(); }
|
else if (argc == 3 && args[1] == cmds[2][0]) {
|
||||||
|
add_ssl_if_needed(std::string{args[2]});
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_SSL
|
// NOLINTNEXTLINE(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers): 6
|
||||||
else if (argc==3 && args[1]==cmds[2][0])
|
else if (argc == 6 && args[1] == cmds[2][0]) {
|
||||||
{ add_ssl_if_needed(std::string{args[2]});}
|
// NOLINTNEXTLINE(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers): 5
|
||||||
|
add_ssl_if_needed(std::string{args[2]}, args[3], args[4], args[5]);
|
||||||
|
}
|
||||||
|
|
||||||
else if (argc==3 && args[1]==cmds[3][0])
|
else if (argc == 3 && args[1] == cmds[3][0]) {
|
||||||
{ del_ssl(std::string{args[2]}); }
|
del_ssl(std::string{args[2]});
|
||||||
|
}
|
||||||
|
|
||||||
else if (argc==2 && args[1]==cmds[3][0])
|
else if (argc == 4 && args[1] == cmds[3][0]) {
|
||||||
{ del_ssl(std::string{LAN_NAME}); }
|
del_ssl(std::string{args[2]}, args[3]);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
else if (argc == 2 && args[1] == cmds[3][0]) // TODO(pst) deprecate
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
auto name = std::string{LAN_NAME};
|
||||||
|
if (del_ssl_legacy(name)) {
|
||||||
|
auto crtpath = std::string{CONF_DIR} + name + ".crt";
|
||||||
|
remove(crtpath.c_str());
|
||||||
|
auto keypath = std::string{CONF_DIR} + name + ".key";
|
||||||
|
remove(keypath.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) { /* do nothing. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (argc == 2 && args[1] == cmds[4][0]) {
|
||||||
|
check_ssl(uci::package{"nginx"});
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
std::cerr<<"Tool for creating Nginx configuration files (";
|
std::cerr << "Tool for creating Nginx configuration files (";
|
||||||
#ifdef VERSION
|
#ifdef VERSION
|
||||||
std::cerr<<"version "<<VERSION<<" ";
|
std::cerr << "version " << VERSION << " ";
|
||||||
#endif
|
#endif
|
||||||
std::cerr<<"with ";
|
std::cerr << "with libuci, ";
|
||||||
#ifndef NO_UBUS
|
#ifndef NO_UBUS
|
||||||
std::cerr<<"ubus, ";
|
std::cerr << "libubus, ";
|
||||||
#endif
|
#endif
|
||||||
#ifndef NO_SSL
|
std::cerr << "libopenssl, ";
|
||||||
std::cerr<<"libopenssl, ";
|
#ifndef NO_PCRE
|
||||||
#ifdef NO_PCRE
|
std::cerr << "PCRE, ";
|
||||||
std::cerr<<"std::regex, ";
|
|
||||||
#else
|
|
||||||
std::cerr<<"PCRE, ";
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
std::cerr << "pthread and libstdcpp)." << std::endl;
|
||||||
std::cerr<<"pthread and libstdcpp)."<<std::endl;
|
|
||||||
|
|
||||||
auto usage = std::string{"usage: "} + *argv + " [";
|
auto usage =
|
||||||
for (auto cmd : cmds) {
|
std::accumulate(cmds.begin(), cmds.end(), std::string{"usage: "} + *argv + " [",
|
||||||
usage += std::string{cmd[0]};
|
[](const auto& use, const auto& cmd) {
|
||||||
usage += std::string{cmd[1]} + "|";
|
return use + std::string{cmd[0]} + (cmd[1].empty() ? "" : " ") +
|
||||||
}
|
std::string{cmd[1]} + "|";
|
||||||
usage[usage.size()-1] = ']';
|
});
|
||||||
std::cerr<<usage<<std::endl;
|
usage[usage.size() - 1] = ']';
|
||||||
|
std::cerr << usage << std::endl;
|
||||||
|
|
||||||
throw std::runtime_error("main error: argument not recognized");
|
throw std::runtime_error("main error: argument not recognized");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (const std::exception & e) { std::cerr<<e.what()<<std::endl; }
|
catch (const std::exception& e) {
|
||||||
|
std::cerr << " * " << *argv << " " << e.what() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
catch (...) { perror("main error"); }
|
catch (...) {
|
||||||
|
std::cerr << " * * " << *argv;
|
||||||
|
perror(" main error");
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,98 +9,103 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <thread>
|
// #include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifndef NO_UBUS
|
#ifndef NO_UBUS
|
||||||
#include "ubus-cxx.hpp"
|
#include "ubus-cxx.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "uci-cxx.hpp"
|
||||||
|
|
||||||
static constexpr auto NGINX_UTIL = std::string_view{"/usr/bin/nginx-util"};
|
static constexpr auto NGINX_UTIL = std::string_view{"/usr/bin/nginx-util"};
|
||||||
|
|
||||||
|
static constexpr auto VAR_UCI_CONF = std::string_view{"/var/lib/nginx/uci.conf"};
|
||||||
|
|
||||||
|
static constexpr auto UCI_CONF = std::string_view{"/etc/nginx/uci.conf"};
|
||||||
|
|
||||||
static constexpr auto NGINX_CONF = std::string_view{"/etc/nginx/nginx.conf"};
|
static constexpr auto NGINX_CONF = std::string_view{"/etc/nginx/nginx.conf"};
|
||||||
|
|
||||||
static constexpr auto CONF_DIR = std::string_view{"/etc/nginx/conf.d/"};
|
static constexpr auto CONF_DIR = std::string_view{"/etc/nginx/conf.d/"};
|
||||||
|
|
||||||
static constexpr auto LAN_NAME = std::string_view{"_lan"};
|
static constexpr auto LAN_NAME = std::string_view{"_lan"};
|
||||||
|
|
||||||
static constexpr auto LAN_LISTEN =std::string_view{"/var/lib/nginx/lan.listen"};
|
static auto constexpr MANAGE_SSL = std::string_view{"uci_manage_ssl"};
|
||||||
|
|
||||||
static constexpr auto LAN_LISTEN_DEFAULT =
|
static constexpr auto LAN_LISTEN = std::string_view{"/var/lib/nginx/lan.listen"};
|
||||||
|
|
||||||
|
static constexpr auto LAN_LISTEN_DEFAULT = // TODO(pst) deprecate
|
||||||
std::string_view{"/var/lib/nginx/lan.listen.default"};
|
std::string_view{"/var/lib/nginx/lan.listen.default"};
|
||||||
|
|
||||||
|
|
||||||
// mode: optional ios::binary and/or ios::app (default ios::trunc)
|
// mode: optional ios::binary and/or ios::app (default ios::trunc)
|
||||||
void write_file(const std::string_view & name, const std::string & str,
|
void write_file(const std::string_view& name,
|
||||||
std::ios_base::openmode flag=std::ios::trunc);
|
const std::string& str,
|
||||||
|
std::ios_base::openmode flag = std::ios::trunc);
|
||||||
|
|
||||||
// mode: optional ios::binary (internally ios::ate|ios::in)
|
// mode: optional ios::binary (internally ios::ate|ios::in)
|
||||||
auto read_file(const std::string_view & name,
|
auto read_file(const std::string_view& name, std::ios_base::openmode mode = std::ios::in)
|
||||||
std::ios_base::openmode mode=std::ios::in) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
|
|
||||||
// all S must be convertible to const char[]
|
// all S must be convertible to const char[]
|
||||||
template<typename ...S>
|
template <typename... S>
|
||||||
auto call(const std::string & program, S... args) -> pid_t;
|
auto call(const std::string& program, S... args) -> pid_t;
|
||||||
|
|
||||||
|
|
||||||
void create_lan_listen();
|
void create_lan_listen();
|
||||||
|
|
||||||
|
void init_uci(const uci::package& pkg);
|
||||||
|
|
||||||
|
auto is_enabled(const uci::package& pkg) -> bool;
|
||||||
|
|
||||||
void init_lan();
|
void init_lan();
|
||||||
|
|
||||||
|
|
||||||
void get_env();
|
void get_env();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------- partial implementation: ------------------------------
|
// --------------------- partial implementation: ------------------------------
|
||||||
|
|
||||||
|
void write_file(const std::string_view& name,
|
||||||
void write_file(const std::string_view & name, const std::string & str,
|
const std::string& str,
|
||||||
const std::ios_base::openmode flag)
|
const std::ios_base::openmode flag)
|
||||||
{
|
{
|
||||||
auto tmp = std::string{name};
|
auto tmp = std::string{name};
|
||||||
|
|
||||||
if ( (flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0 ) {
|
if ((flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0) {
|
||||||
tmp += ".tmp-XXXXXX";
|
tmp += ".tmp-XXXXXX";
|
||||||
auto fd = mkstemp(&tmp[0]);
|
auto fd = mkstemp(&tmp[0]);
|
||||||
if (fd==-1 || close(fd)!=0)
|
if (fd == -1 || close(fd) != 0) {
|
||||||
{ throw std::runtime_error("write_file error: cannot access " + tmp); }
|
throw std::runtime_error("write_file error: cannot access " + tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::ofstream file(tmp.data(), flag);
|
std::ofstream file(tmp.data(), flag);
|
||||||
if (!file.good()) {
|
if (!file.good()) {
|
||||||
throw std::ofstream::failure
|
throw std::ofstream::failure("write_file error: cannot open " + std::string{tmp});
|
||||||
("write_file error: cannot open " + std::string{tmp});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file<<str<<std::flush;
|
file << str << std::flush;
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
} catch(...) {
|
}
|
||||||
if (tmp!=name) { remove(tmp.c_str()); } //remove can fail.
|
catch (...) {
|
||||||
|
if (tmp != name) {
|
||||||
|
remove(tmp.c_str());
|
||||||
|
} // remove can fail.
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rename(tmp.c_str(), name.data()) != 0) {
|
if (rename(tmp.c_str(), name.data()) != 0) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("write_file error: cannot move " + tmp + " to " + name.data());
|
||||||
("write_file error: cannot move " + tmp + " to " + name.data());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto read_file(const std::string_view& name, const std::ios_base::openmode mode) -> std::string
|
||||||
auto read_file(const std::string_view & name,
|
|
||||||
const std::ios_base::openmode mode) -> std::string
|
|
||||||
{
|
{
|
||||||
std::ifstream file(name.data(), mode|std::ios::ate);
|
std::ifstream file(name.data(), mode | std::ios::ate);
|
||||||
if (!file.good()) {
|
if (!file.good()) {
|
||||||
throw std::ifstream::failure(
|
throw std::ifstream::failure("read_file error: cannot open " + std::string{name});
|
||||||
"read_file error: cannot open " + std::string{name});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ret{};
|
std::string ret{};
|
||||||
@ -108,27 +113,25 @@ auto read_file(const std::string_view & name,
|
|||||||
ret.reserve(size);
|
ret.reserve(size);
|
||||||
|
|
||||||
file.seekg(0);
|
file.seekg(0);
|
||||||
ret.assign((std::istreambuf_iterator<char>(file)),
|
ret.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... S>
|
||||||
template<typename ...S>
|
auto call(const char* program, S... args) -> pid_t
|
||||||
auto call(const char * program, S... args) -> pid_t
|
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (pid==0) { //child:
|
if (pid == 0) { // child:
|
||||||
std::array<char *, sizeof...(args)+2> argv =
|
std::array<char*, sizeof...(args) + 2> argv = {strdup(program), strdup(args)..., nullptr};
|
||||||
{ strdup(program), strdup(args)..., nullptr };
|
|
||||||
|
|
||||||
execv(program, argv.data()); // argv cannot be const char * const[]!
|
execv(program, argv.data()); // argv cannot be const char * const[]!
|
||||||
|
|
||||||
_exit(EXIT_FAILURE); // exec never returns.
|
_exit(EXIT_FAILURE); // exec never returns.
|
||||||
} else if (pid>0) { //parent:
|
}
|
||||||
|
else if (pid > 0) { // parent:
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,5 +140,4 @@ auto call(const char * program, S... args) -> pid_t
|
|||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,15 +3,14 @@
|
|||||||
|
|
||||||
// #define OPENSSL_API_COMPAT 0x10102000L
|
// #define OPENSSL_API_COMPAT 0x10102000L
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <memory>
|
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
static constexpr auto rsa_min_modulus_bits = 512;
|
static constexpr auto rsa_min_modulus_bits = 512;
|
||||||
|
|
||||||
@ -19,67 +18,51 @@ using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
|
|||||||
|
|
||||||
using X509_NAME_ptr = std::unique_ptr<X509_NAME, decltype(&::X509_NAME_free)>;
|
using X509_NAME_ptr = std::unique_ptr<X509_NAME, decltype(&::X509_NAME_free)>;
|
||||||
|
|
||||||
|
auto checkend(const std::string& crtpath, time_t seconds = 0, bool use_pem = true) -> bool;
|
||||||
auto checkend(const std::string & crtpath,
|
|
||||||
time_t seconds=0, bool use_pem=true) -> bool;
|
|
||||||
|
|
||||||
|
|
||||||
auto gen_eckey(int curve) -> EVP_PKEY_ptr;
|
auto gen_eckey(int curve) -> EVP_PKEY_ptr;
|
||||||
|
|
||||||
|
auto gen_rsakey(int keysize, BN_ULONG exponent = RSA_F4) -> EVP_PKEY_ptr;
|
||||||
|
|
||||||
auto gen_rsakey(int keysize, BN_ULONG exponent=RSA_F4) -> EVP_PKEY_ptr;
|
void write_key(const EVP_PKEY_ptr& pkey, const std::string& keypath = "", bool use_pem = true);
|
||||||
|
|
||||||
|
|
||||||
void write_key(const EVP_PKEY_ptr & pkey,
|
|
||||||
const std::string & keypath="", bool use_pem=true);
|
|
||||||
|
|
||||||
|
|
||||||
auto subject2name(const std::string & subject) -> X509_NAME_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
void selfsigned(const EVP_PKEY_ptr & pkey, int days,
|
|
||||||
const std::string & subject="", const std::string & crtpath="",
|
|
||||||
bool use_pem=true);
|
|
||||||
|
|
||||||
|
auto subject2name(const std::string& subject) -> X509_NAME_ptr;
|
||||||
|
|
||||||
|
void selfsigned(const EVP_PKEY_ptr& pkey,
|
||||||
|
int days,
|
||||||
|
const std::string& subject = "",
|
||||||
|
const std::string& crtpath = "",
|
||||||
|
bool use_pem = true);
|
||||||
|
|
||||||
// ------------------------- implementation: ----------------------------------
|
// ------------------------- implementation: ----------------------------------
|
||||||
|
|
||||||
|
inline auto print_error(const char* str, const size_t /*len*/, void* errmsg) -> int
|
||||||
inline auto print_error(const char * str, const size_t /*len*/, void * errmsg)
|
|
||||||
-> int
|
|
||||||
{
|
{
|
||||||
*static_cast<std::string *>(errmsg) += str;
|
*static_cast<std::string*>(errmsg) += str;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// wrapper for clang-tidy:
|
// wrapper for clang-tidy:
|
||||||
inline auto _BIO_new_fp(FILE * stream, const bool use_pem,
|
inline auto _BIO_new_fp(FILE* stream, const bool use_pem, const bool close = false) -> BIO*
|
||||||
const bool close=false) -> BIO *
|
|
||||||
{
|
{
|
||||||
return BIO_new_fp( stream, //NOLINTNEXTLINE(hicpp-signed-bitwise) macros:
|
return BIO_new_fp(stream, // NOLINTNEXTLINE(hicpp-signed-bitwise) macros:
|
||||||
(use_pem ? BIO_FP_TEXT : 0) | (close ? BIO_CLOSE : BIO_NOCLOSE) );
|
(use_pem ? BIO_FP_TEXT : 0) | (close ? BIO_CLOSE : BIO_NOCLOSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto checkend(const std::string& crtpath, const time_t seconds, const bool use_pem) -> bool
|
||||||
auto checkend(const std::string & crtpath,
|
|
||||||
const time_t seconds, const bool use_pem) -> bool
|
|
||||||
{
|
{
|
||||||
BIO * bio = crtpath.empty() ?
|
BIO* bio = crtpath.empty() ? _BIO_new_fp(stdin, use_pem)
|
||||||
_BIO_new_fp(stdin, use_pem) :
|
: BIO_new_file(crtpath.c_str(), (use_pem ? "r" : "rb"));
|
||||||
BIO_new_file(crtpath.c_str(), (use_pem ? "r" : "rb"));
|
|
||||||
|
|
||||||
X509 * x509 = nullptr;
|
X509* x509 = nullptr;
|
||||||
|
|
||||||
if (bio != nullptr) {
|
if (bio != nullptr) {
|
||||||
x509 = use_pem ?
|
x509 = use_pem ? PEM_read_bio_X509_AUX(bio, nullptr, nullptr, nullptr)
|
||||||
PEM_read_bio_X509_AUX(bio, nullptr, nullptr, nullptr) :
|
: d2i_X509_bio(bio, nullptr);
|
||||||
d2i_X509_bio(bio, nullptr);
|
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x509==nullptr) {
|
if (x509 == nullptr) {
|
||||||
std::string errmsg{"checkend error: unable to load certificate\n"};
|
std::string errmsg{"checkend error: unable to load certificate\n"};
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
@ -93,10 +76,9 @@ auto checkend(const std::string & crtpath,
|
|||||||
return (cmp >= 0);
|
return (cmp >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
||||||
{
|
{
|
||||||
EC_GROUP * group = curve!=0 ? EC_GROUP_new_by_curve_name(curve) : nullptr;
|
EC_GROUP* group = curve != 0 ? EC_GROUP_new_by_curve_name(curve) : nullptr;
|
||||||
|
|
||||||
if (group == nullptr) {
|
if (group == nullptr) {
|
||||||
std::string errmsg{"gen_eckey error: cannot build group for curve id "};
|
std::string errmsg{"gen_eckey error: cannot build group for curve id "};
|
||||||
@ -109,12 +91,10 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
|||||||
|
|
||||||
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
|
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
|
||||||
|
|
||||||
auto eckey = EC_KEY_new();
|
auto* eckey = EC_KEY_new();
|
||||||
|
|
||||||
if (eckey != nullptr) {
|
if (eckey != nullptr) {
|
||||||
if ( (EC_KEY_set_group(eckey, group) == 0) ||
|
if ((EC_KEY_set_group(eckey, group) == 0) || (EC_KEY_generate_key(eckey) == 0)) {
|
||||||
(EC_KEY_generate_key(eckey) == 0) )
|
|
||||||
{
|
|
||||||
EC_KEY_free(eckey);
|
EC_KEY_free(eckey);
|
||||||
eckey = nullptr;
|
eckey = nullptr;
|
||||||
}
|
}
|
||||||
@ -132,7 +112,7 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
|||||||
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
||||||
|
|
||||||
// EVP_PKEY_assign_EC_KEY is a macro casting eckey to char *:
|
// EVP_PKEY_assign_EC_KEY is a macro casting eckey to char *:
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey)) {
|
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey)) {
|
||||||
EC_KEY_free(eckey);
|
EC_KEY_free(eckey);
|
||||||
std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"};
|
std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"};
|
||||||
@ -143,16 +123,15 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr
|
|||||||
return pkey;
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
||||||
{
|
{
|
||||||
if (keysize<rsa_min_modulus_bits || keysize>OPENSSL_RSA_MAX_MODULUS_BITS) {
|
if (keysize < rsa_min_modulus_bits || keysize > OPENSSL_RSA_MAX_MODULUS_BITS) {
|
||||||
std::string errmsg{"gen_rsakey error: RSA keysize ("};
|
std::string errmsg{"gen_rsakey error: RSA keysize ("};
|
||||||
errmsg += std::to_string(keysize) + ") out of range [512..";
|
errmsg += std::to_string(keysize) + ") out of range [512..";
|
||||||
errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]";
|
errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]";
|
||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
auto bignum = BN_new();
|
auto* bignum = BN_new();
|
||||||
|
|
||||||
if (bignum == nullptr) {
|
if (bignum == nullptr) {
|
||||||
std::string errmsg{"gen_rsakey error: cannot get big number struct\n"};
|
std::string errmsg{"gen_rsakey error: cannot get big number struct\n"};
|
||||||
@ -160,7 +139,7 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
|||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rsa = RSA_new();
|
auto* rsa = RSA_new();
|
||||||
|
|
||||||
if (rsa != nullptr) {
|
if (rsa != nullptr) {
|
||||||
if ((BN_set_word(bignum, exponent) == 0) ||
|
if ((BN_set_word(bignum, exponent) == 0) ||
|
||||||
@ -184,7 +163,7 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
|||||||
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free};
|
||||||
|
|
||||||
// EVP_PKEY_assign_RSA is a macro casting rsa to char *:
|
// EVP_PKEY_assign_RSA is a macro casting rsa to char *:
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) {
|
if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) {
|
||||||
RSA_free(rsa);
|
RSA_free(rsa);
|
||||||
std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"};
|
std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"};
|
||||||
@ -195,32 +174,36 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr
|
|||||||
return pkey;
|
return pkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_key(const EVP_PKEY_ptr& pkey, const std::string& keypath, const bool use_pem)
|
||||||
void write_key(const EVP_PKEY_ptr & pkey,
|
|
||||||
const std::string & keypath, const bool use_pem)
|
|
||||||
{
|
{
|
||||||
BIO * bio = nullptr;
|
BIO* bio = nullptr;
|
||||||
|
|
||||||
if (keypath.empty()) { bio = _BIO_new_fp(stdout, use_pem); }
|
if (keypath.empty()) {
|
||||||
|
bio = _BIO_new_fp(stdout, use_pem);
|
||||||
|
}
|
||||||
|
|
||||||
else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") );
|
else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") );
|
||||||
|
|
||||||
static constexpr auto mask = 0600;
|
static constexpr auto mask = 0600;
|
||||||
// auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask);
|
// auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask);
|
||||||
// creat has no cloexec, alt. triggers cppcoreguidelines-pro-type-vararg
|
// creat has no cloexec, alt. triggers cppcoreguidelines-pro-type-vararg
|
||||||
//NOLINTNEXTLINE(android-cloexec-creat)
|
// NOLINTNEXTLINE(android-cloexec-creat)
|
||||||
auto fd = creat(keypath.c_str(), mask); // the same without va_args.
|
auto fd = creat(keypath.c_str(), mask); // the same without va_args.
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
auto fp = fdopen(fd, (use_pem ? "w" : "wb") );
|
auto* fp = fdopen(fd, (use_pem ? "w" : "wb"));
|
||||||
|
|
||||||
if (fp != nullptr) {
|
if (fp != nullptr) {
|
||||||
bio = _BIO_new_fp(fp, use_pem, true);
|
bio = _BIO_new_fp(fp, use_pem, true);
|
||||||
if (bio == nullptr) { fclose(fp); } // (fp owns fd)
|
if (bio == nullptr) {
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory) fp owns fd:
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
else { close(fd); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bio == nullptr) {
|
if (bio == nullptr) {
|
||||||
@ -233,30 +216,27 @@ void write_key(const EVP_PKEY_ptr & pkey,
|
|||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
auto key = pkey.get();
|
auto* key = pkey.get();
|
||||||
switch (EVP_PKEY_base_id(key)) { // use same format as px5g:
|
switch (EVP_PKEY_base_id(key)) { // use same format as px5g:
|
||||||
case EVP_PKEY_EC:
|
case EVP_PKEY_EC:
|
||||||
len = use_pem ?
|
len = use_pem ? PEM_write_bio_ECPrivateKey(bio, EVP_PKEY_get0_EC_KEY(key), nullptr,
|
||||||
PEM_write_bio_ECPrivateKey(bio, EVP_PKEY_get0_EC_KEY(key),
|
nullptr, 0, nullptr, nullptr)
|
||||||
nullptr, nullptr, 0, nullptr, nullptr) :
|
: i2d_ECPrivateKey_bio(bio, EVP_PKEY_get0_EC_KEY(key));
|
||||||
i2d_ECPrivateKey_bio(bio, EVP_PKEY_get0_EC_KEY(key));
|
|
||||||
break;
|
break;
|
||||||
case EVP_PKEY_RSA:
|
case EVP_PKEY_RSA:
|
||||||
len = use_pem ?
|
len = use_pem ? PEM_write_bio_RSAPrivateKey(bio, EVP_PKEY_get0_RSA(key), nullptr,
|
||||||
PEM_write_bio_RSAPrivateKey(bio, EVP_PKEY_get0_RSA(key),
|
nullptr, 0, nullptr, nullptr)
|
||||||
nullptr, nullptr, 0, nullptr, nullptr) :
|
: i2d_RSAPrivateKey_bio(bio, EVP_PKEY_get0_RSA(key));
|
||||||
i2d_RSAPrivateKey_bio(bio, EVP_PKEY_get0_RSA(key));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
len = use_pem ?
|
len = use_pem
|
||||||
PEM_write_bio_PrivateKey(bio, key,
|
? PEM_write_bio_PrivateKey(bio, key, nullptr, nullptr, 0, nullptr, nullptr)
|
||||||
nullptr, nullptr, 0, nullptr, nullptr) :
|
: i2d_PrivateKey_bio(bio, key);
|
||||||
i2d_PrivateKey_bio(bio, key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
|
|
||||||
if (len==0) {
|
if (len == 0) {
|
||||||
std::string errmsg{"write_key error: cannot write EVP pkey to "};
|
std::string errmsg{"write_key error: cannot write EVP pkey to "};
|
||||||
errmsg += keypath.empty() ? "stdout" : keypath;
|
errmsg += keypath.empty() ? "stdout" : keypath;
|
||||||
errmsg += "\n";
|
errmsg += "\n";
|
||||||
@ -265,10 +245,9 @@ void write_key(const EVP_PKEY_ptr & pkey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto subject2name(const std::string& subject) -> X509_NAME_ptr
|
||||||
auto subject2name(const std::string & subject) -> X509_NAME_ptr
|
|
||||||
{
|
{
|
||||||
if (!subject.empty() && subject[0]!='/') {
|
if (!subject.empty() && subject[0] != '/') {
|
||||||
throw std::runtime_error("subject2name errror: not starting with /");
|
throw std::runtime_error("subject2name errror: not starting with /");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,56 +259,63 @@ auto subject2name(const std::string & subject) -> X509_NAME_ptr
|
|||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subject.empty()) { return name; }
|
if (subject.empty()) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
size_t prev = 1;
|
int prev = 1;
|
||||||
std::string type{};
|
std::string type{};
|
||||||
char chr = '=';
|
char chr = '=';
|
||||||
for (size_t i=0; subject[i] != 0; ) {
|
for (int i = 0; subject[i] != 0;) {
|
||||||
++i;
|
++i;
|
||||||
if (subject[i]=='\\' && subject[++i]=='\0') {
|
if (subject[i] == '\\' && subject[++i] == '\0') {
|
||||||
throw std::runtime_error("subject2name errror: escape at the end");
|
throw std::runtime_error("subject2name errror: escape at the end");
|
||||||
}
|
}
|
||||||
if (subject[i]!=chr && subject[i]!='\0') { continue; }
|
if (subject[i] != chr && subject[i] != '\0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (chr == '=') {
|
if (chr == '=') {
|
||||||
type = subject.substr(prev, i-prev);
|
type = subject.substr(prev, i - prev);
|
||||||
chr = '/';
|
chr = '/';
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
auto nid = OBJ_txt2nid(type.c_str());
|
auto nid = OBJ_txt2nid(type.c_str());
|
||||||
if (nid == NID_undef) {
|
if (nid == NID_undef) {
|
||||||
// skip unknown entries (silently?).
|
// skip unknown entries (silently?).
|
||||||
} else {
|
}
|
||||||
auto val = // X509_NAME_add_entry_by_NID wants it unsigned:
|
else {
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
const auto* val = // X509_NAME_add_entry_by_NID wants it unsigned:
|
||||||
reinterpret_cast<const unsigned char *>(&subject[prev]);
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
reinterpret_cast<const unsigned char*>(&subject[prev]);
|
||||||
|
|
||||||
auto len = i - prev;
|
int len = i - prev;
|
||||||
|
|
||||||
if ( X509_NAME_add_entry_by_NID(name.get(), nid,
|
if (X509_NAME_add_entry_by_NID(
|
||||||
MBSTRING_ASC, //NOLINT(hicpp-signed-bitwise) is macro
|
name.get(), nid,
|
||||||
val, len, -1, 0)
|
MBSTRING_ASC, // NOLINT(hicpp-signed-bitwise) is macro
|
||||||
== 0 )
|
val, len, -1, 0) == 0)
|
||||||
{
|
{
|
||||||
std::string errmsg{"subject2name error: cannot add "};
|
std::string errmsg{"subject2name error: cannot add "};
|
||||||
errmsg += "/" + type +"="+ subject.substr(prev, len) +"\n";
|
errmsg += "/" + type + "=" + subject.substr(prev, len) + "\n";
|
||||||
ERR_print_errors_cb(print_error, &errmsg);
|
ERR_print_errors_cb(print_error, &errmsg);
|
||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chr = '=';
|
chr = '=';
|
||||||
}
|
}
|
||||||
prev = i+1;
|
prev = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selfsigned(const EVP_PKEY_ptr& pkey,
|
||||||
void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
const int days,
|
||||||
const std::string & subject, const std::string & crtpath,
|
const std::string& subject,
|
||||||
|
const std::string& crtpath,
|
||||||
const bool use_pem)
|
const bool use_pem)
|
||||||
{
|
{
|
||||||
auto x509 = X509_new();
|
auto* x509 = X509_new();
|
||||||
|
|
||||||
if (x509 == nullptr) {
|
if (x509 == nullptr) {
|
||||||
std::string errmsg{"selfsigned error: cannot create X509 structure\n"};
|
std::string errmsg{"selfsigned error: cannot create X509 structure\n"};
|
||||||
@ -337,8 +323,7 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
|||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto freeX509_and_throw = [&x509](const std::string & what)
|
auto freeX509_and_throw = [&x509](const std::string& what) {
|
||||||
{
|
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
std::string errmsg{"selfsigned error: cannot set "};
|
std::string errmsg{"selfsigned error: cannot set "};
|
||||||
errmsg += what + " in X509 certificate\n";
|
errmsg += what + " in X509 certificate\n";
|
||||||
@ -346,19 +331,25 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
|||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (X509_set_version(x509, 2) == 0) { freeX509_and_throw("version"); }
|
if (X509_set_version(x509, 2) == 0) {
|
||||||
|
freeX509_and_throw("version");
|
||||||
|
}
|
||||||
|
|
||||||
if (X509_set_pubkey(x509, pkey.get()) == 0) { freeX509_and_throw("pubkey");}
|
if (X509_set_pubkey(x509, pkey.get()) == 0) {
|
||||||
|
freeX509_and_throw("pubkey");
|
||||||
|
}
|
||||||
|
|
||||||
if ((X509_gmtime_adj(X509_getm_notBefore(x509), 0) == nullptr) ||
|
if ((X509_gmtime_adj(X509_getm_notBefore(x509), 0) == nullptr) ||
|
||||||
(X509_time_adj_ex(X509_getm_notAfter(x509), days,0,nullptr) == nullptr))
|
(X509_time_adj_ex(X509_getm_notAfter(x509), days, 0, nullptr) == nullptr))
|
||||||
{
|
{
|
||||||
freeX509_and_throw("times");
|
freeX509_and_throw("times");
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_NAME_ptr name{nullptr, ::X509_NAME_free};
|
X509_NAME_ptr name{nullptr, ::X509_NAME_free};
|
||||||
|
|
||||||
try { name = subject2name(subject); }
|
try {
|
||||||
|
name = subject2name(subject);
|
||||||
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
throw;
|
throw;
|
||||||
@ -372,9 +363,11 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
|||||||
freeX509_and_throw("issuer");
|
freeX509_and_throw("issuer");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bignum = BN_new();
|
auto* bignum = BN_new();
|
||||||
|
|
||||||
if (bignum == nullptr) { freeX509_and_throw("serial (creating big number struct)"); }
|
if (bignum == nullptr) {
|
||||||
|
freeX509_and_throw("serial (creating big number struct)");
|
||||||
|
}
|
||||||
|
|
||||||
static const auto BITS = 159;
|
static const auto BITS = 159;
|
||||||
if (BN_rand(bignum, BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY) == 0) {
|
if (BN_rand(bignum, BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY) == 0) {
|
||||||
@ -393,22 +386,19 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
|||||||
freeX509_and_throw("signing digest");
|
freeX509_and_throw("signing digest");
|
||||||
}
|
}
|
||||||
|
|
||||||
BIO * bio = crtpath.empty() ?
|
BIO* bio = crtpath.empty() ? _BIO_new_fp(stdout, use_pem)
|
||||||
_BIO_new_fp(stdout, use_pem) :
|
: BIO_new_file(crtpath.c_str(), (use_pem ? "w" : "wb"));
|
||||||
BIO_new_file(crtpath.c_str(), (use_pem ? "w" : "wb"));
|
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if (bio != nullptr) {
|
if (bio != nullptr) {
|
||||||
len = use_pem ?
|
len = use_pem ? PEM_write_bio_X509(bio, x509) : i2d_X509_bio(bio, x509);
|
||||||
PEM_write_bio_X509(bio, x509) :
|
|
||||||
i2d_X509_bio(bio, x509);
|
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
|
|
||||||
if (len==0) {
|
if (len == 0) {
|
||||||
std::string errmsg{"selfsigned error: cannot write certificate to "};
|
std::string errmsg{"selfsigned error: cannot write certificate to "};
|
||||||
errmsg += crtpath.empty() ? "stdout" : crtpath;
|
errmsg += crtpath.empty() ? "stdout" : crtpath;
|
||||||
errmsg += "\n";
|
errmsg += "\n";
|
||||||
@ -417,5 +407,4 @@ void selfsigned(const EVP_PKEY_ptr & pkey, const int days,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,66 +1,53 @@
|
|||||||
#include "px5g-openssl.hpp"
|
#include <unistd.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unistd.h>
|
#include "px5g-openssl.hpp"
|
||||||
|
|
||||||
|
class argv_view { // TODO(pst): use std::span when available.
|
||||||
|
|
||||||
class argv_view { // TODO(pst): use std::span when available.
|
private:
|
||||||
|
std::basic_string_view<const char*> data;
|
||||||
|
|
||||||
private:
|
public:
|
||||||
|
argv_view(const argv_view&) = delete;
|
||||||
|
|
||||||
std::basic_string_view<const char *> data;
|
argv_view(argv_view&&) = delete;
|
||||||
|
|
||||||
public:
|
auto operator=(const argv_view&) -> argv_view& = delete;
|
||||||
|
|
||||||
argv_view(const argv_view &) = delete;
|
auto operator=(argv_view &&) -> argv_view& = delete;
|
||||||
|
|
||||||
|
argv_view(const char** argv, int argc) : data{argv, static_cast<size_t>(argc)} {}
|
||||||
|
|
||||||
argv_view(argv_view &&) = delete;
|
inline auto operator[](size_t pos) const -> std::string_view
|
||||||
|
{
|
||||||
|
return std::string_view{data[pos]};
|
||||||
auto operator=(const argv_view &) -> argv_view & = delete;
|
}
|
||||||
|
|
||||||
|
|
||||||
auto operator=(argv_view &&) -> argv_view & = delete;
|
|
||||||
|
|
||||||
|
|
||||||
argv_view(const char ** argv, int argc) :
|
|
||||||
data{argv, static_cast<size_t>(argc)} {}
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator[] (size_t pos) const -> std::string_view
|
|
||||||
{ return std::string_view{data[pos]}; }
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] inline constexpr auto size() const noexcept -> size_t
|
[[nodiscard]] inline constexpr auto size() const noexcept -> size_t
|
||||||
{ return data.size(); }
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
~argv_view() = default;
|
~argv_view() = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const auto default_validity = 30;
|
static const auto default_validity = 30;
|
||||||
|
|
||||||
|
auto checkend(const argv_view& argv) -> int;
|
||||||
|
|
||||||
auto checkend(const argv_view & argv) -> int;
|
void eckey(const argv_view& argv);
|
||||||
|
|
||||||
|
void rsakey(const argv_view& argv);
|
||||||
|
|
||||||
void eckey(const argv_view & argv);
|
void selfsigned(const argv_view& argv);
|
||||||
|
|
||||||
|
inline auto parse_int(const std::string_view& arg) -> int
|
||||||
void rsakey(const argv_view & argv);
|
|
||||||
|
|
||||||
|
|
||||||
void selfsigned(const argv_view & argv);
|
|
||||||
|
|
||||||
|
|
||||||
inline auto parse_int(const std::string_view & arg) -> int
|
|
||||||
{
|
{
|
||||||
size_t pos;
|
size_t pos = 0;
|
||||||
int ret = stoi(std::string{arg}, &pos);
|
int ret = stoi(std::string{arg}, &pos);
|
||||||
if (pos < arg.size()) {
|
if (pos < arg.size()) {
|
||||||
throw std::runtime_error("number has trailing char");
|
throw std::runtime_error("number has trailing char");
|
||||||
@ -68,28 +55,35 @@ inline auto parse_int(const std::string_view & arg) -> int
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto parse_curve(const std::string_view& name) -> int
|
||||||
inline auto parse_curve(const std::string_view & name) -> int
|
|
||||||
{
|
{
|
||||||
if (name=="P-384") { return NID_secp384r1; }
|
if (name == "P-384") {
|
||||||
if (name=="P-521") { return NID_secp521r1; }
|
return NID_secp384r1;
|
||||||
if (name=="P-256" || name=="secp256r1") { return NID_X9_62_prime256v1; }
|
}
|
||||||
if (name=="secp192r1") { return NID_X9_62_prime192v1; }
|
if (name == "P-521") {
|
||||||
|
return NID_secp521r1;
|
||||||
|
}
|
||||||
|
if (name == "P-256" || name == "secp256r1") {
|
||||||
|
return NID_X9_62_prime256v1;
|
||||||
|
}
|
||||||
|
if (name == "secp192r1") {
|
||||||
|
return NID_X9_62_prime192v1;
|
||||||
|
}
|
||||||
return OBJ_sn2nid(name.data());
|
return OBJ_sn2nid(name.data());
|
||||||
// not: if (curve == 0) { curve = EC_curve_nist2nid(name.c_str()); }
|
// not: if (curve == 0) { curve = EC_curve_nist2nid(name.c_str()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto checkend(const argv_view& argv) -> int
|
||||||
auto checkend(const argv_view & argv) -> int
|
|
||||||
{
|
{
|
||||||
bool use_pem = true;
|
bool use_pem = true;
|
||||||
std::string crtpath{};
|
std::string crtpath{};
|
||||||
time_t seconds = 0;
|
time_t seconds = 0;
|
||||||
|
|
||||||
for (size_t i=2; i<argv.size(); ++i) {
|
for (size_t i = 2; i < argv.size(); ++i) {
|
||||||
if (argv[i]=="-der") {
|
if (argv[i] == "-der") {
|
||||||
use_pem = false;
|
use_pem = false;
|
||||||
} else if (argv[i]=="-in") {
|
}
|
||||||
|
else if (argv[i] == "-in") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
@ -98,24 +92,26 @@ auto checkend(const argv_view & argv) -> int
|
|||||||
|
|
||||||
if (!crtpath.empty()) {
|
if (!crtpath.empty()) {
|
||||||
if (argv[i] == crtpath) {
|
if (argv[i] == crtpath) {
|
||||||
std::cerr<<"checkend warning: repeated same -in file\n";
|
std::cerr << "checkend warning: repeated same -in file\n";
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("checkend error: more than one -in file");
|
throw std::runtime_error("checkend error: more than one -in file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crtpath = argv[i];
|
crtpath = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i][0]=='-') {
|
else if (argv[i][0] == '-') {
|
||||||
std::cerr<<"checkend warning: skipping option "<<argv[i]<<std::endl;
|
std::cerr << "checkend warning: skipping option " << argv[i] << std::endl;
|
||||||
} else { // main option:
|
}
|
||||||
|
else { // main option:
|
||||||
intmax_t num = 0;
|
intmax_t num = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
num = parse_int(argv[i]);
|
num = parse_int(argv[i]);
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...) {
|
||||||
auto errmsg = std::string{"checkend error: invalid time "};
|
auto errmsg = std::string{"checkend error: invalid time "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
std::throw_with_nested(std::runtime_error(errmsg));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
@ -123,7 +119,7 @@ auto checkend(const argv_view & argv) -> int
|
|||||||
|
|
||||||
seconds = static_cast<time_t>(num);
|
seconds = static_cast<time_t>(num);
|
||||||
|
|
||||||
if (num!=static_cast<intmax_t>(seconds)) {
|
if (num != static_cast<intmax_t>(seconds)) {
|
||||||
auto errmsg = std::string{"checkend error: time too big "};
|
auto errmsg = std::string{"checkend error: time too big "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
@ -132,23 +128,23 @@ auto checkend(const argv_view & argv) -> int
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool valid = checkend(crtpath, seconds, use_pem);
|
bool valid = checkend(crtpath, seconds, use_pem);
|
||||||
std::cout<<"Certificate will"<<(valid ? " not " : " ")<<"expire"<<std::endl;
|
std::cout << "Certificate will" << (valid ? " not " : " ") << "expire" << std::endl;
|
||||||
|
|
||||||
return (valid ? 0 : 1);
|
return (valid ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eckey(const argv_view& argv)
|
||||||
void eckey(const argv_view & argv)
|
|
||||||
{
|
{
|
||||||
bool has_main_option = false;
|
bool has_main_option = false;
|
||||||
bool use_pem = true;
|
bool use_pem = true;
|
||||||
std::string keypath{};
|
std::string keypath{};
|
||||||
int curve = NID_X9_62_prime256v1;
|
int curve = NID_X9_62_prime256v1;
|
||||||
|
|
||||||
for (size_t i=2; i < argv.size(); ++i) {
|
for (size_t i = 2; i < argv.size(); ++i) {
|
||||||
if (argv[i]=="-der") {
|
if (argv[i] == "-der") {
|
||||||
use_pem = false;
|
use_pem = false;
|
||||||
} else if (argv[i]=="-out") {
|
}
|
||||||
|
else if (argv[i] == "-out") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
@ -156,25 +152,25 @@ void eckey(const argv_view & argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!keypath.empty()) {
|
if (!keypath.empty()) {
|
||||||
if (argv[i]==keypath) {
|
if (argv[i] == keypath) {
|
||||||
std::cerr<<"eckey warning: repeated same -out file\n";
|
std::cerr << "eckey warning: repeated same -out file\n";
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("eckey error: more than one -out file");
|
throw std::runtime_error("eckey error: more than one -out file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keypath = argv[i];
|
keypath = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i][0]=='-') {
|
else if (argv[i][0] == '-') {
|
||||||
std::cerr<<"eckey warning: skipping option "<<argv[i]<<std::endl;
|
std::cerr << "eckey warning: skipping option " << argv[i] << std::endl;
|
||||||
} else { //main option:
|
}
|
||||||
|
else { // main option:
|
||||||
|
|
||||||
if (has_main_option) {
|
if (has_main_option) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("eckey error: more than one main option");
|
||||||
("eckey error: more than one main option");
|
} // else:
|
||||||
} //else:
|
|
||||||
has_main_option = true;
|
has_main_option = true;
|
||||||
|
|
||||||
curve = parse_curve(argv[i]);
|
curve = parse_curve(argv[i]);
|
||||||
@ -184,8 +180,7 @@ void eckey(const argv_view & argv)
|
|||||||
write_key(gen_eckey(curve), keypath, use_pem);
|
write_key(gen_eckey(curve), keypath, use_pem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rsakey(const argv_view& argv)
|
||||||
void rsakey(const argv_view & argv)
|
|
||||||
{
|
{
|
||||||
bool has_main_option = false;
|
bool has_main_option = false;
|
||||||
bool use_pem = true;
|
bool use_pem = true;
|
||||||
@ -193,12 +188,14 @@ void rsakey(const argv_view & argv)
|
|||||||
BN_ULONG exponent = RSA_F4;
|
BN_ULONG exponent = RSA_F4;
|
||||||
int keysize = rsa_min_modulus_bits;
|
int keysize = rsa_min_modulus_bits;
|
||||||
|
|
||||||
for (size_t i=2; i < argv.size(); ++i) {
|
for (size_t i = 2; i < argv.size(); ++i) {
|
||||||
if (argv[i]=="-der") {
|
if (argv[i] == "-der") {
|
||||||
use_pem = false;
|
use_pem = false;
|
||||||
} else if (argv[i]=="-3") {
|
}
|
||||||
|
else if (argv[i] == "-3") {
|
||||||
exponent = 3;
|
exponent = 3;
|
||||||
} else if (argv[i]=="-out") {
|
}
|
||||||
|
else if (argv[i] == "-out") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
@ -206,29 +203,31 @@ void rsakey(const argv_view & argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!keypath.empty()) {
|
if (!keypath.empty()) {
|
||||||
if (argv[i]==keypath) {
|
if (argv[i] == keypath) {
|
||||||
std::cerr<<"rsakey warning: repeated -out file"<<std::endl;
|
std::cerr << "rsakey warning: repeated -out file" << std::endl;
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("rsakey error: more than one -out file");
|
throw std::runtime_error("rsakey error: more than one -out file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keypath = argv[i];
|
keypath = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i][0]=='-') {
|
else if (argv[i][0] == '-') {
|
||||||
std::cerr<<"rsakey warning: skipping option "<<argv[i]<<std::endl;
|
std::cerr << "rsakey warning: skipping option " << argv[i] << std::endl;
|
||||||
} else { //main option:
|
}
|
||||||
|
else { // main option:
|
||||||
|
|
||||||
if (has_main_option) {
|
if (has_main_option) {
|
||||||
throw std::runtime_error("rsakey error: more than one keysize");
|
throw std::runtime_error("rsakey error: more than one keysize");
|
||||||
} //else:
|
} // else:
|
||||||
has_main_option = true;
|
has_main_option = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
keysize = parse_int(argv[i]);
|
keysize = parse_int(argv[i]);
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...) {
|
||||||
std::string errmsg{"rsakey error: invalid keysize "};
|
std::string errmsg{"rsakey error: invalid keysize "};
|
||||||
errmsg += argv[i];
|
errmsg += argv[i];
|
||||||
std::throw_with_nested(std::runtime_error(errmsg));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
@ -239,8 +238,7 @@ void rsakey(const argv_view & argv)
|
|||||||
write_key(gen_rsakey(keysize, exponent), keypath, use_pem);
|
write_key(gen_rsakey(keysize, exponent), keypath, use_pem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selfsigned(const argv_view& argv)
|
||||||
void selfsigned(const argv_view & argv)
|
|
||||||
{
|
{
|
||||||
bool use_pem = true;
|
bool use_pem = true;
|
||||||
int days = default_validity;
|
int days = default_validity;
|
||||||
@ -254,56 +252,58 @@ void selfsigned(const argv_view & argv)
|
|||||||
|
|
||||||
int curve = NID_X9_62_prime256v1;
|
int curve = NID_X9_62_prime256v1;
|
||||||
|
|
||||||
for (size_t i=2; i < argv.size(); ++i) {
|
for (size_t i = 2; i < argv.size(); ++i) {
|
||||||
if (argv[i]=="-der") {
|
if (argv[i] == "-der") {
|
||||||
use_pem = false;
|
use_pem = false;
|
||||||
} else if (argv[i]=="-days") {
|
}
|
||||||
|
else if (argv[i] == "-days") {
|
||||||
++i;
|
++i;
|
||||||
try {
|
try {
|
||||||
days = parse_int(argv[i]);
|
days = parse_int(argv[i]);
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...) {
|
||||||
std::string errmsg{"selfsigned error: not a number for -days "};
|
std::string errmsg{"selfsigned error: not a number for -days "};
|
||||||
errmsg += argv[i].substr(4);
|
errmsg += argv[i].substr(4);
|
||||||
std::throw_with_nested(std::runtime_error(errmsg));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i]=="-newkey") {
|
else if (argv[i] == "-newkey") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("selfsigned error: -newkey misses algorithm option");
|
||||||
("selfsigned error: -newkey misses algorithm option");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto rsa_prefix = std::string_view{"rsa:"};
|
static constexpr auto rsa_prefix = std::string_view{"rsa:"};
|
||||||
|
|
||||||
if (argv[i]=="ec") {
|
if (argv[i] == "ec") {
|
||||||
use_rsa = false;
|
use_rsa = false;
|
||||||
} else if (argv[i].rfind(rsa_prefix, 0) == 0) {
|
}
|
||||||
|
else if (argv[i].rfind(rsa_prefix, 0) == 0) {
|
||||||
use_rsa = true;
|
use_rsa = true;
|
||||||
try {
|
try {
|
||||||
keysize = parse_int(argv[i].substr(rsa_prefix.size()));
|
keysize = parse_int(argv[i].substr(rsa_prefix.size()));
|
||||||
} catch (...) {
|
}
|
||||||
|
catch (...) {
|
||||||
std::string errmsg{"selfsigned error: invalid keysize "};
|
std::string errmsg{"selfsigned error: invalid keysize "};
|
||||||
errmsg += argv[i].substr(4);
|
errmsg += argv[i].substr(4);
|
||||||
std::throw_with_nested(std::runtime_error(errmsg));
|
std::throw_with_nested(std::runtime_error(errmsg));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
throw std::runtime_error("selfsigned error: invalid algorithm");
|
throw std::runtime_error("selfsigned error: invalid algorithm");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i]=="-pkeyopt") {
|
else if (argv[i] == "-pkeyopt") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("selfsigned error: -pkeyopt misses value");
|
||||||
("selfsigned error: -pkeyopt misses value");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto curve_prefix =
|
static constexpr auto curve_prefix = std::string_view{"ec_paramgen_curve:"};
|
||||||
std::string_view{"ec_paramgen_curve:"};
|
|
||||||
|
|
||||||
if (argv[i].rfind(curve_prefix, 0) != 0) {
|
if (argv[i].rfind(curve_prefix, 0) != 0) {
|
||||||
throw std::runtime_error("selfsigned error: -pkeyopt invalid");
|
throw std::runtime_error("selfsigned error: -pkeyopt invalid");
|
||||||
@ -312,60 +312,57 @@ void selfsigned(const argv_view & argv)
|
|||||||
curve = parse_curve(argv[i].substr(curve_prefix.size()));
|
curve = parse_curve(argv[i].substr(curve_prefix.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i]=="-keyout") {
|
else if (argv[i] == "-keyout") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("selfsigned error: -keyout misses path");
|
||||||
("selfsigned error: -keyout misses path");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!keypath.empty()) {
|
if (!keypath.empty()) {
|
||||||
if (argv[i]==keypath) {
|
if (argv[i] == keypath) {
|
||||||
std::cerr<<"selfsigned warning: repeated -keyout file\n";
|
std::cerr << "selfsigned warning: repeated -keyout file\n";
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("selfsigned error: more than one -keyout file");
|
throw std::runtime_error("selfsigned error: more than one -keyout file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keypath = argv[i];
|
keypath = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i]=="-out") {
|
else if (argv[i] == "-out") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("selfsigned error: -out misses filename");
|
||||||
("selfsigned error: -out misses filename");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crtpath.empty()) {
|
if (!crtpath.empty()) {
|
||||||
if (argv[i]==crtpath) {
|
if (argv[i] == crtpath) {
|
||||||
std::cerr<<"selfsigned warning: repeated same -out file\n";
|
std::cerr << "selfsigned warning: repeated same -out file\n";
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("selfsigned error: more than one -out file");
|
throw std::runtime_error("selfsigned error: more than one -out file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crtpath = argv[i];
|
crtpath = argv[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (argv[i]=="-subj") {
|
else if (argv[i] == "-subj") {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (i >= argv.size()) {
|
if (i >= argv.size()) {
|
||||||
throw std::runtime_error
|
throw std::runtime_error("selfsigned error: -subj misses value");
|
||||||
("selfsigned error: -subj misses value");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!subject.empty()) {
|
if (!subject.empty()) {
|
||||||
if (argv[i]==subject) {
|
if (argv[i] == subject) {
|
||||||
std::cerr<<"selfsigned warning: repeated same -subj\n";
|
std::cerr << "selfsigned warning: repeated same -subj\n";
|
||||||
} else {
|
}
|
||||||
throw std::runtime_error
|
else {
|
||||||
("selfsigned error: more than one -subj value");
|
throw std::runtime_error("selfsigned error: more than one -subj value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +370,7 @@ void selfsigned(const argv_view & argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
std::cerr<<"selfsigned warning: skipping option "<<argv[i]<<std::endl;
|
std::cerr << "selfsigned warning: skipping option " << argv[i] << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,60 +378,70 @@ void selfsigned(const argv_view & argv)
|
|||||||
|
|
||||||
selfsigned(pkey, days, subject, crtpath, use_pem);
|
selfsigned(pkey, days, subject, crtpath, use_pem);
|
||||||
|
|
||||||
if (!keypath.empty()) { write_key(pkey, keypath, use_pem); }
|
if (!keypath.empty()) {
|
||||||
|
write_key(pkey, keypath, use_pem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto main(int argc, const char** argv) -> int
|
||||||
auto main(int argc, const char ** argv) -> int
|
|
||||||
{
|
{
|
||||||
auto args = argv_view{argv, argc};
|
auto args = argv_view{argv, argc};
|
||||||
|
|
||||||
auto cmds = std::array{
|
auto cmds = std::array{
|
||||||
std::array<std::string, 2>{"checkend",
|
std::array<std::string, 2>{"checkend",
|
||||||
" [-der] [-in certificate_path] [seconds_remaining]"
|
" [-der] [-in certificate_path] [seconds_remaining]"},
|
||||||
},
|
std::array<std::string, 2>{"eckey", " [-der] [-out key_path] [curve_name]"},
|
||||||
std::array<std::string, 2>{"eckey",
|
std::array<std::string, 2>{"rsakey", " [-der] [-out key_path] [-3] [key_size]"},
|
||||||
" [-der] [-out key_path] [curve_name]"
|
std::array<std::string, 2>{
|
||||||
},
|
"selfsigned",
|
||||||
std::array<std::string, 2>{"rsakey",
|
|
||||||
" [-der] [-out key_path] [-3] [key_size]"
|
|
||||||
},
|
|
||||||
std::array<std::string, 2>{"selfsigned",
|
|
||||||
" [-der] [-keyout key_path] [-out certificate_path]"
|
" [-der] [-keyout key_path] [-out certificate_path]"
|
||||||
" [-newkey ec|rsa:key_size] [-pkeyopt ec_paramgen_curve:name]"
|
" [-newkey ec|rsa:key_size] [-pkeyopt ec_paramgen_curve:name]"
|
||||||
" [-days validity] [-subj /C=.../ST=.../L=.../O=.../CN=.../... ]"
|
" [-days validity] [-subj /C=.../ST=.../L=.../O=.../CN=.../... ]"},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (argc < 2) { throw std::runtime_error("error: no argument"); }
|
if (argc < 2) {
|
||||||
|
throw std::runtime_error("error: no argument");
|
||||||
if (args[1]==cmds[0][0]) {return checkend(args);}
|
|
||||||
|
|
||||||
if (args[1]==cmds[1][0]) { eckey(args); }
|
|
||||||
|
|
||||||
else if (args[1]==cmds[2][0]) { rsakey(args); }
|
|
||||||
|
|
||||||
else if (args[1]==cmds[3][0]) { selfsigned(args); }
|
|
||||||
|
|
||||||
else { throw std::runtime_error("error: argument not recognized"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (const std::exception & e) {
|
|
||||||
|
|
||||||
auto usage = std::string{"usage: \n"} ;
|
|
||||||
for (auto cmd : cmds) {
|
|
||||||
usage += std::string{4, ' '} + *argv +" "+ cmd[0] + cmd[1] +"\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<usage<<std::flush;
|
if (args[1] == cmds[0][0]) {
|
||||||
|
return checkend(args);
|
||||||
|
}
|
||||||
|
|
||||||
auto print_nested =
|
if (args[1] == cmds[1][0]) {
|
||||||
[](auto && self, const std::exception & outer, int depth=0) -> void
|
eckey(args);
|
||||||
{
|
}
|
||||||
std::cerr<<std::string(depth, '\t')<<outer.what()<<std::endl;
|
|
||||||
try { std::rethrow_if_nested(outer); }
|
else if (args[1] == cmds[2][0]) {
|
||||||
catch (const std::exception & inner) { self(self, inner, depth+1); }
|
rsakey(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (args[1] == cmds[3][0]) {
|
||||||
|
selfsigned(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("error: argument not recognized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
auto usage = std::accumulate(
|
||||||
|
cmds.begin(), cmds.end(), std::string{"usage: \n"},
|
||||||
|
[=](const auto& use, const auto& cmd) {
|
||||||
|
return use + std::string{4, ' '} + *argv + " " + cmd[0] + cmd[1] + "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cerr << usage << std::flush;
|
||||||
|
|
||||||
|
auto print_nested = [](auto&& self, const std::exception& outer, int depth = 0) -> void {
|
||||||
|
std::cerr << std::string(depth, '\t') << outer.what() << std::endl;
|
||||||
|
try {
|
||||||
|
std::rethrow_if_nested(outer);
|
||||||
|
}
|
||||||
|
catch (const std::exception& inner) {
|
||||||
|
self(self, inner, depth + 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
print_nested(print_nested, e);
|
print_nested(print_nested, e);
|
||||||
@ -443,7 +450,7 @@ auto main(int argc, const char ** argv) -> int
|
|||||||
}
|
}
|
||||||
|
|
||||||
catch (...) {
|
catch (...) {
|
||||||
std::cerr<<*argv<<" unknown error."<<std::endl;
|
std::cerr << *argv << " unknown error." << std::endl;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,298 +1,279 @@
|
|||||||
#ifndef __REGEXP_PCRE_HPP
|
#ifndef __REGEXP_PCRE_HPP
|
||||||
#define __REGEXP_PCRE_HPP
|
#define __REGEXP_PCRE_HPP
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
#include <array>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace rgx {
|
namespace rgx {
|
||||||
/* partially implement the std::regex interface using PCRE for performance
|
/* partially implement the std::regex interface using PCRE for performance
|
||||||
* (=> pass "match" as non-const reference)
|
* (=> pass "match" as non-const reference)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace regex_constants {
|
namespace regex_constants {
|
||||||
enum error_type
|
enum error_type {
|
||||||
{
|
_enum_error_collate,
|
||||||
_enum_error_collate,
|
_enum_error_ctype,
|
||||||
_enum_error_ctype,
|
_enum_error_escape,
|
||||||
_enum_error_escape,
|
_enum_error_backref,
|
||||||
_enum_error_backref,
|
_enum_error_brack,
|
||||||
_enum_error_brack,
|
_enum_error_paren,
|
||||||
_enum_error_paren,
|
_enum_error_brace,
|
||||||
_enum_error_brace,
|
_enum_error_badbrace,
|
||||||
_enum_error_badbrace,
|
_enum_error_range,
|
||||||
_enum_error_range,
|
_enum_error_space,
|
||||||
_enum_error_space,
|
_enum_error_badrepeat,
|
||||||
_enum_error_badrepeat,
|
_enum_error_complexity,
|
||||||
_enum_error_complexity,
|
_enum_error_stack,
|
||||||
_enum_error_stack,
|
_enum_error_last
|
||||||
_enum_error_last
|
};
|
||||||
};
|
static const error_type error_collate(_enum_error_collate);
|
||||||
static const error_type error_collate(_enum_error_collate);
|
static const error_type error_ctype(_enum_error_ctype);
|
||||||
static const error_type error_ctype(_enum_error_ctype);
|
static const error_type error_escape(_enum_error_escape);
|
||||||
static const error_type error_escape(_enum_error_escape);
|
static const error_type error_backref(_enum_error_backref);
|
||||||
static const error_type error_backref(_enum_error_backref);
|
static const error_type error_brack(_enum_error_brack);
|
||||||
static const error_type error_brack(_enum_error_brack);
|
static const error_type error_paren(_enum_error_paren);
|
||||||
static const error_type error_paren(_enum_error_paren);
|
static const error_type error_brace(_enum_error_brace);
|
||||||
static const error_type error_brace(_enum_error_brace);
|
static const error_type error_badbrace(_enum_error_badbrace);
|
||||||
static const error_type error_badbrace(_enum_error_badbrace);
|
static const error_type error_range(_enum_error_range);
|
||||||
static const error_type error_range(_enum_error_range);
|
static const error_type error_space(_enum_error_space);
|
||||||
static const error_type error_space(_enum_error_space);
|
static const error_type error_badrepeat(_enum_error_badrepeat);
|
||||||
static const error_type error_badrepeat(_enum_error_badrepeat);
|
static const error_type error_complexity(_enum_error_complexity);
|
||||||
static const error_type error_complexity(_enum_error_complexity);
|
static const error_type error_stack(_enum_error_stack);
|
||||||
static const error_type error_stack(_enum_error_stack);
|
} // namespace regex_constants
|
||||||
} // namespace regex_constants
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class regex_error : public std::runtime_error {
|
class regex_error : public std::runtime_error {
|
||||||
|
private:
|
||||||
private:
|
|
||||||
|
|
||||||
regex_constants::error_type errcode;
|
regex_constants::error_type errcode;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit regex_error(regex_constants::error_type code, const char* what = "regex error")
|
||||||
|
: runtime_error(what), errcode(code)
|
||||||
|
{}
|
||||||
|
|
||||||
public:
|
[[nodiscard]] auto virtual code() const -> regex_constants::error_type;
|
||||||
|
|
||||||
explicit regex_error(regex_constants::error_type code,
|
|
||||||
const char * what="regex error")
|
|
||||||
: runtime_error(what), errcode(code)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] auto code() const -> regex_constants::error_type
|
|
||||||
{ return errcode; }
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] auto regex_error::code() const -> regex_constants::error_type
|
||||||
|
{
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
class regex {
|
class regex {
|
||||||
|
private:
|
||||||
private:
|
|
||||||
|
|
||||||
int errcode = 0;
|
int errcode = 0;
|
||||||
|
|
||||||
const char * errptr = nullptr;
|
const char* errptr = nullptr;
|
||||||
|
|
||||||
int erroffset = 0;
|
int erroffset = 0;
|
||||||
|
|
||||||
pcre * const re = nullptr;
|
pcre* const re = nullptr;
|
||||||
|
|
||||||
static const std::array<regex_constants::error_type,86> errcode_pcre2regex;
|
static const std::array<regex_constants::error_type, 86> errcode_pcre2regex;
|
||||||
|
|
||||||
static const auto BASE = 10;
|
static const auto BASE = 10;
|
||||||
|
|
||||||
|
public:
|
||||||
public:
|
|
||||||
|
|
||||||
inline regex() = default;
|
inline regex() = default;
|
||||||
|
|
||||||
|
inline regex(const regex&) = delete;
|
||||||
|
|
||||||
inline regex(const regex &) = delete;
|
inline regex(regex&&) = default;
|
||||||
|
|
||||||
|
inline auto operator=(const regex&) -> regex& = delete;
|
||||||
|
|
||||||
inline regex(regex &&) = default;
|
inline auto operator=(regex &&) -> regex& = delete;
|
||||||
|
|
||||||
|
explicit regex(const std::string& str) : regex(str.c_str()) {}
|
||||||
|
|
||||||
inline auto operator=(const regex &) -> regex & = delete;
|
explicit regex(const char* const str)
|
||||||
|
: re{pcre_compile2(str, 0, &errcode, &errptr, &erroffset, nullptr)}
|
||||||
|
|
||||||
inline auto operator=(regex &&) -> regex & = delete;
|
|
||||||
|
|
||||||
|
|
||||||
explicit regex(const std::string & str)
|
|
||||||
: re{ pcre_compile2(str.c_str(), 0, &errcode, &errptr, &erroffset,nullptr) }
|
|
||||||
{
|
{
|
||||||
if (re==nullptr) {
|
if (re == nullptr) {
|
||||||
std::string what = std::string("regex error: ") + errptr + '\n';
|
std::string what = std::string("regex error: ") + errptr + '\n';
|
||||||
what += " '" + str + "'\n";
|
what += " '" + std::string{str} + "'\n";
|
||||||
what += " " + std::string(erroffset, ' ') + '^';
|
what += " " + std::string(erroffset, ' ') + '^';
|
||||||
|
|
||||||
throw regex_error(errcode_pcre2regex.at(errcode), what.c_str());
|
throw regex_error(errcode_pcre2regex.at(errcode), what.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~regex()
|
||||||
|
{
|
||||||
|
if (re != nullptr) {
|
||||||
|
pcre_free(re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~regex() { if (re != nullptr) { pcre_free(re); } }
|
inline auto operator()() const -> const pcre*
|
||||||
|
{
|
||||||
|
return re;
|
||||||
inline auto operator()() const -> const pcre * { return re; }
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class smatch {
|
class smatch {
|
||||||
|
|
||||||
friend auto regex_search(std::string::const_iterator begin,
|
friend auto regex_search(std::string::const_iterator begin,
|
||||||
std::string::const_iterator end,
|
std::string::const_iterator end,
|
||||||
smatch & match, //NOLINT(google-runtime-references)
|
smatch& match, // NOLINT(google-runtime-references)
|
||||||
const regex & rgx); // match std::regex interface.
|
const regex& rgx); // match std::regex interface.
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
|
private:
|
||||||
std::string::const_iterator begin;
|
std::string::const_iterator begin;
|
||||||
|
|
||||||
std::string::const_iterator end;
|
std::string::const_iterator end;
|
||||||
|
|
||||||
std::vector <int> vec{};
|
std::vector<int> vec{};
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
public:
|
[[nodiscard]] inline auto position(int i = 0) const
|
||||||
|
{
|
||||||
[[nodiscard]] inline auto position(int i=0) const {
|
return (i < 0 || i >= n) ? std::string::npos : vec[2 * i];
|
||||||
return (i<0 || i>=n) ? std::string::npos : vec[2*i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto length(int i = 0) const
|
||||||
[[nodiscard]] inline auto length(int i=0) const {
|
{
|
||||||
return (i<0 || i>=n) ? 0 : vec[2*i+1] - vec[2*i];
|
return (i < 0 || i >= n) ? 0 : vec[2 * i + 1] - vec[2 * i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto str(int i = 0) const -> std::string
|
||||||
[[nodiscard]] auto str(int i=0) const -> std::string { // should we throw?
|
{ // should we throw?
|
||||||
if (i<0 || i>=n) { return ""; }
|
if (i < 0 || i >= n) {
|
||||||
int x = vec[2*i];
|
return "";
|
||||||
if (x<0) { return ""; }
|
}
|
||||||
int y = vec[2*i+1];
|
int x = vec[2 * i];
|
||||||
|
if (x < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int y = vec[2 * i + 1];
|
||||||
return std::string{begin + x, begin + y};
|
return std::string{begin + x, begin + y};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto format(const std::string& fmt) const;
|
||||||
|
|
||||||
[[nodiscard]] auto format(const std::string & fmt) const;
|
[[nodiscard]] auto size() const -> int
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto empty() const
|
||||||
|
{
|
||||||
|
return n < 0;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto size() const -> int { return n; }
|
[[nodiscard]] inline auto ready() const
|
||||||
|
{
|
||||||
|
return !vec.empty();
|
||||||
[[nodiscard]] inline auto empty() const { return n<0; }
|
}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] inline auto ready() const { return !vec.empty(); }
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline auto regex_search(const std::string& subj, const regex& rgx);
|
||||||
|
|
||||||
inline auto regex_search(const std::string & subj, const regex & rgx);
|
auto regex_replace(const std::string& subj, const regex& rgx, const std::string& insert);
|
||||||
|
|
||||||
|
|
||||||
auto regex_replace(const std::string & subj,
|
|
||||||
const regex & rgx,
|
|
||||||
const std::string & insert);
|
|
||||||
|
|
||||||
|
|
||||||
inline auto regex_search(const std::string & subj,
|
|
||||||
smatch & match, //NOLINT(google-runtime-references)
|
|
||||||
const regex & rgx); // match std::regex interface.
|
|
||||||
|
|
||||||
|
inline auto regex_search(const std::string& subj,
|
||||||
|
smatch& match, // NOLINT(google-runtime-references)
|
||||||
|
const regex& rgx); // match std::regex interface.
|
||||||
|
|
||||||
auto regex_search(std::string::const_iterator begin,
|
auto regex_search(std::string::const_iterator begin,
|
||||||
std::string::const_iterator end,
|
std::string::const_iterator end,
|
||||||
smatch & match, //NOLINT(google-runtime-references)
|
smatch& match, // NOLINT(google-runtime-references)
|
||||||
const regex & rgx); // match std::regex interface.
|
const regex& rgx); // match std::regex interface.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------- implementation: ----------------------------------
|
// ------------------------- implementation: ----------------------------------
|
||||||
|
|
||||||
|
inline auto regex_search(const std::string& subj, const regex& rgx)
|
||||||
inline auto regex_search(const std::string & subj, const regex & rgx)
|
|
||||||
{
|
{
|
||||||
if (rgx()==nullptr) {
|
if (rgx() == nullptr) {
|
||||||
throw std::runtime_error("regex_search error: no regex given");
|
throw std::runtime_error("regex_search error: no regex given");
|
||||||
}
|
}
|
||||||
int n = pcre_exec(rgx(), nullptr, subj.c_str(), subj.length(),
|
int n =
|
||||||
0, 0, nullptr, 0);
|
pcre_exec(rgx(), nullptr, subj.c_str(), static_cast<int>(subj.length()), 0, 0, nullptr, 0);
|
||||||
return n>=0;
|
return n >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto regex_search(const std::string::const_iterator begin,
|
auto regex_search(const std::string::const_iterator begin,
|
||||||
const std::string::const_iterator end,
|
const std::string::const_iterator end,
|
||||||
smatch & match,
|
smatch& match,
|
||||||
const regex & rgx)
|
const regex& rgx)
|
||||||
{
|
{
|
||||||
if (rgx()==nullptr) {
|
if (rgx() == nullptr) {
|
||||||
throw std::runtime_error("regex_search error: no regex given");
|
throw std::runtime_error("regex_search error: no regex given");
|
||||||
}
|
}
|
||||||
|
|
||||||
int sz = 0;
|
int sz = 0;
|
||||||
pcre_fullinfo(rgx(), nullptr, PCRE_INFO_CAPTURECOUNT, &sz);
|
pcre_fullinfo(rgx(), nullptr, PCRE_INFO_CAPTURECOUNT, &sz);
|
||||||
sz = 3*(sz + 1);
|
sz = 3 * (sz + 1);
|
||||||
|
|
||||||
match.vec.reserve(sz);
|
match.vec.reserve(sz);
|
||||||
|
|
||||||
const char * subj = &*begin;
|
const char* subj = &*begin;
|
||||||
size_t len = &*end - subj;
|
int len = static_cast<int>(&*end - subj);
|
||||||
|
|
||||||
match.begin = begin;
|
match.begin = begin;
|
||||||
match.end = end;
|
match.end = end;
|
||||||
|
|
||||||
match.n = pcre_exec(rgx(), nullptr, subj, len, 0, 0, &match.vec[0], sz);
|
match.n = pcre_exec(rgx(), nullptr, subj, len, 0, 0, &match.vec[0], sz);
|
||||||
|
|
||||||
if (match.n<0) { return false; }
|
if (match.n < 0) {
|
||||||
if (match.n==0) { match.n = sz/3; }
|
return false;
|
||||||
|
}
|
||||||
|
if (match.n == 0) {
|
||||||
|
match.n = sz / 3;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto regex_search(const std::string& subj, smatch& match, const regex& rgx)
|
||||||
inline auto regex_search(const std::string & subj, smatch & match,
|
|
||||||
const regex & rgx)
|
|
||||||
{
|
{
|
||||||
return regex_search(subj.begin(), subj.end(), match, rgx);
|
return regex_search(subj.begin(), subj.end(), match, rgx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto smatch::format(const std::string& fmt) const
|
||||||
auto smatch::format(const std::string & fmt) const {
|
{
|
||||||
std::string ret{};
|
std::string ret{};
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
|
||||||
size_t pos;
|
size_t pos = 0;
|
||||||
while ((pos=fmt.find('$', index)) != std::string::npos) {
|
while ((pos = fmt.find('$', index)) != std::string::npos) {
|
||||||
ret.append(fmt, index, pos-index);
|
ret.append(fmt, index, pos - index);
|
||||||
index = pos + 1;
|
index = pos + 1;
|
||||||
|
|
||||||
char chr = fmt[index++];
|
char chr = fmt[index++];
|
||||||
switch(chr) {
|
switch (chr) {
|
||||||
|
case '&': // match
|
||||||
case '&': // match
|
|
||||||
ret += str(0);
|
ret += str(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '`': // prefix
|
case '`': // prefix
|
||||||
ret.append(begin, begin+vec[0]);
|
ret.append(begin, begin + vec[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\'': // suffix
|
case '\'': // suffix
|
||||||
ret.append(begin+vec[1], end);
|
ret.append(begin + vec[1], end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (isdigit(chr) != 0) { // one or two digits => submatch:
|
if (isdigit(chr) != 0) { // one or two digits => submatch:
|
||||||
int num = chr - '0';
|
int num = chr - '0';
|
||||||
chr = fmt[index];
|
chr = fmt[index];
|
||||||
if (isdigit(chr) != 0) { // second digit:
|
if (isdigit(chr) != 0) { // second digit:
|
||||||
++index;
|
++index;
|
||||||
static const auto base = 10;
|
static const auto base = 10;
|
||||||
num = num*base + chr - '0';
|
num = num * base + chr - '0';
|
||||||
}
|
}
|
||||||
ret += str(num);
|
ret += str(num);
|
||||||
break;
|
break;
|
||||||
} //else:
|
} // else:
|
||||||
|
|
||||||
ret += '$';
|
ret += '$';
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case '$': // escaped
|
case '$': // escaped
|
||||||
ret += chr;
|
ret += chr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,20 +281,16 @@ auto smatch::format(const std::string & fmt) const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto regex_replace(const std::string& subj, const regex& rgx, const std::string& insert)
|
||||||
auto regex_replace(const std::string & subj,
|
|
||||||
const regex & rgx,
|
|
||||||
const std::string & insert)
|
|
||||||
{
|
{
|
||||||
if (rgx()==nullptr) {
|
if (rgx() == nullptr) {
|
||||||
throw std::runtime_error("regex_replace error: no regex given");
|
throw std::runtime_error("regex_replace error: no regex given");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ret{};
|
std::string ret{};
|
||||||
auto pos = subj.begin();
|
auto pos = subj.begin();
|
||||||
|
|
||||||
for (smatch match;
|
for (smatch match; regex_search(pos, subj.end(), match, rgx);
|
||||||
regex_search(pos, subj.end(), match, rgx);
|
|
||||||
pos += match.position(0) + match.length(0))
|
pos += match.position(0) + match.length(0))
|
||||||
{
|
{
|
||||||
ret.append(pos, pos + match.position(0));
|
ret.append(pos, pos + match.position(0));
|
||||||
@ -324,11 +301,8 @@ auto regex_replace(const std::string & subj,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------ There is only the translation table below : -------------------
|
// ------------ There is only the translation table below : -------------------
|
||||||
|
|
||||||
|
|
||||||
const std::array<regex_constants::error_type, 86> regex::errcode_pcre2regex = {
|
const std::array<regex_constants::error_type, 86> regex::errcode_pcre2regex = {
|
||||||
// 0 no error
|
// 0 no error
|
||||||
regex_constants::error_type::_enum_error_last,
|
regex_constants::error_type::_enum_error_last,
|
||||||
@ -444,7 +418,8 @@ const std::array<regex_constants::error_type, 86> regex::errcode_pcre2regex = {
|
|||||||
regex_constants::error_backref,
|
regex_constants::error_backref,
|
||||||
// 56 inconsistent NEWLINE options
|
// 56 inconsistent NEWLINE options
|
||||||
regex_constants::error_escape,
|
regex_constants::error_escape,
|
||||||
// 57 \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number
|
// 57 \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain
|
||||||
|
// number
|
||||||
regex_constants::error_backref,
|
regex_constants::error_backref,
|
||||||
// 58 a numbered reference must not be zero
|
// 58 a numbered reference must not be zero
|
||||||
regex_constants::error_backref,
|
regex_constants::error_backref,
|
||||||
@ -501,11 +476,8 @@ const std::array<regex_constants::error_type, 86> regex::errcode_pcre2regex = {
|
|||||||
// 84 group name must start with a non-digit
|
// 84 group name must start with a non-digit
|
||||||
regex_constants::error_backref,
|
regex_constants::error_backref,
|
||||||
// 85 parentheses are too deeply nested (stack check)
|
// 85 parentheses are too deeply nested (stack check)
|
||||||
regex_constants::error_stack
|
regex_constants::error_stack};
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace rgx
|
|
||||||
|
|
||||||
|
} // namespace rgx
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,57 @@ PRINT_PASSED=2
|
|||||||
|
|
||||||
NGINX_UTIL="/usr/bin/nginx-util"
|
NGINX_UTIL="/usr/bin/nginx-util"
|
||||||
|
|
||||||
|
ORIG=".original-test-nginx-util-root"
|
||||||
|
|
||||||
|
mkdir -p /tmp/.uci/
|
||||||
|
|
||||||
|
uci commit nginx || { printf "Error invoking: uci commit\n Exit."; exit 2; }
|
||||||
|
|
||||||
|
|
||||||
|
pst_exit() {
|
||||||
|
printf "\nExit: Recovering original settings ... "
|
||||||
|
|
||||||
|
uci revert nginx
|
||||||
|
|
||||||
|
cd "/etc/config/" && rm "nginx" && mv "nginx.${ORIG}" "nginx" ||
|
||||||
|
printf "\n%s: not moved %s to %s\n" "/etc/config/" "nginx${ORIG}" "nginx"
|
||||||
|
|
||||||
|
cd "/etc/crontabs/" && rm "root" && mv "root${ORIG}" "root" ||
|
||||||
|
printf "\n%s: not moved %s to %s\n" "/etc/crontabs/" "root${ORIG}" "root"
|
||||||
|
|
||||||
|
cd "$(dirname "${CONF_DIR}")" && rm -r "${CONF_DIR}" &&
|
||||||
|
mv "$(basename "${CONF_DIR}")${ORIG}" "$(basename "${CONF_DIR}")" ||
|
||||||
|
printf "\n%s: not moved %s to %s\n" "$(dirname "${CONF_DIR}")" \
|
||||||
|
"$(basename "${CONF_DIR}")${ORIG}" "$(basename "${CONF_DIR}")"
|
||||||
|
|
||||||
|
printf "done.\n"
|
||||||
|
|
||||||
|
exit "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p "/etc/config/" && touch "/etc/config/nginx"
|
||||||
|
|
||||||
|
cd "/etc/config/" && [ ! -e "nginx${ORIG}" ] && cp "nginx" "nginx.${ORIG}" || {
|
||||||
|
printf "\n%s: not copied %s to %s\n" "/etc/config/" "nginx" "nginx${ORIG}"
|
||||||
|
pst_exit 3
|
||||||
|
}
|
||||||
|
|
||||||
|
uci set nginx.global.uci_enable=1
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p "/etc/crontabs/" && touch "/etc/crontabs/root"
|
||||||
|
|
||||||
|
cd "/etc/crontabs/" && [ ! -e "root${ORIG}" ] && mv "root" "root${ORIG}" || {
|
||||||
|
printf "\n%s: not moved %s to %s\n" "/etc/crontabs/" "root${ORIG}" "root"
|
||||||
|
pst_exit 4
|
||||||
|
}
|
||||||
|
|
||||||
|
touch "/etc/crontabs/root"
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
__esc_newlines() {
|
__esc_newlines() {
|
||||||
echo "${1}" | sed -E 's/$/\\n/' | tr -d '\n' | sed -E 's/\\n$/\n/'
|
echo "${1}" | sed -E 's/$/\\n/' | tr -d '\n' | sed -E 's/\\n$/\n/'
|
||||||
}
|
}
|
||||||
@ -33,6 +84,32 @@ _echo_sed() {
|
|||||||
echo "" | sed -E "c${1}"
|
echo "" | sed -E "c${1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fileauto="# This file is re-created when Nginx starts."
|
||||||
|
|
||||||
|
setpoint_init_lan() {
|
||||||
|
echo "${fileauto}"
|
||||||
|
|
||||||
|
sed -n -E '/^\s*#UCI_HTTP_CONFIG\s*$/q;p' "${UCI_CONF}.template"
|
||||||
|
|
||||||
|
local rhs="\t}\n\n\tserver { #see uci show 'nginx.\1'"
|
||||||
|
uci -n export nginx \
|
||||||
|
| sed -E -e "s/'//g" \
|
||||||
|
-e '/^\s*package\s+nginx\s*$/d' \
|
||||||
|
-e '/^\s*config\s+main\s/d' \
|
||||||
|
-e "s/^\s*config\s+server\s+(.*)$/$rhs/g" \
|
||||||
|
-e 's/^\s*list\s/\t\t/g' \
|
||||||
|
-e 's/^\s*option\s/\t\t/g' \
|
||||||
|
-e 's/^\s*uci_listen_locally\s+/\t\tlisten 127.0.0.1:/g' \
|
||||||
|
-e '/^\s*uci_/d' \
|
||||||
|
-e '/^$/d' -e "s/[^'\n]$/&;/g" \
|
||||||
|
| sed "1,2d"
|
||||||
|
printf "\t}\n\n"
|
||||||
|
|
||||||
|
sed -E '1,/^\s*#UCI_HTTP_CONFIG\s*$/ d' "${UCI_CONF}.template"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
setpoint_add_ssl() {
|
setpoint_add_ssl() {
|
||||||
local indent="\n$1"
|
local indent="\n$1"
|
||||||
local name="$2"
|
local name="$2"
|
||||||
@ -40,13 +117,13 @@ setpoint_add_ssl() {
|
|||||||
[ "${name}" = "${LAN_NAME}" ] && default=".default"
|
[ "${name}" = "${LAN_NAME}" ] && default=".default"
|
||||||
local prefix="${CONF_DIR}${name}"
|
local prefix="${CONF_DIR}${name}"
|
||||||
|
|
||||||
local CONF="$(grep -vE "$(_regex "${NGX_INCLUDE}" \
|
|
||||||
"${LAN_LISTEN}${default}")" "${prefix}.sans" 2>/dev/null)"
|
|
||||||
local ADDS=""
|
local ADDS=""
|
||||||
echo "${CONF}" \
|
local CONF
|
||||||
| grep -qE "$(_regex "${NGX_INCLUDE}" "${LAN_SSL_LISTEN}${default}")" \
|
CONF="$(sed -E \
|
||||||
|| ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_INCLUDE}" \
|
-e "s/$(_regex "${NGX_INCLUDE}" "${LAN_LISTEN}${default}")/$1$(\
|
||||||
"${LAN_SSL_LISTEN}${default}")"
|
_sed_rhs "${NGX_INCLUDE}" "${LAN_SSL_LISTEN}${default}")/g" \
|
||||||
|
-e "s/^(\s*listen\s+)([^:]*:|\[[^]]*\]:)?80(\s|$|;)/\1\2443 ssl\3/g" \
|
||||||
|
"${prefix}.sans" 2>/dev/null)"
|
||||||
echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_CRT}" "${prefix}")" \
|
echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_CRT}" "${prefix}")" \
|
||||||
|| ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_CRT}" "${prefix}")"
|
|| ADDS="${ADDS}${indent}$(_sed_rhs "${NGX_SSL_CRT}" "${prefix}")"
|
||||||
echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_KEY}" "${prefix}")" \
|
echo "${CONF}" | grep -qE "$(_regex "${NGX_SSL_KEY}" "${prefix}")" \
|
||||||
@ -82,6 +159,18 @@ test_setpoint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_existence() {
|
||||||
|
if [ "$2" -eq "0" ]
|
||||||
|
then
|
||||||
|
[ ! -f "$1" ] && echo "$1 missing!" &&
|
||||||
|
[ "${PRINT_PASSED}" -gt 1 ] && pst_exit 1
|
||||||
|
else
|
||||||
|
[ -f "$1" ] && echo "$1 existing!" &&
|
||||||
|
[ "${PRINT_PASSED}" -gt 1 ] && pst_exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
test() {
|
test() {
|
||||||
eval "$1 2>/dev/null >/dev/null"
|
eval "$1 2>/dev/null >/dev/null"
|
||||||
if [ "$?" -eq "$2" ]
|
if [ "$?" -eq "$2" ]
|
||||||
@ -90,14 +179,19 @@ test() {
|
|||||||
&& printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) passed."
|
&& printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) passed."
|
||||||
else
|
else
|
||||||
printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) failed!!!"
|
printf "%-72s%-1s\n" "$1" "2>/dev/null >/dev/null (-> $2?) failed!!!"
|
||||||
[ "${PRINT_PASSED}" -gt 1 ] && exit 1
|
[ "${PRINT_PASSED}" -gt 0 ] && printf "\n### Snip:\n" && eval "$1"
|
||||||
|
[ "${PRINT_PASSED}" -gt 0 ] && printf "### Snap.\n"
|
||||||
|
[ "${PRINT_PASSED}" -gt 1 ] && pst_exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s get_env ...\n" "${NGINX_UTIL}"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s get_env ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
|
|
||||||
eval $("${NGINX_UTIL}" get_env)
|
eval $("${NGINX_UTIL}" get_env)
|
||||||
|
test '[ -n "${UCI_CONF}" ]' 0
|
||||||
test '[ -n "${NGINX_CONF}" ]' 0
|
test '[ -n "${NGINX_CONF}" ]' 0
|
||||||
test '[ -n "${CONF_DIR}" ]' 0
|
test '[ -n "${CONF_DIR}" ]' 0
|
||||||
test '[ -n "${LAN_NAME}" ]' 0
|
test '[ -n "${LAN_NAME}" ]' 0
|
||||||
@ -106,13 +200,26 @@ test '[ -n "${LAN_SSL_LISTEN}" ]' 0
|
|||||||
test '[ -n "${SSL_SESSION_CACHE_ARG}" ]' 0
|
test '[ -n "${SSL_SESSION_CACHE_ARG}" ]' 0
|
||||||
test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 0
|
test '[ -n "${SSL_SESSION_TIMEOUT_ARG}" ]' 0
|
||||||
test '[ -n "${ADD_SSL_FCT}" ]' 0
|
test '[ -n "${ADD_SSL_FCT}" ]' 0
|
||||||
|
test '[ -n "${MANAGE_SSL}" ]' 0
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "${LAN_LISTEN}")"
|
||||||
|
|
||||||
|
mkdir -p "${CONF_DIR}"
|
||||||
|
|
||||||
|
cd "$(dirname "${CONF_DIR}")" && [ ! -e "$(basename "${CONF_DIR}")${ORIG}" ] &&
|
||||||
|
mv "$(basename "${CONF_DIR}")" "$(basename "${CONF_DIR}")${ORIG}" ||
|
||||||
|
{
|
||||||
|
printf "\n%s: not moved %s to %s\n" "$(dirname "${CONF_DIR}")" \
|
||||||
|
"$(basename "${CONF_DIR}")" "$(basename "${CONF_DIR}")${ORIG}"
|
||||||
|
pst_exit 3
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in %s ...\n" "${CONF_DIR}"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nPrepare files in %s ...\n" "${CONF_DIR}"
|
||||||
|
|
||||||
mkdir -p "${CONF_DIR}"
|
mkdir -p "${CONF_DIR}"
|
||||||
|
|
||||||
cd "${CONF_DIR}" || exit 2
|
cd "${CONF_DIR}" || pst_exit 2
|
||||||
|
|
||||||
NGX_INCLUDE="include '\$';"
|
NGX_INCLUDE="include '\$';"
|
||||||
NGX_SERVER_NAME="server_name * '\$' *;"
|
NGX_SERVER_NAME="server_name * '\$' *;"
|
||||||
@ -140,6 +247,24 @@ server {
|
|||||||
EOF
|
EOF
|
||||||
CONFS="${CONFS} minimal:0"
|
CONFS="${CONFS} minimal:0"
|
||||||
|
|
||||||
|
cat > listens.sans <<EOF
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen 81;
|
||||||
|
listen hostname:80;
|
||||||
|
listen hostname:81;
|
||||||
|
listen [::]:80;
|
||||||
|
listen [::]:81;
|
||||||
|
listen 1.3:80;
|
||||||
|
# listen 1.3:80;
|
||||||
|
listen 1.3:81;
|
||||||
|
listen [1::3]:80;
|
||||||
|
listen [1::3]:81;
|
||||||
|
server_name listens;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
CONFS="${CONFS} listens:0"
|
||||||
|
|
||||||
cat > normal.sans <<EOF
|
cat > normal.sans <<EOF
|
||||||
server {
|
server {
|
||||||
include '${LAN_LISTEN}';
|
include '${LAN_LISTEN}';
|
||||||
@ -148,6 +273,15 @@ server {
|
|||||||
EOF
|
EOF
|
||||||
CONFS="${CONFS} normal:0"
|
CONFS="${CONFS} normal:0"
|
||||||
|
|
||||||
|
cat > acme.sans <<EOF
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
include '${LAN_LISTEN}';
|
||||||
|
server_name acme;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
CONFS="${CONFS} acme:0"
|
||||||
|
|
||||||
cat > more_server.sans <<EOF
|
cat > more_server.sans <<EOF
|
||||||
server {
|
server {
|
||||||
# include '${LAN_LISTEN}';
|
# include '${LAN_LISTEN}';
|
||||||
@ -163,6 +297,9 @@ CONFS="${CONFS} more_server:0"
|
|||||||
cat > more_names.sans <<EOF
|
cat > more_names.sans <<EOF
|
||||||
server {
|
server {
|
||||||
include '${LAN_LISTEN}';
|
include '${LAN_LISTEN}';
|
||||||
|
include '${LAN_LISTEN}';
|
||||||
|
include '${LAN_LISTEN}';
|
||||||
|
not include '${LAN_LISTEN}';
|
||||||
server_name example.com more_names example.org;
|
server_name example.com more_names example.org;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
@ -203,17 +340,10 @@ EOF
|
|||||||
CONFS="${CONFS} tab:0"
|
CONFS="${CONFS} tab:0"
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s init_lan ...\n" "${NGINX_UTIL}"
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "${LAN_LISTEN}")"
|
|
||||||
|
|
||||||
cp "${LAN_NAME}.sans" "${LAN_NAME}.conf"
|
|
||||||
|
|
||||||
test '"${NGINX_UTIL}" init_lan' 0
|
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in %s ...\n" "${CONF_DIR}"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nSetup files in %s ...\n" "${CONF_DIR}"
|
||||||
|
|
||||||
|
|
||||||
for conf in ${CONFS}
|
for conf in ${CONFS}
|
||||||
do test 'setpoint_add_ssl " " '"${conf%:*}" "${conf#*:}"
|
do test 'setpoint_add_ssl " " '"${conf%:*}" "${conf#*:}"
|
||||||
done
|
done
|
||||||
@ -221,26 +351,259 @@ done
|
|||||||
test 'setpoint_add_ssl "\t" tab' 0 # fixes wrong indentation.
|
test 'setpoint_add_ssl "\t" tab' 0 # fixes wrong indentation.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting Cron ... \n"
|
||||||
|
|
||||||
|
|
||||||
|
echo -n "prefix" >"/etc/crontabs/root"
|
||||||
|
test '"${NGINX_UTIL}" add_ssl _lan' 0
|
||||||
|
echo "postfix" >>"/etc/crontabs/root"
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
3 3 12 12 * ${NGINX_UTIL} 'check_ssl'
|
||||||
|
postfix"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" del_ssl _lan' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
3 3 12 12 * ${NGINX_UTIL} 'check_ssl'
|
||||||
|
postfix"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" check_ssl' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
postfix"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" add_ssl _lan' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
postfix
|
||||||
|
3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
|
||||||
|
rm -f "/etc/crontabs/root"
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf '\n\t-"-\t(legacy) ... \n'
|
||||||
|
|
||||||
|
echo -n "prefix" >"/etc/crontabs/root"
|
||||||
|
cp "minimal.sans" "minimal.conf"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" add_ssl minimal' 0
|
||||||
|
echo "postfix" >>"/etc/crontabs/root"
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
3 3 12 12 * ${NGINX_UTIL} 'add_ssl' 'minimal'
|
||||||
|
postfix"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" del_ssl minimal' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "prefix
|
||||||
|
postfix"
|
||||||
|
|
||||||
|
rm -f "/etc/crontabs/root"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s init_lan ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
|
|
||||||
|
rm -f "${LAN_NAME}.conf" "_redirect2ssl.conf" "${UCI_ADDED}.conf"
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
test_setpoint "${UCI_CONF}" "$(setpoint_init_lan)"
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf '\n\t-"-\twith temporary UCI config ... \n'
|
||||||
|
|
||||||
|
UCI_ADDED="$(uci add nginx server)" &&
|
||||||
|
uci set nginx.@server[-1].server_name='temp' &&
|
||||||
|
uci add_list nginx.@server[-1].listen='81 default_server' &&
|
||||||
|
uci add_list nginx.@server[-1].listen='80' &&
|
||||||
|
echo "UCI: nginx.${UCI_ADDED} added."
|
||||||
|
|
||||||
|
rm -f "${LAN_NAME}.conf" "_redirect2ssl.conf" "${UCI_ADDED}.conf"
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
test_setpoint "${UCI_CONF}" "$(setpoint_init_lan)"
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf '\n\t-"-\t(legacy) ... \n'
|
||||||
|
|
||||||
|
cp "${LAN_NAME}.sans" "${LAN_NAME}.conf"
|
||||||
|
touch "_redirect2ssl.conf" "${UCI_ADDED}.conf"
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
|
||||||
|
skipped() {
|
||||||
|
printf "\t# skipped UCI server 'nginx.%s'" "$1"
|
||||||
|
printf " as it could conflict with: %s%s.conf\n\n" "${CONF_DIR}" "$1"
|
||||||
|
}
|
||||||
|
rhs="$(skipped "$LAN_NAME" && skipped _redirect2ssl && skipped "${UCI_ADDED}")"
|
||||||
|
sed -E -e "s/^\t#UCI_HTTP_CONFIG$/$(__esc_sed_rhs "$rhs")\n/" \
|
||||||
|
-e 's/\\n/\n/g' -e "1i${fileauto}" "${UCI_CONF}.template" >"uci.setpoint"
|
||||||
|
|
||||||
|
test_setpoint "${UCI_CONF}" "$(cat "uci.setpoint")"
|
||||||
|
test_setpoint "/etc/crontabs/root" ""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s add_ssl ...\n" "${NGINX_UTIL}"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s add_ssl ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
cp different_name.sans different_name.with
|
|
||||||
|
|
||||||
test '[ "${ADD_SSL_FCT}" = "add_ssl" ] ' 0
|
test '[ "${ADD_SSL_FCT}" = "add_ssl" ] ' 0
|
||||||
|
|
||||||
|
rm -f "${LAN_NAME}.conf" "_redirect2ssl.conf" "${UCI_ADDED}.conf"
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
test 'uci set nginx._lan.uci_manage_ssl="self-signed"' 0
|
||||||
|
"${NGINX_UTIL}" del_ssl "${LAN_NAME}" 2>/dev/null
|
||||||
|
test_setpoint "/etc/crontabs/root" ""
|
||||||
|
test_existence "${LAN_NAME}.crt" 1
|
||||||
|
test_existence "${LAN_NAME}.key" 1
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${UCI_ADDED}"' acme \
|
||||||
|
'"${CONF_DIR}${UCI_ADDED}.crt"' '"${CONF_DIR}${UCI_ADDED}.key"' ' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" ""
|
||||||
|
test_existence "${UCI_ADDED}.crt" 1
|
||||||
|
test_existence "${UCI_ADDED}.key" 1
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${LAN_NAME}" 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
test_existence "${LAN_NAME}.crt" 0
|
||||||
|
test_existence "${LAN_NAME}.key" 0
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${LAN_NAME}" 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
test '"${NGINX_UTIL}" add_ssl inexistent' 1
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
test_setpoint "${UCI_CONF}" "$(setpoint_init_lan)"
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'check_ssl'"
|
||||||
|
test_existence "${UCI_ADDED}.crt" 1
|
||||||
|
test_existence "${UCI_ADDED}.key" 1
|
||||||
|
test_existence "${LAN_NAME}.crt" 0
|
||||||
|
test_existence "${LAN_NAME}.key" 0
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf '\n\t-"-\t(legacy) ... \n'
|
||||||
|
|
||||||
|
cp different_name.sans different_name.with
|
||||||
|
|
||||||
|
cp "/etc/crontabs/root" "cron.setpoint"
|
||||||
for conf in ${CONFS}; do
|
for conf in ${CONFS}; do
|
||||||
name="${conf%:*}"
|
name="${conf%:*}"
|
||||||
|
[ "${name}" = "acme" ] && continue
|
||||||
|
[ "${name}" = "different_name" ] ||
|
||||||
|
echo "3 3 12 12 * ${NGINX_UTIL} 'add_ssl' '${name}'" >>"cron.setpoint"
|
||||||
cp "${name}.sans" "${name}.conf"
|
cp "${name}.sans" "${name}.conf"
|
||||||
test '"${NGINX_UTIL}" add_ssl '"${name}" "${conf#*:}"
|
test '"${NGINX_UTIL}" add_ssl '"${name}" "${conf#*:}"
|
||||||
test_setpoint "${name}.conf" "$(cat "${name}.with")"
|
test_setpoint "${name}.conf" "$(cat "${name}.with")"
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
[ "${name}" = "different_name" ] || test_existence "${name}.crt" 0
|
||||||
|
[ "${name}" = "different_name" ] || test_existence "${name}.key" 0
|
||||||
done
|
done
|
||||||
|
|
||||||
|
cp acme.sans acme.conf
|
||||||
|
test '"${NGINX_UTIL}" add_ssl acme acme /path/to/crt /path/to/key' 0
|
||||||
|
test_setpoint "acme.conf" "$(cat "acme.with")"
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
test_existence "acme.crt" 1
|
||||||
|
test_existence "acme.key" 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s del_ssl ...\n" "${NGINX_UTIL}"
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting %s del_ssl ...\n" "${NGINX_UTIL}"
|
||||||
|
|
||||||
sed -i "/server {/a\\ include '${LAN_LISTEN}';" minimal.sans
|
|
||||||
|
sed -E -e 's/443 ssl/80/' -e '/[^2]ssl/d' "/etc/config/nginx" >"config.setpoint"
|
||||||
|
|
||||||
|
cp "/etc/crontabs/root" "cron.setpoint"
|
||||||
|
rm -f "${LAN_NAME}.conf" "_redirect2ssl.conf" "${UCI_ADDED}.conf"
|
||||||
|
test '"${NGINX_UTIL}" del_ssl '"${LAN_NAME}" 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
test_existence "${LAN_NAME}.crt" 1
|
||||||
|
test_existence "${LAN_NAME}.key" 1
|
||||||
|
test '"${NGINX_UTIL}" del_ssl '"${LAN_NAME}" 1
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
sed -E "/$(__esc_regex "'check_ssl'")/d" "/etc/crontabs/root" >"cron.setpoint"
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
test_setpoint "${UCI_CONF}" "$(setpoint_init_lan)"
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
|
||||||
|
touch "${UCI_ADDED}.crt" "${UCI_ADDED}.key"
|
||||||
|
test '"${NGINX_UTIL}" del_ssl "'${UCI_ADDED}'" acme' 0
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
test_existence "${UCI_ADDED}.crt" 0
|
||||||
|
test_existence "${UCI_ADDED}.key" 0
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" del_ssl inexistent' 1
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
|
||||||
|
test_setpoint "/etc/config/nginx" "$(cat "config.setpoint")"
|
||||||
|
test '"${NGINX_UTIL}" add_ssl "'${UCI_ADDED}'" acme \
|
||||||
|
'"${CONF_DIR}${UCI_ADDED}.crt"' '"${CONF_DIR}${UCI_ADDED}.key"' ' 0
|
||||||
|
test '"${NGINX_UTIL}" add_ssl "'$(uci get "nginx.${UCI_ADDED}.server_name")'"' 0
|
||||||
|
test '"${NGINX_UTIL}" del_ssl "'$(uci get "nginx.${UCI_ADDED}.server_name")'"' 0
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
sed -E "/$(__esc_regex "'check_ssl'")/d" "/etc/crontabs/root" >"cron.setpoint"
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
test_setpoint "${UCI_CONF}" "$(setpoint_init_lan)"
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
test_existence "${UCI_ADDED}.crt" 1
|
||||||
|
test_existence "${UCI_ADDED}.key" 1
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf '\n\t-"-\t(legacy) ... \n'
|
||||||
|
|
||||||
for conf in ${CONFS}; do
|
for conf in ${CONFS}; do
|
||||||
name="${conf%:*}"
|
name="${conf%:*}"
|
||||||
|
[ "${name}" = "acme" ] && continue
|
||||||
|
sed -E "/$(__esc_regex "'${name}'")/d" "/etc/crontabs/root" >"cron.setpoint"
|
||||||
|
touch "${name}.crt" "${name}.key"
|
||||||
cp "${name}.with" "${name}.conf"
|
cp "${name}.with" "${name}.conf"
|
||||||
test '"${NGINX_UTIL}" del_ssl '"${name}" "${conf#*:}"
|
test '"${NGINX_UTIL}" del_ssl '"${name}" "${conf#*:}"
|
||||||
test_setpoint "${name}.conf" "$(cat "${name}.sans")"
|
test_setpoint "${name}.conf" "$(cat "${name}.sans")"
|
||||||
|
test_setpoint "/etc/crontabs/root" "$(cat "cron.setpoint")"
|
||||||
|
[ "${name}" = "different_name" ] && rm "${name}.crt" "${name}.key"
|
||||||
|
test_existence "${name}.crt" 1
|
||||||
|
test_existence "${name}.key" 1
|
||||||
done
|
done
|
||||||
|
test_setpoint "/etc/crontabs/root" ""
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" del_ssl acme acme' 0
|
||||||
|
test_existence "acme.crt" 1
|
||||||
|
test_existence "acme.key" 1
|
||||||
|
|
||||||
|
cp acme.with acme.conf
|
||||||
|
touch acme.crt acme.key
|
||||||
|
echo "3 3 12 12 * ${NGINX_UTIL} 'add_ssl' 'acme'" >>"/etc/crontabs/root"
|
||||||
|
test '"${NGINX_UTIL}" del_ssl acme acme' 0
|
||||||
|
test_setpoint "acme.conf" "$(cat "acme.sans")"
|
||||||
|
test_setpoint "/etc/crontabs/root" "3 3 12 12 * ${NGINX_UTIL} 'add_ssl' 'acme'"
|
||||||
|
test_existence "acme.crt" 0
|
||||||
|
test_existence "acme.key" 0
|
||||||
|
"${NGINX_UTIL}" del_ssl acme 2>/dev/null
|
||||||
|
test_setpoint "/etc/crontabs/root" ""
|
||||||
|
test_existence "acme.crt" 1
|
||||||
|
test_existence "acme.key" 1
|
||||||
|
|
||||||
|
|
||||||
|
[ "$PRINT_PASSED" -gt 0 ] && printf "\nTesting without UCI ... \n"
|
||||||
|
|
||||||
|
rm -f "$(readlink "${UCI_CONF}")"
|
||||||
|
|
||||||
|
test 'uci set nginx.global.uci_enable=0' 0
|
||||||
|
|
||||||
|
test '"${NGINX_UTIL}" init_lan' 0
|
||||||
|
|
||||||
|
test '[ -e "$(readlink '"${UCI_CONF}"')" ]' 1
|
||||||
|
|
||||||
|
cp "${LAN_NAME}.sans" "${LAN_NAME}.conf"
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${LAN_NAME}" 0
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${LAN_NAME}" 0
|
||||||
|
test '"${NGINX_UTIL}" del_ssl '"${LAN_NAME}" 0
|
||||||
|
test '"${NGINX_UTIL}" del_ssl '"${LAN_NAME}" 0
|
||||||
|
|
||||||
|
test 'rm "${LAN_NAME}.conf"' 0
|
||||||
|
test '"${NGINX_UTIL}" add_ssl '"${LAN_NAME}" 1
|
||||||
|
test '"${NGINX_UTIL}" del_ssl '"${LAN_NAME}" 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pst_exit 0
|
||||||
|
@ -14,8 +14,17 @@ TMPROOT="$(mktemp -d "/tmp/test-nginx-util-XXXXXX")"
|
|||||||
|
|
||||||
ln -s /bin "${TMPROOT}/bin"
|
ln -s /bin "${TMPROOT}/bin"
|
||||||
|
|
||||||
mkdir -p "${TMPROOT}/usr/bin/"
|
mkdir -p "${TMPROOT}/etc/crontabs/"
|
||||||
|
|
||||||
|
mkdir -p "${TMPROOT}/etc/config/"
|
||||||
|
cp "./config-nginx-ssl" "${TMPROOT}/etc/config/nginx"
|
||||||
|
|
||||||
|
mkdir -p "${TMPROOT}/etc/nginx/"
|
||||||
|
cp "./uci.conf.template" "${TMPROOT}/etc/nginx/uci.conf.template"
|
||||||
|
ln -s "${TMPROOT}/var/lib/nginx/uci.conf" "${TMPROOT}/etc/nginx/uci.conf"
|
||||||
|
|
||||||
|
mkdir -p "${TMPROOT}/usr/bin/"
|
||||||
|
cp "/usr/local/bin/uci" "${TMPROOT}/usr/bin/"
|
||||||
cp "./test-nginx-util-root.sh" "${TMPROOT}/usr/bin/"
|
cp "./test-nginx-util-root.sh" "${TMPROOT}/usr/bin/"
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,130 +2,118 @@
|
|||||||
|
|
||||||
#include "ubus-cxx.hpp"
|
#include "ubus-cxx.hpp"
|
||||||
|
|
||||||
|
|
||||||
inline void example_for_checking_if_there_is_a_key()
|
inline void example_for_checking_if_there_is_a_key()
|
||||||
{
|
{
|
||||||
if (ubus::call("service", "list").filter("cron")) {
|
if (ubus::call("service", "list").filter("cron")) {
|
||||||
std::cout<<"Cron is active (with or without instances) "<<std::endl;
|
std::cout << "Cron is active (with or without instances) " << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void example_for_getting_values()
|
inline void example_for_getting_values()
|
||||||
{
|
{
|
||||||
auto lan_status = ubus::call("network.interface.lan", "status");
|
auto lan_status = ubus::call("network.interface.lan", "status");
|
||||||
for (auto t : lan_status.filter("ipv6-address", "", "address")) {
|
for (const auto* t : lan_status.filter("ipv6-address", "", "address")) {
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
auto x = const_cast<blob_attr *>(t);
|
auto* x = const_cast<blob_attr*>(t);
|
||||||
std::cout<<"["<<blobmsg_get_string(x)<<"] ";
|
std::cout << "[" << blobmsg_get_string(x) << "] ";
|
||||||
}
|
}
|
||||||
for (auto t : lan_status.filter("ipv4-address", "").filter("address")) {
|
for (const auto* t : lan_status.filter("ipv4-address", "").filter("address")) {
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
auto x = const_cast<blob_attr *>(t);
|
auto* x = const_cast<blob_attr*>(t);
|
||||||
std::cout<<blobmsg_get_string(x)<<" ";
|
std::cout << blobmsg_get_string(x) << " ";
|
||||||
}
|
}
|
||||||
std::cout<<std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void example_for_sending_message()
|
inline void example_for_sending_message()
|
||||||
{
|
{
|
||||||
auto set_arg = [](blob_buf * buf) -> int
|
auto set_arg = [](blob_buf* buf) -> int { return blobmsg_add_string(buf, "config", "nginx"); };
|
||||||
{ return blobmsg_add_string(buf, "config", "nginx"); };
|
for (const auto* t : ubus::call("uci", "get", set_arg).filter("values")) {
|
||||||
for (auto t : ubus::call("uci", "get", set_arg).filter("values")) {
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
auto* x = const_cast<blob_attr*>(t);
|
||||||
auto x = const_cast<blob_attr *>(t);
|
std::cout << blobmsg_get_string(x) << "\n";
|
||||||
std::cout<<blobmsg_get_string(x)<<"\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void example_for_exploring()
|
inline void example_for_exploring()
|
||||||
{
|
{
|
||||||
ubus::strings keys{"ipv4-address", "", ""};
|
ubus::strings keys{"ipv4-address", "", ""};
|
||||||
for (auto t : ubus::call("network.interface.lan", "status").filter(keys)) {
|
for (const auto* t : ubus::call("network.interface.lan", "status").filter(keys)) {
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
auto x = const_cast<blob_attr *>(t);
|
auto* x = const_cast<blob_attr*>(t);
|
||||||
std::cout<<blobmsg_name(x)<<": ";
|
std::cout << blobmsg_name(x) << ": ";
|
||||||
switch (blob_id(x)) {
|
switch (blob_id(x)) {
|
||||||
case BLOBMSG_TYPE_UNSPEC: std::cout<<"[unspecified]"; break;
|
case BLOBMSG_TYPE_UNSPEC: std::cout << "[unspecified]"; break;
|
||||||
case BLOBMSG_TYPE_ARRAY: std::cout<<"[array]"; break;
|
case BLOBMSG_TYPE_ARRAY: std::cout << "[array]"; break;
|
||||||
case BLOBMSG_TYPE_TABLE: std::cout<<"[table]"; break;
|
case BLOBMSG_TYPE_TABLE: std::cout << "[table]"; break;
|
||||||
case BLOBMSG_TYPE_STRING: std::cout<<blobmsg_get_string(x); break;
|
case BLOBMSG_TYPE_STRING: std::cout << blobmsg_get_string(x); break;
|
||||||
case BLOBMSG_TYPE_INT64: std::cout<<blobmsg_get_u64(x); break;
|
case BLOBMSG_TYPE_INT64: std::cout << blobmsg_get_u64(x); break;
|
||||||
case BLOBMSG_TYPE_INT32: std::cout<<blobmsg_get_u32(x); break;
|
case BLOBMSG_TYPE_INT32: std::cout << blobmsg_get_u32(x); break;
|
||||||
case BLOBMSG_TYPE_INT16: std::cout<<blobmsg_get_u16(x); break;
|
case BLOBMSG_TYPE_INT16: std::cout << blobmsg_get_u16(x); break;
|
||||||
case BLOBMSG_TYPE_BOOL: std::cout<<blobmsg_get_bool(x); break;
|
case BLOBMSG_TYPE_BOOL: std::cout << blobmsg_get_bool(x); break;
|
||||||
case BLOBMSG_TYPE_DOUBLE: std::cout<<blobmsg_get_double(x); break;
|
case BLOBMSG_TYPE_DOUBLE: std::cout << blobmsg_get_double(x); break;
|
||||||
default: std::cout<<"[unknown]";
|
default: std::cout << "[unknown]";
|
||||||
}
|
}
|
||||||
std::cout<<std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void example_for_recursive_exploring()
|
inline void example_for_recursive_exploring()
|
||||||
{ // output like from the original ubus call:
|
{ // output like from the original ubus call:
|
||||||
const auto explore = [](auto message) -> void
|
const auto explore = [](auto message) -> void {
|
||||||
{
|
|
||||||
auto end = message.end();
|
auto end = message.end();
|
||||||
auto explore_internal =
|
auto explore_internal = [&end](auto& explore_ref, auto it, size_t depth = 1) -> void {
|
||||||
[&end](auto & explore_ref, auto it, size_t depth=1) -> void
|
std::cout << std::endl;
|
||||||
{
|
|
||||||
std::cout<<std::endl;
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (; it!=end; ++it) {
|
for (; it != end; ++it) {
|
||||||
//NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
auto attr = const_cast<blob_attr *>(*it);
|
auto* attr = const_cast<blob_attr*>(*it);
|
||||||
if (first) { first = false; }
|
if (first) {
|
||||||
else { std::cout<<",\n"; }
|
first = false;
|
||||||
std::cout<<std::string(depth, '\t');
|
}
|
||||||
|
else {
|
||||||
|
std::cout << ",\n";
|
||||||
|
}
|
||||||
|
std::cout << std::string(depth, '\t');
|
||||||
std::string name = blobmsg_name(attr);
|
std::string name = blobmsg_name(attr);
|
||||||
if (!name.empty()) { std::cout<<"\""<<name<<"\": "; }
|
if (!name.empty()) {
|
||||||
|
std::cout << "\"" << name << "\": ";
|
||||||
|
}
|
||||||
switch (blob_id(attr)) {
|
switch (blob_id(attr)) {
|
||||||
case BLOBMSG_TYPE_UNSPEC: std::cout<<"(unspecified)"; break;
|
case BLOBMSG_TYPE_UNSPEC: std::cout << "(unspecified)"; break;
|
||||||
case BLOBMSG_TYPE_ARRAY:
|
case BLOBMSG_TYPE_ARRAY:
|
||||||
std::cout<<"[";
|
std::cout << "[";
|
||||||
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
explore_ref(explore_ref, ubus::iterator{attr}, depth + 1);
|
||||||
std::cout<<"\n"<<std::string(depth, '\t')<<"]";
|
std::cout << "\n" << std::string(depth, '\t') << "]";
|
||||||
break;
|
break;
|
||||||
case BLOBMSG_TYPE_TABLE:
|
case BLOBMSG_TYPE_TABLE:
|
||||||
std::cout<<"{";
|
std::cout << "{";
|
||||||
explore_ref(explore_ref, ubus::iterator{attr}, depth+1);
|
explore_ref(explore_ref, ubus::iterator{attr}, depth + 1);
|
||||||
std::cout<<"\n"<<std::string(depth, '\t')<<"}";
|
std::cout << "\n" << std::string(depth, '\t') << "}";
|
||||||
break;
|
break;
|
||||||
case BLOBMSG_TYPE_STRING:
|
case BLOBMSG_TYPE_STRING:
|
||||||
std::cout<<"\""<<blobmsg_get_string(attr)<<"\"";
|
std::cout << "\"" << blobmsg_get_string(attr) << "\"";
|
||||||
break;
|
|
||||||
case BLOBMSG_TYPE_INT64:
|
|
||||||
std::cout<<blobmsg_get_u64(attr);
|
|
||||||
break;
|
|
||||||
case BLOBMSG_TYPE_INT32:
|
|
||||||
std::cout<<blobmsg_get_u32(attr);
|
|
||||||
break;
|
|
||||||
case BLOBMSG_TYPE_INT16:
|
|
||||||
std::cout<<blobmsg_get_u16(attr);
|
|
||||||
break;
|
break;
|
||||||
|
case BLOBMSG_TYPE_INT64: std::cout << blobmsg_get_u64(attr); break;
|
||||||
|
case BLOBMSG_TYPE_INT32: std::cout << blobmsg_get_u32(attr); break;
|
||||||
|
case BLOBMSG_TYPE_INT16: std::cout << blobmsg_get_u16(attr); break;
|
||||||
case BLOBMSG_TYPE_BOOL:
|
case BLOBMSG_TYPE_BOOL:
|
||||||
std::cout<<(blobmsg_get_bool(attr) ? "true" : "false");
|
std::cout << (blobmsg_get_bool(attr) ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case BLOBMSG_TYPE_DOUBLE:
|
case BLOBMSG_TYPE_DOUBLE: std::cout << blobmsg_get_double(attr); break;
|
||||||
std::cout<<blobmsg_get_double(attr);
|
default: std::cout << "(unknown)"; break;
|
||||||
break;
|
|
||||||
default: std::cout<<"(unknown)"; break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::cout<<"{";
|
std::cout << "{";
|
||||||
explore_internal(explore_internal, message.begin());
|
explore_internal(explore_internal, message.begin());
|
||||||
std::cout<<"\n}"<<std::endl;
|
std::cout << "\n}" << std::endl;
|
||||||
};
|
};
|
||||||
explore(ubus::call("network.interface.lan", "status"));
|
explore(ubus::call("network.interface.lan", "status"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto main() -> int
|
||||||
auto main() -> int {
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
example_for_checking_if_there_is_a_key();
|
example_for_checking_if_there_is_a_key();
|
||||||
|
|
||||||
@ -140,9 +128,13 @@ auto main() -> int {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (const std::exception & e) { std::cerr<<e.what()<<std::endl; }
|
catch (const std::exception& e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
catch (...) { perror("main error"); }
|
catch (...) {
|
||||||
|
perror("main error");
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#ifndef _UBUS_CXX_HPP
|
#ifndef _UBUS_CXX_HPP
|
||||||
#define _UBUS_CXX_HPP
|
#define _UBUS_CXX_HPP
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <libubus.h>
|
#include <libubus.h>
|
||||||
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -13,7 +13,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace ubus {
|
namespace ubus {
|
||||||
|
|
||||||
static constexpr int call_timeout = 500;
|
static constexpr int call_timeout = 500;
|
||||||
@ -22,12 +21,13 @@ using msg_ptr = std::shared_ptr<const blob_attr>;
|
|||||||
|
|
||||||
using strings = std::vector<std::string>;
|
using strings = std::vector<std::string>;
|
||||||
|
|
||||||
|
inline auto concat(strings dest)
|
||||||
|
{
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
inline auto concat(strings dest) { return dest; }
|
template <class... Strings>
|
||||||
|
inline auto concat(strings dest, strings src, Strings... more)
|
||||||
|
|
||||||
template<class ...Strings>
|
|
||||||
inline auto concat(strings dest, strings src, Strings ...more)
|
|
||||||
{
|
{
|
||||||
dest.reserve(dest.size() + src.size());
|
dest.reserve(dest.size() + src.size());
|
||||||
dest.insert(std::end(dest), std::make_move_iterator(std::begin(src)),
|
dest.insert(std::end(dest), std::make_move_iterator(std::begin(src)),
|
||||||
@ -35,182 +35,162 @@ inline auto concat(strings dest, strings src, Strings ...more)
|
|||||||
return concat(std::move(dest), std::move(more)...);
|
return concat(std::move(dest), std::move(more)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class S, class... Strings>
|
||||||
template<class S, class ...Strings>
|
inline auto concat(strings dest, S src, Strings... more)
|
||||||
inline auto concat(strings dest, S src, Strings ...more)
|
|
||||||
{
|
{
|
||||||
dest.emplace_back(std::move(src));
|
dest.emplace_back(std::move(src));
|
||||||
return concat(std::move(dest), std::move(more)...);
|
return concat(std::move(dest), std::move(more)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class iterator {
|
class iterator {
|
||||||
|
private:
|
||||||
private:
|
const strings& keys;
|
||||||
|
|
||||||
const strings & keys;
|
|
||||||
|
|
||||||
const size_t n = 0;
|
const size_t n = 0;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
const blob_attr * pos = nullptr;
|
const blob_attr* pos = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<iterator> cur{};
|
std::unique_ptr<iterator> cur{};
|
||||||
|
|
||||||
iterator * parent = nullptr;
|
iterator* parent = nullptr;
|
||||||
|
|
||||||
size_t rem = 0;
|
size_t rem = 0;
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] inline auto matches() const -> bool
|
[[nodiscard]] inline auto matches() const -> bool
|
||||||
{
|
{
|
||||||
return (keys[i].empty() || blobmsg_name(cur->pos)==keys[i]);
|
return (keys[i].empty() || blobmsg_name(cur->pos) == keys[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit iterator(iterator* par)
|
||||||
explicit iterator(iterator * par)
|
: keys{par->keys}, n{par->n}, pos{par->pos}, cur{this}, parent{par}
|
||||||
: keys{par->keys}, n{par->n}, pos{par->pos}, cur{this}, parent{par}
|
|
||||||
{
|
{
|
||||||
if (pos!=nullptr) {
|
if (pos != nullptr) {
|
||||||
rem = blobmsg_data_len(pos);
|
rem = blobmsg_data_len(pos);
|
||||||
pos = static_cast<blob_attr *>(blobmsg_data(pos));
|
pos = static_cast<blob_attr*>(blobmsg_data(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
public:
|
explicit iterator(const blob_attr* msg, const strings& key_filter = {""})
|
||||||
|
: keys{key_filter}, n{keys.size() - 1}, pos{msg}, cur{this}
|
||||||
explicit iterator(const blob_attr * msg, const strings & filter={""})
|
|
||||||
: keys{filter}, n{keys.size()-1}, pos{msg}, cur{this}
|
|
||||||
{
|
{
|
||||||
if (pos!=nullptr) {
|
if (pos != nullptr) {
|
||||||
rem = blobmsg_data_len(pos);
|
rem = blobmsg_data_len(pos);
|
||||||
pos = static_cast<blob_attr *>(blobmsg_data(pos));
|
pos = static_cast<blob_attr*>(blobmsg_data(pos));
|
||||||
|
|
||||||
if (rem==0) { pos = nullptr; }
|
if (rem == 0) {
|
||||||
else if (i!=n || !matches()) { ++*this; }
|
pos = nullptr;
|
||||||
|
}
|
||||||
|
else if (i != n || !matches()) {
|
||||||
|
++*this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline iterator(iterator&&) noexcept = default;
|
||||||
|
|
||||||
inline iterator(iterator &&) noexcept = default;
|
inline iterator(const iterator&) = delete;
|
||||||
|
|
||||||
|
inline auto operator=(const iterator&) -> iterator& = delete;
|
||||||
|
|
||||||
inline iterator(const iterator &) = delete;
|
inline auto operator=(iterator &&) -> iterator& = delete;
|
||||||
|
|
||||||
|
inline auto operator*()
|
||||||
|
{
|
||||||
|
return cur->pos;
|
||||||
|
}
|
||||||
|
|
||||||
inline auto operator=(const iterator &) -> iterator & = delete;
|
inline auto operator!=(const iterator& rhs)
|
||||||
|
{
|
||||||
|
return (cur->rem != rhs.cur->rem || cur->pos != rhs.cur->pos);
|
||||||
inline auto operator=(iterator &&) -> iterator & = delete;
|
}
|
||||||
|
|
||||||
|
|
||||||
inline auto operator*() { return cur->pos; }
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator!=(const iterator & rhs)
|
|
||||||
{ return (cur->rem!=rhs.cur->rem || cur->pos!=rhs.cur->pos); }
|
|
||||||
|
|
||||||
|
|
||||||
auto operator++() -> iterator &;
|
|
||||||
|
|
||||||
|
auto operator++() -> iterator&;
|
||||||
|
|
||||||
inline ~iterator()
|
inline ~iterator()
|
||||||
{ if (cur.get()==this) { static_cast<void>(cur.release()); } }
|
{
|
||||||
|
if (cur.get() == this) {
|
||||||
|
static_cast<void>(cur.release());
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class message {
|
class message {
|
||||||
|
private:
|
||||||
private:
|
const msg_ptr msg{}; // initialized by callback.
|
||||||
|
|
||||||
const msg_ptr msg{}; // initialized by callback.
|
|
||||||
|
|
||||||
const strings keys{};
|
const strings keys{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline explicit message(msg_ptr message_ptr, strings key_filter = {""})
|
||||||
|
: msg{std::move(message_ptr)}, keys{std::move(key_filter)}
|
||||||
|
{}
|
||||||
|
|
||||||
public:
|
inline message(message&&) = default;
|
||||||
|
|
||||||
inline explicit message(msg_ptr message_ptr, strings filter={""})
|
inline message(const message&) = delete;
|
||||||
: msg{std::move(message_ptr)}, keys{std::move(filter)} {}
|
|
||||||
|
|
||||||
|
inline auto operator=(message &&) -> message& = delete;
|
||||||
|
|
||||||
inline message(message &&) = default;
|
inline auto operator=(const message&) -> message& = delete;
|
||||||
|
|
||||||
|
|
||||||
inline message(const message &) = delete;
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(message &&) -> message & = delete;
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(const message &) -> message & = delete;
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] inline auto begin() const -> iterator
|
[[nodiscard]] inline auto begin() const -> iterator
|
||||||
{ return iterator{msg.get(), keys}; }
|
{
|
||||||
|
return iterator{msg.get(), keys};
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline auto end() const -> iterator
|
[[nodiscard]] inline auto end() const -> iterator
|
||||||
{ return iterator{nullptr, keys}; }
|
{
|
||||||
|
return iterator{nullptr, keys};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit operator bool() const
|
||||||
|
{
|
||||||
|
return begin() != end();
|
||||||
|
}
|
||||||
|
|
||||||
inline explicit operator bool() const { return begin()!=end(); }
|
template <class... Strings>
|
||||||
|
auto filter(Strings... key_filter)
|
||||||
|
|
||||||
template<class ...Strings>
|
|
||||||
auto filter(Strings ...filter)
|
|
||||||
{
|
{
|
||||||
strings both{};
|
strings both{};
|
||||||
if (keys.size()!=1 || !keys[0].empty()) { both = keys; }
|
if (keys.size() != 1 || !keys[0].empty()) {
|
||||||
both = concat(std::move(both), std::move(filter)...);
|
both = keys;
|
||||||
|
}
|
||||||
|
both = concat(std::move(both), std::move(key_filter)...);
|
||||||
return std::move(message{msg, std::move(both)});
|
return std::move(message{msg, std::move(both)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline ~message() = default;
|
inline ~message() = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class lock_shared_resources {
|
class lock_shared_resources {
|
||||||
|
private:
|
||||||
private:
|
|
||||||
|
|
||||||
static std::mutex inuse;
|
static std::mutex inuse;
|
||||||
|
|
||||||
|
public:
|
||||||
public:
|
inline lock_shared_resources()
|
||||||
|
|
||||||
|
|
||||||
inline lock_shared_resources() { inuse.lock(); }
|
|
||||||
|
|
||||||
|
|
||||||
inline lock_shared_resources(lock_shared_resources &&) noexcept = default;
|
|
||||||
|
|
||||||
|
|
||||||
inline lock_shared_resources(const lock_shared_resources &) = delete;
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(const lock_shared_resources &) -> auto & = delete;
|
|
||||||
|
|
||||||
|
|
||||||
inline auto operator=(lock_shared_resources &&) -> auto && = delete;
|
|
||||||
|
|
||||||
|
|
||||||
//NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
|
||||||
inline auto get_context() -> ubus_context * // is member to enforce inuse.
|
|
||||||
{
|
{
|
||||||
static auto ubus_freeing = [] (ubus_context * ctx) { ubus_free(ctx); };
|
inuse.lock();
|
||||||
static std::unique_ptr<ubus_context, decltype(ubus_freeing)>
|
}
|
||||||
lazy_ctx{ubus_connect(nullptr), ubus_freeing};
|
|
||||||
|
|
||||||
if (!lazy_ctx) { // it could be available on a later call:
|
inline lock_shared_resources(lock_shared_resources&&) noexcept = default;
|
||||||
|
|
||||||
|
inline lock_shared_resources(const lock_shared_resources&) = delete;
|
||||||
|
|
||||||
|
inline auto operator=(const lock_shared_resources&) -> auto& = delete;
|
||||||
|
|
||||||
|
inline auto operator=(lock_shared_resources &&) -> auto&& = delete;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
|
inline auto get_context() -> ubus_context* // is member to enforce inuse.
|
||||||
|
{
|
||||||
|
static auto ubus_freeing = [](ubus_context* ctx) { ubus_free(ctx); };
|
||||||
|
static std::unique_ptr<ubus_context, decltype(ubus_freeing)> lazy_ctx{ubus_connect(nullptr),
|
||||||
|
ubus_freeing};
|
||||||
|
|
||||||
|
if (!lazy_ctx) { // it could be available on a later call:
|
||||||
|
|
||||||
lazy_ctx.reset(ubus_connect(nullptr));
|
lazy_ctx.reset(ubus_connect(nullptr));
|
||||||
|
|
||||||
@ -222,82 +202,79 @@ public:
|
|||||||
return lazy_ctx.get();
|
return lazy_ctx.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
//NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
inline auto get_blob_buf() -> blob_buf* // is member to enforce inuse.
|
||||||
inline auto get_blob_buf() -> blob_buf * // is member to enforce inuse.
|
|
||||||
{
|
{
|
||||||
static blob_buf buf;
|
static blob_buf buf;
|
||||||
|
|
||||||
static auto blob_buf_freeing = [] (blob_buf * b) { blob_buf_free(b); };
|
static auto blob_buf_freeing = [](blob_buf* b) { blob_buf_free(b); };
|
||||||
static std::unique_ptr<blob_buf, decltype(blob_buf_freeing)>
|
static std::unique_ptr<blob_buf, decltype(blob_buf_freeing)>
|
||||||
created_to_free_on_the_end_of_life{&buf, blob_buf_freeing};
|
created_to_free_on_the_end_of_life{&buf, blob_buf_freeing};
|
||||||
|
|
||||||
blob_buf_init(&buf, 0);
|
blob_buf_init(&buf, 0);
|
||||||
|
|
||||||
return &buf;
|
return &buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ~lock_shared_resources()
|
||||||
inline ~lock_shared_resources() { inuse.unlock(); }
|
{
|
||||||
|
inuse.unlock();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
auto call(const char* path, const char* method, F set_arguments, int timeout = call_timeout)
|
||||||
|
-> message;
|
||||||
|
|
||||||
template<class F>
|
inline auto call(const char* path, const char* method, int timeout = call_timeout) -> message
|
||||||
auto call(const char * path, const char * method, F set_arguments,
|
{
|
||||||
int timeout=call_timeout) -> message;
|
return call(
|
||||||
|
path, method, [](blob_buf* /*buf*/) { return 0; }, timeout);
|
||||||
|
}
|
||||||
inline auto call(const char * path, const char * method,
|
|
||||||
int timeout=call_timeout) -> message
|
|
||||||
{ return call(path, method, [](blob_buf * /*buf*/) { return 0; }, timeout); }
|
|
||||||
|
|
||||||
|
|
||||||
inline auto call(const char * path, int timeout=call_timeout) -> message
|
|
||||||
{ return call(path, "", timeout); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline auto call(const char* path, int timeout = call_timeout) -> message
|
||||||
|
{
|
||||||
|
return call(path, "", timeout);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------- implementation: ----------------------------------
|
// ------------------------- implementation: ----------------------------------
|
||||||
|
|
||||||
|
|
||||||
std::mutex lock_shared_resources::inuse;
|
std::mutex lock_shared_resources::inuse;
|
||||||
|
|
||||||
|
inline auto iterator::operator++() -> iterator&
|
||||||
inline auto iterator::operator++() -> iterator &
|
|
||||||
{
|
{
|
||||||
for(;;) {
|
for (;;) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::cout<<std::string(i,'>')<<" look for "<<keys[i]<<" at ";
|
std::cout << std::string(i, '>') << " look for " << keys[i] << " at ";
|
||||||
std::cout<<blobmsg_name(cur->pos)<<std::endl;
|
std::cout << blobmsg_name(cur->pos) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto id = blob_id(cur->pos);
|
auto id = blob_id(cur->pos);
|
||||||
if ( (id==BLOBMSG_TYPE_TABLE || id==BLOBMSG_TYPE_ARRAY)
|
if ((id == BLOBMSG_TYPE_TABLE || id == BLOBMSG_TYPE_ARRAY) && i < n && matches() &&
|
||||||
&& i<n
|
blobmsg_data_len(cur->pos) > 0)
|
||||||
&& matches()
|
{ // immmerge:
|
||||||
&& blobmsg_data_len(cur->pos)>0 )
|
|
||||||
{ //immmerge:
|
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
auto tmp = cur.release();
|
auto* tmp = cur.release();
|
||||||
|
|
||||||
struct new_iterator : public iterator // use private constructor:
|
struct new_iterator : public iterator // use private constructor:
|
||||||
{ explicit new_iterator(iterator * par) : iterator{par} {} };
|
{
|
||||||
|
explicit new_iterator(iterator* par) : iterator{par} {}
|
||||||
|
};
|
||||||
cur = std::make_unique<new_iterator>(tmp);
|
cur = std::make_unique<new_iterator>(tmp);
|
||||||
|
}
|
||||||
} else {
|
else {
|
||||||
while (true) {
|
while (true) {
|
||||||
cur->rem -= blob_pad_len(cur->pos);
|
cur->rem -= blob_pad_len(cur->pos);
|
||||||
cur->pos = blob_next(cur->pos);
|
cur->pos = blob_next(cur->pos);
|
||||||
auto len = blob_pad_len(cur->pos);
|
auto len = blob_pad_len(cur->pos);
|
||||||
|
|
||||||
if (cur->rem>0 && len<=cur->rem && len>=sizeof(blob_attr))
|
if (cur->rem > 0 && len <= cur->rem && len >= sizeof(blob_attr)) {
|
||||||
{ break; }
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//emerge:
|
// emerge:
|
||||||
auto tmp = cur->parent;
|
auto* tmp = cur->parent;
|
||||||
|
|
||||||
if (tmp == nullptr) {
|
if (tmp == nullptr) {
|
||||||
cur->pos = nullptr;
|
cur->pos = nullptr;
|
||||||
@ -309,67 +286,69 @@ inline auto iterator::operator++() -> iterator &
|
|||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i==n && matches()) { return *cur; }
|
if (i == n && matches()) {
|
||||||
|
return *cur;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
template<class F>
|
inline auto call(const char* path, const char* method, F set_arguments, int timeout) -> message
|
||||||
inline auto call(const char * path, const char * method, F set_arguments,
|
|
||||||
int timeout) -> message
|
|
||||||
{
|
{
|
||||||
|
|
||||||
auto shared = lock_shared_resources{};
|
auto shared = lock_shared_resources{};
|
||||||
|
|
||||||
auto ctx = shared.get_context();
|
auto* ctx = shared.get_context();
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id = 0;
|
||||||
int err = ubus_lookup_id(ctx, path, &id);
|
int err = ubus_lookup_id(ctx, path, &id);
|
||||||
|
|
||||||
if (err==0) { // call
|
if (err == 0) { // call
|
||||||
ubus_request request{};
|
ubus_request request{};
|
||||||
|
|
||||||
auto buf = shared.get_blob_buf();
|
auto* buf = shared.get_blob_buf();
|
||||||
err = set_arguments(buf);
|
err = set_arguments(buf);
|
||||||
if (err==0) {
|
if (err == 0) {
|
||||||
err = ubus_invoke_async(ctx, id, method, buf->head, &request);
|
err = ubus_invoke_async(ctx, id, method, buf->head, &request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err==0) {
|
if (err == 0) {
|
||||||
|
|
||||||
msg_ptr message_ptr;
|
msg_ptr message_ptr;
|
||||||
|
|
||||||
/* Cannot capture message_ptr, the lambda would be another type.
|
/* Cannot capture message_ptr, the lambda would be another type.
|
||||||
* Pass a location where to save the message as priv pointer when
|
* Pass a location where to save the message as priv pointer when
|
||||||
* invoking and get it back here:
|
* invoking and get it back here:
|
||||||
*/
|
*/
|
||||||
request.priv = &message_ptr;
|
request.priv = &message_ptr;
|
||||||
|
|
||||||
request.data_cb =
|
request.data_cb = [](ubus_request* req, int /*type*/, blob_attr* msg) {
|
||||||
[](ubus_request * req, int /*type*/, blob_attr * msg)
|
if (req == nullptr || msg == nullptr) {
|
||||||
{
|
return;
|
||||||
if (req==nullptr || msg==nullptr) { return; }
|
}
|
||||||
|
|
||||||
auto saved = static_cast<msg_ptr *>(req->priv);
|
auto* saved = static_cast<msg_ptr*>(req->priv);
|
||||||
if (saved==nullptr || *saved) { return; }
|
if (saved == nullptr || *saved) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
saved->reset(blob_memdup(msg), free);
|
saved->reset(blob_memdup(msg), free);
|
||||||
if (!*saved) { throw std::bad_alloc(); }
|
if (!*saved) {
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
err = ubus_complete_request(ctx, &request, timeout);
|
err = ubus_complete_request(ctx, &request, timeout);
|
||||||
|
|
||||||
if (err==0) { return message{message_ptr}; }
|
if (err == 0) {
|
||||||
|
return message{message_ptr};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errmsg = "ubus::call error: cannot invoke";
|
std::string errmsg = "ubus::call error: cannot invoke";
|
||||||
errmsg += " (" + std::to_string(err) + ") " + path + " " + method;
|
errmsg += " (" + std::to_string(err) + ") " + path + " " + method;
|
||||||
throw std::runtime_error(errmsg);
|
throw std::runtime_error(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace ubus
|
||||||
} // namespace ubus
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
22
net/nginx-util/src/uci-cxx.cpp
Normal file
22
net/nginx-util/src/uci-cxx.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "uci-cxx.hpp"
|
||||||
|
|
||||||
|
auto main() -> int
|
||||||
|
{
|
||||||
|
uci::element p = uci::package{"nginx"};
|
||||||
|
std::cout << "package " << p.name() << "\n\n";
|
||||||
|
for (auto s : p) {
|
||||||
|
std::cout << "config " << s.type() << " '" << s.name() << "'\n";
|
||||||
|
for (auto o : s) {
|
||||||
|
for (auto i : o) {
|
||||||
|
std::cout << "\t" << o.type() << " " << o.name() << " '" << i.name() << "'\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
}
|
474
net/nginx-util/src/uci-cxx.hpp
Normal file
474
net/nginx-util/src/uci-cxx.hpp
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
#ifndef _UCI_CXX_HPP
|
||||||
|
#define _UCI_CXX_HPP
|
||||||
|
|
||||||
|
#include <uci.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace uci {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class iterator { // like uci_foreach_element_safe.
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uci_ptr& _ptr;
|
||||||
|
|
||||||
|
uci_element* _it = nullptr;
|
||||||
|
|
||||||
|
uci_element* _next = nullptr;
|
||||||
|
|
||||||
|
// wrapper for clang-tidy
|
||||||
|
inline auto _list_to_element(const uci_list* cur) -> uci_element*
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
return list_to_element(cur); // macro casting container=pointer-offset.
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline explicit iterator(const uci_ptr& ptr, const uci_list* cur)
|
||||||
|
: _ptr{ptr}, _it{_list_to_element(cur)}
|
||||||
|
{
|
||||||
|
_next = _list_to_element(_it->list.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline iterator(iterator&&) noexcept = default;
|
||||||
|
|
||||||
|
inline iterator(const iterator&) = delete;
|
||||||
|
|
||||||
|
inline auto operator=(const iterator&) -> iterator& = delete;
|
||||||
|
|
||||||
|
inline auto operator=(iterator &&) -> iterator& = delete;
|
||||||
|
|
||||||
|
auto operator*() -> T
|
||||||
|
{
|
||||||
|
return T{_ptr, _it};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto operator!=(const iterator& rhs) -> bool
|
||||||
|
{
|
||||||
|
return (&_it->list != &rhs._it->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto operator++() -> iterator&
|
||||||
|
{
|
||||||
|
_it = _next;
|
||||||
|
_next = _list_to_element(_next->list.next);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~iterator() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class locked_context {
|
||||||
|
private:
|
||||||
|
static std::mutex inuse;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline locked_context()
|
||||||
|
{
|
||||||
|
inuse.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline locked_context(locked_context&&) noexcept = default;
|
||||||
|
|
||||||
|
inline locked_context(const locked_context&) = delete;
|
||||||
|
|
||||||
|
inline auto operator=(const locked_context&) -> locked_context& = delete;
|
||||||
|
|
||||||
|
inline auto operator=(locked_context &&) -> locked_context& = delete;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
|
inline auto get() -> uci_context* // is member to enforce inuse
|
||||||
|
{
|
||||||
|
static auto free_ctx = [](uci_context* ctx) { uci_free_context(ctx); };
|
||||||
|
static std::unique_ptr<uci_context, decltype(free_ctx)> lazy_ctx{uci_alloc_context(),
|
||||||
|
free_ctx};
|
||||||
|
|
||||||
|
if (!lazy_ctx) { // it could be available on a later call:
|
||||||
|
lazy_ctx.reset(uci_alloc_context());
|
||||||
|
if (!lazy_ctx) {
|
||||||
|
throw std::runtime_error("uci error: cannot allocate context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lazy_ctx.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~locked_context()
|
||||||
|
{
|
||||||
|
inuse.unlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class element {
|
||||||
|
private:
|
||||||
|
uci_list* _begin = nullptr;
|
||||||
|
|
||||||
|
uci_list* _end = nullptr;
|
||||||
|
|
||||||
|
uci_ptr _ptr{};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] inline auto ptr() -> uci_ptr&
|
||||||
|
{
|
||||||
|
return _ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto ptr() const -> const uci_ptr&
|
||||||
|
{
|
||||||
|
return _ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_begin_end(uci_list* begin, uci_list* end)
|
||||||
|
{
|
||||||
|
_begin = begin;
|
||||||
|
_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit element(const uci_ptr& pre, uci_element* last) : _ptr{pre}
|
||||||
|
{
|
||||||
|
_ptr.last = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit element() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline element(element&&) noexcept = default;
|
||||||
|
|
||||||
|
inline element(const element&) = delete;
|
||||||
|
|
||||||
|
inline auto operator=(const element&) -> element& = delete;
|
||||||
|
|
||||||
|
inline auto operator=(element &&) -> element& = delete;
|
||||||
|
|
||||||
|
auto operator[](std::string_view key) const -> T;
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto name() const -> std::string
|
||||||
|
{
|
||||||
|
return _ptr.last->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rename(const char* value) const;
|
||||||
|
|
||||||
|
void commit() const;
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto begin() const -> iterator<T>
|
||||||
|
{
|
||||||
|
return iterator<T>{_ptr, _begin};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto end() const -> iterator<T>
|
||||||
|
{
|
||||||
|
return iterator<T>{_ptr, _end};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~element() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class section;
|
||||||
|
|
||||||
|
class option;
|
||||||
|
|
||||||
|
class item;
|
||||||
|
|
||||||
|
class package : public element<section> {
|
||||||
|
public:
|
||||||
|
inline package(const uci_ptr& pre, uci_element* last) : element{pre, last}
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
ptr().p = uci_to_package(ptr().last); // macro casting pointer-offset.
|
||||||
|
ptr().package = ptr().last->name;
|
||||||
|
|
||||||
|
auto* end = &ptr().p->sections;
|
||||||
|
auto* begin = end->next;
|
||||||
|
init_begin_end(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit package(const char* name);
|
||||||
|
|
||||||
|
auto set(const char* key, const char* type) const -> section;
|
||||||
|
};
|
||||||
|
|
||||||
|
class section : public element<option> {
|
||||||
|
public:
|
||||||
|
inline section(const uci_ptr& pre, uci_element* last) : element{pre, last}
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
ptr().s = uci_to_section(ptr().last); // macro casting pointer-offset.
|
||||||
|
ptr().section = ptr().last->name;
|
||||||
|
|
||||||
|
auto* end = &ptr().s->options;
|
||||||
|
auto* begin = end->next;
|
||||||
|
init_begin_end(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set(const char* key, const char* value) const -> option;
|
||||||
|
|
||||||
|
void del();
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto anonymous() const -> bool
|
||||||
|
{
|
||||||
|
return ptr().s->anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto type() const -> std::string
|
||||||
|
{
|
||||||
|
return ptr().s->type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class option : public element<item> {
|
||||||
|
public:
|
||||||
|
inline option(const uci_ptr& pre, uci_element* last) : element{pre, last}
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
ptr().o = uci_to_option(ptr().last); // macro casting pointer-offset.
|
||||||
|
ptr().option = ptr().last->name;
|
||||||
|
|
||||||
|
if (ptr().o->type == UCI_TYPE_LIST) { // use union ptr().o->v as list:
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
|
||||||
|
auto* end = &ptr().o->v.list;
|
||||||
|
auto* begin = end->next;
|
||||||
|
init_begin_end(begin, end);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto* begin = &ptr().last->list;
|
||||||
|
auto* end = begin->next;
|
||||||
|
init_begin_end(begin, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void del();
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto type() const -> std::string
|
||||||
|
{
|
||||||
|
return (ptr().o->type == UCI_TYPE_LIST ? "list" : "option");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class item : public element<item> {
|
||||||
|
public:
|
||||||
|
inline item(const uci_ptr& pre, uci_element* last) : element{pre, last}
|
||||||
|
{
|
||||||
|
ptr().value = ptr().last->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto type() const -> std::string
|
||||||
|
{
|
||||||
|
return (ptr().o->type == UCI_TYPE_LIST ? "list" : "option");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto name() const -> std::string
|
||||||
|
{
|
||||||
|
return (ptr().last->type == UCI_TYPE_ITEM
|
||||||
|
? ptr().last->name
|
||||||
|
:
|
||||||
|
// else: use union ptr().o->v as string:
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
|
||||||
|
ptr().o->v.string);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline explicit operator bool() const
|
||||||
|
{
|
||||||
|
const auto x = std::string_view{name()};
|
||||||
|
|
||||||
|
if (x == "0" || x == "off" || x == "false" || x == "no" || x == "disabled") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == "1" || x == "on" || x == "true" || x == "yes" || x == "enabled") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto errmsg = std::string{"uci_error: item is not bool "} + name();
|
||||||
|
throw std::runtime_error(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rename(const char* value) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------- implementation: ----------------------------------
|
||||||
|
|
||||||
|
std::mutex locked_context::inuse{};
|
||||||
|
|
||||||
|
inline auto uci_error(uci_context* ctx, const char* prefix = nullptr) -> std::runtime_error
|
||||||
|
{
|
||||||
|
char* errmsg = nullptr;
|
||||||
|
uci_get_errorstr(ctx, &errmsg, prefix);
|
||||||
|
|
||||||
|
std::unique_ptr<char, decltype(&std::free)> auto_free{errmsg, std::free};
|
||||||
|
return std::runtime_error{errmsg};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto element<T>::operator[](std::string_view key) const -> T
|
||||||
|
{
|
||||||
|
for (auto elmt : *this) {
|
||||||
|
if (elmt.name() == key) {
|
||||||
|
return elmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto errmsg = std::string{"uci error: cannot find "}.append(key);
|
||||||
|
throw uci_error(locked_context{}.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void element<T>::rename(const char* value) const
|
||||||
|
{
|
||||||
|
if (value == name()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
auto tmp_ptr = uci_ptr{_ptr};
|
||||||
|
tmp_ptr.value = value;
|
||||||
|
if (uci_rename(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot rename "}.append(name());
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void element<T>::commit() const
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
// TODO(pst) use when possible:
|
||||||
|
// if (uci_commit(ctx.get(), &_ptr.p, true) != 0) {
|
||||||
|
// auto errmsg = std::string{"uci error: cannot commit "} + _ptr.package;
|
||||||
|
// throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
// }
|
||||||
|
auto err = uci_save(ctx.get(), _ptr.p);
|
||||||
|
if (err == 0) {
|
||||||
|
uci_package* tmp_pkg = nullptr;
|
||||||
|
uci_context* tmp_ctx = uci_alloc_context();
|
||||||
|
err = (tmp_ctx == nullptr ? 1 : 0);
|
||||||
|
if (err == 0) {
|
||||||
|
err = uci_load(tmp_ctx, _ptr.package, &tmp_pkg);
|
||||||
|
}
|
||||||
|
if (err == 0) {
|
||||||
|
err = uci_commit(tmp_ctx, &tmp_pkg, false);
|
||||||
|
}
|
||||||
|
if (err == 0) {
|
||||||
|
err = uci_unload(tmp_ctx, tmp_pkg);
|
||||||
|
}
|
||||||
|
if (tmp_ctx != nullptr) {
|
||||||
|
uci_free_context(tmp_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot commit "} + _ptr.package;
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
package::package(const char* name)
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
|
||||||
|
auto* pkg = uci_lookup_package(ctx.get(), name);
|
||||||
|
if (pkg == nullptr) {
|
||||||
|
if (uci_load(ctx.get(), name, &pkg) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot load package "} + name;
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr().package = name;
|
||||||
|
ptr().p = pkg;
|
||||||
|
ptr().last = &pkg->e;
|
||||||
|
|
||||||
|
auto* end = &ptr().p->sections;
|
||||||
|
auto* begin = end->next;
|
||||||
|
init_begin_end(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto package::set(const char* key, const char* type) const -> section
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
|
||||||
|
auto tmp_ptr = uci_ptr{ptr()};
|
||||||
|
tmp_ptr.section = key;
|
||||||
|
tmp_ptr.value = type;
|
||||||
|
if (uci_set(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot set section "} + type + "'" + key +
|
||||||
|
"' in package " + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return section{ptr(), tmp_ptr.last};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto section::set(const char* key, const char* value) const -> option
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
|
||||||
|
auto tmp_ptr = uci_ptr{ptr()};
|
||||||
|
tmp_ptr.option = key;
|
||||||
|
tmp_ptr.value = value;
|
||||||
|
if (uci_set(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot set option "} + key + "'" + value +
|
||||||
|
"' in package " + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return option{ptr(), tmp_ptr.last};
|
||||||
|
}
|
||||||
|
|
||||||
|
void section::del()
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
if (uci_delete(ctx.get(), &ptr()) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot delete section "} + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void option::del()
|
||||||
|
{
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
if (uci_delete(ctx.get(), &ptr()) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot delete option "} + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void item::rename(const char* value) const
|
||||||
|
{
|
||||||
|
if (value == name()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = locked_context{};
|
||||||
|
auto tmp_ptr = uci_ptr{ptr()};
|
||||||
|
|
||||||
|
if (tmp_ptr.last->type != UCI_TYPE_ITEM) {
|
||||||
|
tmp_ptr.value = value;
|
||||||
|
if (uci_set(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot rename item "} + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} // else:
|
||||||
|
|
||||||
|
tmp_ptr.value = tmp_ptr.last->name;
|
||||||
|
if (uci_del_list(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot rename (del) "} + name();
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_ptr.value = value;
|
||||||
|
if (uci_add_list(ctx.get(), &tmp_ptr) != 0) {
|
||||||
|
auto errmsg = std::string{"uci error: cannot rename (add) "} + value;
|
||||||
|
throw uci_error(ctx.get(), errmsg.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace uci
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user