File size: 4,733 Bytes
b94e45f
 
 
 
0d0f0f9
 
0602b26
b94e45f
0602b26
11c0f3a
b94e45f
7c98fe6
b94e45f
 
 
 
 
 
 
 
 
 
0d0f0f9
b94e45f
 
7c98fe6
fcd6f91
 
b94e45f
7c98fe6
 
 
 
 
 
 
 
 
 
 
 
b94e45f
7c98fe6
 
 
b94e45f
 
 
 
 
 
 
7c98fe6
b94e45f
 
 
 
 
 
 
 
 
 
0d0f0f9
b94e45f
 
 
7c98fe6
 
 
 
 
b94e45f
 
 
 
7c98fe6
 
 
 
 
 
 
 
 
 
 
b94e45f
a82c5eb
 
51c6312
 
 
 
 
 
 
 
 
 
 
0d0f0f9
51c6312
 
 
 
 
 
 
 
 
 
 
a82c5eb
 
 
 
 
 
 
 
fcd6f91
 
a82c5eb
7c98fe6
a82c5eb
 
 
 
dc7d838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from unittest.mock import patch

from fastapi.testclient import TestClient

from free_claude_code.api.dependencies import get_settings
from free_claude_code.config.settings import Settings
from tests.api.support import create_test_app

app = create_test_app()


def test_proxy_auth_requires_canonical_bearer_header():
    client = TestClient(app)
    settings = Settings()
    settings.anthropic_auth_token = "s3cr3t"
    app.dependency_overrides[get_settings] = lambda: settings

    payload = {
        "model": "claude-3-sonnet",
        "messages": [{"role": "user", "content": "hello"}],
    }

    with patch("free_claude_code.api.routes.get_token_count", return_value=1):
        r = client.post("/v1/messages/count_tokens", json=payload)
        assert r.status_code == 401
        assert r.json() == {"detail": "Missing proxy authentication token"}
        assert r.headers["request-id"].startswith("req_")
        assert "x-should-retry" not in r.headers

        for headers in (
            {"X-API-Key": "s3cr3t"},
            {"anthropic-auth-token": "s3cr3t"},
        ):
            r = client.post(
                "/v1/messages/count_tokens",
                json=payload,
                headers=headers,
            )
            assert r.status_code == 401
            assert r.json() == {"detail": "Missing proxy authentication token"}

        r = client.post(
            "/v1/messages/count_tokens",
            json=payload,
            headers={"Authorization": "Bearer s3cr3t"},
        )
        assert r.status_code == 200
        assert r.json()["input_tokens"] == 1

    app.dependency_overrides.clear()


def test_proxy_auth_ignores_conflicting_legacy_headers():
    client = TestClient(app)
    settings = Settings()
    settings.anthropic_auth_token = "b3artoken"
    app.dependency_overrides[get_settings] = lambda: settings

    payload = {
        "model": "claude-3-sonnet",
        "messages": [{"role": "user", "content": "hello"}],
    }

    with patch("free_claude_code.api.routes.get_token_count", return_value=2):
        r = client.post(
            "/v1/messages/count_tokens",
            json=payload,
            headers={
                "Authorization": "Bearer b3artoken",
                "X-API-Key": "stale-anthropic-key",
                "anthropic-auth-token": "stale-proxy-token",
            },
        )
        assert r.status_code == 200
        assert r.json()["input_tokens"] == 2

        r = client.post(
            "/v1/messages/count_tokens",
            json=payload,
            headers={
                "Authorization": "Bearer wrong",
                "X-API-Key": "b3artoken",
            },
        )
        assert r.status_code == 401
        assert r.json() == {"detail": "Invalid proxy authentication token"}

    app.dependency_overrides.clear()


def test_anthropic_auth_token_normalizes_configured_whitespace():
    client = TestClient(app)
    settings = Settings()
    settings.anthropic_auth_token = "  spaced-token  \n"
    app.dependency_overrides[get_settings] = lambda: settings

    payload = {
        "model": "claude-3-sonnet",
        "messages": [{"role": "user", "content": "hello"}],
    }

    with patch("free_claude_code.api.routes.get_token_count", return_value=3):
        r = client.post(
            "/v1/messages/count_tokens",
            json=payload,
            headers={"Authorization": "Bearer spaced-token"},
        )
        assert r.status_code == 200
        assert r.json()["input_tokens"] == 3

    app.dependency_overrides.clear()


def test_anthropic_auth_token_applies_to_models_endpoint():
    client = TestClient(app)
    settings = Settings()
    settings.anthropic_auth_token = "models-token"
    app.dependency_overrides[get_settings] = lambda: settings

    r = client.get("/v1/models")
    assert r.status_code == 401
    assert r.headers["x-request-id"] == r.headers["request-id"]
    assert "x-should-retry" not in r.headers

    r = client.get("/v1/models", headers={"Authorization": "Bearer models-token"})
    assert r.status_code == 200
    assert "data" in r.json()

    app.dependency_overrides.clear()


def test_root_get_requires_auth_but_root_probes_are_public():
    client = TestClient(app)
    settings = Settings()
    settings.anthropic_auth_token = "root-token"
    app.dependency_overrides[get_settings] = lambda: settings

    response = client.get("/")
    assert response.status_code == 401

    head = client.head("/")
    assert head.status_code == 204
    assert head.headers["Allow"] == "GET, HEAD, OPTIONS"

    options = client.options("/")
    assert options.status_code == 204
    assert options.headers["Allow"] == "GET, HEAD, OPTIONS"

    app.dependency_overrides.clear()