PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
yatra / resources / js / hooks / usePermissions.ts

usePermissions.ts in Yatra – Travel Booking & Tour Operator Software 3.0.15, at resources/js/hooks/usePermissions.ts

145 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Permission and role checking hook
3 * Supports both free and Pro version role systems
4 */
5
6 import { useCallback, useMemo } from "react";
7
8 // Types are now in i18n.ts
9
10 interface UsePermissionsReturn {
11 can: (capability: string) => boolean;
12 hasRole: (role: string) => boolean;
13 isPro: boolean;
14 permissions: string[];
15 roles: string[];
16 }
17
18 /**
19 * Hook to check user permissions and roles
20 * @returns Permission checking functions
21 */
22 export const usePermissions = (): UsePermissionsReturn => {
23 const permissions = useMemo(() => {
24 return window.yatraAdmin?.permissions || [];
25 }, []);
26
27 const roles = useMemo(() => {
28 return window.yatraAdmin?.roles || [];
29 }, []);
30
31 const capabilities = useMemo(() => {
32 return window.yatraAdmin?.capabilities || {};
33 }, []);
34
35 const isPro = useMemo(() => {
36 return window.yatraAdmin?.isPro || false;
37 }, []);
38
39 /**
40 * Check if the current user has a specific capability.
41 *
42 * Sources, in order:
43 * 1. `window.yatraAdmin.capabilities` — server-built map of every
44 * `yatra_*` cap the user passes via WP-native `current_user_can`.
45 * Built by AdminAssetsProvider from `$current_user->allcaps`,
46 * filtered to the `yatra_` prefix.
47 * 2. `window.yatraAdmin.userCaps` — Team module's enriched list,
48 * includes the same caps + anything added via the user_has_cap
49 * filter (admin fallback, per-user grants, derived caps).
50 * 3. `window.yatraAdmin.isWpAdmin` — last-resort fallback for site
51 * owners so they're never locked out of anything.
52 *
53 * Default-deny when none match. The previous implementation had a
54 * hardcoded "every user gets yatra_view_trips / yatra_edit_trips /
55 * yatra_view_bookings" map that broke the Team & Access module — an
56 * Accountant calling `can('yatra_edit_trips')` returned true via that
57 * defaults map, leaking Tools / Modules / etc. into their UI even
58 * though their role doesn't grant edit_trips.
59 *
60 * @param capability - Capability to check
61 * @returns True if user has capability
62 */
63 const can = useCallback(
64 (capability: string): boolean => {
65 // 1) Server-built per-user cap map (yatra_* only).
66 if (capabilities[capability] === true) {
67 return true;
68 }
69
70 // 2) Team module's enriched userCaps list.
71 const userCaps = (
72 window.yatraAdmin as { userCaps?: string[] } | undefined
73 )?.userCaps;
74 if (Array.isArray(userCaps) && userCaps.includes(capability)) {
75 return true;
76 }
77
78 // 3) Legacy permissions array (kept for back-compat with any
79 // code path that pre-dates the capabilities map).
80 if (permissions.includes(capability)) {
81 return true;
82 }
83
84 // 4) WP admin fallback — site owners pass everything.
85 //
86 // Belt-and-suspenders: we check THREE signals in case one of
87 // them goes missing on a particular install. All three are
88 // injected by AdminAssetsProvider, but defense in depth is
89 // cheap and protects against:
90 // - server-side filters stripping isWpAdmin from localized data
91 // - JSON-encoding edge cases where booleans get coerced
92 // - roles arrays that contain admin even when capabilities map
93 // was built from a stale $current_user (page-cache + role
94 // changes)
95 const adm = window.yatraAdmin as
96 | {
97 isWpAdmin?: unknown;
98 roles?: unknown;
99 capabilities?: Record<string, unknown>;
100 }
101 | undefined;
102 if (adm) {
103 if (
104 adm.isWpAdmin === true ||
105 adm.isWpAdmin === "1" ||
106 adm.isWpAdmin === 1
107 ) {
108 return true;
109 }
110 if (Array.isArray(adm.roles) && adm.roles.includes("administrator")) {
111 return true;
112 }
113 if (adm.capabilities && adm.capabilities["manage_options"] === true) {
114 return true;
115 }
116 }
117
118 // 5) Pro-only check stays for completeness.
119 if (capability.startsWith("yatra_pro_") && !isPro) {
120 return false;
121 }
122
123 return false;
124 },
125 [capabilities, permissions, isPro],
126 );
127
128 /**
129 * Check if user has a specific role
130 * @param role - Role to check
131 * @returns True if user has role
132 */
133 const hasRole = (role: string): boolean => {
134 return roles.includes(role);
135 };
136
137 return {
138 can,
139 hasRole,
140 isPro,
141 permissions,
142 roles,
143 };
144 };
145