mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-25 16:36:34 -05:00
feat: support custom schema merging in SIWE plugin (#4138)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { APIError, createAuthEndpoint } from "../../api";
|
||||
import { setSessionCookie } from "../../cookies";
|
||||
import { z } from "zod";
|
||||
import type { BetterAuthPlugin } from "../../types";
|
||||
import type { BetterAuthPlugin, InferOptionSchema } from "../../types";
|
||||
import type {
|
||||
ENSLookupArgs,
|
||||
ENSLookupResult,
|
||||
@@ -12,6 +12,7 @@ import type { User } from "../../types";
|
||||
import { schema } from "./schema";
|
||||
import { getOrigin } from "../../utils/url";
|
||||
import { toChecksumAddress } from "../../utils/hashing";
|
||||
import { mergeSchema } from "../../db/schema";
|
||||
|
||||
export interface SIWEPluginOptions {
|
||||
domain: string;
|
||||
@@ -20,12 +21,13 @@ export interface SIWEPluginOptions {
|
||||
getNonce: () => Promise<string>;
|
||||
verifyMessage: (args: SIWEVerifyMessageArgs) => Promise<boolean>;
|
||||
ensLookup?: (args: ENSLookupArgs) => Promise<ENSLookupResult>;
|
||||
schema?: InferOptionSchema<typeof schema>;
|
||||
}
|
||||
|
||||
export const siwe = (options: SIWEPluginOptions) =>
|
||||
({
|
||||
id: "siwe",
|
||||
schema,
|
||||
schema: mergeSchema(schema, options?.schema),
|
||||
endpoints: {
|
||||
getSiweNonce: createAuthEndpoint(
|
||||
"/siwe/nonce",
|
||||
|
||||
@@ -606,6 +606,74 @@ describe("siwe", async (it) => {
|
||||
expect(usersWithTestAddress.length).toBe(1); // Only one user should have this address
|
||||
});
|
||||
|
||||
it("should support custom schema with mergeSchema", async () => {
|
||||
const { client, auth } = await getTestInstance(
|
||||
{
|
||||
logger: {
|
||||
level: "debug",
|
||||
},
|
||||
plugins: [
|
||||
siwe({
|
||||
domain,
|
||||
async getNonce() {
|
||||
return "A1b2C3d4E5f6G7h8J";
|
||||
},
|
||||
async verifyMessage({ message, signature }) {
|
||||
return (
|
||||
signature === "valid_signature" && message === "valid_message"
|
||||
);
|
||||
},
|
||||
schema: {
|
||||
walletAddress: {
|
||||
modelName: "wallet_address",
|
||||
fields: {
|
||||
userId: "user_id",
|
||||
address: "wallet_address",
|
||||
chainId: "chain_id",
|
||||
isPrimary: "is_primary",
|
||||
createdAt: "created_at",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{ clientOptions: { plugins: [siweClient()] } },
|
||||
);
|
||||
|
||||
const testAddress = "0x000000000000000000000000000000000000dEaD";
|
||||
const testChainId = 1;
|
||||
|
||||
// Create account with custom schema
|
||||
await client.siwe.nonce({
|
||||
walletAddress: testAddress,
|
||||
chainId: testChainId,
|
||||
});
|
||||
const result = await client.siwe.verify({
|
||||
message: "valid_message",
|
||||
signature: "valid_signature",
|
||||
walletAddress: testAddress,
|
||||
chainId: testChainId,
|
||||
});
|
||||
expect(result.error).toBeNull();
|
||||
expect(result.data?.success).toBe(true);
|
||||
const context = await auth.$context;
|
||||
|
||||
const walletAddresses: any[] = await context.adapter.findMany({
|
||||
model: "walletAddress",
|
||||
where: [
|
||||
{ field: "address", operator: "eq", value: testAddress },
|
||||
{ field: "chainId", operator: "eq", value: testChainId },
|
||||
],
|
||||
});
|
||||
expect(walletAddresses.length).toBe(1);
|
||||
expect(walletAddresses[0]?.address).toBe(testAddress);
|
||||
expect(walletAddresses[0]?.chainId).toBe(testChainId);
|
||||
expect(walletAddresses[0]?.isPrimary).toBe(true);
|
||||
expect(walletAddresses[0]?.userId).toBeDefined();
|
||||
expect(walletAddresses[0]?.createdAt).toBeDefined();
|
||||
});
|
||||
|
||||
it("should allow same address on different chains for same user", async () => {
|
||||
const { client, auth } = await getTestInstance(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user