Skip to content

Commit c4f2b5c

Browse files
authored
Merge pull request #674 from LIT-Protocol/feat/session-sigs-reader
feat: add session sigs formatter/reader
2 parents 99c24d6 + 021e1dc commit c4f2b5c

File tree

5 files changed

+187
-1
lines changed

5 files changed

+187
-1
lines changed

packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { safeParams } from '@lit-protocol/encryption';
4141
import {
4242
defaultMintClaimCallback,
4343
findMostCommonResponse,
44+
formatSessionSigs,
4445
hexPrefixed,
4546
log,
4647
logError,
@@ -2202,6 +2203,16 @@ export class LitNodeClientNodeJs
22022203

22032204
log('signatures:', signatures);
22042205

2206+
try {
2207+
const formattedSessionSigs = formatSessionSigs(
2208+
JSON.stringify(signatures)
2209+
);
2210+
log(formattedSessionSigs);
2211+
} catch (e) {
2212+
// swallow error
2213+
log('Error formatting session signatures: ', e);
2214+
}
2215+
22052216
return signatures;
22062217
};
22072218

packages/misc/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export {
33
validateSessionSig,
44
validateSessionSigs,
55
} from './lib/helper/session-sigs-validator';
6+
export { formatSessionSigs } from './lib/helper/session-sigs-reader';
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { formatSessionSigs } from './session-sigs-reader';
2+
3+
describe('formatSessionSigs', () => {
4+
it('should format session signatures correctly', () => {
5+
const sessionSigs = {
6+
'https://184.107.182.142:443': {
7+
sig: 'b255b9665541af52215e80f94debee56b3d46431f3b292c54c21b49c9236b800b39c6ec18544a5a80546c2b2216816ca0b989e8ef0bef7e0e429e2645af49b04',
8+
derivedVia: 'litSessionSignViaNacl',
9+
signedMessage:
10+
'{"sessionKey":"85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b","resourceAbilityRequests":[{"resource":{"resource":"*","resourcePrefix":"lit-pkp"},"ability":"pkp-signing"},{"resource":{"resource":"*","resourcePrefix":"lit-litaction"},"ability":"lit-action-execution"}],"capabilities":[{"sig":"0x5bf4189b3447f8b54bcac05fb3e47713641ca588ac9bf196b993468d45a1dfd456d7e9dff1f86f71db68f47d2c84c8cfe84d81c12fce13396f09e7a301eb19a81c","derivedVia":"web3.eth.personal.sign","signedMessage":"localhost wants you to sign in with your Ethereum account:\\n0x3B5dD260598B7579A0b015A1F3BBF322aDC499A1\\n\\nThis is a test statement. You can put anything you want here. I further authorize the stated URI to perform the following actions on my behalf: (1) \'Auth\': \'Auth\' for \'lit-ratelimitincrease://24353\'.\\n\\nURI: lit:capability:delegation\\nVersion: 1\\nChain ID: 1\\nNonce: 0x525df2ace4421a53c2e237f22e1632d8d98fd3bd9ceed2cbb55ec0e2807ef68c\\nIssued At: 2024-10-04T17:46:42.220Z\\nExpiration Time: 2024-10-11T17:46:42.217Z\\nResources:\\n- urn:recap:eyJhdHQiOnsibGl0LXJhdGVsaW1pdGluY3JlYXNlOi8vMjQzNTMiOnsiQXV0aC9BdXRoIjpbeyJkZWxlZ2F0ZV90byI6WyI4MzU1ZjA0NzBlNTU5MDhCMWYwNDY3RTZhMTU3RjY0QjczRkQzQWU2Il0sIm5mdF9pZCI6WyIyNDM1MyJdLCJ1c2VzIjoiMSJ9XX19LCJwcmYiOltdfQ","address":"0x3B5dD260598B7579A0b015A1F3BBF322aDC499A1"},{"sig":"{\\"ProofOfPossession\\":\\"abe6ac4c0847f0e1e5453d63623625615b1e26db3f0296f5e6a1450527cf51431dbb671c8983bd6eae299980da84f5220d723af102792fc32e8b72eb01b97611638d9a8fc2e3fcf5c32fb9628e4546f5f56a229108ad0751609c301abb1f2006\\"}","algo":"LIT_BLS","derivedVia":"lit.bls","signedMessage":"localhost:5173 wants you to sign in with your Ethereum account:\\n0x8355f0470e55908B1f0467E6a157F64B73FD3Ae6\\n\\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) \'Threshold\': \'Execution\' for \'lit-litaction://*\'. (2) \'Threshold\': \'Signing\' for \'lit-pkp://*\'. I further authorize the stated URI to perform the following actions on my behalf: (1) \'Threshold\': \'Execution\' for \'lit-litaction://*\'. (2) \'Threshold\': \'Signing\' for \'lit-pkp://*\'. (3) \'Auth\': \'Auth\' for \'lit-resolvedauthcontext://*\'.\\n\\nURI: lit:session:85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b\\nVersion: 1\\nChain ID: 1\\nNonce: 0x525df2ace4421a53c2e237f22e1632d8d98fd3bd9ceed2cbb55ec0e2807ef68c\\nIssued At: 2024-10-04T17:46:23Z\\nExpiration Time: 2024-10-05T17:46:54.631Z\\nResources:\\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZOW11Wm5GMVNOQ1pBSGZQWTZRUU41dlM3ekFGWkhLTGtURTN1b3h0Q3ZlOSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOltdLCJhdXRoU2lnQWRkcmVzcyI6bnVsbCwiY3VzdG9tQXV0aFJlc291cmNlIjoidHJ1ZSIsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0"}],"issuedAt":"2024-10-04T17:46:55.477Z","expiration":"2024-10-05T17:46:54.631Z","nodeAddress":"https://184.107.182.142:443"}',
11+
address:
12+
'85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b',
13+
algo: 'ed25519',
14+
},
15+
};
16+
17+
const currentTime = new Date('2022-01-01T06:00:00Z');
18+
const formattedSessionSigs = formatSessionSigs(
19+
JSON.stringify(sessionSigs),
20+
currentTime
21+
);
22+
23+
const expectedOutput = `The request time is at: 2022-01-01T06:00:00.000Z
24+
* Outer expiration:
25+
* Issued at: 2024-10-04T17:46:55.477Z
26+
* Expiration: 2024-10-05T17:46:54.631Z
27+
* Duration: 23 hours, 59 minutes, 59.154 seconds
28+
* Status: ✅ Not expired (valid for 1008 days)
29+
* Capabilities:
30+
* Capability 1 (web3.eth.personal.sign):
31+
* Issued at: 2024-10-04T17:46:42.220Z
32+
* Expiration: 2024-10-11T17:46:42.217Z
33+
* Duration: 6 days
34+
* Status: ✅ Not expired (valid for 1014 days)
35+
* Capability 2 (lit.bls):
36+
* Issued at: 2024-10-04T17:46:23.000Z
37+
* Expiration: 2024-10-05T17:46:54.631Z
38+
* Duration: 1 days
39+
* Status: ✅ Not expired (valid for 1008 days)
40+
`;
41+
expect(formattedSessionSigs).toBe(expectedOutput);
42+
});
43+
44+
it('should handle expired session signatures correctly', () => {
45+
const sessionSigs = {
46+
'https://184.107.182.142:443': {
47+
sig: 'b255b9665541af52215e80f94debee56b3d46431f3b292c54c21b49c9236b800b39c6ec18544a5a80546c2b2216816ca0b989e8ef0bef7e0e429e2645af49b04',
48+
derivedVia: 'litSessionSignViaNacl',
49+
signedMessage:
50+
'{"sessionKey":"85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b","resourceAbilityRequests":[{"resource":{"resource":"*","resourcePrefix":"lit-pkp"},"ability":"pkp-signing"},{"resource":{"resource":"*","resourcePrefix":"lit-litaction"},"ability":"lit-action-execution"}],"capabilities":[{"sig":"0x5bf4189b3447f8b54bcac05fb3e47713641ca588ac9bf196b993468d45a1dfd456d7e9dff1f86f71db68f47d2c84c8cfe84d81c12fce13396f09e7a301eb19a81c","derivedVia":"web3.eth.personal.sign","signedMessage":"localhost wants you to sign in with your Ethereum account:\\n0x3B5dD260598B7579A0b015A1F3BBF322aDC499A1\\n\\nThis is a test statement. You can put anything you want here. I further authorize the stated URI to perform the following actions on my behalf: (1) \'Auth\': \'Auth\' for \'lit-ratelimitincrease://24353\'.\\n\\nURI: lit:capability:delegation\\nVersion: 1\\nChain ID: 1\\nNonce: 0x525df2ace4421a53c2e237f22e1632d8d98fd3bd9ceed2cbb55ec0e2807ef68c\\nIssued At: 2022-10-04T17:46:42.220Z\\nExpiration Time: 2022-10-11T17:46:42.217Z\\nResources:\\n- urn:recap:eyJhdHQiOnsibGl0LXJhdGVsaW1pdGluY3JlYXNlOi8vMjQzNTMiOnsiQXV0aC9BdXRoIjpbeyJkZWxlZ2F0ZV90byI6WyI4MzU1ZjA0NzBlNTU5MDhCMWYwNDY3RTZhMTU3RjY0QjczRkQzQWU2Il0sIm5mdF9pZCI6WyIyNDM1MyJdLCJ1c2VzIjoiMSJ9XX19LCJwcmYiOltdfQ","address":"0x3B5dD260598B7579A0b015A1F3BBF322aDC499A1"},{"sig":"{\\"ProofOfPossession\\":\\"abe6ac4c0847f0e1e5453d63623625615b1e26db3f0296f5e6a1450527cf51431dbb671c8983bd6eae299980da84f5220d723af102792fc32e8b72eb01b97611638d9a8fc2e3fcf5c32fb9628e4546f5f56a229108ad0751609c301abb1f2006\\"}","algo":"LIT_BLS","derivedVia":"lit.bls","signedMessage":"localhost:5173 wants you to sign in with your Ethereum account:\\n0x8355f0470e55908B1f0467E6a157F64B73FD3Ae6\\n\\nLit Protocol PKP session signature I further authorize the stated URI to perform the following actions on my behalf: I further authorize the stated URI to perform the following actions on my behalf: (1) \'Threshold\': \'Execution\' for \'lit-litaction://*\'. (2) \'Threshold\': \'Signing\' for \'lit-pkp://*\'. I further authorize the stated URI to perform the following actions on my behalf: (1) \'Threshold\': \'Execution\' for \'lit-litaction://*\'. (2) \'Threshold\': \'Signing\' for \'lit-pkp://*\'. (3) \'Auth\': \'Auth\' for \'lit-resolvedauthcontext://*\'.\\n\\nURI: lit:session:85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b\\nVersion: 1\\nChain ID: 1\\nNonce: 0x525df2ace4421a53c2e237f22e1632d8d98fd3bd9ceed2cbb55ec0e2807ef68c\\nIssued At: 2022-10-04T17:46:23Z\\nExpiration Time: 2022-10-05T17:46:54.631Z\\nResources:\\n- urn:recap:eyJhdHQiOnsibGl0LWxpdGFjdGlvbjovLyoiOnsiVGhyZXNob2xkL0V4ZWN1dGlvbiI6W3t9XX0sImxpdC1wa3A6Ly8qIjp7IlRocmVzaG9sZC9TaWduaW5nIjpbe31dfSwibGl0LXJlc29sdmVkYXV0aGNvbnRleHQ6Ly8qIjp7IkF1dGgvQXV0aCI6W3siYXV0aF9jb250ZXh0Ijp7ImFjdGlvbklwZnNJZHMiOlsiUW1ZOW11Wm5GMVNOQ1pBSGZQWTZRUU41dlM3ekFGWkhLTGtURTN1b3h0Q3ZlOSJdLCJhdXRoTWV0aG9kQ29udGV4dHMiOltdLCJhdXRoU2lnQWRkcmVzcyI6bnVsbCwiY3VzdG9tQXV0aFJlc291cmNlIjoidHJ1ZSIsInJlc291cmNlcyI6W119fV19fSwicHJmIjpbXX0"}],"issuedAt":"2022-10-04T17:46:55.477Z","expiration":"2022-10-05T17:46:54.631Z","nodeAddress":"https://184.107.182.142:443"}',
51+
address:
52+
'85a6d21d91d95f7e4c849d73ae0dc1f80e8d5a3a2a6334c73c683817bdb89c0b',
53+
algo: 'ed25519',
54+
},
55+
};
56+
57+
const currentTime = new Date('2024-01-01T06:00:00Z');
58+
const formattedSessionSigs = formatSessionSigs(
59+
JSON.stringify(sessionSigs),
60+
currentTime
61+
);
62+
63+
const expectedOutput = `The request time is at: 2024-01-01T06:00:00.000Z
64+
* Outer expiration:
65+
* Issued at: 2022-10-04T17:46:55.477Z
66+
* Expiration: 2022-10-05T17:46:54.631Z
67+
* Duration: 23 hours, 59 minutes, 59.154 seconds
68+
* Status: ❌ Expired (expired 452 days ago)
69+
* Capabilities:
70+
* Capability 1 (web3.eth.personal.sign):
71+
* Issued at: 2022-10-04T17:46:42.220Z
72+
* Expiration: 2022-10-11T17:46:42.217Z
73+
* Duration: 6 days
74+
* Status: ❌ Expired (expired 446 days ago)
75+
* Capability 2 (lit.bls):
76+
* Issued at: 2022-10-04T17:46:23.000Z
77+
* Expiration: 2022-10-05T17:46:54.631Z
78+
* Duration: 1 days
79+
* Status: ❌ Expired (expired 452 days ago)
80+
`;
81+
expect(formattedSessionSigs).toBe(expectedOutput);
82+
});
83+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { parseSignedMessage } from './session-sigs-validator';
2+
3+
function formatDuration(start: Date, end: Date): string {
4+
const diff = end.getTime() - start.getTime();
5+
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
6+
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
7+
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
8+
const seconds = ((diff % (1000 * 60)) / 1000).toFixed(3);
9+
10+
let elapsedTime: string;
11+
12+
if (days > 0) {
13+
elapsedTime = `${days} days`;
14+
} else if (hours > 0) {
15+
elapsedTime = `${hours} hours, ${minutes} minutes, ${seconds} seconds`;
16+
} else {
17+
elapsedTime = `${minutes} minutes, ${seconds} seconds`;
18+
}
19+
20+
return elapsedTime;
21+
}
22+
23+
function formatStatus(expirationDate: Date, currentDate: Date): string {
24+
if (expirationDate > currentDate) {
25+
const timeLeft = formatDuration(currentDate, expirationDate);
26+
return `✅ Not expired (valid for ${timeLeft})`;
27+
} else {
28+
const timeAgo = formatDuration(expirationDate, currentDate);
29+
return `❌ Expired (expired ${timeAgo} ago)`;
30+
}
31+
}
32+
33+
export function formatSessionSigs(
34+
sessionSigs: string,
35+
currentTime: Date = new Date()
36+
): string {
37+
const parsedSigs = JSON.parse(sessionSigs);
38+
const firstNodeKey = Object.keys(parsedSigs)[0];
39+
const firstNode = parsedSigs[firstNodeKey];
40+
let signedMessage;
41+
42+
try {
43+
signedMessage = JSON.parse(firstNode.signedMessage);
44+
} catch (error: unknown) {
45+
const errorMessage =
46+
error instanceof Error ? error.message : 'Unknown error';
47+
throw new Error(`Invalid JSON format for signedMessage: ${errorMessage}`);
48+
}
49+
50+
const currentDate = new Date(currentTime);
51+
52+
let result = `The request time is at: ${currentDate.toISOString()}\n`;
53+
54+
// Outer expiration
55+
let issuedAt, expiration;
56+
try {
57+
issuedAt = new Date(signedMessage.issuedAt);
58+
expiration = new Date(signedMessage.expiration);
59+
} catch (error) {
60+
const errorMessage =
61+
error instanceof Error ? error.message : 'Unknown error';
62+
throw new Error(`Error parsing issuedAt or expiration: ${errorMessage}`);
63+
}
64+
65+
result += '* Outer expiration:\n';
66+
result += ` * Issued at: ${issuedAt.toISOString()}\n`;
67+
result += ` * Expiration: ${expiration.toISOString()}\n`;
68+
result += ` * Duration: ${formatDuration(issuedAt, expiration)}\n`;
69+
result += ` * Status: ${formatStatus(expiration, currentDate)}\n`;
70+
71+
// Capabilities
72+
result += '* Capabilities:\n';
73+
signedMessage.capabilities.forEach((cap: any, index: number) => {
74+
const capType = cap.derivedVia;
75+
const parsedCapMessage = parseSignedMessage(cap.signedMessage);
76+
77+
const capIssuedAt = new Date(parsedCapMessage['Issued At'] || '');
78+
const capExpiration = new Date(parsedCapMessage['Expiration Time'] || '');
79+
80+
result += ` * Capability ${index + 1} (${capType}):\n`;
81+
result += ` * Issued at: ${capIssuedAt.toISOString()}\n`;
82+
result += ` * Expiration: ${capExpiration.toISOString()}\n`;
83+
result += ` * Duration: ${formatDuration(
84+
capIssuedAt,
85+
capExpiration
86+
)}\n`;
87+
result += ` * Status: ${formatStatus(capExpiration, currentDate)}\n`;
88+
});
89+
90+
return result;
91+
}

packages/misc/src/lib/helper/session-sigs-validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interface ValidationResult {
1212
}
1313

1414
// Function to parse a signedMessage string into an object
15-
function parseSignedMessage(signedMessage: string): ParsedSignedMessage {
15+
export function parseSignedMessage(signedMessage: string): ParsedSignedMessage {
1616
const lines = signedMessage.split('\n');
1717
const parsedData: ParsedSignedMessage = {};
1818
let currentKey: string | null = null as string | null;

0 commit comments

Comments
 (0)