Skip to content

Commit

Permalink
Fix/get auth method (#281)
Browse files Browse the repository at this point in the history
* update tests to gen pkps in setup for certain networks

* logging and network config updates

* add dynamic address and abi boostraping depedning on the network type.

* add new logging helpers

* remove print on multiformat not loading

* add debug to LitAuthClient options

* remove unused interface

* change logger

* update enum

* add logger wrapper

* add utility logging

* add auth method id tests for stytch factors

* fix getAuthIdByaAuthMethod
  • Loading branch information
Bean authored Dec 14, 2023
1 parent ca14b52 commit 52f1693
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 48 deletions.
4 changes: 1 addition & 3 deletions packages/contracts-sdk/src/lib/contracts-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import { AuthMethod } from '@lit-protocol/types';
let CID: any;
try {
CID = require('multiformats/cid');
} catch (e) {
console.log('CID not found');
}
} catch (e) {}

// ----- autogen:import-data:start -----
// Generated at 2023-11-07T01:50:52.460Z
Expand Down
8 changes: 2 additions & 6 deletions packages/core/src/lib/lit-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '@lit-protocol/constants';

import {
bootstrapLogManager,
isBrowser,
log,
logError,
Expand Down Expand Up @@ -136,12 +137,7 @@ export class LitCore {

// -- set global variables
globalThis.litConfig = this.config;
globalThis.logManager = LogManager.Instance;
globalThis.logManager.withConfig({
"condenseLogs": true
});
globalThis.logManager.setLevel(LogLevel.DEBUG);
globalThis.logger = globalThis.logManager.get('core');
bootstrapLogManager('core');
}

// ========== Logger utilities ==========
Expand Down
35 changes: 35 additions & 0 deletions packages/lit-auth-client/src/lib/lit-auth-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
StytchAuthFactorOtpProvider,
} from '@lit-protocol/lit-auth-client';
import { StytchOtpAuthenticateOptions } from '@lit-protocol/types';
import { AuthMethodType } from '@lit-protocol/constants';

const isClass = (v: unknown) => {
return typeof v === 'function' && /^\s*class\s+/.test(v.toString());
Expand Down Expand Up @@ -123,6 +124,40 @@ describe('initProvider', () => {
});
});

