93 lines
3.6 KiB
Markdown
93 lines
3.6 KiB
Markdown
# Meta Credential Store (operator-only)
|
|
Centralized encrypted store for Muse, Instagram, Facebook account credentials.
|
|
## Location (VM only)
|
|
- `/etc/netvm/meta-credentials/store.age` — age-encrypted JSON (600 root)
|
|
- `/etc/netvm/meta-credentials/.age-key` — age private key (600 root)
|
|
- `/usr/local/bin/meta-creds.sh` — CLI (700 root)
|
|
## Usage
|
|
```bash
|
|
sudo meta-creds.sh list muse # list account IDs (no secrets)
|
|
sudo meta-creds.sh get muse <id> # output JSON (never log this)
|
|
sudo meta-creds.sh add muse <id> # interactive prompts
|
|
```
|
|
## Naming
|
|
|
|
Store ID == `ACCOUNTS.md` `agent` name (e.g. `646`, `pip`, `muse`). The
|
|
secret store and the secret-free registry join on this ID — same account,
|
|
different jobs (secrets vs. state).
|
|
|
|
## Schema
|
|
```json
|
|
{
|
|
"muse": {
|
|
"<id>": {
|
|
"email": "...",
|
|
"phone": "...",
|
|
"via_meta_account": "<facebook|instagram id>",
|
|
"age_verified": "true",
|
|
"instagram_linked": "<handle>",
|
|
"verified_by": "human", "verified_at": "2026-10-03T...",
|
|
"notes": "..."
|
|
}
|
|
},
|
|
"instagram": {
|
|
"<id>": {
|
|
"username": "...", "password": "...",
|
|
"email": "...", "phone": "...",
|
|
"accounts_center": "<alias>",
|
|
"linked_to": ["<other store id>", "..."],
|
|
"login_methods": ["password", "phone_otp"]
|
|
}
|
|
},
|
|
"facebook": {
|
|
"<id>": {
|
|
"email": "...", "password": "...", "phone": "...",
|
|
"accounts_center": "<alias>",
|
|
"linked_to": ["<other store id>", "..."],
|
|
"login_methods": ["password", "phone_otp"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Field notes
|
|
|
|
- `phone`: mobile number for login/2FA. **May be stored here** (encrypted);
|
|
one phone can map to multiple accounts (observed: 646 + piparada share
|
|
a number) — never treat it as a unique key.
|
|
- `via_meta_account` (muse): when muse.ai auth runs through a Meta
|
|
account (phone OTP → Meta account → muse.ai), points at the
|
|
`facebook`/`instagram` entry. This is the 646/pip intersection.
|
|
- `accounts_center`: local alias for the Accounts Center (e.g. `ac-646`).
|
|
Post early-2026 this is the login blast-radius boundary — every account
|
|
in one Center logs into every other by default.
|
|
- `linked_to`: other store IDs in the same Accounts Center. Cached from
|
|
the Meta API's `list-linked`; **the API is ground truth** — when they
|
|
disagree, the API wins and the store gets updated.
|
|
- `login_methods`: how the account can be authenticated. Drives which
|
|
flow the automation attempts.
|
|
|
|
## Intersections
|
|
|
|
- **Phone ↔ accounts (1:many):** the store holds the number (encrypted);
|
|
the human is no longer the sole holder, but the number still never
|
|
appears in logs, chat, memory, or the secret-free registry.
|
|
- **Meta credential → muse.ai session:** a `facebook`/`instagram` entry
|
|
can be the auth path for a `muse` login. Follow `via_meta_account`.
|
|
- **Store ↔ ACCOUNTS.md:** joined on ID. Store = secrets, registry = state.
|
|
- **Store ↔ Meta Accounts Center API** (`docs/META-ACCOUNTS-API.md`):
|
|
the API reads linkage ground truth; the store caches it in `linked_to` /
|
|
`accounts_center`.
|
|
|
|
## Rules
|
|
|
|
- Operators only. Developers never get access (prevents board leaks).
|
|
- Decrypt transiently, never log values, never put in chat/memory.
|
|
- Phone numbers and PII **may** live in `store.age` (age-encrypted, 600
|
|
root, VM only). They must never appear in plaintext anywhere else:
|
|
no logs, no chat, no memory, no registry, no board.
|
|
- Human validates Instagram linking and Meta account ownership;
|
|
operators automate after.
|
|
- When adding an account, fill `accounts_center` / `linked_to` from the
|
|
Meta API (`list-linked`), not from memory.
|