#!/usr/bin/env bash # bitwarden skill — helper REST autenticado. # # Uso: # query.sh /status # GET # query.sh /list/object/items # GET # query.sh "/object/item/" # GET # query.sh /generate?length=20&special=true # GET # query.sh -X POST -H 'Content-Type: application/json' \ # -d '{"name":"foo"}' /object/folder # POST (create) # # Garantiza que `bw serve` esté arriba antes de llamar. # # READ + CREATE ONLY: # - GET siempre permitido # - POST permitido sólo en /object/item, /object/folder, /object/send, # /sync, /unlock, /lock, /generate (sí, hay POST /generate también), # y endpoints de auth # - PUT/DELETE/PATCH bloqueados # - POST a endpoints de mutación (move/restore/confirm/attachment/share) # bloqueados # # El guard NO es la única defensa: el server de Vaultwarden también rechaza # escritura en collections del org NucleOS porque claudecode0 está como # "Can view". Para el vault personal de claudecode0, este guard ES la única # defensa contra modify/delete. set -euo pipefail SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ENV_FILE="$SKILL_DIR/.env" if [[ ! -f "$ENV_FILE" ]]; then echo "ERROR: $ENV_FILE no existe. cp $SKILL_DIR/.env.example $ENV_FILE" >&2 exit 1 fi set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a PORT="${BW_PORT:-8087}" BASE="http://127.0.0.1:${PORT}" # ─── Parsear args: separar flags de curl del path ─────────────────────── args=() path="" method="GET" while [[ $# -gt 0 ]]; do case "$1" in -X|--request) method="$(echo "${2:-GET}" | tr '[:lower:]' '[:upper:]')" args+=("$1" "$2"); shift 2 ;; -X*) method="$(echo "${1#-X}" | tr '[:lower:]' '[:upper:]')" args+=("$1"); shift ;; --request=*) method="$(echo "${1#--request=}" | tr '[:lower:]' '[:upper:]')" args+=("$1"); shift ;; -d|--data|--data-raw|--data-binary|--data-urlencode|-H|--header|-o|--output|-T|--upload-file) args+=("$1" "$2"); shift 2 ;; --) shift; break ;; -*) args+=("$1"); shift ;; *) path="$1"; shift ;; esac done # Cualquier residual posicional [[ $# -gt 0 && -z "$path" ]] && path="$1" if [[ -z "$path" ]]; then cat >&2 < Read examples: query.sh /status query.sh /list/object/items query.sh /list/object/folders query.sh "/object/item/" query.sh "/object/password/" query.sh "/generate?length=20&special=true" Create examples (POST): query.sh -X POST -H 'Content-Type: application/json' \\ -d '{"name":"new folder"}' /object/folder Ver endpoints.md para la cheat sheet completa. EOF exit 2 fi # Asegurar leading / case "$path" in /*) ;; http*) echo "ERROR: pasá solo el path, no URL completa." >&2; exit 1 ;; *) path="/$path" ;; esac # ─── READ + CREATE GUARD ──────────────────────────────────────────────── case "$method" in PUT|DELETE|PATCH) echo "ERROR: la skill 'bitwarden' bloquea $method (read+create only)." >&2 echo " Si REALMENTE necesitás modificar/eliminar, usá bw CLI directo:" >&2 echo " BITWARDENCLI_APPDATA_DIR=$SKILL_DIR/.cache/bw \\" >&2 echo " BW_SESSION=\$(cat $SKILL_DIR/.cache/session) bw " >&2 exit 3 ;; POST) # Path base sin querystring base_path="${path%%\?*}" case "$base_path" in /object/item|/object/folder|/object/send|/object/org-collection) ;; # create permitido /sync|/unlock|/lock|/generate) ;; # auth/utility permitidos *) echo "ERROR: POST $base_path bloqueado por la skill." >&2 echo " POST permitido sólo en: /object/item, /object/folder, /object/send," >&2 echo " /object/org-collection, /sync, /unlock, /lock, /generate." >&2 echo " Endpoints como /move, /restore, /confirm, /object/attachment" >&2 echo " están bloqueados (modifican estado existente)." >&2 exit 3 ;; esac ;; esac # ─── Asegurar bw serve arriba ─────────────────────────────────────────── "$SKILL_DIR/scripts/serve-up.sh" >/dev/null # ─── Llamar ───────────────────────────────────────────────────────────── exec curl -sS \ -H "Accept: application/json" \ "${args[@]}" \ "${BASE}${path}"