describe('getAuthMethodId', () => {
let client: LitAuthClient;
// static tokens from test project
let accessTokenEmailFactor = "eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3ay10ZXN0LWZiMjhlYmY2LTQ3NTMtNDdkMS1iMGUzLTRhY2NkMWE1MTc1NyIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicHJvamVjdC10ZXN0LWRlNGUyNjkwLTE1MDYtNGNmNS04YmNlLTQ0NTcxZGRhZWJjOSJdLCJleHAiOjE2ODg1Njc0MTQsImh0dHBzOi8vc3R5dGNoLmNvbS9zZXNzaW9uIjp7ImlkIjoic2Vzc2lvbi10ZXN0LTlkZDI3ZGE1LTVjNjQtNDE5NS04NjdlLWIxNGE3MWE5M2MxMSIsInN0YXJ0ZWRfYXQiOiIyMDIzLTA3LTA1VDE0OjI1OjE0WiIsImxhc3RfYWNjZXNzZWRfYXQiOiIyMDIzLTA3LTA1VDE0OjI1OjE0WiIsImV4cGlyZXNfYXQiOiIyMDIzLTA5LTEzVDAxOjA1OjE0WiIsImF0dHJpYnV0ZXMiOnsidXNlcl9hZ2VudCI6IiIsImlwX2FkZHJlc3MiOiIifSwiYXV0aGVudGljYXRpb25fZmFjdG9ycyI6W3sidHlwZSI6Im90cCIsImRlbGl2ZXJ5X21ldGhvZCI6ImVtYWlsIiwibGFzdF9hdXRoZW50aWNhdGVkX2F0IjoiMjAyMy0wNy0wNVQxNDoyNToxNFoiLCJlbWFpbF9mYWN0b3IiOnsiZW1haWxfaWQiOiJlbWFpbC10ZXN0LTAwMzZmM2YzLTQ0MjQtNDg2My1iYWQ3LTFkNGU3NTM1ZDJiMCIsImVtYWlsX2FkZHJlc3MiOiJqb3NoQGxpdHByb3RvY29sLmNvbSJ9fV19LCJpYXQiOjE2ODg1NjcxMTQsImlzcyI6InN0eXRjaC5jb20vcHJvamVjdC10ZXN0LWRlNGUyNjkwLTE1MDYtNGNmNS04YmNlLTQ0NTcxZGRhZWJjOSIsIm5iZiI6MTY4ODU2NzExNCwic3ViIjoidXNlci10ZXN0LTY4MTAzZTAxLTc0NjgtNGFiZi04M2M4LTg4NWRiMmNhMWM2YyJ9.rZgaunT1UV2pmliZ0V7nYqYtyfdGas4eY6Q6RCzEEBc5y1K66lopUbvvkfNsLJUjSc3vw12NlIX3Q47zm0XEP8AahrJ0QWAC4v9gmZKVYbKiL2JppqnaxtNLZV9Zo1KAiqm9gdqRQSD29222RTC59PI52AOZd4iTv4lSBIPG2J9rUkUwaRI23bGLMQ8XVkTSS7wcd1Ls08Q-VDXuwl8vuoJhssBfNfxFigk7cKHwbbM-o1sh3upEzV-WFgvJrTstPUNbHOBvGnqKDZX6A_45M5zBnHrerifz4-ST771tajiuW2lQXWvocyYlRT8_a0XBsW77UhU-YBTvKVpj3jmH4A";
let accessTokenSmsFactor = "eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3ay10ZXN0LTYyNWViODMxLTAwOWYtNGNiMy05YTk3LWJlNzU3YTMzNjQwZiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicHJvamVjdC10ZXN0LTI3OTA2MzVkLWJhMzEtNDcwNS1hYWY0LTIxM2JiMGYwNjgxMiJdLCJleHAiOjE2OTgzNTQyMTksImh0dHBzOi8vc3R5dGNoLmNvbS9zZXNzaW9uIjp7ImlkIjoic2Vzc2lvbi10ZXN0LWRhMzliOTBlLTkxMTMtNDQ3NC1hOWEyLWE5NTE3MzdkMGVlNSIsInN0YXJ0ZWRfYXQiOiIyMDIzLTEwLTI2VDIwOjU4OjM4WiIsImxhc3RfYWNjZXNzZWRfYXQiOiIyMDIzLTEwLTI2VDIwOjU4OjM5WiIsImV4cGlyZXNfYXQiOiIyMDIzLTExLTAyVDIwOjU4OjM4WiIsImF0dHJpYnV0ZXMiOnsidXNlcl9hZ2VudCI6IiIsImlwX2FkZHJlc3MiOiIifSwiYXV0aGVudGljYXRpb25fZmFjdG9ycyI6W3sidHlwZSI6Im90cCIsImRlbGl2ZXJ5X21ldGhvZCI6InNtcyIsImxhc3RfYXV0aGVudGljYXRlZF9hdCI6IjIwMjMtMTAtMjZUMjA6NTg6MzhaIiwicGhvbmVfbnVtYmVyX2ZhY3RvciI6eyJwaG9uZV9pZCI6InBob25lLW51bWJlci10ZXN0LWNmYTJjYTFlLTVmNzMtNGM0NS1hOWU2LWNjYWE5MWZkYjE3ZCIsInBob25lX251bWJlciI6IisxMjAxNDA3MjA3MyJ9fV19LCJpYXQiOjE2OTgzNTM5MTksImlzcyI6InN0eXRjaC5jb20vcHJvamVjdC10ZXN0LTI3OTA2MzVkLWJhMzEtNDcwNS1hYWY0LTIxM2JiMGYwNjgxMiIsIm5iZiI6MTY5ODM1MzkxOSwic3ViIjoidXNlci10ZXN0LWFhMGUwZmFhLTFjZTgtNGY4Yy05MGJhLWU2OTZmMWY4OTFlZiJ9.c-TAC_UNHQZgbcUBWYhBMCfctQAaVrL41bWGC3LifgEzFV-AWB9sPG8Ws18X2AdIi2FytAvpluWto4-oIdA5vghXx99pYnn45MuKvbvtixkz7tKXeyVN9BiXiPNWiHMjx_Iw_rPaF-KTLqQi7nCuS_UHcFr5uZrErDuYMdwfXxZPdl1pC0M_7Eh-wIOn_Fyy8bdftT1vqPlFTjxyTIZ2CLoAqizJi8cfPfAaC3dkxA54GT4LJdB9FY5VTkXO9Dc4BNZiL4MDx2jMNtE-RhY2iDDL4KC1yi4MQEdNSTm0KEoAF8_A7uzGkpHtJKjFyB8bZTmcrzqzgq6m732_nhMUbw";
beforeEach(() => {
client = new LitAuthClient({
litRelayConfig: { relayApiKey: 'test-api-key' },
});
});

it('should get auth method for stytch email factor', async () => {
let provider = client.initProvider(ProviderType.StytchEmailFactorOtp);
let id = await provider.getAuthMethodId({
authMethodType: AuthMethodType.StytchEmailFactorOtp,
accessToken: accessTokenEmailFactor
});

expect(id).toBeDefined();
});


it('should get auth method for stytch sms factor', async () => {
let provider = client.initProvider(ProviderType.StytchSmsFactorOtp);
let id = await provider.getAuthMethodId({
authMethodType: AuthMethodType.StytchSmsFactorOtp,
accessToken: accessTokenSmsFactor
});

expect(id).toBeDefined();
});

});

