@zauru-sdk/utils 6.22.0 → 6.23.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.
@@ -1,6 +1,6 @@
1
1
  import { redirect } from "@remix-run/node";
2
2
  import { config } from "@zauru-sdk/config";
3
- import { commitSession, destroySession, getRefreshSession, getSession, loginWebApp, } from "@zauru-sdk/services";
3
+ import { commitSession, destroySession, getHeaders, getRefreshSession, getSession, loginWebApp, } from "@zauru-sdk/services";
4
4
  const loginErrorPayload = (description, title) => ({
5
5
  error: true,
6
6
  type: "error",
@@ -9,6 +9,23 @@ const loginErrorPayload = (description, title) => ({
9
9
  description,
10
10
  });
11
11
  const isDenied = (result) => result === false;
12
+ const isResponse = (value) => typeof Response !== "undefined" && value instanceof Response;
13
+ const deniedLoginPayload = () => loginErrorPayload("No tienes permiso para acceder a esta aplicación. Si crees que esto es un error, contacta al administrador.", "Acceso denegado");
14
+ const evaluateLoginAccess = async (extras, session, headers) => {
15
+ try {
16
+ if (isDenied(await extras?.requireAccess?.(session, headers))) {
17
+ return Response.json(deniedLoginPayload());
18
+ }
19
+ return null;
20
+ }
21
+ catch (error) {
22
+ if (isResponse(error)) {
23
+ throw error;
24
+ }
25
+ const description = error instanceof Error ? error.message : String(error);
26
+ return Response.json(loginErrorPayload(description));
27
+ }
28
+ };
12
29
  const authorizeUrl = (request) => {
13
30
  const url = new URL(request.url);
14
31
  const hostname = `${url.port ? "http://" : "https://"}${url.hostname}${url.port ? `:${url.port}` : ""}`;
@@ -41,7 +58,16 @@ export function createLoginAction(extras) {
41
58
  return redirect(authorizeUrl(request));
42
59
  }
43
60
  if (session.has("code")) {
44
- if (isDenied(await extras?.requireAccess?.(session))) {
61
+ const existingHeaders = await getHeaders(null, session);
62
+ try {
63
+ if (isDenied(await extras?.requireAccess?.(session, existingHeaders))) {
64
+ return redirect("/");
65
+ }
66
+ }
67
+ catch (error) {
68
+ if (isResponse(error)) {
69
+ throw error;
70
+ }
45
71
  return redirect("/");
46
72
  }
47
73
  return redirect("/home");
@@ -50,8 +76,9 @@ export function createLoginAction(extras) {
50
76
  if (loginResponse.error || !loginResponse.data) {
51
77
  return Response.json(loginErrorPayload(loginResponse.userMsg?.toString() ?? ""));
52
78
  }
53
- if (isDenied(await extras?.requireAccess?.(session))) {
54
- return Response.json(loginErrorPayload("No tienes permiso para acceder a esta aplicación. Si crees que esto es un error, contacta al administrador.", "Acceso denegado"));
79
+ const denied = await evaluateLoginAccess(extras, session, loginResponse.data.headers);
80
+ if (denied) {
81
+ return denied;
55
82
  }
56
83
  if (extras?.afterLogin) {
57
84
  await extras.afterLogin({
@@ -78,7 +105,8 @@ export function createSessionGuardLoader(extras) {
78
105
  if (!session.has("username")) {
79
106
  return redirect("/");
80
107
  }
81
- if (isDenied(await extras?.requireAccess?.(session))) {
108
+ const headers = await getHeaders(null, session);
109
+ if (isDenied(await extras?.requireAccess?.(session, headers))) {
82
110
  return redirect("/");
83
111
  }
84
112
  return Response.json({});
@@ -104,7 +132,8 @@ export function createIndexLoader(extras) {
104
132
  return async ({ request }) => {
105
133
  const session = await getSession(request.headers.get("Cookie"));
106
134
  if (session.has("username")) {
107
- if (isDenied(await extras?.requireAccess?.(session))) {
135
+ const headers = await getHeaders(null, session);
136
+ if (isDenied(await extras?.requireAccess?.(session, headers))) {
108
137
  return Response.json({});
109
138
  }
110
139
  return redirect("/home");
@@ -121,7 +150,8 @@ export function createReloadCatalogsLoader(extras) {
121
150
  if (!session.has("username")) {
122
151
  return redirect("/");
123
152
  }
124
- if (isDenied(await extras?.requireAccess?.(session))) {
153
+ const headers = await getHeaders(null, session);
154
+ if (isDenied(await extras?.requireAccess?.(session, headers))) {
125
155
  return redirect("/");
126
156
  }
127
157
  try {
@@ -1,6 +1,6 @@
1
1
  import { redirect } from "@remix-run/node";
2
2
  import { handlePossibleAxiosErrors } from "@zauru-sdk/common";
3
- import { createWebAppTableRegister, getVariablesByName, getWebAppRow, getWebAppTableRegisters, updateWebAppTableRegister, } from "@zauru-sdk/services";
3
+ import { createWebAppTableRegister, getHeaders, getVariablesByName, getWebAppRow, getWebAppTableRegisters, updateWebAppTableRegister, } from "@zauru-sdk/services";
4
4
  import { hasPermission as hasPermissionInContext, isActiveWebappRow, isSuperAdminEmail, } from "./access.js";
5
5
  import { DEFAULT_SUPER_ADMIN_EMAIL_SUFFIXES, isValidPermissionKey, normalizePermissionKeys, } from "./catalog.js";
6
6
  const deletedAt = () => new Date().toISOString();
@@ -11,11 +11,14 @@ const toNumber = (value) => {
11
11
  export function createWebappRbac(config) {
12
12
  const suffixes = config.superAdminEmailSuffixes ?? DEFAULT_SUPER_ADMIN_EMAIL_SUFFIXES;
13
13
  const validKeys = new Set(config.allPermissionKeys);
14
+ const resolveHeaders = async (headers, session) => {
15
+ if (headers?.["X-User-Token"] || headers?.["x-user-token"]) {
16
+ return headers;
17
+ }
18
+ return getHeaders(null, session);
19
+ };
14
20
  const getTableIds = async (headers, session) => {
15
- const vars = await getVariablesByName(headers, session, [
16
- config.rolesTableVar,
17
- config.employeeRolesTableVar,
18
- ]);
21
+ const vars = await getVariablesByName(await resolveHeaders(headers, session), session, [config.rolesTableVar, config.employeeRolesTableVar]);
19
22
  return {
20
23
  rolesTableId: vars[config.rolesTableVar],
21
24
  employeeRolesTableId: vars[config.employeeRolesTableVar],
@@ -210,6 +213,7 @@ export function createWebappRbac(config) {
210
213
  const context = await resolveAccess(headers, session);
211
214
  return context != null;
212
215
  };
216
+ const hasAppAccessFromSession = (session) => hasAppAccess(undefined, session);
213
217
  const requireAppAccess = async (headers, session) => {
214
218
  if (!session.has("username")) {
215
219
  throw redirect("/");
@@ -220,6 +224,7 @@ export function createWebappRbac(config) {
220
224
  }
221
225
  return context;
222
226
  };
227
+ const requireAppAccessFromSession = (session) => requireAppAccess(undefined, session);
223
228
  const requirePermission = async (headers, session, key) => {
224
229
  const context = await requireAppAccess(headers, session);
225
230
  if (!hasPermissionInContext(context, key)) {
@@ -240,7 +245,9 @@ export function createWebappRbac(config) {
240
245
  assignEmployeeRole,
241
246
  resolveAccess,
242
247
  hasAppAccess,
248
+ hasAppAccessFromSession,
243
249
  requireAppAccess,
250
+ requireAppAccessFromSession,
244
251
  requirePermission,
245
252
  hasPermission: hasPermissionInContext,
246
253
  isSuperAdminEmail: (email) => isSuperAdminEmail(email, suffixes),
@@ -6,8 +6,12 @@ export type AuthAccessExtras = {
6
6
  /**
7
7
  * Return `false` to deny. Throw `redirect(...)` to send the user elsewhere.
8
8
  * Any other return (including `void`) allows access.
9
+ *
10
+ * `headers` is present after a successful `loginWebApp`; otherwise it is
11
+ * built from the session (`X-User-Email` / `X-User-Token`). Prefer
12
+ * `rbac.hasAppAccessFromSession` so callers do not pass `{}`.
9
13
  */
10
- requireAccess?: (session: AuthSession) => boolean | void | Promise<boolean | void>;
14
+ requireAccess?: (session: AuthSession, headers?: Record<string, string>) => boolean | void | Promise<boolean | void>;
11
15
  };
12
16
  export type LoginActionExtras = AuthAccessExtras & {
13
17
  afterLogin?: (ctx: {
@@ -29,7 +29,9 @@ export declare function createWebappRbac(config: WebappRbacConfig): {
29
29
  assignEmployeeRole: (headers: any, session: Session, body: AssignEmployeeRoleInput) => Promise<AxiosUtilsResponse<WebAppTableUpdateResponse>>;
30
30
  resolveAccess: (headers: any, session: Session) => Promise<WebappAccessContext | null>;
31
31
  hasAppAccess: (headers: any, session: Session) => Promise<boolean>;
32
+ hasAppAccessFromSession: (session: Session) => Promise<boolean>;
32
33
  requireAppAccess: (headers: any, session: Session) => Promise<WebappAccessContext>;
34
+ requireAppAccessFromSession: (session: Session) => Promise<WebappAccessContext>;
33
35
  requirePermission: (headers: any, session: Session, key: string) => Promise<WebappAccessContext>;
34
36
  hasPermission: typeof hasPermissionInContext;
35
37
  isSuperAdminEmail: (email: string | null | undefined) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/utils",
3
- "version": "6.22.0",
3
+ "version": "6.23.0",
4
4
  "description": "Utilidades, parseo de request y demás para desarrollo de webapps de Zauru",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -71,12 +71,12 @@
71
71
  "dependencies": {
72
72
  "@aws-sdk/client-cloudwatch-logs": "^3.1123.0",
73
73
  "@remix-run/node": "^2.8.1",
74
- "@zauru-sdk/common": "^6.8.5",
74
+ "@zauru-sdk/common": "^6.8.6",
75
75
  "@zauru-sdk/config": "^6.0.0",
76
76
  "@zauru-sdk/graphql": "^6.8.0",
77
- "@zauru-sdk/services": "^6.11.8",
78
- "@zauru-sdk/types": "^6.23.0",
77
+ "@zauru-sdk/services": "^6.11.9",
78
+ "@zauru-sdk/types": "^6.24.0",
79
79
  "moment": "^2.30.1"
80
80
  },
81
- "gitHead": "a3c1f2af46acb59cf9fcb78ecb18d904e33c61e5"
81
+ "gitHead": "7020f7ea3b89b2c07998a5f7eb8586452c0cdc28"
82
82
  }