hazo_auth 3.0.4 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -0
- package/SETUP_CHECKLIST.md +369 -0
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +2 -2
- package/dist/components/layouts/rbac_test/index.d.ts +15 -0
- package/dist/components/layouts/rbac_test/index.d.ts.map +1 -0
- package/dist/components/layouts/rbac_test/index.js +378 -0
- package/dist/components/layouts/shared/components/password_field.js +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/components/layouts/shared/components/two_column_auth_layout.js +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts +2 -3
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.js +133 -8
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +12 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.js +291 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts +13 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.js +158 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts +11 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.js +267 -0
- package/dist/components/layouts/user_management/index.d.ts +9 -2
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +22 -6
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +59 -0
- package/dist/components/ui/tree-view.d.ts +108 -0
- package/dist/components/ui/tree-view.d.ts.map +1 -0
- package/dist/components/ui/tree-view.js +194 -0
- package/dist/lib/auth/auth_types.d.ts +45 -0
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.js +13 -0
- package/dist/lib/auth/hazo_get_auth.server.d.ts +4 -2
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +107 -3
- package/dist/lib/auth/scope_cache.d.ts +92 -0
- package/dist/lib/auth/scope_cache.d.ts.map +1 -0
- package/dist/lib/auth/scope_cache.js +171 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts +39 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -0
- package/dist/lib/scope_hierarchy_config.server.js +96 -0
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +7 -2
- package/dist/lib/services/profile_picture_service.d.ts +1 -7
- package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
- package/dist/lib/services/profile_picture_service.js +77 -32
- package/dist/lib/services/registration_service.js +1 -1
- package/dist/lib/services/scope_labels_service.d.ts +48 -0
- package/dist/lib/services/scope_labels_service.d.ts.map +1 -0
- package/dist/lib/services/scope_labels_service.js +277 -0
- package/dist/lib/services/scope_service.d.ts +114 -0
- package/dist/lib/services/scope_service.d.ts.map +1 -0
- package/dist/lib/services/scope_service.js +582 -0
- package/dist/lib/services/user_scope_service.d.ts +74 -0
- package/dist/lib/services/user_scope_service.d.ts.map +1 -0
- package/dist/lib/services/user_scope_service.js +415 -0
- package/hazo_auth_config.example.ini +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
+
import * as React from "react";
|
|
15
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
16
|
+
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
17
|
+
import { cn } from "../../lib/utils";
|
|
18
|
+
const Select = SelectPrimitive.Root;
|
|
19
|
+
const SelectGroup = SelectPrimitive.Group;
|
|
20
|
+
const SelectValue = SelectPrimitive.Value;
|
|
21
|
+
const SelectTrigger = React.forwardRef((_a, ref) => {
|
|
22
|
+
var { className, children } = _a, props = __rest(_a, ["className", "children"]);
|
|
23
|
+
return (_jsxs(SelectPrimitive.Trigger, Object.assign({ ref: ref, className: cn("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className) }, props, { children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })] })));
|
|
24
|
+
});
|
|
25
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
26
|
+
const SelectScrollUpButton = React.forwardRef((_a, ref) => {
|
|
27
|
+
var { className } = _a, props = __rest(_a, ["className"]);
|
|
28
|
+
return (_jsx(SelectPrimitive.ScrollUpButton, Object.assign({ ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
|
|
29
|
+
});
|
|
30
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
31
|
+
const SelectScrollDownButton = React.forwardRef((_a, ref) => {
|
|
32
|
+
var { className } = _a, props = __rest(_a, ["className"]);
|
|
33
|
+
return (_jsx(SelectPrimitive.ScrollDownButton, Object.assign({ ref: ref, className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(ChevronDown, { className: "h-4 w-4" }) })));
|
|
34
|
+
});
|
|
35
|
+
SelectScrollDownButton.displayName =
|
|
36
|
+
SelectPrimitive.ScrollDownButton.displayName;
|
|
37
|
+
const SelectContent = React.forwardRef((_a, ref) => {
|
|
38
|
+
var { className, children, position = "popper" } = _a, props = __rest(_a, ["className", "children", "position"]);
|
|
39
|
+
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, Object.assign({ ref: ref, className: cn("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", position === "popper" &&
|
|
40
|
+
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className), position: position }, props, { children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn("p-1", position === "popper" &&
|
|
41
|
+
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"), children: children }), _jsx(SelectScrollDownButton, {})] })) }));
|
|
42
|
+
});
|
|
43
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
44
|
+
const SelectLabel = React.forwardRef((_a, ref) => {
|
|
45
|
+
var { className } = _a, props = __rest(_a, ["className"]);
|
|
46
|
+
return (_jsx(SelectPrimitive.Label, Object.assign({ ref: ref, className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className) }, props)));
|
|
47
|
+
});
|
|
48
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
49
|
+
const SelectItem = React.forwardRef((_a, ref) => {
|
|
50
|
+
var { className, children } = _a, props = __rest(_a, ["className", "children"]);
|
|
51
|
+
return (_jsxs(SelectPrimitive.Item, Object.assign({ ref: ref, className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className) }, props, { children: [_jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] })));
|
|
52
|
+
});
|
|
53
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
54
|
+
const SelectSeparator = React.forwardRef((_a, ref) => {
|
|
55
|
+
var { className } = _a, props = __rest(_a, ["className"]);
|
|
56
|
+
return (_jsx(SelectPrimitive.Separator, Object.assign({ ref: ref, className: cn("-mx-1 my-1 h-px bg-muted", className) }, props)));
|
|
57
|
+
});
|
|
58
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
59
|
+
export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
3
|
+
interface TreeDataItem {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
icon?: React.ComponentType<{
|
|
7
|
+
className?: string;
|
|
8
|
+
}>;
|
|
9
|
+
selectedIcon?: React.ComponentType<{
|
|
10
|
+
className?: string;
|
|
11
|
+
}>;
|
|
12
|
+
openIcon?: React.ComponentType<{
|
|
13
|
+
className?: string;
|
|
14
|
+
}>;
|
|
15
|
+
children?: TreeDataItem[];
|
|
16
|
+
actions?: React.ReactNode;
|
|
17
|
+
onClick?: () => void;
|
|
18
|
+
draggable?: boolean;
|
|
19
|
+
droppable?: boolean;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
type TreeRenderItemParams = {
|
|
24
|
+
item: TreeDataItem;
|
|
25
|
+
level: number;
|
|
26
|
+
isLeaf: boolean;
|
|
27
|
+
isSelected: boolean;
|
|
28
|
+
isOpen?: boolean;
|
|
29
|
+
hasChildren: boolean;
|
|
30
|
+
};
|
|
31
|
+
declare const TreeView: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
32
|
+
data: TreeDataItem[] | TreeDataItem;
|
|
33
|
+
initialSelectedItemId?: string;
|
|
34
|
+
onSelectChange?: (item: TreeDataItem | undefined) => void;
|
|
35
|
+
expandAll?: boolean;
|
|
36
|
+
defaultNodeIcon?: React.ComponentType<{
|
|
37
|
+
className?: string;
|
|
38
|
+
}>;
|
|
39
|
+
defaultLeafIcon?: React.ComponentType<{
|
|
40
|
+
className?: string;
|
|
41
|
+
}>;
|
|
42
|
+
onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void;
|
|
43
|
+
renderItem?: (params: TreeRenderItemParams) => React.ReactNode;
|
|
44
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
45
|
+
declare const TreeItem: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
46
|
+
data: TreeDataItem[] | TreeDataItem;
|
|
47
|
+
initialSelectedItemId?: string;
|
|
48
|
+
onSelectChange?: (item: TreeDataItem | undefined) => void;
|
|
49
|
+
expandAll?: boolean;
|
|
50
|
+
defaultNodeIcon?: React.ComponentType<{
|
|
51
|
+
className?: string;
|
|
52
|
+
}>;
|
|
53
|
+
defaultLeafIcon?: React.ComponentType<{
|
|
54
|
+
className?: string;
|
|
55
|
+
}>;
|
|
56
|
+
onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void;
|
|
57
|
+
renderItem?: (params: TreeRenderItemParams) => React.ReactNode;
|
|
58
|
+
} & {
|
|
59
|
+
selectedItemId?: string;
|
|
60
|
+
handleSelectChange: (item: TreeDataItem | undefined) => void;
|
|
61
|
+
expandedItemIds: string[];
|
|
62
|
+
defaultNodeIcon?: React.ComponentType<{
|
|
63
|
+
className?: string;
|
|
64
|
+
}>;
|
|
65
|
+
defaultLeafIcon?: React.ComponentType<{
|
|
66
|
+
className?: string;
|
|
67
|
+
}>;
|
|
68
|
+
handleDragStart?: (item: TreeDataItem) => void;
|
|
69
|
+
handleDrop?: (item: TreeDataItem) => void;
|
|
70
|
+
draggedItem: TreeDataItem | null;
|
|
71
|
+
level?: number;
|
|
72
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
73
|
+
declare const TreeNode: ({ item, handleSelectChange, expandedItemIds, selectedItemId, defaultNodeIcon, defaultLeafIcon, handleDragStart, handleDrop, draggedItem, renderItem, level, }: {
|
|
74
|
+
item: TreeDataItem;
|
|
75
|
+
handleSelectChange: (item: TreeDataItem | undefined) => void;
|
|
76
|
+
expandedItemIds: string[];
|
|
77
|
+
selectedItemId?: string;
|
|
78
|
+
defaultNodeIcon?: React.ComponentType<{
|
|
79
|
+
className?: string;
|
|
80
|
+
}>;
|
|
81
|
+
defaultLeafIcon?: React.ComponentType<{
|
|
82
|
+
className?: string;
|
|
83
|
+
}>;
|
|
84
|
+
handleDragStart?: (item: TreeDataItem) => void;
|
|
85
|
+
handleDrop?: (item: TreeDataItem) => void;
|
|
86
|
+
draggedItem: TreeDataItem | null;
|
|
87
|
+
renderItem?: (params: TreeRenderItemParams) => React.ReactNode;
|
|
88
|
+
level?: number;
|
|
89
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
90
|
+
declare const TreeLeaf: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
91
|
+
item: TreeDataItem;
|
|
92
|
+
level: number;
|
|
93
|
+
selectedItemId?: string;
|
|
94
|
+
handleSelectChange: (item: TreeDataItem | undefined) => void;
|
|
95
|
+
defaultLeafIcon?: React.ComponentType<{
|
|
96
|
+
className?: string;
|
|
97
|
+
}>;
|
|
98
|
+
handleDragStart?: (item: TreeDataItem) => void;
|
|
99
|
+
handleDrop?: (item: TreeDataItem) => void;
|
|
100
|
+
draggedItem: TreeDataItem | null;
|
|
101
|
+
renderItem?: (params: TreeRenderItemParams) => React.ReactNode;
|
|
102
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
103
|
+
declare const AccordionTrigger: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
104
|
+
children?: React.ReactNode;
|
|
105
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
106
|
+
declare const AccordionContent: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
107
|
+
export { TreeView, type TreeDataItem, type TreeRenderItemParams, AccordionTrigger, AccordionContent, TreeLeaf, TreeNode, TreeItem };
|
|
108
|
+
//# sourceMappingURL=tree-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-view.d.ts","sourceRoot":"","sources":["../../../src/components/ui/tree-view.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
|
+
import React from 'react';
|
|
15
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
16
|
+
import { ChevronRight } from 'lucide-react';
|
|
17
|
+
import { cva } from 'class-variance-authority';
|
|
18
|
+
import { cn } from '../../lib/utils';
|
|
19
|
+
const treeVariants = cva('group hover:before:opacity-100 before:absolute before:rounded-lg before:left-0 px-2 before:w-full before:opacity-0 before:bg-accent/70 before:h-[2rem] before:-z-10');
|
|
20
|
+
const selectedTreeVariants = cva('before:opacity-100 before:bg-accent/70 text-accent-foreground');
|
|
21
|
+
const dragOverVariants = cva('before:opacity-100 before:bg-primary/20 text-primary-foreground');
|
|
22
|
+
const TreeView = React.forwardRef((_a, ref) => {
|
|
23
|
+
var { data, initialSelectedItemId, onSelectChange, expandAll, defaultLeafIcon, defaultNodeIcon, className, onDocumentDrag, renderItem } = _a, props = __rest(_a, ["data", "initialSelectedItemId", "onSelectChange", "expandAll", "defaultLeafIcon", "defaultNodeIcon", "className", "onDocumentDrag", "renderItem"]);
|
|
24
|
+
const [selectedItemId, setSelectedItemId] = React.useState(initialSelectedItemId);
|
|
25
|
+
const [draggedItem, setDraggedItem] = React.useState(null);
|
|
26
|
+
const handleSelectChange = React.useCallback((item) => {
|
|
27
|
+
setSelectedItemId(item === null || item === void 0 ? void 0 : item.id);
|
|
28
|
+
if (onSelectChange) {
|
|
29
|
+
onSelectChange(item);
|
|
30
|
+
}
|
|
31
|
+
}, [onSelectChange]);
|
|
32
|
+
const handleDragStart = React.useCallback((item) => {
|
|
33
|
+
setDraggedItem(item);
|
|
34
|
+
}, []);
|
|
35
|
+
const handleDrop = React.useCallback((targetItem) => {
|
|
36
|
+
if (draggedItem && onDocumentDrag && draggedItem.id !== targetItem.id) {
|
|
37
|
+
onDocumentDrag(draggedItem, targetItem);
|
|
38
|
+
}
|
|
39
|
+
setDraggedItem(null);
|
|
40
|
+
}, [draggedItem, onDocumentDrag]);
|
|
41
|
+
const expandedItemIds = React.useMemo(() => {
|
|
42
|
+
if (!initialSelectedItemId) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const ids = [];
|
|
46
|
+
function walkTreeItems(items, targetId) {
|
|
47
|
+
if (Array.isArray(items)) {
|
|
48
|
+
for (let i = 0; i < items.length; i++) {
|
|
49
|
+
ids.push(items[i].id);
|
|
50
|
+
if (walkTreeItems(items[i], targetId) && !expandAll) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (!expandAll)
|
|
54
|
+
ids.pop();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (!expandAll && items.id === targetId) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
else if (items.children) {
|
|
61
|
+
return walkTreeItems(items.children, targetId);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
walkTreeItems(data, initialSelectedItemId);
|
|
65
|
+
return ids;
|
|
66
|
+
}, [data, expandAll, initialSelectedItemId]);
|
|
67
|
+
return (_jsxs("div", { className: cn('overflow-hidden relative p-2', className), children: [_jsx(TreeItem, Object.assign({ data: data, ref: ref, selectedItemId: selectedItemId, handleSelectChange: handleSelectChange, expandedItemIds: expandedItemIds, defaultLeafIcon: defaultLeafIcon, defaultNodeIcon: defaultNodeIcon, handleDragStart: handleDragStart, handleDrop: handleDrop, draggedItem: draggedItem, renderItem: renderItem, level: 0 }, props)), _jsx("div", { className: 'w-full h-[48px]', onDrop: () => { handleDrop({ id: '', name: 'parent_div' }); } })] }));
|
|
68
|
+
});
|
|
69
|
+
TreeView.displayName = 'TreeView';
|
|
70
|
+
const TreeItem = React.forwardRef((_a, ref) => {
|
|
71
|
+
var { className, data, selectedItemId, handleSelectChange, expandedItemIds, defaultNodeIcon, defaultLeafIcon, handleDragStart, handleDrop, draggedItem, renderItem, level, onSelectChange, expandAll, initialSelectedItemId, onDocumentDrag } = _a, props = __rest(_a, ["className", "data", "selectedItemId", "handleSelectChange", "expandedItemIds", "defaultNodeIcon", "defaultLeafIcon", "handleDragStart", "handleDrop", "draggedItem", "renderItem", "level", "onSelectChange", "expandAll", "initialSelectedItemId", "onDocumentDrag"]);
|
|
72
|
+
if (!(Array.isArray(data))) {
|
|
73
|
+
data = [data];
|
|
74
|
+
}
|
|
75
|
+
return (_jsx("div", Object.assign({ ref: ref, role: "tree", className: className }, props, { children: _jsx("ul", { children: data.map((item) => (_jsx("li", { children: item.children ? (_jsx(TreeNode, { item: item, level: level !== null && level !== void 0 ? level : 0, selectedItemId: selectedItemId, expandedItemIds: expandedItemIds, handleSelectChange: handleSelectChange, defaultNodeIcon: defaultNodeIcon, defaultLeafIcon: defaultLeafIcon, handleDragStart: handleDragStart, handleDrop: handleDrop, draggedItem: draggedItem, renderItem: renderItem })) : (_jsx(TreeLeaf, { item: item, level: level !== null && level !== void 0 ? level : 0, selectedItemId: selectedItemId, handleSelectChange: handleSelectChange, defaultLeafIcon: defaultLeafIcon, handleDragStart: handleDragStart, handleDrop: handleDrop, draggedItem: draggedItem, renderItem: renderItem })) }, item.id))) }) })));
|
|
76
|
+
});
|
|
77
|
+
TreeItem.displayName = 'TreeItem';
|
|
78
|
+
const TreeNode = ({ item, handleSelectChange, expandedItemIds, selectedItemId, defaultNodeIcon, defaultLeafIcon, handleDragStart, handleDrop, draggedItem, renderItem, level = 0, }) => {
|
|
79
|
+
var _a;
|
|
80
|
+
const [value, setValue] = React.useState(expandedItemIds.includes(item.id) ? [item.id] : []);
|
|
81
|
+
const [isDragOver, setIsDragOver] = React.useState(false);
|
|
82
|
+
const hasChildren = !!((_a = item.children) === null || _a === void 0 ? void 0 : _a.length);
|
|
83
|
+
const isSelected = selectedItemId === item.id;
|
|
84
|
+
const isOpen = value.includes(item.id);
|
|
85
|
+
const onDragStart = (e) => {
|
|
86
|
+
if (!item.draggable) {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
e.dataTransfer.setData('text/plain', item.id);
|
|
91
|
+
handleDragStart === null || handleDragStart === void 0 ? void 0 : handleDragStart(item);
|
|
92
|
+
};
|
|
93
|
+
const onDragOver = (e) => {
|
|
94
|
+
if (item.droppable !== false && draggedItem && draggedItem.id !== item.id) {
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
setIsDragOver(true);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const onDragLeave = () => {
|
|
100
|
+
setIsDragOver(false);
|
|
101
|
+
};
|
|
102
|
+
const onDrop = (e) => {
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
setIsDragOver(false);
|
|
105
|
+
handleDrop === null || handleDrop === void 0 ? void 0 : handleDrop(item);
|
|
106
|
+
};
|
|
107
|
+
return (_jsx(AccordionPrimitive.Root, { type: "multiple", value: value, onValueChange: (s) => setValue(s), children: _jsxs(AccordionPrimitive.Item, { value: item.id, children: [_jsx(AccordionTrigger, { className: cn(treeVariants(), isSelected && selectedTreeVariants(), isDragOver && dragOverVariants(), item.className), onClick: () => {
|
|
108
|
+
var _a;
|
|
109
|
+
handleSelectChange(item);
|
|
110
|
+
(_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
111
|
+
}, draggable: !!item.draggable, onDragStart: onDragStart, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop, children: renderItem ? (renderItem({
|
|
112
|
+
item,
|
|
113
|
+
level,
|
|
114
|
+
isLeaf: false,
|
|
115
|
+
isSelected,
|
|
116
|
+
isOpen,
|
|
117
|
+
hasChildren,
|
|
118
|
+
})) : (_jsxs(_Fragment, { children: [_jsx(TreeIcon, { item: item, isSelected: isSelected, isOpen: isOpen, default: defaultNodeIcon }), _jsx("span", { className: "text-sm truncate", children: item.name }), _jsx(TreeActions, { isSelected: isSelected, children: item.actions })] })) }), _jsx(AccordionContent, { className: "ml-4 pl-1 border-l", children: _jsx(TreeItem, { data: item.children ? item.children : item, selectedItemId: selectedItemId, handleSelectChange: handleSelectChange, expandedItemIds: expandedItemIds, defaultLeafIcon: defaultLeafIcon, defaultNodeIcon: defaultNodeIcon, handleDragStart: handleDragStart, handleDrop: handleDrop, draggedItem: draggedItem, renderItem: renderItem, level: level + 1 }) })] }) }));
|
|
119
|
+
};
|
|
120
|
+
const TreeLeaf = React.forwardRef((_a, ref) => {
|
|
121
|
+
var { className, item, level, selectedItemId, handleSelectChange, defaultLeafIcon, handleDragStart, handleDrop, draggedItem, renderItem } = _a, props = __rest(_a, ["className", "item", "level", "selectedItemId", "handleSelectChange", "defaultLeafIcon", "handleDragStart", "handleDrop", "draggedItem", "renderItem"]);
|
|
122
|
+
const [isDragOver, setIsDragOver] = React.useState(false);
|
|
123
|
+
const isSelected = selectedItemId === item.id;
|
|
124
|
+
const onDragStart = (e) => {
|
|
125
|
+
if (!item.draggable || item.disabled) {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
e.dataTransfer.setData('text/plain', item.id);
|
|
130
|
+
handleDragStart === null || handleDragStart === void 0 ? void 0 : handleDragStart(item);
|
|
131
|
+
};
|
|
132
|
+
const onDragOver = (e) => {
|
|
133
|
+
if (item.droppable !== false && !item.disabled && draggedItem && draggedItem.id !== item.id) {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
setIsDragOver(true);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const onDragLeave = () => {
|
|
139
|
+
setIsDragOver(false);
|
|
140
|
+
};
|
|
141
|
+
const onDrop = (e) => {
|
|
142
|
+
if (item.disabled)
|
|
143
|
+
return;
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
setIsDragOver(false);
|
|
146
|
+
handleDrop === null || handleDrop === void 0 ? void 0 : handleDrop(item);
|
|
147
|
+
};
|
|
148
|
+
return (_jsx("div", Object.assign({ ref: ref, className: cn('ml-5 flex text-left items-center py-2 cursor-pointer before:right-1', treeVariants(), className, isSelected && selectedTreeVariants(), isDragOver && dragOverVariants(), item.disabled && 'opacity-50 cursor-not-allowed pointer-events-none', item.className), onClick: () => {
|
|
149
|
+
var _a;
|
|
150
|
+
if (item.disabled)
|
|
151
|
+
return;
|
|
152
|
+
handleSelectChange(item);
|
|
153
|
+
(_a = item.onClick) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
154
|
+
}, draggable: !!item.draggable && !item.disabled, onDragStart: onDragStart, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop }, props, { children: renderItem ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-4 w-4 shrink-0 mr-1" }), renderItem({
|
|
155
|
+
item,
|
|
156
|
+
level,
|
|
157
|
+
isLeaf: true,
|
|
158
|
+
isSelected,
|
|
159
|
+
hasChildren: false,
|
|
160
|
+
})] })) : (_jsxs(_Fragment, { children: [_jsx(TreeIcon, { item: item, isSelected: isSelected, default: defaultLeafIcon }), _jsx("span", { className: "flex-grow text-sm truncate", children: item.name }), _jsx(TreeActions, { isSelected: isSelected && !item.disabled, children: item.actions })] })) })));
|
|
161
|
+
});
|
|
162
|
+
TreeLeaf.displayName = 'TreeLeaf';
|
|
163
|
+
const AccordionTrigger = React.forwardRef((_a, ref) => {
|
|
164
|
+
var { className, children, onClick } = _a, props = __rest(_a, ["className", "children", "onClick"]);
|
|
165
|
+
return (_jsx(AccordionPrimitive.Header, { className: "flex", children: _jsx(AccordionPrimitive.Trigger, { asChild: true, children: _jsxs("div", Object.assign({ ref: ref, role: "button", tabIndex: 0, className: cn('flex flex-1 w-full items-center py-2 transition-all cursor-pointer first:[&[data-state=open]>svg]:first-of-type:rotate-90', className), onClick: onClick, onKeyDown: (e) => {
|
|
166
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(e);
|
|
169
|
+
}
|
|
170
|
+
} }, props, { children: [_jsx(ChevronRight, { className: "h-4 w-4 shrink-0 transition-transform duration-200 text-accent-foreground/50 mr-1" }), children] })) }) }));
|
|
171
|
+
});
|
|
172
|
+
AccordionTrigger.displayName = 'AccordionTrigger';
|
|
173
|
+
const AccordionContent = React.forwardRef((_a, ref) => {
|
|
174
|
+
var { className, children } = _a, props = __rest(_a, ["className", "children"]);
|
|
175
|
+
return (_jsx(AccordionPrimitive.Content, Object.assign({ ref: ref, className: cn('overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down', className) }, props, { children: _jsx("div", { className: "pb-1 pt-0", children: children }) })));
|
|
176
|
+
});
|
|
177
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
|
178
|
+
const TreeIcon = ({ item, isOpen, isSelected, default: defaultIcon }) => {
|
|
179
|
+
let Icon = defaultIcon;
|
|
180
|
+
if (isSelected && item.selectedIcon) {
|
|
181
|
+
Icon = item.selectedIcon;
|
|
182
|
+
}
|
|
183
|
+
else if (isOpen && item.openIcon) {
|
|
184
|
+
Icon = item.openIcon;
|
|
185
|
+
}
|
|
186
|
+
else if (item.icon) {
|
|
187
|
+
Icon = item.icon;
|
|
188
|
+
}
|
|
189
|
+
return Icon ? (_jsx(Icon, { className: "h-4 w-4 shrink-0 mr-2" })) : (_jsx(_Fragment, {}));
|
|
190
|
+
};
|
|
191
|
+
const TreeActions = ({ children, isSelected }) => {
|
|
192
|
+
return (_jsx("div", { className: cn(isSelected ? 'block' : 'hidden', 'absolute right-3 group-hover:block'), children: children }));
|
|
193
|
+
};
|
|
194
|
+
export { TreeView, AccordionTrigger, AccordionContent, TreeLeaf, TreeNode, TreeItem };
|
|
@@ -8,9 +8,18 @@ export type HazoAuthUser = {
|
|
|
8
8
|
is_active: boolean;
|
|
9
9
|
profile_picture_url: string | null;
|
|
10
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Scope access information returned when HRBAC scope checking is used
|
|
13
|
+
*/
|
|
14
|
+
export type ScopeAccessInfo = {
|
|
15
|
+
scope_type: string;
|
|
16
|
+
scope_id: string;
|
|
17
|
+
scope_seq: string;
|
|
18
|
+
};
|
|
11
19
|
/**
|
|
12
20
|
* Result type for hazo_get_auth function
|
|
13
21
|
* Returns authenticated state with user data and permissions, or unauthenticated state
|
|
22
|
+
* Optionally includes scope access information when HRBAC is used
|
|
14
23
|
*/
|
|
15
24
|
export type HazoAuthResult = {
|
|
16
25
|
authenticated: true;
|
|
@@ -18,11 +27,14 @@ export type HazoAuthResult = {
|
|
|
18
27
|
permissions: string[];
|
|
19
28
|
permission_ok: boolean;
|
|
20
29
|
missing_permissions?: string[];
|
|
30
|
+
scope_ok?: boolean;
|
|
31
|
+
scope_access_via?: ScopeAccessInfo;
|
|
21
32
|
} | {
|
|
22
33
|
authenticated: false;
|
|
23
34
|
user: null;
|
|
24
35
|
permissions: [];
|
|
25
36
|
permission_ok: false;
|
|
37
|
+
scope_ok?: false;
|
|
26
38
|
};
|
|
27
39
|
/**
|
|
28
40
|
* Options for hazo_get_auth function
|
|
@@ -38,6 +50,21 @@ export type HazoAuthOptions = {
|
|
|
38
50
|
* If false (default), returns permission_ok: false without throwing
|
|
39
51
|
*/
|
|
40
52
|
strict?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The scope level to check access for (e.g., "hazo_scopes_l3")
|
|
55
|
+
* If provided along with scope_id or scope_seq, enables HRBAC checking
|
|
56
|
+
*/
|
|
57
|
+
scope_type?: string;
|
|
58
|
+
/**
|
|
59
|
+
* The scope ID (UUID) to check access for
|
|
60
|
+
* Takes precedence over scope_seq if both provided
|
|
61
|
+
*/
|
|
62
|
+
scope_id?: string;
|
|
63
|
+
/**
|
|
64
|
+
* The scope seq (friendly ID like "L3_001") to check access for
|
|
65
|
+
* Used if scope_id is not provided
|
|
66
|
+
*/
|
|
67
|
+
scope_seq?: string;
|
|
41
68
|
};
|
|
42
69
|
/**
|
|
43
70
|
* Custom error class for permission denials
|
|
@@ -50,4 +77,22 @@ export declare class PermissionError extends Error {
|
|
|
50
77
|
user_friendly_message?: string | undefined;
|
|
51
78
|
constructor(missing_permissions: string[], user_permissions: string[], required_permissions: string[], user_friendly_message?: string | undefined);
|
|
52
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Custom error class for scope access denials in HRBAC
|
|
82
|
+
* Thrown when strict mode is enabled and user lacks access to required scope
|
|
83
|
+
*/
|
|
84
|
+
export declare class ScopeAccessError extends Error {
|
|
85
|
+
scope_type: string;
|
|
86
|
+
scope_identifier: string;
|
|
87
|
+
user_scopes: Array<{
|
|
88
|
+
scope_type: string;
|
|
89
|
+
scope_id: string;
|
|
90
|
+
scope_seq: string;
|
|
91
|
+
}>;
|
|
92
|
+
constructor(scope_type: string, scope_identifier: string, user_scopes: Array<{
|
|
93
|
+
scope_type: string;
|
|
94
|
+
scope_id: string;
|
|
95
|
+
scope_seq: string;
|
|
96
|
+
}>);
|
|
97
|
+
}
|
|
53
98
|
//# sourceMappingURL=auth_types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_types.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_types.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"auth_types.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_types.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB;IACE,aAAa,EAAE,IAAI,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC,GACD;IACE,aAAa,EAAE,KAAK,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,EAAE,CAAC;IAChB,aAAa,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IAE/B,mBAAmB,EAAE,MAAM,EAAE;IAC7B,gBAAgB,EAAE,MAAM,EAAE;IAC1B,oBAAoB,EAAE,MAAM,EAAE;IAC9B,qBAAqB,CAAC,EAAE,MAAM;gBAH9B,mBAAmB,EAAE,MAAM,EAAE,EAC7B,gBAAgB,EAAE,MAAM,EAAE,EAC1B,oBAAoB,EAAE,MAAM,EAAE,EAC9B,qBAAqB,CAAC,EAAE,MAAM,YAAA;CAKxC;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IAEhC,UAAU,EAAE,MAAM;IAClB,gBAAgB,EAAE,MAAM;IACxB,WAAW,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;gBAF/E,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAKzF"}
|
|
@@ -14,3 +14,16 @@ export class PermissionError extends Error {
|
|
|
14
14
|
this.name = "PermissionError";
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Custom error class for scope access denials in HRBAC
|
|
19
|
+
* Thrown when strict mode is enabled and user lacks access to required scope
|
|
20
|
+
*/
|
|
21
|
+
export class ScopeAccessError extends Error {
|
|
22
|
+
constructor(scope_type, scope_identifier, user_scopes) {
|
|
23
|
+
super(`Access denied to scope: ${scope_type} / ${scope_identifier}`);
|
|
24
|
+
this.scope_type = scope_type;
|
|
25
|
+
this.scope_identifier = scope_identifier;
|
|
26
|
+
this.user_scopes = user_scopes;
|
|
27
|
+
this.name = "ScopeAccessError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -3,10 +3,12 @@ import type { HazoAuthResult, HazoAuthOptions } from "./auth_types";
|
|
|
3
3
|
/**
|
|
4
4
|
* Main hazo_get_auth function for server-side use in API routes
|
|
5
5
|
* Returns user details, permissions, and checks required permissions
|
|
6
|
+
* Optionally checks HRBAC scope access when scope options are provided
|
|
6
7
|
* @param request - NextRequest object
|
|
7
|
-
* @param options - Optional parameters for permission checking
|
|
8
|
-
* @returns HazoAuthResult with user data and
|
|
8
|
+
* @param options - Optional parameters for permission checking and HRBAC scope checking
|
|
9
|
+
* @returns HazoAuthResult with user data, permissions, and optional scope access info
|
|
9
10
|
* @throws PermissionError if strict mode and permissions are missing
|
|
11
|
+
* @throws ScopeAccessError if strict mode and scope access is denied
|
|
10
12
|
*/
|
|
11
13
|
export declare function hazo_get_auth(request: NextRequest, options?: HazoAuthOptions): Promise<HazoAuthResult>;
|
|
12
14
|
//# sourceMappingURL=hazo_get_auth.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,cAAc,EAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,cAAc,EAAgB,eAAe,EAAmB,MAAM,cAAc,CAAC;AA0RnG;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAgNzB"}
|
|
@@ -2,11 +2,15 @@ import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
|
|
|
2
2
|
import { createCrudService } from "hazo_connect/server";
|
|
3
3
|
import { create_app_logger } from "../app_logger";
|
|
4
4
|
import { get_filename, get_line_number } from "../utils/api_route_helpers";
|
|
5
|
-
import { PermissionError } from "./auth_types";
|
|
5
|
+
import { PermissionError, ScopeAccessError } from "./auth_types";
|
|
6
6
|
import { get_auth_cache } from "./auth_cache";
|
|
7
|
+
import { get_scope_cache } from "./scope_cache";
|
|
7
8
|
import { get_rate_limiter } from "./auth_rate_limiter";
|
|
8
9
|
import { get_auth_utility_config } from "../auth_utility_config.server";
|
|
9
10
|
import { validate_session_token } from "../services/session_token_service";
|
|
11
|
+
import { is_hrbac_enabled, get_scope_hierarchy_config } from "../scope_hierarchy_config.server";
|
|
12
|
+
import { check_user_scope_access, get_user_scopes } from "../services/user_scope_service";
|
|
13
|
+
import { is_valid_scope_level } from "../services/scope_service";
|
|
10
14
|
// section: helpers
|
|
11
15
|
/**
|
|
12
16
|
* Gets client IP address from request
|
|
@@ -137,14 +141,84 @@ function get_friendly_error_message(missing_permissions, config) {
|
|
|
137
141
|
// Default message if no specific mapping
|
|
138
142
|
return "You don't have the required permissions to perform this action. Please contact your administrator.";
|
|
139
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Gets user scopes with caching
|
|
146
|
+
* @param user_id - User ID
|
|
147
|
+
* @returns Array of user scope entries
|
|
148
|
+
*/
|
|
149
|
+
async function get_user_scopes_cached(user_id) {
|
|
150
|
+
const scope_config = get_scope_hierarchy_config();
|
|
151
|
+
const scope_cache = get_scope_cache(scope_config.scope_cache_max_entries, scope_config.scope_cache_ttl_minutes);
|
|
152
|
+
// Check cache
|
|
153
|
+
const cached = scope_cache.get(user_id);
|
|
154
|
+
if (cached) {
|
|
155
|
+
return cached.scopes;
|
|
156
|
+
}
|
|
157
|
+
// Fetch from database
|
|
158
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
159
|
+
const result = await get_user_scopes(hazoConnect, user_id);
|
|
160
|
+
if (!result.success || !result.scopes) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
// Convert to cache entry format and cache
|
|
164
|
+
const scopes = result.scopes.map((s) => ({
|
|
165
|
+
scope_type: s.scope_type,
|
|
166
|
+
scope_id: s.scope_id,
|
|
167
|
+
scope_seq: s.scope_seq,
|
|
168
|
+
}));
|
|
169
|
+
scope_cache.set(user_id, scopes);
|
|
170
|
+
return scopes;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Checks if user has access to a specific scope
|
|
174
|
+
* @param user_id - User ID
|
|
175
|
+
* @param scope_type - Scope level
|
|
176
|
+
* @param scope_id - Scope ID (optional)
|
|
177
|
+
* @param scope_seq - Scope seq (optional)
|
|
178
|
+
* @returns Object with scope_ok and access_via info
|
|
179
|
+
*/
|
|
180
|
+
async function check_scope_access(user_id, scope_type, scope_id, scope_seq) {
|
|
181
|
+
const logger = create_app_logger();
|
|
182
|
+
// Validate scope_type
|
|
183
|
+
if (!is_valid_scope_level(scope_type)) {
|
|
184
|
+
logger.warn("auth_utility_invalid_scope_type", {
|
|
185
|
+
filename: get_filename(),
|
|
186
|
+
line_number: get_line_number(),
|
|
187
|
+
scope_type,
|
|
188
|
+
user_id,
|
|
189
|
+
});
|
|
190
|
+
return { scope_ok: false, user_scopes: [] };
|
|
191
|
+
}
|
|
192
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
193
|
+
const result = await check_user_scope_access(hazoConnect, user_id, scope_type, scope_id, scope_seq);
|
|
194
|
+
const user_scopes = (result.user_scopes || []).map((s) => ({
|
|
195
|
+
scope_type: s.scope_type,
|
|
196
|
+
scope_id: s.scope_id,
|
|
197
|
+
scope_seq: s.scope_seq,
|
|
198
|
+
}));
|
|
199
|
+
if (result.has_access && result.access_via) {
|
|
200
|
+
return {
|
|
201
|
+
scope_ok: true,
|
|
202
|
+
scope_access_via: {
|
|
203
|
+
scope_type: result.access_via.scope_type,
|
|
204
|
+
scope_id: result.access_via.scope_id,
|
|
205
|
+
scope_seq: result.access_via.scope_seq,
|
|
206
|
+
},
|
|
207
|
+
user_scopes,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return { scope_ok: false, user_scopes };
|
|
211
|
+
}
|
|
140
212
|
// section: main_function
|
|
141
213
|
/**
|
|
142
214
|
* Main hazo_get_auth function for server-side use in API routes
|
|
143
215
|
* Returns user details, permissions, and checks required permissions
|
|
216
|
+
* Optionally checks HRBAC scope access when scope options are provided
|
|
144
217
|
* @param request - NextRequest object
|
|
145
|
-
* @param options - Optional parameters for permission checking
|
|
146
|
-
* @returns HazoAuthResult with user data and
|
|
218
|
+
* @param options - Optional parameters for permission checking and HRBAC scope checking
|
|
219
|
+
* @returns HazoAuthResult with user data, permissions, and optional scope access info
|
|
147
220
|
* @throws PermissionError if strict mode and permissions are missing
|
|
221
|
+
* @throws ScopeAccessError if strict mode and scope access is denied
|
|
148
222
|
*/
|
|
149
223
|
export async function hazo_get_auth(request, options) {
|
|
150
224
|
var _a, _b, _c;
|
|
@@ -274,11 +348,41 @@ export async function hazo_get_auth(request, options) {
|
|
|
274
348
|
throw new PermissionError(missing_permissions, permissions, options.required_permissions, friendly_message);
|
|
275
349
|
}
|
|
276
350
|
}
|
|
351
|
+
// Check HRBAC scope access if enabled and scope options provided
|
|
352
|
+
let scope_ok;
|
|
353
|
+
let scope_access_via;
|
|
354
|
+
const hrbac_enabled = is_hrbac_enabled();
|
|
355
|
+
const has_scope_options = (options === null || options === void 0 ? void 0 : options.scope_type) && ((options === null || options === void 0 ? void 0 : options.scope_id) || (options === null || options === void 0 ? void 0 : options.scope_seq));
|
|
356
|
+
if (hrbac_enabled && has_scope_options) {
|
|
357
|
+
const scope_result = await check_scope_access(user.id, options.scope_type, options === null || options === void 0 ? void 0 : options.scope_id, options === null || options === void 0 ? void 0 : options.scope_seq);
|
|
358
|
+
scope_ok = scope_result.scope_ok;
|
|
359
|
+
scope_access_via = scope_result.scope_access_via;
|
|
360
|
+
// Log scope denial if permission logging is enabled
|
|
361
|
+
if (!scope_ok && config.log_permission_denials) {
|
|
362
|
+
const client_ip = get_client_ip(request);
|
|
363
|
+
logger.warn("auth_utility_scope_access_denied", {
|
|
364
|
+
filename: get_filename(),
|
|
365
|
+
line_number: get_line_number(),
|
|
366
|
+
user_id: user.id,
|
|
367
|
+
scope_type: options.scope_type,
|
|
368
|
+
scope_id: options === null || options === void 0 ? void 0 : options.scope_id,
|
|
369
|
+
scope_seq: options === null || options === void 0 ? void 0 : options.scope_seq,
|
|
370
|
+
user_scopes: scope_result.user_scopes,
|
|
371
|
+
ip: client_ip,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
// Throw error if strict mode and scope access denied
|
|
375
|
+
if (!scope_ok && (options === null || options === void 0 ? void 0 : options.strict)) {
|
|
376
|
+
throw new ScopeAccessError(options.scope_type, (options === null || options === void 0 ? void 0 : options.scope_id) || (options === null || options === void 0 ? void 0 : options.scope_seq) || "unknown", scope_result.user_scopes);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
277
379
|
return {
|
|
278
380
|
authenticated: true,
|
|
279
381
|
user,
|
|
280
382
|
permissions,
|
|
281
383
|
permission_ok,
|
|
282
384
|
missing_permissions,
|
|
385
|
+
scope_ok,
|
|
386
|
+
scope_access_via,
|
|
283
387
|
};
|
|
284
388
|
}
|