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

feat: Store blockhash from handshake + use it in SIWE #248

Merged
49 changes: 49 additions & 0 deletions apps/html/manual_tests.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,49 @@

//var authSig = JSON.parse("{\"sig\":\"0x18a173d68d2f78cc5c13da0dfe36eec2a293285bee6d42547b9577bf26cdc985660ed3dddc4e75d422366cac07e8a9fc77669b10373bef9c7b8e4280252dfddf1b\",\"derivedVia\":\"web3.eth.personal.sign\",\"signedMessage\":\"I am creating an account to use LITs at 2021-08-04T20:14:04.918Z\",\"address\":\"0xdbd360f30097fb6d938dcc8b7b62854b36160b45\"}")

var CheckAndSignAuthMessageWithoutBlockhash = async() => {
const authSig = await LitJsSdk.checkAndSignAuthMessage({
chain: "ethereum",
});
let nonceLine = authSig.signedMessage.match(/^Nonce: (.+)$/m);

if (nonceLine[1].length === 17) {
document.getElementById(
'status'
).innerText = "CheckAndSignAuthMessageWithoutBlockhash passed!";
return true;
} else {
document.getElementById('status').innerText = "CheckAndSignAuthMessageWithoutBlockhash failed!";
return false;
}

await LitJsSdk.disconnectWeb3();
}

// The nonce should be we the below blockhash
var CheckAndSignAuthMessageWithBlockhash = async() => {
// Currently this will be undefined but later we should replace it with the hardcoded blockhash
const TEST_BLOCKHASH = "0xfe88c94d860f01a17f961bf4bdfb6e0c6cd10d3fda5cc861e805ca1240c58553";
const nonce = litNodeClient.getLatestBlockhash() || TEST_BLOCKHASH;

const authSig = await LitJsSdk.checkAndSignAuthMessage({
chain: "ethereum",
nonce,
});

if (authSig.signedMessage.includes(TEST_BLOCKHASH)) {
document.getElementById(
'status'
).innerText = "CheckAndSignAuthMessageWithBlockhash passed!";
return true;
} else {
document.getElementById('status').innerText = "CheckAndSignAuthMessageWithBlockhash failed!";
return false;
}

await LitJsSdk.disconnectWeb3();
}

