Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add storage provider #1494

Merged
merged 20 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/epk-cipher/src/ethereum-private-key-cipher-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ export default class EthereumPrivateKeyCipherProvider
}
}

/**
* Check if encryption is available
*
* @returns true if encryption is available
*/
public isEncryptionAvailable(): boolean {
return true;
}

/**
* Check if decryption is available
*
* @returns true if decryption is available
*/
public isDecryptionAvailable(): boolean {
return this.decryptionParametersDictionary.size > 0;
}

/**
* Encrypts data
*
Expand Down
2 changes: 2 additions & 0 deletions packages/integration-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@requestnetwork/epk-decryption": "0.7.1",
"@requestnetwork/epk-signature": "0.9.1",
"@requestnetwork/ethereum-storage": "0.36.1",
"@requestnetwork/lit-protocol-cipher": "0.1.0",
"@requestnetwork/multi-format": "0.19.1",
"@requestnetwork/payment-detection": "0.45.1",
"@requestnetwork/payment-processor": "0.48.0",
Expand All @@ -55,6 +56,7 @@
"@requestnetwork/transaction-manager": "0.36.1",
"@requestnetwork/types": "0.45.1",
"@requestnetwork/utils": "0.45.1",
"@requestnetwork/web3-signature": "0.8.1",
"@types/jest": "29.5.6",
"@types/node": "18.11.9",
"ethers": "5.7.2",
Expand Down
18 changes: 11 additions & 7 deletions packages/lit-protocol-cipher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,25 @@
"clean": "rm -rf dist tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
"lint": "eslint . --fix",
"lint:check": "eslint .",
"test": "jest",
"test": "yarn node --experimental-vm-modules $(yarn bin jest)",
"test:watch": "yarn test --watch"
},
"dependencies": {
"@lit-protocol/auth-browser": "6.11.2",
"@lit-protocol/auth-helpers": "6.11.2",
"@lit-protocol/constants": "6.11.2",
"@lit-protocol/lit-node-client": "6.11.2",
"@lit-protocol/types": "6.11.2",
"@lit-protocol/auth-browser": "7.0.0",
"@lit-protocol/auth-helpers": "7.0.0",
"@lit-protocol/constants": "7.0.0",
"@lit-protocol/encryption": "7.0.0",
"@lit-protocol/lit-node-client": "7.0.0",
"@lit-protocol/lit-node-client-nodejs": "7.0.0",
"@lit-protocol/types": "7.0.0",
"@requestnetwork/request-client.js": "0.50.0",
"@requestnetwork/types": "0.45.1",
"ethers": "5.7.2"
"ethers": "5.7.2",
"node-localstorage": "3.0.5"
},
"devDependencies": {
"@types/node": "18.11.9",
"@types/node-localstorage": "^1.3.3",
"jest-junit": "16.0.0",
"ts-node": "10.9.1",
"typescript": "5.1.3"
Expand Down
241 changes: 133 additions & 108 deletions packages/lit-protocol-cipher/src/lit-protocol-cipher-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import {
} from '@lit-protocol/types';
import {
LitAccessControlConditionResource,
LitAbility,
createSiweMessageWithRecaps,
generateAuthSig,
} from '@lit-protocol/auth-helpers';
import { disconnectWeb3 } from '@lit-protocol/auth-browser';
import { Signer } from 'ethers';
import { LIT_ABILITY } from '@lit-protocol/constants';
import { decryptToString, encryptString } from '@lit-protocol/encryption';

/**
* @class LitProvider
* @description A provider class that simplifies the usage of Lit Protocol for encryption and decryption.
Expand Down Expand Up @@ -45,6 +47,8 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
*/
private sessionSigs: SessionSigsMap | null = null;

private client: LitJsSdk.LitNodeClient | LitJsSdk.LitNodeClientNodeJs | null = null;

