Skip to content

Commit

Permalink
馃敁 Add config to secure instance from unauth users (#559)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukevella committed Mar 14, 2023
1 parent e65c87b commit 1b38a3c
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 104 deletions.
15 changes: 13 additions & 2 deletions apps/web/declarations/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ declare global {
*/
NODE_ENV: "development" | "production";
/**
* Can be "false" or a relative path eg. "/new"
* Set to "true" to take users straight to app instead of landing page
*/
LANDING_PAGE: string;
DISABLE_LANDING_PAGE?: string;
/**
* Must be 32 characters long
*/
Expand Down Expand Up @@ -57,6 +57,17 @@ declare global {
* Port number of the SMTP server
*/
SMTP_PORT: string;
/**
* Comma separated list of email addresses that are allowed to register and login.
* If not set, all emails are allowed. Wildcard characters are supported.
*
* Example: "[email protected], *@example.com, *@*.example.com"
*/
ALLOWED_EMAILS?: string;
/**
* "true" to require authentication for creating new polls and accessing admin pages
*/
AUTH_REQUIRED?: string;
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion apps/web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ const nextConfig = {
return [
{
source: "/",
destination: "/home",
destination:
process.env.DISABLE_LANDING_PAGE === "true" ? "/new" : "/home",
},
];
},
Expand Down
1 change: 1 addition & 0 deletions apps/web/public/locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"editDetails": "Edit details",
"editOptions": "Edit options",
"email": "Email",
"emailNotAllowed": "This email is not allowed.",
"emailPlaceholder": "[email protected]",
"endingGuestSessionNotice": "Once a guest session ends it cannot be resumed. You will not be able to edit any votes or comments you've made with this session.",
"endSession": "End session",
Expand Down
43 changes: 35 additions & 8 deletions apps/web/src/components/auth/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,16 @@ export const RegisterForm: React.FunctionComponent<{
});

if (!res.ok) {
switch (res.code) {
switch (res.reason) {
case "userAlreadyExists":
setError("email", {
message: t("userAlreadyExists"),
});
break;
case "emailNotAllowed":
setError("email", {
message: t("emailNotAllowed"),
});
}
} else {
setToken(res.token);
Expand Down Expand Up @@ -308,7 +312,22 @@ export const LoginForm: React.FunctionComponent<{
email: values.email,
});

setToken(res.token);
if (res.ok) {
setToken(res.token);
} else {
switch (res.reason) {
case "emailNotAllowed":
setError("email", {
message: t("emailNotAllowed"),
});
break;
case "userNotFound":
setError("email", {
message: t("userNotFound"),
});
break;
}
}
}}
onChange={() => setToken(undefined)}
email={getValues("email")}
Expand All @@ -323,13 +342,21 @@ export const LoginForm: React.FunctionComponent<{
email: data.email,
});

if (!res.token) {
setError("email", {
type: "not_found",
message: t("userNotFound"),
});
} else {
if (res.ok) {
setToken(res.token);
} else {
switch (res.reason) {
case "emailNotAllowed":
setError("email", {
message: t("emailNotAllowed"),
});
break;
case "userNotFound":
setError("email", {
message: t("userNotFound"),
});
break;
}
}
})}
>
Expand Down
20 changes: 10 additions & 10 deletions apps/web/src/components/layouts/standard-layout/user-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ export const UserDropdown: React.FunctionComponent<DropdownProps> = ({
onClick={openLoginModal}
/>
) : null}
<DropdownItem
icon={Logout}
label={user.isGuest ? t("app:forgetMe") : t("app:logout")}
onClick={() => {
if (user?.isGuest) {
{user.isGuest ? (
<DropdownItem
icon={Logout}
label={t("app:forgetMe")}
onClick={() => {
modalContext.render({
title: t("app:areYouSure"),
description: t("app:endingGuestSessionNotice"),
Expand All @@ -95,11 +95,11 @@ export const UserDropdown: React.FunctionComponent<DropdownProps> = ({
okText: t("app:endSession"),
cancelText: t("app:cancel"),
});
} else {
logout();
}
}}
/>
}}
/>
) : (
<DropdownItem icon={Logout} href="/logout" label={t("app:logout")} />
)}
</Dropdown>
);
};
3 changes: 2 additions & 1 deletion apps/web/src/pages/admin/[urlId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getStandardLayout } from "@/components/layouts/standard-layout";
import { ParticipantsProvider } from "@/components/participants-provider";
import { Poll } from "@/components/poll";
import { PollContextProvider } from "@/components/poll-context";
import { withSessionSsr } from "@/utils/auth";
import { withAuthIfRequired, withSessionSsr } from "@/utils/auth";
import { trpc } from "@/utils/trpc";
import { withPageTranslations } from "@/utils/with-page-translations";

