-
-
Notifications
You must be signed in to change notification settings - Fork 243
refactor: move oidc handling to backend and add support for oidc post #923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 23 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
ed94490
refactor: use new cache store in auth service
steveiliop56 3e5757c
fix: fix race conditions
steveiliop56 ac9689d
tests: add cache store tests
steveiliop56 fe84638
fix: fix bugs in cache order
steveiliop56 82d21c3
Merge branch 'refactor/service-cache' into refactor/oidc-codes
steveiliop56 695feca
refactor: rework oidc session storage
steveiliop56 faa3156
Merge branch 'main' into refactor/oidc-store
steveiliop56 83ed9ec
feat: add db cleanup routine back
steveiliop56 4fe5de2
chore: fix memory store
steveiliop56 a723004
tests: fix oidc service tests
steveiliop56 1c4ca8f
chore: differentiate oauth userinfo from oidc userinfo
steveiliop56 b5770ef
fix: add memory back in the db bootstrap
steveiliop56 5caee88
fix: ensure no oidc code reuse
steveiliop56 b3c152f
chore: rabbit comments
steveiliop56 97e0e0d
wip: backend
steveiliop56 2454ba5
refactor: use ticket approach for oidc flow
steveiliop56 da90792
Merge branch 'main' into refactor/oidc-authorize
steveiliop56 f078e35
fix: fix oauth oidc flow
steveiliop56 47b7f1e
feat: add back support for request oidc param
steveiliop56 5e954da
chore: go mod tidy
steveiliop56 ace64fa
tests: rework oidc tests and aim for better coverage
steveiliop56 a69d22b
feat: add new quick actions menu instead of individual dropdowns in f…
steveiliop56 4e671ed
tests: fix proxy controller tests
steveiliop56 ede6e80
fix: support for oidc post (forgot that)
steveiliop56 3c9817c
tests: fix oidc controller tests
steveiliop56 6a4d85d
chore: rabbit comments
steveiliop56 5c5d7a4
chore: own review comments
steveiliop56 b75fe9a
fix: fix bugs in jwt parsing and redirect uri handling
steveiliop56 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
205 changes: 205 additions & 0 deletions
205
frontend/src/components/quick-actions/quick-actions.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| import { languages, SupportedLanguage } from "@/lib/i18n/locales"; | ||
| import { | ||
| DropdownMenu, | ||
| DropdownMenuContent, | ||
| DropdownMenuItem, | ||
| DropdownMenuLabel, | ||
| DropdownMenuPortal, | ||
| DropdownMenuSeparator, | ||
| DropdownMenuSub, | ||
| DropdownMenuSubContent, | ||
| DropdownMenuSubTrigger, | ||
| DropdownMenuTrigger, | ||
| } from "../ui/dropdown-menu"; | ||
| import { useState } from "react"; | ||
| import i18n from "@/lib/i18n/i18n"; | ||
| import { useUserContext } from "@/context/user-context"; | ||
| import { ScrollArea } from "../ui/scroll-area"; | ||
| import { useTheme } from "../providers/theme-provider"; | ||
| import { | ||
| Check, | ||
| DoorOpenIcon, | ||
| Languages, | ||
| Monitor, | ||
| Moon, | ||
| Palette, | ||
| Settings, | ||
| Sun, | ||
| } from "lucide-react"; | ||
| import { useTranslation } from "react-i18next"; | ||
| import { useLocation } from "react-router"; | ||
| import { useRef } from "react"; | ||
| import { | ||
| useScreenParams, | ||
| recompileScreenParams, | ||
| } from "@/lib/hooks/screen-params"; | ||
| import { useMutation } from "@tanstack/react-query"; | ||
| import axios from "axios"; | ||
| import { toast } from "sonner"; | ||
| import { useEffect } from "react"; | ||
|
|
||
| function Avatar({ initial }: { initial: string }) { | ||
| return ( | ||
| <span className="group relative grid size-10 place-items-center rounded-full"> | ||
| <span className="absolute inset-0 overflow-hidden rounded-full bg-linear-to-b from-neutral-50 to-neutral-100 dark:from-neutral-700 dark:to-neutral-950 shadow-lg"></span> | ||
| <span className="relative text-sm font-semibold text-primary"> | ||
| {initial} | ||
| </span> | ||
| </span> | ||
| ); | ||
| } | ||
|
|
||
| export const QuickActions = () => { | ||
| const { auth } = useUserContext(); | ||
| const { theme, setTheme } = useTheme(); | ||
| const { t } = useTranslation(); | ||
| const { search } = useLocation(); | ||
|
|
||
| const [language, setLanguage] = useState<SupportedLanguage>( | ||
| i18n.language as SupportedLanguage, | ||
| ); | ||
|
|
||
| const redirectTimer = useRef<number | null>(null); | ||
| const searchParams = new URLSearchParams(search); | ||
| const screenParams = useScreenParams(searchParams); | ||
| const compiledParams = recompileScreenParams(screenParams); | ||
|
|
||
| const logoutMutation = useMutation({ | ||
| mutationFn: () => axios.post("/api/user/logout"), | ||
| mutationKey: ["logout"], | ||
| onSuccess: () => { | ||
| toast.success(t("logoutSuccessTitle"), { | ||
| description: t("logoutSuccessSubtitle"), | ||
| }); | ||
|
|
||
| redirectTimer.current = window.setTimeout(() => { | ||
| window.location.replace(`/login${compiledParams}`); | ||
| }, 500); | ||
| }, | ||
| onError: () => { | ||
| toast.error(t("logoutFailTitle"), { | ||
| description: t("logoutFailSubtitle"), | ||
| }); | ||
| }, | ||
| }); | ||
|
|
||
| useEffect(() => { | ||
| return () => { | ||
| if (redirectTimer.current) { | ||
| clearTimeout(redirectTimer.current); | ||
| } | ||
| }; | ||
| }, [redirectTimer]); | ||
|
|
||
| const initial = auth.authenticated | ||
| ? (auth.name[0] || "U").toUpperCase() | ||
| : null; | ||
|
|
||
| const handleSelect = (option: string) => { | ||
| setLanguage(option as SupportedLanguage); | ||
| i18n.changeLanguage(option as SupportedLanguage); | ||
| }; | ||
|
|
||
| const themes = [ | ||
| { key: "light", label: t("quickActionsThemeLight"), icon: Sun }, | ||
| { key: "dark", label: t("quickActionsThemeDark"), icon: Moon }, | ||
| { key: "system", label: t("quickActionsThemeSystem"), icon: Monitor }, | ||
| ] as const; | ||
|
|
||
| return ( | ||
| <DropdownMenu> | ||
| <DropdownMenuTrigger asChild> | ||
| <button className="rounded-full transition-transform duration-200 will-change-transform hover:scale-105 hover:cursor-pointer focus:ring-0 focus:outline-3 focus:outline-ring/50"> | ||
| {auth.authenticated ? ( | ||
| <Avatar initial={initial!} /> | ||
| ) : ( | ||
| <span className="bg-card text-primary border-border size-10 flex items-center justify-center rounded-full border shadow-lg"> | ||
| <Settings className="size-4" /> | ||
| </span> | ||
| )} | ||
| </button> | ||
| </DropdownMenuTrigger> | ||
|
|
||
| <DropdownMenuContent | ||
| align="end" | ||
| sideOffset={8} | ||
| className="rounded-xl p-1" | ||
| > | ||
| {auth.authenticated && ( | ||
| <> | ||
| <DropdownMenuLabel className="flex items-center gap-3 p-2"> | ||
| <div className="bg-foreground text-background flex size-9 shrink-0 items-center justify-center rounded-full text-sm font-medium"> | ||
| {initial} | ||
| </div> | ||
| <div className="flex min-w-0 flex-col"> | ||
| <span className="truncate text-sm font-medium"> | ||
| {auth.name} | ||
| </span> | ||
| <span className="text-muted-foreground truncate text-xs font-normal"> | ||
| {auth.email} | ||
| </span> | ||
| </div> | ||
| </DropdownMenuLabel> | ||
|
|
||
| <DropdownMenuSeparator /> | ||
| </> | ||
| )} | ||
|
|
||
| <DropdownMenuSub> | ||
| <DropdownMenuSubTrigger> | ||
| <Languages className="size-4" /> | ||
| {t("quickActionsLanguage")} | ||
| </DropdownMenuSubTrigger> | ||
| <DropdownMenuPortal> | ||
| <DropdownMenuSubContent sideOffset={8} className="rounded-xl p-1"> | ||
| <ScrollArea className="h-80"> | ||
| {Object.entries(languages).map(([key, value]) => ( | ||
| <DropdownMenuItem | ||
| key={key} | ||
| onSelect={() => handleSelect(key)} | ||
| > | ||
| {value} | ||
| {language === key && <Check className="size-4" />} | ||
| </DropdownMenuItem> | ||
| ))} | ||
| </ScrollArea> | ||
| </DropdownMenuSubContent> | ||
| </DropdownMenuPortal> | ||
| </DropdownMenuSub> | ||
|
|
||
| <DropdownMenuSub> | ||
| <DropdownMenuSubTrigger> | ||
| <Palette className="size-4" /> | ||
| {t("quickActionsTheme")} | ||
| </DropdownMenuSubTrigger> | ||
| <DropdownMenuPortal> | ||
| <DropdownMenuSubContent className="rounded-xl p-1" sideOffset={8}> | ||
| {themes.map(({ key, label, icon: Icon }) => ( | ||
| <DropdownMenuItem key={key} onClick={() => setTheme(key)}> | ||
| <span className="flex items-center gap-2"> | ||
| <Icon className="size-4" /> | ||
| {label} | ||
| </span> | ||
| {theme === key && <Check className="size-4" />} | ||
| </DropdownMenuItem> | ||
| ))} | ||
| </DropdownMenuSubContent> | ||
| </DropdownMenuPortal> | ||
| </DropdownMenuSub> | ||
|
|
||
| {auth.authenticated && ( | ||
| <> | ||
| <DropdownMenuSeparator /> | ||
| <DropdownMenuItem | ||
| onSelect={() => logoutMutation.mutate()} | ||
| className="text-destructive" | ||
| > | ||
| <DoorOpenIcon className="size-4" /> | ||
| {t("quickActionsLogout")} | ||
| </DropdownMenuItem> | ||
| </> | ||
| )} | ||
| </DropdownMenuContent> | ||
| </DropdownMenu> | ||
| ); | ||
| }; | ||
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import * as React from "react" | ||
| import { ScrollArea as ScrollAreaPrimitive } from "radix-ui" | ||
|
|
||
| import { cn } from "@/lib/utils" | ||
|
|
||
| function ScrollArea({ | ||
| className, | ||
| children, | ||
| ...props | ||
| }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) { | ||
| return ( | ||
| <ScrollAreaPrimitive.Root | ||
| data-slot="scroll-area" | ||
| className={cn("relative", className)} | ||
| {...props} | ||
| > | ||
| <ScrollAreaPrimitive.Viewport | ||
| data-slot="scroll-area-viewport" | ||
| className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1" | ||
| > | ||
| {children} | ||
| </ScrollAreaPrimitive.Viewport> | ||
| <ScrollBar /> | ||
| <ScrollAreaPrimitive.Corner /> | ||
| </ScrollAreaPrimitive.Root> | ||
| ) | ||
| } | ||
|
|
||
| function ScrollBar({ | ||
| className, | ||
| orientation = "vertical", | ||
| ...props | ||
| }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) { | ||
| return ( | ||
| <ScrollAreaPrimitive.ScrollAreaScrollbar | ||
| data-slot="scroll-area-scrollbar" | ||
| orientation={orientation} | ||
| className={cn( | ||
| "flex touch-none p-px transition-colors select-none", | ||
| orientation === "vertical" && | ||
| "h-full w-2.5 border-l border-l-transparent", | ||
| orientation === "horizontal" && | ||
| "h-2.5 flex-col border-t border-t-transparent", | ||
| className | ||
| )} | ||
| {...props} | ||
| > | ||
| <ScrollAreaPrimitive.ScrollAreaThumb | ||
| data-slot="scroll-area-thumb" | ||
| className="relative flex-1 rounded-full bg-border" | ||
| /> | ||
| </ScrollAreaPrimitive.ScrollAreaScrollbar> | ||
| ) | ||
| } | ||
|
|
||
| export { ScrollArea, ScrollBar } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| type UseLoginForProps = { | ||
| login_for?: "oidc" | "app"; | ||
| compiledParams: string; | ||
| }; | ||
|
|
||
| export const useLoginFor = (props: UseLoginForProps): string => { | ||
| const { login_for, compiledParams } = props; | ||
|
|
||
| switch (login_for) { | ||
| case "oidc": | ||
| return "/oidc/authorize" + compiledParams; | ||
| case "app": | ||
| return "/continue" + compiledParams; | ||
| default: | ||
| return "/logout"; | ||
| } | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.