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
2 changes: 1 addition & 1 deletion apps/wallet-ui/src/app/[ecosystem]/(authed)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default async function Layout(props: {

const { children } = props;

await authedOnly();
await authedOnly(params.ecosystem);
const ecosystem = await getEcosystemInfo(params.ecosystem);
return (
<div className="flex w-full flex-col items-stretch">
Expand Down
6 changes: 4 additions & 2 deletions apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { getCurrentUser } from "../../../lib/auth";

export default async function Layout({
children,
}: { children: React.ReactNode }) {
params,
}: { children: React.ReactNode; params: Promise<{ ecosystem: string }> }) {
const { ecosystem } = await params;
const userAddress = await getCurrentUser();
if (userAddress) {
redirect(`/wallet/${userAddress}`);
redirect(`${ecosystem}/wallet/${userAddress}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

The redirect path is missing a leading forward slash, which could cause navigation issues. The correct path should be:

redirect(`/${ecosystem}/wallet/${userAddress}`)

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

}

return (
Expand Down
13 changes: 8 additions & 5 deletions apps/wallet-ui/src/app/[ecosystem]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { getCurrentUser } from "@/lib/auth";
import { redirect } from "next/navigation";

export default async function Page() {
const user = await getCurrentUser();
if (user) {
redirect("/wallet/${user}");
export default async function Page({
params,
}: { params: Promise<{ ecosystem: string }> }) {
const { ecosystem } = await params;
const address = await getCurrentUser();
if (address) {
redirect(`${ecosystem}/wallet/${address}`);
}
redirect("/login");
redirect(`${ecosystem}/login`);
}
12 changes: 7 additions & 5 deletions apps/wallet-ui/src/app/[ecosystem]/wc/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { redirect } from "next/navigation";

export default async function Page(props: {
searchParams: Promise<{ uri: string }>;
params: Promise<{ ecosystem: string }>;
}) {
const searchParams = await props.searchParams;

const { uri } = searchParams;
const [{ uri }, { ecosystem }] = await Promise.all([
props.searchParams,
props.params,
]);

const currentUser = await getCurrentUser();

if (!currentUser) {
redirect(`/login?uri=${encodeURIComponent(uri)}`);
redirect(`${ecosystem}/login?uri=${encodeURIComponent(uri)}`);
}

redirect(`/wallet/${currentUser}?uri=${encodeURIComponent(uri)}`);
redirect(`${ecosystem}/wallet/${currentUser}?uri=${encodeURIComponent(uri)}`);
}
4 changes: 4 additions & 0 deletions apps/wallet-ui/src/components/ConnectButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use client";
import { logout } from "@/lib/auth";
import { client } from "@/lib/client";
import { useTheme } from "next-themes";
import {
Expand All @@ -23,6 +24,9 @@ export default function ConnectButton({
wallets={[ecosystemWallet(ecosystem)]}
client={client}
theme={theme === "light" ? "light" : "dark"}
onDisconnect={() => {
logout();
}}
/>
);
}
2 changes: 1 addition & 1 deletion apps/wallet-ui/src/components/ConnectEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function ConnectEmbed() {
const success = await login(loginParams);
if (success) {
router.push(
`/wallet/${loginParams.payload.address}?${searchParams.toString()}`,
`/${params.ecosystem}/wallet/${loginParams.payload.address}?${searchParams.toString()}`,
);
}
},
Expand Down
7 changes: 3 additions & 4 deletions apps/wallet-ui/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,22 @@ export async function login(payload: VerifyLoginPayloadParams) {
name: "jwt",
value: jwt,
httpOnly: true,
secure: process.env.NODE_ENV !== "development",
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 3600,
domain: process.env.NEXT_PUBLIC_ROOT_DOMAIN,
path: "/",
});
return true;
}
return false;
}

export async function authedOnly() {
export async function authedOnly(ecosystem?: string) {
const loggedIn = await getCurrentUser();
if (loggedIn) {
return;
}
redirect("/login");
redirect(`/${ecosystem || ""}/login`);
}

export async function isLoggedIn(): Promise<boolean> {
Expand Down
45 changes: 17 additions & 28 deletions apps/wallet-ui/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,25 @@
import { type NextRequest, NextResponse } from "next/server";

export const config = {
matcher: [
/*
* Match all paths except for:
* 1. /api routes
* 2. /_next (Next.js internals)
* 3. /_static (inside /public)
* 4. all root files inside /public (e.g. /favicon.ico)
*/
"/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)",
],
};
export const config = { matcher: "/((?!.*\\.).*)" };

const ROOT_DOMAIN = process.env.NEXT_PUBLIC_ROOT_DOMAIN;
export default async function middleware(req: NextRequest) {
// Get the request hostname (e.g. demo.thirdweb.com)
const hostname = req.headers.get("host");
export function middleware(request: NextRequest) {
const url = request.nextUrl;
const hostname = request.headers.get("host") || "";

const searchParams = req.nextUrl.searchParams.toString();
const url = req.nextUrl;
const path = `${url.pathname}${
searchParams.length > 0 ? `?${searchParams}` : ""
}`;
// Match pattern: something.ecosystem.domain.tld
const match = hostname.match(/^([^.]+)\.ecosystem\.([^.]+\.[^.]+)$/);

// keep root application at `/`
if (hostname === ROOT_DOMAIN || hostname === null) {
return NextResponse.next();
}
if (match) {
const [_, subdomain, primaryDomain] = match;

// Redirect to ecosystem.domain.tld/subdomain
const newUrl = new URL(`${url.protocol}//ecosystem.${primaryDomain}`);
newUrl.pathname = `/${subdomain}${url.pathname}`;
newUrl.search = url.search;

// rewrite everything else to `/[ecosystem]/... dynamic route
const ecosystem = hostname.split(".")[0];
// 308 is permanent redirect, preserves request method
return NextResponse.redirect(newUrl, 308);
}

return NextResponse.rewrite(new URL(`/${ecosystem}${path}`, req.url));
return NextResponse.next();
}