valleydam 0.1.1
A DNS-based cryptographic identity verification protocol for AI agents and automated HTTP clients.
Requires Python: >=3.7

# ⛰️ ValleyDam

ValleyDam is a lightweight, open protocol for verifying the identity of automated HTTP clients — including AI agents and web scrapers — using DNS-backed cryptographic proof.

It enables a website to verify that a request *actually* came from `bot.openai.com` (or your startup’s domain) **without** API keys, IP allowlists, or complex authentication handshakes.

---

Today, websites have no reliable way to identify automated clients.

- **User-Agent strings are lies**  
  Anyone can send `User-Agent: Googlebot`.

- **IP blocking is messy**  
  Legitimate bots often run on shared cloud infrastructure (AWS, GCP).

- **API keys don’t scale**  
  You can’t safely issue and manage API keys for every website on the internet.

---

## The Solution

ValleyDam uses **Ed25519 digital signatures** anchored in **DNS TXT records** to create a verifiable, spoof-resistant identity for bots.

### How it works

1. **The bot signs each request** using a private Ed25519 key.
2. **The server retrieves the public key** from the bot’s DNS record  
   (e.g. `_agent.yourwebsite.com`).
3. **The signature is verified**. If it matches, the bot’s identity is cryptographically proven.

No central authority. No shared secrets. No API keys.

---

## 📦 Installation

```bash
pip install valleydam
```

---

## 🚀 Usage

### For Web Scrapper or Agent Developers (The Client)

If you are building a scraper or AI agent, use `ValleyDamSession` to automatically sign outgoing HTTP requests.

---

#### 1. Generate Your Identity

Run the CLI to generate a private key and receive your DNS TXT record value:

```bash
valleydam-gen
```

Follow the printed instructions to add the TXT record to your domain’s DNS.

---

#### 2. Use ValleyDam in Your Code

ValleyDam behaves just like the standard Python `requests` library.

```python
from valleydam import ValleyDamSession

# Initialize your authenticated session
agent = ValleyDamSession(
    domain="yourwebsite.com",                       # Your verified domain
    private_key_path="yourwebsite_com_private.pem"  # Generated in step 1
)

# Make requests as normal — they are now cryptographically signed
response = agent.get("https://protected-website.com/api/data")

print(response.text)
```

---

### For Website Owners (The Server)

Use theGuide

ValleyDam verifies incoming automated traffic and prevents agent impersonation by validating request signatures against DNS-published public keys.

It runs as middleware and works with Flask, Django, FastAPI, and similar frameworks.

---


#### 🔒 Hard Validation (Block)

Reject invalid or spoofed requests. Best for protected or agent-only APIs.

```python
from flask import Flask, request, jsonify
from valleydam import verify_request

app = Flask(__name__)

@app.route('/agent-api', methods=['POST'])
def protected_route():
    try:
        verify_request(request)
        identity = request.headers.get('X-ValleyDam-KeyID')
        return jsonify({
            "status": "Welcome",
            "verified_user": identity
        })
    except ValueError as e:
        return jsonify({
            "error": "Access Denied",
            "reason": str(e)
        }), 403

if __name__ == "__main__":
    app.run(port=5000)
```

#### 📄 Soft Validation (Log Only)

Attempt verification, log results, but allow all traffic.

```python
import logging
from flask import Flask, request, jsonify
from valleydam import verify_request

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route('/public-api', methods=['GET', 'POST'])
def public_route():
    identity = "Unverified (Anonymous)"

    try:
        verify_request(request)
        identity = request.headers.get('X-ValleyDam-KeyID')
        logging.info(f"Verified request from: {identity}")
    except ValueError as e:
        logging.warning(f"Verification failed: {e}")

    return jsonify({
        "data": "This is public data",
        "your_status": identity
    })

if __name__ == "__main__":
    app.run(port=5000)
```