@t-0/provider-sdk 1.1.29 → 1.1.30
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 +22 -5
- package/lib/cjs/client/client.d.ts +4 -14
- package/lib/cjs/client/client.js +2 -38
- package/lib/cjs/client/signer.d.ts +1 -3
- package/lib/cjs/client/signer.js +7 -34
- package/lib/cjs/common/client/client.d.ts +14 -0
- package/lib/cjs/common/client/client.js +42 -0
- package/lib/cjs/common/client/signer.d.ts +3 -0
- package/lib/cjs/common/client/signer.js +36 -0
- package/lib/cjs/common/crypto/hash.d.ts +2 -0
- package/lib/cjs/common/crypto/hash.js +17 -0
- package/lib/cjs/common/crypto/index.d.ts +5 -0
- package/lib/cjs/common/crypto/index.js +14 -0
- package/lib/cjs/common/crypto/keys.d.ts +2 -0
- package/lib/cjs/common/crypto/keys.js +23 -0
- package/lib/cjs/common/crypto/request.d.ts +20 -0
- package/lib/cjs/common/crypto/request.js +51 -0
- package/lib/cjs/common/crypto/verify.d.ts +1 -0
- package/lib/cjs/common/crypto/verify.js +19 -0
- package/lib/cjs/common/health.d.ts +21 -0
- package/lib/cjs/common/health.js +45 -0
- package/lib/cjs/common/health_pb.d.ts +157 -0
- package/lib/cjs/common/health_pb.js +90 -0
- package/lib/cjs/common/node.d.ts +3 -0
- package/lib/cjs/common/node.js +15 -0
- package/lib/cjs/common/service.d.ts +37 -0
- package/lib/cjs/common/service.js +85 -0
- package/lib/cjs/common/validate.d.ts +25 -0
- package/lib/cjs/common/validate.js +42 -0
- package/lib/cjs/common/validation.d.ts +26 -0
- package/lib/cjs/common/validation.js +57 -0
- package/lib/cjs/crypto/hash.d.ts +1 -2
- package/lib/cjs/crypto/hash.js +15 -15
- package/lib/cjs/crypto/index.d.ts +1 -5
- package/lib/cjs/crypto/index.js +15 -12
- package/lib/cjs/crypto/keys.d.ts +1 -2
- package/lib/cjs/crypto/keys.js +15 -17
- package/lib/cjs/crypto/request.d.ts +1 -20
- package/lib/cjs/crypto/request.js +15 -47
- package/lib/cjs/crypto/verify.d.ts +1 -1
- package/lib/cjs/crypto/verify.js +15 -17
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/service/health.d.ts +4 -21
- package/lib/cjs/service/health.js +5 -41
- package/lib/cjs/service/health_pb.d.ts +1 -157
- package/lib/cjs/service/health_pb.js +15 -88
- package/lib/cjs/service/node.d.ts +1 -3
- package/lib/cjs/service/node.js +15 -13
- package/lib/cjs/service/service.d.ts +6 -20
- package/lib/cjs/service/service.js +5 -84
- package/lib/cjs/service/validate.d.ts +1 -25
- package/lib/cjs/service/validate.js +15 -40
- package/lib/cjs/service/validate_response.d.ts +9 -18
- package/lib/cjs/service/validate_response.js +19 -57
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/client/client.d.ts +3 -13
- package/lib/esm/client/client.js +2 -35
- package/lib/esm/client/signer.d.ts +1 -3
- package/lib/esm/client/signer.js +1 -32
- package/lib/esm/common/client/client.d.ts +14 -0
- package/lib/esm/common/client/client.js +36 -0
- package/lib/esm/common/client/signer.d.ts +3 -0
- package/lib/esm/common/client/signer.js +32 -0
- package/lib/esm/common/crypto/hash.d.ts +2 -0
- package/lib/esm/common/crypto/hash.js +13 -0
- package/lib/esm/common/crypto/index.d.ts +5 -0
- package/lib/esm/common/crypto/index.js +4 -0
- package/lib/esm/common/crypto/keys.d.ts +2 -0
- package/lib/esm/common/crypto/keys.js +19 -0
- package/lib/esm/common/crypto/request.d.ts +20 -0
- package/lib/esm/common/crypto/request.js +47 -0
- package/lib/esm/common/crypto/verify.d.ts +1 -0
- package/lib/esm/common/crypto/verify.js +16 -0
- package/lib/esm/common/health.d.ts +21 -0
- package/lib/esm/common/health.js +41 -0
- package/lib/esm/common/health_pb.d.ts +157 -0
- package/lib/esm/common/health_pb.js +87 -0
- package/lib/esm/common/node.d.ts +3 -0
- package/lib/esm/common/node.js +11 -0
- package/lib/esm/common/service.d.ts +37 -0
- package/lib/esm/common/service.js +78 -0
- package/lib/esm/common/validate.d.ts +25 -0
- package/lib/esm/common/validate.js +38 -0
- package/lib/esm/common/validation.d.ts +26 -0
- package/lib/esm/common/validation.js +54 -0
- package/lib/esm/crypto/hash.d.ts +1 -2
- package/lib/esm/crypto/hash.js +1 -13
- package/lib/esm/crypto/index.d.ts +1 -5
- package/lib/esm/crypto/index.js +1 -4
- package/lib/esm/crypto/keys.d.ts +1 -2
- package/lib/esm/crypto/keys.js +1 -15
- package/lib/esm/crypto/request.d.ts +1 -20
- package/lib/esm/crypto/request.js +1 -45
- package/lib/esm/crypto/verify.d.ts +1 -1
- package/lib/esm/crypto/verify.js +1 -16
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/service/health.d.ts +4 -21
- package/lib/esm/service/health.js +3 -41
- package/lib/esm/service/health_pb.d.ts +1 -157
- package/lib/esm/service/health_pb.js +1 -87
- package/lib/esm/service/node.d.ts +1 -3
- package/lib/esm/service/node.js +1 -11
- package/lib/esm/service/service.d.ts +6 -20
- package/lib/esm/service/service.js +4 -81
- package/lib/esm/service/validate.d.ts +1 -25
- package/lib/esm/service/validate.js +1 -38
- package/lib/esm/service/validate_response.d.ts +9 -18
- package/lib/esm/service/validate_response.js +15 -54
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1,88 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.createService = exports.REQUEST_VALIDITY_MILLIS = void 0;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const health_js_1 = require("./health.js");
|
|
13
|
-
exports.REQUEST_VALIDITY_MILLIS = 60000;
|
|
14
|
-
const createSignatureVerification = (networkPublicKey) => (next) => async (req) => {
|
|
15
|
-
const ts = decodeNum(getHeader(req, headers_js_1.default.SignatureTimestamp));
|
|
16
|
-
if (Date.now() - ts > 60000) {
|
|
17
|
-
throw new connect_1.ConnectError(`${headers_js_1.default.SignatureTimestamp} must be within ${exports.REQUEST_VALIDITY_MILLIS} milliseconds from now`, connect_1.Code.InvalidArgument);
|
|
18
|
-
}
|
|
19
|
-
const publicKey = decodeHex(getHeader(req, headers_js_1.default.PublicKey));
|
|
20
|
-
if (networkPublicKey.compare(publicKey) !== 0) {
|
|
21
|
-
throw new connect_1.ConnectError(`${headers_js_1.default.PublicKey} value is not network public key`, connect_1.Code.Unauthenticated);
|
|
22
|
-
}
|
|
23
|
-
const signature = decodeHex(getHeader(req, headers_js_1.default.Signature));
|
|
24
|
-
const hasher = req.contextValues.get(kHash);
|
|
25
|
-
const tsBuf = Buffer.alloc(8);
|
|
26
|
-
tsBuf.writeBigUInt64LE(BigInt(ts)); // 64‑bit little‑endian timestamp
|
|
27
|
-
const digest = hasher
|
|
28
|
-
.update(tsBuf)
|
|
29
|
-
.digest();
|
|
30
|
-
if (!(0, verify_js_1.verifySignature)(publicKey, digest, signature)) {
|
|
31
|
-
throw new connect_1.ConnectError(`${headers_js_1.default.Signature} has invalid signature`, connect_1.Code.Unauthenticated);
|
|
32
|
-
}
|
|
33
|
-
return await next(req);
|
|
34
|
-
};
|
|
35
|
-
const createService = (networkPublicKey, registerRoutes, options) => {
|
|
36
|
-
if (typeof networkPublicKey == "string") {
|
|
37
|
-
networkPublicKey = decodeHex(networkPublicKey);
|
|
38
|
-
}
|
|
39
|
-
return {
|
|
40
|
-
routes: (router) => {
|
|
41
|
-
const collected = [];
|
|
42
|
-
const origService = router.service.bind(router);
|
|
43
|
-
const wrappedRouter = {
|
|
44
|
-
service: (desc, impl) => {
|
|
45
|
-
collected.push(desc.typeName);
|
|
46
|
-
origService(desc, impl);
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
registerRoutes(wrappedRouter);
|
|
50
|
-
// Health is the only service this transport mounts on its own — see
|
|
51
|
-
// docs/HEALTH_SERVICE.md. Same interceptors as everything else, so the
|
|
52
|
-
// probe is signed like any other call.
|
|
53
|
-
collected.push(health_pb_js_1.Health.typeName);
|
|
54
|
-
origService(health_pb_js_1.Health, (0, health_js_1.createHealthServiceImpl)(collected));
|
|
55
|
-
},
|
|
56
|
-
interceptors: [createSignatureVerification(networkPublicKey), (0, validate_response_js_1.createValidationInterceptor)(options?.logger)],
|
|
57
|
-
grpcWeb: false,
|
|
58
|
-
contextValues: (req) => {
|
|
59
|
-
return (0, connect_1.createContextValues)().set(kHash, req.hasher);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
};
|
|
4
|
+
const service_js_1 = require("../common/service.js");
|
|
5
|
+
const version_js_1 = require("../version.js");
|
|
6
|
+
var service_js_2 = require("../common/service.js");
|
|
7
|
+
Object.defineProperty(exports, "REQUEST_VALIDITY_MILLIS", { enumerable: true, get: function () { return service_js_2.REQUEST_VALIDITY_MILLIS; } });
|
|
8
|
+
const createService = (networkPublicKey, registerRoutes, options) => (0, service_js_1.createService)(networkPublicKey, registerRoutes, { ...options, version: options?.version ?? version_js_1.SDK_VERSION });
|
|
63
9
|
exports.createService = createService;
|
|
64
|
-
const kHash = (0, connect_1.createContextKey)(undefined);
|
|
65
|
-
function getHeader(req, header) {
|
|
66
|
-
const raw = req.header.get(header);
|
|
67
|
-
if (!raw) {
|
|
68
|
-
throw new connect_1.ConnectError(`missing required header '${header}'`, connect_1.Code.InvalidArgument);
|
|
69
|
-
}
|
|
70
|
-
return raw;
|
|
71
|
-
}
|
|
72
|
-
function decodeHex(value) {
|
|
73
|
-
value = value.startsWith('0x') ? value.slice(2) : value;
|
|
74
|
-
try {
|
|
75
|
-
return Buffer.from(value, "hex");
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
throw new connect_1.ConnectError(`invalid header format. '${value}' must be hex encoded`, connect_1.Code.InvalidArgument);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function decodeNum(value) {
|
|
82
|
-
try {
|
|
83
|
-
return parseInt(value);
|
|
84
|
-
}
|
|
85
|
-
catch (e) {
|
|
86
|
-
throw new connect_1.ConnectError(`invalid header format. '${value}' must be a number`, connect_1.Code.InvalidArgument);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,25 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Shared protovalidate validator instance for the public {@link validate} helper.
|
|
4
|
-
* Construction is cheap, but reusing one instance avoids repeated compilation
|
|
5
|
-
* of the same rules.
|
|
6
|
-
*/
|
|
7
|
-
export declare const validator: import("@bufbuild/protovalidate").Validator;
|
|
8
|
-
/**
|
|
9
|
-
* Validates a response message against its buf.validate proto annotations.
|
|
10
|
-
*
|
|
11
|
-
* On success, returns the message unchanged (typed). On failure, throws a
|
|
12
|
-
* {@link ConnectError} with {@link Code.Internal} and a message matching the
|
|
13
|
-
* shape emitted by the SDK's response-validation interceptor — so propagating
|
|
14
|
-
* the error from a handler produces the same wire response as not calling
|
|
15
|
-
* `validate` at all.
|
|
16
|
-
*
|
|
17
|
-
* Intended use:
|
|
18
|
-
* ```ts
|
|
19
|
-
* return validate(PayOutResponseSchema, { result: { case: "accepted", value: {} } });
|
|
20
|
-
* ```
|
|
21
|
-
*
|
|
22
|
-
* Catch the error to convert it into a domain-level failure (e.g. the `Failed`
|
|
23
|
-
* arm of a `oneof result`) instead of an opaque `Code.Internal`.
|
|
24
|
-
*/
|
|
25
|
-
export declare function validate<Desc extends DescMessage>(schema: Desc, msg: MessageShape<Desc>): MessageShape<Desc>;
|
|
1
|
+
export * from "../common/validate.js";
|
|
@@ -1,42 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Shared protovalidate validator instance for the public {@link validate} helper.
|
|
9
|
-
* Construction is cheap, but reusing one instance avoids repeated compilation
|
|
10
|
-
* of the same rules.
|
|
11
|
-
*/
|
|
12
|
-
exports.validator = (0, protovalidate_1.createValidator)();
|
|
13
|
-
/**
|
|
14
|
-
* Validates a response message against its buf.validate proto annotations.
|
|
15
|
-
*
|
|
16
|
-
* On success, returns the message unchanged (typed). On failure, throws a
|
|
17
|
-
* {@link ConnectError} with {@link Code.Internal} and a message matching the
|
|
18
|
-
* shape emitted by the SDK's response-validation interceptor — so propagating
|
|
19
|
-
* the error from a handler produces the same wire response as not calling
|
|
20
|
-
* `validate` at all.
|
|
21
|
-
*
|
|
22
|
-
* Intended use:
|
|
23
|
-
* ```ts
|
|
24
|
-
* return validate(PayOutResponseSchema, { result: { case: "accepted", value: {} } });
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* Catch the error to convert it into a domain-level failure (e.g. the `Failed`
|
|
28
|
-
* arm of a `oneof result`) instead of an opaque `Code.Internal`.
|
|
29
|
-
*/
|
|
30
|
-
function validate(schema, msg) {
|
|
31
|
-
const result = exports.validator.validate(schema, msg);
|
|
32
|
-
if (result.kind === "invalid") {
|
|
33
|
-
const details = result.violations
|
|
34
|
-
.map((v) => `${v.field?.toString() ?? ""}: ${v.message}`)
|
|
35
|
-
.join("; ");
|
|
36
|
-
throw new connect_1.ConnectError(`response validation failed: ${details}`, connect_1.Code.Internal);
|
|
37
|
-
}
|
|
38
|
-
if (result.kind === "error") {
|
|
39
|
-
throw new connect_1.ConnectError(`response validation error: ${result.error.message}`, connect_1.Code.Internal);
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
40
7
|
}
|
|
41
|
-
|
|
42
|
-
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("../common/validate.js"), exports);
|
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
import type { Interceptor } from "@connectrpc/connect";
|
|
2
|
+
import type { Logger } from "../common/validation.js";
|
|
3
|
+
import { createValidationInterceptor } from "../common/validation.js";
|
|
4
|
+
export { createValidationInterceptor, type Logger, type ValidationInterceptorOptions } from "../common/validation.js";
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* { error: (msg, fields) => pinoInstance.error(fields, msg) }
|
|
6
|
+
* Registry covering the t-0 network provider contract protos. Leaf file
|
|
7
|
+
* descriptors pull in their full dependency graph, so adding new messages
|
|
8
|
+
* or fields to existing protos requires only `buf:generate`.
|
|
7
9
|
*/
|
|
8
|
-
export
|
|
9
|
-
error(msg: string, fields?: Record<string, unknown>): void;
|
|
10
|
-
}
|
|
10
|
+
export declare const networkRegistry: import("@bufbuild/protobuf").Registry;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* buf.validate proto annotations before they are serialized and sent.
|
|
14
|
-
* Also validates incoming requests using the official @connectrpc/validate interceptor.
|
|
15
|
-
*
|
|
16
|
-
* Invalid requests return Code.InvalidArgument; invalid responses return Code.Internal.
|
|
17
|
-
*
|
|
18
|
-
* On invalid responses, a single structured `error`-level line is emitted to
|
|
19
|
-
* the supplied {@link Logger} (default: `console.error` with JSON-encoded
|
|
20
|
-
* fields) before the `Code.Internal` error is thrown. This is the safety net
|
|
21
|
-
* for handler code paths that skipped the public `validate()` helper.
|
|
12
|
+
* Validation interceptor pre-configured for the t-0 network provider contract.
|
|
22
13
|
*/
|
|
23
|
-
export declare function
|
|
14
|
+
export declare function createNetworkValidationInterceptor(logger?: Logger): Interceptor;
|
|
24
15
|
/**
|
|
25
16
|
* @deprecated Use createValidationInterceptor instead.
|
|
26
17
|
*/
|
|
@@ -1,65 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createResponseValidation = void 0;
|
|
4
|
-
exports.
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line no-console
|
|
13
|
-
console.error(JSON.stringify({ msg, ...(fields ?? {}) })),
|
|
14
|
-
};
|
|
3
|
+
exports.createResponseValidation = exports.networkRegistry = exports.createValidationInterceptor = void 0;
|
|
4
|
+
exports.createNetworkValidationInterceptor = createNetworkValidationInterceptor;
|
|
5
|
+
const protobuf_1 = require("@bufbuild/protobuf");
|
|
6
|
+
const provider_pb_js_1 = require("../common/gen/tzero/v1/payment/provider_pb.js");
|
|
7
|
+
const network_pb_js_1 = require("../common/gen/tzero/v1/payment/network_pb.js");
|
|
8
|
+
const validation_js_1 = require("../common/validation.js");
|
|
9
|
+
// Re-export everything from the common layer for backward compatibility.
|
|
10
|
+
var validation_js_2 = require("../common/validation.js");
|
|
11
|
+
Object.defineProperty(exports, "createValidationInterceptor", { enumerable: true, get: function () { return validation_js_2.createValidationInterceptor; } });
|
|
15
12
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* Invalid requests return Code.InvalidArgument; invalid responses return Code.Internal.
|
|
21
|
-
*
|
|
22
|
-
* On invalid responses, a single structured `error`-level line is emitted to
|
|
23
|
-
* the supplied {@link Logger} (default: `console.error` with JSON-encoded
|
|
24
|
-
* fields) before the `Code.Internal` error is thrown. This is the safety net
|
|
25
|
-
* for handler code paths that skipped the public `validate()` helper.
|
|
13
|
+
* Registry covering the t-0 network provider contract protos. Leaf file
|
|
14
|
+
* descriptors pull in their full dependency graph, so adding new messages
|
|
15
|
+
* or fields to existing protos requires only `buf:generate`.
|
|
26
16
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const schema = req.method.output;
|
|
34
|
-
const msg = resp.message;
|
|
35
|
-
const result = validator.validate(schema, msg);
|
|
36
|
-
if (result.kind === "invalid") {
|
|
37
|
-
const violations = result.violations.map((v) => ({
|
|
38
|
-
field: v.field?.toString() ?? "",
|
|
39
|
-
message: v.message,
|
|
40
|
-
}));
|
|
41
|
-
const details = violations.map((v) => `${v.field}: ${v.message}`).join("; ");
|
|
42
|
-
logger.error("response validation failed", {
|
|
43
|
-
rpc_method: `${req.service.typeName}/${req.method.name}`,
|
|
44
|
-
response_type: schema.typeName,
|
|
45
|
-
violations,
|
|
46
|
-
sdk_version: version_js_1.SDK_VERSION,
|
|
47
|
-
});
|
|
48
|
-
throw new connect_1.ConnectError(`response validation failed: ${details}`, connect_1.Code.Internal);
|
|
49
|
-
}
|
|
50
|
-
if (result.kind === "error") {
|
|
51
|
-
logger.error("response validation error", {
|
|
52
|
-
rpc_method: `${req.service.typeName}/${req.method.name}`,
|
|
53
|
-
response_type: schema.typeName,
|
|
54
|
-
error: result.error.message,
|
|
55
|
-
sdk_version: version_js_1.SDK_VERSION,
|
|
56
|
-
});
|
|
57
|
-
throw new connect_1.ConnectError(`response validation error: ${result.error.message}`, connect_1.Code.Internal);
|
|
58
|
-
}
|
|
59
|
-
return resp;
|
|
60
|
-
};
|
|
17
|
+
exports.networkRegistry = (0, protobuf_1.createRegistry)(provider_pb_js_1.file_tzero_v1_payment_provider, network_pb_js_1.file_tzero_v1_payment_network);
|
|
18
|
+
/**
|
|
19
|
+
* Validation interceptor pre-configured for the t-0 network provider contract.
|
|
20
|
+
*/
|
|
21
|
+
function createNetworkValidationInterceptor(logger) {
|
|
22
|
+
return (0, validation_js_1.createValidationInterceptor)({ logger, registry: exports.networkRegistry });
|
|
61
23
|
}
|
|
62
24
|
/**
|
|
63
25
|
* @deprecated Use createValidationInterceptor instead.
|
|
64
26
|
*/
|
|
65
|
-
exports.createResponseValidation = createValidationInterceptor;
|
|
27
|
+
exports.createResponseValidation = validation_js_1.createValidationInterceptor;
|
package/lib/cjs/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "1.1.
|
|
1
|
+
export declare const SDK_VERSION = "1.1.30";
|
package/lib/cjs/version.js
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Signature } from "../common/client/client.js";
|
|
2
|
+
import type { DescService } from "@bufbuild/protobuf";
|
|
2
3
|
export declare const DEFAULT_ENDPOINT = "https://api.t-0.network";
|
|
3
4
|
export declare function createClient<T extends DescService>(signer: string | Buffer | ((data: Buffer) => Promise<Signature>) | Buffer<ArrayBufferLike>, endpoint: string | undefined, svc: T): import("@connectrpc/connect").Client<T>;
|
|
4
|
-
|
|
5
|
-
* Signature with metadata for particular request
|
|
6
|
-
*/
|
|
7
|
-
export interface Signature {
|
|
8
|
-
signature: Buffer;
|
|
9
|
-
publicKey: Buffer;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Signature function for signing requests to T-0 API. Accepts any data in string format and return signature
|
|
13
|
-
* with metadata
|
|
14
|
-
*/
|
|
15
|
-
export type SignerFunction = (data: Buffer) => Promise<Signature>;
|
|
5
|
+
export type { Signature, SignerFunction } from "../common/client/client.js";
|
|
16
6
|
export default createClient;
|
package/lib/esm/client/client.js
CHANGED
|
@@ -1,39 +1,6 @@
|
|
|
1
|
-
import { createClient as
|
|
2
|
-
import { createConnectTransport } from "@connectrpc/connect-web";
|
|
3
|
-
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
4
|
-
import CreateSigner from "./signer.js";
|
|
5
|
-
import NetworkHeaders from "../common/headers.js";
|
|
1
|
+
import { createClient as createClientCommon } from "../common/client/client.js";
|
|
6
2
|
export const DEFAULT_ENDPOINT = "https://api.t-0.network";
|
|
7
3
|
export function createClient(signer, endpoint, svc) {
|
|
8
|
-
|
|
9
|
-
endpoint = endpoint || DEFAULT_ENDPOINT;
|
|
10
|
-
if (typeof signer === "string" || Buffer.isBuffer(signer)) {
|
|
11
|
-
signer = CreateSigner(signer);
|
|
12
|
-
}
|
|
13
|
-
customFetch = async (r, init) => {
|
|
14
|
-
if (!init?.body || !((init.body) instanceof Uint8Array)) {
|
|
15
|
-
throw "unsupported body type";
|
|
16
|
-
}
|
|
17
|
-
const ts = Date.now();
|
|
18
|
-
// 64‑bit little‑endian timestamp
|
|
19
|
-
const tsBuf = Buffer.alloc(8);
|
|
20
|
-
tsBuf.writeBigUInt64LE(BigInt(ts));
|
|
21
|
-
const hash = keccak_256.create()
|
|
22
|
-
.update(init.body)
|
|
23
|
-
.update(tsBuf);
|
|
24
|
-
const hashHex = Buffer.from(hash.digest());
|
|
25
|
-
const sig = await signer(hashHex);
|
|
26
|
-
const headers = new Headers(init?.headers);
|
|
27
|
-
headers.append(NetworkHeaders.Signature, "0x" + sig.signature.toString('hex'));
|
|
28
|
-
headers.append(NetworkHeaders.PublicKey, "0x" + sig.publicKey.toString('hex'));
|
|
29
|
-
headers.append(NetworkHeaders.SignatureTimestamp, ts.toString());
|
|
30
|
-
const modifiedInit = { ...init, headers };
|
|
31
|
-
return fetch(r, modifiedInit);
|
|
32
|
-
};
|
|
33
|
-
const transport = createConnectTransport({
|
|
34
|
-
baseUrl: endpoint || DEFAULT_ENDPOINT,
|
|
35
|
-
fetch: customFetch,
|
|
36
|
-
});
|
|
37
|
-
return createConnectClient(svc, transport);
|
|
4
|
+
return createClientCommon(signer, endpoint || DEFAULT_ENDPOINT, svc);
|
|
38
5
|
}
|
|
39
6
|
export default createClient;
|
package/lib/esm/client/signer.js
CHANGED
|
@@ -1,32 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export const CreateSigner = (privateKey) => {
|
|
3
|
-
privateKey = parsePrivateKey(privateKey);
|
|
4
|
-
const publicKey = Buffer.from(secp256k1.getPublicKey(privateKey, false));
|
|
5
|
-
return async (data) => {
|
|
6
|
-
// Ensure hash is 32 bytes
|
|
7
|
-
if (data.length !== 32) {
|
|
8
|
-
throw new Error('Message hash must be 32 bytes');
|
|
9
|
-
}
|
|
10
|
-
// Sign the hash
|
|
11
|
-
const signature = secp256k1.sign(data, privateKey, { prehash: false });
|
|
12
|
-
return {
|
|
13
|
-
signature: Buffer.from(signature),
|
|
14
|
-
publicKey: publicKey,
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
const parsePrivateKey = (privateKey) => {
|
|
19
|
-
if (typeof privateKey == 'string') {
|
|
20
|
-
privateKey = privateKey.replace(/^0x/, '');
|
|
21
|
-
if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
|
|
22
|
-
throw new Error('Private key must be 64 hex characters');
|
|
23
|
-
}
|
|
24
|
-
privateKey = Buffer.from(privateKey, 'hex');
|
|
25
|
-
}
|
|
26
|
-
// Validate private key
|
|
27
|
-
if (!secp256k1.utils.isValidSecretKey(privateKey)) {
|
|
28
|
-
throw new Error('Invalid private key');
|
|
29
|
-
}
|
|
30
|
-
return privateKey;
|
|
31
|
-
};
|
|
32
|
-
export default CreateSigner;
|
|
1
|
+
export { CreateSigner, default } from "../common/client/signer.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DescService } from "@bufbuild/protobuf";
|
|
2
|
+
export declare function createClient<T extends DescService>(signer: string | Buffer | ((data: Buffer) => Promise<Signature>) | Buffer<ArrayBufferLike>, endpoint: string, svc: T): import("@connectrpc/connect").Client<T>;
|
|
3
|
+
/**
|
|
4
|
+
* Signature with metadata for particular request
|
|
5
|
+
*/
|
|
6
|
+
export interface Signature {
|
|
7
|
+
signature: Buffer;
|
|
8
|
+
publicKey: Buffer;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Signature function for signing requests to T-0 API. Accepts any data in string format and return signature
|
|
12
|
+
* with metadata
|
|
13
|
+
*/
|
|
14
|
+
export type SignerFunction = (data: Buffer) => Promise<Signature>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createClient as createConnectClient } from "@connectrpc/connect";
|
|
2
|
+
import { createConnectTransport } from "@connectrpc/connect-web";
|
|
3
|
+
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
4
|
+
import CreateSigner from "./signer.js";
|
|
5
|
+
import NetworkHeaders from "../headers.js";
|
|
6
|
+
export function createClient(signer, endpoint, svc) {
|
|
7
|
+
let customFetch;
|
|
8
|
+
if (typeof signer === "string" || Buffer.isBuffer(signer)) {
|
|
9
|
+
signer = CreateSigner(signer);
|
|
10
|
+
}
|
|
11
|
+
customFetch = async (r, init) => {
|
|
12
|
+
if (!init?.body || !((init.body) instanceof Uint8Array)) {
|
|
13
|
+
throw "unsupported body type";
|
|
14
|
+
}
|
|
15
|
+
const ts = Date.now();
|
|
16
|
+
// 64‑bit little‑endian timestamp
|
|
17
|
+
const tsBuf = Buffer.alloc(8);
|
|
18
|
+
tsBuf.writeBigUInt64LE(BigInt(ts));
|
|
19
|
+
const hash = keccak_256.create()
|
|
20
|
+
.update(init.body)
|
|
21
|
+
.update(tsBuf);
|
|
22
|
+
const hashHex = Buffer.from(hash.digest());
|
|
23
|
+
const sig = await signer(hashHex);
|
|
24
|
+
const headers = new Headers(init?.headers);
|
|
25
|
+
headers.append(NetworkHeaders.Signature, "0x" + sig.signature.toString('hex'));
|
|
26
|
+
headers.append(NetworkHeaders.PublicKey, "0x" + sig.publicKey.toString('hex'));
|
|
27
|
+
headers.append(NetworkHeaders.SignatureTimestamp, ts.toString());
|
|
28
|
+
const modifiedInit = { ...init, headers };
|
|
29
|
+
return fetch(r, modifiedInit);
|
|
30
|
+
};
|
|
31
|
+
const transport = createConnectTransport({
|
|
32
|
+
baseUrl: endpoint,
|
|
33
|
+
fetch: customFetch,
|
|
34
|
+
});
|
|
35
|
+
return createConnectClient(svc, transport);
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
2
|
+
export const CreateSigner = (privateKey) => {
|
|
3
|
+
privateKey = parsePrivateKey(privateKey);
|
|
4
|
+
const publicKey = Buffer.from(secp256k1.getPublicKey(privateKey, false));
|
|
5
|
+
return async (data) => {
|
|
6
|
+
// Ensure hash is 32 bytes
|
|
7
|
+
if (data.length !== 32) {
|
|
8
|
+
throw new Error('Message hash must be 32 bytes');
|
|
9
|
+
}
|
|
10
|
+
// Sign the hash
|
|
11
|
+
const signature = secp256k1.sign(data, privateKey, { prehash: false });
|
|
12
|
+
return {
|
|
13
|
+
signature: Buffer.from(signature),
|
|
14
|
+
publicKey: publicKey,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const parsePrivateKey = (privateKey) => {
|
|
19
|
+
if (typeof privateKey == 'string') {
|
|
20
|
+
privateKey = privateKey.replace(/^0x/, '');
|
|
21
|
+
if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
|
|
22
|
+
throw new Error('Private key must be 64 hex characters');
|
|
23
|
+
}
|
|
24
|
+
privateKey = Buffer.from(privateKey, 'hex');
|
|
25
|
+
}
|
|
26
|
+
// Validate private key
|
|
27
|
+
if (!secp256k1.utils.isValidSecretKey(privateKey)) {
|
|
28
|
+
throw new Error('Invalid private key');
|
|
29
|
+
}
|
|
30
|
+
return privateKey;
|
|
31
|
+
};
|
|
32
|
+
export default CreateSigner;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
2
|
+
export function keccak256(...inputs) {
|
|
3
|
+
const h = keccak_256.create();
|
|
4
|
+
for (const input of inputs) {
|
|
5
|
+
h.update(input);
|
|
6
|
+
}
|
|
7
|
+
return Buffer.from(h.digest());
|
|
8
|
+
}
|
|
9
|
+
export function computeDigest(body, timestampMs) {
|
|
10
|
+
const tsBuf = Buffer.alloc(8);
|
|
11
|
+
tsBuf.writeBigUInt64LE(BigInt(timestampMs));
|
|
12
|
+
return keccak256(body, tsBuf);
|
|
13
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { verifySignature } from './verify.js';
|
|
2
|
+
export { keccak256, computeDigest } from './hash.js';
|
|
3
|
+
export { parsePublicKey, publicKeysEqual } from './keys.js';
|
|
4
|
+
export { createRequestVerifier, DEFAULT_TOLERANCE_MS } from './request.js';
|
|
5
|
+
export type { CreateVerifierOptions, VerifyRequest, VerifyRequestResult, VerifyRequestFailure, RequestVerifier } from './request.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function parsePublicKey(key) {
|
|
2
|
+
if (typeof key === 'string') {
|
|
3
|
+
const hex = key.startsWith('0x') ? key.slice(2) : key;
|
|
4
|
+
if (!/^[0-9a-fA-F]*$/.test(hex) || hex.length % 2 !== 0) {
|
|
5
|
+
throw new Error('Public key contains invalid hex characters');
|
|
6
|
+
}
|
|
7
|
+
key = Buffer.from(hex, 'hex');
|
|
8
|
+
}
|
|
9
|
+
if (key.length !== 65 || key[0] !== 0x04) {
|
|
10
|
+
throw new Error('Public key must be 65 bytes in uncompressed format (0x04 prefix)');
|
|
11
|
+
}
|
|
12
|
+
return Buffer.from(key);
|
|
13
|
+
}
|
|
14
|
+
export function publicKeysEqual(a, b) {
|
|
15
|
+
if (a.length !== b.length) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return Buffer.from(a).compare(Buffer.from(b)) === 0;
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const DEFAULT_TOLERANCE_MS = 60000;
|
|
2
|
+
export interface CreateVerifierOptions {
|
|
3
|
+
networkPublicKey: string | Buffer;
|
|
4
|
+
toleranceMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface VerifyRequest {
|
|
7
|
+
body: Uint8Array | ArrayBufferView | ArrayBufferLike;
|
|
8
|
+
signatureHeader: string;
|
|
9
|
+
publicKeyHeader: string;
|
|
10
|
+
timestampHeader: string;
|
|
11
|
+
}
|
|
12
|
+
export type VerifyRequestFailure = 'invalid_timestamp' | 'timestamp_out_of_range' | 'invalid_public_key' | 'unknown_public_key' | 'invalid_signature_format' | 'signature_failed';
|
|
13
|
+
export type VerifyRequestResult = {
|
|
14
|
+
valid: true;
|
|
15
|
+
} | {
|
|
16
|
+
valid: false;
|
|
17
|
+
reason: VerifyRequestFailure;
|
|
18
|
+
};
|
|
19
|
+
export type RequestVerifier = (req: VerifyRequest) => VerifyRequestResult;
|
|
20
|
+
export declare function createRequestVerifier(opts: CreateVerifierOptions): RequestVerifier;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { verifySignature } from './verify.js';
|
|
2
|
+
import { computeDigest } from './hash.js';
|
|
3
|
+
import { parsePublicKey, publicKeysEqual } from './keys.js';
|
|
4
|
+
export const DEFAULT_TOLERANCE_MS = 60000;
|
|
5
|
+
export function createRequestVerifier(opts) {
|
|
6
|
+
const networkKey = parsePublicKey(opts.networkPublicKey);
|
|
7
|
+
const tolerance = opts.toleranceMs ?? DEFAULT_TOLERANCE_MS;
|
|
8
|
+
return (req) => {
|
|
9
|
+
const ts = parseInt(req.timestampHeader, 10);
|
|
10
|
+
if (!Number.isFinite(ts) || ts < 0) {
|
|
11
|
+
return { valid: false, reason: 'invalid_timestamp' };
|
|
12
|
+
}
|
|
13
|
+
if (Math.abs(Date.now() - ts) > tolerance) {
|
|
14
|
+
return { valid: false, reason: 'timestamp_out_of_range' };
|
|
15
|
+
}
|
|
16
|
+
let publicKey;
|
|
17
|
+
try {
|
|
18
|
+
publicKey = parsePublicKey(req.publicKeyHeader);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return { valid: false, reason: 'invalid_public_key' };
|
|
22
|
+
}
|
|
23
|
+
if (!publicKeysEqual(publicKey, networkKey)) {
|
|
24
|
+
return { valid: false, reason: 'unknown_public_key' };
|
|
25
|
+
}
|
|
26
|
+
const sigHex = req.signatureHeader.startsWith('0x')
|
|
27
|
+
? req.signatureHeader.slice(2)
|
|
28
|
+
: req.signatureHeader;
|
|
29
|
+
if (!/^[0-9a-fA-F]*$/.test(sigHex) || sigHex.length % 2 !== 0) {
|
|
30
|
+
return { valid: false, reason: 'invalid_signature_format' };
|
|
31
|
+
}
|
|
32
|
+
const signature = Buffer.from(sigHex, 'hex');
|
|
33
|
+
if (signature.length !== 64 && signature.length !== 65) {
|
|
34
|
+
return { valid: false, reason: 'invalid_signature_format' };
|
|
35
|
+
}
|
|
36
|
+
const body = req.body instanceof Uint8Array
|
|
37
|
+
? req.body
|
|
38
|
+
: ArrayBuffer.isView(req.body)
|
|
39
|
+
? new Uint8Array(req.body.buffer, req.body.byteOffset, req.body.byteLength)
|
|
40
|
+
: new Uint8Array(req.body);
|
|
41
|
+
const digest = computeDigest(body, ts);
|
|
42
|
+
if (!verifySignature(publicKey, digest, signature)) {
|
|
43
|
+
return { valid: false, reason: 'signature_failed' };
|
|
44
|
+
}
|
|
45
|
+
return { valid: true };
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function verifySignature(publicKey: Uint8Array, digest: Uint8Array, signature: Uint8Array): boolean;
|