tags are how the marketplace is browsed rather than scrolled: a list of them on the left, the plugins that carry one on the right. a closed vocabulary (PLUGIN_TAGS in the platform) because free text becomes homelab, home-lab, Home Lab and selfhosted inside a month, and a filter list of synonyms is worse than no filter at all. declared here rather than curated in the catalogue, so a plugin can say what it is and nobody edits a table when one ships. the marketplace caches it on sync, exactly as it already does for label and summary.
58 lines
2.6 KiB
TypeScript
58 lines
2.6 KiB
TypeScript
import type { PluginManifest } from '@@/plugins/manifest';
|
|
|
|
/**
|
|
* Wallet — a self-custodial bitcoin wallet, with the keys on the server rather than on a device.
|
|
*
|
|
* ── Read `docs/wallet-key-custody.md` before changing anything here ──
|
|
*
|
|
* The seed is sealed under a key derived from the OWNER OF THAT WALLET's passphrase by scrypt
|
|
* (N=2¹⁷), then encrypted again at rest. The server cannot open it without the passphrase, which it
|
|
* never stores. That is not incidental — it is what makes the next paragraph safe.
|
|
*
|
|
* ── This permission is GRANTABLE, and that is deliberate ──
|
|
*
|
|
* It was `kind: 'admin'` — owner only — until this extraction, which was single-user thinking. Every
|
|
* wallet query is scoped by `user_id`, and the id comes from `X-Officer-User`, injected by the platform
|
|
* from the authenticated session. A caller cannot name someone else's.
|
|
*
|
|
* So granting this to a role gives that person THEIR OWN wallet. It does not give them yours, and it
|
|
* does not give you theirs: not through the API, and not with root either, because their seed is sealed
|
|
* under a passphrase you do not have.
|
|
*
|
|
* ── The gap that is real, and deferred on purpose ──
|
|
*
|
|
* Watch-only data — xpubs, and the balances, addresses and history derived from them — is stored in the
|
|
* CLEAR, so a locked wallet still shows a balance without anyone typing a passphrase. That ergonomics
|
|
* choice is why the wallet spends its life locked. The cost: anyone with the Postgres database or a
|
|
* backup of it can read any user's balances and history. They can never move a coin.
|
|
*
|
|
* Encrypting it per-user is a future option, and it costs balance-while-locked. Recorded here rather
|
|
* than discovered later.
|
|
*
|
|
* ── No `osDependencies` ──
|
|
*
|
|
* Everything is JS. Chain data comes from Esplora or NBXplorer over `fetch`.
|
|
*/
|
|
export const manifest: PluginManifest = {
|
|
publisher: 'officerdev',
|
|
version: '1.0.0',
|
|
platform: '>=1.0.0',
|
|
|
|
label: 'Bitcoin Wallet',
|
|
summary: 'A self-custodial bitcoin wallet — keys sealed on the server, never on a device',
|
|
/** self-custody is the point, and keys are the risk. */
|
|
tags: ['Personal', 'Security'],
|
|
icon: 'Bitcoin',
|
|
color: '#f7931a',
|
|
|
|
permissions: [
|
|
{
|
|
key: 'bitcoin-wallet',
|
|
label: 'Bitcoin Wallet',
|
|
// Written to be read in the grants list, where it sits beside Photos and Music and must not look
|
|
// like them. Granting gives that account its own wallet; it never exposes anyone else's.
|
|
description: "Bitcoin wallet — each account gets its own, sealed under that account's own passphrase",
|
|
},
|
|
],
|
|
};
|