Skip to content
Open
Changes from all 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
108 changes: 50 additions & 58 deletions hono-cloudflare-worker/src/siwf.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,60 @@
import type { Hex } from 'viem';
import { parseSiweMessage, SiweMessage } from 'viem/siwe';
import { consumeNonce } from './nonce';
import { createAppClient, viemConnector } from '@farcaster/auth-client';


export async function verifyMessage(
env: Cloudflare.Env,
{
import type { Hex } from 'viem';
import { parseSiweMessage, SiweMessage } from 'viem/siwe';
import { consumeNonce } from './nonce';
import { createAppClient, viemConnector } from '@farcaster/auth-client';


export async function verifyMessage(
env: Cloudflare.Env,
{
domain,
message,
signature,
acceptAuthAddress
}: {
domain: string;
message: string;
signature: string;
acceptAuthAddress?: boolean;
}
): Promise<
| { isValid: true; fid: number; address: string; }
| { isValid: false; reason: string; message?: string; }
> {
const appClient = createAppClient(
{
relay: "https://relay.farcaster.xyz",
ethereum: viemConnector({ rpcUrls: env.ETH_RPC_URLS.split(',') }),
}
);

const siweMessage = parseSiweMessage(message);
if (!siweMessage.nonce) {
return { isValid: false, reason: 'invalid_nonce' }
}

// Verify the signature before consuming the nonce so invalid requests cannot burn valid nonces.
const verifyStart = Date.now();
const verifyResult = await appClient.verifySignInMessage({
nonce: siweMessage.nonce,
domain,
message,
signature,
acceptAuthAddress
}: {
domain: string;
message: string;
signature: string;
acceptAuthAddress?: boolean;
}
): Promise<
| { isValid: true; fid: number; address: string; }
| { isValid: false; reason: string; message?: string; }
> {
const appClient = createAppClient(
{
relay: "https://relay.farcaster.xyz",
ethereum: viemConnector({ rpcUrls: env.ETH_RPC_URLS.split(',') }),
}
);
signature: signature as Hex,
acceptAuthAddress,
});
console.log({ action: 'verifySignInMessage', duration: Date.now() - verifyStart });

const siweMessage = parseSiweMessage(message);
if (!siweMessage.nonce) {
return { isValid: false, reason: 'invalid_nonce' }
if (verifyResult.isError) {
return { isValid: false, reason: 'invalid_signature', message: verifyResult.error?.message }
}

// Juice perf by performing this operations in parallel
const [verifyResult, consumedNonce] = await Promise.all([
(async (nonce) => {
const verifyStart = Date.now();
const verifyResult = await appClient.verifySignInMessage({
nonce,
domain,
message,
signature: signature as Hex,
acceptAuthAddress,
})
console.log({ action: 'verifySignInMessage', duration: Date.now() - verifyStart });
return verifyResult;
})(siweMessage.nonce),
(async (nonce) => {
const consumeStart = Date.now();
const nonceResult = await consumeNonce(env, nonce)
console.log({ action: 'consumeNonce', duration: Date.now() - consumeStart });

return nonceResult;
})(siweMessage.nonce)
])
const consumeStart = Date.now();
const consumedNonce = await consumeNonce(env, siweMessage.nonce);
console.log({ action: 'consumeNonce', duration: Date.now() - consumeStart });

if (!consumedNonce) {
return { isValid: false, reason: 'invalid_nonce', message: 'Invalid nonce' }
}

if (verifyResult.isError) {
return { isValid: false, reason: 'invalid_signature', message: verifyResult.error?.message }
}

return { isValid: true, fid: verifyResult.fid, address: (siweMessage as SiweMessage).address }
}
return { isValid: true, fid: verifyResult.fid, address: (siweMessage as SiweMessage).address }
}