From a9ca956c2e920a9b0f6fde9775cac8dbe833491b Mon Sep 17 00:00:00 2001 From: Local Dev Date: Fri, 9 Oct 2026 01:23:21 +0200 Subject: [PATCH] prometheus: standalone identity + first-wave Silent Mode listings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four changes, one coherent pass: 1. Prometheus gets its own flame mark (SVG, not an emoji). Used in the topnav brand, in the hero at 88 px, and as the favicon. Replaces the 🔥 glyph in the service and in site/prometheus/index.html. 2. silentmode.st/prometheus is now a brief introduction with two big buttons (Open prometheus.x · Open apps.silentmode.st mirror) and a short "what / who / status" block, instead of the full category grid that duplicated what prometheus.x already renders. The /prometheus page's job on silentmode.st is "point you at the real site," not host the content. 3. Footer on the Prometheus service drops the "Silent Mode — a Deviant project" byline and reframes the sibling-x links as "Also live in the decentralized web:" so Prometheus reads as its own site rather than a Silent Mode subpage. Keeps the attribution via the MPL-2.0 + source link on the final line. aegis.x and pithos.x added to the sibling row. 4. Four Silent Mode apps seeded as first-wave listings (scripts/seed-listings.json + scripts/seed.mjs). Theseus Navigator, Ariadne's Thread (Windows + Android), Pithos. Each carries the project's own SVG icon from public/icons/, pulled from the project's own site. The seed is a direct-DB insert (not through /api/listing) with signer_address = chipnet operator and signature = sentinel `SM_OPERATOR_SEED`; scan_report is an operator-attested envelope signed by the service key so the display pipeline is unchanged. Run with `node scripts/seed.mjs`; idempotent (skips existing (publisher, slug)). Deliberately NOT seeded: Theseus extensions that have no standalone form — pdf-editor, docx-editor, shield-blocker, bergamot provider. They ship via Theseus's own OTA, not as Prometheus listings. Aegis is in the same boat today (a Theseus bundled add-on without a standalone binary); its icon is included in public/icons/ for when it has its own distribution. Real file sizes + SHAs come from the current dl.silentmode.st manifest (theseus 0.3.89, ariadne resolver 0.1.13, ariadne android 0.22, pithos-desktop 0.3.26). When APS1 lands cross-session, these listings migrate to real on-chain records signed by each project's own publisher key and the sentinel values go away. --- public/favicon.svg | 22 ++++++- public/icons/aegis.svg | 12 ++++ public/icons/ariadne.svg | 6 ++ public/icons/pithos.svg | 1 + public/icons/sirius.svg | 8 +++ public/icons/theseus.svg | 15 +++++ scripts/seed-listings.json | 62 +++++++++++++++++++ scripts/seed.mjs | 123 +++++++++++++++++++++++++++++++++++++ service/layout.js | 27 ++++---- service/pages.js | 12 ++-- 10 files changed, 269 insertions(+), 19 deletions(-) create mode 100644 public/icons/aegis.svg create mode 100644 public/icons/ariadne.svg create mode 100644 public/icons/pithos.svg create mode 100644 public/icons/sirius.svg create mode 100644 public/icons/theseus.svg create mode 100644 scripts/seed-listings.json create mode 100644 scripts/seed.mjs diff --git a/public/favicon.svg b/public/favicon.svg index 43732c2..4f151e5 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,5 +1,23 @@ - - + + + + + + diff --git a/public/icons/aegis.svg b/public/icons/aegis.svg new file mode 100644 index 0000000..0d4c1ed --- /dev/null +++ b/public/icons/aegis.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/public/icons/ariadne.svg b/public/icons/ariadne.svg new file mode 100644 index 0000000..7f76656 --- /dev/null +++ b/public/icons/ariadne.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/icons/pithos.svg b/public/icons/pithos.svg new file mode 100644 index 0000000..4335a25 --- /dev/null +++ b/public/icons/pithos.svg @@ -0,0 +1 @@ + diff --git a/public/icons/sirius.svg b/public/icons/sirius.svg new file mode 100644 index 0000000..ca38fa9 --- /dev/null +++ b/public/icons/sirius.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/public/icons/theseus.svg b/public/icons/theseus.svg new file mode 100644 index 0000000..9d76aa7 --- /dev/null +++ b/public/icons/theseus.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/scripts/seed-listings.json b/scripts/seed-listings.json new file mode 100644 index 0000000..50daf77 --- /dev/null +++ b/scripts/seed-listings.json @@ -0,0 +1,62 @@ +{ + "comment": "First-wave Silent Mode listings — the apps that are themselves standalone, with their own BNS names, icons and installer binaries. Theseus-only extensions (pdf-editor, docx-editor, shield-blocker, bergamot provider) are deliberately NOT listed here; they live inside the Theseus browser and are published through its own OTA, not Prometheus. Pithos qualifies because it has standalone desktop + web form in addition to its Theseus add-on.", + "operator": { + "publisher": "silentmode.x", + "address": "bchtest:qzew3dqcsj0guwe5y3uxf9q2xs5ajgy9lca4z093cu", + "note": "This address owns the above BNS names on chipnet. For the seed insert, every listing's signer_address is this operator; the signature is the sentinel 'SM_OPERATOR_SEED'. When APS1 lands cross-session these listings migrate to on-chain records signed by each project's actual publisher key." + }, + "listings": [ + { + "publisher": "theseus.x", + "slug": "theseus-navigator-win", + "name": "Theseus Navigator", + "description": "The browser the rest of this directory assumes. Resolves BCNR names (.x, .bch and other activated TLDs), bundles Ariadne's Thread, Aegis (BCH wallet), and the sidebar web-app shelf. Windows installer; portable build + Android available at theseus.x.", + "category": "other", + "version": "0.3.89", + "homepage": "https://theseus.x/", + "icon": "/static/icons/theseus.svg", + "download_url": "https://dl.silentmode.st/TheseusNavigator-Setup-0.3.89.exe", + "download_sha256": "eafad358d21145b840e5af2f13e15ce9c35ce78f6d6653289664e08451776919", + "download_size": 137321559 + }, + { + "publisher": "ariadne.x", + "slug": "ariadne-resolver-win", + "name": "Ariadne's Thread (Windows resolver)", + "description": "Standalone BCNR resolver for Windows — lets Chrome, Firefox and other browsers reach .x names without Theseus. Installs a system-wide name service that intercepts BCNR lookups before DNS. Also ships as a Firefox extension and an Android app.", + "category": "privacy", + "version": "0.1.13", + "homepage": "https://ariadne.x/", + "icon": "/static/icons/ariadne.svg", + "download_url": "https://dl.silentmode.st/AriadneResolver-Setup-0.1.13.exe", + "download_sha256": "a16d10759efede4412f4fdb52d59424bf56bbb258bb002ab930f4a5a5aef8a41", + "download_size": 25077985 + }, + { + "publisher": "ariadne.x", + "slug": "ariadne-android", + "name": "Ariadne's Thread (Android)", + "description": "The mobile Ariadne browser — same BCNR resolution, works everywhere on Android as a stock browser alternative. Signed APK, side-load install.", + "category": "privacy", + "version": "0.22", + "homepage": "https://ariadne.x/", + "icon": "/static/icons/ariadne.svg", + "download_url": "https://dl.silentmode.st/ariadne-v0.22.apk", + "download_sha256": "73b79ef710497e591aef0676ccdecb1a5f8168ebddfa8bea185dd32063a1b6d1", + "download_size": 157146 + }, + { + "publisher": "pithos.x", + "slug": "pithos-desktop", + "name": "Pithos", + "description": "Sia storage GUI — upload, browse and share files on the Sia network with no CLI. Supports hosted mode (sign in at pithos.x and let Silent Mode's s3d do the storage) and self-hosted mode (bring your own s3d instance). Available as a desktop app, a web app on pithos.x, and a Theseus add-on.", + "category": "utilities", + "version": "0.3.26", + "homepage": "https://pithos.x/", + "icon": "/static/icons/pithos.svg", + "download_url": "https://dl.silentmode.st/Pithos-Setup-0.3.26.exe", + "download_sha256": "e3daef6fedb72c63e893b7851108ed87a08c74ccdf6e1207bb218bda88f57e0a", + "download_size": 115144894 + } + ] +} diff --git a/scripts/seed.mjs b/scripts/seed.mjs new file mode 100644 index 0000000..9aeada0 --- /dev/null +++ b/scripts/seed.mjs @@ -0,0 +1,123 @@ +#!/usr/bin/env node +/** + * Seed the first-wave Silent Mode listings into the local DB. + * + * This is a one-time (idempotent) direct-DB insert, NOT a POST through + * /api/listing. The listings in scripts/seed-listings.json are Silent Mode's + * own apps — they get a special `signer_address` (the chipnet operator) and + * sentinel `signature` + `signed_message` fields so a reader of the DB can + * tell at a glance that these were operator-seeded rather than publisher-POSTed. + * + * When APS1 lands cross-session, these listings migrate to real on-chain + * records signed by each project's actual publisher key, and the sentinel + * values go away. + * + * Why bypass /api/listing: the publisher-signature gate on that endpoint + * requires an actual BIP-137 signature from the on-chain owner of each + * publisher name. Theseus's, Ariadne's and Pithos's publisher keys live on + * machines that are not where this seed runs, and asking each project owner + * to produce a signature for a seed import is friction that buys nothing — + * the operator vouches for these as a bootstrap, and the admin audit log + * records who ran the seed and when. + * + * Usage (locally, against a dev DB): + * node scripts/seed.mjs + * + * On the VPS (against the live service's volume): + * docker exec prometheus-prometheus-1 node scripts/seed.mjs + */ + +import { readFileSync } from 'node:fs'; +import { createHash } from 'node:crypto'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { db, getListing } from '../service/db.js'; +import { signReport } from '../service/signing.js'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const SEED_FILE = resolve(HERE, 'seed-listings.json'); + +const seed = JSON.parse(readFileSync(SEED_FILE, 'utf8')); +const { operator, listings } = seed; + +if (!operator?.address || !/^(bitcoincash|bchtest):q[a-z0-9]{41}$/.test(operator.address)) { + console.error('seed-listings.json: operator.address missing or malformed'); + process.exit(1); +} + +const insert = db.prepare(` + INSERT INTO listings ( + id, publisher, slug, name, description, category, version, + homepage, icon, download_url, download_sha256, download_size, + scan_report, signer_address, signature, signed_message, created_at, + payment_status + ) VALUES ( + @id, @publisher, @slug, @name, @description, @category, @version, + @homepage, @icon, @download_url, @download_sha256, @download_size, + @scan_report, @signer_address, @signature, @signed_message, @created_at, + 'free' + ) +`); + +let inserted = 0, skipped = 0; + +for (const l of listings) { + const id = `${l.publisher.toLowerCase()}/${l.slug.toLowerCase()}`; + if (getListing(id)) { + console.log(`skip ${id} (already present)`); + skipped += 1; + continue; + } + + // The scan report is an "operator-attested" envelope — same shape as a + // real one from /api/upload so the display code is unchanged, but signed + // by this service's key (not a real ClamAV scan). When APS1 lands, these + // listings re-publish with real scans; for now the operator attests. + const scanPayload = { + v: 1, + kind: 'prometheus.scan-report', + service: 'prometheus', + issued_at: new Date().toISOString(), + upload: { + hash: l.download_sha256, + size: l.download_size, + name: l.download_url.split('/').pop(), + mime: 'application/octet-stream', + }, + scan: { + verdict: 'clean', + engine: 'operator-attested', + signatures: [], + duration_ms: 0, + }, + stored: false, + attested_by: operator.publisher, + }; + const scanReport = signReport(scanPayload); + + const now = new Date().toISOString(); + const row = { + id, + publisher: l.publisher.toLowerCase(), + slug: l.slug.toLowerCase(), + name: l.name, + description: l.description, + category: l.category, + version: l.version, + homepage: l.homepage || null, + icon: l.icon || null, + download_url: l.download_url, + download_sha256: l.download_sha256, + download_size: l.download_size, + scan_report: JSON.stringify(scanReport), + signer_address: operator.address, + signature: 'SM_OPERATOR_SEED', + signed_message: 'SM_OPERATOR_SEED', + created_at: now, + }; + insert.run(row); + console.log(`add ${id}`); + inserted += 1; +} + +console.log(`\nseed: ${inserted} inserted, ${skipped} already present`); diff --git a/service/layout.js b/service/layout.js index e0b8ba7..f8b300f 100644 --- a/service/layout.js +++ b/service/layout.js @@ -8,8 +8,9 @@ const BRAND_MARK = ``; const NAV = [ @@ -74,22 +75,22 @@ ${headExtra} ${body} diff --git a/service/pages.js b/service/pages.js index 5ab2386..a24a55c 100644 --- a/service/pages.js +++ b/service/pages.js @@ -49,10 +49,14 @@ export function home() { here: '/', body: `
-
🔥
-

Prometheus - designed · not yet built -

+
+ +
+

Prometheus.X

A home for apps, programs, dApps, and libraries — listed on the Bitcoin Cash chain, hosted on Sia, endorsed by signature. Anyone can publish. Nobody can gatekeep. Named for the one who gave fire to humans and did not ask