# Script to generate API keys for existing partners # Run with: mix run priv/scripts/generate_api_keys.exs alias DaProductApp.{Repo, Partners} alias DaProductApp.Partners.Partner import Ecto.Query defmodule ApiKeyGenerator do @moduledoc """ Generates secure API keys for existing partners who don't have them. """ # Generate a secure API key (32 bytes = 256 bits) def generate_api_key do :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false) |> String.replace("+", "_") |> String.replace("/", "-") end # Generate a secure API secret (64 bytes = 512 bits) def generate_api_secret do :crypto.strong_rand_bytes(64) |> Base.url_encode64(padding: false) |> String.replace("+", "_") |> String.replace("/", "-") end def update_partner_with_keys do # Find all partners without API keys partners_without_keys = Repo.all( from p in Partner, where: is_nil(p.api_key) or is_nil(p.api_secret) ) if Enum.empty?(partners_without_keys) do IO.puts("✅ All partners already have API keys") else IO.puts("🔑 Generating API keys for #{length(partners_without_keys)} partners...") Enum.each(partners_without_keys, fn partner -> api_key = generate_api_key() api_secret = generate_api_secret() # Set default rate limit if not set rate_limit = partner.rate_limit_per_minute || 100 # Set API key expiration to 1 year from now expires_at = DateTime.utc_now() |> DateTime.add(365, :day) changeset = partner |> Partner.changeset(%{ api_key: api_key, api_secret: api_secret, rate_limit_per_minute: rate_limit, api_key_expires_at: expires_at }) case Repo.update(changeset) do {:ok, updated_partner} -> IO.puts("✅ Generated API keys for partner: #{updated_partner.partner_name}") IO.puts(" API Key: #{api_key}") IO.puts(" API Secret: #{String.slice(api_secret, 0, 10)}...") IO.puts(" Rate Limit: #{rate_limit} requests/minute") IO.puts(" Expires: #{expires_at}") IO.puts("") {:error, changeset} -> IO.puts("❌ Failed to update partner #{partner.name}") IO.inspect(changeset.errors) end end) end end def show_existing_keys do partners_with_keys = Repo.all( from p in Partner, where: not is_nil(p.api_key), select: [:id, :partner_name, :api_key, :rate_limit_per_minute, :api_key_expires_at] ) if Enum.empty?(partners_with_keys) do IO.puts("â„šī¸ No partners have API keys yet") else IO.puts("📋 Current API Keys:") IO.puts("=" <> String.duplicate("=", 80)) Enum.each(partners_with_keys, fn partner -> expires_info = case partner.api_key_expires_at do nil -> "Never" date -> Calendar.strftime(date, "%Y-%m-%d %H:%M UTC") end IO.puts("Partner: #{partner.partner_name}") IO.puts("API Key: #{partner.api_key}") IO.puts("Rate Limit: #{partner.rate_limit_per_minute || 100} req/min") IO.puts("Expires: #{expires_info}") IO.puts("-" <> String.duplicate("-", 40)) end) end end end # Main execution IO.puts("🚀 API Key Management Script") IO.puts("=" <> String.duplicate("=", 50)) # Show current state ApiKeyGenerator.show_existing_keys() # Generate keys for partners that need them ApiKeyGenerator.update_partner_with_keys() IO.puts("✅ API Key generation complete!") IO.puts("💡 Remember to securely share these keys with your partners") IO.puts("💡 You can re-run this script safely - it won't regenerate existing keys")