From 8f7f18e069b11152f25b16e92fabdff56e62e032 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 4 Jan 2024 21:57:32 +0000 Subject: [PATCH] Added impersonation for admins --- app/api/account/impersonate/route.ts | 91 +++++++++++++++ app/api/account/route.ts | 4 +- .../connections/twitch/delete/route.ts | 4 +- app/api/settings/connections/twitch/route.ts | 4 +- app/api/settings/tts/default/route.ts | 6 +- app/api/settings/tts/filter/users/route.ts | 8 +- app/api/settings/tts/filter/words/route.ts | 17 +-- app/api/settings/tts/route.ts | 6 +- app/api/token/[id]/route.ts | 21 +++- app/api/token/bot/route.ts | 4 +- app/api/token/route.ts | 17 ++- app/api/tokens/route.ts | 4 +- app/api/users/route.ts | 41 +++++++ app/settings/api/keys/page.tsx | 15 --- app/settings/tts/filters/page.tsx | 24 ++-- app/settings/tts/voices/page.tsx | 8 +- auth.ts | 41 ++++++- components/navigation/adminprofile.tsx | 108 +++++++++++++++++- components/navigation/settings.tsx | 24 ++-- components/navigation/userprofile.tsx | 2 +- data/impersonation.ts | 10 ++ lib/fetch-user-impersonation.ts | 67 +++++++++++ lib/fetch-user.ts | 43 +++++++ lib/validate-api.ts | 40 ------- prisma/schema.prisma | 16 +++ 25 files changed, 494 insertions(+), 131 deletions(-) create mode 100644 app/api/account/impersonate/route.ts create mode 100644 app/api/users/route.ts create mode 100644 data/impersonation.ts create mode 100644 lib/fetch-user-impersonation.ts create mode 100644 lib/fetch-user.ts delete mode 100644 lib/validate-api.ts diff --git a/app/api/account/impersonate/route.ts b/app/api/account/impersonate/route.ts new file mode 100644 index 0000000..1887674 --- /dev/null +++ b/app/api/account/impersonate/route.ts @@ -0,0 +1,91 @@ +import { db } from "@/lib/db" +import { NextResponse } from "next/server"; +import fetchUser from "@/lib/fetch-user"; + +export async function GET(req: Request) { + try { + const user = await fetchUser(req) + if (!user || user.role != "ADMIN") { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const impersonation = await db.impersonation.findFirst({ + where: { + sourceId: user.id + } + }); + + return NextResponse.json(impersonation); + } catch (error) { + console.log("[AUTH/ACCOUNT/IMPERSONATION]", error); + return new NextResponse("Internal Error", { status: 500 }); + } +} + +export async function POST(req: Request) { + try { + const user = await fetchUser(req) + if (!user || user.role != "ADMIN") { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const { targetId } = await req.json(); + + const impersonation = await db.impersonation.create({ + data: { + sourceId: user.id, + targetId + } + }); + + return NextResponse.json(impersonation); + } catch (error) { + console.log("[AUTH/ACCOUNT/IMPERSONATION]", error); + return new NextResponse("Internal Error", { status: 500 }); + } +} + +export async function PUT(req: Request) { + try { + const user = await fetchUser(req) + if (!user || user.role != "ADMIN") { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const { targetId } = await req.json(); + + const impersonation = await db.impersonation.update({ + where: { + sourceId: user.id, + }, + data: { + targetId + } + }); + + return NextResponse.json(impersonation); + } catch (error) { + console.log("[AUTH/ACCOUNT/IMPERSONATION]", error); + return new NextResponse("Internal Error", { status: 500 }); + } +} + +export async function DELETE(req: Request) { + try { + const user = await fetchUser(req) + if (!user || user.role != "ADMIN") { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const impersonation = await db.impersonation.delete({ + where: { + sourceId: user.id + } + }); + + return NextResponse.json(impersonation) + } catch (error) { + console.log("[AUTH/ACCOUNT/IMPERSONATION]", error); + return new NextResponse("Internal Error" + error, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/api/account/route.ts b/app/api/account/route.ts index 9db57cd..28e4b63 100644 --- a/app/api/account/route.ts +++ b/app/api/account/route.ts @@ -1,12 +1,12 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; import { auth } from "@/auth"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUser from "@/lib/fetch-user"; export async function GET(req: Request) { try { - return NextResponse.json(await fetchUserUsingAPI(req)) + return NextResponse.json(await fetchUser(req)) } catch (error) { console.log("[ACCOUNT]", error); return new NextResponse("Internal Error", { status: 500 }); diff --git a/app/api/settings/connections/twitch/delete/route.ts b/app/api/settings/connections/twitch/delete/route.ts index 6ed56dc..42efdaf 100644 --- a/app/api/settings/connections/twitch/delete/route.ts +++ b/app/api/settings/connections/twitch/delete/route.ts @@ -1,10 +1,10 @@ import { db } from "@/lib/db" -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import { NextResponse } from "next/server"; export async function POST(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/settings/connections/twitch/route.ts b/app/api/settings/connections/twitch/route.ts index 149fa01..b2712e8 100644 --- a/app/api/settings/connections/twitch/route.ts +++ b/app/api/settings/connections/twitch/route.ts @@ -1,10 +1,10 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/settings/tts/default/route.ts b/app/api/settings/tts/default/route.ts index 53b85f9..0d5d498 100644 --- a/app/api/settings/tts/default/route.ts +++ b/app/api/settings/tts/default/route.ts @@ -1,11 +1,11 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import voices from "@/data/tts"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -26,7 +26,7 @@ export async function GET(req: Request) { export async function POST(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/settings/tts/filter/users/route.ts b/app/api/settings/tts/filter/users/route.ts index ef17317..551a6cd 100644 --- a/app/api/settings/tts/filter/users/route.ts +++ b/app/api/settings/tts/filter/users/route.ts @@ -1,10 +1,10 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -24,7 +24,7 @@ export async function GET(req: Request) { export async function POST(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -57,7 +57,7 @@ export async function POST(req: Request) { export async function DELETE(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/settings/tts/filter/words/route.ts b/app/api/settings/tts/filter/words/route.ts index 88c8029..080d271 100644 --- a/app/api/settings/tts/filter/words/route.ts +++ b/app/api/settings/tts/filter/words/route.ts @@ -1,10 +1,10 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -24,7 +24,7 @@ export async function GET(req: Request) { export async function POST(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -35,7 +35,7 @@ export async function POST(req: Request) { data: { search, replace, - userId: user.id as string + userId: user.id } }); @@ -48,7 +48,7 @@ export async function POST(req: Request) { export async function PUT(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -61,7 +61,8 @@ export async function PUT(req: Request) { }, data: { search, - replace + replace, + userId: user.id } }); @@ -74,7 +75,7 @@ export async function PUT(req: Request) { export async function DELETE(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -87,7 +88,7 @@ export async function DELETE(req: Request) { const filter = await db.ttsWordFilter.delete({ where: { userId_search: { - userId: user.id as string, + userId: user.id, search } } diff --git a/app/api/settings/tts/route.ts b/app/api/settings/tts/route.ts index 58ce379..e9c0cd2 100644 --- a/app/api/settings/tts/route.ts +++ b/app/api/settings/tts/route.ts @@ -1,11 +1,11 @@ import { db } from "@/lib/db" import { NextResponse } from "next/server"; -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import voices from "@/data/tts"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } @@ -40,7 +40,7 @@ export async function GET(req: Request) { export async function POST(req: Request) { try { - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/token/[id]/route.ts b/app/api/token/[id]/route.ts index bfac406..09b43f8 100644 --- a/app/api/token/[id]/route.ts +++ b/app/api/token/[id]/route.ts @@ -1,12 +1,17 @@ import { db } from "@/lib/db" -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import { NextResponse } from "next/server"; export async function GET(req: Request, { params } : { params: { id: string } }) { try { + const user = await fetchUserWithImpersonation(req) + if (!user) { + return new NextResponse("Unauthorized", { status: 401 }); + } + let id = req.headers?.get('x-api-key') if (id == null) { - return NextResponse.json(null); + return NextResponse.json(null); } const tokens = await db.apiKey.findFirst({ @@ -18,15 +23,19 @@ export async function GET(req: Request, { params } : { params: { id: string } }) return NextResponse.json(tokens); } catch (error) { console.log("[TOKEN/GET]", error); - return new NextResponse("Internal Error", { status: 500}); + return new NextResponse("Internal Error", { status: 500 }); } } export async function DELETE(req: Request, { params } : { params: { id: string } }) { try { - const { id } = params - const user = await fetchUserUsingAPI(req) + const user = await fetchUserWithImpersonation(req) + if (!user) { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const { id } = params const token = await db.apiKey.delete({ where: { id, @@ -37,6 +46,6 @@ export async function DELETE(req: Request, { params } : { params: { id: string } return NextResponse.json(token); } catch (error) { console.log("[TOKEN/DELETE]", error); - return new NextResponse("Internal Error", { status: 500}); + return new NextResponse("Internal Error", { status: 500 }); } } \ No newline at end of file diff --git a/app/api/token/bot/route.ts b/app/api/token/bot/route.ts index c876f7b..cca9cdf 100644 --- a/app/api/token/bot/route.ts +++ b/app/api/token/bot/route.ts @@ -1,10 +1,10 @@ import { db } from "@/lib/db" -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import { NextResponse } from "next/server"; export async function GET(req: Request) { try { - const user = await fetchUserUsingAPI(req); + const user = await fetchUserWithImpersonation(req); if (!user) { return new NextResponse("Unauthorized", { status: 401 }); } diff --git a/app/api/token/route.ts b/app/api/token/route.ts index fc9aa43..3609867 100644 --- a/app/api/token/route.ts +++ b/app/api/token/route.ts @@ -1,13 +1,18 @@ -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUserWithImpersonation from "@/lib/fetch-user-impersonation"; import { db } from "@/lib/db" import { NextResponse } from "next/server"; export async function POST(req: Request) { try { + const user = await fetchUserWithImpersonation(req) + if (!user) { + return new NextResponse("Unauthorized", { status: 401 }); + } + let { userId, label } = await req.json(); if (userId == null) { - const user = await fetchUserUsingAPI(req); + const user = await fetchUserWithImpersonation(req); if (user != null) { userId = user.id; } @@ -31,9 +36,13 @@ export async function POST(req: Request) { export async function DELETE(req: Request) { try { + const user = await fetchUserWithImpersonation(req) + if (!user) { + return new NextResponse("Unauthorized", { status: 401 }); + } + let { id } = await req.json(); - const user = await fetchUserUsingAPI(req); - if (!id || !user) { + if (!id) { return NextResponse.json(null) } diff --git a/app/api/tokens/route.ts b/app/api/tokens/route.ts index 9199d81..6f69725 100644 --- a/app/api/tokens/route.ts +++ b/app/api/tokens/route.ts @@ -1,4 +1,4 @@ -import fetchUserUsingAPI from "@/lib/validate-api"; +import fetchUser from "@/lib/fetch-user"; import { db } from "@/lib/db" import { NextResponse } from "next/server"; @@ -8,7 +8,7 @@ export async function GET(req: Request) { let userId = searchParams.get('userId') if (userId == null) { - const user = await fetchUserUsingAPI(req); + const user = await fetchUser(req); if (user != null) { userId = user.id as string; } diff --git a/app/api/users/route.ts b/app/api/users/route.ts new file mode 100644 index 0000000..f4f3a24 --- /dev/null +++ b/app/api/users/route.ts @@ -0,0 +1,41 @@ +import { db } from "@/lib/db" +import { NextResponse } from "next/server"; +import fetchUser from "@/lib/fetch-user"; + +export async function GET(req: Request) { + try { + const user = await fetchUser(req) + if (!user || user.role != "ADMIN") { + return new NextResponse("Unauthorized", { status: 401 }); + } + + const { searchParams } = new URL(req.url) + const qn = searchParams.get('qn') as string + const id = searchParams.get('id') as string + + if (qn) { + const users = await db.user.findMany({ + where: { + name: { + contains: qn + } + } + }) + return NextResponse.json(users) + } + if (id) { + const users = await db.user.findUnique({ + where: { + id: id + } + }) + return NextResponse.json(users) + } + + const users = await db.user.findMany(); + return NextResponse.json(users) + } catch (error) { + console.log("[AUTH/ACCOUNT/IMPERSONATION]", error); + return new NextResponse("Internal Error", { status: 500 }); + } +} \ No newline at end of file diff --git a/app/settings/api/keys/page.tsx b/app/settings/api/keys/page.tsx index d858fd7..456e720 100644 --- a/app/settings/api/keys/page.tsx +++ b/app/settings/api/keys/page.tsx @@ -20,7 +20,6 @@ const SettingsPage = () => { try { const keys = (await axios.get("/api/tokens")).data ?? {}; setApiKeys(keys) - console.log(keys); } catch (error) { console.log("ERROR", error) } @@ -49,20 +48,6 @@ const SettingsPage = () => { } } - useEffect(() => { - const fetchData = async () => { - try { - const keys = (await axios.get("/api/tokens")).data; - setApiKeys(keys) - console.log(keys); - } catch (error) { - console.log("ERROR", error) - } - }; - - fetchData().catch(console.error); - }, [apiKeyViewable]); - return (
diff --git a/app/settings/tts/filters/page.tsx b/app/settings/tts/filters/page.tsx index 4f5667d..3ecf7fc 100644 --- a/app/settings/tts/filters/page.tsx +++ b/app/settings/tts/filters/page.tsx @@ -13,8 +13,7 @@ import { useForm } from "react-hook-form"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import * as z from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; -import { DropdownMenu, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from "@/components/ui/dropdown-menu"; -import { DropdownMenuContent, DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { Label } from "@/components/ui/label"; @@ -58,7 +57,6 @@ const TTSFiltersPage = () => { try { const replacementData = await axios.get("/api/settings/tts/filter/words") - console.log(replacementData.data) setReplacements(replacementData.data ?? []) } catch (e) { console.log("ERROR", e) @@ -112,8 +110,9 @@ const TTSFiltersPage = () => { const onReplaceAdd = async () => { await axios.post("/api/settings/tts/filter/words", { search, replace }) .then(d => { - replacements.push(d.data) + replacements.push({ id: d.data.id, search: d.data.search, replace: d.data.replace, userId: d.data.userId }) setReplacements(replacements) + setSearch("") }).catch(e => { // TODO: handle already exist. console.log("LOGGED:", e) @@ -135,7 +134,9 @@ const TTSFiltersPage = () => { const onReplaceDelete = async (id: string) => { await axios.delete("/api/settings/tts/filter/words?id=" + id) .then(d => { - setReplacements(replacements.filter(r => r.id != id)) + const r = replacements.filter(r => r.id != d.data.id) + setReplacements(r) + console.log(r) }).catch(e => { // TODO: handle does not exist. console.log("LOGGED:", e) @@ -166,9 +167,9 @@ const TTSFiltersPage = () => {
TTS Filters
-
+
{userTags.map((user, index) => ( -
+

{user.tag} @@ -200,7 +201,7 @@ const TTSFiltersPage = () => { {tags.map((tag) => ( { onAddExtended({ username: userTags[index].username, tag: value}, false) @@ -216,7 +217,7 @@ const TTSFiltersPage = () => { - + Delete @@ -235,7 +236,7 @@ const TTSFiltersPage = () => { control={usernameFilteredForm.control} name="username" render={({ field }) => ( - + @@ -272,6 +273,7 @@ const TTSFiltersPage = () => { {tags.map((tag) => ( { setTag(value) setOpen(false) @@ -297,7 +299,7 @@ const TTSFiltersPage = () => {

Regex Replacement

{replacements.map((term: { id: string, search: string, replace: string, userId: string }) => ( -
+
term.search = e.target.value } defaultValue={term.search} /> term.replace = e.target.value } defaultValue={term.replace} /> + + + + + No voices found. + + {users.map((user) => ( + { + onImpersonationChange(user.id, user.name ?? "") + setOpen(false) + }} + > + + {user.name} + + ))} + + + + +
); } diff --git a/components/navigation/settings.tsx b/components/navigation/settings.tsx index 16a0578..3d4c3af 100644 --- a/components/navigation/settings.tsx +++ b/components/navigation/settings.tsx @@ -10,28 +10,26 @@ const SettingsNavigation = async () => {
Hermes
-
- - - - -
+ + + +
-
-
    -
  • +
    +
      +
    • Settings
    • -
    • - +
    • +
    • -
    • +
    • Text to Speech
    • @@ -49,7 +47,7 @@ const SettingsNavigation = async () => {
    • -
    • +
    • API
    • diff --git a/components/navigation/userprofile.tsx b/components/navigation/userprofile.tsx index 92a347b..6ac905d 100644 --- a/components/navigation/userprofile.tsx +++ b/components/navigation/userprofile.tsx @@ -32,7 +32,7 @@ const UserProfile = () => { return (
      -

      Logged in as:

      +

      Logged in as:

      {user?.username}

      ); diff --git a/data/impersonation.ts b/data/impersonation.ts new file mode 100644 index 0000000..ed44d46 --- /dev/null +++ b/data/impersonation.ts @@ -0,0 +1,10 @@ +import { db } from "@/lib/db"; + +export const getImpersonationById = async (id: string) => { + try { + const impersonation = await db.impersonation.findUnique({ where: { sourceId: id }}) + return impersonation; + } catch { + return null; + } +} \ No newline at end of file diff --git a/lib/fetch-user-impersonation.ts b/lib/fetch-user-impersonation.ts new file mode 100644 index 0000000..30433e1 --- /dev/null +++ b/lib/fetch-user-impersonation.ts @@ -0,0 +1,67 @@ +import { auth } from "@/auth"; +import { db } from "./db"; + +export default async function fetchUserWithImpersonation(req: Request) { + const session = await auth() + + if (session) { + const user = fetch(session.user.id) + if (user) { + return user + } + } + + const token = req.headers?.get('x-api-key') + if (token === null || token === undefined) + return null + + const key = await db.apiKey.findFirst({ + where: { + id: token as string + } + }) + + if (!key) return null + + return fetch(key.userId) +} + +const fetch = async (userId: string) => { + const user = await db.user.findFirst({ + where: { + id: userId + } + }) + + if (!user) return null + + if (user.role == "ADMIN") { + const impersonation = await db.impersonation.findFirst({ + where: { + sourceId: userId + } + }) + + if (impersonation) { + const copied = await db.user.findFirst({ + where: { + id: impersonation.targetId + } + }) + + if (copied) { + return { + id: copied.id, + username: copied.name, + role: copied.role + } + } + } + } + + return { + id: user.id, + username: user.name, + role: user.role + } +} \ No newline at end of file diff --git a/lib/fetch-user.ts b/lib/fetch-user.ts new file mode 100644 index 0000000..6316fb7 --- /dev/null +++ b/lib/fetch-user.ts @@ -0,0 +1,43 @@ +import { auth } from "@/auth"; +import { db } from "./db"; + +export default async function fetchUser(req: Request) { + const session = await auth() + + if (session) { + const user = fetch(session.user.id) + if (user) { + return user + } + } + + const token = req.headers?.get('x-api-key') + if (token === null || token === undefined) + return null + + const key = await db.apiKey.findFirst({ + where: { + id: token as string + } + }) + + if (!key) return null + + return fetch(key.userId) +} + +const fetch = async (userId: string) => { + const user = await db.user.findFirst({ + where: { + id: userId + } + }) + + if (!user) return null + + return { + id: user.id, + username: user.name, + role: user.role + } +} \ No newline at end of file diff --git a/lib/validate-api.ts b/lib/validate-api.ts deleted file mode 100644 index bdc9f4a..0000000 --- a/lib/validate-api.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { auth } from "@/auth"; -import { db } from "./db"; - -export default async function fetchUserUsingAPI(req: Request) { - const session = await auth() - - if (session) { - const user = await db.user.findFirst({ - where: { - name: session.user?.name - } - }) - - return { - id: user?.id, - username: user?.name - } - } - - const token = req.headers?.get('x-api-key') - if (token === null || token === undefined) - return null - - const key = await db.apiKey.findFirst({ - where: { - id: token as string - } - }) - - const user = await db.user.findFirst({ - where: { - id: key?.userId - } - }) - - return { - id: user?.id, - username: user?.name - } -} \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d622a25..d25c8c1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -23,6 +23,9 @@ model User { ttsDefaultVoice Int @default(1) ttsEnabledVoice Int @default(1048575) + impersonationSources Impersonation[] @relation(name: "impersonationSources") + impersonationTargets Impersonation[] @relation(name: "impersonationTargets") + apiKeys ApiKey[] accounts Account[] twitchConnections TwitchConnection[] @@ -50,6 +53,19 @@ model Account { user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) + @@index([userId]) +} + +model Impersonation { + sourceId String + targetId String + + source User @relation(name: "impersonationSources", fields: [sourceId], references: [id], onDelete: Cascade) + target User @relation(name: "impersonationTargets", fields: [targetId], references: [id], onDelete: Cascade) + + @@id([sourceId]) + @@index([sourceId]) + @@index([targetId]) } model ApiKey {