responses-proxy 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/cli.js +118 -0
- package/dist/anthropic-messages.js +383 -0
- package/dist/anthropic-messages.test.js +209 -0
- package/dist/audit-log.js +138 -0
- package/dist/audit-log.test.js +480 -0
- package/dist/billing-expiration.js +70 -0
- package/dist/billing-expiration.test.js +114 -0
- package/dist/billing.js +716 -0
- package/dist/billing.test.js +228 -0
- package/dist/chatgpt-oauth-store.js +240 -0
- package/dist/chatgpt-oauth-store.test.js +88 -0
- package/dist/chatgpt-oauth.js +118 -0
- package/dist/chatgpt-oauth.test.js +63 -0
- package/dist/chatgpt-provider-auth.js +60 -0
- package/dist/chatgpt-provider-auth.test.js +101 -0
- package/dist/client/app-icon.svg +17 -0
- package/dist/client/assets/index-C7Vvhst8.js +14 -0
- package/dist/client/assets/index-DpqgYK3L.css +1 -0
- package/dist/client/favicon.svg +17 -0
- package/dist/client/index.html +31 -0
- package/dist/client-config-apply.js +345 -0
- package/dist/client-config-apply.test.js +185 -0
- package/dist/client-token-limits.js +111 -0
- package/dist/client-token-limits.test.js +129 -0
- package/dist/codex-config.js +47 -0
- package/dist/codex-setup.js +87 -0
- package/dist/codex-setup.test.js +30 -0
- package/dist/config.js +314 -0
- package/dist/cost-analytics.js +31 -0
- package/dist/cost-analytics.test.js +38 -0
- package/dist/customer-key-access.js +126 -0
- package/dist/customer-key-access.test.js +178 -0
- package/dist/customer-keys.js +209 -0
- package/dist/customer-keys.test.js +68 -0
- package/dist/customer-usage.js +18 -0
- package/dist/customer-usage.test.js +55 -0
- package/dist/dashboard-auth.js +318 -0
- package/dist/dashboard-auth.test.js +133 -0
- package/dist/dashboard-serving.test.js +235 -0
- package/dist/error-response.js +174 -0
- package/dist/error-response.test.js +88 -0
- package/dist/forward.js +357 -0
- package/dist/health-websocket-manager.js +174 -0
- package/dist/http-rate-limit.js +36 -0
- package/dist/http-rate-limit.test.js +62 -0
- package/dist/kiro-auth.js +136 -0
- package/dist/kiro-auth.test.js +234 -0
- package/dist/kiro-codewhisperer.js +646 -0
- package/dist/kiro-codewhisperer.test.js +219 -0
- package/dist/kiro-device-login.js +338 -0
- package/dist/kiro-eventstream.js +219 -0
- package/dist/kiro-eventstream.test.js +79 -0
- package/dist/kiro-forward.js +401 -0
- package/dist/kiro-import-cli.js +69 -0
- package/dist/kiro-import.js +94 -0
- package/dist/kiro-import.test.js +125 -0
- package/dist/kiro-token-store.js +196 -0
- package/dist/kiro-token-store.test.js +207 -0
- package/dist/krouter-usage.js +243 -0
- package/dist/model-combo-repository.js +147 -0
- package/dist/model-routing.js +69 -0
- package/dist/model-routing.test.js +41 -0
- package/dist/normalize-request.js +531 -0
- package/dist/normalize-request.test.js +277 -0
- package/dist/omv-public-firewall.test.js +11 -0
- package/dist/package.json +17 -0
- package/dist/prompt-cache-state.js +146 -0
- package/dist/prompt-cache-state.test.js +71 -0
- package/dist/prompt-cache.js +229 -0
- package/dist/provider-health-service.js +404 -0
- package/dist/provider-request-parameters.js +107 -0
- package/dist/provider-request-parameters.test.js +26 -0
- package/dist/provider-routing.js +114 -0
- package/dist/provider-routing.test.js +64 -0
- package/dist/provider-usage.js +314 -0
- package/dist/request-timeout-policy.js +61 -0
- package/dist/request-timeout-policy.test.js +40 -0
- package/dist/response-cache.js +69 -0
- package/dist/response-cache.test.js +28 -0
- package/dist/routing-combo-repository.js +300 -0
- package/dist/routing-engine.js +377 -0
- package/dist/routing-integration.js +155 -0
- package/dist/routing-simulation-engine.js +326 -0
- package/dist/rtk-layer.js +483 -0
- package/dist/rtk-layer.test.js +198 -0
- package/dist/runtime-provider-repository.js +1742 -0
- package/dist/runtime-provider-repository.test.js +1177 -0
- package/dist/schema.js +118 -0
- package/dist/schema.test.js +16 -0
- package/dist/sepay-webhook.js +87 -0
- package/dist/sepay-webhook.test.js +142 -0
- package/dist/server-body-limit.test.js +35 -0
- package/dist/server-client-token-limits.test.js +161 -0
- package/dist/server-codex-config-setup.test.js +76 -0
- package/dist/server-http-rate-limit.test.js +80 -0
- package/dist/server-response-cache.test.js +105 -0
- package/dist/server-routes-alias.test.js +39 -0
- package/dist/server-sepay-webhook-security.test.js +59 -0
- package/dist/server.js +5906 -0
- package/dist/session-log.js +178 -0
- package/dist/tailnet-funnel-script.test.js +33 -0
- package/dist/telegram-bot/actions.js +118 -0
- package/dist/telegram-bot/admin-actions.js +103 -0
- package/dist/telegram-bot/auth.js +46 -0
- package/dist/telegram-bot/auth.test.js +1 -0
- package/dist/telegram-bot/bot-identity-repository.js +189 -0
- package/dist/telegram-bot/bot-identity-repository.test.js +78 -0
- package/dist/telegram-bot/callbacks.js +30 -0
- package/dist/telegram-bot/codex-config-delivery.js +38 -0
- package/dist/telegram-bot/codex-config-delivery.test.js +75 -0
- package/dist/telegram-bot/commands/accounts.js +140 -0
- package/dist/telegram-bot/commands/apikey.js +737 -0
- package/dist/telegram-bot/commands/apply.js +265 -0
- package/dist/telegram-bot/commands/clients.js +13 -0
- package/dist/telegram-bot/commands/customer-billing.test.js +271 -0
- package/dist/telegram-bot/commands/grant.js +138 -0
- package/dist/telegram-bot/commands/grant.test.js +217 -0
- package/dist/telegram-bot/commands/help.js +52 -0
- package/dist/telegram-bot/commands/me.js +53 -0
- package/dist/telegram-bot/commands/models.js +6 -0
- package/dist/telegram-bot/commands/oauth.js +64 -0
- package/dist/telegram-bot/commands/plans.js +96 -0
- package/dist/telegram-bot/commands/providers.js +27 -0
- package/dist/telegram-bot/commands/quota.js +10 -0
- package/dist/telegram-bot/commands/renew-user.js +139 -0
- package/dist/telegram-bot/commands/renew-user.test.js +184 -0
- package/dist/telegram-bot/commands/renew.js +1369 -0
- package/dist/telegram-bot/commands/renew.test.js +1633 -0
- package/dist/telegram-bot/commands/start.js +212 -0
- package/dist/telegram-bot/commands/start.test.js +280 -0
- package/dist/telegram-bot/commands/status.js +6 -0
- package/dist/telegram-bot/commands/tailscale.js +15 -0
- package/dist/telegram-bot/commands/tailscale.test.js +76 -0
- package/dist/telegram-bot/commands/test.js +51 -0
- package/dist/telegram-bot/commands/test.test.js +14 -0
- package/dist/telegram-bot/commands/usage.js +10 -0
- package/dist/telegram-bot/config.js +98 -0
- package/dist/telegram-bot/config.test.js +42 -0
- package/dist/telegram-bot/customer-actions.js +160 -0
- package/dist/telegram-bot/customer-api-keys.js +68 -0
- package/dist/telegram-bot/customer-billing.js +72 -0
- package/dist/telegram-bot/customer-workspace-repository.js +134 -0
- package/dist/telegram-bot/customer-workspace-repository.test.js +47 -0
- package/dist/telegram-bot/dashboard-login.js +39 -0
- package/dist/telegram-bot/format.js +140 -0
- package/dist/telegram-bot/grants.js +370 -0
- package/dist/telegram-bot/grants.test.js +290 -0
- package/dist/telegram-bot/index.js +85 -0
- package/dist/telegram-bot/message-cleanup.js +55 -0
- package/dist/telegram-bot/message-cleanup.test.js +77 -0
- package/dist/telegram-bot/message-format.js +45 -0
- package/dist/telegram-bot/message-format.test.js +10 -0
- package/dist/telegram-bot/proxy-client.js +174 -0
- package/dist/telegram-bot/rate-limit.js +95 -0
- package/dist/telegram-bot/rate-limit.test.js +58 -0
- package/dist/telegram-bot/sessions.js +171 -0
- package/dist/telegram-bot/sessions.test.js +107 -0
- package/dist/telegram-bot/telegram-adapter.js +126 -0
- package/dist/telegram-bot/worker.js +63 -0
- package/package.json +39 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "responses-proxy-server-rate-limit-"));
|
|
7
|
+
const dbFile = path.join(tempDir, "app.sqlite");
|
|
8
|
+
process.env.RESPONSES_PROXY_DISABLE_LISTEN = "true";
|
|
9
|
+
process.env.APP_DB_PATH = dbFile;
|
|
10
|
+
process.env.CUSTOMER_KEY_DB_PATH = dbFile;
|
|
11
|
+
process.env.UPSTREAM_BASE_URL = "https://upstream.example/v1";
|
|
12
|
+
process.env.UPSTREAM_API_KEY = "provider-key";
|
|
13
|
+
process.env.PROVIDER_USAGE_CHECK_ENABLED = "false";
|
|
14
|
+
process.env.CHATGPT_OAUTH_ENABLED = "false";
|
|
15
|
+
process.env.LOG_LEVEL = "silent";
|
|
16
|
+
process.env.HTTP_TRUST_PROXY = "false";
|
|
17
|
+
process.env.HTTP_RATE_LIMIT_ENABLED = "true";
|
|
18
|
+
process.env.HTTP_RATE_LIMIT_WINDOW_MS = "60000";
|
|
19
|
+
process.env.HTTP_RATE_LIMIT_RESPONSES_MAX_REQUESTS = "1";
|
|
20
|
+
process.env.HTTP_RATE_LIMIT_UNAUTHENTICATED_MAX_REQUESTS = "1";
|
|
21
|
+
const { app } = await import("./server.js");
|
|
22
|
+
test.after(async () => {
|
|
23
|
+
await app.close();
|
|
24
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
25
|
+
});
|
|
26
|
+
test("responses endpoint returns 429 after configured rate limit threshold", async () => {
|
|
27
|
+
const first = await app.inject({
|
|
28
|
+
method: "POST",
|
|
29
|
+
url: "/v1/responses",
|
|
30
|
+
headers: {
|
|
31
|
+
"x-forwarded-for": "203.0.113.10",
|
|
32
|
+
},
|
|
33
|
+
payload: {},
|
|
34
|
+
});
|
|
35
|
+
assert.equal(first.statusCode, 400);
|
|
36
|
+
assert.equal(first.headers["x-ratelimit-limit"], "1");
|
|
37
|
+
assert.equal(first.headers["x-ratelimit-remaining"], "0");
|
|
38
|
+
const second = await app.inject({
|
|
39
|
+
method: "POST",
|
|
40
|
+
url: "/v1/responses",
|
|
41
|
+
headers: {
|
|
42
|
+
"x-forwarded-for": "198.51.100.10",
|
|
43
|
+
},
|
|
44
|
+
payload: {},
|
|
45
|
+
});
|
|
46
|
+
assert.equal(second.statusCode, 429);
|
|
47
|
+
assert.equal(second.headers["retry-after"], "60");
|
|
48
|
+
assert.equal(second.headers["x-ratelimit-limit"], "1");
|
|
49
|
+
assert.equal(second.headers["x-ratelimit-remaining"], "0");
|
|
50
|
+
assert.equal(second.json().error.code, "HTTP_RATE_LIMIT_EXCEEDED");
|
|
51
|
+
});
|
|
52
|
+
test("bearer requests get separate rate limit buckets by token", async () => {
|
|
53
|
+
const firstBearer = await app.inject({
|
|
54
|
+
method: "POST",
|
|
55
|
+
url: "/v1/responses",
|
|
56
|
+
headers: {
|
|
57
|
+
authorization: "Bearer bearer-token-a",
|
|
58
|
+
},
|
|
59
|
+
payload: {},
|
|
60
|
+
});
|
|
61
|
+
assert.equal(firstBearer.statusCode, 400);
|
|
62
|
+
const secondBearer = await app.inject({
|
|
63
|
+
method: "POST",
|
|
64
|
+
url: "/v1/responses",
|
|
65
|
+
headers: {
|
|
66
|
+
authorization: "Bearer bearer-token-b",
|
|
67
|
+
},
|
|
68
|
+
payload: {},
|
|
69
|
+
});
|
|
70
|
+
assert.equal(secondBearer.statusCode, 400);
|
|
71
|
+
const thirdBearer = await app.inject({
|
|
72
|
+
method: "POST",
|
|
73
|
+
url: "/v1/responses",
|
|
74
|
+
headers: {
|
|
75
|
+
authorization: "Bearer bearer-token-a",
|
|
76
|
+
},
|
|
77
|
+
payload: {},
|
|
78
|
+
});
|
|
79
|
+
assert.equal(thirdBearer.statusCode, 429);
|
|
80
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "responses-proxy-server-response-cache-"));
|
|
8
|
+
const dbFile = path.join(tempDir, "app.sqlite");
|
|
9
|
+
const upstream = createServer((request, response) => {
|
|
10
|
+
if (request.url !== "/responses") {
|
|
11
|
+
response.statusCode = 404;
|
|
12
|
+
response.end();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
response.setHeader("Content-Type", "application/json");
|
|
16
|
+
response.end(JSON.stringify({
|
|
17
|
+
id: `upstream-${upstreamHits + 1}`,
|
|
18
|
+
object: "response",
|
|
19
|
+
status: "completed",
|
|
20
|
+
output: [],
|
|
21
|
+
usage: {
|
|
22
|
+
input_tokens: 12,
|
|
23
|
+
output_tokens: 3,
|
|
24
|
+
total_tokens: 15,
|
|
25
|
+
input_tokens_details: { cached_tokens: 0 },
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
upstreamHits += 1;
|
|
29
|
+
});
|
|
30
|
+
let upstreamHits = 0;
|
|
31
|
+
process.env.RESPONSES_PROXY_DISABLE_LISTEN = "true";
|
|
32
|
+
process.env.APP_DB_PATH = dbFile;
|
|
33
|
+
process.env.CUSTOMER_KEY_DB_PATH = dbFile;
|
|
34
|
+
process.env.UPSTREAM_BASE_URL = "http://127.0.0.1:0";
|
|
35
|
+
process.env.UPSTREAM_API_KEY = "provider-key";
|
|
36
|
+
process.env.PROVIDER_USAGE_CHECK_ENABLED = "false";
|
|
37
|
+
process.env.CHATGPT_OAUTH_ENABLED = "false";
|
|
38
|
+
process.env.LOG_LEVEL = "silent";
|
|
39
|
+
process.env.RESPONSE_CACHE_ENABLED = "true";
|
|
40
|
+
process.env.RESPONSE_CACHE_TTL_MS = "60000";
|
|
41
|
+
process.env.RESPONSE_CACHE_MAX_PAYLOAD_BYTES = "524288";
|
|
42
|
+
process.env.RESPONSES_PROXY_CLIENT_API_KEY = "provider-key";
|
|
43
|
+
await new Promise((resolve) => {
|
|
44
|
+
upstream.listen(0, "127.0.0.1", () => resolve());
|
|
45
|
+
});
|
|
46
|
+
const upstreamAddress = upstream.address();
|
|
47
|
+
if (!upstreamAddress || typeof upstreamAddress === "string") {
|
|
48
|
+
throw new Error("Upstream server did not bind to a port");
|
|
49
|
+
}
|
|
50
|
+
process.env.UPSTREAM_BASE_URL = `http://127.0.0.1:${upstreamAddress.port}`;
|
|
51
|
+
const { app } = await import("./server.js");
|
|
52
|
+
test.after(async () => {
|
|
53
|
+
await app.close();
|
|
54
|
+
await new Promise((resolve) => upstream.close(() => resolve()));
|
|
55
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
56
|
+
});
|
|
57
|
+
test("response cache hits on repeated non-stream requests and analytics exposes stats", async () => {
|
|
58
|
+
const payload = {
|
|
59
|
+
model: "gpt-4.1",
|
|
60
|
+
input: "hello",
|
|
61
|
+
};
|
|
62
|
+
const first = await app.inject({
|
|
63
|
+
method: "POST",
|
|
64
|
+
url: "/v1/responses",
|
|
65
|
+
headers: {
|
|
66
|
+
authorization: "Bearer provider-key",
|
|
67
|
+
},
|
|
68
|
+
payload,
|
|
69
|
+
});
|
|
70
|
+
assert.equal(first.statusCode, 200);
|
|
71
|
+
assert.equal(first.headers["x-proxy-response-cache"], undefined);
|
|
72
|
+
assert.equal(upstreamHits, 1);
|
|
73
|
+
const second = await app.inject({
|
|
74
|
+
method: "POST",
|
|
75
|
+
url: "/v1/responses",
|
|
76
|
+
headers: {
|
|
77
|
+
authorization: "Bearer provider-key",
|
|
78
|
+
},
|
|
79
|
+
payload,
|
|
80
|
+
});
|
|
81
|
+
assert.equal(second.statusCode, 200);
|
|
82
|
+
assert.equal(second.headers["x-proxy-response-cache"], "hit");
|
|
83
|
+
assert.equal(upstreamHits, 1);
|
|
84
|
+
assert.deepEqual(second.json(), first.json());
|
|
85
|
+
const analytics = await app.inject({
|
|
86
|
+
method: "GET",
|
|
87
|
+
url: "/api/analytics/cost-summary",
|
|
88
|
+
headers: {
|
|
89
|
+
authorization: "Bearer provider-key",
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
assert.equal(analytics.statusCode, 200);
|
|
93
|
+
const body = analytics.json();
|
|
94
|
+
assert.equal(body.summary.totalRequests >= 1, true);
|
|
95
|
+
assert.equal(body.responseCacheStats?.totalEntries, 1);
|
|
96
|
+
const flushed = await app.inject({
|
|
97
|
+
method: "POST",
|
|
98
|
+
url: "/api/analytics/response-cache/flush",
|
|
99
|
+
headers: {
|
|
100
|
+
authorization: "Bearer provider-key",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
assert.equal(flushed.statusCode, 200);
|
|
104
|
+
assert.equal(flushed.json().deleted, 1);
|
|
105
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "responses-proxy-server-routes-alias-"));
|
|
7
|
+
const dbFile = path.join(tempDir, "app.sqlite");
|
|
8
|
+
process.env.RESPONSES_PROXY_DISABLE_LISTEN = "true";
|
|
9
|
+
process.env.APP_DB_PATH = dbFile;
|
|
10
|
+
process.env.CUSTOMER_KEY_DB_PATH = dbFile;
|
|
11
|
+
process.env.UPSTREAM_BASE_URL = "https://upstream.example/v1";
|
|
12
|
+
process.env.UPSTREAM_API_KEY = "provider-key";
|
|
13
|
+
process.env.PROVIDER_USAGE_CHECK_ENABLED = "false";
|
|
14
|
+
process.env.CHATGPT_OAUTH_ENABLED = "false";
|
|
15
|
+
process.env.LOG_LEVEL = "silent";
|
|
16
|
+
const { app } = await import("./server.js");
|
|
17
|
+
test.after(async () => {
|
|
18
|
+
await app.close();
|
|
19
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
test("route alias /v1/chat/completions routes to responses handler and fails validation with 400", async () => {
|
|
22
|
+
const response = await app.inject({
|
|
23
|
+
method: "POST",
|
|
24
|
+
url: "/v1/chat/completions",
|
|
25
|
+
payload: {},
|
|
26
|
+
});
|
|
27
|
+
// If it was a 404, it would return 404. Returning 400 means it hit the handler and failed validation.
|
|
28
|
+
assert.equal(response.statusCode, 400);
|
|
29
|
+
assert.equal(response.json().error?.code, "INVALID_RESPONSES_REQUEST");
|
|
30
|
+
});
|
|
31
|
+
test("route alias /v1/completions routes to responses handler and fails validation with 400", async () => {
|
|
32
|
+
const response = await app.inject({
|
|
33
|
+
method: "POST",
|
|
34
|
+
url: "/v1/completions",
|
|
35
|
+
payload: {},
|
|
36
|
+
});
|
|
37
|
+
assert.equal(response.statusCode, 400);
|
|
38
|
+
assert.equal(response.json().error?.code, "INVALID_RESPONSES_REQUEST");
|
|
39
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "responses-proxy-server-sepay-"));
|
|
7
|
+
const dbFile = path.join(tempDir, "app.sqlite");
|
|
8
|
+
process.env.RESPONSES_PROXY_DISABLE_LISTEN = "true";
|
|
9
|
+
process.env.APP_DB_PATH = dbFile;
|
|
10
|
+
process.env.CUSTOMER_KEY_DB_PATH = dbFile;
|
|
11
|
+
process.env.UPSTREAM_BASE_URL = "https://upstream.example/v1";
|
|
12
|
+
process.env.UPSTREAM_API_KEY = "provider-key";
|
|
13
|
+
process.env.PROVIDER_USAGE_CHECK_ENABLED = "false";
|
|
14
|
+
process.env.CHATGPT_OAUTH_ENABLED = "false";
|
|
15
|
+
process.env.LOG_LEVEL = "silent";
|
|
16
|
+
process.env.SEPAY_WEBHOOK_ENABLED = "true";
|
|
17
|
+
process.env.SEPAY_WEBHOOK_SECRET = "webhook-secret";
|
|
18
|
+
process.env.HTTP_TRUST_PROXY = "true";
|
|
19
|
+
process.env.SEPAY_WEBHOOK_ALLOWED_IPS = "203.0.113.10,198.51.100.0/24";
|
|
20
|
+
const { app } = await import("./server.js");
|
|
21
|
+
test.after(async () => {
|
|
22
|
+
await app.close();
|
|
23
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
24
|
+
});
|
|
25
|
+
test("sepay webhook rejects non-allowed source ip", async () => {
|
|
26
|
+
const response = await app.inject({
|
|
27
|
+
method: "POST",
|
|
28
|
+
url: "/api/sepay/webhook",
|
|
29
|
+
headers: {
|
|
30
|
+
authorization: "Bearer webhook-secret",
|
|
31
|
+
"x-forwarded-for": "192.0.2.10",
|
|
32
|
+
},
|
|
33
|
+
payload: {},
|
|
34
|
+
});
|
|
35
|
+
assert.equal(response.statusCode, 403);
|
|
36
|
+
assert.equal(response.json().error.code, "SEPAY_WEBHOOK_IP_FORBIDDEN");
|
|
37
|
+
});
|
|
38
|
+
test("sepay webhook accepts allowed exact ip and cidr", async () => {
|
|
39
|
+
const exact = await app.inject({
|
|
40
|
+
method: "POST",
|
|
41
|
+
url: "/api/sepay/webhook",
|
|
42
|
+
headers: {
|
|
43
|
+
authorization: "Bearer webhook-secret",
|
|
44
|
+
"x-forwarded-for": "203.0.113.10",
|
|
45
|
+
},
|
|
46
|
+
payload: {},
|
|
47
|
+
});
|
|
48
|
+
assert.equal(exact.statusCode, 200);
|
|
49
|
+
const cidr = await app.inject({
|
|
50
|
+
method: "POST",
|
|
51
|
+
url: "/api/sepay/webhook",
|
|
52
|
+
headers: {
|
|
53
|
+
authorization: "Bearer webhook-secret",
|
|
54
|
+
"x-forwarded-for": "198.51.100.42",
|
|
55
|
+
},
|
|
56
|
+
payload: {},
|
|
57
|
+
});
|
|
58
|
+
assert.equal(cidr.statusCode, 200);
|
|
59
|
+
});
|