var testEncryptingFileAndZipWithMetadata = async ({
accessControlConditions,
evmContractConditions,
Expand Down Expand Up @@ -1564,6 +1607,12 @@ <h1>Manual tests</h1>
<div id="networkStatus">Connecting to Lit Protocol Network...</div>
<br />
<br />
<button onclick="CheckAndSignAuthMessageWithoutBlockhash()">checkAndSignAuthMessage without blockhash</button>
<br />
<br />
<button onclick="CheckAndSignAuthMessageWithBlockhash()">checkAndSignAuthMessage with blockhash</button>
<br />
<br />
<button onclick="ETHEmptyWallet()">ETH (Empty Wallet)</button>
<br />
<br />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import path from 'path';
import { success, fail, testThis } from '../../tools/scripts/utils.mjs';

import * as LitJsSdk from '@lit-protocol/lit-node-client';
import { fromString as uint8arrayFromString } from "uint8arrays/from-string";
import ethers from "ethers";
import siwe from "siwe";

export async function main() {
// ==================== Setup ====================

const privKey = "3dfb4f70b15b6fccc786347aaea445f439a7f10fd10c55dd50cafc3d5a0abac1";
const privKeyBuffer = uint8arrayFromString(privKey, "base16");
const wallet = new ethers.Wallet(privKeyBuffer);

const domain = "localhost";
const origin = "https://localhost/login";
const statement = "This is a test statement. You can put anything you want here.";

const TEST_BLOCKHASH = "0xfe88c94d860f01a17f961bf4bdfb6e0c6cd10d3fda5cc861e805ca1240c58553";

// ==================== Test Logic ====================

const litNodeClient = new LitJsSdk.LitNodeClient({
litNetwork: "cayenne",
});
await litNodeClient.connect();
let nonce = litNodeClient.getLatestBlockhash();

if (!nonce) {
console.log("Latest blockhash is undefined as the corr node changes hasn't been deployed");
nonce = TEST_BLOCKHASH;
}

const siweMessage = new siwe.SiweMessage({
domain,
address: wallet.address,
statement,
uri: origin,
version: "1",
chainId: "1",
nonce,
});

const messageToSign = siweMessage.prepareMessage();
const signature = await wallet.signMessage(messageToSign);

// ==================== Post-Validation ====================

const recoveredAddress = ethers.utils.verifyMessage(messageToSign, signature);

const authSig = {
sig: signature,
derivedVia: "web3.eth.personal.sign",
signedMessage: messageToSign,
address: recoveredAddress,
};

console.log(authSig);

if (!authSig.signedMessage.includes(TEST_BLOCKHASH)) {
return fail("authSig doesn't contain the blockhash");
}

// ==================== Success ====================

return success('Can create an authSig with the latest blockhash as its nonce');
}

await testThis({ name: path.basename(import.meta.url), fn: main });
2 changes: 2 additions & 0 deletions packages/auth-browser/src/lib/auth-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const checkAndSignAuthMessage = ({
uri,
cosmosWalletType,
walletConnectProjectId,
nonce,
}: AuthCallbackParams): Promise<AuthSig> => {
const chainInfo = ALL_LIT_CHAINS[chain];

Expand Down Expand Up @@ -51,6 +52,7 @@ export const checkAndSignAuthMessage = ({
expiration,
uri,
walletConnectProjectId,
nonce,
});
} else if (chainInfo.vmType === VMTYPE.SVM) {
return checkAndSignSolAuthMessage();
Expand Down
12 changes: 11 additions & 1 deletion packages/auth-browser/src/lib/chains/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ interface signAndSaveAuthParams {
resources: any;
expiration: string;
uri?: string;
nonce: string,
}

interface IABI {
Expand Down Expand Up @@ -466,6 +467,7 @@ export const checkAndSignEVMAuthMessage = async ({
expiration,
uri,
walletConnectProjectId,
nonce,
}: AuthCallbackParams): Promise<AuthSig> => {
// -- check if it's nodejs
if (isNode()) {
Expand Down Expand Up @@ -601,6 +603,7 @@ export const checkAndSignEVMAuthMessage = async ({
resources,
expiration: expirationString,
uri,
nonce,
});
} catch (e: any) {
log(e);
Expand Down Expand Up @@ -634,6 +637,7 @@ export const checkAndSignEVMAuthMessage = async ({
resources,
expiration: expirationString,
uri,
nonce,
});
log('7. authSig:', authSig);

Expand All @@ -649,6 +653,7 @@ export const checkAndSignEVMAuthMessage = async ({
resources,
expiration: expirationString,
uri,
nonce,
});
}
log('8. mustResign:', mustResign);
Expand All @@ -666,6 +671,7 @@ export const checkAndSignEVMAuthMessage = async ({
resources,
expiration: expirationString,
uri,
nonce,
});
}

Expand All @@ -683,6 +689,7 @@ const _signAndGetAuth = async ({
resources,
expiration,
uri,
nonce,
}: signAndSaveAuthParams): Promise<AuthSig> => {
await signAndSaveAuthMessage({
web3,
Expand All @@ -691,6 +698,7 @@ const _signAndGetAuth = async ({
resources,
expiration,
uri,
nonce,
});

let authSigOrError = getStorageItem(LOCAL_STORAGE_KEYS.AUTH_SIGNATURE);
Expand All @@ -716,7 +724,7 @@ const _signAndGetAuth = async ({
* Sign the auth message with the user's wallet, and store it in localStorage.
* Called by checkAndSignAuthMessage if the user does not have a signature stored.
*
* @param { signAndSaveAuthParams }}
* @param { signAndSaveAuthParams }
* @returns { AuthSig }
*/
export const signAndSaveAuthMessage = async ({
Expand All @@ -726,6 +734,7 @@ export const signAndSaveAuthMessage = async ({
resources,
expiration,
uri,
nonce,
}: signAndSaveAuthParams): Promise<AuthSig> => {
// check if it's nodejs
if (isNode()) {
Expand All @@ -745,6 +754,7 @@ export const signAndSaveAuthMessage = async ({
version: '1',
chainId,
expirationTime: expiration,
nonce,
};

if (resources && resources.length > 0) {
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/lib/lit-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class LitCore {
networkPubKey: string | null;
networkPubKeySet: string | null;
hdRootPubkeys: string[] | null;
latestBlockhash: string | null;

// ========== Constructor ==========
constructor(args: any[LitNodeClientConfig | CustomNetwork | any]) {
Expand All @@ -88,6 +89,7 @@ export class LitCore {
this.networkPubKey = null;
this.networkPubKeySet = null;
this.hdRootPubkeys = null;
this.latestBlockhash = null;
// -- set bootstrapUrls to match the network litNetwork unless it's set to custom
this.setCustomBootstrapUrls();

Expand Down Expand Up @@ -146,6 +148,7 @@ export class LitCore {
networkPubKey: resp.networkPublicKey,
networkPubKeySet: resp.networkPublicKeySet,
hdRootPubkeys: resp.hdRootPubkeys,
latestBlockhash: resp.latestBlockhash,
};

// -- validate returned keys
Expand All @@ -158,6 +161,10 @@ export class LitCore {
log('Error connecting to node. Detected "ERR" in keys', url, keys);
}

if (!keys.latestBlockhash) {
log('Error getting latest blockhash from the node.');
}

this.serverKeys[url] = keys;
})
.catch((e: any) => {
Expand Down Expand Up @@ -193,6 +200,11 @@ export class LitCore {
(keysFromSingleNode: any) => keysFromSingleNode.hdRootPubkeys
)
);
this.latestBlockhash = mostCommonString(
Object.values(this.serverKeys).map(
(keysFromSingleNode: any) => keysFromSingleNode.latestBlockhash
)
);
this.ready = true;

log(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
EthWalletAuthenticateOptions,
} from '@lit-protocol/types';
import { LIT_CHAINS, AuthMethodType } from '@lit-protocol/constants';
import { SiweMessage } from 'lit-siwe';
import { generateNonce, SiweMessage } from 'lit-siwe';
import { ethers } from 'ethers';
import { BaseProvider } from './BaseProvider';
import { checkAndSignAuthMessage } from '@lit-protocol/lit-node-client';
Expand Down Expand Up @@ -74,6 +74,7 @@ export default class EthWalletProvider extends BaseProvider {
version: '1',
chainId,
expirationTime: expiration,
nonce: this.litNodeClient.latestBlockhash || generateNonce(),
};

const message: SiweMessage = new SiweMessage(preparedMessage);
Expand All @@ -91,6 +92,7 @@ export default class EthWalletProvider extends BaseProvider {
} else {
authSig = await checkAndSignAuthMessage({
chain,
nonce: this.litNodeClient.latestBlockhash || generateNonce(),
});
}

Expand Down
14 changes: 12 additions & 2 deletions packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ import {

import { computeAddress } from '@ethersproject/transactions';
import { joinSignature, sha256 } from 'ethers/lib/utils';
import { SiweMessage } from 'lit-siwe';
import { generateNonce, SiweMessage } from 'lit-siwe';

import { LitCore } from '@lit-protocol/core';
import { IPFSBundledSDK } from '@lit-protocol/lit-third-party-libs';
Expand Down Expand Up @@ -302,6 +302,10 @@ export class LitNodeClientNodeJs extends LitCore {
return LitNodeClientNodeJs.getExpiration();
}

getLatestBlockhash = () => {
return this.latestBlockhash;
}

/**
*
* Get the signature from local storage, if not, generates one
Expand All @@ -314,8 +318,8 @@ export class LitNodeClientNodeJs extends LitCore {
switchChain,
expiration,
sessionKeyUri,
nonce,
}: GetWalletSigProps): Promise<AuthSig> => {

let walletSig: AuthSig;

const storageKey = LOCAL_STORAGE_KEYS.WALLET_SIGNATURE;
Expand Down Expand Up @@ -351,6 +355,7 @@ export class LitNodeClientNodeJs extends LitCore {
...(switchChain && { switchChain }),
expiration,
uri: sessionKeyUri,
nonce,
};

log("callback body:", body);
Expand All @@ -377,6 +382,7 @@ export class LitNodeClientNodeJs extends LitCore {
switchChain,
expiration,
uri: sessionKeyUri,
nonce,
});
}

Expand Down Expand Up @@ -2103,6 +2109,7 @@ export class LitNodeClientNodeJs extends LitCore {
chainId: params.chainId ?? 1,
expirationTime: _expiration,
resources: params.resources,
nonce: this.latestBlockhash || generateNonce(),
});

let siweMessageStr: string = siweMessage.prepareMessage();
Expand Down Expand Up @@ -2273,6 +2280,7 @@ export class LitNodeClientNodeJs extends LitCore {
params.resourceAbilityRequests.map((r) => r.resource)
);
let expiration = params.expiration || LitNodeClientNodeJs.getExpiration();
let nonce = this.latestBlockhash || generateNonce();

// -- (TRY) to get the wallet signature
let authSig = await this.getWalletSig({
Expand All @@ -2282,6 +2290,7 @@ export class LitNodeClientNodeJs extends LitCore {
switchChain: params.switchChain,
expiration: expiration,
sessionKeyUri: sessionKeyUri,
nonce,
});

let needToResignSessionKey = await this.checkNeedToResignSessionKey({
Expand All @@ -2302,6 +2311,7 @@ export class LitNodeClientNodeJs extends LitCore {
switchChain: params.switchChain,
expiration,
uri: sessionKeyUri,
nonce,
},
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/lib/ILitNodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface ILitNodeClient {
subnetPubKey: string | null;
networkPubKey: string | null;
networkPubKeySet: string | null;
latestBlockhash: string | null;

// ========== Constructor ==========
// ** IMPORTANT !! You have to create your constructor when implementing this class **
Expand Down
Loading
Loading