Zod schemas for routes under /plugins (#6378)
* fix: schema for slack routes * fix: slack.post * fix: email
This commit is contained in:
@@ -8,6 +8,15 @@ import { getTestServer } from "@server/test/support";
|
||||
const server = getTestServer();
|
||||
|
||||
describe("email", () => {
|
||||
it("should fail with status 400 bad request if email is invalid", async () => {
|
||||
const res = await server.post("/auth/email", {
|
||||
body: { email: "invalid" },
|
||||
});
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(400);
|
||||
expect(body.message).toEqual("email: Invalid email");
|
||||
});
|
||||
|
||||
it("should require email param", async () => {
|
||||
const res = await server.post("/auth/email", {
|
||||
body: {},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Router from "koa-router";
|
||||
import { Client, NotificationEventType } from "@shared/types";
|
||||
import { NotificationEventType } from "@shared/types";
|
||||
import { parseDomain } from "@shared/utils/domains";
|
||||
import InviteAcceptedEmail from "@server/emails/templates/InviteAcceptedEmail";
|
||||
import SigninEmail from "@server/emails/templates/SigninEmail";
|
||||
@@ -7,20 +7,22 @@ import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||
import env from "@server/env";
|
||||
import { AuthorizationError } from "@server/errors";
|
||||
import { rateLimiter } from "@server/middlewares/rateLimiter";
|
||||
import validate from "@server/middlewares/validate";
|
||||
import { User, Team } from "@server/models";
|
||||
import { APIContext } from "@server/types";
|
||||
import { RateLimiterStrategy } from "@server/utils/RateLimiter";
|
||||
import { signIn } from "@server/utils/authentication";
|
||||
import { getUserForEmailSigninToken } from "@server/utils/jwt";
|
||||
import { assertEmail, assertPresent } from "@server/validation";
|
||||
import * as T from "./schema";
|
||||
|
||||
const router = new Router();
|
||||
|
||||
router.post(
|
||||
"email",
|
||||
rateLimiter(RateLimiterStrategy.TenPerHour),
|
||||
async (ctx) => {
|
||||
const { email, client } = ctx.request.body;
|
||||
assertEmail(email, "email is required");
|
||||
validate(T.EmailSchema),
|
||||
async (ctx: APIContext<T.EmailReq>) => {
|
||||
const { email, client } = ctx.input.body;
|
||||
|
||||
const domain = parseDomain(ctx.request.hostname);
|
||||
|
||||
@@ -71,7 +73,7 @@ router.post(
|
||||
to: user.email,
|
||||
token: user.getEmailSigninToken(),
|
||||
teamUrl: team.url,
|
||||
client: client === Client.Desktop ? Client.Desktop : Client.Web,
|
||||
client,
|
||||
}).schedule();
|
||||
|
||||
user.lastSigninEmailSentAt = new Date();
|
||||
@@ -84,52 +86,57 @@ router.post(
|
||||
}
|
||||
);
|
||||
|
||||
router.get("email.callback", async (ctx) => {
|
||||
const { token, client } = ctx.request.query;
|
||||
assertPresent(token, "token is required");
|
||||
router.get(
|
||||
"email.callback",
|
||||
validate(T.EmailCallbackSchema),
|
||||
async (ctx: APIContext<T.EmailCallbackReq>) => {
|
||||
const { token, client } = ctx.input.query;
|
||||
|
||||
let user!: User;
|
||||
let user!: User;
|
||||
|
||||
try {
|
||||
user = await getUserForEmailSigninToken(token as string);
|
||||
} catch (err) {
|
||||
ctx.redirect(`/?notice=expired-token`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
user = await getUserForEmailSigninToken(token as string);
|
||||
} catch (err) {
|
||||
ctx.redirect(`/?notice=expired-token`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.team.emailSigninEnabled) {
|
||||
return ctx.redirect("/?notice=auth-error");
|
||||
}
|
||||
if (!user.team.emailSigninEnabled) {
|
||||
return ctx.redirect("/?notice=auth-error");
|
||||
}
|
||||
|
||||
if (user.isSuspended) {
|
||||
return ctx.redirect("/?notice=user-suspended");
|
||||
}
|
||||
if (user.isSuspended) {
|
||||
return ctx.redirect("/?notice=user-suspended");
|
||||
}
|
||||
|
||||
if (user.isInvited) {
|
||||
await new WelcomeEmail({
|
||||
to: user.email,
|
||||
teamUrl: user.team.url,
|
||||
}).schedule();
|
||||
|
||||
const inviter = await user.$get("invitedBy");
|
||||
if (inviter?.subscribedToEventType(NotificationEventType.InviteAccepted)) {
|
||||
await new InviteAcceptedEmail({
|
||||
to: inviter.email,
|
||||
inviterId: inviter.id,
|
||||
invitedName: user.name,
|
||||
if (user.isInvited) {
|
||||
await new WelcomeEmail({
|
||||
to: user.email,
|
||||
teamUrl: user.team.url,
|
||||
}).schedule();
|
||||
}
|
||||
}
|
||||
|
||||
// set cookies on response and redirect to team subdomain
|
||||
await signIn(ctx, "email", {
|
||||
user,
|
||||
team: user.team,
|
||||
isNewTeam: false,
|
||||
isNewUser: false,
|
||||
client: client === Client.Desktop ? Client.Desktop : Client.Web,
|
||||
});
|
||||
});
|
||||
const inviter = await user.$get("invitedBy");
|
||||
if (
|
||||
inviter?.subscribedToEventType(NotificationEventType.InviteAccepted)
|
||||
) {
|
||||
await new InviteAcceptedEmail({
|
||||
to: inviter.email,
|
||||
inviterId: inviter.id,
|
||||
invitedName: user.name,
|
||||
teamUrl: user.team.url,
|
||||
}).schedule();
|
||||
}
|
||||
}
|
||||
|
||||
// set cookies on response and redirect to team subdomain
|
||||
await signIn(ctx, "email", {
|
||||
user,
|
||||
team: user.team,
|
||||
isNewTeam: false,
|
||||
isNewUser: false,
|
||||
client,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
21
plugins/email/server/auth/schema.ts
Normal file
21
plugins/email/server/auth/schema.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { z } from "zod";
|
||||
import { Client } from "@shared/types";
|
||||
import { BaseSchema } from "@server/routes/api/schema";
|
||||
|
||||
export const EmailSchema = BaseSchema.extend({
|
||||
body: z.object({
|
||||
email: z.string().email(),
|
||||
client: z.nativeEnum(Client).default(Client.Web),
|
||||
}),
|
||||
});
|
||||
|
||||
export type EmailReq = z.infer<typeof EmailSchema>;
|
||||
|
||||
export const EmailCallbackSchema = BaseSchema.extend({
|
||||
query: z.object({
|
||||
token: z.string(),
|
||||
client: z.nativeEnum(Client).default(Client.Web),
|
||||
}),
|
||||
});
|
||||
|
||||
export type EmailCallbackReq = z.infer<typeof EmailCallbackSchema>;
|
||||
Reference in New Issue
Block a user