From d6d19eaf0c30ed2dc6322c5589d294522d7b1735 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 10 May 2026 12:18:43 +0200 Subject: [PATCH] feat: add API key management script Interactive menu to add/update/clear API keys: - Translation: OpenAI, DeepL, OpenRouter - Payment: Stripe (secret, webhook, price IDs) - Admin password change with bcrypt - Switch translation provider - Status overview with masked keys Co-Authored-By: Claude Opus 4.7 --- scripts/manage-keys.sh | 231 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 scripts/manage-keys.sh diff --git a/scripts/manage-keys.sh b/scripts/manage-keys.sh new file mode 100644 index 0000000..08844c5 --- /dev/null +++ b/scripts/manage-keys.sh @@ -0,0 +1,231 @@ +#!/bin/bash +# ============================================ +# Wordly.art - Gestion des cles API +# ============================================ +# Ajouter, modifier ou supprimer des cles API +# Usage: bash scripts/manage-keys.sh +# ============================================ + +ENV_FILE=".env" + +# Couleurs +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +if [ ! -f "$ENV_FILE" ]; then + echo -e "${RED}Fichier .env non trouve. Lance d'abord: bash scripts/setup-env.sh${NC}" + exit 1 +fi + +# Fonction pour lire une valeur dans .env +get_env() { + grep "^${1}=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2- || echo "" +} + +# Fonction pour ecrire une valeur dans .env +set_env() { + local key="$1" + local value="$2" + if grep -q "^${key}=" "$ENV_FILE"; then + sed -i "s|^${key}=.*|${key}=${value}|" "$ENV_FILE" + else + echo "${key}=${value}" >> "$ENV_FILE" + fi +} + +# Fonction pour effacer une valeur dans .env +clear_env() { + local key="$1" + sed -i "s|^${key}=.*|${key}=|" "$ENV_FILE" +} + +# Fonction pour afficher le statut d'une cle +show_key_status() { + local name="$1" + local key="$2" + local value=$(get_env "$key") + if [ -n "$value" ] && [ "$value" != "" ]; then + local masked="${value:0:8}...${value: -4}" + echo -e " ${GREEN}OK${NC} ${name}: ${masked}" + else + echo -e " ${RED}--${NC} ${name}: ${YELLOW}non configure${NC}" + fi +} + +# Fonction pour demander une cle +ask_key() { + local name="$1" + local key="$2" + local current=$(get_env "$key") + + echo "" + if [ -n "$current" ]; then + local masked="${current:0:8}...${current: -4}" + echo -e " Actuel: ${masked}" + fi + echo -ne " ${YELLOW}Nouvelle cle (Enter pour garder, 'x' pour effacer):${NC} " + stty -echo 2>/dev/null || true + read -r value + stty echo 2>/dev/null || true + echo "" + + if [ "$value" = "x" ]; then + clear_env "$key" + echo -e " ${RED}Cle supprimee${NC}" + elif [ -n "$value" ]; then + set_env "$key" "$value" + echo -e " ${GREEN}Cle mise a jour${NC}" + else + echo -e " ${CYAN}Inchange${NC}" + fi +} + +# =========================================== +# Menu principal +# =========================================== +while true; do + echo "" + echo -e "${CYAN}${BOLD}=========================================${NC}" + echo -e "${CYAN}${BOLD} Wordly.art - Gestion des cles API${NC}" + echo -e "${CYAN}${BOLD}=========================================${NC}" + echo "" + echo -e "${BOLD}Statut actuel :${NC}" + echo "" + + # Traduction + echo -e " ${BOLD}Traduction :${NC}" + show_key_status "OpenAI" "OPENAI_API_KEY" + show_key_status "DeepL" "DEEPL_API_KEY" + show_key_status "OpenRouter" "OPENROUTER_API_KEY" + show_key_status "Google" "GOOGLE_API_KEY" + echo "" + + # Paiement + echo -e " ${BOLD}Paiement :${NC}" + show_key_status "Stripe Secret" "STRIPE_SECRET_KEY" + show_key_status "Stripe Webhook" "STRIPE_WEBHOOK_SECRET" + show_key_status "Stripe Price Starter" "STRIPE_STARTER_PRICE_ID" + show_key_status "Stripe Price Pro" "STRIPE_PRO_PRICE_ID" + show_key_status "Stripe Price Business" "STRIPE_BUSINESS_PRICE_ID" + echo "" + + # Menu + echo -e "${BOLD}Actions :${NC}" + echo " 1) Configurer OpenAI" + echo " 2) Configurer DeepL" + echo " 3) Configurer OpenRouter" + echo " 4) Configurer Stripe (toutes les cles)" + echo " 5) Changer le mot de passe admin" + echo " 6) Changer le service de traduction" + echo " 7) Tout afficher (attention: secrets visibles)" + echo " 0) Quitter" + echo "" + echo -ne "${YELLOW}Choix:${NC} " + read -r choice + + case "$choice" in + 1) + echo -e "\n${BOLD}--- OpenAI ---${NC}" + echo " Ou: https://platform.openai.com/api-keys" + ask_key "OpenAI" "OPENAI_API_KEY" + ;; + 2) + echo -e "\n${BOLD}--- DeepL ---${NC}" + echo " Ou: https://www.deepl.com/pro-api (gratuit 500k caracteres/mois)" + ask_key "DeepL" "DEEPL_API_KEY" + ;; + 3) + echo -e "\n${BOLD}--- OpenRouter ---${NC}" + echo " Ou: https://openrouter.ai/keys" + ask_key "OpenRouter" "OPENROUTER_API_KEY" + ;; + 4) + echo -e "\n${BOLD}--- Stripe ---${NC}" + echo " Ou: https://dashboard.stripe.com/apikeys" + echo " Webhooks: https://dashboard.stripe.com/webhooks" + echo " Prices: https://dashboard.stripe.com/products" + ask_key "Stripe Secret Key" "STRIPE_SECRET_KEY" + ask_key "Stripe Webhook Secret" "STRIPE_WEBHOOK_SECRET" + ask_key "Price ID Starter" "STRIPE_STARTER_PRICE_ID" + ask_key "Price ID Pro" "STRIPE_PRO_PRICE_ID" + ask_key "Price ID Business" "STRIPE_BUSINESS_PRICE_ID" + echo "" + echo -e "${GREEN}Cles Stripe configurees.${NC}" + echo -e "${YELLOW}Pense a redemarrer: docker compose restart backend${NC}" + ;; + 5) + echo -e "\n${BOLD}--- Changer le mot de passe admin ---${NC}" + echo -ne " Nouveau mot de passe: " + stty -echo 2>/dev/null || true + read -r new_pass + stty echo 2>/dev/null || true + echo "" + echo -ne " Confirmer: " + stty -echo 2>/dev/null || true + read -r new_pass2 + stty echo 2>/dev/null || true + echo "" + + if [ "$new_pass" != "$new_pass2" ]; then + echo -e " ${RED}Les mots de passe ne correspondent pas${NC}" + elif [ -z "$new_pass" ]; then + echo -e " ${RED}Mot de passe vide${NC}" + else + echo -e " ${CYAN}Generation du hash...${NC}" + NEW_HASH=$(docker run --rm python:3.12-slim bash -c \ + "pip install 'passlib[bcrypt]' bcrypt > /dev/null 2>&1 && \ + python3 -c \"from passlib.context import CryptContext; \ + print(CryptContext(schemes=['bcrypt']).hash('${new_pass}'))\"" 2>/dev/null) + if [ -n "$NEW_HASH" ]; then + set_env "ADMIN_PASSWORD_HASH" "$NEW_HASH" + echo -e " ${GREEN}Mot de passe mis a jour${NC}" + echo -e " ${YELLOW}Redemarre le backend: docker compose restart backend${NC}" + else + echo -e " ${RED}Erreur lors de la generation du hash${NC}" + fi + fi + ;; + 6) + echo -e "\n${BOLD}--- Service de traduction ---${NC}" + echo " Actuel: $(get_env TRANSLATION_SERVICE)" + echo " 1) ollama (local, gratuit)" + echo " 2) deepl (haute qualite)" + echo " 3) openai (GPT)" + echo " 4) openrouter (multi-modeles)" + echo "" + echo -ne " Choix: " + read -r svc + case "$svc" in + 1) set_env "TRANSLATION_SERVICE" "ollama" ;; + 2) set_env "TRANSLATION_SERVICE" "deepl" ;; + 3) set_env "TRANSLATION_SERVICE" "openai" ;; + 4) set_env "TRANSLATION_SERVICE" "openrouter" ;; + *) echo -e " ${RED}Choix invalide${NC}" ;; + esac + echo -e " ${GREEN}Service mis a jour${NC}" + echo -e " ${YELLOW}Redemarre: docker compose restart backend${NC}" + ;; + 7) + echo "" + echo -e "${RED}${BOLD}ATTENTION: Secrets visibles!${NC}" + echo -ne "${YELLOW}Taper 'oui' pour continuer:${NC} " + read -r confirm + if [ "$confirm" = "oui" ]; then + echo "" + cat "$ENV_FILE" | grep -v "^#" | grep -v "^$" + fi + ;; + 0) + echo "" + echo -e "${GREEN}Au revoir!${NC}" + exit 0 + ;; + *) + echo -e "${RED}Choix invalide${NC}" + ;; + esac +done