From 553ecc14904427386538b851b8937723bd93be18 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:46:05 +0200 Subject: [PATCH] fix: PowerShell installer fixes for Windows and Logto console login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three issues fixed: 1. Docker socket: use /var/run/docker.sock instead of Windows named pipe (//./pipe/docker_engine) — Linux containers can't use named pipes. 2. FQDN detection: reverse-DNS lookup on host IPs to find the FQDN instead of relying on GetHostEntry which returns bare hostname on Windows machines with DNS-registered domain suffixes. 3. Reinstall path duplication: Push-Location/Pop-Location in the reinstall handler used try/catch without finally, so Pop-Location was skipped when docker compose wrote to stderr under ErrorActionPreference=Stop. CWD stayed in the install dir, causing the relative ./cameleer default to resolve to cameleer/cameleer. 4. Logto bootstrap: register admin-console redirect URIs and add the admin user to Logto's internal organizations (t-default, t-admin) with the admin role — both required for console login to work. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/logto-bootstrap.sh | 22 ++++++++++++++++++++++ installer/install.ps1 | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/docker/logto-bootstrap.sh b/docker/logto-bootstrap.sh index 78aa7ee..9e04051 100644 --- a/docker/logto-bootstrap.sh +++ b/docker/logto-bootstrap.sh @@ -476,6 +476,28 @@ if [ -n "$ADMIN_TENANT_USER_ID" ] && [ "$ADMIN_TENANT_USER_ID" != "null" ]; then admin_api_patch "/api/sign-in-exp" '{"signInMode": "SignIn"}' >/dev/null 2>&1 log "Set sign-in mode to SignIn." + # Register admin-console redirect URIs (Logto ships with empty URIs) + ADMIN_PUBLIC="${ADMIN_ENDPOINT:-${PROTO}://${HOST}:3002}" + admin_api_patch "/api/applications/admin-console" "{ + \"oidcClientMetadata\": { + \"redirectUris\": [\"${ADMIN_PUBLIC}/console/callback\"], + \"postLogoutRedirectUris\": [\"${ADMIN_PUBLIC}/console\"] + } + }" >/dev/null 2>&1 + log "Registered admin-console redirect URIs." + + # Add admin user to Logto's internal organizations (required for console login) + for ORG_ID in t-default t-admin; do + admin_api_post "/api/organizations/${ORG_ID}/users" "{\"userIds\": [\"$ADMIN_TENANT_USER_ID\"]}" >/dev/null 2>&1 + done + ADMIN_ORG_ROLE_ID=$(admin_api_get "/api/organization-roles" | jq -r '.[] | select(.name == "admin") | .id') + if [ -n "$ADMIN_ORG_ROLE_ID" ] && [ "$ADMIN_ORG_ROLE_ID" != "null" ]; then + for ORG_ID in t-default t-admin; do + admin_api_post "/api/organizations/${ORG_ID}/users/${ADMIN_TENANT_USER_ID}/roles" "{\"organizationRoleIds\": [\"$ADMIN_ORG_ROLE_ID\"]}" >/dev/null 2>&1 + done + fi + log "Added admin to Logto console organizations." + log "SaaS admin granted Logto console access." else log "WARNING: Could not create admin console user" diff --git a/installer/install.ps1 b/installer/install.ps1 index b90315f..776647d 100644 --- a/installer/install.ps1 +++ b/installer/install.ps1 @@ -347,19 +347,36 @@ function Check-Prerequisites { function Auto-Detect { if (-not $script:cfg.PublicHost) { + $detectedHost = $null + # Try reverse DNS on each host IP — picks up FQDN from DNS server try { - $fqdn = [System.Net.Dns]::GetHostEntry([System.Net.Dns]::GetHostName()).HostName - $script:cfg.PublicHost = $fqdn.ToLower() - } catch { - $script:cfg.PublicHost = [System.Net.Dns]::GetHostName().ToLower() + foreach ($addr in [System.Net.Dns]::GetHostAddresses([System.Net.Dns]::GetHostName())) { + if ($addr.AddressFamily -ne 'InterNetwork') { continue } # IPv4 only + if ($addr.ToString().StartsWith('127.')) { continue } + try { + $rev = [System.Net.Dns]::GetHostEntry($addr).HostName + if ($rev -and $rev.Contains('.')) { + $detectedHost = $rev + break + } + } catch {} + } + } catch {} + if (-not $detectedHost) { + # Fallback: .NET forward lookup, then bare hostname + try { + $detectedHost = [System.Net.Dns]::GetHostEntry([System.Net.Dns]::GetHostName()).HostName + } catch { + $detectedHost = [System.Net.Dns]::GetHostName() + } } + $script:cfg.PublicHost = $detectedHost.ToLower() } if (-not $script:cfg.DockerSocket) { - if ($env:OS -eq 'Windows_NT') { - $script:cfg.DockerSocket = '//./pipe/docker_engine' - } else { - $script:cfg.DockerSocket = $DEFAULT_DOCKER_SOCKET - } + # Always use /var/run/docker.sock — containers are Linux and Docker Desktop + # maps the host socket into the VM automatically. The Windows named pipe + # (//./pipe/docker_engine) does NOT work as a volume mount for Linux containers. + $script:cfg.DockerSocket = $DEFAULT_DOCKER_SOCKET } } @@ -1720,12 +1737,12 @@ function Handle-Rerun { } Log-Info 'Reinstalling...' try { Invoke-ComposeDown } catch {} + Push-Location $c.InstallDir try { - Push-Location $c.InstallDir $proj = Coalesce $c.ComposeProject 'cameleer-saas' docker compose -p $proj down -v 2>$null - Pop-Location } catch {} + finally { Pop-Location } foreach ($fname in @('.env','.env.bak','docker-compose.yml','cameleer.conf','credentials.txt','INSTALL.md','traefik-dynamic.yml')) { $fp = Join-Path $c.InstallDir $fname if (Test-Path $fp) { Remove-Item $fp -Force }