mirror of
https://github.com/better-auth/better-auth.git
synced 2026-06-01 11:56:43 -05:00
fix: convert username to lowercase on signup (#876)
This commit is contained in:
@@ -11,6 +11,7 @@ import type {
|
||||
import type { toZod } from "../../types/to-zod";
|
||||
import { parseUserInput } from "../../db/schema";
|
||||
import { BASE_ERROR_CODES } from "../../error/codes";
|
||||
import { isDevelopment } from "../../utils/env";
|
||||
|
||||
export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
createAuthEndpoint(
|
||||
@@ -161,7 +162,9 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
ctx.context.logger.error("Failed to create user", e);
|
||||
if (isDevelopment) {
|
||||
ctx.context.logger.error("Failed to create user", e);
|
||||
}
|
||||
throw new APIError("UNPROCESSABLE_ENTITY", {
|
||||
message: BASE_ERROR_CODES.FAILED_TO_CREATE_USER,
|
||||
details: e,
|
||||
|
||||
@@ -148,6 +148,10 @@ export function parseInputData<T extends Record<string, any>>(
|
||||
parsedData[key] = fields[key].validator.input.parse(data[key]);
|
||||
continue;
|
||||
}
|
||||
if (fields[key].transform?.input && data[key] !== undefined) {
|
||||
parsedData[key] = fields[key].transform?.input(data[key]);
|
||||
continue;
|
||||
}
|
||||
parsedData[key] = data[key];
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export const username = () => {
|
||||
INVALID_USERNAME_OR_PASSWORD: "invalid username or password",
|
||||
EMAIL_NOT_VERIFIED: "email not verified",
|
||||
UNEXPECTED_ERROR: "unexpected error",
|
||||
USERNAME_IS_ALREADY_TAKEN: "username is already taken. please try another.",
|
||||
};
|
||||
return {
|
||||
id: "username",
|
||||
@@ -163,10 +164,43 @@ export const username = () => {
|
||||
required: false,
|
||||
unique: true,
|
||||
returned: true,
|
||||
transform: {
|
||||
input(value) {
|
||||
return value?.toString().toLowerCase();
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
before: [
|
||||
{
|
||||
matcher(context) {
|
||||
return context.path === "/sign-up/email";
|
||||
},
|
||||
async handler(ctx) {
|
||||
const username = ctx.body.username;
|
||||
if (username) {
|
||||
const user = await ctx.context.adapter.findOne<User>({
|
||||
model: "user",
|
||||
where: [
|
||||
{
|
||||
field: "username",
|
||||
value: username.toLowerCase(),
|
||||
},
|
||||
],
|
||||
});
|
||||
if (user) {
|
||||
throw new APIError("UNPROCESSABLE_ENTITY", {
|
||||
message: ERROR_CODES.USERNAME_IS_ALREADY_TAKEN,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
$ERROR_CODES: TWO_FACTOR_ERROR_CODES,
|
||||
} satisfies BetterAuthPlugin;
|
||||
};
|
||||
|
||||
@@ -65,4 +65,14 @@ describe("username", async (it) => {
|
||||
});
|
||||
expect(session?.user.username).toBe("new-username-2");
|
||||
});
|
||||
|
||||
it("should fail on duplicate username", async () => {
|
||||
const res = await client.signUp.email({
|
||||
email: "new-email-2@gamil.com",
|
||||
username: "New-username-2",
|
||||
password: "new-password",
|
||||
name: "new-name",
|
||||
});
|
||||
expect(res.error?.status).toBe(422);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user