Skip to content

Commit

Permalink
access to setting only for admin
Browse files Browse the repository at this point in the history
  • Loading branch information
Anchel123 committed Jun 27, 2024
1 parent 9905286 commit d0fb869
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 77 deletions.
45 changes: 27 additions & 18 deletions app/api/auth/[...nextauth]/options.ts
Original file line number Diff line number Diff line change
@@ -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<number, FalkorDB>();

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",
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion app/api/user/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { User } from "./model"
const ROLE = new Map<string, string[]>(
[
["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"]]
]
)
Expand Down
74 changes: 19 additions & 55 deletions app/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { useSession, signIn, signOut } from "next-auth/react"
import {
DropdownMenu,
Expand All @@ -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 (
<button
type="button"
Expand All @@ -45,38 +25,22 @@ export default function AvatarButton() {
)
}

const name = session?.user?.name || "Anchel";
const email = session?.user?.email;
const image = session?.user?.image ?? ""
const initials = name ? getInitials(name) : ""
setUserStatus(session.user.role)

const { name } = session.user;

return (
<div>
<DropdownMenu>
<DropdownMenuTrigger>
<HoverCard>
<HoverCardTrigger>
<div className="flex items-center gap-3">
<div className="text-black">{name || "Name Not Found"}</div>
<Avatar className="h-8 w-8">
<AvatarImage alt="@shadcn" src={image} />
<AvatarFallback className="bg-black text-white rounded-full">{initials}</AvatarFallback>
</Avatar>
</div>
</HoverCardTrigger>
<HoverCardContent>
<div className="flex flex-col text-left">
<div>Name: {name || "Name Not Found"}</div>
<div>Email: {email || "Email Not Found"}</div>
</div>
</HoverCardContent>
</HoverCard>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => signOut({ callbackUrl: '/' })}>Logout</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<DropdownMenu>
<DropdownMenuTrigger>
<div className="flex items-center gap-3">
<div className="text-black">{name || "default"}</div>
</div>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => signOut({ callbackUrl: '/' })}>Logout</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
5 changes: 4 additions & 1 deletion app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useState } from "react";
import Image from "next/image";
import { cn, prepareArg, securedFetch } from "@/lib/utils";
import { useRouter, usePathname } from "next/navigation";
import { Role } from "next-auth";
import Button from "./Button";
import Avatar from "./Avatar";

Expand All @@ -21,6 +22,7 @@ export default function Header({ graphName, inCreate = false, inSettings = false
const [open, setOpen] = useState<boolean>(false)
const router = useRouter()
const pathname = usePathname()
const [userStatus, setUserStatus] = useState<Role>()

// const [newName, setNewName] = useState<string>("")

Expand Down Expand Up @@ -168,6 +170,7 @@ export default function Header({ graphName, inCreate = false, inSettings = false
}
<div>
<button
disabled={userStatus !== "Admin"}
className={cn("flex flex-row gap-2", !graphName && "text-[#57577B]")}
title="Settings"
type="button"
Expand All @@ -178,7 +181,7 @@ export default function Header({ graphName, inCreate = false, inSettings = false
<Settings size={25} />
</button>
</div>
<Avatar />
<Avatar setUserStatus={setUserStatus}/>
</div>
</div>
</div>
Expand Down
3 changes: 1 addition & 2 deletions app/login/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
3 changes: 3 additions & 0 deletions types/next-auth.d.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down

0 comments on commit d0fb869

Please sign in to comment.