@prosopo/api 3.5.20 → 3.5.21
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/.turbo/turbo-build$colon$cjs.log +2 -2
- package/.turbo/turbo-build$colon$tsc.log +9 -9
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +5 -0
- package/dist/tests/api.test-d.d.ts +2 -0
- package/dist/tests/api.test-d.d.ts.map +1 -0
- package/dist/tests/api.test-d.js +66 -0
- package/dist/tests/api.test-d.js.map +1 -0
- package/dist/tests/apiHarness.d.ts +25 -0
- package/dist/tests/apiHarness.d.ts.map +1 -0
- package/dist/tests/apiHarness.js +87 -0
- package/dist/tests/apiHarness.js.map +1 -0
- package/dist/tests/httpClientBase.unit.test.d.ts +2 -0
- package/dist/tests/httpClientBase.unit.test.d.ts.map +1 -0
- package/dist/tests/httpClientBase.unit.test.js +257 -0
- package/dist/tests/httpClientBase.unit.test.js.map +1 -0
- package/dist/tests/providerApi.unit.test.d.ts +2 -0
- package/dist/tests/providerApi.unit.test.d.ts.map +1 -0
- package/dist/tests/providerApi.unit.test.js +536 -0
- package/dist/tests/providerApi.unit.test.js.map +1 -0
- package/package.json +5 -2
- package/vite.test.config.ts +19 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api@3.5.
|
|
2
|
+
> @prosopo/api@3.5.21 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -33,4 +33,4 @@ dist/cjs/index.cjs 0.61 kB │ gzip: 0.24 kB
|
|
|
33
33
|
dist/cjs/api/HttpClientBase.cjs 2.29 kB │ gzip: 0.61 kB
|
|
34
34
|
dist/cjs/api/ProviderApi.cjs 13.81 kB │ gzip: 2.26 kB
|
|
35
35
|
|
|
36
|
-
[32m✓ built in
|
|
36
|
+
[32m✓ built in 72ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api@3.5.
|
|
2
|
+
> @prosopo/api@3.5.21 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
12:36:02 PM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -10,17 +10,17 @@
|
|
|
10
10
|
* ../types/tsconfig.json
|
|
11
11
|
* tsconfig.json
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
12:36:02 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/index.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
12:36:02 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
12:36:02 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
12:36:02 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
12:36:02 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
12:36:02 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
12:36:02 PM - Building project '/home/runner/work/captcha/captcha/packages/api/tsconfig.json'...
|
|
26
26
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api@3.5.
|
|
2
|
+
> @prosopo/api@3.5.21 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/api@3.5.
|
|
6
|
+
> @prosopo/api@3.5.21 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -38,4 +38,4 @@ dist/index.js 0.36 kB │ gzip: 0.18 kB
|
|
|
38
38
|
dist/api/HttpClientBase.js 2.19 kB │ gzip: 0.60 kB
|
|
39
39
|
dist/api/ProviderApi.js 12.18 kB │ gzip: 2.27 kB
|
|
40
40
|
|
|
41
|
-
[32m✓ built in
|
|
41
|
+
[32m✓ built in 73ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# @prosopo/api
|
|
2
2
|
|
|
3
|
+
## 3.5.21
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- 1e0cf14: Add unit and type tests for the provider API client: transport behaviour (JSON error bodies vs transport errors, 400 handling, parse failures, header merging), the in-flight challenge de-duplication, every client and admin endpoint's path, body and headers, and the frictionless honeypot meta header. 128 tests, 100% statement, branch, function and line coverage. No behaviour changes.
|
|
7
|
+
|
|
3
8
|
## 3.5.20
|
|
4
9
|
### Patch Changes
|
|
5
10
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test-d.d.ts","sourceRoot":"","sources":["../../src/tests/api.test-d.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { assertType, describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
import HttpClientBase from "../api/HttpClientBase.js";
|
|
3
|
+
import ProviderApi, { VERIFY_FORWARDED_HEADER } from "../api/ProviderApi.js";
|
|
4
|
+
import { ApiClient } from "../api/apiClient.js";
|
|
5
|
+
describe("the package entrypoint", () => {
|
|
6
|
+
test("exports exactly the client surface", () => {
|
|
7
|
+
expectTypeOf().toEqualTypeOf();
|
|
8
|
+
expectTypeOf().toEqualTypeOf();
|
|
9
|
+
expectTypeOf().toEqualTypeOf();
|
|
10
|
+
expectTypeOf().toEqualTypeOf();
|
|
11
|
+
expectTypeOf().toExtend();
|
|
12
|
+
});
|
|
13
|
+
test("the forwarded marker is a string constant callers can set as a header", () => {
|
|
14
|
+
expectTypeOf(VERIFY_FORWARDED_HEADER).toExtend();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe("HttpClientBase's types", () => {
|
|
18
|
+
test("takes a base URL and an optional prefix", () => {
|
|
19
|
+
expectTypeOf().toEqualTypeOf();
|
|
20
|
+
});
|
|
21
|
+
test("the transport methods are not part of the public surface", () => {
|
|
22
|
+
expectTypeOf(new HttpClientBase("url").fetch).toBeCallableWith("/path");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("HttpError's types", () => {
|
|
26
|
+
test("carries the status, text and URL", () => {
|
|
27
|
+
expectTypeOf().toEqualTypeOf();
|
|
28
|
+
expectTypeOf().toEqualTypeOf();
|
|
29
|
+
expectTypeOf().toEqualTypeOf();
|
|
30
|
+
expectTypeOf().toEqualTypeOf();
|
|
31
|
+
expectTypeOf().toExtend();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe("ApiClient's types", () => {
|
|
35
|
+
test("needs both a URL and the account it speaks for", () => {
|
|
36
|
+
expectTypeOf().toEqualTypeOf();
|
|
37
|
+
assertType(new ApiClient("https://provider.prosopo.io"));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("ProviderApi's types", () => {
|
|
41
|
+
test("implements the shared provider interface", () => {
|
|
42
|
+
expectTypeOf().toExtend();
|
|
43
|
+
expectTypeOf().toExtend();
|
|
44
|
+
});
|
|
45
|
+
test("the challenge fetchers take optional session and simd arguments", () => {
|
|
46
|
+
expectTypeOf().toEqualTypeOf();
|
|
47
|
+
expectTypeOf().toEqualTypeOf();
|
|
48
|
+
});
|
|
49
|
+
test("challenge responses all extend the shared ApiResponse", () => {
|
|
50
|
+
expectTypeOf().toExtend();
|
|
51
|
+
expectTypeOf().toExtend();
|
|
52
|
+
});
|
|
53
|
+
test("the image challenge returns the captcha body", () => {
|
|
54
|
+
expectTypeOf().toEqualTypeOf();
|
|
55
|
+
});
|
|
56
|
+
test("verification calls resolve to a verification response", () => {
|
|
57
|
+
expectTypeOf().toEqualTypeOf();
|
|
58
|
+
expectTypeOf().toEqualTypeOf();
|
|
59
|
+
expectTypeOf().toEqualTypeOf();
|
|
60
|
+
});
|
|
61
|
+
test("the in-flight dedupe map is private, not part of the contract", () => {
|
|
62
|
+
const client = new ProviderApi("url", "account");
|
|
63
|
+
client.inFlightChallenges;
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=api.test-d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.test-d.js","sourceRoot":"","sources":["../../src/tests/api.test-d.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type PoWChallengeId } from "@prosopo/types";
|
|
2
|
+
export interface RecordedRequest {
|
|
3
|
+
url: string;
|
|
4
|
+
init: RequestInit | undefined;
|
|
5
|
+
body: unknown;
|
|
6
|
+
headers: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface FetchStub {
|
|
9
|
+
requests: RecordedRequest[];
|
|
10
|
+
last: () => RecordedRequest;
|
|
11
|
+
respond: (body: unknown, init?: ResponseInit) => void;
|
|
12
|
+
respondOnce: (body: unknown, init?: ResponseInit) => void;
|
|
13
|
+
fail: (error: Error) => void;
|
|
14
|
+
defer: () => {
|
|
15
|
+
resolve: (body: unknown) => void;
|
|
16
|
+
reject: (e: Error) => void;
|
|
17
|
+
};
|
|
18
|
+
restore: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const stubFetch: (defaultBody?: unknown) => FetchStub;
|
|
21
|
+
export declare const BASE_URL = "https://provider.prosopo.io";
|
|
22
|
+
export declare const SITE_KEY = "5site000000000000000000000000000000000000000000000000";
|
|
23
|
+
export declare const USER = "5user000000000000000000000000000000000000000000000000";
|
|
24
|
+
export declare const CHALLENGE: PoWChallengeId;
|
|
25
|
+
//# sourceMappingURL=apiHarness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiHarness.d.ts","sourceRoot":"","sources":["../../src/tests/apiHarness.ts"],"names":[],"mappings":"AAcA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGpE,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IAEzB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAE5B,IAAI,EAAE,MAAM,eAAe,CAAC;IAE5B,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IAEtD,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IAE1D,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAE7B,KAAK,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;KAAE,CAAC;IAC9E,OAAO,EAAE,MAAM,IAAI,CAAC;CACpB;AAwBD,eAAO,MAAM,SAAS,iBACR,OAAO,KAClB,SAsEF,CAAC;AAEF,eAAO,MAAM,QAAQ,gCAAgC,CAAC;AACtD,eAAO,MAAM,QAAQ,0DAA0D,CAAC;AAChF,eAAO,MAAM,IAAI,0DAA0D,CAAC;AAG5E,eAAO,MAAM,SAAS,EAAE,cAAsG,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { POW_SEPARATOR } from "@prosopo/types";
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
const headersOf = (init) => {
|
|
4
|
+
const headers = init?.headers;
|
|
5
|
+
if (!headers)
|
|
6
|
+
return {};
|
|
7
|
+
if (headers instanceof Headers)
|
|
8
|
+
return Object.fromEntries(headers.entries());
|
|
9
|
+
if (Array.isArray(headers))
|
|
10
|
+
return Object.fromEntries(headers);
|
|
11
|
+
return { ...headers };
|
|
12
|
+
};
|
|
13
|
+
const parseBody = (init) => {
|
|
14
|
+
const body = init?.body;
|
|
15
|
+
if (typeof body !== "string")
|
|
16
|
+
return undefined;
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(body);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return body;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const stubFetch = (defaultBody = { status: "ok" }) => {
|
|
25
|
+
const requests = [];
|
|
26
|
+
const queue = [];
|
|
27
|
+
let fallback = () => Promise.resolve(new Response(JSON.stringify(defaultBody), {
|
|
28
|
+
status: 200,
|
|
29
|
+
headers: { "content-type": "application/json" },
|
|
30
|
+
}));
|
|
31
|
+
const original = globalThis.fetch;
|
|
32
|
+
const impl = (input, init) => {
|
|
33
|
+
requests.push({
|
|
34
|
+
url: String(input),
|
|
35
|
+
init,
|
|
36
|
+
body: parseBody(init),
|
|
37
|
+
headers: headersOf(init),
|
|
38
|
+
});
|
|
39
|
+
const next = queue.shift();
|
|
40
|
+
return (next ?? fallback)();
|
|
41
|
+
};
|
|
42
|
+
globalThis.fetch = vi.fn(impl);
|
|
43
|
+
const responseOf = (body, init) => {
|
|
44
|
+
return () => Promise.resolve(new Response(typeof body === "string" ? body : JSON.stringify(body), {
|
|
45
|
+
status: 200,
|
|
46
|
+
headers: { "content-type": "application/json" },
|
|
47
|
+
...init,
|
|
48
|
+
}));
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
requests,
|
|
52
|
+
last: () => {
|
|
53
|
+
const request = requests[requests.length - 1];
|
|
54
|
+
if (!request)
|
|
55
|
+
throw new Error("no request was made");
|
|
56
|
+
return request;
|
|
57
|
+
},
|
|
58
|
+
respond: (body, init) => {
|
|
59
|
+
fallback = responseOf(body, init);
|
|
60
|
+
},
|
|
61
|
+
respondOnce: (body, init) => {
|
|
62
|
+
queue.push(responseOf(body, init));
|
|
63
|
+
},
|
|
64
|
+
fail: (error) => {
|
|
65
|
+
fallback = () => Promise.reject(error);
|
|
66
|
+
},
|
|
67
|
+
defer: () => {
|
|
68
|
+
let settle = () => undefined;
|
|
69
|
+
const gate = new Promise((resolve) => {
|
|
70
|
+
settle = resolve;
|
|
71
|
+
});
|
|
72
|
+
queue.push(() => gate.then((outcome) => outcome()));
|
|
73
|
+
return {
|
|
74
|
+
resolve: (body) => settle(responseOf(body)),
|
|
75
|
+
reject: (e) => settle(() => Promise.reject(e)),
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
restore: () => {
|
|
79
|
+
globalThis.fetch = original;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export const BASE_URL = "https://provider.prosopo.io";
|
|
84
|
+
export const SITE_KEY = "5site000000000000000000000000000000000000000000000000";
|
|
85
|
+
export const USER = "5user000000000000000000000000000000000000000000000000";
|
|
86
|
+
export const CHALLENGE = `1753900000000${POW_SEPARATOR}${USER}${POW_SEPARATOR}${SITE_KEY}${POW_SEPARATOR}salt`;
|
|
87
|
+
//# sourceMappingURL=apiHarness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiHarness.js","sourceRoot":"","sources":["../../src/tests/apiHarness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpClientBase.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/httpClientBase.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import HttpClientBase from "../api/HttpClientBase.js";
|
|
3
|
+
import { HttpError } from "../api/HttpError.js";
|
|
4
|
+
import { ApiClient } from "../api/apiClient.js";
|
|
5
|
+
import { BASE_URL, stubFetch } from "./apiHarness.js";
|
|
6
|
+
class TestClient extends HttpClientBase {
|
|
7
|
+
get(input, init) {
|
|
8
|
+
return this.fetch(input, init);
|
|
9
|
+
}
|
|
10
|
+
send(input, body, init) {
|
|
11
|
+
return this.post(input, body, init);
|
|
12
|
+
}
|
|
13
|
+
sendWithHeaders(input, body, init) {
|
|
14
|
+
return this.postWithHeaders(input, body, init);
|
|
15
|
+
}
|
|
16
|
+
url() {
|
|
17
|
+
return this.baseURL;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
let fetchStub;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
fetchStub = stubFetch();
|
|
23
|
+
vi.spyOn(console, "error").mockImplementation(() => undefined);
|
|
24
|
+
});
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
fetchStub.restore();
|
|
27
|
+
vi.restoreAllMocks();
|
|
28
|
+
});
|
|
29
|
+
const client = (prefix) => prefix === undefined
|
|
30
|
+
? new TestClient(BASE_URL)
|
|
31
|
+
: new TestClient(BASE_URL, prefix);
|
|
32
|
+
const json = (body, status = 200) => ({
|
|
33
|
+
status,
|
|
34
|
+
headers: { "content-type": "application/json" },
|
|
35
|
+
statusText: status === 200 ? "OK" : "Error",
|
|
36
|
+
});
|
|
37
|
+
describe("the base URL", () => {
|
|
38
|
+
test("defaults to no prefix", () => {
|
|
39
|
+
expect(client().url()).toBe(BASE_URL);
|
|
40
|
+
});
|
|
41
|
+
test("appends the prefix, so paths stay relative to it", async () => {
|
|
42
|
+
const withPrefix = client("/v1");
|
|
43
|
+
expect(withPrefix.url()).toBe(`${BASE_URL}/v1`);
|
|
44
|
+
await withPrefix.get("/status");
|
|
45
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}/v1/status`);
|
|
46
|
+
});
|
|
47
|
+
test("an empty path still hits the base URL", async () => {
|
|
48
|
+
await client().get("");
|
|
49
|
+
expect(fetchStub.last().url).toBe(BASE_URL);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe("fetch", () => {
|
|
53
|
+
test("returns the parsed JSON body", async () => {
|
|
54
|
+
fetchStub.respond({ registered: true });
|
|
55
|
+
await expect(client().get("/status")).resolves.toEqual({
|
|
56
|
+
registered: true,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
test("passes the caller's init straight through", async () => {
|
|
60
|
+
await client().get("/status", { headers: { "X-Test": "1" } });
|
|
61
|
+
expect(fetchStub.last().headers).toEqual({ "X-Test": "1" });
|
|
62
|
+
});
|
|
63
|
+
test("throws an HttpError for a non-JSON failure", async () => {
|
|
64
|
+
fetchStub.respond("gateway down", {
|
|
65
|
+
status: 502,
|
|
66
|
+
statusText: "Bad Gateway",
|
|
67
|
+
headers: { "content-type": "text/plain" },
|
|
68
|
+
});
|
|
69
|
+
await expect(client().get("/status")).rejects.toBeInstanceOf(HttpError);
|
|
70
|
+
});
|
|
71
|
+
test("a JSON error body is handed back instead of thrown, so callers can read the error", async () => {
|
|
72
|
+
fetchStub.respond({ error: { message: "rate limited" } }, json({}, 429));
|
|
73
|
+
await expect(client().get("/status")).resolves.toEqual({
|
|
74
|
+
error: { message: "rate limited" },
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
test("a 400 is handed back even without a JSON content type", async () => {
|
|
78
|
+
fetchStub.respond('{"error":"bad request"}', {
|
|
79
|
+
status: 400,
|
|
80
|
+
headers: { "content-type": "text/plain" },
|
|
81
|
+
});
|
|
82
|
+
await expect(client().get("/status")).resolves.toEqual({
|
|
83
|
+
error: "bad request",
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
test("a response with no content type at all is treated as a failure", async () => {
|
|
87
|
+
fetchStub.respond("", { status: 500, headers: {} });
|
|
88
|
+
await expect(client().get("/status")).rejects.toBeInstanceOf(HttpError);
|
|
89
|
+
});
|
|
90
|
+
test("rejects with the network error when fetch itself fails", async () => {
|
|
91
|
+
const boom = new Error("network down");
|
|
92
|
+
fetchStub.fail(boom);
|
|
93
|
+
await expect(client().get("/status")).rejects.toBe(boom);
|
|
94
|
+
});
|
|
95
|
+
test("rejects when the body is not valid JSON", async () => {
|
|
96
|
+
fetchStub.respond("<html>not json</html>", json({}));
|
|
97
|
+
await expect(client().get("/status")).rejects.toBeInstanceOf(Error);
|
|
98
|
+
});
|
|
99
|
+
test("an empty 200 body is a parse failure, not a silent undefined", async () => {
|
|
100
|
+
fetchStub.respond("", json({}));
|
|
101
|
+
await expect(client().get("/status")).rejects.toBeInstanceOf(Error);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe("post", () => {
|
|
105
|
+
test("sends the body as JSON with the right method", async () => {
|
|
106
|
+
await client().send("/solve", { nonce: 1 });
|
|
107
|
+
const request = fetchStub.last();
|
|
108
|
+
expect(request.init?.method).toBe("POST");
|
|
109
|
+
expect(request.body).toEqual({ nonce: 1 });
|
|
110
|
+
expect(request.headers["Content-Type"]).toBe("application/json");
|
|
111
|
+
});
|
|
112
|
+
test("caller headers are merged on top of the content type", async () => {
|
|
113
|
+
await client().send("/solve", {}, { headers: { "Prosopo-Site-Key": "key" } });
|
|
114
|
+
expect(fetchStub.last().headers).toEqual({
|
|
115
|
+
"Content-Type": "application/json",
|
|
116
|
+
"Prosopo-Site-Key": "key",
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
test("a caller may override the content type", async () => {
|
|
120
|
+
await client().send("/solve", {}, { headers: { "Content-Type": "text/*" } });
|
|
121
|
+
expect(fetchStub.last().headers["Content-Type"]).toBe("text/*");
|
|
122
|
+
});
|
|
123
|
+
test("headers survive an init that also carries other options", async () => {
|
|
124
|
+
await client().send("/solve", {}, { keepalive: true, headers: { "X-A": "1" } });
|
|
125
|
+
const request = fetchStub.last();
|
|
126
|
+
expect(request.init?.keepalive).toBe(true);
|
|
127
|
+
expect(request.headers["Content-Type"]).toBe("application/json");
|
|
128
|
+
expect(request.headers["X-A"]).toBe("1");
|
|
129
|
+
});
|
|
130
|
+
test("an undefined body still produces a request", async () => {
|
|
131
|
+
await client().send("/solve", undefined);
|
|
132
|
+
expect(fetchStub.last().init?.body).toBeUndefined();
|
|
133
|
+
});
|
|
134
|
+
test("a zero-length array body is sent, not dropped", async () => {
|
|
135
|
+
await client().send("/events", []);
|
|
136
|
+
expect(fetchStub.last().init?.body).toBe("[]");
|
|
137
|
+
});
|
|
138
|
+
test("returns the parsed response", async () => {
|
|
139
|
+
fetchStub.respond({ verified: true });
|
|
140
|
+
await expect(client().send("/solve", {})).resolves.toEqual({
|
|
141
|
+
verified: true,
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
test("throws an HttpError for a non-JSON failure", async () => {
|
|
145
|
+
fetchStub.respond("nope", { status: 503, headers: {} });
|
|
146
|
+
await expect(client().send("/solve", {})).rejects.toBeInstanceOf(HttpError);
|
|
147
|
+
});
|
|
148
|
+
test("hands back a 400 JSON body", async () => {
|
|
149
|
+
fetchStub.respond({ error: "bad" }, json({}, 400));
|
|
150
|
+
await expect(client().send("/solve", {})).resolves.toEqual({
|
|
151
|
+
error: "bad",
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
test("rejects with the network error", async () => {
|
|
155
|
+
const boom = new Error("offline");
|
|
156
|
+
fetchStub.fail(boom);
|
|
157
|
+
await expect(client().send("/solve", {})).rejects.toBe(boom);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe("postWithHeaders", () => {
|
|
161
|
+
test("returns the body and the response headers together", async () => {
|
|
162
|
+
fetchStub.respond({ captchaType: "pow" }, {
|
|
163
|
+
status: 200,
|
|
164
|
+
headers: {
|
|
165
|
+
"content-type": "application/json",
|
|
166
|
+
"x-prosopo-meta": "encoded",
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
const { data, headers } = await client().sendWithHeaders("/frictionless", {});
|
|
170
|
+
expect(data).toEqual({ captchaType: "pow" });
|
|
171
|
+
expect(headers.get("x-prosopo-meta")).toBe("encoded");
|
|
172
|
+
});
|
|
173
|
+
test("sends JSON with the merged headers", async () => {
|
|
174
|
+
await client().sendWithHeaders("/frictionless", { token: "t" }, {
|
|
175
|
+
headers: { "Prosopo-User": "user" },
|
|
176
|
+
});
|
|
177
|
+
const request = fetchStub.last();
|
|
178
|
+
expect(request.init?.method).toBe("POST");
|
|
179
|
+
expect(request.body).toEqual({ token: "t" });
|
|
180
|
+
expect(request.headers).toEqual({
|
|
181
|
+
"Content-Type": "application/json",
|
|
182
|
+
"Prosopo-User": "user",
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
test("a missing meta header is absent rather than an error", async () => {
|
|
186
|
+
const { headers } = await client().sendWithHeaders("/frictionless", {});
|
|
187
|
+
expect(headers.get("x-prosopo-meta")).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
test("throws an HttpError for a non-JSON failure", async () => {
|
|
190
|
+
fetchStub.respond("nope", { status: 500, headers: {} });
|
|
191
|
+
await expect(client().sendWithHeaders("/frictionless", {})).rejects.toBeInstanceOf(HttpError);
|
|
192
|
+
});
|
|
193
|
+
test("hands back a 400 JSON body with its headers", async () => {
|
|
194
|
+
fetchStub.respond({ error: "bad" }, json({}, 400));
|
|
195
|
+
const { data } = await client().sendWithHeaders("/frictionless", {});
|
|
196
|
+
expect(data).toEqual({ error: "bad" });
|
|
197
|
+
});
|
|
198
|
+
test("rejects when the body cannot be parsed", async () => {
|
|
199
|
+
fetchStub.respond("not json", json({}));
|
|
200
|
+
await expect(client().sendWithHeaders("/frictionless", {})).rejects.toBeInstanceOf(Error);
|
|
201
|
+
});
|
|
202
|
+
test("rejects with the network error", async () => {
|
|
203
|
+
const boom = new Error("offline");
|
|
204
|
+
fetchStub.fail(boom);
|
|
205
|
+
await expect(client().sendWithHeaders("/frictionless", {})).rejects.toBe(boom);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe("HttpError", () => {
|
|
209
|
+
test("carries the status, text and URL a caller needs to triage", () => {
|
|
210
|
+
const error = new HttpError(429, "Too Many Requests", `${BASE_URL}/pow`);
|
|
211
|
+
expect(error.status).toBe(429);
|
|
212
|
+
expect(error.statusText).toBe("Too Many Requests");
|
|
213
|
+
expect(error.url).toBe(`${BASE_URL}/pow`);
|
|
214
|
+
expect(error.name).toBe("HttpError");
|
|
215
|
+
expect(error).toBeInstanceOf(Error);
|
|
216
|
+
expect(error.message).toBe(`HTTP error! status: 429 (Too Many Requests) for URL: ${BASE_URL}/pow`);
|
|
217
|
+
});
|
|
218
|
+
test("is distinguishable from any other error at a catch site", () => {
|
|
219
|
+
expect(new HttpError(500, "", "")).toBeInstanceOf(HttpError);
|
|
220
|
+
expect(new Error("plain")).not.toBeInstanceOf(HttpError);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe("ApiClient", () => {
|
|
224
|
+
test("keeps an explicit protocol", () => {
|
|
225
|
+
const api = new ApiClient("http://localhost:9229", "account");
|
|
226
|
+
expect(new TestClient("http://localhost:9229").url()).toBe("http://localhost:9229");
|
|
227
|
+
expect(api).toBeInstanceOf(HttpClientBase);
|
|
228
|
+
});
|
|
229
|
+
test("assumes HTTPS when the URL has no protocol", async () => {
|
|
230
|
+
class Probe extends ApiClient {
|
|
231
|
+
go() {
|
|
232
|
+
return this.fetch("/status");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
await new Probe("provider.prosopo.io", "account").go();
|
|
236
|
+
expect(fetchStub.last().url).toBe("https://provider.prosopo.io/status");
|
|
237
|
+
});
|
|
238
|
+
test("does not upgrade an https URL twice", async () => {
|
|
239
|
+
class Probe extends ApiClient {
|
|
240
|
+
go() {
|
|
241
|
+
return this.fetch("/status");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
await new Probe("https://provider.prosopo.io", "account").go();
|
|
245
|
+
expect(fetchStub.last().url).toBe("https://provider.prosopo.io/status");
|
|
246
|
+
});
|
|
247
|
+
test("an empty base URL becomes a relative https URL, not a crash", async () => {
|
|
248
|
+
class Probe extends ApiClient {
|
|
249
|
+
go() {
|
|
250
|
+
return this.fetch("/status");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
await new Probe("", "account").go();
|
|
254
|
+
expect(fetchStub.last().url).toBe("https:///status");
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
//# sourceMappingURL=httpClientBase.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpClientBase.unit.test.js","sourceRoot":"","sources":["../../src/tests/httpClientBase.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providerApi.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/providerApi.unit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import { AdminApiPaths, ApiParams, CaptchaType, ClientApiPaths, DecisionMachineKind, DecisionMachineLanguage, DecisionMachineRuntime, DecisionMachineScope, ModeEnum, PublicApiPaths, Tier, } from "@prosopo/types";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
|
+
import { HttpError } from "../api/HttpError.js";
|
|
4
|
+
import ProviderApi, { VERIFY_FORWARDED_HEADER } from "../api/ProviderApi.js";
|
|
5
|
+
import { BASE_URL, CHALLENGE, SITE_KEY, USER, stubFetch, } from "./apiHarness.js";
|
|
6
|
+
let fetchStub;
|
|
7
|
+
const api = () => new ProviderApi(BASE_URL, SITE_KEY);
|
|
8
|
+
const randomProvider = {
|
|
9
|
+
providerAccount: "5provider",
|
|
10
|
+
provider: {
|
|
11
|
+
url: BASE_URL,
|
|
12
|
+
datasetId: "0xdataset",
|
|
13
|
+
datasetIdContent: "0xcontent",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const powChallenge = {
|
|
17
|
+
status: "ok",
|
|
18
|
+
[ApiParams.challenge]: CHALLENGE,
|
|
19
|
+
[ApiParams.difficulty]: 4,
|
|
20
|
+
[ApiParams.timestamp]: "1753900000000",
|
|
21
|
+
[ApiParams.signature]: {
|
|
22
|
+
[ApiParams.provider]: { [ApiParams.challenge]: "0xproviderchallengesig" },
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const puzzleChallenge = {
|
|
26
|
+
status: "ok",
|
|
27
|
+
[ApiParams.challenge]: CHALLENGE,
|
|
28
|
+
[ApiParams.targetX]: 10,
|
|
29
|
+
[ApiParams.targetY]: 20,
|
|
30
|
+
[ApiParams.originX]: 1,
|
|
31
|
+
[ApiParams.originY]: 2,
|
|
32
|
+
[ApiParams.tolerance]: 5,
|
|
33
|
+
[ApiParams.timestamp]: "1753900000000",
|
|
34
|
+
[ApiParams.signature]: {
|
|
35
|
+
[ApiParams.provider]: { [ApiParams.challenge]: "0xproviderchallengesig" },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const clientMetaData = {
|
|
39
|
+
widgetHeight: 1,
|
|
40
|
+
widgetWidth: 2,
|
|
41
|
+
};
|
|
42
|
+
const body = () => fetchStub.last().body;
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
fetchStub = stubFetch();
|
|
45
|
+
vi.spyOn(console, "error").mockImplementation(() => undefined);
|
|
46
|
+
});
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
fetchStub.restore();
|
|
49
|
+
vi.restoreAllMocks();
|
|
50
|
+
});
|
|
51
|
+
describe("identifying headers", () => {
|
|
52
|
+
test("every client call names the site key, so the provider can scope it", async () => {
|
|
53
|
+
await api().getCaptchaChallenge(USER, randomProvider);
|
|
54
|
+
expect(fetchStub.last().headers["Prosopo-Site-Key"]).toBe(SITE_KEY);
|
|
55
|
+
expect(fetchStub.last().headers["Prosopo-User"]).toBe(USER);
|
|
56
|
+
});
|
|
57
|
+
test("calls with no user still carry the site key", async () => {
|
|
58
|
+
await api().submitUserEvents({ events: [] }, "s");
|
|
59
|
+
expect(fetchStub.last().headers["Prosopo-Site-Key"]).toBe(SITE_KEY);
|
|
60
|
+
expect(fetchStub.last().headers["Prosopo-User"]).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe("getCaptchaChallenge", () => {
|
|
64
|
+
test("posts the site key and user to the image challenge path", async () => {
|
|
65
|
+
await api().getCaptchaChallenge(USER, randomProvider);
|
|
66
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.GetImageCaptchaChallenge}`);
|
|
67
|
+
expect(body()).toEqual({
|
|
68
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
69
|
+
[ApiParams.user]: USER,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
test("omits the optional fields when they are absent", async () => {
|
|
73
|
+
await api().getCaptchaChallenge(USER, randomProvider, undefined, undefined);
|
|
74
|
+
expect(body()[ApiParams.sessionId]).toBeUndefined();
|
|
75
|
+
expect(body()[ApiParams.simdReadings]).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
test("includes the session id and simd readings when given", async () => {
|
|
78
|
+
await api().getCaptchaChallenge(USER, randomProvider, "session", "readings");
|
|
79
|
+
expect(body()[ApiParams.sessionId]).toBe("session");
|
|
80
|
+
expect(body()[ApiParams.simdReadings]).toBe("readings");
|
|
81
|
+
});
|
|
82
|
+
test("an empty session id is treated as absent", async () => {
|
|
83
|
+
await api().getCaptchaChallenge(USER, randomProvider, "", "");
|
|
84
|
+
expect(body()[ApiParams.sessionId]).toBeUndefined();
|
|
85
|
+
expect(body()[ApiParams.simdReadings]).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
test("returns the provider's body", async () => {
|
|
88
|
+
fetchStub.respond({ captchas: [] });
|
|
89
|
+
await expect(api().getCaptchaChallenge(USER, randomProvider)).resolves.toEqual({ captchas: [] });
|
|
90
|
+
});
|
|
91
|
+
test("propagates a transport failure", async () => {
|
|
92
|
+
fetchStub.fail(new Error("offline"));
|
|
93
|
+
await expect(api().getCaptchaChallenge(USER, randomProvider)).rejects.toThrow("offline");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe("in-flight de-duplication of challenge fetches", () => {
|
|
97
|
+
test("a second call with the same session id joins the first request", async () => {
|
|
98
|
+
const deferred = fetchStub.defer();
|
|
99
|
+
const client = api();
|
|
100
|
+
const first = client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
101
|
+
const second = client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
102
|
+
expect(fetchStub.requests).toHaveLength(1);
|
|
103
|
+
deferred.resolve(powChallenge);
|
|
104
|
+
expect(await first).toEqual(await second);
|
|
105
|
+
});
|
|
106
|
+
test("different session ids are separate requests", async () => {
|
|
107
|
+
const client = api();
|
|
108
|
+
await Promise.all([
|
|
109
|
+
client.getPowCaptchaChallenge(USER, SITE_KEY, "a"),
|
|
110
|
+
client.getPowCaptchaChallenge(USER, SITE_KEY, "b"),
|
|
111
|
+
]);
|
|
112
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
113
|
+
});
|
|
114
|
+
test("the same session id on a different path is a separate request", async () => {
|
|
115
|
+
const client = api();
|
|
116
|
+
await Promise.all([
|
|
117
|
+
client.getPowCaptchaChallenge(USER, SITE_KEY, "session"),
|
|
118
|
+
client.getPuzzleCaptchaChallenge(USER, SITE_KEY, "session"),
|
|
119
|
+
]);
|
|
120
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
121
|
+
});
|
|
122
|
+
test("calls without a session id are never deduped", async () => {
|
|
123
|
+
const client = api();
|
|
124
|
+
await Promise.all([
|
|
125
|
+
client.getPowCaptchaChallenge(USER, SITE_KEY),
|
|
126
|
+
client.getPowCaptchaChallenge(USER, SITE_KEY),
|
|
127
|
+
]);
|
|
128
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
129
|
+
});
|
|
130
|
+
test("a retry after the first call settles starts a fresh request", async () => {
|
|
131
|
+
const client = api();
|
|
132
|
+
await client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
133
|
+
await client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
134
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
135
|
+
});
|
|
136
|
+
test("a failed call is dropped from the in-flight map, so a retry can proceed", async () => {
|
|
137
|
+
const client = api();
|
|
138
|
+
fetchStub.fail(new Error("offline"));
|
|
139
|
+
await expect(client.getPowCaptchaChallenge(USER, SITE_KEY, "session")).rejects.toThrow("offline");
|
|
140
|
+
fetchStub.respond(powChallenge);
|
|
141
|
+
await expect(client.getPowCaptchaChallenge(USER, SITE_KEY, "session")).resolves.toEqual(powChallenge);
|
|
142
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
143
|
+
});
|
|
144
|
+
test("both joined callers see the same failure", async () => {
|
|
145
|
+
const deferred = fetchStub.defer();
|
|
146
|
+
const client = api();
|
|
147
|
+
const first = client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
148
|
+
const second = client.getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
149
|
+
deferred.reject(new Error("offline"));
|
|
150
|
+
await expect(first).rejects.toThrow("offline");
|
|
151
|
+
await expect(second).rejects.toThrow("offline");
|
|
152
|
+
});
|
|
153
|
+
test("two clients do not share an in-flight map", async () => {
|
|
154
|
+
const first = api().getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
155
|
+
const second = api().getPowCaptchaChallenge(USER, SITE_KEY, "session");
|
|
156
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
157
|
+
await Promise.all([first, second]);
|
|
158
|
+
});
|
|
159
|
+
test("image challenges dedupe on their own path too", async () => {
|
|
160
|
+
fetchStub.defer();
|
|
161
|
+
const client = api();
|
|
162
|
+
void client.getCaptchaChallenge(USER, randomProvider, "session");
|
|
163
|
+
void client.getCaptchaChallenge(USER, randomProvider, "session");
|
|
164
|
+
expect(fetchStub.requests).toHaveLength(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("submitCaptchaSolution", () => {
|
|
168
|
+
const submit = (behavioralData, simdReadings, meta) => api().submitCaptchaSolution([], "0xrequesthash", USER, "1753900000000", "0xproviderhashsig", "0xusertimestampsig", behavioralData, simdReadings, meta);
|
|
169
|
+
test("posts the solution with both signatures", async () => {
|
|
170
|
+
await submit();
|
|
171
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.SubmitImageCaptchaSolution}`);
|
|
172
|
+
expect(body()).toEqual({
|
|
173
|
+
[ApiParams.user]: USER,
|
|
174
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
175
|
+
[ApiParams.captchas]: [],
|
|
176
|
+
[ApiParams.requestHash]: "0xrequesthash",
|
|
177
|
+
[ApiParams.timestamp]: "1753900000000",
|
|
178
|
+
[ApiParams.signature]: {
|
|
179
|
+
[ApiParams.user]: { [ApiParams.timestamp]: "0xusertimestampsig" },
|
|
180
|
+
[ApiParams.provider]: { [ApiParams.requestHash]: "0xproviderhashsig" },
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
test("an empty solution list is still submitted, not short-circuited", async () => {
|
|
185
|
+
await submit();
|
|
186
|
+
expect(body()[ApiParams.captchas]).toEqual([]);
|
|
187
|
+
});
|
|
188
|
+
test("attaches the optional telemetry when present", async () => {
|
|
189
|
+
await submit("behaviour", "readings", clientMetaData);
|
|
190
|
+
expect(body()[ApiParams.behavioralData]).toBe("behaviour");
|
|
191
|
+
expect(body()[ApiParams.simdReadings]).toBe("readings");
|
|
192
|
+
expect(body()[ApiParams.clientMetaData]).toEqual(clientMetaData);
|
|
193
|
+
});
|
|
194
|
+
test("empty telemetry strings are omitted rather than sent blank", async () => {
|
|
195
|
+
await submit("", "");
|
|
196
|
+
expect(ApiParams.behavioralData in body()).toBe(false);
|
|
197
|
+
expect(ApiParams.simdReadings in body()).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe("verifyDappUser", () => {
|
|
201
|
+
test("posts the token, signature and ip", async () => {
|
|
202
|
+
await api().verifyDappUser("token", "0xsig", USER, undefined, "1.2.3.4");
|
|
203
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.VerifyImageCaptchaSolutionDapp}`);
|
|
204
|
+
expect(body()).toEqual({
|
|
205
|
+
[ApiParams.token]: "token",
|
|
206
|
+
[ApiParams.dappSignature]: "0xsig",
|
|
207
|
+
[ApiParams.ip]: "1.2.3.4",
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
test("includes maxVerifiedTime and email when given", async () => {
|
|
211
|
+
await api().verifyDappUser("token", "0xsig", USER, 60_000, "1.2.3.4", "user@example.com");
|
|
212
|
+
expect(body()[ApiParams.maxVerifiedTime]).toBe(60_000);
|
|
213
|
+
expect(body()[ApiParams.email]).toBe("user@example.com");
|
|
214
|
+
});
|
|
215
|
+
test("a zero maxVerifiedTime is dropped, so the provider applies its default", async () => {
|
|
216
|
+
await api().verifyDappUser("token", "0xsig", USER, 0);
|
|
217
|
+
expect(ApiParams.maxVerifiedTime in body()).toBe(false);
|
|
218
|
+
});
|
|
219
|
+
test("an omitted ip is sent as undefined rather than a placeholder", async () => {
|
|
220
|
+
await api().verifyDappUser("token", "0xsig", USER);
|
|
221
|
+
expect(ApiParams.ip in body()).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
describe("pow challenge and solution", () => {
|
|
225
|
+
test("requests a challenge for the user and site key", async () => {
|
|
226
|
+
await api().getPowCaptchaChallenge(USER, SITE_KEY);
|
|
227
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.GetPowCaptchaChallenge}`);
|
|
228
|
+
expect(body()).toEqual({
|
|
229
|
+
[ApiParams.user]: USER,
|
|
230
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
test("submits the nonce with the provider's challenge signature", async () => {
|
|
234
|
+
await api().submitPowCaptchaSolution(powChallenge, USER, SITE_KEY, 42, "0xusertimestampsig");
|
|
235
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.SubmitPowCaptchaSolution}`);
|
|
236
|
+
expect(body()).toMatchObject({
|
|
237
|
+
[ApiParams.challenge]: CHALLENGE,
|
|
238
|
+
[ApiParams.difficulty]: 4,
|
|
239
|
+
[ApiParams.nonce]: 42,
|
|
240
|
+
[ApiParams.user]: USER,
|
|
241
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
242
|
+
[ApiParams.signature]: {
|
|
243
|
+
[ApiParams.provider]: {
|
|
244
|
+
[ApiParams.challenge]: "0xproviderchallengesig",
|
|
245
|
+
},
|
|
246
|
+
[ApiParams.user]: { [ApiParams.timestamp]: "0xusertimestampsig" },
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
test("passes simd readings on the challenge request when present", async () => {
|
|
251
|
+
await api().getPowCaptchaChallenge(USER, SITE_KEY, undefined, "readings");
|
|
252
|
+
expect(body()[ApiParams.simdReadings]).toBe("readings");
|
|
253
|
+
});
|
|
254
|
+
test("a nonce of zero is submitted, not treated as missing", async () => {
|
|
255
|
+
await api().submitPowCaptchaSolution(powChallenge, USER, SITE_KEY, 0, "s");
|
|
256
|
+
expect(body()[ApiParams.nonce]).toBe(0);
|
|
257
|
+
});
|
|
258
|
+
test("attaches the optional proof fields when present", async () => {
|
|
259
|
+
await api().submitPowCaptchaSolution(powChallenge, USER, SITE_KEY, 1, "s", "behaviour", "salt", "readings", clientMetaData, "proof");
|
|
260
|
+
expect(body()).toMatchObject({
|
|
261
|
+
[ApiParams.behavioralData]: "behaviour",
|
|
262
|
+
[ApiParams.salt]: "salt",
|
|
263
|
+
[ApiParams.simdReadings]: "readings",
|
|
264
|
+
[ApiParams.fingerprintProof]: "proof",
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
test("the schema strips anything it does not declare", async () => {
|
|
268
|
+
await api().submitPowCaptchaSolution(powChallenge, USER, SITE_KEY, 1, "s");
|
|
269
|
+
expect(ApiParams.timestamp in body()).toBe(false);
|
|
270
|
+
});
|
|
271
|
+
test("a malformed challenge is rejected before any request is made", async () => {
|
|
272
|
+
const bad = {
|
|
273
|
+
...powChallenge,
|
|
274
|
+
[ApiParams.challenge]: "not-a-challenge",
|
|
275
|
+
};
|
|
276
|
+
expect(() => api().submitPowCaptchaSolution(bad, USER, SITE_KEY, 1, "s")).toThrow();
|
|
277
|
+
expect(fetchStub.requests).toHaveLength(0);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
describe("puzzle challenge and solution", () => {
|
|
281
|
+
test("requests a puzzle challenge", async () => {
|
|
282
|
+
await api().getPuzzleCaptchaChallenge(USER, SITE_KEY, "session", "readings");
|
|
283
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.GetPuzzleCaptchaChallenge}`);
|
|
284
|
+
expect(body()).toEqual({
|
|
285
|
+
[ApiParams.user]: USER,
|
|
286
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
287
|
+
[ApiParams.sessionId]: "session",
|
|
288
|
+
[ApiParams.simdReadings]: "readings",
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
test("submits the final position and the drag trail", async () => {
|
|
292
|
+
await api().submitPuzzleCaptchaSolution(puzzleChallenge, USER, SITE_KEY, 11, 22, [{ x: 1, y: 2, t: 3 }], "0xusertimestampsig");
|
|
293
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.SubmitPuzzleCaptchaSolution}`);
|
|
294
|
+
expect(body()).toMatchObject({
|
|
295
|
+
[ApiParams.finalX]: 11,
|
|
296
|
+
[ApiParams.finalY]: 22,
|
|
297
|
+
[ApiParams.puzzleEvents]: [{ x: 1, y: 2, t: 3 }],
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
test("an empty event trail is submitted, and the provider decides", async () => {
|
|
301
|
+
await api().submitPuzzleCaptchaSolution(puzzleChallenge, USER, SITE_KEY, 0, 0, [], "s");
|
|
302
|
+
expect(body()[ApiParams.puzzleEvents]).toEqual([]);
|
|
303
|
+
});
|
|
304
|
+
test("attaches the optional puzzle telemetry when present", async () => {
|
|
305
|
+
await api().submitPuzzleCaptchaSolution(puzzleChallenge, USER, SITE_KEY, 1, 2, [], "s", "behaviour", "salt", "readings", clientMetaData);
|
|
306
|
+
expect(body()).toMatchObject({
|
|
307
|
+
[ApiParams.behavioralData]: "behaviour",
|
|
308
|
+
[ApiParams.salt]: "salt",
|
|
309
|
+
[ApiParams.simdReadings]: "readings",
|
|
310
|
+
});
|
|
311
|
+
expect(body()[ApiParams.clientMetaData]).toBeDefined();
|
|
312
|
+
});
|
|
313
|
+
test("verifies a puzzle token, with the email only when supplied", async () => {
|
|
314
|
+
await api().submitPuzzleCaptchaVerify("token", "0xsig", USER, "1.2.3.4");
|
|
315
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.VerifyPuzzleCaptchaSolution}`);
|
|
316
|
+
expect(ApiParams.email in body()).toBe(false);
|
|
317
|
+
await api().submitPuzzleCaptchaVerify("token", "0xsig", USER, "1.2.3.4", "user@example.com");
|
|
318
|
+
expect(body()[ApiParams.email]).toBe("user@example.com");
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
describe("getFrictionlessCaptcha", () => {
|
|
322
|
+
const frictionlessBody = { status: "ok", [ApiParams.captchaType]: "pow" };
|
|
323
|
+
test("posts the token and head hash", async () => {
|
|
324
|
+
fetchStub.respond(frictionlessBody);
|
|
325
|
+
await api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER);
|
|
326
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.GetFrictionlessCaptchaChallenge}`);
|
|
327
|
+
expect(body()).toEqual({
|
|
328
|
+
[ApiParams.token]: "token",
|
|
329
|
+
[ApiParams.headHash]: "0xhead",
|
|
330
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
331
|
+
[ApiParams.user]: USER,
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
test("includes the optional context when supplied", async () => {
|
|
335
|
+
fetchStub.respond(frictionlessBody);
|
|
336
|
+
await api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER, ModeEnum.invisible, "readings", "https://site.example/page", "https://iframe.example");
|
|
337
|
+
expect(body()).toMatchObject({
|
|
338
|
+
[ApiParams.mode]: ModeEnum.invisible,
|
|
339
|
+
[ApiParams.simdReadings]: "readings",
|
|
340
|
+
[ApiParams.currentUrl]: "https://site.example/page",
|
|
341
|
+
[ApiParams.iframeUrl]: "https://iframe.example",
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
test("moves the honeypot from the meta header onto the response", async () => {
|
|
345
|
+
fetchStub.respond(frictionlessBody, {
|
|
346
|
+
status: 200,
|
|
347
|
+
headers: {
|
|
348
|
+
"content-type": "application/json",
|
|
349
|
+
"x-prosopo-meta": "encoded-honeypot",
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
const response = await api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER);
|
|
353
|
+
expect(response[ApiParams.hp]).toBe("encoded-honeypot");
|
|
354
|
+
});
|
|
355
|
+
test("leaves the body untouched when there is no meta header", async () => {
|
|
356
|
+
fetchStub.respond(frictionlessBody);
|
|
357
|
+
const response = await api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER);
|
|
358
|
+
expect(ApiParams.hp in response).toBe(false);
|
|
359
|
+
});
|
|
360
|
+
test("an empty meta header is treated as absent", async () => {
|
|
361
|
+
fetchStub.respond(frictionlessBody, {
|
|
362
|
+
status: 200,
|
|
363
|
+
headers: { "content-type": "application/json", "x-prosopo-meta": "" },
|
|
364
|
+
});
|
|
365
|
+
const response = await api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER);
|
|
366
|
+
expect(response[ApiParams.hp]).toBeUndefined();
|
|
367
|
+
});
|
|
368
|
+
test("is not deduped: a frictionless call always reaches the provider", async () => {
|
|
369
|
+
const client = api();
|
|
370
|
+
fetchStub.respond(frictionlessBody);
|
|
371
|
+
await Promise.all([
|
|
372
|
+
client.getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER),
|
|
373
|
+
client.getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER),
|
|
374
|
+
]);
|
|
375
|
+
expect(fetchStub.requests).toHaveLength(2);
|
|
376
|
+
});
|
|
377
|
+
test("propagates a transport failure", async () => {
|
|
378
|
+
fetchStub.respond("nope", { status: 500, headers: {} });
|
|
379
|
+
await expect(api().getFrictionlessCaptcha("token", "0xhead", SITE_KEY, USER)).rejects.toBeInstanceOf(HttpError);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
describe("status and details", () => {
|
|
383
|
+
test("reads the provider status", async () => {
|
|
384
|
+
fetchStub.respond({ status: "ok" });
|
|
385
|
+
await api().getProviderStatus();
|
|
386
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.GetProviderStatus}`);
|
|
387
|
+
expect(fetchStub.last().init?.method).toBeUndefined();
|
|
388
|
+
});
|
|
389
|
+
test("reads the public provider details", async () => {
|
|
390
|
+
await api().getProviderDetails();
|
|
391
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${PublicApiPaths.GetProviderDetails}`);
|
|
392
|
+
});
|
|
393
|
+
test("submits user events", async () => {
|
|
394
|
+
const events = { events: [] };
|
|
395
|
+
await api().submitUserEvents(events, "0xstring");
|
|
396
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.SubmitUserEvents}`);
|
|
397
|
+
expect(body()).toEqual({ events, string: "0xstring" });
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
describe("forwardVerify", () => {
|
|
401
|
+
test("marks the request as forwarded so the receiver does not forward again", async () => {
|
|
402
|
+
await api().forwardVerify(ClientApiPaths.VerifyPowCaptchaSolution, { [ApiParams.token]: "token" }, USER);
|
|
403
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.VerifyPowCaptchaSolution}`);
|
|
404
|
+
expect(fetchStub.last().headers[VERIFY_FORWARDED_HEADER]).toBe("true");
|
|
405
|
+
});
|
|
406
|
+
test("the marker header is lowercase, to match express's normalised keys", () => {
|
|
407
|
+
expect(VERIFY_FORWARDED_HEADER).toBe(VERIFY_FORWARDED_HEADER.toLowerCase());
|
|
408
|
+
});
|
|
409
|
+
test("forwards the body verbatim", async () => {
|
|
410
|
+
const forwarded = { [ApiParams.token]: "token", extra: "kept" };
|
|
411
|
+
await api().forwardVerify(ClientApiPaths.VerifyImageCaptchaSolutionDapp, forwarded, USER);
|
|
412
|
+
expect(body()).toEqual(forwarded);
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
describe("submitPowCaptchaVerify", () => {
|
|
416
|
+
test("posts the token and signature", async () => {
|
|
417
|
+
await api().submitPowCaptchaVerify("token", "0xsig", USER, "1.2.3.4");
|
|
418
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${ClientApiPaths.VerifyPowCaptchaSolution}`);
|
|
419
|
+
expect(body()).toEqual({
|
|
420
|
+
[ApiParams.token]: "token",
|
|
421
|
+
[ApiParams.dappSignature]: "0xsig",
|
|
422
|
+
[ApiParams.ip]: "1.2.3.4",
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
test("adds the email only when one is supplied", async () => {
|
|
426
|
+
await api().submitPowCaptchaVerify("token", "0xsig", USER);
|
|
427
|
+
expect(ApiParams.email in body()).toBe(false);
|
|
428
|
+
await api().submitPowCaptchaVerify("token", "0xsig", USER, undefined, "user@example.com");
|
|
429
|
+
expect(body()[ApiParams.email]).toBe("user@example.com");
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
describe("the admin endpoints", () => {
|
|
433
|
+
const JWT = "jwt-token";
|
|
434
|
+
const settings = {
|
|
435
|
+
captchaType: CaptchaType.pow,
|
|
436
|
+
domains: ["example.com"],
|
|
437
|
+
frictionlessThreshold: 0.5,
|
|
438
|
+
powDifficulty: 4,
|
|
439
|
+
};
|
|
440
|
+
const auth = () => fetchStub.last().headers;
|
|
441
|
+
test("every admin call is bearer-authorised and site-key scoped", async () => {
|
|
442
|
+
await api().registerSiteKey(SITE_KEY, Tier.Free, settings, JWT);
|
|
443
|
+
expect(auth().Authorization).toBe(`Bearer ${JWT}`);
|
|
444
|
+
expect(auth()["Prosopo-Site-Key"]).toBe(SITE_KEY);
|
|
445
|
+
});
|
|
446
|
+
test("registers one site key", async () => {
|
|
447
|
+
await api().registerSiteKey(SITE_KEY, Tier.Free, settings, JWT);
|
|
448
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.SiteKeyRegister}`);
|
|
449
|
+
expect(body()).toEqual({ siteKey: SITE_KEY, tier: Tier.Free, settings });
|
|
450
|
+
});
|
|
451
|
+
test("registers a batch of site keys verbatim", async () => {
|
|
452
|
+
const batch = [{ siteKey: SITE_KEY, tier: Tier.Free, settings }];
|
|
453
|
+
await api().registerSiteKeys(batch, JWT);
|
|
454
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.SiteKeysRegister}`);
|
|
455
|
+
expect(body()).toEqual(batch);
|
|
456
|
+
});
|
|
457
|
+
test("removes one site key", async () => {
|
|
458
|
+
await api().removeSiteKey(SITE_KEY, JWT);
|
|
459
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.SiteKeyRemove}`);
|
|
460
|
+
expect(body()).toEqual({ siteKey: SITE_KEY });
|
|
461
|
+
});
|
|
462
|
+
test("removes a batch of site keys", async () => {
|
|
463
|
+
await api().removeSiteKeys([{ siteKey: SITE_KEY }], JWT);
|
|
464
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.SiteKeysRemove}`);
|
|
465
|
+
expect(body()).toEqual([{ siteKey: SITE_KEY }]);
|
|
466
|
+
});
|
|
467
|
+
test("an invalid removal batch never leaves the client", async () => {
|
|
468
|
+
expect(() => api().removeSiteKeys([{ siteKey: 1 }], JWT)).toThrow();
|
|
469
|
+
expect(fetchStub.requests).toHaveLength(0);
|
|
470
|
+
});
|
|
471
|
+
test("updates the detector key", async () => {
|
|
472
|
+
await api().updateDetectorKey("0xdetector", JWT);
|
|
473
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.UpdateDetectorKey}`);
|
|
474
|
+
expect(body()).toEqual({ detectorKey: "0xdetector" });
|
|
475
|
+
});
|
|
476
|
+
test("removes a detector key, with an optional expiry", async () => {
|
|
477
|
+
await api().removeDetectorKey("0xdetector", JWT);
|
|
478
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.RemoveDetectorKey}`);
|
|
479
|
+
expect(body()).toMatchObject({ detectorKey: "0xdetector" });
|
|
480
|
+
await api().removeDetectorKey("0xdetector", JWT, 60);
|
|
481
|
+
expect(body()).toMatchObject({ expirationInSeconds: 60 });
|
|
482
|
+
});
|
|
483
|
+
test("updates a decision machine with its full descriptor", async () => {
|
|
484
|
+
await api().updateDecisionMachine(DecisionMachineScope.Dapp, DecisionMachineRuntime.Node, "export default () => true", JWT, SITE_KEY, DecisionMachineLanguage.JavaScript, "machine", "1.0.0", CaptchaType.pow, DecisionMachineKind.Decision);
|
|
485
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.UpdateDecisionMachine}`);
|
|
486
|
+
expect(body()).toMatchObject({
|
|
487
|
+
[ApiParams.decisionMachineScope]: DecisionMachineScope.Dapp,
|
|
488
|
+
[ApiParams.decisionMachineRuntime]: DecisionMachineRuntime.Node,
|
|
489
|
+
[ApiParams.decisionMachineSource]: "export default () => true",
|
|
490
|
+
[ApiParams.dapp]: SITE_KEY,
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
test("reads all decision machines with an empty body", async () => {
|
|
494
|
+
await api().getAllDecisionMachines(JWT);
|
|
495
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.GetAllDecisionMachines}`);
|
|
496
|
+
expect(body()).toEqual({});
|
|
497
|
+
});
|
|
498
|
+
test("reads one decision machine by id", async () => {
|
|
499
|
+
await api().getDecisionMachine("machine-id", JWT);
|
|
500
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.GetDecisionMachine}`);
|
|
501
|
+
expect(body()).toEqual({ id: "machine-id" });
|
|
502
|
+
});
|
|
503
|
+
test("removes one decision machine by id", async () => {
|
|
504
|
+
await api().removeDecisionMachine("machine-id", JWT);
|
|
505
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.RemoveDecisionMachine}`);
|
|
506
|
+
expect(body()).toEqual({ id: "machine-id" });
|
|
507
|
+
});
|
|
508
|
+
test("removes all decision machines", async () => {
|
|
509
|
+
await api().removeAllDecisionMachines(JWT);
|
|
510
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.RemoveAllDecisionMachines}`);
|
|
511
|
+
expect(body()).toEqual({});
|
|
512
|
+
});
|
|
513
|
+
test("clears counters, optionally for a single site key", async () => {
|
|
514
|
+
await api().clearAllCounters(JWT);
|
|
515
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.ClearAllCounters}`);
|
|
516
|
+
await api().clearAllCounters(JWT, SITE_KEY);
|
|
517
|
+
expect(body()).toMatchObject({ [ApiParams.dapp]: SITE_KEY });
|
|
518
|
+
});
|
|
519
|
+
test("toggles maintenance mode with a signed timestamp instead of a JWT", async () => {
|
|
520
|
+
await api().toggleMaintenanceMode(true, "1753900000000", "0xsig");
|
|
521
|
+
expect(fetchStub.last().url).toBe(`${BASE_URL}${AdminApiPaths.ToggleMaintenanceMode}`);
|
|
522
|
+
expect(body()).toEqual({ enabled: true });
|
|
523
|
+
expect(fetchStub.last().headers.timestamp).toBe("1753900000000");
|
|
524
|
+
expect(fetchStub.last().headers.signature).toBe("0xsig");
|
|
525
|
+
expect(fetchStub.last().headers.Authorization).toBeUndefined();
|
|
526
|
+
});
|
|
527
|
+
test("disabling maintenance mode is sent as false, not omitted", async () => {
|
|
528
|
+
await api().toggleMaintenanceMode(false, "1753900000000", "0xsig");
|
|
529
|
+
expect(body()).toEqual({ enabled: false });
|
|
530
|
+
});
|
|
531
|
+
test("an admin failure surfaces as an HttpError", async () => {
|
|
532
|
+
fetchStub.respond("forbidden", { status: 403, headers: {} });
|
|
533
|
+
await expect(api().getAllDecisionMachines(JWT)).rejects.toBeInstanceOf(HttpError);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
//# sourceMappingURL=providerApi.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providerApi.unit.test.js","sourceRoot":"","sources":["../../src/tests/providerApi.unit.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/api",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.21",
|
|
4
4
|
"description": "Wrapper for the provider API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
"build:cross-env": "vite build --config vite.esm.config.ts",
|
|
23
23
|
"build:tsc": "tsc --build --verbose",
|
|
24
24
|
"build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
|
|
25
|
-
"typecheck": "tsc --project tsconfig.types.json"
|
|
25
|
+
"typecheck": "tsc --project tsconfig.types.json",
|
|
26
|
+
"test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts",
|
|
27
|
+
"test:watch": "NODE_ENV=${NODE_ENV:-test}; npx vitest watch --config ./vite.test.config.ts",
|
|
28
|
+
"test:coverage": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --coverage --config ./vite.test.config.ts"
|
|
26
29
|
},
|
|
27
30
|
"repository": {
|
|
28
31
|
"type": "git",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import { ViteTestConfig } from "@prosopo/config";
|
|
16
|
+
|
|
17
|
+
process.env.NODE_ENV = "test";
|
|
18
|
+
|
|
19
|
+
export default ViteTestConfig();
|