Skip to content

Commit 243d4a1

Browse files
committed
feat(auth): add `createPkpSessionSigs
1 parent f044ae9 commit 243d4a1

File tree

2 files changed

+238
-9
lines changed

2 files changed

+238
-9
lines changed

packages/auth/src/lib/AuthManager/auth-manager.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getChildLogger } from '@lit-protocol/logger';
2+
import type { LitClient } from '@lit-protocol/lit-client';
23
import { AuthData, HexPrefixedSchema } from '@lit-protocol/schemas';
34
import { AuthSig, SessionKeyPair } from '@lit-protocol/types';
45
import { z } from 'zod';
@@ -14,6 +15,8 @@ import { getCustomAuthContextAdapter } from './authAdapters/getCustomAuthContext
1415
import { generatePkpDelegationAuthSig } from './authAdapters/generatePkpDelegationAuthSig';
1516
import { generateEoaDelegationAuthSig } from './authAdapters/generateEoaDelegationAuthSig';
1617
import { getPkpAuthContextFromPreGeneratedAdapter } from './authAdapters/getPkpAuthContextFromPreGeneratedAdapter';
18+
import type { PkpSessionSigsProduct } from './authAdapters/getPkpSessionSigsAdapter';
19+
import { getPkpSessionSigsAdapter } from './authAdapters/getPkpSessionSigsAdapter';
1720

1821
export interface AuthManagerParams {
1922
storage: LitAuthStorageProvider;
@@ -31,9 +34,7 @@ export interface BaseAuthContext<T> {
3134
authConfig: z.infer<typeof AuthConfigSchema>;
3235
config: T;
3336

34-
// @ts-expect-error - LitClientType is not defined in the package. We need to define this
35-
// once the LitClienType is ready
36-
litClient: ReturnType<typeof createLitClient>;
37+
litClient: LitClient;
3738
}
3839

3940
/**
@@ -62,12 +63,18 @@ export type ConstructorConfig<T> = T extends new (config: infer C) => any
6263

6364
export const createAuthManager = (authManagerParams: AuthManagerParams) => {
6465
return {
65-
// throw new Error(`Invalid authenticator: ${params.authenticator}`);
66-
// },
67-
// TODO: for wrapped keys!
68-
// createRequestToken: async () => {
69-
// // use createSessionSisg then send to wrapped key service
70-
// }
66+
/**
67+
* A migration helper to create session sigs for wrapped keys and datil v7
68+
*/
69+
createPkpSessionSigs: async (params: {
70+
pkpPublicKey: z.infer<typeof HexPrefixedSchema>;
71+
litClient: BaseAuthContext<any>['litClient'];
72+
sessionKeyPair: SessionKeyPair;
73+
delegationAuthSig: AuthSig;
74+
product?: PkpSessionSigsProduct;
75+
}) => {
76+
return getPkpSessionSigsAdapter(authManagerParams, params);
77+
},
7178
createEoaAuthContext: (params: EoaAuthContextAdapterParams) => {
7279
return getEoaAuthContextAdapter(authManagerParams, params);
7380
},
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import { getChildLogger } from '@lit-protocol/logger';
2+
import {
3+
PricingContextSchema,
4+
issueSessionFromContext,
5+
} from '@lit-protocol/networks';
6+
import { HexPrefixedSchema } from '@lit-protocol/schemas';
7+
import { AuthSig, SessionKeyPair, SessionSigsMap } from '@lit-protocol/types';
8+
import { z } from 'zod';
9+
import type { LitClient } from '@lit-protocol/lit-client';
10+
import type { AuthManagerParams } from '../auth-manager';
11+
import { getPkpAuthContextAdapter } from './getPkpAuthContextAdapter';
12+
import { getPkpAuthContextFromPreGeneratedAdapter } from './getPkpAuthContextFromPreGeneratedAdapter';
13+
14+
const _logger = getChildLogger({
15+
module: 'getPkpSessionSigsAdapter',
16+
});
17+
18+
type SupportedProduct =
19+
| 'DECRYPTION'
20+
| 'SIGN'
21+
| 'LIT_ACTION'
22+
| 'SIGN_SESSION_KEY';
23+
24+
export type PkpSessionSigsProduct = SupportedProduct;
25+
26+
const BigIntLikeSchema = z
27+
.union([z.bigint(), z.number().finite(), z.string()])
28+
.transform((value) => {
29+
if (typeof value === 'bigint') {
30+
return value;
31+
}
32+
33+
if (typeof value === 'number') {
34+
return BigInt(Math.trunc(value));
35+
}
36+
37+
const normalized = value.trim();
38+
39+
if (normalized.length === 0) {
40+
throw new Error('Cannot convert empty string to bigint');
41+
}
42+
43+
return BigInt(normalized);
44+
});
45+
46+
const RespondingNodePricesSchema = z.array(
47+
z.object({
48+
url: z.string(),
49+
prices: z.array(BigIntLikeSchema).transform((prices) => {
50+
return prices.map((price) => {
51+
if (price < 0n) {
52+
throw new Error('Node price must be non-negative');
53+
}
54+
return price;
55+
});
56+
}),
57+
})
58+
);
59+
60+
const HandshakeThresholdSchema = z
61+
.union([z.number(), z.bigint(), z.string()])
62+
.transform((value) => {
63+
if (typeof value === 'number') {
64+
return Math.trunc(value);
65+
}
66+
67+
if (typeof value === 'bigint') {
68+
return Number(value);
69+
}
70+
71+
const parsed = Number(value);
72+
73+
if (!Number.isFinite(parsed)) {
74+
throw new Error('Invalid threshold value provided by handshake result');
75+
}
76+
77+
return Math.trunc(parsed);
78+
})
79+
.refine((value) => value > 0, {
80+
message: 'Threshold must be a positive integer',
81+
});
82+
83+
export const getPkpSessionSigsAdapter = async (
84+
_: AuthManagerParams,
85+
params: {
86+
pkpPublicKey: z.infer<typeof HexPrefixedSchema>;
87+
litClient: LitClient;
88+
sessionKeyPair: SessionKeyPair;
89+
delegationAuthSig: AuthSig;
90+
product?: SupportedProduct;
91+
}
92+
): Promise<SessionSigsMap> => {
93+
const {
94+
pkpPublicKey,
95+
sessionKeyPair,
96+
delegationAuthSig,
97+
litClient,
98+
product = 'LIT_ACTION',
99+
} = params;
100+
101+
_logger.info(
102+
{
103+
pkpPublicKey,
104+
hasSessionKeyPair: !!sessionKeyPair,
105+
hasDelegationAuthSig: !!delegationAuthSig,
106+
product,
107+
},
108+
'getPkpSessionSigsAdapter: Preparing to generate session signatures'
109+
);
110+
111+
const litClientCtx = await litClient.getContext();
112+
113+
const latestConnectionInfo = litClientCtx?.latestConnectionInfo;
114+
const handshakeResult = litClientCtx?.handshakeResult;
115+
116+
if (!latestConnectionInfo || !handshakeResult) {
117+
throw new Error(
118+
'Missing latest connection info or handshake result from Lit client context'
119+
);
120+
}
121+
122+
const nodePrices = latestConnectionInfo.priceFeedInfo?.networkPrices;
123+
124+
if (!nodePrices?.length) {
125+
throw new Error(
126+
'No node pricing information available from Lit client context'
127+
);
128+
}
129+
130+
const serverKeys = handshakeResult.serverKeys ?? {};
131+
const respondingUrlSet = new Set(Object.keys(serverKeys));
132+
133+
const respondingNodePrices = nodePrices.filter((item) =>
134+
respondingUrlSet.has(item.url)
135+
);
136+
137+
const threshold = HandshakeThresholdSchema.parse(handshakeResult.threshold);
138+
139+
if (respondingNodePrices.length < threshold) {
140+
throw new Error(
141+
`Not enough handshake nodes to satisfy threshold. Threshold: ${threshold}, responding nodes: ${respondingNodePrices.length}`
142+
);
143+
}
144+
145+
const pricingNodePrices =
146+
RespondingNodePricesSchema.parse(respondingNodePrices);
147+
148+
const userMaxPriceValue =
149+
typeof litClientCtx.getUserMaxPrice === 'function'
150+
? litClientCtx.getUserMaxPrice({ product })
151+
: undefined;
152+
153+
const userMaxPrice =
154+
userMaxPriceValue !== undefined
155+
? BigIntLikeSchema.parse(userMaxPriceValue)
156+
: undefined;
157+
158+
const pricingContextInput: Parameters<typeof PricingContextSchema.parse>[0] =
159+
{
160+
product,
161+
nodePrices: pricingNodePrices,
162+
threshold,
163+
...(userMaxPrice !== undefined ? { userMaxPrice } : {}),
164+
};
165+
166+
const pricingContext = PricingContextSchema.parse(pricingContextInput);
167+
168+
let authContext:
169+
| Awaited<ReturnType<typeof getPkpAuthContextAdapter>>
170+
| Awaited<ReturnType<typeof getPkpAuthContextFromPreGeneratedAdapter>>;
171+
172+
// if (authConfig && authData) {
173+
// authContext = await getPkpAuthContextAdapter(upstreamParams, {
174+
// authData,
175+
// pkpPublicKey,
176+
// authConfig,
177+
// cache,
178+
// sessionKeyPair,
179+
// delegationAuthSig,
180+
// litClient: {
181+
// getContext: async () => litClientCtx,
182+
// },
183+
// });
184+
// } else {
185+
if (!sessionKeyPair || !delegationAuthSig) {
186+
throw new Error(
187+
'sessionKeyPair and delegationAuthSig are required when authConfig or authData are not provided'
188+
);
189+
}
190+
191+
_logger.info(
192+
{
193+
pkpPublicKey,
194+
},
195+
'getPkpSessionSigsAdapter: Falling back to pre-generated auth context helper'
196+
);
197+
198+
authContext = await getPkpAuthContextFromPreGeneratedAdapter({
199+
pkpPublicKey,
200+
sessionKeyPair,
201+
delegationAuthSig,
202+
// ...(authData ? { authData } : {}),
203+
});
204+
// }
205+
206+
const sessionSigs = await issueSessionFromContext({
207+
authContext,
208+
pricingContext,
209+
delegationAuthSig: delegationAuthSig,
210+
});
211+
212+
_logger.info(
213+
{
214+
pkpPublicKey,
215+
product,
216+
respondingNodeCount: respondingNodePrices.length,
217+
},
218+
'getPkpSessionSigsAdapter: Session signatures generated successfully'
219+
);
220+
221+
return sessionSigs;
222+
};

0 commit comments

Comments
 (0)