diff --git a/app/api/auth/[...nextauth]/options.ts b/app/api/auth/[...nextauth]/options.ts index 063b039..91490cf 100644 --- a/app/api/auth/[...nextauth]/options.ts +++ b/app/api/auth/[...nextauth]/options.ts @@ -1,11 +1,11 @@ import { FalkorDB } from "falkordb"; import CredentialsProvider from "next-auth/providers/credentials" -import { AuthOptions, getServerSession } from "next-auth" +import { AuthOptions, Role, getServerSession } from "next-auth" import { NextResponse } from "next/server"; const connections = new Map(); -async function newClient(credentials: { host: string, port: string, password: string, username: string, tls: string, ca: string }, id: number) { +async function newClient(credentials: { host: string, port: string, password: string, username: string, tls: string, ca: string }, id: number): Promise<{ role: Role, client: FalkorDB }> { const client = credentials.ca === "undefined" ? await FalkorDB.connect({ socket: { host: credentials.host ?? "localhost", @@ -17,14 +17,14 @@ async function newClient(credentials: { host: string, port: string, password: st password: credentials.password ?? undefined, username: credentials.username ?? undefined }) - : await FalkorDB.connect({ - socket: { - host: credentials.host ?? "localhost", - port: credentials.port ? parseInt(credentials.port, 10) : 6379, - }, - password: credentials.password ?? undefined, - username: credentials.username ?? undefined - }) + : await FalkorDB.connect({ + socket: { + host: credentials.host ?? "localhost", + port: credentials.port ? parseInt(credentials.port, 10) : 6379, + }, + password: credentials.password ?? undefined, + username: credentials.username ?? undefined + }) // Save connection in connections map for later use connections.set(id, client) @@ -42,9 +42,17 @@ async function newClient(credentials: { host: string, port: string, password: st } }); - // Verify connection - await client.connection.ping() - return client + // Verify connection and Role + const admin = await client.connection.aclGetUser(credentials.username || "default") + + if (admin) return { role: "Admin", client } + + try { + await client.connection.sendCommand(["GRAPH.QUERY"]) + return { role: "Read-Write", client } + } catch (error) { + return { role: "Read-Only", client } + } } let userId = 1; @@ -71,7 +79,7 @@ const authOptions: AuthOptions = { const id = userId; userId += 1; - await newClient(credentials, id) + const { role } = await newClient(credentials, id) const res = { id, @@ -80,7 +88,8 @@ const authOptions: AuthOptions = { password: credentials.password, username: credentials.username, tls: credentials.tls === "true", - ca: credentials.ca + ca: credentials.ca, + role } return res } catch (err) { @@ -140,20 +149,20 @@ export async function getClient() { // If client is not found, create a new one if (!client) { - client = await newClient({ + client = (await newClient({ host: user.host, port: user.port.toString() ?? "6379", username: user.username, password: user.password, tls: String(user.tls), ca: user.ca - }, user.id) + }, user.id)).client } if (!client) { return NextResponse.json({ message: "Not authenticated" }, { status: 401 }) } - + return client } diff --git a/app/api/user/route.ts b/app/api/user/route.ts index df62b09..151161f 100644 --- a/app/api/user/route.ts +++ b/app/api/user/route.ts @@ -5,7 +5,7 @@ import { User } from "./model" const ROLE = new Map( [ ["Admin", ["on", "~*", "&*", "+@all"]], - ["Read-Write", ["on", "~*", "resetchannels", "-@all", "+graph.query", "+graph.profile", "+graph.explain", "+graph.list", "+ping"]], + ["Read-Write", ["on", "~*", "resetchannels", "-@all", "+graph.query", "+graph.explain", "+graph.list", "+ping", "+graph.profile",]], ["Read-Only", ["on", "~*", "resetchannels", "-@all", "+graph.ro_query", "+graph.explain", "+graph.list", "+ping"]] ] ) diff --git a/app/components/Avatar.tsx b/app/components/Avatar.tsx index e23dec5..e55f586 100644 --- a/app/components/Avatar.tsx +++ b/app/components/Avatar.tsx @@ -1,6 +1,5 @@ 'use client'; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { useSession, signIn, signOut } from "next-auth/react" import { DropdownMenu, @@ -10,31 +9,12 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" -import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"; +import { Role } from "next-auth"; -// A function that takes a full name as a string and returns its initials as a string -function getInitials(fullName: string): string { - // Split the full name by spaces and store the parts in an array - const nameParts = fullName.split(" "); - // Initialize an empty string to store the initials - let initials = ""; - // Loop through the name parts array - nameParts.forEach((part) => { - - // If the part is not empty, append its first character (uppercased) to the initials string - if (part) { - initials += part[0].toUpperCase(); - } - }) - // Return the initials string - return initials; -} - - -export default function AvatarButton() { +export default function AvatarButton({ setUserStatus }: { setUserStatus: (status: Role) => void }) { const { data: session, status } = useSession() - if (status === "unauthenticated") { + if (status === "unauthenticated" || !session) { return ( - + diff --git a/app/login/LoginForm.tsx b/app/login/LoginForm.tsx index f6e95a6..f02bfb6 100644 --- a/app/login/LoginForm.tsx +++ b/app/login/LoginForm.tsx @@ -2,14 +2,13 @@ import { SignInOptions, SignInResponse, signIn } from "next-auth/react"; import { FormEvent, useEffect, useState } from "react"; -import { useSearchParams } from "next/navigation"; +import { useSearchParams, useRouter } from "next/navigation"; import Dropzone from "@/app/components/Dropzone"; import { Checkbox } from "@/components/ui/checkbox"; import { Eye } from "lucide-react"; import Input from "@/app/components/Input"; import Button from "@/app/components/Button"; import Image from "next/image"; -import { useRouter } from "next/navigation"; const DEFAULT_HOST = "localhost"; const DEFAULT_PORT = "6379"; diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index a9b0398..ed08179 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -1,9 +1,12 @@ import { DefaultUser } from "next-auth"; declare module "next-auth" { + + type Role = "Admin" | "Read-Write" | "Read-Only"; interface User extends DefaultUser { id: number; + role: Role; host: string; port: number; tls: boolean;