Expand Down Expand Up @@ -51,6 +51,7 @@ Page.getLayout = getStandardLayout;

export const getServerSideProps: GetServerSideProps = withSessionSsr(
[
withAuthIfRequired,
withPageTranslations(["common", "app", "errors"]),
async (ctx) => {
return {
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/pages/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useMount } from "react-use";

import FullPageLoader from "../components/full-page-loader";
import { withSession } from "../components/user-provider";
import { withSessionSsr } from "../utils/auth";
import { withAuthIfRequired, withSessionSsr } from "../utils/auth";
import { trpc } from "../utils/trpc";
import { withPageTranslations } from "../utils/with-page-translations";

Expand All @@ -26,8 +26,9 @@ const Demo: NextPage = () => {
return <FullPageLoader>{t("creatingDemo")}</FullPageLoader>;
};

export const getServerSideProps = withSessionSsr(
export const getServerSideProps = withSessionSsr([
withAuthIfRequired,
withPageTranslations(["common", "app"]),
);
]);

export default withSession(Demo);
39 changes: 11 additions & 28 deletions apps/web/src/pages/home.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
import { GetServerSideProps } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";

import Home from "@/components/home";
import { composeGetServerSideProps } from "@/utils/auth";
import { withPageTranslations } from "@/utils/with-page-translations";

export default function Page() {
return <Home />;
}

export const getServerSideProps: GetServerSideProps = async ({
locale = "en",
}) => {
if (process.env.LANDING_PAGE) {
if (process.env.LANDING_PAGE === "false") {
return {
redirect: {
destination: "/new",
permanent: false,
},
};
export const getServerSideProps: GetServerSideProps = composeGetServerSideProps(
async () => {
// TODO (Luke Vella) [2023-03-14]: Remove this once we split the app from the landing page
if (process.env.DISABLE_LANDING_PAGE === "true") {
return { notFound: true };
}
// if starts with /, it's a relative path
if (process.env.LANDING_PAGE.startsWith("/")) {
return {
redirect: {
destination: process.env.LANDING_PAGE,
permanent: false,
},
};
}
}
return {
props: {
...(await serverSideTranslations(locale, ["common", "homepage"])),
},
};
};
return { props: {} };
},
withPageTranslations(["common", "homepage"]),
);
7 changes: 4 additions & 3 deletions apps/web/src/pages/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import CreatePoll from "@/components/create-poll";

import StandardLayout from "../components/layouts/standard-layout";
import { NextPageWithLayout } from "../types";
import { withSessionSsr } from "../utils/auth";
import { withAuthIfRequired, withSessionSsr } from "../utils/auth";
import { withPageTranslations } from "../utils/with-page-translations";

const Page: NextPageWithLayout = () => {
Expand All @@ -28,6 +28,7 @@ Page.getLayout = function getLayout(page) {

export default Page;

export const getServerSideProps: GetServerSideProps = withSessionSsr(
export const getServerSideProps: GetServerSideProps = withSessionSsr([
withAuthIfRequired,
withPageTranslations(["common", "app"]),
);
]);
17 changes: 5 additions & 12 deletions apps/web/src/pages/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { withSessionSsr } from "@/utils/auth";
import { withAuth, withSessionSsr } from "@/utils/auth";

import { getStandardLayout } from "../components/layouts/standard-layout";
import { Profile } from "../components/profile";
Expand All @@ -11,16 +11,9 @@ const Page: NextPageWithLayout = () => {

Page.getLayout = getStandardLayout;

export const getServerSideProps = withSessionSsr(async (ctx) => {
if (ctx.req.session.user.isGuest !== false) {
return {
redirect: {
destination: "/login",
},
props: {},
};
}
return withPageTranslations(["common", "app"])(ctx);
});
export const getServerSideProps = withSessionSsr([
withAuth,
withPageTranslations(["common", "app"]),
]);

export default Page;
Loading

0 comments on commit 1b38a3c

Please sign in to comment.