describe('getProvider', () => {
let client: LitAuthClient;

Expand Down
28 changes: 23 additions & 5 deletions packages/lit-auth-client/src/lib/lit-auth-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import EthWalletProvider from './providers/EthWalletProvider';
import WebAuthnProvider from './providers/WebAuthnProvider';
import { StytchOtpProvider } from './providers/StytchOtpProvider';
import AppleProvider from './providers/AppleProvider';
import StytchEmailOtpProvider from './providers/StytchAuthFactorOtp';
import StytchAuthFactorOtpProvider from './providers/StytchAuthFactorOtp';
import { bootstrapLogManager, getLoggerbyId, log } from '@lit-protocol/misc';

/**
* Class that handles authentication through Lit login
Expand All @@ -42,6 +42,11 @@ export class LitAuthClient {
*/
private providers: Map<string, BaseProvider>;

/**
* Configures logging
*/
private debug: boolean;

/**
* Create a LitAuthClient instance
*
Expand All @@ -53,7 +58,8 @@ export class LitAuthClient {
*/
constructor(options?: LitAuthClientOptions) {
this.providers = new Map();

bootstrapLogManager('auth-client');
this.debug = options?.debug ?? false;
// Check if custom relay object is provided
if (options?.customRelay) {
this.relay = options?.customRelay;
Expand All @@ -74,12 +80,15 @@ export class LitAuthClient {
} else {
this.litNodeClient = new LitNodeClient({
litNetwork: 'cayenne',
debug: false,
debug: options.debug ?? false,
});
}

// Set RPC URL
this.rpcUrl = options?.rpcUrl || 'https://chain-rpc.litprotocol.com/http';
this.log('rpc url: ', this.rpcUrl);
this.log('relay config: ', options.litRelayConfig);
this.log('relay instance: ', this.relay);
}

/**
Expand All @@ -101,7 +110,7 @@ export class LitAuthClient {
};

let provider: T;

log('resolving provider of type: ', type);
switch (type) {
case 'google':
provider = new GoogleProvider({
Expand Down Expand Up @@ -215,7 +224,10 @@ export class LitAuthClient {
authId = await GoogleProvider.authMethodId(authMethod);
break;
case AuthMethodType.StytchOtp:
authId = await GoogleProvider.authMethodId(authMethod);
authId = await StytchOtpProvider.authMethodId(authMethod);
break;
case AuthMethodType.StytchEmailFactorOtp:
authId = await StytchAuthFactorOtpProvider.authMethodId(authMethod);
break;
default:
throw new Error(
Expand All @@ -225,4 +237,10 @@ export class LitAuthClient {

return authId;
}

private log(... args: any) {
if (this.debug) {
getLoggerbyId('auth-client').debug(...args);
}
}
}
73 changes: 46 additions & 27 deletions packages/lit-auth-client/src/lib/providers/StytchAuthFactorOtp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,6 @@ import {
StytchToken,
} from '@lit-protocol/types';

export interface EmailAuthFactor {
email_address: string;
email_id: string;
created_at: string;
delivery_method: string;
last_authenticated_at: string;
type: string;
updated_at: string;
}
import { ethers } from 'ethers';
import {
FactorParser,
emailOtpAuthFactorParser,
Expand All @@ -31,8 +21,9 @@ export default class StytchAuthFactorOtpProvider<
T extends FactorParser
> extends BaseProvider {
private _params: StytchOtpProviderOptions;
private _provider: string = 'https://stytch.com/session';
private _factor: T;
private static _provider: string = 'https://stytch.com/session';

constructor(
params: BaseProviderOptions,
config: StytchOtpProviderOptions,
Expand Down Expand Up @@ -72,11 +63,11 @@ export default class StytchAuthFactorOtpProvider<
);
}

const parsedToken: StytchToken = this._parseJWT(accessToken);
const factorParser = this._resolveAuthFactor(this._factor);
const parsedToken: StytchToken = StytchAuthFactorOtpProvider._parseJWT(accessToken);
const factorParser = StytchAuthFactorOtpProvider._resolveAuthFactor(this._factor);

try {
factorParser.parser(parsedToken, this._provider);
factorParser.parser(parsedToken, StytchAuthFactorOtpProvider._provider);
} catch (e) {
reject(e);
}
Expand All @@ -88,6 +79,19 @@ export default class StytchAuthFactorOtpProvider<
});
}


/**
* Get auth method id that can be used to look up and interact with
* PKPs associated with the given auth method
*
* @param {AuthMethod} authMethod - Auth method object
*
* @returns {Promise<string>} - Auth method id
*/
public async getAuthMethodId(authMethod: AuthMethod): Promise<string> {
return StytchAuthFactorOtpProvider.authMethodId(authMethod);
}

/**
* Get auth method id that can be used to look up and interact with
* PKPs associated with the given auth method.
Expand All @@ -97,20 +101,40 @@ export default class StytchAuthFactorOtpProvider<
*
* @returns {Promise<string>} - Auth method id
*/
public async getAuthMethodId(
public static async authMethodId(
authMethod: AuthMethod,
options?: any
): Promise<string> {
return new Promise<string>((_resolve, _reject) => {
return new Promise<string>((resolve, reject) => {
const accessToken = authMethod.accessToken;
const parsedToken: StytchToken = this._parseJWT(accessToken);
const factorParser = this._resolveAuthFactor(this._factor).parser;

return factorParser(parsedToken, this._provider);
const parsedToken: StytchToken = StytchAuthFactorOtpProvider._parseJWT(accessToken);
let factor: FactorParser = 'email';
switch(authMethod.authMethodType) {
case AuthMethodType.StytchEmailFactorOtp:
factor = 'email';
break;
case AuthMethodType.StytchSmsFactorOtp:
factor = 'sms';
break;
case AuthMethodType.StytchWhatsAppFactorOtp:
factor = 'whatsApp';
break;
case AuthMethodType.StytchTotpFactorOtp:
factor = 'totp';
break;
default:
throw new Error("Unsupport stytch auth type");
}
const factorParser = this._resolveAuthFactor(factor).parser;
try {
resolve(factorParser(parsedToken, this._provider));
} catch(e) {
reject(e);
}
});
}

private _resolveAuthFactor(factor: T): {
private static _resolveAuthFactor(factor: FactorParser): {
parser: Function;
authMethodType: AuthMethodType;
} {
Expand All @@ -136,25 +160,20 @@ export default class StytchAuthFactorOtpProvider<
authMethodType: AuthMethodType.StytchTotpFactorOtp,
};
}

throw new Error(
'Unable to determine factor, are you using one of the supported factor types?'
);
}

/**
*
* @param jwt token to parse
* @returns {string}- userId contained within the token message
*/
private _parseJWT(jwt: string): StytchToken {
private static _parseJWT(jwt: string): StytchToken {
const parts = jwt.split('.');
if (parts.length !== 3) {
throw new Error('Invalid token length');
}
const body = Buffer.from(parts[1], 'base64');
const parsedBody: StytchToken = JSON.parse(body.toString('ascii'));
console.log('JWT body: ', parsedBody);
return parsedBody;
}
}
3 changes: 2 additions & 1 deletion packages/lit-auth-client/src/lib/relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
IRelayPollStatusResponse,
LitRelayConfig,
} from '@lit-protocol/types';
import { log } from './utils';

/**
* Class that communicates with Lit relay server
Expand Down Expand Up @@ -38,7 +39,7 @@ export class LitRelay implements IRelay {
this.relayUrl =
config.relayUrl || 'https://relayer-server-staging-cayenne.getlit.dev';
this.relayApiKey = config.relayApiKey || '';
console.log("Lit's relay server URL:", this.relayUrl);
log("Lit's relay server URL:", this.relayUrl);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/lit-auth-client/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getLoggerbyId } from '@lit-protocol/misc';
import { LoginUrlParams } from '@lit-protocol/types';
import * as cbor from 'cbor-web';

Expand Down Expand Up @@ -307,3 +308,9 @@ export function unparse(buf: any) {
bth[buf[i++]]
);
}


export function log(... args: any) {
const logger = getLoggerbyId('auth-client');
logger.debug(...args);
}
18 changes: 17 additions & 1 deletion packages/misc/src/lib/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '@lit-protocol/types';
import { JsonRpcProvider } from '@ethersproject/providers';
import { Contract } from '@ethersproject/contracts';

import { LogLevel, LogManager } from '@lit-protocol/logger';
import { version } from '@lit-protocol/constants';

const logBuffer: Array<Array<any>> = [];
Expand Down Expand Up @@ -201,6 +201,22 @@ export const throwRemovedFunctionError = (functionName: string) => {
});
};

export const bootstrapLogManager = (id: string, level: LogLevel = LogLevel.DEBUG) => {
if(!globalThis.logManager) {
globalThis.logManager = LogManager.Instance;
globalThis.logManager.withConfig({
"condenseLogs": true
});
globalThis.logManager.setLevel(level);
}

globalThis.logger = globalThis.logManager.get(id);
}

export const getLoggerbyId = (id: string) => {
return globalThis.logManager.get(id);
}

/**
*
* console.log but prepend [Lit-JS-SDK] before the message
Expand Down
19 changes: 14 additions & 5 deletions packages/types/src/lib/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ export enum IRelayAuthStatus {
Failed = 'Failed',
}

/**
* Supported PKP auth method types
*/
export enum AuthMethodType {
EthWallet = 1,
LitAction,
WebAuthn,
Discord,
Google,
GoogleJwt,
LitAction = 2,
WebAuthn = 3,
Discord = 4,
Google = 5,
GoogleJwt = 6,
AppleJwt = 8,
StytchOtp = 9,
StytchEmailFactorOtp = 10,
StytchSmsFactorOtp = 11,
StytchWhatsAppFactorOtp = 12,
StytchTotpFactorOtp = 13,
}
Loading

0 comments on commit 52f1693

Please sign in to comment.