mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-01 16:45:40 +02:00
fix rendering issues on resource unauthorized
This commit is contained in:
parent
5bbf32f6a6
commit
500a81aa42
8 changed files with 58 additions and 20 deletions
|
@ -4,7 +4,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "ENVIRONMENT=dev tsx watch server/index.ts",
|
"dev": "NODE_ENV=development ENVIRONMENT=dev tsx watch server/index.ts",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
"db:push": "npx tsx server/db/migrate.ts",
|
"db:push": "npx tsx server/db/migrate.ts",
|
||||||
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
||||||
|
|
|
@ -51,7 +51,7 @@ app.prepare().then(() => {
|
||||||
externalServer.use(logIncomingMiddleware);
|
externalServer.use(logIncomingMiddleware);
|
||||||
externalServer.use(prefix, unauthenticated);
|
externalServer.use(prefix, unauthenticated);
|
||||||
externalServer.use(prefix, authenticated);
|
externalServer.use(prefix, authenticated);
|
||||||
externalServer.use(`${prefix}/ws`, wsRouter);
|
// externalServer.use(`${prefix}/ws`, wsRouter);
|
||||||
|
|
||||||
externalServer.use(notFoundMiddleware);
|
externalServer.use(notFoundMiddleware);
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ app.prepare().then(() => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
handleWSUpgrade(httpServer);
|
// handleWSUpgrade(httpServer);
|
||||||
|
|
||||||
externalServer.use(errorHandlerMiddleware);
|
externalServer.use(errorHandlerMiddleware);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
resourcePassword,
|
resourcePassword,
|
||||||
resourcePincode,
|
resourcePincode,
|
||||||
resources,
|
resources,
|
||||||
|
User,
|
||||||
userOrgs,
|
userOrgs,
|
||||||
} from "@server/db/schema";
|
} from "@server/db/schema";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
|
@ -106,7 +107,7 @@ export async function verifyResourceSession(
|
||||||
const { session, user } = await validateSessionToken(sessionToken);
|
const { session, user } = await validateSessionToken(sessionToken);
|
||||||
if (session && user) {
|
if (session && user) {
|
||||||
const isAllowed = await isUserAllowedToAccessResource(
|
const isAllowed = await isUserAllowedToAccessResource(
|
||||||
user.userId,
|
user,
|
||||||
resource,
|
resource,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -191,15 +192,19 @@ function allowed(res: Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isUserAllowedToAccessResource(
|
async function isUserAllowedToAccessResource(
|
||||||
userId: string,
|
user: User,
|
||||||
resource: Resource,
|
resource: Resource,
|
||||||
) {
|
): Promise<boolean> {
|
||||||
|
if (config.flags?.require_email_verification && !user.emailVerified) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const userOrgRole = await db
|
const userOrgRole = await db
|
||||||
.select()
|
.select()
|
||||||
.from(userOrgs)
|
.from(userOrgs)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(userOrgs.userId, userId),
|
eq(userOrgs.userId, user.userId),
|
||||||
eq(userOrgs.orgId, resource.orgId),
|
eq(userOrgs.orgId, resource.orgId),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -229,7 +234,7 @@ async function isUserAllowedToAccessResource(
|
||||||
.from(userResources)
|
.from(userResources)
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(userResources.userId, userId),
|
eq(userResources.userId, user.userId),
|
||||||
eq(userResources.resourceId, resource.resourceId),
|
eq(userResources.resourceId, resource.resourceId),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Button } from "@app/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
@ -5,8 +8,9 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@app/components/ui/card";
|
} from "@app/components/ui/card";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default async function ResourceAccessDenied() {
|
export default function ResourceAccessDenied() {
|
||||||
return (
|
return (
|
||||||
<Card className="w-full max-w-md">
|
<Card className="w-full max-w-md">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
@ -17,6 +21,11 @@ export default async function ResourceAccessDenied() {
|
||||||
<CardContent>
|
<CardContent>
|
||||||
You're not alowed to access this resource. If this is a mistake,
|
You're not alowed to access this resource. If this is a mistake,
|
||||||
please contact the administrator.
|
please contact the administrator.
|
||||||
|
<div className="text-center mt-4">
|
||||||
|
<Button>
|
||||||
|
<Link href="/">Go Home</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
@ -23,7 +23,7 @@ import {
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { LockIcon, UserIcon, Binary, Key, User } from "lucide-react";
|
import { LockIcon, Binary, Key, User } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
InputOTP,
|
InputOTP,
|
||||||
InputOTPGroup,
|
InputOTPGroup,
|
||||||
|
@ -34,11 +34,10 @@ import { useRouter } from "next/navigation";
|
||||||
import { Alert, AlertDescription } from "@app/components/ui/alert";
|
import { Alert, AlertDescription } from "@app/components/ui/alert";
|
||||||
import { formatAxiosError } from "@app/lib/utils";
|
import { formatAxiosError } from "@app/lib/utils";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { LoginResponse } from "@server/routers/auth";
|
|
||||||
import ResourceAccessDenied from "./ResourceAccessDenied";
|
|
||||||
import LoginForm from "@app/components/LoginForm";
|
import LoginForm from "@app/components/LoginForm";
|
||||||
import { AuthWithPasswordResponse } from "@server/routers/resource";
|
import { AuthWithPasswordResponse } from "@server/routers/resource";
|
||||||
import { redirect } from "next/dist/server/api-utils";
|
import { redirect } from "next/dist/server/api-utils";
|
||||||
|
import ResourceAccessDenied from "./ResourceAccessDenied";
|
||||||
|
|
||||||
const pinSchema = z.object({
|
const pinSchema = z.object({
|
||||||
pin: z
|
pin: z
|
||||||
|
@ -159,13 +158,15 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleSSOAuth() {
|
async function handleSSOAuth() {
|
||||||
|
let isAllowed = false;
|
||||||
try {
|
try {
|
||||||
await api.get(`/resource/${props.resource.id}`);
|
await api.get(`/resource/${props.resource.id}`);
|
||||||
|
isAllowed = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setAccessDenied(true);
|
setAccessDenied(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accessDenied) {
|
if (isAllowed) {
|
||||||
window.location.href = props.redirect;
|
window.location.href = props.redirect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,6 +175,11 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
<div>
|
<div>
|
||||||
{!accessDenied ? (
|
{!accessDenied ? (
|
||||||
<div>
|
<div>
|
||||||
|
<div className="text-center mb-2">
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
Powered by Fossorial
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Authentication Required</CardTitle>
|
<CardTitle>Authentication Required</CardTitle>
|
||||||
|
@ -365,7 +371,11 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
className={`${numMethods <= 1 ? "mt-0" : ""}`}
|
className={`${numMethods <= 1 ? "mt-0" : ""}`}
|
||||||
>
|
>
|
||||||
<LoginForm
|
<LoginForm
|
||||||
redirect={window.location.href}
|
redirect={
|
||||||
|
typeof window !== "undefined"
|
||||||
|
? window.location.href
|
||||||
|
: ""
|
||||||
|
}
|
||||||
onLogin={async () =>
|
onLogin={async () =>
|
||||||
await handleSSOAuth()
|
await handleSSOAuth()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Button } from "@app/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
@ -5,6 +6,7 @@ import {
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@app/components/ui/card";
|
} from "@app/components/ui/card";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default async function ResourceNotFound() {
|
export default async function ResourceNotFound() {
|
||||||
return (
|
return (
|
||||||
|
@ -15,7 +17,12 @@ export default async function ResourceNotFound() {
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
The resource you're trying to access does not exist
|
The resource you're trying to access does not exist.
|
||||||
|
<div className="text-center mt-4">
|
||||||
|
<Button>
|
||||||
|
<Link href="/">Go Home</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default async function ResourceAuthPage(props: {
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
const getUser = cache(verifySession);
|
const getUser = cache(verifySession);
|
||||||
const user = await getUser();
|
const user = await getUser({ skipCheckVerifyEmail: true });
|
||||||
|
|
||||||
if (!authInfo) {
|
if (!authInfo) {
|
||||||
return (
|
return (
|
||||||
|
@ -48,6 +48,16 @@ export default async function ResourceAuthPage(props: {
|
||||||
|
|
||||||
const redirectUrl = searchParams.redirect || authInfo.url;
|
const redirectUrl = searchParams.redirect || authInfo.url;
|
||||||
|
|
||||||
|
if (
|
||||||
|
user &&
|
||||||
|
!user.emailVerified &&
|
||||||
|
process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED === "true"
|
||||||
|
) {
|
||||||
|
redirect(
|
||||||
|
`/auth/verify-email?redirect=/auth/resource/${authInfo.resourceId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const allCookies = await cookies();
|
const allCookies = await cookies();
|
||||||
const cookieName =
|
const cookieName =
|
||||||
process.env.RESOURCE_SESSION_COOKIE_NAME + `_${params.resourceId}`;
|
process.env.RESOURCE_SESSION_COOKIE_NAME + `_${params.resourceId}`;
|
||||||
|
|
|
@ -72,14 +72,11 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
if (res && res.status === 200) {
|
if (res && res.status === 200) {
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
if (res.data?.data?.emailVerificationRequired) {
|
if (res.data?.data?.emailVerificationRequired) {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
console.log("here", redirect)
|
|
||||||
router.push(`/auth/verify-email?redirect=${redirect}`);
|
router.push(`/auth/verify-email?redirect=${redirect}`);
|
||||||
} else {
|
} else {
|
||||||
router.push("/auth/verify-email");
|
router.push("/auth/verify-email");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue