From d026857b99c0bee155b88c7470e3a018595a80f9 Mon Sep 17 00:00:00 2001 From: spacesops Date: Tue, 25 Aug 2026 16:20:05 -0400 Subject: [PATCH] pre --- README.md | 22 +++++++++++++--------- background.png | Bin 0 -> 39509 bytes spacesops.png | Bin 0 -> 13803 bytes startos/actions/configurePlatform.ts | 20 +++++++++++++++++++- startos/fileModels/storeJson.ts | 1 + startos/i18n/dictionaries/default.ts | 4 +++- startos/main.ts | 5 ++++- startos/manifest/index.ts | 2 +- startos/utils.ts | 9 ++++++--- startos/versions/index.ts | 7 +++++-- startos/versions/v1.0.2.0.ts | 14 ++++++++++++++ startos/versions/v1.0.2.1.ts | 13 +++++++++++++ startos/versions/v1.0.3.0.ts | 14 ++++++++++++++ 13 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 background.png create mode 100644 spacesops.png create mode 100644 startos/versions/v1.0.2.0.ts create mode 100644 startos/versions/v1.0.2.1.ts create mode 100644 startos/versions/v1.0.3.0.ts diff --git a/README.md b/README.md index 5b8c68b..454a99c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ auto-connects to it — see [Installation and First-Run Flow](#installation-and- | Field | Value | | --- | --- | -| Image | `docker.io/spacesops/spacesops:v1.0.1` | +| Image | `docker.io/spacesops/spacesops:v1.0.3` | | Base | `node:20-alpine` | | Architectures | `x86_64` (linux/amd64), `aarch64` (linux/arm64) | | Entrypoint | The image's `/app/docker-entrypoint.sh` is **kept**. StartOS runs `/app/docker-entrypoint.sh node server.js` as the daemon. | @@ -86,7 +86,7 @@ credentials. Instead, at startup it: 2. Reads `spacedAuth.{username,password}` from the Spaces `store.json`. 3. Connects to spaced at `http://spaces.startos:7225` with those credentials, exporting `SPACED_RPC_URL`, `SPACED_RPC_USER`, `SPACED_RPC_PASSWORD`, and - `SPACED_WALLETLOAD_NAME=main`. + `SPACED_WALLETLOAD_NAME=default`. If Spaces is not installed yet, or its credentials have not been seeded, the service **restarts until they appear** — this is expected. (Dependency @@ -101,6 +101,7 @@ declarations do not gate startup; SpacesOps handles readiness itself.) | `OPERATOR_SECRET_HEX` / `OPERATOR_PUBLIC_HEX` (generated or imported) | | | `PLATFORM_SESSION_SECRET` (generated) | | | `SPACED_RPC_*` (auto-wired from Spaces) | | +| `PLATFORM_CALLBACK_HOST` (defaults to `spacesops.startos`; override via **Configure Platform**) | | | Optional: `OPERATOR_RELAY`, `PLATFORM_MODE`, `COINGECKO_*`, `SUBS_*` (via **Configure Platform**) | | ## Network Access and Interfaces @@ -116,7 +117,7 @@ declarations do not gate startup; SpacesOps handles readiness itself.) | `show-operator-credentials` | Show Operator Credentials | Enabled | Any | — | Displays the Nostr operator keypair: npub (QR), hex public key, and the masked nsec / hex secret. | | `import-operator-key` | Import Operator Key | Enabled | Any | 64-char hex secret key | Replaces the operator keypair. Derives the public key automatically. **Warns** that it changes the operator identity; the service restarts to apply it. | | `show-admin-credentials` | Show Admin Credentials | Enabled | Any | — | Displays the **fixed** built-in admin login (`admin` / `Whatever!`) with a security warning. | -| `configure-platform` | Configure Platform | Enabled | Any | relay, mode, CoinGecko, SUBS (all optional) | Sets the Nostr relay, theme mode, pricing, and SUBS backend. Saving restarts the service. | +| `configure-platform` | Configure Platform | Enabled | Any | relay, mode, CoinGecko, SUBS, callback host | Sets the Nostr relay, theme mode, pricing, SUBS backend, and `PLATFORM_CALLBACK_HOST`. Saving restarts the service. | ## Backups and Restore @@ -139,7 +140,7 @@ volume is **not** part of this package's backup. and sync Spaces before (or alongside) SpacesOps; the service restarts until those credentials are available. 2. **The admin password is fixed and well-known.** Admin Basic Auth is hardcoded - in the v1.0.1 image as `admin` / `Whatever!` with **no environment override**. + in the v1.0.3 image as `admin` / `Whatever!` with **no environment override**. It cannot be changed without rebuilding the image. **Keep this service private (Tor-only) and never expose its admin routes to the public internet** — the admin area can run SQL and manage tenants. See **Show Admin Credentials**. @@ -147,14 +148,16 @@ volume is **not** part of this package's backup. StartOS reverse proxy can reach the app (it otherwise binds `127.0.0.1:3000`). 4. **Subname-purchase and pricing are off by default.** They activate only when you fill in the relevant fields in **Configure Platform** (`COINGECKO_*` for - pricing, `SUBS_*` for subname purchase + cert-callback flows). + pricing, `SUBS_*` for subname purchase + cert-callback flows). Payment + callback URLs use `PLATFORM_CALLBACK_HOST`, which defaults to `spacesops.startos` + and can be overridden in **Configure Platform**. 5. **The SUBS backend is not auto-wired to the Spaces subs daemon in v1.** The Spaces service's subs daemon listens on 7777 with a different API/auth than the SUBS endpoint (port 7244) SpacesOps expects, so SUBS must be configured manually if used. StartOS always sets `NODE_EXTRA_CA_CERTS` to the StartOS root CA (fetched via `sdk.getSslCertificate` for the SUBS `*.startos` hostname when configured, otherwise `spaces.startos`) so outbound HTTPS to - same-host StartOS services succeeds and the v1.0.1 image entrypoint does not + same-host StartOS services succeeds and the v1.0.3 image entrypoint does not crash on its broken `_SCRIPT_DIR` default. ## What Is Unchanged from Upstream @@ -170,8 +173,8 @@ volume is **not** part of this package's backup. ```yaml package_id: spacesops -upstream_version: 1.0.1 -image: docker.io/spacesops/spacesops:v1.0.1 +upstream_version: 1.0.3 +image: docker.io/spacesops/spacesops:v1.0.3 architectures: [x86_64, aarch64] volumes: main: /data @@ -193,7 +196,8 @@ startos_managed_env_vars: - SPACED_RPC_URL # http://spaces.startos:7225 - SPACED_RPC_USER # from Spaces store.json - SPACED_RPC_PASSWORD # from Spaces store.json - - SPACED_WALLETLOAD_NAME # main + - SPACED_WALLETLOAD_NAME # default + - PLATFORM_CALLBACK_HOST # store.platformCallbackHost ?? spacesops.startos optional_env_vars: # only set when configured via configure-platform - COINGECKO_API_KEY - COINGECKO_TOKEN_COINS diff --git a/background.png b/background.png new file mode 100644 index 0000000000000000000000000000000000000000..11e516969b65958afbe3c540b0c2d33dd53c78c8 GIT binary patch literal 39509 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 ({ name: i18n('Configure Platform'), description: i18n( - 'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, and SUBS backend. Saving restarts the service so the new settings take effect.', + 'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, SUBS backend, and callback host. Saving restarts the service so the new settings take effect.', ), warning: null, allowedStatuses: 'any', @@ -136,6 +151,8 @@ export const configurePlatform = sdk.Action.withInput( subsUrl: store?.subsUrl ?? null, subsUser: store?.subsUser ?? null, subsPassword: store?.subsPassword ?? null, + platformCallbackHost: + store?.platformCallbackHost ?? DEFAULT_PLATFORM_CALLBACK_HOST, } }, @@ -149,6 +166,7 @@ export const configurePlatform = sdk.Action.withInput( subsUrl: input.subsUrl || null, subsUser: input.subsUser || null, subsPassword: input.subsPassword || null, + platformCallbackHost: input.platformCallbackHost?.trim() || null, }) return { diff --git a/startos/fileModels/storeJson.ts b/startos/fileModels/storeJson.ts index 1cc93a4..129fc01 100644 --- a/startos/fileModels/storeJson.ts +++ b/startos/fileModels/storeJson.ts @@ -16,6 +16,7 @@ const shape = z.object({ subsUrl: z.string().nullable().catch(null), subsUser: z.string().nullable().catch(null), subsPassword: z.string().nullable().catch(null), + platformCallbackHost: z.string().nullable().catch(null), }) export const storeJson = FileHelper.json( diff --git a/startos/i18n/dictionaries/default.ts b/startos/i18n/dictionaries/default.ts index c850ba7..29565dd 100644 --- a/startos/i18n/dictionaries/default.ts +++ b/startos/i18n/dictionaries/default.ts @@ -16,7 +16,7 @@ const dict = { 'SUBS RPC Password': 12, 'Optional SUBS RPC password (SUBS_RPC_PASSWORD).': 13, 'Configure Platform': 14, - 'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, and SUBS backend. Saving restarts the service so the new settings take effect.': 15, + 'Set optional SpacesOps settings: Nostr relay, theme mode, CoinGecko pricing, SUBS backend, and callback host. Saving restarts the service so the new settings take effect.': 15, Success: 16, 'Platform configuration saved. The service is restarting to apply the new settings.': 17, 'Operator Secret Key (hex)': 18, @@ -50,6 +50,8 @@ const dict = { 'Web Interface': 46, 'The web interface is ready': 47, 'The web interface is not ready': 48, + 'CALLBACK HOST': 49, + 'Callback hostname SpacesOps uses for cert-callback flows (PLATFORM_CALLBACK_HOST). Leave blank to use spacesops.startos.': 50, } as const /** diff --git a/startos/main.ts b/startos/main.ts index 055b899..df66ea7 100644 --- a/startos/main.ts +++ b/startos/main.ts @@ -5,6 +5,7 @@ import { sdk } from './sdk' import { dataDir, DEFAULT_OPERATOR_RELAY, + DEFAULT_PLATFORM_CALLBACK_HOST, DEFAULT_PLATFORM_MODE, SPACED_RPC_URL, SPACED_WALLETLOAD_NAME, @@ -110,8 +111,10 @@ export const main = sdk.setupMain(async ({ effects }) => { if (store.subsUrl) env.SUBS_URI_VALUE = store.subsUrl if (store.subsUser) env.SUBS_RPC_USER = store.subsUser if (store.subsPassword) env.SUBS_RPC_PASSWORD = store.subsPassword + env.PLATFORM_CALLBACK_HOST = + store.platformCallbackHost ?? DEFAULT_PLATFORM_CALLBACK_HOST - // v1.0.1's entrypoint sources setup-spacesops-env.sh with set -u. That file + // v1.0.3's entrypoint sources setup-spacesops-env.sh with set -u. That file // exports NODE_EXTRA_CA_CERTS using ${_SCRIPT_DIR}, but _SCRIPT_DIR is set on // a separate non-export line the entrypoint never evals — startup crashes // unless NODE_EXTRA_CA_CERTS is already set. Fetch the StartOS root CA for diff --git a/startos/manifest/index.ts b/startos/manifest/index.ts index 69904ed..3854a95 100644 --- a/startos/manifest/index.ts +++ b/startos/manifest/index.ts @@ -14,7 +14,7 @@ export const manifest = setupManifest({ volumes: ['main'], images: { spacesops: { - source: { dockerTag: 'spacesops/spacesops:v1.0.1' }, + source: { dockerTag: 'spacesops/spacesops:v1.0.3' }, arch: ['x86_64', 'aarch64'], }, }, diff --git a/startos/utils.ts b/startos/utils.ts index af2fc15..ca85294 100644 --- a/startos/utils.ts +++ b/startos/utils.ts @@ -18,16 +18,16 @@ export const SPACES_PACKAGE_ID = 'spaces' // Spaces exposes its spaced JSON-RPC as the `spaces-api` interface on 7225, // reachable from a dependent package at this address. export const SPACED_RPC_URL = 'http://spaces.startos:7225' -export const SPACED_WALLETLOAD_NAME = 'main' +export const SPACED_WALLETLOAD_NAME = 'default' -// Admin Basic Auth is baked into the v1.0.1 image with NO env override. It +// Admin Basic Auth is baked into the v1.0.3 image with NO env override. It // cannot be changed without rebuilding the image. Surfaced (with a warning) // via the "Show Admin Credentials" action. export const ADMIN_USER = 'admin' export const ADMIN_PASSWORD = 'Whatever!' // Where StartOS writes the StartOS root CA for outbound *.startos HTTPS (see -// main.ts). Always injected as NODE_EXTRA_CA_CERTS — required on v1.0.1+ where +// main.ts). Always injected as NODE_EXTRA_CA_CERTS — required on v1.0.3+ where // the image entrypoint's setup-spacesops-env.sh references _SCRIPT_DIR without // defining it under set -u. export const nodeExtraCaCertVolumeSubpath = '.startos/startos-root-ca.crt' @@ -51,6 +51,9 @@ export function startOsHostnameFromUrl(url: string): string | null { export const DEFAULT_OPERATOR_RELAY = 'wss://relay.primal.net' export const DEFAULT_PLATFORM_MODE = 'prod' export const DEFAULT_COINGECKO_TOKEN_COINS = 'bitcoin' +// Hostname SpacesOps uses when building payment callback URLs +// (http://${PLATFORM_CALLBACK_HOST}:${PORT}/...). +export const DEFAULT_PLATFORM_CALLBACK_HOST = 'spacesops.startos' // 32 random bytes as a 64-char hex string — a secp256k1/Nostr secret key. The // odds of an out-of-range key are ~1 in 2^128; if getPublicKey rejects it, diff --git a/startos/versions/index.ts b/startos/versions/index.ts index f480cb4..f750bcf 100644 --- a/startos/versions/index.ts +++ b/startos/versions/index.ts @@ -1,8 +1,11 @@ import { VersionGraph } from '@start9labs/start-sdk' import { v_1_0_1_0 } from './v1.0.1.0' import { v_1_0_1_1 } from './v1.0.1.1' +import { v_1_0_2_0 } from './v1.0.2.0' +import { v_1_0_2_1 } from './v1.0.2.1' +import { v_1_0_3_0 } from './v1.0.3.0' export const versionGraph = VersionGraph.of({ - current: v_1_0_1_1, - other: [v_1_0_1_0], + current: v_1_0_3_0, + other: [v_1_0_2_1, v_1_0_2_0, v_1_0_1_1, v_1_0_1_0], }) diff --git a/startos/versions/v1.0.2.0.ts b/startos/versions/v1.0.2.0.ts new file mode 100644 index 0000000..3ec2fdb --- /dev/null +++ b/startos/versions/v1.0.2.0.ts @@ -0,0 +1,14 @@ +import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' + +export const v_1_0_2_0 = VersionInfo.of({ + version: '1.0.2:0', + releaseNotes: { + en_US: `Upstream upgrade to SpacesOps v1.0.2. +- Bumps the image to spacesops/spacesops:v1.0.2 on x86_64 and aarch64. +- No StartOS-side configuration, action, or migration changes; existing operator keypair, session secret, and Configure-Platform settings are preserved.`, + }, + migrations: { + up: async ({ effects }) => {}, + down: IMPOSSIBLE, + }, +}) diff --git a/startos/versions/v1.0.2.1.ts b/startos/versions/v1.0.2.1.ts new file mode 100644 index 0000000..642952d --- /dev/null +++ b/startos/versions/v1.0.2.1.ts @@ -0,0 +1,13 @@ +import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' + +export const v_1_0_2_1 = VersionInfo.of({ + version: '1.0.2:1', + releaseNotes: { + en_US: `- Adds PLATFORM_CALLBACK_HOST to Configure Platform (defaults to spacesops.startos) for cert-callback and payment callback URLs. +- Sets SPACED_WALLETLOAD_NAME to default (was main).`, + }, + migrations: { + up: async ({ effects }) => {}, + down: IMPOSSIBLE, + }, +}) diff --git a/startos/versions/v1.0.3.0.ts b/startos/versions/v1.0.3.0.ts new file mode 100644 index 0000000..7341348 --- /dev/null +++ b/startos/versions/v1.0.3.0.ts @@ -0,0 +1,14 @@ +import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' + +export const v_1_0_3_0 = VersionInfo.of({ + version: '1.0.3:0', + releaseNotes: { + en_US: `Upstream upgrade to SpacesOps v1.0.3. +- Bumps the image to spacesops/spacesops:v1.0.3 on x86_64 and aarch64. +- No StartOS-side configuration, action, or migration changes; existing operator keypair, session secret, and Configure-Platform settings are preserved.`, + }, + migrations: { + up: async ({ effects }) => {}, + down: IMPOSSIBLE, + }, +})