From 1a0662d7520ada730ca9e709c6d35882ce84add8 Mon Sep 17 00:00:00 2001 From: operator Date: Sat, 3 Oct 2026 14:48:24 +0000 Subject: [PATCH] meta-creds.sh: operator CLI for Meta credential store --- CREDSTORE.md | 32 ++++++++++++++++++++++++++++++++ bin/meta-creds.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 CREDSTORE.md create mode 100755 bin/meta-creds.sh diff --git a/CREDSTORE.md b/CREDSTORE.md new file mode 100644 index 0000000..8e74868 --- /dev/null +++ b/CREDSTORE.md @@ -0,0 +1,32 @@ +# 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 # output JSON (never log this) +sudo meta-creds.sh add muse # interactive prompts +``` +## Schema +```json +{ + "muse": { + "": { + "email": "...", "phone": "...", + "age_verified": "true", + "instagram_linked": "", + "verified_by": "human", "verified_at": "2026-10-03T...", + "notes": "..." + } + }, + "instagram": {"": {"username": "...", "password": "...", "email": "..."}}, + "facebook": {"": {"email": "...", "password": "..."}} +} +``` +## Rules +- Operators only. Developers never get access (prevents board leaks). +- Decrypt transiently, never log values, never put in chat/memory. +- Human validates Instagram linking; operators automate after. diff --git a/bin/meta-creds.sh b/bin/meta-creds.sh new file mode 100755 index 0000000..08a4470 --- /dev/null +++ b/bin/meta-creds.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Meta credential store CLI (operator-only) +# Usage: +# meta-creds.sh add # interactive add (prompts for fields) +# meta-creds.sh get # output JSON to stdout (never log) +# meta-creds.sh list # list IDs (no secrets) +# Types: muse, instagram, facebook +STORE_DIR="/etc/netvm/meta-credentials" +STORE="$STORE_DIR/store.age" +KEY="$STORE_DIR/.age-key" +if [ ! -f "$STORE" ] || [ ! -f "$KEY" ]; then + echo "error: store not initialized" >&2; exit 1 +fi +decrypt() { sudo age -d -i "$KEY" "$STORE" 2>/dev/null; } +encrypt() { + PUBKEY=$(sudo grep "public key" "$KEY" | awk '{print $4}') + sudo age -r "$PUBKEY" -o "$STORE.tmp" 2>/dev/null && sudo mv "$STORE.tmp" "$STORE" && sudo chmod 600 "$STORE" +} +case "$1" in + list) + decrypt | jq -r ".$2 | keys[]" 2>/dev/null || echo "(empty)" + ;; + get) + decrypt | jq ".$2[\"$3\"]" 2>/dev/null + ;; + add) + TYPE="$2"; ID="$3" + echo "Adding $TYPE/$ID (fields as JSON, empty to skip):" + TMP=$(mktemp) + decrypt > "$TMP" 2>/dev/null + # Build entry via prompts + ENTRY=$(jq -n '{}') + for field in email phone username password notes age_verified instagram_linked verified_by; do + read -p "$field: " val + if [ -n "$val" ]; then + ENTRY=$(echo "$ENTRY" | jq --arg v "$val" ".$field=\$v") + fi + done + ENTRY=$(echo "$ENTRY" | jq ".verified_at=\"$(date -u +%FT%TZ)\"") + jq --arg t "$TYPE" --arg id "$ID" --argjson e "$ENTRY" '.[$t][$id]=$e' "$TMP" | encrypt + rm -f "$TMP" + echo "added $TYPE/$ID" + ;; + *) + echo "usage: meta-creds.sh {list|get|add} [id]" + ;; +esac