Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ns-api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=ns-api
PKG_VERSION:=3.7.1
PKG_VERSION:=3.8.0
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/ns-api-$(PKG_VERSION)
Expand Down
14 changes: 13 additions & 1 deletion packages/ns-api/files/ns.controller
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ def get_version():
return version.replace("-", " ", 1)
return version

def get_package_version(package):
# installed version of an apk package, or an empty string if it is not installed
try:
output = subprocess.run(["apk", "list", "-I", package], capture_output=True, text=True).stdout.strip()
return output.split()[0].removeprefix(f"{package}-") if output else ""
except (subprocess.SubprocessError, IndexError):
return ""

def parse_key(line):
# parse key: <type> <data> <comment>
tmp = line.strip().split(" ")
Expand Down Expand Up @@ -123,7 +131,11 @@ def info():
ret["fqdn"] = get_hostname()
ret["system_id"] = u.get("ns-plug", "config", "system_id", default="")
ret["subscription_type"] = u.get("ns-plug", "config", "type", default="")
ret["api_version"] = subprocess.run(["apk", "list", "-I", "ns-api"], capture_output=True, text=True).stdout.strip().split()[0].removeprefix("ns-api-")
ret["api_version"] = get_package_version("ns-api")
# reported separately from api_version: the controller uses it to decide whether this unit can
# serve its own UI under the controller's per-unit path prefix, and the two packages are
# versioned independently
ret["ui_version"] = get_package_version("ns-ui")
return ret

def add_ssh_key(ssh_key):
Expand Down
21 changes: 21 additions & 0 deletions packages/ns-api/files/ns.update
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ def check_package_updates():
ret.sort(key=lambda package: package["package"])
return {"updates": ret}

def list_installed_packages():
try:
p = subprocess.run(["/usr/bin/apk", "query", "--installed", "--format", "json",
"--fields", "name,version,description", "*"],
check=True, capture_output=True, text=True)
except Exception as e:
print(e, file=sys.stderr)
return utils.generic_error("apk_query_failed")
ret = []
for package in json.loads(p.stdout):
ret.append({
"name": package.get("name", ""),
"version": package.get("version", ""),
"description": package.get("description", "")
})
ret.sort(key=lambda package: package["name"])
return {"packages": ret}

def get_package_updates_lat_check():
return {"lastCheck": last_package_check()}

Expand Down Expand Up @@ -184,6 +202,7 @@ if cmd == "list":
json.dumps(
{
"check-package-updates": {},
"list-installed-packages": {},
"get-package-updates-last-check": {},
"get-automatic-updates-status": {},
"install-package-updates": {},
Expand All @@ -201,6 +220,8 @@ elif cmd == "call":
action = sys.argv[2]
if action == "check-package-updates":
ret = check_package_updates()
elif action == "list-installed-packages":
ret = list_installed_packages()
elif action == "get-package-updates-last-check":
ret = get_package_updates_lat_check()
elif action == "get-automatic-updates-status":
Expand Down
6 changes: 4 additions & 2 deletions packages/ns-ui/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=ns-ui
# renovate: datasource=github-releases depName=NethServer/nethsecurity-ui
PKG_VERSION:=2.23.3
PKG_VERSION:=2.24.0
PKG_RELEASE:=1

PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/NethServer/nethsecurity-ui.git
PKG_SOURCE_VERSION:=$(PKG_VERSION)
# PKG_VERSION is what the controller gates on (ns-api reports it as info.ui_version), but renovate
# maintains it independently of this SHA. Once the UI release is tagged, use $(PKG_VERSION) here.
PKG_SOURCE_VERSION:=82b3c57b7e4d3d2c0fe79ffece3811b0d078148e
PKG_SOURCE_SUBDIR:=nethsecurity-ui-$(PKG_SOURCE_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
PKG_MIRROR_HASH:=skip
Expand Down
67 changes: 51 additions & 16 deletions packages/ns-ui/files/ns-ui
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,95 @@ set -e
NSUI_FILE=/etc/nginx/conf.d/00ns.locations
NSUI_EXTRA_FILE=/etc/nginx/conf.d/ns-ui.conf
NSUI_API_LOCATIONS_FILE=/etc/nginx/conf.d/ns-ui-api.inc
NSUI_STATIC_LOCATIONS_FILE=/etc/nginx/conf.d/ns-ui-static.inc
LUCI_FILE=/etc/nginx/conf.d/luci.locations

# Shared API locations, included by both the default and extra ns-ui instances
# This is being put here instead of statically due to the following issue:
# https://github.com/NethServer/nethsecurity/issues/1834
cat <<'EOF' > "$NSUI_API_LOCATIONS_FILE"
# body size limits on unauthenticated routes to prevent memory exhaustion
# X-Forwarded-For is appended, not overwritten: when a controller proxies this unit, $remote_addr
# is the controller's VPN address, so overwriting would collapse every remote client into one
# address and make rate limiting and audit logs useless.
location = /api/login {
client_max_body_size 32k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8090;
}

location = /api/logout {
client_max_body_size 1k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8090;
}

location = /api/2fa/otp-verify {
client_max_body_size 32k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8090;
}

location /api/ {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8090/api/;
proxy_read_timeout 180s;
}
EOF

# Shared static locations, included by both the default and extra ns-ui instances.
#
# Cache headers matter more than they look: index.html references content-hashed chunks, and
# without them browsers apply heuristic freshness and can serve a stale index.html for days. After
# a package upgrade the chunks it names are gone, try_files returns 404 and the UI is a white
# screen until a hard reload.
cat <<'EOF' > "$NSUI_STATIC_LOCATIONS_FILE"
location / {
gzip on;
gzip_types text/css application/javascript image/svg+xml;
root /www-ns;
try_files $uri $uri/ =404;
}

# hashed filenames, so these are safe to keep forever
location /assets/ {
gzip on;
gzip_types text/css application/javascript image/svg+xml;
root /www-ns;
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
}

# unhashed, and the entry point to everything else: must always be revalidated
location = /index.html {
root /www-ns;
add_header Cache-Control "no-cache";
}

location = /branding.js {
root /www-ns;
add_header Cache-Control "no-cache";
}

location = /favicon.ico {
root /www-ns;
add_header Cache-Control "no-cache";
}
EOF

# Manage default ns-ui instance on port 443
nsui_enable=$(uci -q get ns-ui.config.nsui_enable)
rm -f "$NSUI_FILE.disabled"
if [ "$nsui_enable" == "1" ]; then
cat <<EOF > "$NSUI_FILE"
# NethSecurity UI and API

location / {
root /www-ns;
try_files \$uri \$uri/ /index.html;
}

include $NSUI_STATIC_LOCATIONS_FILE;
include $NSUI_API_LOCATIONS_FILE;
EOF
else
Expand Down Expand Up @@ -93,13 +134,7 @@ server {
server_tokens $server_tokens;

# enable NS UI
location / {
gzip on;
gzip_types text/css application/javascript image/svg+xml;
root /www-ns;
try_files \$uri \$uri/ /index.html;
}

include $NSUI_STATIC_LOCATIONS_FILE;
include $NSUI_API_LOCATIONS_FILE;
}
EOF
Expand Down
Loading