@koralabs/kora-labs-common 6.4.25 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/utils/cip8/index.d.ts +14 -0
- package/utils/cip8/index.js +95 -0
- package/utils/crypto/index.d.ts +1 -0
- package/utils/crypto/index.js +16 -1
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koralabs/kora-labs-common",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0",
|
|
4
4
|
"description": "Kora Labs Common Utilities",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@aws-sdk/client-kms": "^3.1003.0",
|
|
43
|
+
"@emurgo/cardano-message-signing-nodejs": "^1.0.1",
|
|
43
44
|
"bech32": "^2.0.0",
|
|
44
45
|
"blakejs": "^1.2.1",
|
|
45
46
|
"boolean": "^3.2.0",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a CIP-30 signData (CIP-8) signature.
|
|
3
|
+
*
|
|
4
|
+
* Parses the COSE structures produced by the wallet, reconstructs the
|
|
5
|
+
* SigStructure using the library (not manual CBOR), and verifies the
|
|
6
|
+
* Ed25519 signature with Node.js crypto.
|
|
7
|
+
*
|
|
8
|
+
* @param signatureCborHex - COSESign1 CBOR hex from wallet signData response
|
|
9
|
+
* @param publicKeyCborHex - COSEKey CBOR hex from wallet signData response
|
|
10
|
+
* @param expectedPayloadHex - hex of the expected signed payload (e.g. requestId + handle as UTF-8 bytes)
|
|
11
|
+
* @param expectedAddressHex - hex of the expected signing address (must match the address in the COSE protected headers)
|
|
12
|
+
* @returns true if the signature is valid
|
|
13
|
+
*/
|
|
14
|
+
export declare const verifyCip30SignData: (signatureCborHex: string, publicKeyCborHex: string, expectedPayloadHex: string, expectedAddressHex: string) => Promise<boolean>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
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]; } };
|
|
7
|
+
}
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.verifyCip30SignData = void 0;
|
|
27
|
+
const crypto_1 = require("crypto");
|
|
28
|
+
let _cms;
|
|
29
|
+
const getCms = async () => {
|
|
30
|
+
if (!_cms) {
|
|
31
|
+
_cms = await Promise.resolve().then(() => __importStar(require('@emurgo/cardano-message-signing-nodejs')));
|
|
32
|
+
}
|
|
33
|
+
return _cms;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Verify a CIP-30 signData (CIP-8) signature.
|
|
37
|
+
*
|
|
38
|
+
* Parses the COSE structures produced by the wallet, reconstructs the
|
|
39
|
+
* SigStructure using the library (not manual CBOR), and verifies the
|
|
40
|
+
* Ed25519 signature with Node.js crypto.
|
|
41
|
+
*
|
|
42
|
+
* @param signatureCborHex - COSESign1 CBOR hex from wallet signData response
|
|
43
|
+
* @param publicKeyCborHex - COSEKey CBOR hex from wallet signData response
|
|
44
|
+
* @param expectedPayloadHex - hex of the expected signed payload (e.g. requestId + handle as UTF-8 bytes)
|
|
45
|
+
* @param expectedAddressHex - hex of the expected signing address (must match the address in the COSE protected headers)
|
|
46
|
+
* @returns true if the signature is valid
|
|
47
|
+
*/
|
|
48
|
+
const verifyCip30SignData = async (signatureCborHex, publicKeyCborHex, expectedPayloadHex, expectedAddressHex) => {
|
|
49
|
+
var _a;
|
|
50
|
+
const cms = await getCms();
|
|
51
|
+
// Parse COSESign1 and COSEKey from wallet output
|
|
52
|
+
const coseSign1 = cms.COSESign1.from_bytes(Buffer.from(signatureCborHex, 'hex'));
|
|
53
|
+
const coseKey = cms.COSEKey.from_bytes(Buffer.from(publicKeyCborHex, 'hex'));
|
|
54
|
+
// Extract the address from the protected headers and verify it matches
|
|
55
|
+
const protectedHeaders = coseSign1.headers().protected().deserialized_headers();
|
|
56
|
+
const addressLabel = cms.Label.new_text('address');
|
|
57
|
+
const addressValue = protectedHeaders.header(addressLabel);
|
|
58
|
+
if (addressValue) {
|
|
59
|
+
const addressBytes = Buffer.from((_a = addressValue.as_bytes()) !== null && _a !== void 0 ? _a : new Uint8Array()).toString('hex');
|
|
60
|
+
if (addressBytes !== expectedAddressHex) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Verify the payload matches what we expect
|
|
65
|
+
const signedPayload = coseSign1.payload();
|
|
66
|
+
if (signedPayload) {
|
|
67
|
+
const payloadHex = Buffer.from(signedPayload).toString('hex');
|
|
68
|
+
if (payloadHex !== expectedPayloadHex) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Reconstruct the SigStructure (what was actually signed) using the library
|
|
73
|
+
const sigStructure = coseSign1.signed_data();
|
|
74
|
+
const sigStructureBytes = sigStructure.to_bytes();
|
|
75
|
+
// Extract the raw Ed25519 signature
|
|
76
|
+
const signatureBytes = coseSign1.signature();
|
|
77
|
+
// Extract the Ed25519 public key from COSEKey (label -2 is the "x" coordinate / public key)
|
|
78
|
+
const xLabel = cms.Label.new_int(cms.Int.new_i32(-2));
|
|
79
|
+
const pubKeyValue = coseKey.header(xLabel);
|
|
80
|
+
if (!pubKeyValue) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const pubKeyBytes = pubKeyValue.as_bytes();
|
|
84
|
+
if (!pubKeyBytes || pubKeyBytes.length !== 32) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
// Wrap the raw Ed25519 public key in DER SPKI format for Node.js crypto
|
|
88
|
+
const pubKeyDer = Buffer.concat([
|
|
89
|
+
Buffer.from('302a300506032b6570032100', 'hex'),
|
|
90
|
+
Buffer.from(pubKeyBytes)
|
|
91
|
+
]);
|
|
92
|
+
const keyObject = (0, crypto_1.createPublicKey)({ key: pubKeyDer, format: 'der', type: 'spki' });
|
|
93
|
+
return (0, crypto_1.verify)(null, Buffer.from(sigStructureBytes), keyObject, Buffer.from(signatureBytes));
|
|
94
|
+
};
|
|
95
|
+
exports.verifyCip30SignData = verifyCip30SignData;
|
package/utils/crypto/index.d.ts
CHANGED
|
@@ -23,4 +23,5 @@ export declare const bech32AddressFromHashes: (paymentHash: string, paymentHashT
|
|
|
23
23
|
export declare const buildHolderInfo: (addr: string) => AddressDetails;
|
|
24
24
|
export declare const getDateStringFromSlot: (currentSlot: number) => Date;
|
|
25
25
|
export declare const getSlotNumberFromDate: (date: Date) => number;
|
|
26
|
+
export declare const addressHexToBech32: (hex: string) => string;
|
|
26
27
|
export declare const blake2b: (input: string | Buffer | Uint8Array, outlen?: number) => string;
|
package/utils/crypto/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.blake2b = exports.getSlotNumberFromDate = exports.getDateStringFromSlot = exports.buildHolderInfo = exports.bech32AddressFromHashes = exports.bech32FromHex = exports.getPaymentKeyHash = exports.buildStakeKey = exports.buildPaymentAddressType = exports.getPaymentAddressType = exports.checkNameLabel = exports.parseAssetNameLabel = exports.decodeAddress = exports.getChallengeFromVerifier = exports.base64urlencode = exports.sha256 = exports.getRandomCodeVerifier = exports.dec2hex = exports.getNativeCrypto = void 0;
|
|
29
|
+
exports.blake2b = exports.addressHexToBech32 = exports.getSlotNumberFromDate = exports.getDateStringFromSlot = exports.buildHolderInfo = exports.bech32AddressFromHashes = exports.bech32FromHex = exports.getPaymentKeyHash = exports.buildStakeKey = exports.buildPaymentAddressType = exports.getPaymentAddressType = exports.checkNameLabel = exports.parseAssetNameLabel = exports.decodeAddress = exports.getChallengeFromVerifier = exports.base64urlencode = exports.sha256 = exports.getRandomCodeVerifier = exports.dec2hex = exports.getNativeCrypto = void 0;
|
|
30
30
|
const bech32_1 = require("bech32");
|
|
31
31
|
const blakejs_1 = require("blakejs");
|
|
32
32
|
const bs58_1 = __importDefault(require("bs58"));
|
|
@@ -271,6 +271,21 @@ const getSlotNumberFromDate = (date) => {
|
|
|
271
271
|
return (Math.floor(date.getTime() / 1000) - 1596491091) + 4924800;
|
|
272
272
|
};
|
|
273
273
|
exports.getSlotNumberFromDate = getSlotNumberFromDate;
|
|
274
|
+
const addressHexToBech32 = (hex) => {
|
|
275
|
+
const bytes = Uint8Array.from(Buffer.from(hex, 'hex'));
|
|
276
|
+
if (bytes.length === 0)
|
|
277
|
+
return '';
|
|
278
|
+
const header = bytes[0];
|
|
279
|
+
const addressType = header >> 4;
|
|
280
|
+
const networkId = header & 0x0f;
|
|
281
|
+
const isTestnet = networkId === 0;
|
|
282
|
+
const isReward = addressType === 14 || addressType === 15;
|
|
283
|
+
const type = isReward ? 'stake' : 'addr';
|
|
284
|
+
const prefix = isTestnet && (type === 'addr' || type === 'stake') ? `${type}_test` : type;
|
|
285
|
+
const words = bech32_1.bech32.toWords(bytes);
|
|
286
|
+
return bech32_1.bech32.encode(prefix, words, 2048);
|
|
287
|
+
};
|
|
288
|
+
exports.addressHexToBech32 = addressHexToBech32;
|
|
274
289
|
const blake2b = (input, outlen = 32) => {
|
|
275
290
|
if (typeof input == 'string') {
|
|
276
291
|
input = Buffer.from(input, 'hex');
|
package/utils/index.d.ts
CHANGED
|
@@ -30,4 +30,5 @@ export declare const isUserIssueTrackingId: (value: unknown) => value is string;
|
|
|
30
30
|
export declare const normalizeUserIssueEventSegment: (value: string) => string;
|
|
31
31
|
export declare const buildUserIssueEventKey: (repo: string, flow: string, pathOrFunction: string, step: string) => string;
|
|
32
32
|
export { decodeCborToJson, encodeJsonToDatum, DefaultTextFormat as KeyType } from './cbor';
|
|
33
|
+
export * from './cip8';
|
|
33
34
|
export * from './crypto';
|
package/utils/index.js
CHANGED
|
@@ -199,4 +199,5 @@ var cbor_1 = require("./cbor");
|
|
|
199
199
|
Object.defineProperty(exports, "decodeCborToJson", { enumerable: true, get: function () { return cbor_1.decodeCborToJson; } });
|
|
200
200
|
Object.defineProperty(exports, "encodeJsonToDatum", { enumerable: true, get: function () { return cbor_1.encodeJsonToDatum; } });
|
|
201
201
|
Object.defineProperty(exports, "KeyType", { enumerable: true, get: function () { return cbor_1.DefaultTextFormat; } });
|
|
202
|
+
__exportStar(require("./cip8"), exports);
|
|
202
203
|
__exportStar(require("./crypto"), exports);
|