@keetanetwork/anchor 0.0.61 → 0.0.63
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/lib/anchor-metadata-server.d.ts +54 -0
- package/lib/anchor-metadata-server.d.ts.map +1 -0
- package/lib/anchor-metadata-server.js +62 -0
- package/lib/anchor-metadata-server.js.map +1 -0
- package/lib/chaining.d.ts +29 -6
- package/lib/chaining.d.ts.map +1 -1
- package/lib/chaining.js +61 -24
- package/lib/chaining.js.map +1 -1
- package/lib/error.d.ts +35 -0
- package/lib/error.d.ts.map +1 -1
- package/lib/error.generated.d.ts +3 -0
- package/lib/error.generated.d.ts.map +1 -0
- package/lib/error.generated.js +104 -0
- package/lib/error.generated.js.map +1 -0
- package/lib/error.js +66 -1
- package/lib/error.js.map +1 -1
- package/lib/http-server/common.d.ts +20 -2
- package/lib/http-server/common.d.ts.map +1 -1
- package/lib/http-server/common.js +47 -0
- package/lib/http-server/common.js.map +1 -1
- package/lib/http-server/index.d.ts +22 -0
- package/lib/http-server/index.d.ts.map +1 -1
- package/lib/http-server/index.js +23 -0
- package/lib/http-server/index.js.map +1 -1
- package/lib/metadata.types.d.ts +40 -0
- package/lib/metadata.types.d.ts.map +1 -1
- package/lib/metadata.types.js.map +1 -1
- package/lib/queue/drivers/queue_postgres.d.ts.map +1 -1
- package/lib/queue/drivers/queue_postgres.js +47 -43
- package/lib/queue/drivers/queue_postgres.js.map +1 -1
- package/lib/resolver.d.ts +19 -20
- package/lib/resolver.d.ts.map +1 -1
- package/lib/resolver.js +1420 -681
- package/lib/resolver.js.map +1 -1
- package/lib/token-metadata.d.ts.map +1 -1
- package/lib/token-metadata.js +1 -1
- package/lib/token-metadata.js.map +1 -1
- package/lib/utils/certificate-network.d.ts +84 -0
- package/lib/utils/certificate-network.d.ts.map +1 -0
- package/lib/utils/certificate-network.js +104 -0
- package/lib/utils/certificate-network.js.map +1 -0
- package/lib/utils/signing.d.ts +12 -0
- package/lib/utils/signing.d.ts.map +1 -1
- package/lib/utils/signing.js +145 -2
- package/lib/utils/signing.js.map +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +2 -2
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +7 -53
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/server.d.ts +6 -4
- package/services/asset-movement/server.d.ts.map +1 -1
- package/services/asset-movement/server.js +3 -3
- package/services/asset-movement/server.js.map +1 -1
- package/services/fx/client.d.ts +2 -1
- package/services/fx/client.d.ts.map +1 -1
- package/services/fx/client.js +5 -3
- package/services/fx/client.js.map +1 -1
- package/services/fx/common.js +7 -7
- package/services/fx/server.d.ts +9 -7
- package/services/fx/server.d.ts.map +1 -1
- package/services/fx/server.js +5 -5
- package/services/fx/server.js.map +1 -1
- package/services/kyc/server.d.ts +6 -4
- package/services/kyc/server.d.ts.map +1 -1
- package/services/kyc/server.js +3 -3
- package/services/kyc/server.js.map +1 -1
- package/services/notification/common.d.ts +2 -1
- package/services/notification/common.d.ts.map +1 -1
- package/services/notification/common.generated.js +20 -20
- package/services/notification/common.js +3 -2
- package/services/notification/common.js.map +1 -1
- package/services/notification/server.d.ts +7 -6
- package/services/notification/server.d.ts.map +1 -1
- package/services/notification/server.js +25 -62
- package/services/notification/server.js.map +1 -1
- package/services/storage/clients/contacts.d.ts +5 -11
- package/services/storage/clients/contacts.d.ts.map +1 -1
- package/services/storage/clients/contacts.js +1 -1
- package/services/storage/clients/contacts.js.map +1 -1
- package/services/storage/common.d.ts +2 -1
- package/services/storage/common.d.ts.map +1 -1
- package/services/storage/common.js +7 -2
- package/services/storage/common.js.map +1 -1
- package/services/storage/server.d.ts +7 -5
- package/services/storage/server.d.ts.map +1 -1
- package/services/storage/server.js +29 -99
- package/services/storage/server.js.map +1 -1
- package/services/username/common.d.ts +2 -1
- package/services/username/common.d.ts.map +1 -1
- package/services/username/common.generated.js +14 -48
- package/services/username/common.generated.js.map +1 -1
- package/services/username/common.js +3 -2
- package/services/username/common.js.map +1 -1
- package/services/username/server.d.ts +7 -6
- package/services/username/server.d.ts.map +1 -1
- package/services/username/server.js +38 -46
- package/services/username/server.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-metadata.d.ts","sourceRoot":"","sources":["../../src/lib/token-metadata.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"token-metadata.d.ts","sourceRoot":"","sources":["../../src/lib/token-metadata.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC;IAC9E,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAgCD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,aAAa,GAAG,aAAa,CAYtG;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,iBAAiB,GAAG,MAAM,CAKvF"}
|
package/lib/token-metadata.js
CHANGED
|
@@ -9,7 +9,7 @@ function parseDecimalPlaces(input) {
|
|
|
9
9
|
}
|
|
10
10
|
value = Number(value);
|
|
11
11
|
}
|
|
12
|
-
if (Number.
|
|
12
|
+
if (!Number.isFinite(value) || value < 0 || value > 1024 || !Number.isInteger(value)) {
|
|
13
13
|
valid = false;
|
|
14
14
|
}
|
|
15
15
|
if (!valid) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-metadata.js","sourceRoot":"","sources":["../../src/lib/token-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"token-metadata.js","sourceRoot":"","sources":["../../src/lib/token-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAWnG,SAAS,kBAAkB,CAAC,KAAsB;IACjD,IAAI,KAAK,GAAG,IAAI,CAAC;IAEjB,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACzB,KAAK,GAAG,KAAK,CAAC;QACf,CAAC;QAED,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACtF,KAAK,GAAG,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAK,CAAC,IAAI,8BAA8B,CAAC;YACxC,MAAM,EAAE;gBACP;oBACC,IAAI,EAAE,eAAe;oBACrB,OAAO,EAAE,gCAAgC,KAAK,EAAE;iBAChD;aACD;SACD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAM,CAAC,KAAK,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAmD;IACtF,IAAI,OAAO,CAAC;IACZ,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACP,OAAO,GAAG,OAAO,CAAC;IACnB,CAAC;IAED,OAAM,CAAC;QACN,GAAG,OAAO;QACV,aAAa,EAAE,kBAAkB,CAAC,OAAO,CAAC,aAAa,CAAC;KACxD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA2C;IAC9E,2FAA2F;IAC3F,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACvD,OAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACvB,CAAC","sourcesContent":["import { KeetaAnchorUserValidationError } from \"./error.js\";\nimport { parseTokenMetadataJSON, stringifyTokenMetadataJSON } from \"./token-metadata.generated.js\";\n\nexport interface TokenMetadata {\n\tdecimalPlaces: number;\n\tlogoURI?: string;\n}\n\nexport interface TokenMetadataJSON extends Omit<TokenMetadata, \"decimalPlaces\"> {\n\tdecimalPlaces: number | string;\n}\n\nfunction parseDecimalPlaces(input: number | string): number {\n\tlet valid = true;\n\n\tlet value = input;\n\tif (typeof value === 'string') {\n\t\tif (value.trim() === '') {\n\t\t\tvalid = false;\n\t\t}\n\n\t\tvalue = Number(value);\n\t}\n\n\tif (!Number.isFinite(value) || value < 0 || value > 1024 || !Number.isInteger(value)) {\n\t\tvalid = false;\n\t}\n\n\tif (!valid) {\n\t\tthrow(new KeetaAnchorUserValidationError({\n\t\t\tfields: [\n\t\t\t\t{\n\t\t\t\t\tpath: 'decimalPlaces',\n\t\t\t\t\tmessage: `Invalid decimalPlaces value: ${input}`\n\t\t\t\t}\n\t\t\t]\n\t\t}));\n\t}\n\n\treturn(value);\n}\n\n/**\n * Parse token metadata from a base64-encoded JSON string or a TokenMetadataJSON object, returning a TokenMetadata object.\n * @param encoded the value to parse\n * @returns the parsed TokenMetadata object\n */\nexport function decodeTokenMetadata(encoded: string | TokenMetadataJSON | TokenMetadata): TokenMetadata {\n\tlet decoded;\n\tif (typeof encoded === \"string\") {\n\t\tdecoded = parseTokenMetadataJSON(atob(encoded));\n\t} else {\n\t\tdecoded = encoded;\n\t}\n\n\treturn({\n\t\t...decoded,\n\t\tdecimalPlaces: parseDecimalPlaces(decoded.decimalPlaces)\n\t});\n}\n\n/**\n * Encodes token metadata into a base64-encoded JSON string.\n *\n * @param metadata - The token metadata to encode {@link TokenMetadata}\n * @returns The base64-encoded JSON string containing the token metadata\n */\nexport function encodeTokenMetadata(metadata: TokenMetadata | TokenMetadataJSON): string {\n\t// Normalize metadata so that decimalPlaces is always a number, ensuring canonical encoding\n\tconst normalized = decodeTokenMetadata(metadata);\n\tconst payload = stringifyTokenMetadataJSON(normalized);\n\treturn(btoa(payload));\n}\n"]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type * as KeetaNetClient from '@keetanetwork/keetanet-client';
|
|
2
|
+
import * as KeetaNet from '@keetanetwork/keetanet-client';
|
|
3
|
+
import { Certificate } from '../certificates.js';
|
|
4
|
+
type AccountKeyAlgorithm = InstanceType<typeof KeetaNetClient.lib.Account>['keyType'];
|
|
5
|
+
type KeetaNetAccount = ReturnType<typeof KeetaNetClient.lib.Account.fromSeed<AccountKeyAlgorithm>>;
|
|
6
|
+
type KeetaNetNetwork = typeof KeetaNet.Client.Config.networksArray[number];
|
|
7
|
+
/**
|
|
8
|
+
* Outcome of verifying an account's on-chain cert chain against a trust
|
|
9
|
+
* set:
|
|
10
|
+
*
|
|
11
|
+
* - `'trusted'`: at least one published cert chains to a trusted issuer.
|
|
12
|
+
* - `'no-certs'`: account has no published certificates.
|
|
13
|
+
* - `'untrusted'`: certs exist but none chain to a trusted issuer.
|
|
14
|
+
*/
|
|
15
|
+
export type CertificateChainStatus = 'trusted' | 'no-certs' | 'untrusted';
|
|
16
|
+
/**
|
|
17
|
+
* Verify that the supplied account has at least one on-chain certificate
|
|
18
|
+
* whose chain terminates at one of the supplied trusted issuers.
|
|
19
|
+
*/
|
|
20
|
+
export declare function verifyAccountCertificateChain(args: {
|
|
21
|
+
account: KeetaNetAccount;
|
|
22
|
+
client: InstanceType<typeof KeetaNetClient.Client>;
|
|
23
|
+
trustedIssuers: Certificate[];
|
|
24
|
+
}): Promise<CertificateChainStatus>;
|
|
25
|
+
/**
|
|
26
|
+
* Public configuration for the on-chain certificate-chain gate. Pass on a
|
|
27
|
+
* server config (`requireCertificateChain`) to require that every authenticated
|
|
28
|
+
* caller has at least one published certificate chaining to one of `trustedIssuers`.
|
|
29
|
+
*/
|
|
30
|
+
export interface CertificateChainConfig {
|
|
31
|
+
trustedIssuers: Certificate[];
|
|
32
|
+
client: InstanceType<typeof KeetaNetClient.Client>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Post-validation form of {@link CertificateChainConfig}. `acceptedIssuerDNs`
|
|
36
|
+
* is precomputed once so error payloads don't re-walk `trustedIssuers`.
|
|
37
|
+
*/
|
|
38
|
+
export interface ResolvedCertificateChainRequirement {
|
|
39
|
+
readonly trustedIssuers: Certificate[];
|
|
40
|
+
readonly client: InstanceType<typeof KeetaNetClient.Client>;
|
|
41
|
+
readonly acceptedIssuerDNs: {
|
|
42
|
+
name: string;
|
|
43
|
+
value: string;
|
|
44
|
+
}[][];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate and freeze a `CertificateChainConfig`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveCertificateChainConfig(config: CertificateChainConfig | undefined): ResolvedCertificateChainRequirement | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Default delimiter used by {@link certificateChainConfigFromBundle} to
|
|
52
|
+
* separate concatenated PEM-encoded certificates in a single string.
|
|
53
|
+
*/
|
|
54
|
+
export declare const DEFAULT_CERTIFICATE_BUNDLE_DELIMITER = "|";
|
|
55
|
+
/**
|
|
56
|
+
* Arguments accepted by {@link certificateChainConfigFromBundle}.
|
|
57
|
+
*/
|
|
58
|
+
export interface CertificateChainConfigFromBundleArgs {
|
|
59
|
+
/**
|
|
60
|
+
* One or more PEM-encoded certificates joined with `delimiter`.
|
|
61
|
+
*/
|
|
62
|
+
pemBundle: string;
|
|
63
|
+
/**
|
|
64
|
+
* KeetaNet network used to instantiate the client.
|
|
65
|
+
*/
|
|
66
|
+
network: KeetaNetNetwork;
|
|
67
|
+
/**
|
|
68
|
+
* Delimiter used to split `pemBundle`. Defaults to
|
|
69
|
+
* {@link DEFAULT_CERTIFICATE_BUNDLE_DELIMITER}.
|
|
70
|
+
*/
|
|
71
|
+
delimiter?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build a {@link CertificateChainConfig} from a delimited PEM bundle and a network.
|
|
75
|
+
*/
|
|
76
|
+
export declare function certificateChainConfigFromBundle(args: CertificateChainConfigFromBundleArgs): CertificateChainConfig;
|
|
77
|
+
/**
|
|
78
|
+
* Verify the signing account's on-chain certificate chain against the
|
|
79
|
+
* resolved requirement. Throws `KeetaAnchorCertificateRequiredError` when
|
|
80
|
+
* the gate is configured and the account fails it.
|
|
81
|
+
*/
|
|
82
|
+
export declare function assertAccountCertificateChain(account: KeetaNetAccount, requirement: ResolvedCertificateChainRequirement | undefined): Promise<void>;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=certificate-network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate-network.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/certificate-network.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,cAAc,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,KAAK,mBAAmB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;AACtF,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAEnG,KAAK,eAAe,GAAG,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAE1E;;;GAGG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,EAAE;IACzD,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IACnD,cAAc,EAAE,WAAW,EAAE,CAAC;CAC9B,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmClC;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,MAAM,EAAE,YAAY,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;CACnD;AAED;;;GAGG;AACH,MAAM,WAAW,mCAAmC;IACnD,QAAQ,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5D,QAAQ,CAAC,iBAAiB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;KAAE,EAAE,EAAE,CAAC;CACjE;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,sBAAsB,GAAG,SAAS,GAAG,mCAAmC,GAAG,SAAS,CAazI;AAED;;;GAGG;AACH,eAAO,MAAM,oCAAoC,MAAM,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACpD;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,oCAAoC,GAAG,sBAAsB,CAcnH;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CAAC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,mCAAmC,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzJ"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as KeetaNet from '@keetanetwork/keetanet-client';
|
|
2
|
+
import { Certificate } from '../certificates.js';
|
|
3
|
+
import { KeetaAnchorCertificateRequiredError } from '../error.js';
|
|
4
|
+
/**
|
|
5
|
+
* Verify that the supplied account has at least one on-chain certificate
|
|
6
|
+
* whose chain terminates at one of the supplied trusted issuers.
|
|
7
|
+
*/
|
|
8
|
+
export async function verifyAccountCertificateChain(args) {
|
|
9
|
+
const { account, client, trustedIssuers } = args;
|
|
10
|
+
const records = await client.getAllCertificates(account);
|
|
11
|
+
if (records.length === 0) {
|
|
12
|
+
return ('no-certs');
|
|
13
|
+
}
|
|
14
|
+
if (trustedIssuers.length === 0) {
|
|
15
|
+
return ('untrusted');
|
|
16
|
+
}
|
|
17
|
+
const rootSet = new Set(trustedIssuers);
|
|
18
|
+
for (const record of records) {
|
|
19
|
+
let intermediate;
|
|
20
|
+
if (record.intermediates === null) {
|
|
21
|
+
intermediate = new Set();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
intermediate = new Set(record.intermediates.getCertificates());
|
|
25
|
+
}
|
|
26
|
+
let candidate;
|
|
27
|
+
try {
|
|
28
|
+
candidate = new Certificate(record.certificate.toPEM(), {
|
|
29
|
+
store: { root: rootSet, intermediate }
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (candidate.trusted) {
|
|
36
|
+
return ('trusted');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return ('untrusted');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate and freeze a `CertificateChainConfig`.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveCertificateChainConfig(config) {
|
|
45
|
+
if (config === undefined) {
|
|
46
|
+
return (undefined);
|
|
47
|
+
}
|
|
48
|
+
if (config.trustedIssuers.length === 0) {
|
|
49
|
+
throw (new Error('requireCertificateChain.trustedIssuers must contain at least one issuer'));
|
|
50
|
+
}
|
|
51
|
+
return ({
|
|
52
|
+
trustedIssuers: config.trustedIssuers,
|
|
53
|
+
client: config.client,
|
|
54
|
+
acceptedIssuerDNs: config.trustedIssuers.map(function (cert) { return (cert.subjectDN); })
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Default delimiter used by {@link certificateChainConfigFromBundle} to
|
|
59
|
+
* separate concatenated PEM-encoded certificates in a single string.
|
|
60
|
+
*/
|
|
61
|
+
export const DEFAULT_CERTIFICATE_BUNDLE_DELIMITER = '|';
|
|
62
|
+
/**
|
|
63
|
+
* Build a {@link CertificateChainConfig} from a delimited PEM bundle and a network.
|
|
64
|
+
*/
|
|
65
|
+
export function certificateChainConfigFromBundle(args) {
|
|
66
|
+
const delimiter = args.delimiter ?? DEFAULT_CERTIFICATE_BUNDLE_DELIMITER;
|
|
67
|
+
const trustedIssuers = args.pemBundle
|
|
68
|
+
.split(delimiter)
|
|
69
|
+
.map(function (pem) { return (pem.trim()); })
|
|
70
|
+
.filter(function (pem) { return (pem.length > 0); })
|
|
71
|
+
.map(function (pem) { return (new Certificate(pem)); });
|
|
72
|
+
if (trustedIssuers.length === 0) {
|
|
73
|
+
throw (new Error('pemBundle contains no certificates'));
|
|
74
|
+
}
|
|
75
|
+
const client = KeetaNet.Client.fromNetwork(args.network);
|
|
76
|
+
return ({ trustedIssuers, client });
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Verify the signing account's on-chain certificate chain against the
|
|
80
|
+
* resolved requirement. Throws `KeetaAnchorCertificateRequiredError` when
|
|
81
|
+
* the gate is configured and the account fails it.
|
|
82
|
+
*/
|
|
83
|
+
export async function assertAccountCertificateChain(account, requirement) {
|
|
84
|
+
if (requirement === undefined) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const status = await verifyAccountCertificateChain({
|
|
88
|
+
account,
|
|
89
|
+
client: requirement.client,
|
|
90
|
+
trustedIssuers: requirement.trustedIssuers
|
|
91
|
+
});
|
|
92
|
+
if (status === 'trusted') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
let kind;
|
|
96
|
+
if (status === 'no-certs') {
|
|
97
|
+
kind = 'missing';
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
kind = 'untrusted';
|
|
101
|
+
}
|
|
102
|
+
throw (new KeetaAnchorCertificateRequiredError({ acceptedIssuers: requirement.acceptedIssuerDNs, kind }));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=certificate-network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate-network.js","sourceRoot":"","sources":["../../../src/lib/utils/certificate-network.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as KeetaNetClient from '@keetanetwork/keetanet-client';\nimport * as KeetaNet from '@keetanetwork/keetanet-client';\n\nimport type { KeetaAnchorCertificateRequiredKind } from '../error.js';\nimport { Certificate } from '../certificates.js';\nimport { KeetaAnchorCertificateRequiredError } from '../error.js';\n\ntype AccountKeyAlgorithm = InstanceType<typeof KeetaNetClient.lib.Account>['keyType'];\ntype KeetaNetAccount = ReturnType<typeof KeetaNetClient.lib.Account.fromSeed<AccountKeyAlgorithm>>;\ntype BaseCertificate = InstanceType<typeof KeetaNetClient.lib.Utils.Certificate.Certificate>;\ntype KeetaNetNetwork = typeof KeetaNet.Client.Config.networksArray[number];\n\n/**\n * Outcome of verifying an account's on-chain cert chain against a trust\n * set:\n *\n * - `'trusted'`: at least one published cert chains to a trusted issuer.\n * - `'no-certs'`: account has no published certificates.\n * - `'untrusted'`: certs exist but none chain to a trusted issuer.\n */\nexport type CertificateChainStatus = 'trusted' | 'no-certs' | 'untrusted';\n\n/**\n * Verify that the supplied account has at least one on-chain certificate\n * whose chain terminates at one of the supplied trusted issuers.\n */\nexport async function verifyAccountCertificateChain(args: {\n\taccount: KeetaNetAccount;\n\tclient: InstanceType<typeof KeetaNetClient.Client>;\n\ttrustedIssuers: Certificate[];\n}): Promise<CertificateChainStatus> {\n\tconst { account, client, trustedIssuers } = args;\n\tconst records = await client.getAllCertificates(account);\n\tif (records.length === 0) {\n\t\treturn('no-certs');\n\t}\n\n\tif (trustedIssuers.length === 0) {\n\t\treturn('untrusted');\n\t}\n\n\tconst rootSet = new Set<BaseCertificate>(trustedIssuers);\n\tfor (const record of records) {\n\t\tlet intermediate: Set<BaseCertificate>;\n\t\tif (record.intermediates === null) {\n\t\t\tintermediate = new Set<BaseCertificate>();\n\t\t} else {\n\t\t\tintermediate = new Set<BaseCertificate>(record.intermediates.getCertificates());\n\t\t}\n\n\t\tlet candidate: Certificate;\n\t\ttry {\n\t\t\tcandidate = new Certificate(record.certificate.toPEM(), {\n\t\t\t\tstore: { root: rootSet, intermediate }\n\t\t\t});\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (candidate.trusted) {\n\t\t\treturn('trusted');\n\t\t}\n\t}\n\n\treturn('untrusted');\n}\n\n/**\n * Public configuration for the on-chain certificate-chain gate. Pass on a\n * server config (`requireCertificateChain`) to require that every authenticated\n * caller has at least one published certificate chaining to one of `trustedIssuers`.\n */\nexport interface CertificateChainConfig {\n\ttrustedIssuers: Certificate[];\n\tclient: InstanceType<typeof KeetaNetClient.Client>;\n}\n\n/**\n * Post-validation form of {@link CertificateChainConfig}. `acceptedIssuerDNs`\n * is precomputed once so error payloads don't re-walk `trustedIssuers`.\n */\nexport interface ResolvedCertificateChainRequirement {\n\treadonly trustedIssuers: Certificate[];\n\treadonly client: InstanceType<typeof KeetaNetClient.Client>;\n\treadonly acceptedIssuerDNs: { name: string; value: string; }[][];\n}\n\n/**\n * Validate and freeze a `CertificateChainConfig`.\n */\nexport function resolveCertificateChainConfig(config: CertificateChainConfig | undefined): ResolvedCertificateChainRequirement | undefined {\n\tif (config === undefined) {\n\t\treturn(undefined);\n\t}\n\tif (config.trustedIssuers.length === 0) {\n\t\tthrow(new Error('requireCertificateChain.trustedIssuers must contain at least one issuer'));\n\t}\n\n\treturn({\n\t\ttrustedIssuers: config.trustedIssuers,\n\t\tclient: config.client,\n\t\tacceptedIssuerDNs: config.trustedIssuers.map(function(cert) { return(cert.subjectDN); })\n\t});\n}\n\n/**\n * Default delimiter used by {@link certificateChainConfigFromBundle} to\n * separate concatenated PEM-encoded certificates in a single string.\n */\nexport const DEFAULT_CERTIFICATE_BUNDLE_DELIMITER = '|';\n\n/**\n * Arguments accepted by {@link certificateChainConfigFromBundle}.\n */\nexport interface CertificateChainConfigFromBundleArgs {\n\t/**\n\t * One or more PEM-encoded certificates joined with `delimiter`.\n\t */\n\tpemBundle: string;\n\n\t/**\n\t * KeetaNet network used to instantiate the client.\n\t */\n\tnetwork: KeetaNetNetwork;\n\n\t/**\n\t * Delimiter used to split `pemBundle`. Defaults to\n\t * {@link DEFAULT_CERTIFICATE_BUNDLE_DELIMITER}.\n\t */\n\tdelimiter?: string;\n}\n\n/**\n * Build a {@link CertificateChainConfig} from a delimited PEM bundle and a network.\n */\nexport function certificateChainConfigFromBundle(args: CertificateChainConfigFromBundleArgs): CertificateChainConfig {\n\tconst delimiter = args.delimiter ?? DEFAULT_CERTIFICATE_BUNDLE_DELIMITER;\n\tconst trustedIssuers = args.pemBundle\n\t\t.split(delimiter)\n\t\t.map(function(pem) { return(pem.trim()); })\n\t\t.filter(function(pem) { return(pem.length > 0); })\n\t\t.map(function(pem) { return(new Certificate(pem)); });\n\n\tif (trustedIssuers.length === 0) {\n\t\tthrow(new Error('pemBundle contains no certificates'));\n\t}\n\n\tconst client = KeetaNet.Client.fromNetwork(args.network);\n\treturn({ trustedIssuers, client });\n}\n\n/**\n * Verify the signing account's on-chain certificate chain against the\n * resolved requirement. Throws `KeetaAnchorCertificateRequiredError` when\n * the gate is configured and the account fails it.\n */\nexport async function assertAccountCertificateChain(account: KeetaNetAccount, requirement: ResolvedCertificateChainRequirement | undefined): Promise<void> {\n\tif (requirement === undefined) {\n\t\treturn;\n\t}\n\n\tconst status = await verifyAccountCertificateChain({\n\t\taccount,\n\t\tclient: requirement.client,\n\t\ttrustedIssuers: requirement.trustedIssuers\n\t});\n\tif (status === 'trusted') {\n\t\treturn;\n\t}\n\n\tlet kind: KeetaAnchorCertificateRequiredKind;\n\tif (status === 'no-certs') {\n\t\tkind = 'missing';\n\t} else {\n\t\tkind = 'untrusted';\n\t}\n\n\tthrow(new KeetaAnchorCertificateRequiredError({ acceptedIssuers: requirement.acceptedIssuerDNs, kind }));\n}\n"]}
|
package/lib/utils/signing.d.ts
CHANGED
|
@@ -3,6 +3,18 @@ import { Buffer } from '../../lib/utils/buffer.js';
|
|
|
3
3
|
export type SignableAccount = ReturnType<InstanceType<typeof KeetaNetLib.Account>['assertAccount']>;
|
|
4
4
|
export type VerifiableAccount = InstanceType<typeof KeetaNetLib.Account>;
|
|
5
5
|
export type Signable = (string | number | bigint | InstanceType<typeof KeetaNetLib.Account>)[];
|
|
6
|
+
/**
|
|
7
|
+
* Structural input to {@link objectToSignable}.
|
|
8
|
+
*/
|
|
9
|
+
export type SignableInput = {
|
|
10
|
+
[key: string | number | symbol]: unknown;
|
|
11
|
+
} | SignableInput[] | Signable[number] | undefined | null | boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Canonicalize a tree into a {@link Signable} via {@link canonicalizeJson}.
|
|
14
|
+
* {@link KeetaNetLib.Account} instances are replaced by their `publicKeyAndTypeString`.
|
|
15
|
+
* {@link Date} instances are replaced by their ISO 8601 string.
|
|
16
|
+
*/
|
|
17
|
+
export declare function objectToSignable(item: SignableInput): Signable;
|
|
6
18
|
/**
|
|
7
19
|
* Options for signature verification
|
|
8
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAMnE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAMnE,OAAO,EAAE,MAAM,EAAgD,MAAM,2BAA2B,CAAC;AAKjG,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,YAAY,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACpG,MAAM,MAAM,iBAAiB,GAAG,YAAY,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AACzE,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,aAAa,GACxB;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,GAC5C,aAAa,EAAE,GACf,QAAQ,CAAC,MAAM,CAAC,GAChB,SAAS,GACT,IAAI,GACJ,OAAO,CAAC;AA2GT;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,CA2D9D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,aAAa,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;CAAE,CAoDjL;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CAAE,CAAC,CAS1I;AAED,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,EAC5C,OAAO,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,OAAO,CAAC,CA6BlB"}
|
package/lib/utils/signing.js
CHANGED
|
@@ -1,7 +1,150 @@
|
|
|
1
1
|
import { lib as KeetaNetLib } from '@keetanetwork/keetanet-client';
|
|
2
|
-
import { Buffer, bufferToArrayBuffer } from '../../lib/utils/buffer.js';
|
|
2
|
+
import { Buffer, bufferToArrayBuffer, arrayBufferLikeToBuffer } from '../../lib/utils/buffer.js';
|
|
3
3
|
import crypto from '../../lib/utils/crypto.js';
|
|
4
4
|
import { assertNever } from '../../lib/utils/never.js';
|
|
5
|
+
import { KeetaAnchorError } from '../error.js';
|
|
6
|
+
const TO_SIGNABLE_MAX_NODES = 1000;
|
|
7
|
+
const TO_SIGNABLE_MAX_OUTPUT_BYTES = 65536;
|
|
8
|
+
/**
|
|
9
|
+
* Detects unpaired UTF-16 surrogate code units. JCS
|
|
10
|
+
* ({@link https://www.rfc-editor.org/rfc/rfc8785 RFC 8785} Section 3.2.2.2)
|
|
11
|
+
* requires implementations to reject such strings.
|
|
12
|
+
*/
|
|
13
|
+
const LONE_SURROGATE_PATTERN = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
14
|
+
/**
|
|
15
|
+
* Serialize a JSON-shaped value following JCS
|
|
16
|
+
* ({@link https://www.rfc-editor.org/rfc/rfc8785 RFC 8785}).
|
|
17
|
+
*/
|
|
18
|
+
function canonicalizeJson(value) {
|
|
19
|
+
/**
|
|
20
|
+
* Literal serialization (Section 3.2.2.1).
|
|
21
|
+
*/
|
|
22
|
+
if (value === null || typeof value === 'boolean') {
|
|
23
|
+
return (JSON.stringify(value));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* String serialization (Section 3.2.2.2). Lone UTF-16 surrogates MUST cause termination.
|
|
27
|
+
*/
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
if (LONE_SURROGATE_PATTERN.test(value)) {
|
|
30
|
+
throw (new KeetaAnchorError('Lone UTF-16 surrogate in canonicalizeJson'));
|
|
31
|
+
}
|
|
32
|
+
return (JSON.stringify(value));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Number serialization (Section 3.2.2.3). NaN and Infinity MUST cause termination.
|
|
36
|
+
*/
|
|
37
|
+
if (typeof value === 'number') {
|
|
38
|
+
if (!Number.isFinite(value)) {
|
|
39
|
+
throw (new KeetaAnchorError('non-finite number in canonicalizeJson'));
|
|
40
|
+
}
|
|
41
|
+
return (JSON.stringify(value));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Big integer serialization (Appendix D); I-JSON safe-integer range required.
|
|
45
|
+
*/
|
|
46
|
+
if (typeof value === 'bigint') {
|
|
47
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
|
|
48
|
+
throw (new KeetaAnchorError('bigint out of safe integer range in canonicalizeJson'));
|
|
49
|
+
}
|
|
50
|
+
return (value.toString());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Array element order MUST NOT be changed (Section 3.2.3); sparse holes serialize as JSON `null`.
|
|
54
|
+
*/
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
for (let i = 0; i < value.length; i++) {
|
|
58
|
+
parts.push(i in value ? canonicalizeJson(value[i]) : 'null');
|
|
59
|
+
}
|
|
60
|
+
return (`[${parts.join(',')}]`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Object property sorting by UTF-16 code unit (Section 3.2.3); recursion required.
|
|
64
|
+
* Only plain objects are permitted; class instances (Date, Map, etc.) are rejected.
|
|
65
|
+
*/
|
|
66
|
+
if (typeof value === 'object') {
|
|
67
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
68
|
+
throw (new KeetaAnchorError('Non-plain object in canonicalizeJson'));
|
|
69
|
+
}
|
|
70
|
+
const entries = Object.entries(value);
|
|
71
|
+
for (const [key] of entries) {
|
|
72
|
+
if (LONE_SURROGATE_PATTERN.test(key)) {
|
|
73
|
+
throw (new KeetaAnchorError('Lone UTF-16 surrogate in object key'));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
entries.sort(([a], [b]) => {
|
|
77
|
+
if (a < b) {
|
|
78
|
+
return (-1);
|
|
79
|
+
}
|
|
80
|
+
if (a > b) {
|
|
81
|
+
return (1);
|
|
82
|
+
}
|
|
83
|
+
return (0);
|
|
84
|
+
});
|
|
85
|
+
const parts = [];
|
|
86
|
+
for (const [key, child] of entries) {
|
|
87
|
+
parts.push(`${JSON.stringify(key)}:${canonicalizeJson(child)}`);
|
|
88
|
+
}
|
|
89
|
+
return (`{${parts.join(',')}}`);
|
|
90
|
+
}
|
|
91
|
+
throw (new KeetaAnchorError('Unsupported value type in canonicalizeJson'));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Canonicalize a tree into a {@link Signable} via {@link canonicalizeJson}.
|
|
95
|
+
* {@link KeetaNetLib.Account} instances are replaced by their `publicKeyAndTypeString`.
|
|
96
|
+
* {@link Date} instances are replaced by their ISO 8601 string.
|
|
97
|
+
*/
|
|
98
|
+
export function objectToSignable(item) {
|
|
99
|
+
let nodeCount = 0;
|
|
100
|
+
function visit(value) {
|
|
101
|
+
nodeCount++;
|
|
102
|
+
if (nodeCount > TO_SIGNABLE_MAX_NODES) {
|
|
103
|
+
throw (new KeetaAnchorError('Too much data to sign in objectToSignable'));
|
|
104
|
+
}
|
|
105
|
+
if (value === undefined || value === null) {
|
|
106
|
+
return (null);
|
|
107
|
+
}
|
|
108
|
+
if (value instanceof Date) {
|
|
109
|
+
if (Number.isNaN(value.valueOf())) {
|
|
110
|
+
throw (new KeetaAnchorError('Invalid Date in objectToSignable'));
|
|
111
|
+
}
|
|
112
|
+
return (value.toISOString());
|
|
113
|
+
}
|
|
114
|
+
if (KeetaNetLib.Account.isInstance(value)) {
|
|
115
|
+
return (value.publicKeyAndTypeString);
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
if (value.length > TO_SIGNABLE_MAX_NODES - nodeCount) {
|
|
119
|
+
throw (new KeetaAnchorError('Too much data to sign in objectToSignable'));
|
|
120
|
+
}
|
|
121
|
+
const result = [];
|
|
122
|
+
for (const child of value) {
|
|
123
|
+
result.push(visit(child));
|
|
124
|
+
}
|
|
125
|
+
return (result);
|
|
126
|
+
}
|
|
127
|
+
if (typeof value === 'object') {
|
|
128
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
129
|
+
throw (new KeetaAnchorError('Non-plain object in objectToSignable'));
|
|
130
|
+
}
|
|
131
|
+
const result = {};
|
|
132
|
+
for (const [key, child] of Object.entries(value)) {
|
|
133
|
+
if (child === undefined) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
result[key] = visit(child);
|
|
137
|
+
}
|
|
138
|
+
return (result);
|
|
139
|
+
}
|
|
140
|
+
return (value);
|
|
141
|
+
}
|
|
142
|
+
const canonical = canonicalizeJson(visit(item));
|
|
143
|
+
if (Buffer.byteLength(canonical, 'utf8') > TO_SIGNABLE_MAX_OUTPUT_BYTES) {
|
|
144
|
+
throw (new KeetaAnchorError('Canonical output exceeds size limit in objectToSignable'));
|
|
145
|
+
}
|
|
146
|
+
return ([canonical]);
|
|
147
|
+
}
|
|
5
148
|
export function FormatData(account, data, nonce, timestamp) {
|
|
6
149
|
nonce ??= crypto.randomUUID();
|
|
7
150
|
timestamp ??= new Date();
|
|
@@ -50,7 +193,7 @@ export function FormatData(account, data, nonce, timestamp) {
|
|
|
50
193
|
return ({
|
|
51
194
|
nonce: nonce,
|
|
52
195
|
timestamp: timestampString,
|
|
53
|
-
verificationData:
|
|
196
|
+
verificationData: arrayBufferLikeToBuffer(verificationData.toBER())
|
|
54
197
|
});
|
|
55
198
|
}
|
|
56
199
|
export async function SignData(account, data) {
|
package/lib/utils/signing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/lib/utils/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAMnE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAgBvD,MAAM,UAAU,UAAU,CAAC,OAA0B,EAAE,IAAc,EAAE,KAAc,EAAE,SAAyB;IAC/G,KAAK,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;IAC9B,SAAS,KAAK,IAAI,IAAI,EAAE,CAAC;IAEzB,IAAI,eAAuB,CAAC;IAC5B,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QACnC,eAAe,GAAG,SAAS,CAAC;IAC7B,CAAC;SAAM,CAAC;QACP,eAAe,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,KAAK,GAAwB;QAClC,KAAK;QACL,eAAe;QACf,OAAO,CAAC,gBAAgB;KACxB,CAAC;IAEF,MAAM,MAAM,GAAoC;QAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa;KACjD,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACP,WAAW,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACF,CAAC;IAED;;OAEG;IACH,aAAa;IACb,mEAAmE;IACnE,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxF,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEzE,OAAM,CAAC;QACN,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,eAAe;QAC1B,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;KACvD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB,EAAE,IAAc;IACtE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAE5E,OAAM,CAAC;QACN,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;KACnD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,OAA0B,EAC1B,IAAc,EACd,MAA4C,EAC5C,OAAuB;IAEvB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC;IACzC,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5C;;;;;;;OAOG;IACH,IAAI,SAAS,CAAC,WAAW,EAAE,KAAK,eAAe,EAAE,CAAC;QACjD,OAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACtD,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,IAAI,IAAI,EAAE,CAAC;IAC3D,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC;QACzE,wDAAwD;QACxD,OAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,mGAAmG;IACnG,MAAM,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;IAE/E,OAAM,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACvJ,CAAC","sourcesContent":["import { lib as KeetaNetLib } from '@keetanetwork/keetanet-client';\nimport type {\n\tValidateASN1 as KeetaNetASN1Validation,\n\tASN1AnyJS as KeetaNetASN1AnyJS\n} from '@keetanetwork/keetanet-client/lib/utils/asn1.js';\n\nimport { Buffer, bufferToArrayBuffer } from '../../lib/utils/buffer.js';\nimport crypto from '../../lib/utils/crypto.js';\nimport { assertNever } from '../../lib/utils/never.js';\n\nexport type SignableAccount = ReturnType<InstanceType<typeof KeetaNetLib.Account>['assertAccount']>;\nexport type VerifiableAccount = InstanceType<typeof KeetaNetLib.Account>;\nexport type Signable = (string | number | bigint | InstanceType<typeof KeetaNetLib.Account>)[];\n\n/**\n * Options for signature verification\n */\nexport interface VerifyOptions {\n\t/** Maximum allowed time difference in milliseconds (default: 5 * 60 * 1000 = 5 minutes) */\n\tmaxSkewMs?: number;\n\t/** Reference time for skew calculation (default: new Date()) */\n\treferenceTime?: Date;\n}\n\nexport function FormatData(account: VerifiableAccount, data: Signable, nonce?: string, timestamp?: string | Date): { nonce: string; timestamp: string; verificationData: Buffer; } {\n\tnonce ??= crypto.randomUUID();\n\ttimestamp ??= new Date();\n\n\tlet timestampString: string;\n\tif (typeof timestamp === 'string') {\n\t\ttimestampString = timestamp;\n\t} else {\n\t\ttimestampString = timestamp.toISOString();\n\t}\n\n\tconst input: KeetaNetASN1AnyJS[] = [\n\t\tnonce,\n\t\ttimestampString,\n\t\taccount.publicKeyAndType\n\t];\n\n\tconst schema: KeetaNetASN1Validation.Schema[] = [\n\t\t{ type: 'string', kind: 'utf8' },\n\t\t{ type: 'string', kind: 'utf8' },\n\t\tKeetaNetLib.Utils.ASN1.ValidateASN1.IsOctetString\n\t];\n\n\tfor (const item of data) {\n\t\tif (typeof item === 'string') {\n\t\t\tinput.push(item);\n\t\t\tschema.push({ type: 'string', kind: 'utf8' });\n\t\t} else if (typeof item === 'number' || typeof item === 'bigint') {\n\t\t\tinput.push(item);\n\t\t\tschema.push(KeetaNetLib.Utils.ASN1.ValidateASN1.IsInteger);\n\t\t} else if (KeetaNetLib.Account.isInstance(item)) {\n\t\t\tinput.push(item.publicKeyAndType);\n\t\t\tschema.push(KeetaNetLib.Utils.ASN1.ValidateASN1.IsOctetString);\n\t\t} else {\n\t\t\tassertNever(item);\n\t\t}\n\t}\n\n\t/*\n\t * Verify that the generated ASN.1 data matches the expected schema before returning it.\n\t */\n\t// @ts-ignore\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst inputCanonical = KeetaNetLib.Utils.ASN1.ValidateASN1.againstSchema(input, schema);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tconst verificationData = KeetaNetLib.Utils.ASN1.JStoASN1(inputCanonical);\n\n\treturn({\n\t\tnonce: nonce,\n\t\ttimestamp: timestampString,\n\t\tverificationData: Buffer.from(verificationData.toBER())\n\t});\n}\n\nexport async function SignData(account: SignableAccount, data: Signable): Promise<{ nonce: string; timestamp: string; signature: string; }> {\n\tconst { nonce, timestamp, verificationData } = FormatData(account, data);\n\tconst signature = await account.sign(bufferToArrayBuffer(verificationData));\n\n\treturn({\n\t\tnonce: nonce,\n\t\ttimestamp: timestamp,\n\t\tsignature: signature.getBuffer().toString('base64')\n\t});\n}\n\nexport async function VerifySignedData(\n\taccount: VerifiableAccount,\n\tdata: Signable,\n\tsigned: Awaited<ReturnType<typeof SignData>>,\n\toptions?: VerifyOptions\n): Promise<boolean> {\n\tconst nonce = signed.nonce;\n\tconst timestampString = signed.timestamp;\n\tconst signatureBuffer = Buffer.from(signed.signature, 'base64');\n\n\tconst timestamp = new Date(timestampString);\n\t/*\n\t * Enforce that the timestamp string is in valid ISO 8601 format,\n\t * not just a date that can be parsed\n\t *\n\t * XXX:TODO: This is not a perfect check since ISO 8601 does not require millisecond-level\n\t * precision and technically allows other timezones (though we will not support\n\t * those). This will be changed in the future to be more robust.\n\t */\n\tif (timestamp.toISOString() !== timestampString) {\n\t\treturn(false);\n\t}\n\n\tconst maxSkewMs = options?.maxSkewMs ?? 5 * 60 * 1000;\n\tconst referenceTime = options?.referenceTime ?? new Date();\n\tif (Math.abs(timestamp.valueOf() - referenceTime.valueOf()) > maxSkewMs) {\n\t\t/* Timestamp exceeds allowed skew from reference time */\n\t\treturn(false);\n\t}\n\n\t/* XXX:TODO: Verify that the timestamp is a valid ISO 8601 date string within a reasonable range */\n\tconst { verificationData } = FormatData(account, data, nonce, timestampString);\n\n\treturn(account.verify(KeetaNetLib.Utils.Helper.bufferToArrayBuffer(verificationData), KeetaNetLib.Utils.Helper.bufferToArrayBuffer(signatureBuffer)));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/lib/utils/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAMnE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACjG,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,MAAM,qBAAqB,GAAG,IAAI,CAAC;AACnC,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAE3C;;;;GAIG;AACH,MAAM,sBAAsB,GAAG,wEAAwE,CAAC;AAExG;;;GAGG;AACH,SAAS,gBAAgB,CAAC,KAAc;IACvC;;OAEG;IACH,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAClD,OAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACxC,MAAK,CAAC,IAAI,gBAAgB,CAAC,2CAA2C,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,OAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAK,CAAC,IAAI,gBAAgB,CAAC,uCAAuC,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,OAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACxF,MAAK,CAAC,IAAI,gBAAgB,CAAC,sDAAsD,CAAC,CAAC,CAAC;QACrF,CAAC;QAED,OAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC;QAED,OAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YAChG,MAAK,CAAC,IAAI,gBAAgB,CAAC,sCAAsC,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtC,KAAK,MAAM,CAAE,GAAG,CAAE,IAAI,OAAO,EAAE,CAAC;YAC/B,IAAI,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtC,MAAK,CAAC,IAAI,gBAAgB,CAAC,qCAAqC,CAAC,CAAC,CAAC;YACpE,CAAC;QACF,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAE,EAAE,CAAE,CAAC,CAAE,EAAE,EAAE;YAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACX,OAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACZ,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACX,OAAM,CAAC,CAAC,CAAC,CAAC;YACX,CAAC;YAED,OAAM,CAAC,CAAC,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,OAAO,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,OAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,MAAK,CAAC,IAAI,gBAAgB,CAAC,4CAA4C,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAmB;IACnD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,SAAS,KAAK,CAAC,KAAc;QAC5B,SAAS,EAAE,CAAC;QACZ,IAAI,SAAS,GAAG,qBAAqB,EAAE,CAAC;YACvC,MAAK,CAAC,IAAI,gBAAgB,CAAC,2CAA2C,CAAC,CAAC,CAAC;QAC1E,CAAC;QAED,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC3C,OAAM,CAAC,IAAI,CAAC,CAAC;QACd,CAAC;QACD,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBACnC,MAAK,CAAC,IAAI,gBAAgB,CAAC,kCAAkC,CAAC,CAAC,CAAC;YACjE,CAAC;YAED,OAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,OAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,MAAM,GAAG,qBAAqB,GAAG,SAAS,EAAE,CAAC;gBACtD,MAAK,CAAC,IAAI,gBAAgB,CAAC,2CAA2C,CAAC,CAAC,CAAC;YAC1E,CAAC;YAED,MAAM,MAAM,GAAc,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3B,CAAC;YAED,OAAM,CAAC,MAAM,CAAC,CAAC;QAChB,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;gBAChG,MAAK,CAAC,IAAI,gBAAgB,CAAC,sCAAsC,CAAC,CAAC,CAAC;YACrE,CAAC;YAED,MAAM,MAAM,GAA+B,EAAE,CAAC;YAC9C,KAAK,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACzB,SAAS;gBACV,CAAC;gBAED,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAED,OAAM,CAAC,MAAM,CAAC,CAAC;QAChB,CAAC;QAED,OAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,4BAA4B,EAAE,CAAC;QACzE,MAAK,CAAC,IAAI,gBAAgB,CAAC,yDAAyD,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,OAAM,CAAC,CAAE,SAAS,CAAE,CAAC,CAAC;AACvB,CAAC;AAYD,MAAM,UAAU,UAAU,CAAC,OAA0B,EAAE,IAAc,EAAE,KAAc,EAAE,SAAyB;IAC/G,KAAK,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;IAC9B,SAAS,KAAK,IAAI,IAAI,EAAE,CAAC;IAEzB,IAAI,eAAuB,CAAC;IAC5B,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QACnC,eAAe,GAAG,SAAS,CAAC;IAC7B,CAAC;SAAM,CAAC;QACP,eAAe,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,KAAK,GAAwB;QAClC,KAAK;QACL,eAAe;QACf,OAAO,CAAC,gBAAgB;KACxB,CAAC;IAEF,MAAM,MAAM,GAAoC;QAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;QAChC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa;KACjD,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACP,WAAW,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACF,CAAC;IAED;;OAEG;IACH,aAAa;IACb,mEAAmE;IACnE,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxF,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEzE,OAAM,CAAC;QACN,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,eAAe;QAC1B,gBAAgB,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;KACnE,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB,EAAE,IAAc;IACtE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAE5E,OAAM,CAAC;QACN,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;KACnD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,OAA0B,EAC1B,IAAc,EACd,MAA4C,EAC5C,OAAuB;IAEvB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC;IACzC,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5C;;;;;;;OAOG;IACH,IAAI,SAAS,CAAC,WAAW,EAAE,KAAK,eAAe,EAAE,CAAC;QACjD,OAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACtD,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,IAAI,IAAI,EAAE,CAAC;IAC3D,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC;QACzE,wDAAwD;QACxD,OAAM,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,mGAAmG;IACnG,MAAM,EAAE,gBAAgB,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;IAE/E,OAAM,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACvJ,CAAC","sourcesContent":["import { lib as KeetaNetLib } from '@keetanetwork/keetanet-client';\nimport type {\n\tValidateASN1 as KeetaNetASN1Validation,\n\tASN1AnyJS as KeetaNetASN1AnyJS\n} from '@keetanetwork/keetanet-client/lib/utils/asn1.js';\n\nimport { Buffer, bufferToArrayBuffer, arrayBufferLikeToBuffer } from '../../lib/utils/buffer.js';\nimport crypto from '../../lib/utils/crypto.js';\nimport { assertNever } from '../../lib/utils/never.js';\nimport { KeetaAnchorError } from '../error.js';\n\nexport type SignableAccount = ReturnType<InstanceType<typeof KeetaNetLib.Account>['assertAccount']>;\nexport type VerifiableAccount = InstanceType<typeof KeetaNetLib.Account>;\nexport type Signable = (string | number | bigint | InstanceType<typeof KeetaNetLib.Account>)[];\n\n/**\n * Structural input to {@link objectToSignable}.\n */\nexport type SignableInput =\n\t{ [key: string | number | symbol]: unknown } |\n\tSignableInput[] |\n\tSignable[number] |\n\tundefined |\n\tnull |\n\tboolean;\n\nconst TO_SIGNABLE_MAX_NODES = 1000;\nconst TO_SIGNABLE_MAX_OUTPUT_BYTES = 65536;\n\n/**\n * Detects unpaired UTF-16 surrogate code units. JCS\n * ({@link https://www.rfc-editor.org/rfc/rfc8785 RFC 8785} Section 3.2.2.2)\n * requires implementations to reject such strings.\n */\nconst LONE_SURROGATE_PATTERN = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/**\n * Serialize a JSON-shaped value following JCS\n * ({@link https://www.rfc-editor.org/rfc/rfc8785 RFC 8785}).\n */\nfunction canonicalizeJson(value: unknown): string {\n\t/**\n\t * Literal serialization (Section 3.2.2.1).\n\t */\n\tif (value === null || typeof value === 'boolean') {\n\t\treturn(JSON.stringify(value));\n\t}\n\n\t/**\n\t * String serialization (Section 3.2.2.2). Lone UTF-16 surrogates MUST cause termination.\n\t */\n\tif (typeof value === 'string') {\n\t\tif (LONE_SURROGATE_PATTERN.test(value)) {\n\t\t\tthrow(new KeetaAnchorError('Lone UTF-16 surrogate in canonicalizeJson'));\n\t\t}\n\n\t\treturn(JSON.stringify(value));\n\t}\n\n\t/**\n\t * Number serialization (Section 3.2.2.3). NaN and Infinity MUST cause termination.\n\t */\n\tif (typeof value === 'number') {\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow(new KeetaAnchorError('non-finite number in canonicalizeJson'));\n\t\t}\n\n\t\treturn(JSON.stringify(value));\n\t}\n\n\t/**\n\t * Big integer serialization (Appendix D); I-JSON safe-integer range required.\n\t */\n\tif (typeof value === 'bigint') {\n\t\tif (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {\n\t\t\tthrow(new KeetaAnchorError('bigint out of safe integer range in canonicalizeJson'));\n\t\t}\n\n\t\treturn(value.toString());\n\t}\n\n\t/**\n\t * Array element order MUST NOT be changed (Section 3.2.3); sparse holes serialize as JSON `null`.\n\t */\n\tif (Array.isArray(value)) {\n\t\tconst parts: string[] = [];\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\tparts.push(i in value ? canonicalizeJson(value[i]) : 'null');\n\t\t}\n\n\t\treturn(`[${parts.join(',')}]`);\n\t}\n\n\t/**\n\t * Object property sorting by UTF-16 code unit (Section 3.2.3); recursion required.\n\t * Only plain objects are permitted; class instances (Date, Map, etc.) are rejected.\n\t */\n\tif (typeof value === 'object') {\n\t\tif (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {\n\t\t\tthrow(new KeetaAnchorError('Non-plain object in canonicalizeJson'));\n\t\t}\n\n\t\tconst entries = Object.entries(value);\n\t\tfor (const [ key ] of entries) {\n\t\t\tif (LONE_SURROGATE_PATTERN.test(key)) {\n\t\t\t\tthrow(new KeetaAnchorError('Lone UTF-16 surrogate in object key'));\n\t\t\t}\n\t\t}\n\n\t\tentries.sort(([ a ], [ b ]) => {\n\t\t\tif (a < b) {\n\t\t\t\treturn(-1);\n\t\t\t}\n\t\t\tif (a > b) {\n\t\t\t\treturn(1);\n\t\t\t}\n\n\t\t\treturn(0);\n\t\t});\n\n\t\tconst parts: string[] = [];\n\t\tfor (const [ key, child ] of entries) {\n\t\t\tparts.push(`${JSON.stringify(key)}:${canonicalizeJson(child)}`);\n\t\t}\n\n\t\treturn(`{${parts.join(',')}}`);\n\t}\n\n\tthrow(new KeetaAnchorError('Unsupported value type in canonicalizeJson'));\n}\n\n/**\n * Canonicalize a tree into a {@link Signable} via {@link canonicalizeJson}.\n * {@link KeetaNetLib.Account} instances are replaced by their `publicKeyAndTypeString`.\n * {@link Date} instances are replaced by their ISO 8601 string.\n */\nexport function objectToSignable(item: SignableInput): Signable {\n\tlet nodeCount = 0;\n\tfunction visit(value: unknown): unknown {\n\t\tnodeCount++;\n\t\tif (nodeCount > TO_SIGNABLE_MAX_NODES) {\n\t\t\tthrow(new KeetaAnchorError('Too much data to sign in objectToSignable'));\n\t\t}\n\n\t\tif (value === undefined || value === null) {\n\t\t\treturn(null);\n\t\t}\n\t\tif (value instanceof Date) {\n\t\t\tif (Number.isNaN(value.valueOf())) {\n\t\t\t\tthrow(new KeetaAnchorError('Invalid Date in objectToSignable'));\n\t\t\t}\n\n\t\t\treturn(value.toISOString());\n\t\t}\n\t\tif (KeetaNetLib.Account.isInstance(value)) {\n\t\t\treturn(value.publicKeyAndTypeString);\n\t\t}\n\t\tif (Array.isArray(value)) {\n\t\t\tif (value.length > TO_SIGNABLE_MAX_NODES - nodeCount) {\n\t\t\t\tthrow(new KeetaAnchorError('Too much data to sign in objectToSignable'));\n\t\t\t}\n\n\t\t\tconst result: unknown[] = [];\n\t\t\tfor (const child of value) {\n\t\t\t\tresult.push(visit(child));\n\t\t\t}\n\n\t\t\treturn(result);\n\t\t}\n\t\tif (typeof value === 'object') {\n\t\t\tif (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {\n\t\t\t\tthrow(new KeetaAnchorError('Non-plain object in objectToSignable'));\n\t\t\t}\n\n\t\t\tconst result: { [key: string]: unknown } = {};\n\t\t\tfor (const [ key, child ] of Object.entries(value)) {\n\t\t\t\tif (child === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tresult[key] = visit(child);\n\t\t\t}\n\n\t\t\treturn(result);\n\t\t}\n\n\t\treturn(value);\n\t}\n\n\tconst canonical = canonicalizeJson(visit(item));\n\tif (Buffer.byteLength(canonical, 'utf8') > TO_SIGNABLE_MAX_OUTPUT_BYTES) {\n\t\tthrow(new KeetaAnchorError('Canonical output exceeds size limit in objectToSignable'));\n\t}\n\n\treturn([ canonical ]);\n}\n\n/**\n * Options for signature verification\n */\nexport interface VerifyOptions {\n\t/** Maximum allowed time difference in milliseconds (default: 5 * 60 * 1000 = 5 minutes) */\n\tmaxSkewMs?: number;\n\t/** Reference time for skew calculation (default: new Date()) */\n\treferenceTime?: Date;\n}\n\nexport function FormatData(account: VerifiableAccount, data: Signable, nonce?: string, timestamp?: string | Date): { nonce: string; timestamp: string; verificationData: Buffer; } {\n\tnonce ??= crypto.randomUUID();\n\ttimestamp ??= new Date();\n\n\tlet timestampString: string;\n\tif (typeof timestamp === 'string') {\n\t\ttimestampString = timestamp;\n\t} else {\n\t\ttimestampString = timestamp.toISOString();\n\t}\n\n\tconst input: KeetaNetASN1AnyJS[] = [\n\t\tnonce,\n\t\ttimestampString,\n\t\taccount.publicKeyAndType\n\t];\n\n\tconst schema: KeetaNetASN1Validation.Schema[] = [\n\t\t{ type: 'string', kind: 'utf8' },\n\t\t{ type: 'string', kind: 'utf8' },\n\t\tKeetaNetLib.Utils.ASN1.ValidateASN1.IsOctetString\n\t];\n\n\tfor (const item of data) {\n\t\tif (typeof item === 'string') {\n\t\t\tinput.push(item);\n\t\t\tschema.push({ type: 'string', kind: 'utf8' });\n\t\t} else if (typeof item === 'number' || typeof item === 'bigint') {\n\t\t\tinput.push(item);\n\t\t\tschema.push(KeetaNetLib.Utils.ASN1.ValidateASN1.IsInteger);\n\t\t} else if (KeetaNetLib.Account.isInstance(item)) {\n\t\t\tinput.push(item.publicKeyAndType);\n\t\t\tschema.push(KeetaNetLib.Utils.ASN1.ValidateASN1.IsOctetString);\n\t\t} else {\n\t\t\tassertNever(item);\n\t\t}\n\t}\n\n\t/*\n\t * Verify that the generated ASN.1 data matches the expected schema before returning it.\n\t */\n\t// @ts-ignore\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\tconst inputCanonical = KeetaNetLib.Utils.ASN1.ValidateASN1.againstSchema(input, schema);\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\tconst verificationData = KeetaNetLib.Utils.ASN1.JStoASN1(inputCanonical);\n\n\treturn({\n\t\tnonce: nonce,\n\t\ttimestamp: timestampString,\n\t\tverificationData: arrayBufferLikeToBuffer(verificationData.toBER())\n\t});\n}\n\nexport async function SignData(account: SignableAccount, data: Signable): Promise<{ nonce: string; timestamp: string; signature: string; }> {\n\tconst { nonce, timestamp, verificationData } = FormatData(account, data);\n\tconst signature = await account.sign(bufferToArrayBuffer(verificationData));\n\n\treturn({\n\t\tnonce: nonce,\n\t\ttimestamp: timestamp,\n\t\tsignature: signature.getBuffer().toString('base64')\n\t});\n}\n\nexport async function VerifySignedData(\n\taccount: VerifiableAccount,\n\tdata: Signable,\n\tsigned: Awaited<ReturnType<typeof SignData>>,\n\toptions?: VerifyOptions\n): Promise<boolean> {\n\tconst nonce = signed.nonce;\n\tconst timestampString = signed.timestamp;\n\tconst signatureBuffer = Buffer.from(signed.signature, 'base64');\n\n\tconst timestamp = new Date(timestampString);\n\t/*\n\t * Enforce that the timestamp string is in valid ISO 8601 format,\n\t * not just a date that can be parsed\n\t *\n\t * XXX:TODO: This is not a perfect check since ISO 8601 does not require millisecond-level\n\t * precision and technically allows other timezones (though we will not support\n\t * those). This will be changed in the future to be more robust.\n\t */\n\tif (timestamp.toISOString() !== timestampString) {\n\t\treturn(false);\n\t}\n\n\tconst maxSkewMs = options?.maxSkewMs ?? 5 * 60 * 1000;\n\tconst referenceTime = options?.referenceTime ?? new Date();\n\tif (Math.abs(timestamp.valueOf() - referenceTime.valueOf()) > maxSkewMs) {\n\t\t/* Timestamp exceeds allowed skew from reference time */\n\t\treturn(false);\n\t}\n\n\t/* XXX:TODO: Verify that the timestamp is a valid ISO 8601 date string within a reasonable range */\n\tconst { verificationData } = FormatData(account, data, nonce, timestampString);\n\n\treturn(account.verify(KeetaNetLib.Utils.Helper.bufferToArrayBuffer(verificationData), KeetaNetLib.Utils.Helper.bufferToArrayBuffer(signatureBuffer)));\n}\n"]}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keetanetwork/anchor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@keetanetwork/anchor",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.63",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@keetanetwork/currency-info": "1.2.5",
|
|
13
|
-
"@keetanetwork/keetanet-client": "0.16.
|
|
13
|
+
"@keetanetwork/keetanet-client": "0.16.2",
|
|
14
14
|
"typia": "9.5.0"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
@@ -185,8 +185,8 @@
|
|
|
185
185
|
"license": "ISC"
|
|
186
186
|
},
|
|
187
187
|
"node_modules/@keetanetwork/keetanet-client": {
|
|
188
|
-
"version": "0.16.
|
|
189
|
-
"integrity": "sha512-
|
|
188
|
+
"version": "0.16.2",
|
|
189
|
+
"integrity": "sha512-ifhICBG8k4r1Fyi+SaMgu9DUCIHuu5iV/YVmn2NKCwF7U+6kOoEJeRgrVyan9Vd8tF+xHtrj2O8dIwAWu44x9w==",
|
|
190
190
|
"license": "see LICENSE",
|
|
191
191
|
"dependencies": {
|
|
192
192
|
"secp256k1": "5.0.1"
|
|
@@ -218,8 +218,8 @@
|
|
|
218
218
|
"optional": true
|
|
219
219
|
},
|
|
220
220
|
"node_modules/@protobufjs/codegen": {
|
|
221
|
-
"version": "2.0.
|
|
222
|
-
"integrity": "sha512-
|
|
221
|
+
"version": "2.0.5",
|
|
222
|
+
"integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
|
|
223
223
|
"license": "BSD-3-Clause",
|
|
224
224
|
"optional": true
|
|
225
225
|
},
|
|
@@ -246,8 +246,8 @@
|
|
|
246
246
|
"optional": true
|
|
247
247
|
},
|
|
248
248
|
"node_modules/@protobufjs/inquire": {
|
|
249
|
-
"version": "1.1.
|
|
250
|
-
"integrity": "sha512-
|
|
249
|
+
"version": "1.1.1",
|
|
250
|
+
"integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==",
|
|
251
251
|
"license": "BSD-3-Clause",
|
|
252
252
|
"optional": true
|
|
253
253
|
},
|
|
@@ -264,8 +264,8 @@
|
|
|
264
264
|
"optional": true
|
|
265
265
|
},
|
|
266
266
|
"node_modules/@protobufjs/utf8": {
|
|
267
|
-
"version": "1.1.
|
|
268
|
-
"integrity": "sha512-
|
|
267
|
+
"version": "1.1.1",
|
|
268
|
+
"integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==",
|
|
269
269
|
"license": "BSD-3-Clause",
|
|
270
270
|
"optional": true
|
|
271
271
|
},
|
|
@@ -1688,22 +1688,22 @@
|
|
|
1688
1688
|
}
|
|
1689
1689
|
},
|
|
1690
1690
|
"node_modules/protobufjs": {
|
|
1691
|
-
"version": "7.5.
|
|
1692
|
-
"integrity": "sha512-
|
|
1691
|
+
"version": "7.5.8",
|
|
1692
|
+
"integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==",
|
|
1693
1693
|
"hasInstallScript": true,
|
|
1694
1694
|
"license": "BSD-3-Clause",
|
|
1695
1695
|
"optional": true,
|
|
1696
1696
|
"dependencies": {
|
|
1697
1697
|
"@protobufjs/aspromise": "^1.1.2",
|
|
1698
1698
|
"@protobufjs/base64": "^1.1.2",
|
|
1699
|
-
"@protobufjs/codegen": "^2.0.
|
|
1699
|
+
"@protobufjs/codegen": "^2.0.5",
|
|
1700
1700
|
"@protobufjs/eventemitter": "^1.1.0",
|
|
1701
1701
|
"@protobufjs/fetch": "^1.1.0",
|
|
1702
1702
|
"@protobufjs/float": "^1.0.2",
|
|
1703
|
-
"@protobufjs/inquire": "^1.1.
|
|
1703
|
+
"@protobufjs/inquire": "^1.1.1",
|
|
1704
1704
|
"@protobufjs/path": "^1.1.2",
|
|
1705
1705
|
"@protobufjs/pool": "^1.1.0",
|
|
1706
|
-
"@protobufjs/utf8": "^1.1.
|
|
1706
|
+
"@protobufjs/utf8": "^1.1.1",
|
|
1707
1707
|
"@types/node": ">=13.7.0",
|
|
1708
1708
|
"long": "^5.0.0"
|
|
1709
1709
|
},
|
|
@@ -1924,8 +1924,8 @@
|
|
|
1924
1924
|
}
|
|
1925
1925
|
},
|
|
1926
1926
|
"node_modules/teeny-request/node_modules/@tootallnate/once": {
|
|
1927
|
-
"version": "2.0.
|
|
1928
|
-
"integrity": "sha512-
|
|
1927
|
+
"version": "2.0.1",
|
|
1928
|
+
"integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==",
|
|
1929
1929
|
"license": "MIT",
|
|
1930
1930
|
"optional": true,
|
|
1931
1931
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keetanetwork/anchor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.63",
|
|
4
4
|
"description": "KeetaNetwork Network Anchor",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@keetanetwork/currency-info": "1.2.5",
|
|
27
|
-
"@keetanetwork/keetanet-client": "0.16.
|
|
27
|
+
"@keetanetwork/keetanet-client": "0.16.2",
|
|
28
28
|
"typia": "9.5.0"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|