/**
* @constructor
* @param {LitNodeClient|LitNodeClientNodeJs} litClient - An instance of a Lit Protocol client (either client-side or Node.js).
Expand All @@ -58,6 +62,7 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
this.chain = chain;
this.network = network;
this.dataAccess = new HttpDataAccess({ nodeConnectionConfig });
void this.initializeClient();
}

/**
Expand All @@ -67,15 +72,37 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
* @throws {Error} Throws an error if the environment is not supported.
* @private
*/
private initializeClient(): LitJsSdk.LitNodeClient | LitJsSdk.LitNodeClientNodeJs {
if (typeof window !== 'undefined') {
return new LitJsSdk.LitNodeClient({
litNetwork: this.network,
});
} else {
return new LitJsSdk.LitNodeClientNodeJs({
litNetwork: this.network,
});
private async initializeClient() {
try {
// Using process.browser instead of typeof window
if (typeof window !== 'undefined') {
this.client = new LitJsSdk.LitNodeClient({
litNetwork: this.network,
});
await this.client.connect();
} else {
// Create dynamic import URL to prevent webpack analysis
const moduleUrl = 'node-localstorage';
const { LocalStorage } = await (0, eval)(`import('${moduleUrl}')`);

const localStorage = new LocalStorage('./request-network-lit-protocol-cipher');

const storageProvider = {
getItem: (key: string) => localStorage.getItem(key),
setItem: (key: string, value: string) => localStorage.setItem(key, value),
removeItem: (key: string) => localStorage.removeItem(key),
provider: localStorage,
};

this.client = new LitJsSdk.LitNodeClientNodeJs({
litNetwork: this.network,
storageProvider,
});

await this.client.connect();
}
} catch (error) {
throw new Error(`Failed to initialize Lit client: ${error.message}`);
}
}

Expand All @@ -100,75 +127,68 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
* @returns {Promise<void>}
*/
public async getSessionSignatures(signer: Signer, walletAddress: string): Promise<void> {
if (!this.client) {
throw new Error('Lit client not initialized');
}
if (this.sessionSigs) {
return;
}

let client: LitJsSdk.LitNodeClient | LitJsSdk.LitNodeClientNodeJs | null = null;
const capacityDelegationAuthSig: AuthSig = this.dataAccess.getLitCapacityDelegationAuthSig
? await this.dataAccess.getLitCapacityDelegationAuthSig(walletAddress)
: ({} as AuthSig);

try {
client = this.initializeClient();
await client.connect();

const capacityDelegationAuthSig: AuthSig = this.dataAccess.getLitCapacityDelegationAuthSig
? await this.dataAccess.getLitCapacityDelegationAuthSig(walletAddress)
: ({} as AuthSig);

// Get the latest blockhash
const latestBlockhash = await client.getLatestBlockhash();

// Define the authNeededCallback function
const authNeededCallback = async (params: AuthCallbackParams) => {
if (!params.uri) {
throw new Error('uri is required');
}
if (!params.expiration) {
throw new Error('expiration is required');
}

if (!params.resourceAbilityRequests) {
throw new Error('resourceAbilityRequests is required');
}

// Create the SIWE message
const toSign = await createSiweMessageWithRecaps({
uri: params.uri,
expiration: params.expiration,
resources: params.resourceAbilityRequests,
walletAddress: walletAddress,
nonce: latestBlockhash,
litNodeClient: client,
});
// Get the latest blockhash
const latestBlockhash = await this.client?.getLatestBlockhash();

// Generate the authSig
const authSig = await generateAuthSig({
signer: signer,
toSign,
});
// Define the authNeededCallback function
const authNeededCallback = async (params: AuthCallbackParams) => {
if (!params.uri) {
throw new Error('uri is required');
}
if (!params.expiration) {
throw new Error('expiration is required');
}

if (!params.resourceAbilityRequests) {
throw new Error('resourceAbilityRequests is required');
}

return authSig;
};
// Create the SIWE message
const toSign = await createSiweMessageWithRecaps({
uri: params.uri,
expiration: params.expiration,
resources: params.resourceAbilityRequests,
walletAddress: walletAddress,
nonce: latestBlockhash || '',
litNodeClient: this.client,
});

// Generate the authSig
const authSig = await generateAuthSig({
signer: signer,
toSign,
});

// Define the Lit resource
const litResource = new LitAccessControlConditionResource('*');
return authSig;
};

// Get the session signatures
this.sessionSigs = await client.getSessionSigs({
// Define the Lit resource
const litResource = new LitAccessControlConditionResource('*');

// Get the session signatures
this.sessionSigs =
(await this.client?.getSessionSigs({
chain: this.chain,
capabilityAuthSigs: [capacityDelegationAuthSig],
resourceAbilityRequests: [
{
resource: litResource,
ability: LitAbility.AccessControlConditionDecryption,
ability: LIT_ABILITY.AccessControlConditionDecryption,
},
],
authNeededCallback,
});
} finally {
if (client) {
await client.disconnect();
}
}
})) || {};
}

/**
Expand Down Expand Up @@ -220,6 +240,15 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
return accessControlConditions;
}

/**
* @function isEncryptionAvailable
* @description Checks if encryption is available.
* @returns {boolean} A boolean indicating if encryption is available.
*/
public isEncryptionAvailable(): boolean {
return this.client !== null;
}

/**
* @async
* @function encrypt
Expand All @@ -236,30 +265,32 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
encryptionParams: EncryptionTypes.IEncryptionParameters[];
},
): Promise<EncryptResponse | null> {
let client: LitJsSdk.LitNodeClient | LitJsSdk.LitNodeClientNodeJs | null = null;
if (!this.client) {
throw new Error('Lit client not initialized');
}

try {
client = this.initializeClient();
const stringifiedData = typeof data === 'string' ? data : JSON.stringify(data);

await client.connect();
const stringifiedData = typeof data === 'string' ? data : JSON.stringify(data);
const accessControlConditions = await this.getLitAccessControlConditions(
options.encryptionParams,
);

const accessControlConditions = await this.getLitAccessControlConditions(
options.encryptionParams,
);
return await encryptString(
{
accessControlConditions: accessControlConditions,
dataToEncrypt: stringifiedData,
},
this.client,
);
}

return await LitJsSdk.encryptString(
{
accessControlConditions: accessControlConditions,
dataToEncrypt: stringifiedData,
},
client,
);
} finally {
if (client) {
await client.disconnect();
}
}
/**
* @function isDecryptionAvailable
* @description Checks if decryption is available.
* @returns {boolean} A boolean indicating if decryption is available.
*/
public isDecryptionAvailable(): boolean {
return this.client !== null && this.sessionSigs !== null;
}

/**
Expand All @@ -279,34 +310,28 @@ export default class LitProvider implements CipherProviderTypes.ICipherProvider
encryptionParams: EncryptionTypes.IEncryptionParameters[];
},
): Promise<string | null> {
let client: LitJsSdk.LitNodeClient | LitJsSdk.LitNodeClientNodeJs | null = null;
if (!this.client) {
throw new Error('Lit client not initialized');
}

try {
if (!this.sessionSigs) {
throw new Error('Session signatures are required to decrypt data');
}
client = this.initializeClient();
await client.connect();
if (!this.sessionSigs) {
throw new Error('Session signatures are required to decrypt data');
}

const accessControlConditions = await this.getLitAccessControlConditions(
options.encryptionParams,
);
const accessControlConditions = await this.getLitAccessControlConditions(
options.encryptionParams,
);

const decryptedData = await LitJsSdk.decryptToString(
{
accessControlConditions: accessControlConditions,
chain: this.chain,
ciphertext: encryptedData.ciphertext,
dataToEncryptHash: encryptedData.dataToEncryptHash,
sessionSigs: this.sessionSigs,
},
client,
);
return decryptedData;
} finally {
if (client) {
await client.disconnect();
}
}
const decryptedData = await decryptToString(
{
accessControlConditions: accessControlConditions,
chain: this.chain,
ciphertext: encryptedData.ciphertext,
dataToEncryptHash: encryptedData.dataToEncryptHash,
sessionSigs: this.sessionSigs,
},
this.client,
);
return decryptedData;
}
}
Loading