diff --git a/Containers/apache/Caddyfile b/Containers/apache/Caddyfile index 4b92d807..92e84b49 100644 --- a/Containers/apache/Caddyfile +++ b/Containers/apache/Caddyfile @@ -58,6 +58,11 @@ http://{$APACHE_HOST}:23973, # For Collabora callback and WOPI requests, see con reverse_proxy {$WHITEBOARD_HOST}:3002 } + # HaRP (ExApps) + route /exapps/* { + reverse_proxy {$HARP_HOST}:8780 + } + # Nextcloud route { header Strict-Transport-Security max-age=31536000; diff --git a/Containers/nextcloud/entrypoint.sh b/Containers/nextcloud/entrypoint.sh index 5f47a0f4..5cf27364 100644 --- a/Containers/nextcloud/entrypoint.sh +++ b/Containers/nextcloud/entrypoint.sh @@ -1022,13 +1022,13 @@ else fi fi -# Docker socket proxy +# Docker socket proxy / HaRP # app_api is a shipped app if [ -d "/var/www/html/custom_apps/app_api" ]; then php /var/www/html/occ app:disable app_api rm -r "/var/www/html/custom_apps/app_api" fi -if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ]; then +if [ "$DOCKER_SOCKET_PROXY_ENABLED" = 'yes' ] || [ "$HARP_ENABLED" = 'yes' ]; then if [ "$(php /var/www/html/occ config:app:get app_api enabled)" != "yes" ]; then php /var/www/html/occ app:enable app_api fi diff --git a/manual-install/readme.md b/manual-install/readme.md index ea2c2978..6908db09 100644 --- a/manual-install/readme.md +++ b/manual-install/readme.md @@ -12,7 +12,7 @@ You can run the containers that are build for AIO with docker-compose. This come - You lose the AIO interface - You lose update notifications and automatic updates - You lose all AIO backup and restore features -- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi)) +- You lose the built-in [Docker Socket Proxy container](https://github.com/nextcloud/docker-socket-proxy#readme) and [HaRP container](https://github.com/nextcloud/HaRP) (needed for [Nextcloud App API](https://github.com/nextcloud/app_api#nextcloud-appapi)) - You lose all community containers: https://github.com/nextcloud/all-in-one/tree/main/community-containers#community-containers - **You need to know what you are doing, especially when modifying the compose.yaml file** - For updating, you need to strictly follow the at the bottom described update routine diff --git a/manual-install/update-yaml.sh b/manual-install/update-yaml.sh index af746aee..95df1c41 100644 --- a/manual-install/update-yaml.sh +++ b/manual-install/update-yaml.sh @@ -27,6 +27,8 @@ OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "next OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-borgbackup"))')" OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-docker-socket-proxy"))')" OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-docker-socket-proxy"]) then del(.[index("nextcloud-aio-docker-socket-proxy")]) else . end else . end')" +OUTPUT="$(echo "$OUTPUT" | jq 'del(.services[] | select(.container_name == "nextcloud-aio-harp"))')" +OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= if contains(["nextcloud-aio-harp"]) then del(.[index("nextcloud-aio-harp")]) else . end else . end')" OUTPUT="$(echo "$OUTPUT" | jq '.services[] |= if has("depends_on") then .depends_on |= map({ (.): { "condition": "service_started", "required": false } }) else . end' | jq '.services[] |= if has("depends_on") then .depends_on |= reduce .[] as $item ({}; . + $item) else . end')" sudo snap install yq @@ -45,6 +47,8 @@ sed -i 's|- ip_binding: |- |' containers.yml sed -i '/AIO_TOKEN/d' containers.yml sed -i '/AIO_URL/d' containers.yml sed -i '/DOCKER_SOCKET_PROXY_ENABLED/d' containers.yml +sed -i '/HARP_ENABLED/d' containers.yml +sed -i '/HP_SHARED_KEY/d' containers.yml sed -i '/ADDITIONAL_TRUSTED_PROXY/d' containers.yml sed -i '/TURN_DOMAIN/d' containers.yml diff --git a/php/containers.json b/php/containers.json index 8c507f91..e33bfa58 100644 --- a/php/containers.json +++ b/php/containers.json @@ -10,6 +10,7 @@ "nextcloud-aio-talk", "nextcloud-aio-notify-push", "nextcloud-aio-whiteboard", + "nextcloud-aio-harp", "nextcloud-aio-nextcloud" ], "display_name": "Apache", @@ -49,7 +50,8 @@ "APACHE_MAX_SIZE=%APACHE_MAX_SIZE%", "APACHE_MAX_TIME=%NEXTCLOUD_MAX_TIME%", "NOTIFY_PUSH_HOST=nextcloud-aio-notify-push", - "WHITEBOARD_HOST=nextcloud-aio-whiteboard" + "WHITEBOARD_HOST=nextcloud-aio-whiteboard", + "HARP_HOST=nextcloud-aio-harp" ], "volumes": [ { @@ -146,7 +148,8 @@ "nextcloud-aio-fulltextsearch", "nextcloud-aio-talk-recording", "nextcloud-aio-imaginary", - "nextcloud-aio-docker-socket-proxy" + "nextcloud-aio-docker-socket-proxy", + "nextcloud-aio-harp" ], "display_name": "Nextcloud", "image": "ghcr.io/nextcloud-releases/aio-nextcloud", @@ -172,7 +175,8 @@ "SIGNALING_SECRET", "FULLTEXTSEARCH_PASSWORD", "IMAGINARY_SECRET", - "WHITEBOARD_SECRET" + "WHITEBOARD_SECRET", + "HP_SHARED_KEY" ], "volumes": [ { @@ -257,7 +261,9 @@ "THIS_IS_AIO=true", "IMAGINARY_SECRET=%IMAGINARY_SECRET%", "WHITEBOARD_SECRET=%WHITEBOARD_SECRET%", - "WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%" + "WHITEBOARD_ENABLED=%WHITEBOARD_ENABLED%", + "HARP_ENABLED=%HARP_ENABLED%", + "HP_SHARED_KEY=%HP_SHARED_KEY%" ], "stop_grace_period": 600, "restart": "unless-stopped", @@ -846,6 +852,51 @@ "NET_RAW" ] }, + { + "container_name": "nextcloud-aio-harp", + "image_tag": "release", + "display_name": "HaRP", + "image": "ghcr.io/nextcloud/nextcloud-appapi-harp", + "init": true, + "internal_port": "8780", + "expose": [ + "8780" + ], + "environment": [ + "HP_SHARED_KEY=%HP_SHARED_KEY%", + "NC_INSTANCE_URL=https://%NC_DOMAIN%", + "HP_LOG_LEVEL=warning", + "HP_FRP_DISABLE_TLS=true", + "TZ=%TIMEZONE%" + ], + "secrets": [ + "HP_SHARED_KEY" + ], + "volumes": [ + { + "source": "%WATCHTOWER_DOCKER_SOCKET_PATH%", + "destination": "/var/run/docker.sock", + "writeable": false + }, + { + "source": "nextcloud_aio_harp", + "destination": "/certs", + "writeable": true + } + ], + "restart": "unless-stopped", + "read_only": true, + "tmpfs": [ + "/tmp", + "/run/harp" + ], + "cap_drop": [ + "NET_RAW" + ], + "backup_volumes": [ + "nextcloud_aio_harp" + ] + }, { "container_name": "nextcloud-aio-whiteboard", "image_tag": "%AIO_CHANNEL%", diff --git a/php/public/containers-form-submit.js b/php/public/containers-form-submit.js index 1382bced..ee6e62cb 100644 --- a/php/public/containers-form-submit.js +++ b/php/public/containers-form-submit.js @@ -120,9 +120,16 @@ document.addEventListener("DOMContentLoaded", function () { } } + function handleHarpWarning() { + if (document.getElementById("harp").checked) { + alert('⚠️ Warning! Enabling this container comes with possible Security problems since you are exposing the docker socket and all its privileges to the HaRP container. Enable this only if you are sure what you are doing!'); + } + } + // Initialize event listeners for specific behaviors document.getElementById("talk").addEventListener('change', handleTalkVisibility); document.getElementById("docker-socket-proxy").addEventListener('change', handleDockerSocketProxyWarning); + document.getElementById("harp").addEventListener('change', handleHarpWarning); // Initialize talk-recording visibility on page load handleTalkVisibility(); // Ensure talk-recording is correctly initialized diff --git a/php/public/disable-harp.js b/php/public/disable-harp.js new file mode 100644 index 00000000..fb3b992b --- /dev/null +++ b/php/public/disable-harp.js @@ -0,0 +1,7 @@ +document.addEventListener("DOMContentLoaded", function(event) { + // HaRP + let harp = document.getElementById("harp"); + if (harp) { + harp.disabled = true; + } +}); diff --git a/php/public/index.php b/php/public/index.php index b57f65a5..d4a2d47c 100644 --- a/php/public/index.php +++ b/php/public/index.php @@ -136,6 +136,7 @@ $app->get('/containers', function (Request $request, Response $response, array $ 'is_nvidia_gpu_enabled' => $configurationManager->isNvidiaGpuEnabled(), 'is_talk_recording_enabled' => $configurationManager->isTalkRecordingEnabled(), 'is_docker_socket_proxy_enabled' => $configurationManager->isDockerSocketProxyEnabled(), + 'is_harp_enabled' => $configurationManager->isHarpEnabled(), 'is_whiteboard_enabled' => $configurationManager->isWhiteboardEnabled(), 'community_containers' => $configurationManager->listAvailableCommunityContainers(), 'community_containers_enabled' => $configurationManager->GetEnabledCommunityContainers(), diff --git a/php/src/ContainerDefinitionFetcher.php b/php/src/ContainerDefinitionFetcher.php index d7498047..12e49cfd 100644 --- a/php/src/ContainerDefinitionFetcher.php +++ b/php/src/ContainerDefinitionFetcher.php @@ -90,6 +90,10 @@ readonly class ContainerDefinitionFetcher { if (!$this->configurationManager->isDockerSocketProxyEnabled()) { continue; } + } elseif ($entry['container_name'] === 'nextcloud-aio-harp') { + if (!$this->configurationManager->isHarpEnabled()) { + continue; + } } elseif ($entry['container_name'] === 'nextcloud-aio-whiteboard') { if (!$this->configurationManager->isWhiteboardEnabled()) { continue; @@ -199,6 +203,10 @@ readonly class ContainerDefinitionFetcher { if (!$this->configurationManager->isDockerSocketProxyEnabled()) { continue; } + } elseif ($value === 'nextcloud-aio-harp') { + if (!$this->configurationManager->isHarpEnabled()) { + continue; + } } elseif ($value === 'nextcloud-aio-whiteboard') { if (!$this->configurationManager->isWhiteboardEnabled()) { continue; diff --git a/php/src/Controller/ConfigurationController.php b/php/src/Controller/ConfigurationController.php index b449db6a..56b3c80f 100644 --- a/php/src/Controller/ConfigurationController.php +++ b/php/src/Controller/ConfigurationController.php @@ -119,6 +119,11 @@ readonly class ConfigurationController { } else { $this->configurationManager->SetDockerSocketProxyEnabledState(0); } + if (isset($request->getParsedBody()['harp'])) { + $this->configurationManager->SetHarpEnabledState(1); + } else { + $this->configurationManager->SetHarpEnabledState(0); + } if (isset($request->getParsedBody()['whiteboard'])) { $this->configurationManager->SetWhiteboardEnabledState(1); } else { diff --git a/php/src/Data/ConfigurationManager.php b/php/src/Data/ConfigurationManager.php index 320bc477..740cc335 100644 --- a/php/src/Data/ConfigurationManager.php +++ b/php/src/Data/ConfigurationManager.php @@ -162,6 +162,21 @@ class ConfigurationManager $this->WriteConfig($config); } + public function isHarpEnabled() : bool { + $config = $this->GetConfig(); + if (isset($config['isHarpEnabled']) && $config['isHarpEnabled'] === 1) { + return true; + } else { + return false; + } + } + + public function SetHarpEnabledState(int $value) : void { + $config = $this->GetConfig(); + $config['isHarpEnabled'] = $value; + $this->WriteConfig($config); + } + public function isWhiteboardEnabled() : bool { $config = $this->GetConfig(); if (isset($config['isWhiteboardEnabled']) && $config['isWhiteboardEnabled'] === 0) { diff --git a/php/src/Docker/DockerActionManager.php b/php/src/Docker/DockerActionManager.php index fb3701a4..603bba78 100644 --- a/php/src/Docker/DockerActionManager.php +++ b/php/src/Docker/DockerActionManager.php @@ -582,6 +582,7 @@ readonly class DockerActionManager { 'IMAGINARY_ENABLED' => $this->configurationManager->isImaginaryEnabled() ? 'yes' : '', 'FULLTEXTSEARCH_ENABLED' => $this->configurationManager->isFulltextsearchEnabled() ? 'yes' : '', 'DOCKER_SOCKET_PROXY_ENABLED' => $this->configurationManager->isDockerSocketProxyEnabled() ? 'yes' : '', + 'HARP_ENABLED' => $this->configurationManager->isHarpEnabled() ? 'yes' : '', 'NEXTCLOUD_UPLOAD_LIMIT' => $this->configurationManager->GetNextcloudUploadLimit(), 'NEXTCLOUD_MEMORY_LIMIT' => $this->configurationManager->GetNextcloudMemoryLimit(), 'NEXTCLOUD_MAX_TIME' => $this->configurationManager->GetNextcloudMaxTime(), diff --git a/php/templates/includes/optional-containers.twig b/php/templates/includes/optional-containers.twig index dcf59bfb..4cc07006 100644 --- a/php/templates/includes/optional-containers.twig +++ b/php/templates/includes/optional-containers.twig @@ -198,6 +198,20 @@ >
++ + +
+