Skip to content
Closed
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ NODE_ENV=development
# FROM_EMAIL=
# REPLY_TO_EMAIL=

# OPTIONAL VARIABLES
WHITELISTED_EMAILS="matt@gmail\.com|jane@yahoo\.com"
# Description: This environment variable defines a regex pattern for allowed email addresses.
# Only emails that match this pattern will be able to sign up or log in.

Comment on lines +27 to +31

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please have a look further up the file, the Optional Variables section already exists.

The WHITELISTED_EMAILS line would have to be commented out as it's optional.

The description is good, but would have to go above the env var, not below. You can also drop the Description: prefix.

# CLOUD VARIABLES
POSTHOG_PROJECT_KEY=
PLAIN_API_KEY=
Expand Down
1 change: 1 addition & 0 deletions apps/webapp/app/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const EnvironmentSchema = z.object({
MAGIC_LINK_SECRET: z.string(),
ENCRYPTION_KEY: z.string(),
REMIX_APP_PORT: z.string().optional(),
WHITELISTED_EMAILS: z.string().optional(),
LOGIN_ORIGIN: z.string().default("http://localhost:3030"),
APP_ORIGIN: z.string().default("http://localhost:3030"),
APP_ENV: z
Expand Down
18 changes: 18 additions & 0 deletions apps/webapp/app/models/user.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { Prisma, User } from "@trigger.dev/database";
import type { GitHubProfile } from "remix-auth-github";
import { prisma } from "~/db.server";
import { env } from "~/env.server";
import { authenticator } from "~/services/auth.server";
import { addEmailLinkStrategy } from "~/services/emailAuth.server";
export type { User } from "@trigger.dev/database";

addEmailLinkStrategy(authenticator);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? We already do this elsewhere.


type FindOrCreateMagicLink = {
authenticationMethod: "MAGIC_LINK";
email: string;
Expand All @@ -22,7 +27,12 @@ type LoggedInUser = {
isNewUser: boolean;
};

class EmailWhitelistError extends Error {}

export async function findOrCreateUser(input: FindOrCreateUser): Promise<LoggedInUser> {
if (!isEmailWhitelisted(input.email, env.WHITELISTED_EMAILS)) {
throw new EmailWhitelistError("Access to this instance is restricted.");
}
switch (input.authenticationMethod) {
case "GITHUB": {
return findOrCreateGithubUser(input);
Expand Down Expand Up @@ -178,3 +188,11 @@ export async function grantUserCloudAccess({ id, inviteCode }: { id: string; inv
},
});
}

function isEmailWhitelisted(email: string, whitelist: string | undefined) {
if (whitelist) {
const regex = new RegExp(whitelist);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if whitelist contains an invalid regular expression?

return regex.test(email);
}
return true; // No whitelist means all emails are allowed
}
2 changes: 1 addition & 1 deletion apps/webapp/app/routes/magic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export async function loader({ request }: LoaderArgs) {

await authenticator.authenticate("email-link", request, {
successRedirect: redirectTo ?? "/",
failureRedirect: "/login",
failureRedirect: "/login/magic",
Comment thread
nicktrn marked this conversation as resolved.
});
}