186 lines
7.1 KiB
Markdown
186 lines
7.1 KiB
Markdown
|
|
# Publishing to your name
|
||
|
|
|
||
|
|
Every page Sirius Press serves can also exist as a static file in your name's
|
||
|
|
storage, signed by the key that owns the name. This is what makes the site
|
||
|
|
outlive its server.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What gets published, and when
|
||
|
|
|
||
|
|
Publishing or editing a post queues the pages it affects:
|
||
|
|
|
||
|
|
- the post itself
|
||
|
|
- the home page
|
||
|
|
- the blog page, if you have one
|
||
|
|
- every category, tag or other public archive it belongs to
|
||
|
|
- any asset those pages reference — stylesheets, scripts, images — the first
|
||
|
|
time it is seen
|
||
|
|
|
||
|
|
Unpublishing or deleting a post removes its file and re-queues the pages that
|
||
|
|
linked to it. A static mirror that keeps serving a post the author deleted is
|
||
|
|
worse than no mirror at all, because the author believes it is gone.
|
||
|
|
|
||
|
|
**Export everything** on the Publishing screen queues the whole site: every
|
||
|
|
published post and page, every public archive, the home page.
|
||
|
|
|
||
|
|
Password-protected posts are never exported. To the exporter they render as a
|
||
|
|
password form, and publishing that form to permanent public storage would be a
|
||
|
|
strange thing to do on purpose.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Who signs, and where the key lives
|
||
|
|
|
||
|
|
The BNS gateway only accepts a write signed by the name's **current on-chain
|
||
|
|
owner**. That is the whole security model, and it has a consequence there is no
|
||
|
|
way around: whatever signs your uploads holds the key that owns your name and
|
||
|
|
whatever funds sit with it. There is no weaker credential to give a server.
|
||
|
|
|
||
|
|
So the question is not *how much* of your key the server gets. It is whether it
|
||
|
|
gets it at all.
|
||
|
|
|
||
|
|
### Manual — the default
|
||
|
|
|
||
|
|
Nothing is stored. Exports queue up; when you open **Sirius Press → Publishing**
|
||
|
|
you type your recovery phrase, and the page signs each file and uploads it
|
||
|
|
straight from your browser to the gateway. The phrase is cleared from the form
|
||
|
|
as soon as it has been used and the derived key is wiped when the run ends.
|
||
|
|
|
||
|
|
- Nothing sensitive on the server. A compromised host leaks your posts, which
|
||
|
|
were public anyway.
|
||
|
|
- A post published on a schedule sits in the queue until somebody signs in.
|
||
|
|
|
||
|
|
### Automatic
|
||
|
|
|
||
|
|
Your recovery phrase is encrypted with AES-256-GCM under a key derived from
|
||
|
|
`SIRIUS_PRESS_KEY` in `wp-config.php`, and stored in the database. Cron drains
|
||
|
|
the queue by itself.
|
||
|
|
|
||
|
|
- Scheduled posts publish while you sleep.
|
||
|
|
- Anyone who can read **both** your database and `wp-config.php` has your name
|
||
|
|
and your coins. That is most people who get a shell on the box.
|
||
|
|
|
||
|
|
The encryption protects one specific thing — a stolen database dump, a leaked
|
||
|
|
backup — and the settings screen says exactly that rather than implying more.
|
||
|
|
|
||
|
|
**A reasonable middle path:** run automatic mode with a wallet that holds the
|
||
|
|
name and nothing else. Keep your coins somewhere that has never been typed into
|
||
|
|
a web server. This does not protect the name, but it bounds what a compromise
|
||
|
|
costs to "the attacker can publish to my name until I move it", which is
|
||
|
|
recoverable.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Derivation paths
|
||
|
|
|
||
|
|
Sirius Press derives its publishing key at `m/44'/145'/0'/0/0` — BCH coin type,
|
||
|
|
first account, first address. Same as the Sirius portal wallet, same as most
|
||
|
|
BCH wallets.
|
||
|
|
|
||
|
|
If your name was bought with a wallet minted somewhere else, the path may
|
||
|
|
differ. The symptom is unmistakable once you know it: every upload returns 403,
|
||
|
|
and **Sirius Press → Settings** shows two different addresses side by side —
|
||
|
|
the one your phrase derives, and the one the chain says owns the name.
|
||
|
|
|
||
|
|
Change the path in Settings. Operator wallets created from the Silent Mode CLI
|
||
|
|
were derived on the BTC coin type, `m/44'/0'/0'/0/0`.
|
||
|
|
|
||
|
|
The settings screen checks this for you as soon as you save a phrase: it
|
||
|
|
derives the address, asks the gateway who owns the name, and tells you whether
|
||
|
|
they match. A mismatch caught there is a sentence of explanation. The same
|
||
|
|
mismatch caught later is a 403 in a cron log nobody reads.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## The queue
|
||
|
|
|
||
|
|
Rows are keyed by path, not by post — several posts changing in a minute should
|
||
|
|
not queue the home page five times.
|
||
|
|
|
||
|
|
Each attempt renders the page, hashes the result, and compares it to what was
|
||
|
|
last published at that path. Identical bytes are marked done without an upload,
|
||
|
|
which is the common case: a WordPress page re-renders byte-for-byte far more
|
||
|
|
often than it changes.
|
||
|
|
|
||
|
|
Failures retry up to five times and then stop, and the first exhausted retry
|
||
|
|
puts a message in your inbox — once an hour at most, because a misconfigured
|
||
|
|
key fails on every row and four hundred identical messages are the same as
|
||
|
|
none.
|
||
|
|
|
||
|
|
### From the command line
|
||
|
|
|
||
|
|
```bash
|
||
|
|
wp sirius status # name, key, owner, queue depth
|
||
|
|
wp sirius export --all # queue everything, then push it
|
||
|
|
wp sirius export --limit=50 # work through part of the queue
|
||
|
|
wp sirius export --all --dry-run # build every page, upload nothing
|
||
|
|
```
|
||
|
|
|
||
|
|
`--dry-run` is the fastest way to find a page that renders badly for the
|
||
|
|
exporter without publishing anything.
|
||
|
|
|
||
|
|
The first full export of an existing site is the one job genuinely better in a
|
||
|
|
terminal: thousands of pages, a long run, and no browser tab that must stay
|
||
|
|
open. Note that CLI publishing needs automatic mode, since there is no browser
|
||
|
|
to sign in manual mode.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What the exported pages look like
|
||
|
|
|
||
|
|
Pages are fetched over a loopback HTTP request, not rendered in-process. That
|
||
|
|
costs a round trip and is worth it: a theme's output depends on the whole
|
||
|
|
request lifecycle, and reconstructing it by calling `get_the_content()` gives
|
||
|
|
you something that resembles the page rather than the page.
|
||
|
|
|
||
|
|
Links are rewritten to be **document-relative** — `../../about/index.html`
|
||
|
|
rather than `/about/index.html` or an absolute URL. Absolute links would drag
|
||
|
|
readers back to the origin server the export exists to make optional.
|
||
|
|
Root-relative ones break when the same bucket is browsed under
|
||
|
|
`/bns/<name>/` on the public gateway. Document-relative works in both places.
|
||
|
|
|
||
|
|
Asset URLs lose their `?ver=` query, because the bucket stores one copy of each
|
||
|
|
file and the query would only ever produce a 404.
|
||
|
|
|
||
|
|
### Things that cannot work in a static copy
|
||
|
|
|
||
|
|
Anything needing PHP at read time: the search form, the comment form, a cart, a
|
||
|
|
"related posts" widget that queries at render. They will appear and do nothing.
|
||
|
|
|
||
|
|
If your theme has such a thing, hide it during export:
|
||
|
|
|
||
|
|
```php
|
||
|
|
add_action( 'sirius_press_rendering_export', function () {
|
||
|
|
add_filter( 'get_search_form', '__return_empty_string' );
|
||
|
|
remove_action( 'wp_footer', 'my_theme_live_widget' );
|
||
|
|
} );
|
||
|
|
```
|
||
|
|
|
||
|
|
That action fires on the live request, while the exporter is fetching — which
|
||
|
|
is the right moment, because removing something afterwards means also unpicking
|
||
|
|
the styles and spacing it left behind.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Hooks
|
||
|
|
|
||
|
|
```php
|
||
|
|
// Skip a post entirely.
|
||
|
|
add_filter( 'sirius_press_should_export_post', function ( $export, $post ) {
|
||
|
|
return 'private-type' === $post->post_type ? false : $export;
|
||
|
|
}, 10, 2 );
|
||
|
|
|
||
|
|
// Add to, or trim, what a full export covers.
|
||
|
|
add_filter( 'sirius_press_export_targets', function ( $targets ) {
|
||
|
|
$targets['feed/index.xml'] = array( 'url' => home_url( '/feed/' ), 'kind' => 'feed' );
|
||
|
|
return $targets;
|
||
|
|
} );
|
||
|
|
|
||
|
|
// Change which paths a post edit invalidates.
|
||
|
|
add_filter( 'sirius_press_affected_paths', function ( $paths, $post ) { … }, 10, 2 );
|
||
|
|
|
||
|
|
// React to a successful upload.
|
||
|
|
add_action( 'sirius_press_exported', function ( $path, $bytes ) { … }, 10, 2 );
|
||
|
|
```
|