diff --git a/README.md b/README.md index 7430be2..b330578 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,11 @@ For merchants, the Trusted Agent Protocol describes a standardized set of mechan This repository contains a complete sample implementation demonstrating the Trusted Agent Protocol across multiple components: -### 🚀 **Running the Sample** +If you prefer an automated setup flow on macOS, run `quick_setup.sh` from the repository root. It sets up the environment, generates keys, configures each service, and starts the sample applications. + +Note: It requires you to have uv installed on your computer. + +### **Running the Sample** 1. **Install Dependencies** (from root directory): ```bash @@ -78,7 +82,7 @@ This repository contains a complete sample implementation demonstrating the Trus - Configure merchant URL: http://localhost:3001 - Generate signatures and interact with the sample merchant -### 📚 **Component Documentation** +### **Component Documentation** Each component has detailed setup instructions: @@ -88,7 +92,7 @@ Each component has detailed setup instructions: - **[CDN Proxy](./cdn-proxy/README.md)** - Node.js proxy implementing RFC 9421 signature verification - **[Agent Registry](./agent-registry/README.md)** - Public key registry service for agent verification -### 🏗️ **Architecture Overview** +### **Architecture Overview** The sample demonstrates a complete TAP ecosystem: 1. **TAP Agent** generates RFC 9421 compliant signatures diff --git a/cdn-proxy/README.md b/cdn-proxy/README.md index f24c4b7..f6dde00 100644 --- a/cdn-proxy/README.md +++ b/cdn-proxy/README.md @@ -20,12 +20,12 @@ DEBUG=true ## Features -- 🔐 **RFC 9421 Signature Verification**: Validates HTTP Message Signatures -- 🎭 **Multi-Algorithm Support**: Ed25519 and RSA-PSS-SHA256 algorithms -- 🌐 **Request Proxying**: Routes verified requests to merchant backend -- 🔑 **Dynamic Key Retrieval**: Fetches public keys from Agent Registry -- 📊 **Request Logging**: Detailed logging for debugging -- 🛡️ **Security Demo**: Shows secure error handling patterns +- **RFC 9421 Signature Verification**: Validates HTTP Message Signatures +- **Multi-Algorithm Support**: Ed25519 and RSA-PSS-SHA256 algorithms +- **Request Proxying**: Routes verified requests to merchant backend +- **Dynamic Key Retrieval**: Fetches public keys from Agent Registry +- **Request Logging**: Detailed logging for debugging +- **Security Demo**: Shows secure error handling patterns ## Quick Start diff --git a/cdn-proxy/server.js b/cdn-proxy/server.js index 703d9ce..ffb76ee 100644 --- a/cdn-proxy/server.js +++ b/cdn-proxy/server.js @@ -146,7 +146,7 @@ app.use((req, res, next) => { */ // Agent Registry API base URL -const AGENT_REGISTRY_URL = 'http://localhost:9002'; +const AGENT_REGISTRY_URL = 'http://localhost:8001'; // Cache for fetched keys to avoid repeated API calls const keyCache = new Map(); diff --git a/merchant-backend/create_sample_data.py b/merchant-backend/create_sample_data.py index a0bc20b..cb7b393 100644 --- a/merchant-backend/create_sample_data.py +++ b/merchant-backend/create_sample_data.py @@ -6,6 +6,10 @@ # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from dotenv import load_dotenv + +load_dotenv() + from app.database.database import SessionLocal, create_tables from app.models.models import Product diff --git a/merchant-frontend/.env b/merchant-frontend/.env index e34ef44..2c2a534 100644 --- a/merchant-frontend/.env +++ b/merchant-frontend/.env @@ -1,15 +1,15 @@ # React Frontend Environment Variables + # API Configuration -# VITE_API_BASE_URL=http://localhost:8000 # Uncomment for production -# In development, we use Vite proxy, so leave this empty or use relative URLs +VITE_API_BASE_URL=http://localhost:8000 VITE_API_URL=/api # CDN Configuration VITE_CDN_PROXY_URL=http://localhost:3001 -# Development Configuration -VITE_DEBUG_MODE=true - # Application Configuration VITE_APP_NAME=Merchant Frontend VITE_APP_VERSION=0.1.0 + +# Debug Configuration +VITE_DEBUG_MODE= diff --git a/merchant-frontend/README.md b/merchant-frontend/README.md index d4d0497..39adedc 100644 --- a/merchant-frontend/README.md +++ b/merchant-frontend/README.md @@ -13,10 +13,10 @@ VITE_CDN_PROXY_URL=http://localhost:3001 ## Features -- 🛍️ **E-commerce Sample**: Products, shopping cart, and checkout flow -- 🔐 **TAP Integration**: Works with signature-verified requests -- 📱 **Responsive Design**: Mobile-friendly interface -- 🛒 **Cart Management**: Session-based shopping cart +- **E-commerce Sample**: Products, shopping cart, and checkout flow +- **TAP Integration**: Works with signature-verified requests +- **Responsive Design**: Mobile-friendly interface +- **Cart Management**: Session-based shopping cart ## Quick Start diff --git a/quick_setup.sh b/quick_setup.sh new file mode 100755 index 0000000..eebbcaf --- /dev/null +++ b/quick_setup.sh @@ -0,0 +1,257 @@ +#Setups the Trusted Agent Protocol application +#Works only on macOS + +############################################################ +# Global Variables / Utils +############################################################ + +PROJECT_DIR=$(pwd) +OPENED_WINDOWS=() + +get_debug() { + read -p "Debug mode? (y/n): " debug + if [ "$debug" = "y" ]; then + echo "DEBUG=true" + else + echo "DEBUG=false" + fi +} + +# Function to open a new terminal tab and run a command +run_in_tab() { + local tab_name=$1 + local dir=$2 + local cmd=$3 + local full_cmd="cd \"$PROJECT_DIR/$dir\" && printf '\\033]0;%s\\007' \"$tab_name\" && $cmd" + + echo "Starting $tab_name..." + + local window_id + window_id=$(osascript - "$full_cmd" <<'EOF' + on run argv + tell application "Terminal" + activate + tell application "System Events" to keystroke "t" using command down + delay 0.5 + do script (item 1 of argv) in front window + return id of front window + end tell + end run +EOF + ) + + if [ -n "$window_id" ]; then + local found=0 + for wid in "${OPENED_WINDOWS[@]}"; do + [ "$wid" = "$window_id" ] && found=1 && break + done + [ "$found" -eq 0 ] && OPENED_WINDOWS+=("$window_id") + fi +} + +cleanup() { + echo "" + echo "Shutting down all services..." + for wid in "${OPENED_WINDOWS[@]}"; do + osascript -e "tell application \"Terminal\"" -e "try" -e "close (every window whose id is $wid)" -e "end try" -e "end tell" 2>/dev/null || true + done + echo "All service windows closed." +} + +trap cleanup EXIT INT TERM + +start_app() { + local tab_name=$1 + local dir=$2 + local cmd=$3 + + if [ ! -d "$PROJECT_DIR/$dir" ]; then + echo "Failed to start $tab_name: directory not found: $PROJECT_DIR/$dir" + return 1 + fi + + if run_in_tab "$tab_name" "$dir" "$cmd"; then + echo "Started $tab_name" + return 0 + else + echo "Failed to start $tab_name" + return 1 + fi +} + +############################################################ +# Setup +############################################################ + +if ! command -v uv >/dev/null 2>&1; then + echo "uv is required but was not found. Install it first, then rerun setup." + exit 1 +fi + +if [ ! -d ".venv" ]; then + uv venv .venv --python 3.12 || { + echo "Failed to create Python 3.12 virtual environment with uv. Aborting setup." + exit 1 + } +else + echo "Using existing .venv" +fi + +source .venv/bin/activate +uv pip install -r requirements.txt || { + echo "Failed to install Python dependencies. Aborting setup." + exit 1 +} + +#setup environment in agent-registry + +cd agent-registry + +get_debug + +cat > .env << EOF +# Agent Registry Environment Variables + +# Database Configuration +DATABASE_URL=sqlite:///./agent_registry.db + +# Server Configuration +HOST=0.0.0.0 +PORT=8001 + +# Debug Configuration +$(get_debug) +EOF + +../.venv/bin/python populate_sample_data.py + +#setup environment in cdn-proxy + +cd ../cdn-proxy + +cat > .env << EOF +# CDN Proxy Environment Variables + +# Server Configuration +PORT=3001 + +# Merchant API Configuration +MERCHANT_API_URL=http://localhost:8000 + +# Debug Configuration +$(get_debug) +EOF + +#setup environment in merchant-backend + +cd ../merchant-backend + +get_debug + +cat > .env << EOF +# Merchant Backend Environment Variables + +# Server Configuration +PORT=8000 + +# Database Configuration +DATABASE_URL=sqlite:///./merchant_backend.db + +# Debug Configuration +$(get_debug) +EOF + +../.venv/bin/python create_sample_data.py + +#setup environment in merchant-frontend + +cd ../merchant-frontend + +cat > .env << EOF +# React Frontend Environment Variables + +# API Configuration +VITE_API_BASE_URL=http://localhost:8000 +VITE_API_URL=/api + +# CDN Configuration +VITE_CDN_PROXY_URL=http://localhost:3001 + +# Application Configuration +VITE_APP_NAME=Merchant Frontend +VITE_APP_VERSION=0.1.0 + +# Debug Configuration +VITE_DEBUG_MODE=$(get_debug) +EOF + +#setup envioronment in tap-agent + +cd ../tap-agent + +#RSA Key Generation + +openssl genrsa -out rsa_private_key.pem 2048 +openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem + +RSA_PRIVATE_KEY=$(< rsa_private_key.pem) +RSA_PUBLIC_KEY=$(< rsa_public_key.pem) +RSA_PRIVATE_KEY_ENV=$(awk '{printf "%s\\n", $0}' rsa_private_key.pem) +RSA_PUBLIC_KEY_ENV=$(awk '{printf "%s\\n", $0}' rsa_public_key.pem) + +echo "RSA Private Key: $RSA_PRIVATE_KEY" +echo "RSA Public Key: $RSA_PUBLIC_KEY" + +#Ed25519 Key Generation + +openssl genpkey -algorithm Ed25519 -out ed25519_private.pem +openssl pkey -in ed25519_private.pem -pubout -out ed25519_public.pem + +ED25519_PRIVATE_KEY=$(base64 -b 0 -i ed25519_private.pem) +ED25519_PUBLIC_KEY=$(base64 -b 0 -i ed25519_public.pem) + +echo "Ed25519 Private Key: $ED25519_PRIVATE_KEY" +echo "Ed25519 Public Key: $ED25519_PUBLIC_KEY" + +cat > .env << EOF +# TAP Agent Environment Variables + +# RSA Keys +RSA_PRIVATE_KEY="$RSA_PRIVATE_KEY_ENV" +RSA_PUBLIC_KEY="$RSA_PUBLIC_KEY_ENV" + +# Ed25519 Keys +ED25519_PRIVATE_KEY="$ED25519_PRIVATE_KEY" +ED25519_PUBLIC_KEY="$ED25519_PUBLIC_KEY" + +# Debug Configuration +$(get_debug) +EOF + +rm rsa_private_key.pem rsa_public_key.pem ed25519_private.pem ed25519_public.pem + +#starting the application + +STARTUP_FAILED=0 + +start_app "agent-registry" "agent-registry" "source ../.venv/bin/activate && python3 main.py" || STARTUP_FAILED=1 +start_app "cdn-proxy" "cdn-proxy" "npm install && npm start" || STARTUP_FAILED=1 +start_app "merchant-backend" "merchant-backend" "source ../.venv/bin/activate && python3 -m uvicorn app.main:app --reload --port 8000" || STARTUP_FAILED=1 +start_app "merchant-frontend" "merchant-frontend" "npm install && npm start" || STARTUP_FAILED=1 +start_app "tap-agent" "tap-agent" "source ../.venv/bin/activate && playwright install && streamlit run agent_app.py --server.runOnSave true" || STARTUP_FAILED=1 + +if [ "$STARTUP_FAILED" -eq 0 ]; then + echo "All applications started successfully!" + echo "You can now access the applications at the following URLs:" + echo " - Agent Registry: http://localhost:8001" + echo " - CDN Proxy: http://localhost:3001" + echo " - Merchant Backend: http://localhost:8000" + echo " - Merchant Frontend: http://localhost:3000" + echo " - TAP Agent: http://localhost:8501" + echo "" + echo "Press Ctrl+C to stop all services and close terminal windows." + while true; do sleep 1; done +else + echo "One or more applications failed to start. Check the messages above." + exit 1 +fi diff --git a/tap-agent/README.md b/tap-agent/README.md index 0e316ec..2e23c68 100644 --- a/tap-agent/README.md +++ b/tap-agent/README.md @@ -18,14 +18,14 @@ ED25519_PUBLIC_KEY="base64_encoded_public_key" ## Features -- 🔐 **Dual Algorithm Support**: Ed25519 and RSA-PSS-SHA256 signatures -- 📋 **RFC 9421 Compliant**: Full HTTP Message Signatures implementation -- 🎯 **Action Selection**: Product details extraction or complete checkout process -- �️ **E-commerce Integration**: Automated cart management and order processing -- 🎭 **Playwright Automation**: Browser-based interaction with merchant sites -- 📊 **Dynamic Input Data**: Real-time signature parameter updates -- 🔄 **Session Management**: Persistent key storage and state management -- 🎨 **Modern UI**: Clean, intuitive Streamlit interface +- **Dual Algorithm Support**: Ed25519 and RSA-PSS-SHA256 signatures +- **RFC 9421 Compliant**: Full HTTP Message Signatures implementation +- **Action Selection**: Product details extraction or complete checkout process +- **E-commerce Integration**: Automated cart management and order processing +- **Playwright Automation**: Browser-based interaction with merchant sites +- **Dynamic Input Data**: Real-time signature parameter updates +- **Session Management**: Persistent key storage and state management +- **Modern UI**: Clean, intuitive Streamlit interface ## Quick Start @@ -70,8 +70,8 @@ Choose between two signature algorithms: ### 3. Action Selection Choose your interaction type: -- **📦 Product Details**: Extract product information from merchant site -- **🛒 Complete Checkout**: Perform full e-commerce checkout process +- **Product Details**: Extract product information from merchant site +- **Complete Checkout**: Perform full e-commerce checkout process ### 4. Execute Action Click the action button to: diff --git a/tap-agent/agent_app.py b/tap-agent/agent_app.py index 43b7862..521a44a 100644 --- a/tap-agent/agent_app.py +++ b/tap-agent/agent_app.py @@ -1349,9 +1349,12 @@ def create_ed25519_signature(private_key_pem: str, authority: str, path: str, ke st.error(f"Ed25519 keys not configured. Please add ED25519_PRIVATE_KEY and ED25519_PUBLIC_KEY to your .env file.") return "", "" - # Load private key from base64 - private_bytes = base64.b64decode(ed25519_private_b64) - private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes) + # Load private key from base64-encoded PEM + private_pem = base64.b64decode(ed25519_private_b64) + private_key = serialization.load_pem_private_key( + private_pem, + password=None, + ) print(f"🔑 Using Ed25519 Private Key: {ed25519_private_b64[:20]}...") print(f"🔑 Using Ed25519 Public Key: {ed25519_public_b64[:20]}...")