-
+
Whitelisted Users
diff --git a/pages/settings/appearance.tsx b/pages/settings/appearance.tsx
index 4f333bc..2ddde66 100644
--- a/pages/settings/appearance.tsx
+++ b/pages/settings/appearance.tsx
@@ -8,7 +8,7 @@ export default function Appearance() {
return (
- Select Theme
+ Select Theme
-
+
Confirm Your Password
diff --git a/pages/settings/password.tsx b/pages/settings/password.tsx
index d54a9b0..90b8abf 100644
--- a/pages/settings/password.tsx
+++ b/pages/settings/password.tsx
@@ -51,7 +51,7 @@ export default function Password() {
should be at least 8 characters.
-
New Password
+
New Password
-
- Confirm New Password
-
+
Confirm New Password
(Sort.DateNewestFirst);
@@ -81,6 +81,25 @@ export default function Index() {
setRenameTag(false);
};
+ const remove = async () => {
+ setSubmitLoader(true);
+
+ const load = toast.loading("Applying...");
+
+ let response;
+
+ if (activeTag?.id) response = await removeTag(activeTag?.id);
+
+ toast.dismiss(load);
+
+ if (response?.ok) {
+ toast.success("Tag Removed.");
+ router.push("/links");
+ } else toast.error(response?.data as string);
+ setSubmitLoader(false);
+ setRenameTag(false);
+ };
+
return (
@@ -153,6 +172,13 @@ export default function Index() {
setExpandDropdown(false);
},
},
+ {
+ name: "Remove Tag",
+ onClick: () => {
+ remove();
+ setExpandDropdown(false);
+ },
+ },
]}
onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement;
diff --git a/store/tags.ts b/store/tags.ts
index 26552bf..a27b859 100644
--- a/store/tags.ts
+++ b/store/tags.ts
@@ -10,6 +10,7 @@ type TagStore = {
tags: Tag[];
setTags: () => void;
updateTag: (tag: Tag) => Promise
;
+ removeTag: (tagId: number) => Promise;
};
const useTagStore = create()((set) => ({
@@ -42,6 +43,20 @@ const useTagStore = create()((set) => ({
return { ok: response.ok, data: data.response };
},
+ removeTag: async (tagId) => {
+ const response = await fetch(`/api/v1/tags/${tagId}`, {
+ method: "DELETE",
+ });
+
+ if (response.ok) {
+ set((state) => ({
+ tags: state.tags.filter((e) => e.id !== tagId),
+ }));
+ }
+
+ const data = await response.json();
+ return { ok: response.ok, data: data.response };
+ },
}));
export default useTagStore;
From c8edc3844b9c9815461313dd107f50c261a3f339 Mon Sep 17 00:00:00 2001
From: daniel31x13
Date: Mon, 6 Nov 2023 08:25:57 -0500
Subject: [PATCH 26/33] code refactoring + many security/bug fixes
---
.../Modal/Collection/TeamManagement.tsx | 3 +-
components/SettingsSidebar.tsx | 2 +-
hooks/useInitialData.tsx | 18 ++--
hooks/useRedirect.tsx | 30 -------
layouts/AuthRedirect.tsx | 33 +++++---
layouts/CenteredForm.tsx | 14 +++-
layouts/LinkLayout.tsx | 7 +-
lib/api/authenticateUser.ts | 31 -------
lib/api/checkSubscription.ts | 49 -----------
lib/api/checkSubscriptionByEmail.ts | 52 ++++++++++++
.../users}/getPublicUserById.ts | 25 ++++--
.../users/userId/deleteUserById.ts | 5 ++
.../controllers/users/userId/getUserById.ts | 6 +-
.../users/userId/updateUserById.ts | 5 +-
lib/api/paymentCheckout.ts | 6 +-
lib/api/verifySubscription.ts | 70 ++++++++++++++++
lib/api/verifyUser.ts | 60 +++++++++++++
lib/client/getPublicUserData.ts | 2 +-
pages/_app.tsx | 6 +-
pages/api/v1/archives/[...params].ts | 6 +-
pages/api/v1/auth/[...nextauth].ts | 84 ++++++-------------
pages/api/v1/avatar/[id].ts | 6 +-
pages/api/v1/collections/[id].ts | 6 +-
pages/api/v1/collections/index.ts | 6 +-
pages/api/v1/dashboard/index.ts | 6 +-
pages/api/v1/links/[id]/archive/index.ts | 6 +-
pages/api/v1/links/[id]/index.ts | 6 +-
pages/api/v1/links/index.ts | 6 +-
pages/api/v1/migration/index.ts | 6 +-
pages/api/v1/payment/index.ts | 22 +++--
pages/api/v1/public/users/[id].ts | 18 ++++
pages/api/v1/tags/[id].ts | 6 +-
pages/api/v1/tags/index.ts | 6 +-
pages/api/v1/users/[id].ts | 64 ++++++++------
pages/index.tsx | 9 +-
pages/register.tsx | 4 +-
pages/settings/account.tsx | 18 +---
pages/settings/billing.tsx | 3 +-
pages/settings/delete.tsx | 4 +-
pages/settings/password.tsx | 1 -
pages/subscribe.tsx | 5 +-
.../migration.sql | 19 +++++
.../migration.sql | 8 ++
prisma/schema.prisma | 24 +++++-
styles/globals.css | 5 ++
types/enviornment.d.ts | 4 +-
types/global.ts | 3 +
types/next-auth.d.ts | 4 +-
48 files changed, 472 insertions(+), 317 deletions(-)
delete mode 100644 hooks/useRedirect.tsx
delete mode 100644 lib/api/authenticateUser.ts
delete mode 100644 lib/api/checkSubscription.ts
create mode 100644 lib/api/checkSubscriptionByEmail.ts
rename lib/api/controllers/{users/userId => public/users}/getPublicUserById.ts (62%)
create mode 100644 lib/api/verifySubscription.ts
create mode 100644 lib/api/verifyUser.ts
create mode 100644 pages/api/v1/public/users/[id].ts
create mode 100644 prisma/migrations/20231103051515_add_subscription_table/migration.sql
create mode 100644 prisma/migrations/20231104052926_changed_subscription_relation/migration.sql
diff --git a/components/Modal/Collection/TeamManagement.tsx b/components/Modal/Collection/TeamManagement.tsx
index 0dfa92e..b625570 100644
--- a/components/Modal/Collection/TeamManagement.tsx
+++ b/components/Modal/Collection/TeamManagement.tsx
@@ -47,6 +47,7 @@ export default function TeamManagement({
id: null,
name: "",
username: "",
+ image: "",
});
useEffect(() => {
@@ -401,7 +402,7 @@ export default function TeamManagement({
>
diff --git a/components/SettingsSidebar.tsx b/components/SettingsSidebar.tsx
index d5b072b..ac9a7b7 100644
--- a/components/SettingsSidebar.tsx
+++ b/components/SettingsSidebar.tsx
@@ -113,7 +113,7 @@ export default function SettingsSidebar({ className }: { className?: string }) {
- {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? (
+ {process.env.NEXT_PUBLIC_STRIPE ? (
{
- if (
- status === "authenticated" &&
- (!process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE || data.user.isSubscriber)
- ) {
+ if (status === "authenticated") {
+ setAccount(data?.user.id as number);
+ }
+ }, [status, data]);
+
+ // Get the rest of the data
+ useEffect(() => {
+ if (account.id && (!process.env.NEXT_PUBLIC_STRIPE || account.username)) {
setCollections();
setTags();
// setLinks();
- setAccount(data.user.id);
}
- }, [status, data]);
+ }, [account]);
}
diff --git a/hooks/useRedirect.tsx b/hooks/useRedirect.tsx
deleted file mode 100644
index a6b9637..0000000
--- a/hooks/useRedirect.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useEffect, useState } from "react";
-import { useSession } from "next-auth/react";
-import { useRouter } from "next/router";
-
-export default function useRedirect() {
- const router = useRouter();
- const { status } = useSession();
- const [redirect, setRedirect] = useState(true);
-
- useEffect(() => {
- if (
- status === "authenticated" &&
- (router.pathname === "/login" || router.pathname === "/register")
- ) {
- router.push("/").then(() => {
- setRedirect(false);
- });
- } else if (
- status === "unauthenticated" &&
- !(router.pathname === "/login" || router.pathname === "/register")
- ) {
- router.push("/login").then(() => {
- setRedirect(false);
- });
- } else if (status === "loading") setRedirect(true);
- else setRedirect(false);
- }, [status]);
-
- return redirect;
-}
diff --git a/layouts/AuthRedirect.tsx b/layouts/AuthRedirect.tsx
index 8942666..da1f6fc 100644
--- a/layouts/AuthRedirect.tsx
+++ b/layouts/AuthRedirect.tsx
@@ -16,17 +16,29 @@ export default function AuthRedirect({ children }: Props) {
const [redirect, setRedirect] = useState(true);
const { account } = useAccountStore();
- const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
+ const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER === "true";
+ const stripeEnabled = process.env.NEXT_PUBLIC_STRIPE === "true";
useInitialData();
useEffect(() => {
if (!router.pathname.startsWith("/public")) {
if (
+ status === "authenticated" &&
+ account.id &&
+ !account.subscription?.active &&
+ stripeEnabled
+ ) {
+ router.push("/subscribe").then(() => {
+ setRedirect(false);
+ });
+ }
+ // Redirect to "/choose-username" if user is authenticated and is either a subscriber OR subscription is undefiend, and doesn't have a username
+ else if (
emailEnabled &&
status === "authenticated" &&
- (data.user.isSubscriber === true ||
- data.user.isSubscriber === undefined) &&
+ account.subscription?.active &&
+ stripeEnabled &&
account.id &&
!account.username
) {
@@ -35,21 +47,16 @@ export default function AuthRedirect({ children }: Props) {
});
} else if (
status === "authenticated" &&
- data.user.isSubscriber === false
- ) {
- router.push("/subscribe").then(() => {
- setRedirect(false);
- });
- } else if (
- status === "authenticated" &&
+ account.id &&
(router.pathname === "/login" ||
router.pathname === "/register" ||
router.pathname === "/confirmation" ||
router.pathname === "/subscribe" ||
router.pathname === "/choose-username" ||
- router.pathname === "/forgot")
+ router.pathname === "/forgot" ||
+ router.pathname === "/")
) {
- router.push("/").then(() => {
+ router.push("/dashboard").then(() => {
setRedirect(false);
});
} else if (
@@ -69,7 +76,7 @@ export default function AuthRedirect({ children }: Props) {
} else {
setRedirect(false);
}
- }, [status, account]);
+ }, [status, account, router.pathname]);
if (status !== "loading" && !redirect) return <>{children}>;
else return <>>;
diff --git a/layouts/CenteredForm.tsx b/layouts/CenteredForm.tsx
index 03052ec..83ac99a 100644
--- a/layouts/CenteredForm.tsx
+++ b/layouts/CenteredForm.tsx
@@ -10,10 +10,20 @@ interface Props {
export default function CenteredForm({ text, children }: Props) {
const { theme } = useTheme();
+
return (
- {theme === "dark" ? (
+ {theme ? (
+
+ ) : undefined}
+ {/* {theme === "dark" ? (
- )}
+ )} */}
{text ? (
{text}
diff --git a/layouts/LinkLayout.tsx b/layouts/LinkLayout.tsx
index 4850802..b2c135e 100644
--- a/layouts/LinkLayout.tsx
+++ b/layouts/LinkLayout.tsx
@@ -93,11 +93,14 @@ export default function LinkLayout({ children }: Props) {
*/}
router.back()}
+ onClick={() => router.push(`/collections/${linkCollection?.id}`)}
className="inline-flex gap-1 hover:opacity-60 items-center select-none cursor-pointer p-2 lg:p-0 lg:px-1 lg:my-2 text-gray-500 dark:text-gray-300 rounded-md duration-100"
>
- Back
+ Back{" "}
+
+ to {linkCollection?.name}
+
diff --git a/lib/api/authenticateUser.ts b/lib/api/authenticateUser.ts
deleted file mode 100644
index 12f744f..0000000
--- a/lib/api/authenticateUser.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { NextApiRequest, NextApiResponse } from "next";
-import { getToken } from "next-auth/jwt";
-import { prisma } from "./db";
-import { User } from "@prisma/client";
-
-type Props = {
- req: NextApiRequest;
- res: NextApiResponse;
-};
-
-export default async function authenticateUser({
- req,
- res,
-}: Props): Promise {
- const token = await getToken({ req });
- const userId = token?.id;
-
- if (!userId) {
- res.status(401).json({ message: "You must be logged in." });
- return null;
- } else if (process.env.STRIPE_SECRET_KEY && token.isSubscriber === false) {
- res.status(401).json({
- message:
- "You are not a subscriber, feel free to reach out to us at support@linkwarden.app if you think this is an issue.",
- });
- return null;
- }
-
- const user = await prisma.user.findUnique({ where: { id: userId } });
- return user;
-}
diff --git a/lib/api/checkSubscription.ts b/lib/api/checkSubscription.ts
deleted file mode 100644
index b459fb3..0000000
--- a/lib/api/checkSubscription.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import Stripe from "stripe";
-
-export default async function checkSubscription(
- stripeSecretKey: string,
- email: string
-) {
- const stripe = new Stripe(stripeSecretKey, {
- apiVersion: "2022-11-15",
- });
-
- const listByEmail = await stripe.customers.list({
- email: email.toLowerCase(),
- expand: ["data.subscriptions"],
- });
-
- let subscriptionCanceledAt: number | null | undefined;
-
- const isSubscriber = listByEmail.data.some((customer, i) => {
- const hasValidSubscription = customer.subscriptions?.data.some(
- (subscription) => {
- const NEXT_PUBLIC_TRIAL_PERIOD_DAYS =
- process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS;
- const secondsInTwoWeeks = NEXT_PUBLIC_TRIAL_PERIOD_DAYS
- ? Number(NEXT_PUBLIC_TRIAL_PERIOD_DAYS) * 86400
- : 1209600;
-
- subscriptionCanceledAt = subscription.canceled_at;
-
- const isNotCanceledOrHasTime = !(
- subscription.canceled_at &&
- new Date() >
- new Date((subscription.canceled_at + secondsInTwoWeeks) * 1000)
- );
-
- return subscription?.items?.data[0].plan && isNotCanceledOrHasTime;
- }
- );
-
- return (
- customer.email?.toLowerCase() === email.toLowerCase() &&
- hasValidSubscription
- );
- });
-
- return {
- isSubscriber,
- subscriptionCanceledAt,
- };
-}
diff --git a/lib/api/checkSubscriptionByEmail.ts b/lib/api/checkSubscriptionByEmail.ts
new file mode 100644
index 0000000..460a168
--- /dev/null
+++ b/lib/api/checkSubscriptionByEmail.ts
@@ -0,0 +1,52 @@
+import Stripe from "stripe";
+
+const MONTHLY_PRICE_ID = process.env.MONTHLY_PRICE_ID;
+const YEARLY_PRICE_ID = process.env.YEARLY_PRICE_ID;
+const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
+
+export default async function checkSubscriptionByEmail(email: string) {
+ let active: boolean | undefined,
+ stripeSubscriptionId: string | undefined,
+ currentPeriodStart: number | undefined,
+ currentPeriodEnd: number | undefined;
+
+ if (!STRIPE_SECRET_KEY)
+ return {
+ active,
+ stripeSubscriptionId,
+ currentPeriodStart,
+ currentPeriodEnd,
+ };
+
+ const stripe = new Stripe(STRIPE_SECRET_KEY, {
+ apiVersion: "2022-11-15",
+ });
+
+ console.log("Request made to Stripe by:", email);
+ const listByEmail = await stripe.customers.list({
+ email: email.toLowerCase(),
+ expand: ["data.subscriptions"],
+ });
+
+ listByEmail.data.some((customer) => {
+ customer.subscriptions?.data.some((subscription) => {
+ subscription.current_period_end;
+
+ active = subscription.items.data.some(
+ (e) =>
+ (e.price.id === MONTHLY_PRICE_ID && e.price.active === true) ||
+ (e.price.id === YEARLY_PRICE_ID && e.price.active === true)
+ );
+ stripeSubscriptionId = subscription.id;
+ currentPeriodStart = subscription.current_period_start * 1000;
+ currentPeriodEnd = subscription.current_period_end * 1000;
+ });
+ });
+
+ return {
+ active,
+ stripeSubscriptionId,
+ currentPeriodStart,
+ currentPeriodEnd,
+ };
+}
diff --git a/lib/api/controllers/users/userId/getPublicUserById.ts b/lib/api/controllers/public/users/getPublicUserById.ts
similarity index 62%
rename from lib/api/controllers/users/userId/getPublicUserById.ts
rename to lib/api/controllers/public/users/getPublicUserById.ts
index c5a575e..8f7ea48 100644
--- a/lib/api/controllers/users/userId/getPublicUserById.ts
+++ b/lib/api/controllers/public/users/getPublicUserById.ts
@@ -3,7 +3,7 @@ import { prisma } from "@/lib/api/db";
export default async function getPublicUserById(
targetId: number | string,
isId: boolean,
- requestingUsername?: string
+ requestingId?: number
) {
const user = await prisma.user.findUnique({
where: isId
@@ -29,12 +29,23 @@ export default async function getPublicUserById(
(usernames) => usernames.username
);
- if (
- user?.isPrivate &&
- (!requestingUsername ||
- !whitelistedUsernames.includes(requestingUsername?.toLowerCase()))
- ) {
- return { response: "User not found or profile is private.", status: 404 };
+ if (user?.isPrivate) {
+ if (requestingId) {
+ const requestingUsername = (
+ await prisma.user.findUnique({ where: { id: requestingId } })
+ )?.username;
+
+ if (
+ !requestingUsername ||
+ !whitelistedUsernames.includes(requestingUsername?.toLowerCase())
+ ) {
+ return {
+ response: "User not found or profile is private.",
+ status: 404,
+ };
+ }
+ } else
+ return { response: "User not found or profile is private.", status: 404 };
}
const { password, ...lessSensitiveInfo } = user;
diff --git a/lib/api/controllers/users/userId/deleteUserById.ts b/lib/api/controllers/users/userId/deleteUserById.ts
index 0641525..4b2e940 100644
--- a/lib/api/controllers/users/userId/deleteUserById.ts
+++ b/lib/api/controllers/users/userId/deleteUserById.ts
@@ -68,6 +68,11 @@ export default async function deleteUserById(
where: { ownerId: userId },
});
+ // Delete subscription
+ await prisma.subscription.delete({
+ where: { userId },
+ });
+
// Delete user's avatar
removeFile({ filePath: `uploads/avatar/${userId}.jpg` });
diff --git a/lib/api/controllers/users/userId/getUserById.ts b/lib/api/controllers/users/userId/getUserById.ts
index 32bc3a6..8c6faa8 100644
--- a/lib/api/controllers/users/userId/getUserById.ts
+++ b/lib/api/controllers/users/userId/getUserById.ts
@@ -11,6 +11,7 @@ export default async function getUserById(userId: number) {
username: true,
},
},
+ subscriptions: true,
},
});
@@ -21,11 +22,14 @@ export default async function getUserById(userId: number) {
(usernames) => usernames.username
);
- const { password, ...lessSensitiveInfo } = user;
+ const { password, subscriptions, ...lessSensitiveInfo } = user;
const data = {
...lessSensitiveInfo,
whitelistedUsers: whitelistedUsernames,
+ subscription: {
+ active: subscriptions?.active,
+ },
};
return { response: data, status: 200 };
diff --git a/lib/api/controllers/users/userId/updateUserById.ts b/lib/api/controllers/users/userId/updateUserById.ts
index fc4c015..0043c8b 100644
--- a/lib/api/controllers/users/userId/updateUserById.ts
+++ b/lib/api/controllers/users/userId/updateUserById.ts
@@ -139,10 +139,12 @@ export default async function updateUserById(
},
include: {
whitelistedUsers: true,
+ subscriptions: true,
},
});
- const { whitelistedUsers, password, ...userInfo } = updatedUser;
+ const { whitelistedUsers, password, subscriptions, ...userInfo } =
+ updatedUser;
// If user.whitelistedUsers is not provided, we will assume the whitelistedUsers should be removed
const newWhitelistedUsernames: string[] = data.whitelistedUsers || [];
@@ -196,6 +198,7 @@ export default async function updateUserById(
...userInfo,
whitelistedUsers: newWhitelistedUsernames,
image: userInfo.image ? `${userInfo.image}?${Date.now()}` : "",
+ subscription: { active: subscriptions?.active },
};
return { response, status: 200 };
diff --git a/lib/api/paymentCheckout.ts b/lib/api/paymentCheckout.ts
index 49bf027..bae7f1d 100644
--- a/lib/api/paymentCheckout.ts
+++ b/lib/api/paymentCheckout.ts
@@ -14,12 +14,12 @@ export default async function paymentCheckout(
expand: ["data.subscriptions"],
});
- const isExistingCostomer = listByEmail?.data[0]?.id || undefined;
+ const isExistingCustomer = listByEmail?.data[0]?.id || undefined;
const NEXT_PUBLIC_TRIAL_PERIOD_DAYS =
process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS;
const session = await stripe.checkout.sessions.create({
- customer: isExistingCostomer ? isExistingCostomer : undefined,
+ customer: isExistingCustomer ? isExistingCustomer : undefined,
line_items: [
{
price: priceId,
@@ -27,7 +27,7 @@ export default async function paymentCheckout(
},
],
mode: "subscription",
- customer_email: isExistingCostomer ? undefined : email.toLowerCase(),
+ customer_email: isExistingCustomer ? undefined : email.toLowerCase(),
success_url: `${process.env.BASE_URL}?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.BASE_URL}/login`,
automatic_tax: {
diff --git a/lib/api/verifySubscription.ts b/lib/api/verifySubscription.ts
new file mode 100644
index 0000000..d8055d4
--- /dev/null
+++ b/lib/api/verifySubscription.ts
@@ -0,0 +1,70 @@
+import { prisma } from "./db";
+import { Subscription, User } from "@prisma/client";
+import checkSubscriptionByEmail from "./checkSubscriptionByEmail";
+
+interface UserIncludingSubscription extends User {
+ subscriptions: Subscription | null;
+}
+
+export default async function verifySubscription(
+ user?: UserIncludingSubscription
+) {
+ if (!user) {
+ return null;
+ }
+
+ const subscription = user.subscriptions;
+
+ const currentDate = new Date();
+
+ if (
+ subscription &&
+ currentDate > subscription.currentPeriodEnd &&
+ !subscription.active
+ ) {
+ return null;
+ }
+
+ if (!subscription || currentDate > subscription.currentPeriodEnd) {
+ const {
+ active,
+ stripeSubscriptionId,
+ currentPeriodStart,
+ currentPeriodEnd,
+ } = await checkSubscriptionByEmail(user.email as string);
+
+ if (
+ active &&
+ stripeSubscriptionId &&
+ currentPeriodStart &&
+ currentPeriodEnd
+ ) {
+ await prisma.subscription
+ .upsert({
+ where: {
+ userId: user.id,
+ },
+ create: {
+ active,
+ stripeSubscriptionId,
+ currentPeriodStart: new Date(currentPeriodStart),
+ currentPeriodEnd: new Date(currentPeriodEnd),
+ userId: user.id,
+ },
+ update: {
+ active,
+ stripeSubscriptionId,
+ currentPeriodStart: new Date(currentPeriodStart),
+ currentPeriodEnd: new Date(currentPeriodEnd),
+ },
+ })
+ .catch((err) => console.log(err));
+ }
+
+ if (!active) {
+ return null;
+ }
+ }
+
+ return user;
+}
diff --git a/lib/api/verifyUser.ts b/lib/api/verifyUser.ts
new file mode 100644
index 0000000..943f68e
--- /dev/null
+++ b/lib/api/verifyUser.ts
@@ -0,0 +1,60 @@
+import { NextApiRequest, NextApiResponse } from "next";
+import { getToken } from "next-auth/jwt";
+import { prisma } from "./db";
+import { User } from "@prisma/client";
+import verifySubscription from "./verifySubscription";
+
+type Props = {
+ req: NextApiRequest;
+ res: NextApiResponse;
+};
+
+const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
+
+export default async function verifyUser({
+ req,
+ res,
+}: Props): Promise {
+ const token = await getToken({ req });
+ const userId = token?.id;
+
+ if (!userId) {
+ res.status(401).json({ response: "You must be logged in." });
+ return null;
+ }
+
+ const user = await prisma.user.findUnique({
+ where: {
+ id: userId,
+ },
+ include: {
+ subscriptions: true,
+ },
+ });
+
+ if (!user) {
+ res.status(404).json({ response: "User not found." });
+ return null;
+ }
+
+ if (!user.username) {
+ res.status(401).json({
+ response: "Username not found.",
+ });
+ return null;
+ }
+
+ if (STRIPE_SECRET_KEY) {
+ const subscribedUser = verifySubscription(user);
+
+ if (!subscribedUser) {
+ res.status(401).json({
+ response:
+ "You are not a subscriber, feel free to reach out to us at support@linkwarden.app if you think this is an issue.",
+ });
+ return null;
+ }
+ }
+
+ return user;
+}
diff --git a/lib/client/getPublicUserData.ts b/lib/client/getPublicUserData.ts
index 20bd1e9..595ea7c 100644
--- a/lib/client/getPublicUserData.ts
+++ b/lib/client/getPublicUserData.ts
@@ -1,7 +1,7 @@
import { toast } from "react-hot-toast";
export default async function getPublicUserData(id: number | string) {
- const response = await fetch(`/api/v1/users/${id}`);
+ const response = await fetch(`/api/v1/public/users/${id}`);
const data = await response.json();
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 69d8b6f..25217f9 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -22,7 +22,11 @@ export default function App({
}, []);
return (
-
+
Linkwarden
diff --git a/pages/api/v1/archives/[...params].ts b/pages/api/v1/archives/[...params].ts
index 5534ea3..1436c04 100644
--- a/pages/api/v1/archives/[...params].ts
+++ b/pages/api/v1/archives/[...params].ts
@@ -1,14 +1,14 @@
import type { NextApiRequest, NextApiResponse } from "next";
import getPermission from "@/lib/api/getPermission";
import readFile from "@/lib/api/storage/readFile";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function Index(req: NextApiRequest, res: NextApiResponse) {
if (!req.query.params)
return res.status(401).json({ response: "Invalid parameters." });
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
const collectionId = req.query.params[0];
const linkId = req.query.params[1];
diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts
index 3228a35..0b4ab7e 100644
--- a/pages/api/v1/auth/[...nextauth].ts
+++ b/pages/api/v1/auth/[...nextauth].ts
@@ -1,24 +1,26 @@
import { prisma } from "@/lib/api/db";
import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";
-import { AuthOptions, Session, User } from "next-auth";
+import { AuthOptions } from "next-auth";
import bcrypt from "bcrypt";
import EmailProvider from "next-auth/providers/email";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { Adapter } from "next-auth/adapters";
import sendVerificationRequest from "@/lib/api/sendVerificationRequest";
import { Provider } from "next-auth/providers";
-import checkSubscription from "@/lib/api/checkSubscription";
+import verifySubscription from "@/lib/api/verifySubscription";
const emailEnabled =
process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false;
+const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
+
const providers: Provider[] = [
CredentialsProvider({
type: "credentials",
credentials: {},
async authorize(credentials, req) {
- console.log("User logged in attempt...");
+ console.log("User log in attempt...");
if (!credentials) return null;
const { username, password } = credentials as {
@@ -26,7 +28,7 @@ const providers: Provider[] = [
password: string;
};
- const findUser = await prisma.user.findFirst({
+ const user = await prisma.user.findFirst({
where: emailEnabled
? {
OR: [
@@ -46,12 +48,12 @@ const providers: Provider[] = [
let passwordMatches: boolean = false;
- if (findUser?.password) {
- passwordMatches = bcrypt.compareSync(password, findUser.password);
+ if (user?.password) {
+ passwordMatches = bcrypt.compareSync(password, user.password);
}
if (passwordMatches) {
- return { id: findUser?.id };
+ return { id: user?.id };
} else return null as any;
},
}),
@@ -82,62 +84,28 @@ export const authOptions: AuthOptions = {
},
callbacks: {
async jwt({ token, trigger, user }) {
- const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
-
- const NEXT_PUBLIC_TRIAL_PERIOD_DAYS =
- process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS;
- const secondsInTwoWeeks = NEXT_PUBLIC_TRIAL_PERIOD_DAYS
- ? Number(NEXT_PUBLIC_TRIAL_PERIOD_DAYS) * 86400
- : 1209600;
- const subscriptionIsTimesUp =
- token.subscriptionCanceledAt &&
- new Date() >
- new Date(
- ((token.subscriptionCanceledAt as number) + secondsInTwoWeeks) *
- 1000
- );
-
- if (
- STRIPE_SECRET_KEY &&
- (trigger || subscriptionIsTimesUp || !token.isSubscriber)
- ) {
- const user = await prisma.user.findUnique({
- where: {
- id: Number(token.sub),
- },
- });
-
- const subscription = await checkSubscription(
- STRIPE_SECRET_KEY,
- user?.email as string
- );
-
- if (subscription.subscriptionCanceledAt) {
- token.subscriptionCanceledAt = subscription.subscriptionCanceledAt;
- } else token.subscriptionCanceledAt = undefined;
-
- token.isSubscriber = subscription.isSubscriber;
- }
-
- if (trigger === "signIn") {
- token.id = user.id as number;
- } else if (trigger === "update" && token.id) {
- const user = await prisma.user.findUnique({
- where: {
- id: token.id as number,
- },
- });
-
- if (user?.name) {
- token.name = user.name;
- }
- }
+ token.sub = token.sub ? Number(token.sub) : undefined;
+ if (trigger === "signIn") token.id = user?.id as number;
return token;
},
async session({ session, token }) {
session.user.id = token.id;
- session.user.isSubscriber = token.isSubscriber;
+
+ if (STRIPE_SECRET_KEY) {
+ const user = await prisma.user.findUnique({
+ where: {
+ id: token.id,
+ },
+ include: {
+ subscriptions: true,
+ },
+ });
+
+ if (user) {
+ const subscribedUser = await verifySubscription(user);
+ }
+ }
return session;
},
diff --git a/pages/api/v1/avatar/[id].ts b/pages/api/v1/avatar/[id].ts
index 307cb8a..f20b9b6 100644
--- a/pages/api/v1/avatar/[id].ts
+++ b/pages/api/v1/avatar/[id].ts
@@ -1,13 +1,13 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "@/lib/api/db";
import readFile from "@/lib/api/storage/readFile";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function Index(req: NextApiRequest, res: NextApiResponse) {
const queryId = Number(req.query.id);
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (!queryId)
return res
diff --git a/pages/api/v1/collections/[id].ts b/pages/api/v1/collections/[id].ts
index 6f98690..4f8020c 100644
--- a/pages/api/v1/collections/[id].ts
+++ b/pages/api/v1/collections/[id].ts
@@ -1,14 +1,14 @@
import type { NextApiRequest, NextApiResponse } from "next";
import updateCollectionById from "@/lib/api/controllers/collections/collectionId/updateCollectionById";
import deleteCollectionById from "@/lib/api/controllers/collections/collectionId/deleteCollectionById";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function collections(
req: NextApiRequest,
res: NextApiResponse
) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "PUT") {
const updated = await updateCollectionById(
diff --git a/pages/api/v1/collections/index.ts b/pages/api/v1/collections/index.ts
index 5f938f5..3b229dd 100644
--- a/pages/api/v1/collections/index.ts
+++ b/pages/api/v1/collections/index.ts
@@ -1,14 +1,14 @@
import type { NextApiRequest, NextApiResponse } from "next";
import getCollections from "@/lib/api/controllers/collections/getCollections";
import postCollection from "@/lib/api/controllers/collections/postCollection";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function collections(
req: NextApiRequest,
res: NextApiResponse
) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
const collections = await getCollections(user.id);
diff --git a/pages/api/v1/dashboard/index.ts b/pages/api/v1/dashboard/index.ts
index dfbd50a..ea2a3da 100644
--- a/pages/api/v1/dashboard/index.ts
+++ b/pages/api/v1/dashboard/index.ts
@@ -1,11 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { LinkRequestQuery } from "@/types/global";
import getDashboardData from "@/lib/api/controllers/dashboard/getDashboardData";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function links(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
const convertedData: LinkRequestQuery = {
diff --git a/pages/api/v1/links/[id]/archive/index.ts b/pages/api/v1/links/[id]/archive/index.ts
index 2306202..7fc141f 100644
--- a/pages/api/v1/links/[id]/archive/index.ts
+++ b/pages/api/v1/links/[id]/archive/index.ts
@@ -1,13 +1,13 @@
import type { NextApiRequest, NextApiResponse } from "next";
import archive from "@/lib/api/archive";
import { prisma } from "@/lib/api/db";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
const RE_ARCHIVE_LIMIT = Number(process.env.RE_ARCHIVE_LIMIT) || 5;
export default async function links(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
const link = await prisma.link.findUnique({
where: {
diff --git a/pages/api/v1/links/[id]/index.ts b/pages/api/v1/links/[id]/index.ts
index 290aea5..146ecb2 100644
--- a/pages/api/v1/links/[id]/index.ts
+++ b/pages/api/v1/links/[id]/index.ts
@@ -2,11 +2,11 @@ import type { NextApiRequest, NextApiResponse } from "next";
import deleteLinkById from "@/lib/api/controllers/links/linkId/deleteLinkById";
import updateLinkById from "@/lib/api/controllers/links/linkId/updateLinkById";
import getLinkById from "@/lib/api/controllers/links/linkId/getLinkById";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function links(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
const updated = await getLinkById(user.id, Number(req.query.id));
diff --git a/pages/api/v1/links/index.ts b/pages/api/v1/links/index.ts
index 35dcacc..58a352a 100644
--- a/pages/api/v1/links/index.ts
+++ b/pages/api/v1/links/index.ts
@@ -2,11 +2,11 @@ import type { NextApiRequest, NextApiResponse } from "next";
import getLinks from "@/lib/api/controllers/links/getLinks";
import postLink from "@/lib/api/controllers/links/postLink";
import { LinkRequestQuery } from "@/types/global";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function links(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
// Convert the type of the request query to "LinkRequestQuery"
diff --git a/pages/api/v1/migration/index.ts b/pages/api/v1/migration/index.ts
index 74db8c6..4afd7e7 100644
--- a/pages/api/v1/migration/index.ts
+++ b/pages/api/v1/migration/index.ts
@@ -3,7 +3,7 @@ import exportData from "@/lib/api/controllers/migration/exportData";
import importFromHTMLFile from "@/lib/api/controllers/migration/importFromHTMLFile";
import importFromLinkwarden from "@/lib/api/controllers/migration/importFromLinkwarden";
import { MigrationFormat, MigrationRequest } from "@/types/global";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export const config = {
api: {
@@ -14,8 +14,8 @@ export const config = {
};
export default async function users(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
const data = await exportData(user.id);
diff --git a/pages/api/v1/payment/index.ts b/pages/api/v1/payment/index.ts
index 2404610..779d646 100644
--- a/pages/api/v1/payment/index.ts
+++ b/pages/api/v1/payment/index.ts
@@ -1,19 +1,27 @@
import type { NextApiRequest, NextApiResponse } from "next";
import paymentCheckout from "@/lib/api/paymentCheckout";
import { Plan } from "@/types/global";
-import authenticateUser from "@/lib/api/authenticateUser";
+import { getToken } from "next-auth/jwt";
+import { prisma } from "@/lib/api/db";
export default async function users(req: NextApiRequest, res: NextApiResponse) {
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
const MONTHLY_PRICE_ID = process.env.MONTHLY_PRICE_ID;
const YEARLY_PRICE_ID = process.env.YEARLY_PRICE_ID;
- if (!STRIPE_SECRET_KEY || !MONTHLY_PRICE_ID || !YEARLY_PRICE_ID) {
- return res.status(400).json({ response: "Payment is disabled." });
- }
+ const token = await getToken({ req });
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ if (!STRIPE_SECRET_KEY || !MONTHLY_PRICE_ID || !YEARLY_PRICE_ID)
+ return res.status(400).json({ response: "Payment is disabled." });
+
+ console.log(token);
+
+ if (!token?.id) return res.status(404).json({ response: "Token invalid." });
+
+ const email = (await prisma.user.findUnique({ where: { id: token.id } }))
+ ?.email;
+
+ if (!email) return res.status(404).json({ response: "User not found." });
let PRICE_ID = MONTHLY_PRICE_ID;
@@ -25,7 +33,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
const users = await paymentCheckout(
STRIPE_SECRET_KEY,
- user.email as string,
+ email as string,
PRICE_ID
);
return res.status(users.status).json({ response: users.response });
diff --git a/pages/api/v1/public/users/[id].ts b/pages/api/v1/public/users/[id].ts
new file mode 100644
index 0000000..5126740
--- /dev/null
+++ b/pages/api/v1/public/users/[id].ts
@@ -0,0 +1,18 @@
+import type { NextApiRequest, NextApiResponse } from "next";
+import getPublicUserById from "@/lib/api/controllers/public/users/getPublicUserById";
+import { getToken } from "next-auth/jwt";
+
+export default async function users(req: NextApiRequest, res: NextApiResponse) {
+ const token = await getToken({ req });
+ const requestingId = token?.id;
+
+ const lookupId = req.query.id as string;
+
+ // Check if "lookupId" is the user "id" or their "username"
+ const isId = lookupId.split("").every((e) => Number.isInteger(parseInt(e)));
+
+ if (req.method === "GET") {
+ const users = await getPublicUserById(lookupId, isId, requestingId);
+ return res.status(users.status).json({ response: users.response });
+ }
+}
diff --git a/pages/api/v1/tags/[id].ts b/pages/api/v1/tags/[id].ts
index 3a6b5f3..d82b1f7 100644
--- a/pages/api/v1/tags/[id].ts
+++ b/pages/api/v1/tags/[id].ts
@@ -1,11 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import updeteTagById from "@/lib/api/controllers/tags/tagId/updeteTagById";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
import deleteTagById from "@/lib/api/controllers/tags/tagId/deleteTagById";
export default async function tags(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
const tagId = Number(req.query.id);
diff --git a/pages/api/v1/tags/index.ts b/pages/api/v1/tags/index.ts
index dd4cd39..2376ef9 100644
--- a/pages/api/v1/tags/index.ts
+++ b/pages/api/v1/tags/index.ts
@@ -1,10 +1,10 @@
import type { NextApiRequest, NextApiResponse } from "next";
import getTags from "@/lib/api/controllers/tags/getTags";
-import authenticateUser from "@/lib/api/authenticateUser";
+import verifyUser from "@/lib/api/verifyUser";
export default async function tags(req: NextApiRequest, res: NextApiResponse) {
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ const user = await verifyUser({ req, res });
+ if (!user) return;
if (req.method === "GET") {
const tags = await getTags(user.id);
diff --git a/pages/api/v1/users/[id].ts b/pages/api/v1/users/[id].ts
index 0c69c25..6063d53 100644
--- a/pages/api/v1/users/[id].ts
+++ b/pages/api/v1/users/[id].ts
@@ -1,48 +1,58 @@
import type { NextApiRequest, NextApiResponse } from "next";
import getUserById from "@/lib/api/controllers/users/userId/getUserById";
-import getPublicUserById from "@/lib/api/controllers/users/userId/getPublicUserById";
import updateUserById from "@/lib/api/controllers/users/userId/updateUserById";
import deleteUserById from "@/lib/api/controllers/users/userId/deleteUserById";
-import authenticateUser from "@/lib/api/authenticateUser";
-import { prisma } from "@/lib/api/db";
import { getToken } from "next-auth/jwt";
+import { prisma } from "@/lib/api/db";
+import verifySubscription from "@/lib/api/verifySubscription";
+
+const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
export default async function users(req: NextApiRequest, res: NextApiResponse) {
const token = await getToken({ req });
const userId = token?.id;
- if (!token?.id)
- return res.status(400).json({ response: "Invalid parameters." });
+ if (!userId) {
+ return res.status(401).json({ response: "You must be logged in." });
+ }
- const username = (await prisma.user.findUnique({ where: { id: token.id } }))
- ?.username;
+ if (userId !== Number(req.query.id))
+ return res.status(401).json({ response: "Permission denied." });
- if (!username) return res.status(404).json({ response: "User not found." });
-
- const lookupId = req.query.id as string;
- const isSelf =
- userId === Number(lookupId) || username === lookupId ? true : false;
-
- // Check if "lookupId" is the user "id" or their "username"
- const isId = lookupId.split("").every((e) => Number.isInteger(parseInt(e)));
-
- if (req.method === "GET" && !isSelf) {
- const users = await getPublicUserById(lookupId, isId, username);
+ if (req.method === "GET") {
+ const users = await getUserById(userId);
return res.status(users.status).json({ response: users.response });
}
- const user = await authenticateUser({ req, res });
- if (!user) return res.status(404).json({ response: "User not found." });
+ if (STRIPE_SECRET_KEY) {
+ const user = await prisma.user.findUnique({
+ where: {
+ id: token.id,
+ },
+ include: {
+ subscriptions: true,
+ },
+ });
- if (req.method === "GET") {
- const users = await getUserById(user.id);
- return res.status(users.status).json({ response: users.response });
- } else if (req.method === "PUT") {
- const updated = await updateUserById(user.id, req.body);
+ if (user) {
+ const subscribedUser = await verifySubscription(user);
+ if (!subscribedUser) {
+ return res.status(401).json({
+ response:
+ "You are not a subscriber, feel free to reach out to us at support@linkwarden.app if you think this is an issue.",
+ });
+ }
+ } else {
+ return res.status(404).json({ response: "User not found." });
+ }
+ }
+
+ if (req.method === "PUT") {
+ const updated = await updateUserById(userId, req.body);
return res.status(updated.status).json({ response: updated.response });
- } else if (req.method === "DELETE" && user.id === Number(req.query.id)) {
+ } else if (req.method === "DELETE") {
console.log(req.body);
- const updated = await deleteUserById(user.id, req.body);
+ const updated = await deleteUserById(userId, req.body);
return res.status(updated.status).json({ response: updated.response });
}
}
diff --git a/pages/index.tsx b/pages/index.tsx
index e4679ca..aa5897c 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,10 +1,3 @@
-import { useRouter } from "next/router";
-import { useEffect } from "react";
-
export default function Index() {
- const router = useRouter();
-
- useEffect(() => {
- router.push("/dashboard");
- }, []);
+ return null;
}
diff --git a/pages/register.tsx b/pages/register.tsx
index 62ce26d..f836843 100644
--- a/pages/register.tsx
+++ b/pages/register.tsx
@@ -96,7 +96,7 @@ export default function Register() {
return (
- {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? (
+ {process.env.NEXT_PUBLIC_STRIPE ? (
By signing up, you agree to our{" "}
diff --git a/pages/settings/account.tsx b/pages/settings/account.tsx
index d177025..0642424 100644
--- a/pages/settings/account.tsx
+++ b/pages/settings/account.tsx
@@ -86,20 +86,6 @@ export default function Account() {
if (response.ok) {
toast.success("Settings Applied!");
-
- // if (user.email !== account.email) {
- // update({
- // id: data?.user.id,
- // });
-
- // signOut();
- // } else if (
- // user.username !== account.username ||
- // user.name !== account.name
- // )
- // update({
- // id: data?.user.id,
- // });
} else toast.error(response.data as string);
setSubmitLoader(false);
};
@@ -190,7 +176,7 @@ export default function Account() {
Email
{user.email !== account.email &&
- process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE === "true" ? (
+ process.env.NEXT_PUBLIC_STRIPE === "true" ? (
Updating this field will change your billing email as well
@@ -388,7 +374,7 @@ export default function Account() {
This will permanently delete ALL the Links, Collections, Tags, and
archived data you own.{" "}
- {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE
+ {process.env.NEXT_PUBLIC_STRIPE
? "It will also cancel your subscription. "
: undefined}{" "}
You will be prompted to enter your password before the deletion
diff --git a/pages/settings/billing.tsx b/pages/settings/billing.tsx
index 185f2a7..953d1ee 100644
--- a/pages/settings/billing.tsx
+++ b/pages/settings/billing.tsx
@@ -6,8 +6,7 @@ export default function Billing() {
const router = useRouter();
useEffect(() => {
- if (!process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE)
- router.push("/settings/profile");
+ if (!process.env.NEXT_PUBLIC_STRIPE) router.push("/settings/profile");
}, []);
return (
diff --git a/pages/settings/delete.tsx b/pages/settings/delete.tsx
index a0096e1..bd0c632 100644
--- a/pages/settings/delete.tsx
+++ b/pages/settings/delete.tsx
@@ -72,7 +72,7 @@ export default function Password() {
This will permanently delete all the Links, Collections, Tags, and
archived data you own. It will also log you out
- {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE
+ {process.env.NEXT_PUBLIC_STRIPE
? " and cancel your subscription"
: undefined}
. This action is irreversible!
@@ -91,7 +91,7 @@ export default function Password() {
/>
- {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? (
+ {process.env.NEXT_PUBLIC_STRIPE ? (