@albirex/platformatic-logto 1.3.4 → 1.3.6

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/lib/index.cjs CHANGED
@@ -33,7 +33,6 @@ __export(index_exports, {
33
33
  });
34
34
  module.exports = __toCommonJS(index_exports);
35
35
  var import_fastify_plugin = __toESM(require("fastify-plugin"), 1);
36
- var import_leven = __toESM(require("leven"), 1);
37
36
  var fastifyUser = __toESM(require("fastify-user"), 1);
38
37
 
39
38
  // src/utils/find-rule.ts
@@ -132,12 +131,22 @@ var auth = async (app, opts) => {
132
131
  const scopes = await scopesResp.json();
133
132
  for (const scope of scopes) {
134
133
  const roleName = role.name;
135
- const [scopeAction, entity] = scope.name.split(":");
134
+ let [scopeAction, entity] = scope.name.split(":");
136
135
  if (!app.platformatic.entities[entity]) {
137
- const nearest = findNearestEntity(entity);
138
- app.log.warn(`Unknown entity '${entity}' in authorization rule. Did you mean '${nearest.entity}'?`);
136
+ app.log.debug(`Unknown entity '${entity}' in authorization rule`);
139
137
  continue;
140
138
  }
139
+ switch (scopeAction) {
140
+ case "create":
141
+ scopeAction = "save";
142
+ break;
143
+ case "read":
144
+ scopeAction = "find";
145
+ break;
146
+ case "update":
147
+ scopeAction = "updateMany";
148
+ break;
149
+ }
141
150
  const checkExists = rules.find((r) => r.role === roleName && r.entity === entity);
142
151
  if (checkExists) {
143
152
  if (opts.checks) {
@@ -172,6 +181,21 @@ var auth = async (app, opts) => {
172
181
  }
173
182
  }
174
183
  }
184
+ const logRules = rules.reduce((prev, curr) => {
185
+ (prev[curr["role"]] ??= []).push(curr);
186
+ return prev;
187
+ }, {});
188
+ for (const key in logRules) {
189
+ app.log.info(`Rules set for role ${key}`);
190
+ for (const element of logRules[key]) {
191
+ const { entity, entities, role, ...other } = element;
192
+ app.log.info(` ${entity ?? entities.join(",")}: ${JSON.stringify(other)}`);
193
+ }
194
+ }
195
+ const missingEntities = Object.keys(app.platformatic.entities).filter((e) => !rules.map((r) => r.entity).includes(e));
196
+ if (missingEntities.length) {
197
+ app.log.warn(`Missing rules for entities: ${missingEntities.join(", ")}`);
198
+ }
175
199
  app.log.debug("LogTo calculated rules");
176
200
  app.log.debug(rules);
177
201
  return rules;
@@ -209,18 +233,6 @@ var auth = async (app, opts) => {
209
233
  };
210
234
  }
211
235
  }
212
- function findNearestEntity(ruleEntity) {
213
- const entities = Object.keys(app.platformatic.entities);
214
- const nearest = entities.reduce((acc, entity) => {
215
- const distance = (0, import_leven.default)(ruleEntity, entity);
216
- if (distance < acc.distance) {
217
- acc.distance = distance;
218
- acc.entity = entity;
219
- }
220
- return acc;
221
- }, { distance: Infinity, entity: null });
222
- return nearest;
223
- }
224
236
  app.addHook("onReady", async function() {
225
237
  const rules = await composeLogToRules();
226
238
  const entityRules = {};
@@ -237,8 +249,7 @@ var auth = async (app, opts) => {
237
249
  for (const ruleEntity of ruleEntities) {
238
250
  const newRule = { ...rule, entity: ruleEntity, entities: void 0 };
239
251
  if (!app.platformatic.entities[newRule.entity]) {
240
- const nearest = findNearestEntity(ruleEntity);
241
- throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}. Did you mean '${nearest.entity}'?`);
252
+ throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}`);
242
253
  }
243
254
  if (!entityRules[ruleEntity]) {
244
255
  entityRules[ruleEntity] = [];
@@ -247,6 +258,9 @@ var auth = async (app, opts) => {
247
258
  }
248
259
  }
249
260
  for (const entityKey of Object.keys(app.platformatic.entities)) {
261
+ let useOriginal = function(ctx) {
262
+ return !ctx;
263
+ };
250
264
  const rules2 = entityRules[entityKey] || [];
251
265
  const type = app.platformatic.entities[entityKey];
252
266
  let userPropToFillForPublish;
@@ -265,6 +279,9 @@ var auth = async (app, opts) => {
265
279
  checkSaveMandatoryFieldsInRules(type, rules2);
266
280
  app.platformatic.addEntityHooks(entityKey, {
267
281
  async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {
282
+ if (useOriginal(ctx)) {
283
+ return originalFind({ ...restOpts, where, ctx, fields });
284
+ }
268
285
  const request = getRequestFromContext(ctx);
269
286
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
270
287
  checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields));
@@ -272,6 +289,9 @@ var auth = async (app, opts) => {
272
289
  return originalFind({ ...restOpts, where, ctx, fields });
273
290
  },
274
291
  async save(originalSave, { input, ctx, fields, ...restOpts }) {
292
+ if (useOriginal(ctx)) {
293
+ return originalSave({ ctx, input, fields, ...restOpts });
294
+ }
275
295
  const request = getRequestFromContext(ctx);
276
296
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
277
297
  if (!rule.save) {
@@ -307,6 +327,9 @@ var auth = async (app, opts) => {
307
327
  return originalSave({ input, ctx, fields, ...restOpts });
308
328
  },
309
329
  async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {
330
+ if (useOriginal(ctx)) {
331
+ return originalInsert({ inputs, ctx, fields, ...restOpts });
332
+ }
310
333
  const request = getRequestFromContext(ctx);
311
334
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
312
335
  if (!rule.save) {
@@ -329,12 +352,18 @@ var auth = async (app, opts) => {
329
352
  return originalInsert({ inputs, ctx, fields, ...restOpts });
330
353
  },
331
354
  async delete(originalDelete, { where, ctx, fields, ...restOpts }) {
355
+ if (useOriginal(ctx)) {
356
+ return originalDelete({ where, ctx, fields, ...restOpts });
357
+ }
332
358
  const request = getRequestFromContext(ctx);
333
359
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
334
360
  where = await fromRuleToWhere(ctx, rule.delete, where, request.user);
335
361
  return originalDelete({ where, ctx, fields, ...restOpts });
336
362
  },
337
363
  async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {
364
+ if (useOriginal(ctx)) {
365
+ return originalUpdateMany({ ...restOpts, where, ctx, fields });
366
+ }
338
367
  const request = getRequestFromContext(ctx);
339
368
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
340
369
  where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user);
package/lib/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils/find-rule.ts","../src/utils/utils.ts","../src/utils/errors.ts"],"sourcesContent":["import fp from 'fastify-plugin'\nimport leven from 'leven'\nimport * as fastifyUser from 'fastify-user'\n\nimport findRule from './utils/find-rule.js'\nimport { getRequestFromContext, getRoles } from './utils/utils.js'\nimport { Unauthorized, UnauthorizedField, MissingNotNullableError } from './utils/errors.js'\nimport fastifyLogto from '@albirex/fastify-logto';\nimport { FastifyInstance, FastifyPluginAsync } from 'fastify'\nimport type { FastifyUserPluginOptions } from 'fastify-user';\nimport type { Entity, PlatformaticContext } from '@platformatic/sql-mapper'\n\nconst PLT_ADMIN_ROLE = 'platformatic-admin'\n\nexport type PlatformaticRule = {\n role: string;\n entity?: string;\n entities?: string[];\n defaults?: Record<string, string>;\n checks?: boolean;\n find?: boolean;\n save?: boolean;\n delete?: boolean;\n\n};\n\nexport type PlatformaticLogtoAuthOptions = {\n logtoBaseUrl?: string;\n logtoAppId?: string;\n logtoAppSecret?: string;\n adminSecret?: string;\n rolePath?: string;\n roleKey?: string;\n userPath?: string;\n userKey?: string;\n anonymousRole?: string;\n allowAnonymous?: boolean;\n checks?: boolean;\n defaults?: boolean;\n jwtPlugin: FastifyUserPluginOptions\n};\n\nconst auth: FastifyPluginAsync<PlatformaticLogtoAuthOptions> = async (app: FastifyInstance, opts: PlatformaticLogtoAuthOptions) => {\n app.register(fastifyLogto, {\n endpoint: opts.logtoBaseUrl || 'https://auth.example.com',\n appId: opts.logtoAppId || 'your-app-id',\n appSecret: opts.logtoAppSecret || 'your-app-secret',\n });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await app.register(fastifyUser as any, opts.jwtPlugin);\n\n const adminSecret = opts.adminSecret\n const roleKey = opts.rolePath || opts.roleKey || 'X-PLATFORMATIC-ROLE'\n const userKey = opts.userPath || opts.userKey || 'X-PLATFORMATIC-USER-ID'\n const isRolePath = !!opts.rolePath // if `true` the role is intepreted as path like `user.role`\n const anonymousRole = opts.anonymousRole || 'anonymous'\n\n async function composeLogToRules() {\n const rolesResp = await app.logto.callAPI('/api/roles?type=User', 'GET');\n\n if (!rolesResp.ok) {\n throw rolesResp;\n }\n\n const roles = await rolesResp.json();\n const rules: PlatformaticRule[] = [{\n role: anonymousRole,\n entities: Object.keys(app.platformatic.entities),\n find: opts.allowAnonymous,\n save: opts.allowAnonymous,\n delete: opts.allowAnonymous,\n }];\n\n for (const role of roles) {\n const scopesResp = await app.logto.callAPI(`/api/roles/${role.id}/scopes`, 'GET');\n\n if (!scopesResp.ok) {\n throw scopesResp;\n }\n\n const scopes = await scopesResp.json();\n\n for (const scope of scopes) {\n const roleName = role.name;\n const [scopeAction, entity] = scope.name.split(':');\n\n if (!app.platformatic.entities[entity]) {\n const nearest = findNearestEntity(entity)\n app.log.warn(`Unknown entity '${entity}' in authorization rule. Did you mean '${nearest.entity}'?`)\n continue;\n }\n\n const checkExists = rules.find(r => r.role === roleName && r.entity === entity);\n if (checkExists) {\n if (opts.checks) {\n checkExists[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n checkExists[scopeAction] = true;\n }\n } else {\n const newRule: PlatformaticRule = {\n role: roleName,\n entity,\n };\n\n if (opts.checks) {\n newRule[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n newRule[scopeAction] = true;\n }\n\n if (opts.defaults) {\n newRule.defaults = {\n userId: userKey\n };\n }\n\n rules.push(newRule);\n }\n }\n }\n\n app.log.debug('LogTo calculated rules');\n app.log.debug(rules);\n return rules;\n }\n\n app.decorateRequest('setupDBAuthorizationUser', setupUser)\n\n async function setupUser() {\n // if (!adminSecret) {\n await this.extractUser()\n // }\n\n let forceAdminRole = false\n if (adminSecret && this.headers['x-platformatic-admin-secret'] === adminSecret) {\n if (opts.jwtPlugin.jwt) {\n forceAdminRole = true\n } else {\n this.log.info('admin secret is valid')\n this.user = new Proxy(this.headers, {\n get: (target, key) => {\n let value;\n if (!target[key.toString()]) {\n const newKey = key.toString().toLowerCase()\n value = target[newKey]\n } else {\n value = target[key.toString()]\n }\n\n if (!value && key.toString().toLowerCase() === roleKey.toLowerCase()) {\n value = PLT_ADMIN_ROLE\n }\n return value\n },\n })\n }\n }\n\n if (forceAdminRole) {\n // We replace just the role in `request.user`, all the rest is untouched\n this.user = {\n // ...request.user,\n [roleKey]: PLT_ADMIN_ROLE,\n }\n }\n }\n\n function findNearestEntity(ruleEntity) {\n // There is an unknown entity. Let's find out the nearest one for a nice error message\n const entities = Object.keys(app.platformatic.entities)\n\n const nearest = entities.reduce((acc, entity) => {\n\n const distance = leven(ruleEntity, entity)\n if (distance < acc.distance) {\n acc.distance = distance\n acc.entity = entity\n }\n return acc\n }, { distance: Infinity, entity: null })\n return nearest\n }\n\n app.addHook('onReady', async function () {\n const rules = await composeLogToRules();\n\n // TODO validate that there is at most a rule for a given role\n const entityRules = {};\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n\n let ruleEntities = null\n if (rule.entity) {\n ruleEntities = [rule.entity]\n } else if (rule.entities) {\n ruleEntities = [...rule.entities]\n } else {\n throw new Error(`Missing entity in authorization rule ${i}`)\n }\n\n for (const ruleEntity of ruleEntities) {\n const newRule = { ...rule, entity: ruleEntity, entities: undefined }\n if (!app.platformatic.entities[newRule.entity]) {\n const nearest = findNearestEntity(ruleEntity)\n throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}. Did you mean '${nearest.entity}'?`)\n }\n\n if (!entityRules[ruleEntity]) {\n entityRules[ruleEntity] = []\n }\n entityRules[ruleEntity].push(newRule)\n }\n }\n\n for (const entityKey of Object.keys(app.platformatic.entities)) {\n const rules = entityRules[entityKey] || []\n const type = app.platformatic.entities[entityKey]\n\n // We have subscriptions!\n let userPropToFillForPublish\n const topicsWithoutChecks = false\n\n // mqtt\n // if (app.platformatic.mq) {\n // for (const rule of rules) {\n // const checks = rule.find?.checks\n // if (typeof checks !== 'object') {\n // topicsWithoutChecks = !!rule.find\n // continue\n // }\n // const keys = Object.keys(checks)\n // if (keys.length !== 1) {\n // throw new Error(`Subscription requires that the role \"${rule.role}\" has only one check in the find rule for entity \"${rule.entity}\"`)\n // }\n // const key = keys[0]\n\n // const val = typeof checks[key] === 'object' ? checks[key].eq : checks[key]\n // if (userPropToFillForPublish && userPropToFillForPublish.val !== val) {\n // throw new Error('Unable to configure subscriptions and authorization due to multiple check clauses in find')\n // }\n // userPropToFillForPublish = { key, val }\n // }\n // }\n\n if (userPropToFillForPublish && topicsWithoutChecks) {\n throw new Error(`Subscription for entity \"${entityKey}\" have conflictling rules across roles`)\n }\n\n // MUST set this after doing the security checks on the subscriptions\n if (adminSecret) {\n rules.push({\n role: PLT_ADMIN_ROLE,\n find: true,\n save: true,\n delete: true,\n })\n }\n\n // If we have `fields` in save rules, we need to check if all the not-nullable\n // fields are specified\n checkSaveMandatoryFieldsInRules(type, rules)\n\n // function useOriginal(skipAuth: boolean, ctx: PlatformaticContext) {\n // if (skipAuth === false && !ctx) {\n // throw new Error('Cannot set skipAuth to `false` without ctx')\n // }\n\n // return skipAuth || !ctx\n // }\n\n app.platformatic.addEntityHooks(entityKey, {\n async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalFind({ ...restOpts, where, ctx, fields })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields))\n where = await fromRuleToWhere(ctx, rule.find, where, request.user)\n\n return originalFind({ ...restOpts, where, ctx, fields })\n },\n async save(originalSave, { input, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalSave({ ctx, input, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, input)\n\n if (rule.defaults) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n\n const hasAllPrimaryKeys = input[type.primaryKey] !== undefined;\n const whereConditions = {}\n whereConditions[type.primaryKey] = { eq: input[type.primaryKey] }\n\n if (hasAllPrimaryKeys) {\n const where = await fromRuleToWhere(ctx, rule.save, whereConditions, request.user)\n\n const found = await type.find({\n where,\n ctx,\n fields,\n })\n\n if (found.length === 0) {\n throw new Unauthorized()\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n },\n\n async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalInsert({ inputs, ctx, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, inputs)\n\n /* istanbul ignore else */\n if (rule.defaults) {\n for (const input of inputs) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n }\n\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n },\n\n async delete(originalDelete, { where, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalDelete({ where, ctx, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.delete, where, request.user)\n\n return originalDelete({ where, ctx, fields, ...restOpts })\n },\n\n async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalUpdateMany({ ...restOpts, where, ctx, fields })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user)\n\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n },\n })\n }\n })\n}\n\nasync function fromRuleToWhere(ctx: PlatformaticContext, rule, where, user) {\n if (!rule) {\n throw new Unauthorized()\n }\n const request = getRequestFromContext(ctx)\n /* istanbul ignore next */\n where = where || {}\n\n if (typeof rule === 'object') {\n const { checks } = rule\n\n /* istanbul ignore else */\n if (checks) {\n for (const key of Object.keys(checks)) {\n const clauses = checks[key]\n if (typeof clauses === 'string') {\n // case: \"userId\": \"X-PLATFORMATIC-USER-ID\"\n where[key] = {\n eq: request.user[clauses],\n }\n } else {\n // case:\n // userId: {\n // eq: 'X-PLATFORMATIC-USER-ID'\n // }\n for (const clauseKey of Object.keys(clauses)) {\n const clause = clauses[clauseKey]\n where[key] = {\n [clauseKey]: request.user[clause],\n }\n }\n }\n }\n }\n } else if (typeof rule === 'function') {\n where = await rule({ user, ctx, where })\n }\n return where\n}\n\nasync function findRuleForRequestUser(ctx: PlatformaticContext, rules: PlatformaticRule[], roleKey: string, anonymousRole: string, isRolePath = false) {\n const request = getRequestFromContext(ctx)\n await request.setupDBAuthorizationUser()\n const roles = getRoles(request, roleKey, anonymousRole, isRolePath)\n const rule = findRule(rules, roles)\n if (!rule) {\n ctx.reply.request.log.warn({ roles, rules }, 'no rule for roles')\n throw new Unauthorized()\n }\n ctx.reply.request.log.trace({ roles, rule }, 'found rule')\n return rule\n}\n\nfunction checkFieldsFromRule(rule, fields) {\n if (!rule) {\n throw new Unauthorized()\n }\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n for (const field of fields) {\n if (!fieldsFromRule.includes(field)) {\n throw new UnauthorizedField(field)\n }\n }\n }\n}\n\nconst validateInputs = (inputs, fieldsFromRule) => {\n for (const input of inputs) {\n const inputFields = Object.keys(input)\n for (const inputField of inputFields) {\n if (!fieldsFromRule.includes(inputField)) {\n throw new UnauthorizedField(inputField)\n }\n }\n }\n}\n\nfunction checkInputFromRuleFields(rule, inputs) {\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n if (!Array.isArray(inputs)) {\n // save\n validateInputs([inputs], fieldsFromRule)\n } else {\n // insert\n validateInputs(inputs, fieldsFromRule)\n }\n }\n}\n\nfunction checkSaveMandatoryFieldsInRules(type: Entity, rules) {\n // List of not nullable, not PKs field to validate save/insert when allowed fields are specified on the rule\n const mandatoryFields =\n Object.values(type.fields)\n .filter(k => (!k.isNullable && !k.primaryKey))\n .map(({ camelcase }) => (camelcase))\n\n for (const rule of rules) {\n const { entity, save } = rule\n if (save && save.fields) {\n const fields = save.fields\n for (const mField of mandatoryFields) {\n if (!fields.includes(mField)) {\n throw new MissingNotNullableError(mField, entity)\n }\n }\n }\n }\n}\n\nexport default fp(auth, {name: '@albirex/platformatic-logto'})\n","'use strict'\n\nimport { PlatformaticRule } from '../index.js'\n\nfunction findRule(rules: PlatformaticRule[], roles: string[]) {\n let found = null\n for (const rule of rules) {\n for (const role of roles) {\n if (rule.role === role) {\n found = rule\n break\n }\n }\n if (found) {\n break\n }\n }\n return found\n}\n\nexport default findRule\n","'use strict'\n\nexport function getRequestFromContext (ctx) {\n if (ctx && !ctx.reply) {\n throw new Error('Missing reply in context. You should call this function with { ctx: { reply }}')\n }\n return ctx.reply.request\n}\n\nexport function getRoles (request, roleKey, anonymousRole, isRolePath = false) {\n let output = []\n const user = request.user\n if (!user) {\n output.push(anonymousRole)\n return output\n }\n\n let rolesRaw\n if (isRolePath) {\n const roleKeys = roleKey.split('.')\n rolesRaw = user\n for (const key of roleKeys) {\n rolesRaw = rolesRaw[key]\n }\n } else {\n rolesRaw = user[roleKey]\n }\n\n if (typeof rolesRaw === 'string') {\n output = rolesRaw.split(',')\n } else if (Array.isArray(rolesRaw)) {\n output = rolesRaw\n }\n if (output.length === 0) {\n output.push(anonymousRole)\n }\n\n return output\n}\n","'use strict'\n\nimport createError from '@fastify/error'\n\nconst ERROR_PREFIX = 'PLT_DB_AUTH'\n\nexport const Unauthorized = createError(`${ERROR_PREFIX}_UNAUTHORIZED`, 'operation not allowed', 401)\nexport const UnauthorizedField = createError(`${ERROR_PREFIX}_FIELD_UNAUTHORIZED`, 'field not allowed: %s', 401)\nexport const MissingNotNullableError = createError(`${ERROR_PREFIX}_NOT_NULLABLE_MISSING`, 'missing not nullable field: \"%s\" in save rule for entity \"%s\"')\n"],"mappings":"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","names":["createError","fastifyLogto","leven","rules","fp"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils/find-rule.ts","../src/utils/utils.ts","../src/utils/errors.ts"],"sourcesContent":["import fp from 'fastify-plugin'\nimport * as fastifyUser from 'fastify-user'\n\nimport findRule from './utils/find-rule.js'\nimport { getRequestFromContext, getRoles } from './utils/utils.js'\nimport { Unauthorized, UnauthorizedField, MissingNotNullableError } from './utils/errors.js'\nimport fastifyLogto from '@albirex/fastify-logto';\nimport { FastifyInstance, FastifyPluginAsync } from 'fastify'\nimport type { FastifyUserPluginOptions } from 'fastify-user';\nimport type { Entity, PlatformaticContext } from '@platformatic/sql-mapper'\n\nconst PLT_ADMIN_ROLE = 'platformatic-admin'\n\nexport type PlatformaticRule = {\n role: string;\n entity?: string;\n entities?: string[];\n defaults?: Record<string, string>;\n checks?: boolean;\n find?: boolean;\n save?: boolean;\n delete?: boolean;\n\n};\n\nexport type PlatformaticLogtoAuthOptions = {\n logtoBaseUrl?: string;\n logtoAppId?: string;\n logtoAppSecret?: string;\n adminSecret?: string;\n rolePath?: string;\n roleKey?: string;\n userPath?: string;\n userKey?: string;\n anonymousRole?: string;\n allowAnonymous?: boolean;\n checks?: boolean;\n defaults?: boolean;\n jwtPlugin: FastifyUserPluginOptions\n};\n\nconst auth: FastifyPluginAsync<PlatformaticLogtoAuthOptions> = async (app: FastifyInstance, opts: PlatformaticLogtoAuthOptions) => {\n app.register(fastifyLogto, {\n endpoint: opts.logtoBaseUrl || 'https://auth.example.com',\n appId: opts.logtoAppId || 'your-app-id',\n appSecret: opts.logtoAppSecret || 'your-app-secret',\n });\n\n await app.register(fastifyUser as unknown as FastifyPluginAsync, opts.jwtPlugin);\n\n const adminSecret = opts.adminSecret\n const roleKey = opts.rolePath || opts.roleKey || 'X-PLATFORMATIC-ROLE'\n const userKey = opts.userPath || opts.userKey || 'X-PLATFORMATIC-USER-ID'\n const isRolePath = !!opts.rolePath // if `true` the role is intepreted as path like `user.role`\n const anonymousRole = opts.anonymousRole || 'anonymous'\n\n async function composeLogToRules() {\n const rolesResp = await app.logto.callAPI('/api/roles?type=User', 'GET');\n\n if (!rolesResp.ok) {\n throw rolesResp;\n }\n\n const roles = await rolesResp.json();\n const rules: PlatformaticRule[] = [{\n role: anonymousRole,\n entities: Object.keys(app.platformatic.entities),\n find: opts.allowAnonymous,\n save: opts.allowAnonymous,\n delete: opts.allowAnonymous,\n }];\n\n for (const role of roles) {\n const scopesResp = await app.logto.callAPI(`/api/roles/${role.id}/scopes`, 'GET');\n\n if (!scopesResp.ok) {\n throw scopesResp;\n }\n\n const scopes = await scopesResp.json();\n\n for (const scope of scopes) {\n const roleName = role.name;\n // eslint-disable-next-line prefer-const\n let [scopeAction, entity] = scope.name.split(':');\n\n if (!app.platformatic.entities[entity]) {\n app.log.debug(`Unknown entity '${entity}' in authorization rule`)\n continue;\n }\n\n switch (scopeAction) {\n case 'create':\n scopeAction = 'save'\n break;\n case 'read':\n scopeAction = 'find'\n break;\n case 'update':\n scopeAction = 'updateMany'\n break;\n }\n\n const checkExists = rules.find(r => r.role === roleName && r.entity === entity);\n if (checkExists) {\n if (opts.checks) {\n checkExists[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n checkExists[scopeAction] = true;\n }\n } else {\n const newRule: PlatformaticRule = {\n role: roleName,\n entity,\n };\n\n if (opts.checks) {\n newRule[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n newRule[scopeAction] = true;\n }\n\n if (opts.defaults) {\n newRule.defaults = {\n userId: userKey\n };\n }\n\n rules.push(newRule);\n }\n }\n }\n\n const logRules = rules.reduce((prev, curr) => {\n (prev[curr['role']] ??= []).push(curr);\n return prev;\n }, {})\n\n for (const key in logRules) {\n app.log.info(`Rules set for role ${key}`);\n\n for (const element of logRules[key]) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { entity, entities, role, ...other } = element;\n app.log.info(`\\t${entity ?? entities.join(',')}: ${JSON.stringify(other)}`);\n }\n }\n\n const missingEntities = Object.keys(app.platformatic.entities).filter((e) => !rules.map((r) => r.entity).includes(e));\n\n if (missingEntities.length) {\n app.log.warn(`Missing rules for entities: ${missingEntities.join(', ')}`);\n }\n\n app.log.debug('LogTo calculated rules');\n app.log.debug(rules);\n return rules;\n }\n\n app.decorateRequest('setupDBAuthorizationUser', setupUser)\n\n async function setupUser() {\n // if (!adminSecret) {\n await this.extractUser()\n // }\n\n let forceAdminRole = false\n if (adminSecret && this.headers['x-platformatic-admin-secret'] === adminSecret) {\n if (opts.jwtPlugin.jwt) {\n forceAdminRole = true\n } else {\n this.log.info('admin secret is valid')\n this.user = new Proxy(this.headers, {\n get: (target, key) => {\n let value;\n if (!target[key.toString()]) {\n const newKey = key.toString().toLowerCase()\n value = target[newKey]\n } else {\n value = target[key.toString()]\n }\n\n if (!value && key.toString().toLowerCase() === roleKey.toLowerCase()) {\n value = PLT_ADMIN_ROLE\n }\n return value\n },\n })\n }\n }\n\n if (forceAdminRole) {\n // We replace just the role in `request.user`, all the rest is untouched\n this.user = {\n // ...request.user,\n [roleKey]: PLT_ADMIN_ROLE,\n }\n }\n }\n\n app.addHook('onReady', async function () {\n const rules = await composeLogToRules();\n\n // TODO validate that there is at most a rule for a given role\n const entityRules = {};\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n\n let ruleEntities = null\n if (rule.entity) {\n ruleEntities = [rule.entity]\n } else if (rule.entities) {\n ruleEntities = [...rule.entities]\n } else {\n throw new Error(`Missing entity in authorization rule ${i}`)\n }\n\n for (const ruleEntity of ruleEntities) {\n const newRule = { ...rule, entity: ruleEntity, entities: undefined }\n if (!app.platformatic.entities[newRule.entity]) {\n throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}`)\n }\n\n if (!entityRules[ruleEntity]) {\n entityRules[ruleEntity] = []\n }\n entityRules[ruleEntity].push(newRule)\n }\n }\n\n for (const entityKey of Object.keys(app.platformatic.entities)) {\n const rules = entityRules[entityKey] || []\n const type = app.platformatic.entities[entityKey]\n\n // We have subscriptions!\n let userPropToFillForPublish\n const topicsWithoutChecks = false\n\n // mqtt\n // if (app.platformatic.mq) {\n // for (const rule of rules) {\n // const checks = rule.find?.checks\n // if (typeof checks !== 'object') {\n // topicsWithoutChecks = !!rule.find\n // continue\n // }\n // const keys = Object.keys(checks)\n // if (keys.length !== 1) {\n // throw new Error(`Subscription requires that the role \"${rule.role}\" has only one check in the find rule for entity \"${rule.entity}\"`)\n // }\n // const key = keys[0]\n\n // const val = typeof checks[key] === 'object' ? checks[key].eq : checks[key]\n // if (userPropToFillForPublish && userPropToFillForPublish.val !== val) {\n // throw new Error('Unable to configure subscriptions and authorization due to multiple check clauses in find')\n // }\n // userPropToFillForPublish = { key, val }\n // }\n // }\n\n if (userPropToFillForPublish && topicsWithoutChecks) {\n throw new Error(`Subscription for entity \"${entityKey}\" have conflictling rules across roles`)\n }\n\n // MUST set this after doing the security checks on the subscriptions\n if (adminSecret) {\n rules.push({\n role: PLT_ADMIN_ROLE,\n find: true,\n save: true,\n delete: true,\n })\n }\n\n // If we have `fields` in save rules, we need to check if all the not-nullable\n // fields are specified\n checkSaveMandatoryFieldsInRules(type, rules)\n\n function useOriginal(ctx: PlatformaticContext) {\n return !ctx\n }\n\n app.platformatic.addEntityHooks(entityKey, {\n async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {\n if (useOriginal(ctx)) {\n return originalFind({ ...restOpts, where, ctx, fields })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields))\n where = await fromRuleToWhere(ctx, rule.find, where, request.user)\n\n return originalFind({ ...restOpts, where, ctx, fields })\n },\n async save(originalSave, { input, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalSave({ ctx, input, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, input)\n\n if (rule.defaults) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n\n const hasAllPrimaryKeys = input[type.primaryKey] !== undefined;\n const whereConditions = {}\n whereConditions[type.primaryKey] = { eq: input[type.primaryKey] }\n\n if (hasAllPrimaryKeys) {\n const where = await fromRuleToWhere(ctx, rule.save, whereConditions, request.user)\n\n const found = await type.find({\n where,\n ctx,\n fields,\n })\n\n if (found.length === 0) {\n throw new Unauthorized()\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n },\n\n async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, inputs)\n\n /* istanbul ignore else */\n if (rule.defaults) {\n for (const input of inputs) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n }\n\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n },\n\n async delete(originalDelete, { where, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalDelete({ where, ctx, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.delete, where, request.user)\n\n return originalDelete({ where, ctx, fields, ...restOpts })\n },\n\n async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user)\n\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n },\n })\n }\n })\n}\n\nasync function fromRuleToWhere(ctx: PlatformaticContext, rule, where, user) {\n if (!rule) {\n throw new Unauthorized()\n }\n const request = getRequestFromContext(ctx)\n /* istanbul ignore next */\n where = where || {}\n\n if (typeof rule === 'object') {\n const { checks } = rule\n\n /* istanbul ignore else */\n if (checks) {\n for (const key of Object.keys(checks)) {\n const clauses = checks[key]\n if (typeof clauses === 'string') {\n // case: \"userId\": \"X-PLATFORMATIC-USER-ID\"\n where[key] = {\n eq: request.user[clauses],\n }\n } else {\n // case:\n // userId: {\n // eq: 'X-PLATFORMATIC-USER-ID'\n // }\n for (const clauseKey of Object.keys(clauses)) {\n const clause = clauses[clauseKey]\n where[key] = {\n [clauseKey]: request.user[clause],\n }\n }\n }\n }\n }\n } else if (typeof rule === 'function') {\n where = await rule({ user, ctx, where })\n }\n return where\n}\n\nasync function findRuleForRequestUser(ctx: PlatformaticContext, rules: PlatformaticRule[], roleKey: string, anonymousRole: string, isRolePath = false) {\n const request = getRequestFromContext(ctx)\n await request.setupDBAuthorizationUser()\n const roles = getRoles(request, roleKey, anonymousRole, isRolePath)\n const rule = findRule(rules, roles)\n if (!rule) {\n ctx.reply.request.log.warn({ roles, rules }, 'no rule for roles')\n throw new Unauthorized()\n }\n ctx.reply.request.log.trace({ roles, rule }, 'found rule')\n return rule\n}\n\nfunction checkFieldsFromRule(rule, fields) {\n if (!rule) {\n throw new Unauthorized()\n }\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n for (const field of fields) {\n if (!fieldsFromRule.includes(field)) {\n throw new UnauthorizedField(field)\n }\n }\n }\n}\n\nconst validateInputs = (inputs, fieldsFromRule) => {\n for (const input of inputs) {\n const inputFields = Object.keys(input)\n for (const inputField of inputFields) {\n if (!fieldsFromRule.includes(inputField)) {\n throw new UnauthorizedField(inputField)\n }\n }\n }\n}\n\nfunction checkInputFromRuleFields(rule, inputs) {\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n if (!Array.isArray(inputs)) {\n // save\n validateInputs([inputs], fieldsFromRule)\n } else {\n // insert\n validateInputs(inputs, fieldsFromRule)\n }\n }\n}\n\nfunction checkSaveMandatoryFieldsInRules(type: Entity, rules) {\n // List of not nullable, not PKs field to validate save/insert when allowed fields are specified on the rule\n const mandatoryFields =\n Object.values(type.fields)\n .filter(k => (!k.isNullable && !k.primaryKey))\n .map(({ camelcase }) => (camelcase))\n\n for (const rule of rules) {\n const { entity, save } = rule\n if (save && save.fields) {\n const fields = save.fields\n for (const mField of mandatoryFields) {\n if (!fields.includes(mField)) {\n throw new MissingNotNullableError(mField, entity)\n }\n }\n }\n }\n}\n\nexport default fp(auth, { name: '@albirex/platformatic-logto' })\n","'use strict'\n\nimport { PlatformaticRule } from '../index.js'\n\nfunction findRule(rules: PlatformaticRule[], roles: string[]) {\n let found = null\n for (const rule of rules) {\n for (const role of roles) {\n if (rule.role === role) {\n found = rule\n break\n }\n }\n if (found) {\n break\n }\n }\n return found\n}\n\nexport default findRule\n","'use strict'\n\nexport function getRequestFromContext (ctx) {\n if (ctx && !ctx.reply) {\n throw new Error('Missing reply in context. You should call this function with { ctx: { reply }}')\n }\n return ctx.reply.request\n}\n\nexport function getRoles (request, roleKey, anonymousRole, isRolePath = false) {\n let output = []\n const user = request.user\n if (!user) {\n output.push(anonymousRole)\n return output\n }\n\n let rolesRaw\n if (isRolePath) {\n const roleKeys = roleKey.split('.')\n rolesRaw = user\n for (const key of roleKeys) {\n rolesRaw = rolesRaw[key]\n }\n } else {\n rolesRaw = user[roleKey]\n }\n\n if (typeof rolesRaw === 'string') {\n output = rolesRaw.split(',')\n } else if (Array.isArray(rolesRaw)) {\n output = rolesRaw\n }\n if (output.length === 0) {\n output.push(anonymousRole)\n }\n\n return output\n}\n","'use strict'\n\nimport createError from '@fastify/error'\n\nconst ERROR_PREFIX = 'PLT_DB_AUTH'\n\nexport const Unauthorized = createError(`${ERROR_PREFIX}_UNAUTHORIZED`, 'operation not allowed', 401)\nexport const UnauthorizedField = createError(`${ERROR_PREFIX}_FIELD_UNAUTHORIZED`, 'field not allowed: %s', 401)\nexport const MissingNotNullableError = createError(`${ERROR_PREFIX}_NOT_NULLABLE_MISSING`, 'missing not nullable field: \"%s\" in save rule for entity \"%s\"')\n"],"mappings":"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","names":["createError","fastifyLogto","rules","fp"]}
package/lib/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // src/index.ts
2
2
  import fp from "fastify-plugin";
3
- import leven from "leven";
4
3
  import * as fastifyUser from "fastify-user";
5
4
 
6
5
  // src/utils/find-rule.ts
@@ -99,12 +98,22 @@ var auth = async (app, opts) => {
99
98
  const scopes = await scopesResp.json();
100
99
  for (const scope of scopes) {
101
100
  const roleName = role.name;
102
- const [scopeAction, entity] = scope.name.split(":");
101
+ let [scopeAction, entity] = scope.name.split(":");
103
102
  if (!app.platformatic.entities[entity]) {
104
- const nearest = findNearestEntity(entity);
105
- app.log.warn(`Unknown entity '${entity}' in authorization rule. Did you mean '${nearest.entity}'?`);
103
+ app.log.debug(`Unknown entity '${entity}' in authorization rule`);
106
104
  continue;
107
105
  }
106
+ switch (scopeAction) {
107
+ case "create":
108
+ scopeAction = "save";
109
+ break;
110
+ case "read":
111
+ scopeAction = "find";
112
+ break;
113
+ case "update":
114
+ scopeAction = "updateMany";
115
+ break;
116
+ }
108
117
  const checkExists = rules.find((r) => r.role === roleName && r.entity === entity);
109
118
  if (checkExists) {
110
119
  if (opts.checks) {
@@ -139,6 +148,21 @@ var auth = async (app, opts) => {
139
148
  }
140
149
  }
141
150
  }
151
+ const logRules = rules.reduce((prev, curr) => {
152
+ (prev[curr["role"]] ??= []).push(curr);
153
+ return prev;
154
+ }, {});
155
+ for (const key in logRules) {
156
+ app.log.info(`Rules set for role ${key}`);
157
+ for (const element of logRules[key]) {
158
+ const { entity, entities, role, ...other } = element;
159
+ app.log.info(` ${entity ?? entities.join(",")}: ${JSON.stringify(other)}`);
160
+ }
161
+ }
162
+ const missingEntities = Object.keys(app.platformatic.entities).filter((e) => !rules.map((r) => r.entity).includes(e));
163
+ if (missingEntities.length) {
164
+ app.log.warn(`Missing rules for entities: ${missingEntities.join(", ")}`);
165
+ }
142
166
  app.log.debug("LogTo calculated rules");
143
167
  app.log.debug(rules);
144
168
  return rules;
@@ -176,18 +200,6 @@ var auth = async (app, opts) => {
176
200
  };
177
201
  }
178
202
  }
179
- function findNearestEntity(ruleEntity) {
180
- const entities = Object.keys(app.platformatic.entities);
181
- const nearest = entities.reduce((acc, entity) => {
182
- const distance = leven(ruleEntity, entity);
183
- if (distance < acc.distance) {
184
- acc.distance = distance;
185
- acc.entity = entity;
186
- }
187
- return acc;
188
- }, { distance: Infinity, entity: null });
189
- return nearest;
190
- }
191
203
  app.addHook("onReady", async function() {
192
204
  const rules = await composeLogToRules();
193
205
  const entityRules = {};
@@ -204,8 +216,7 @@ var auth = async (app, opts) => {
204
216
  for (const ruleEntity of ruleEntities) {
205
217
  const newRule = { ...rule, entity: ruleEntity, entities: void 0 };
206
218
  if (!app.platformatic.entities[newRule.entity]) {
207
- const nearest = findNearestEntity(ruleEntity);
208
- throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}. Did you mean '${nearest.entity}'?`);
219
+ throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}`);
209
220
  }
210
221
  if (!entityRules[ruleEntity]) {
211
222
  entityRules[ruleEntity] = [];
@@ -214,6 +225,9 @@ var auth = async (app, opts) => {
214
225
  }
215
226
  }
216
227
  for (const entityKey of Object.keys(app.platformatic.entities)) {
228
+ let useOriginal = function(ctx) {
229
+ return !ctx;
230
+ };
217
231
  const rules2 = entityRules[entityKey] || [];
218
232
  const type = app.platformatic.entities[entityKey];
219
233
  let userPropToFillForPublish;
@@ -232,6 +246,9 @@ var auth = async (app, opts) => {
232
246
  checkSaveMandatoryFieldsInRules(type, rules2);
233
247
  app.platformatic.addEntityHooks(entityKey, {
234
248
  async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {
249
+ if (useOriginal(ctx)) {
250
+ return originalFind({ ...restOpts, where, ctx, fields });
251
+ }
235
252
  const request = getRequestFromContext(ctx);
236
253
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
237
254
  checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields));
@@ -239,6 +256,9 @@ var auth = async (app, opts) => {
239
256
  return originalFind({ ...restOpts, where, ctx, fields });
240
257
  },
241
258
  async save(originalSave, { input, ctx, fields, ...restOpts }) {
259
+ if (useOriginal(ctx)) {
260
+ return originalSave({ ctx, input, fields, ...restOpts });
261
+ }
242
262
  const request = getRequestFromContext(ctx);
243
263
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
244
264
  if (!rule.save) {
@@ -274,6 +294,9 @@ var auth = async (app, opts) => {
274
294
  return originalSave({ input, ctx, fields, ...restOpts });
275
295
  },
276
296
  async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {
297
+ if (useOriginal(ctx)) {
298
+ return originalInsert({ inputs, ctx, fields, ...restOpts });
299
+ }
277
300
  const request = getRequestFromContext(ctx);
278
301
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
279
302
  if (!rule.save) {
@@ -296,12 +319,18 @@ var auth = async (app, opts) => {
296
319
  return originalInsert({ inputs, ctx, fields, ...restOpts });
297
320
  },
298
321
  async delete(originalDelete, { where, ctx, fields, ...restOpts }) {
322
+ if (useOriginal(ctx)) {
323
+ return originalDelete({ where, ctx, fields, ...restOpts });
324
+ }
299
325
  const request = getRequestFromContext(ctx);
300
326
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
301
327
  where = await fromRuleToWhere(ctx, rule.delete, where, request.user);
302
328
  return originalDelete({ where, ctx, fields, ...restOpts });
303
329
  },
304
330
  async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {
331
+ if (useOriginal(ctx)) {
332
+ return originalUpdateMany({ ...restOpts, where, ctx, fields });
333
+ }
305
334
  const request = getRequestFromContext(ctx);
306
335
  const rule = await findRuleForRequestUser(ctx, rules2, roleKey, anonymousRole, isRolePath);
307
336
  where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user);
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils/find-rule.ts","../src/utils/utils.ts","../src/utils/errors.ts"],"sourcesContent":["import fp from 'fastify-plugin'\nimport leven from 'leven'\nimport * as fastifyUser from 'fastify-user'\n\nimport findRule from './utils/find-rule.js'\nimport { getRequestFromContext, getRoles } from './utils/utils.js'\nimport { Unauthorized, UnauthorizedField, MissingNotNullableError } from './utils/errors.js'\nimport fastifyLogto from '@albirex/fastify-logto';\nimport { FastifyInstance, FastifyPluginAsync } from 'fastify'\nimport type { FastifyUserPluginOptions } from 'fastify-user';\nimport type { Entity, PlatformaticContext } from '@platformatic/sql-mapper'\n\nconst PLT_ADMIN_ROLE = 'platformatic-admin'\n\nexport type PlatformaticRule = {\n role: string;\n entity?: string;\n entities?: string[];\n defaults?: Record<string, string>;\n checks?: boolean;\n find?: boolean;\n save?: boolean;\n delete?: boolean;\n\n};\n\nexport type PlatformaticLogtoAuthOptions = {\n logtoBaseUrl?: string;\n logtoAppId?: string;\n logtoAppSecret?: string;\n adminSecret?: string;\n rolePath?: string;\n roleKey?: string;\n userPath?: string;\n userKey?: string;\n anonymousRole?: string;\n allowAnonymous?: boolean;\n checks?: boolean;\n defaults?: boolean;\n jwtPlugin: FastifyUserPluginOptions\n};\n\nconst auth: FastifyPluginAsync<PlatformaticLogtoAuthOptions> = async (app: FastifyInstance, opts: PlatformaticLogtoAuthOptions) => {\n app.register(fastifyLogto, {\n endpoint: opts.logtoBaseUrl || 'https://auth.example.com',\n appId: opts.logtoAppId || 'your-app-id',\n appSecret: opts.logtoAppSecret || 'your-app-secret',\n });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await app.register(fastifyUser as any, opts.jwtPlugin);\n\n const adminSecret = opts.adminSecret\n const roleKey = opts.rolePath || opts.roleKey || 'X-PLATFORMATIC-ROLE'\n const userKey = opts.userPath || opts.userKey || 'X-PLATFORMATIC-USER-ID'\n const isRolePath = !!opts.rolePath // if `true` the role is intepreted as path like `user.role`\n const anonymousRole = opts.anonymousRole || 'anonymous'\n\n async function composeLogToRules() {\n const rolesResp = await app.logto.callAPI('/api/roles?type=User', 'GET');\n\n if (!rolesResp.ok) {\n throw rolesResp;\n }\n\n const roles = await rolesResp.json();\n const rules: PlatformaticRule[] = [{\n role: anonymousRole,\n entities: Object.keys(app.platformatic.entities),\n find: opts.allowAnonymous,\n save: opts.allowAnonymous,\n delete: opts.allowAnonymous,\n }];\n\n for (const role of roles) {\n const scopesResp = await app.logto.callAPI(`/api/roles/${role.id}/scopes`, 'GET');\n\n if (!scopesResp.ok) {\n throw scopesResp;\n }\n\n const scopes = await scopesResp.json();\n\n for (const scope of scopes) {\n const roleName = role.name;\n const [scopeAction, entity] = scope.name.split(':');\n\n if (!app.platformatic.entities[entity]) {\n const nearest = findNearestEntity(entity)\n app.log.warn(`Unknown entity '${entity}' in authorization rule. Did you mean '${nearest.entity}'?`)\n continue;\n }\n\n const checkExists = rules.find(r => r.role === roleName && r.entity === entity);\n if (checkExists) {\n if (opts.checks) {\n checkExists[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n checkExists[scopeAction] = true;\n }\n } else {\n const newRule: PlatformaticRule = {\n role: roleName,\n entity,\n };\n\n if (opts.checks) {\n newRule[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n newRule[scopeAction] = true;\n }\n\n if (opts.defaults) {\n newRule.defaults = {\n userId: userKey\n };\n }\n\n rules.push(newRule);\n }\n }\n }\n\n app.log.debug('LogTo calculated rules');\n app.log.debug(rules);\n return rules;\n }\n\n app.decorateRequest('setupDBAuthorizationUser', setupUser)\n\n async function setupUser() {\n // if (!adminSecret) {\n await this.extractUser()\n // }\n\n let forceAdminRole = false\n if (adminSecret && this.headers['x-platformatic-admin-secret'] === adminSecret) {\n if (opts.jwtPlugin.jwt) {\n forceAdminRole = true\n } else {\n this.log.info('admin secret is valid')\n this.user = new Proxy(this.headers, {\n get: (target, key) => {\n let value;\n if (!target[key.toString()]) {\n const newKey = key.toString().toLowerCase()\n value = target[newKey]\n } else {\n value = target[key.toString()]\n }\n\n if (!value && key.toString().toLowerCase() === roleKey.toLowerCase()) {\n value = PLT_ADMIN_ROLE\n }\n return value\n },\n })\n }\n }\n\n if (forceAdminRole) {\n // We replace just the role in `request.user`, all the rest is untouched\n this.user = {\n // ...request.user,\n [roleKey]: PLT_ADMIN_ROLE,\n }\n }\n }\n\n function findNearestEntity(ruleEntity) {\n // There is an unknown entity. Let's find out the nearest one for a nice error message\n const entities = Object.keys(app.platformatic.entities)\n\n const nearest = entities.reduce((acc, entity) => {\n\n const distance = leven(ruleEntity, entity)\n if (distance < acc.distance) {\n acc.distance = distance\n acc.entity = entity\n }\n return acc\n }, { distance: Infinity, entity: null })\n return nearest\n }\n\n app.addHook('onReady', async function () {\n const rules = await composeLogToRules();\n\n // TODO validate that there is at most a rule for a given role\n const entityRules = {};\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n\n let ruleEntities = null\n if (rule.entity) {\n ruleEntities = [rule.entity]\n } else if (rule.entities) {\n ruleEntities = [...rule.entities]\n } else {\n throw new Error(`Missing entity in authorization rule ${i}`)\n }\n\n for (const ruleEntity of ruleEntities) {\n const newRule = { ...rule, entity: ruleEntity, entities: undefined }\n if (!app.platformatic.entities[newRule.entity]) {\n const nearest = findNearestEntity(ruleEntity)\n throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}. Did you mean '${nearest.entity}'?`)\n }\n\n if (!entityRules[ruleEntity]) {\n entityRules[ruleEntity] = []\n }\n entityRules[ruleEntity].push(newRule)\n }\n }\n\n for (const entityKey of Object.keys(app.platformatic.entities)) {\n const rules = entityRules[entityKey] || []\n const type = app.platformatic.entities[entityKey]\n\n // We have subscriptions!\n let userPropToFillForPublish\n const topicsWithoutChecks = false\n\n // mqtt\n // if (app.platformatic.mq) {\n // for (const rule of rules) {\n // const checks = rule.find?.checks\n // if (typeof checks !== 'object') {\n // topicsWithoutChecks = !!rule.find\n // continue\n // }\n // const keys = Object.keys(checks)\n // if (keys.length !== 1) {\n // throw new Error(`Subscription requires that the role \"${rule.role}\" has only one check in the find rule for entity \"${rule.entity}\"`)\n // }\n // const key = keys[0]\n\n // const val = typeof checks[key] === 'object' ? checks[key].eq : checks[key]\n // if (userPropToFillForPublish && userPropToFillForPublish.val !== val) {\n // throw new Error('Unable to configure subscriptions and authorization due to multiple check clauses in find')\n // }\n // userPropToFillForPublish = { key, val }\n // }\n // }\n\n if (userPropToFillForPublish && topicsWithoutChecks) {\n throw new Error(`Subscription for entity \"${entityKey}\" have conflictling rules across roles`)\n }\n\n // MUST set this after doing the security checks on the subscriptions\n if (adminSecret) {\n rules.push({\n role: PLT_ADMIN_ROLE,\n find: true,\n save: true,\n delete: true,\n })\n }\n\n // If we have `fields` in save rules, we need to check if all the not-nullable\n // fields are specified\n checkSaveMandatoryFieldsInRules(type, rules)\n\n // function useOriginal(skipAuth: boolean, ctx: PlatformaticContext) {\n // if (skipAuth === false && !ctx) {\n // throw new Error('Cannot set skipAuth to `false` without ctx')\n // }\n\n // return skipAuth || !ctx\n // }\n\n app.platformatic.addEntityHooks(entityKey, {\n async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalFind({ ...restOpts, where, ctx, fields })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields))\n where = await fromRuleToWhere(ctx, rule.find, where, request.user)\n\n return originalFind({ ...restOpts, where, ctx, fields })\n },\n async save(originalSave, { input, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalSave({ ctx, input, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, input)\n\n if (rule.defaults) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n\n const hasAllPrimaryKeys = input[type.primaryKey] !== undefined;\n const whereConditions = {}\n whereConditions[type.primaryKey] = { eq: input[type.primaryKey] }\n\n if (hasAllPrimaryKeys) {\n const where = await fromRuleToWhere(ctx, rule.save, whereConditions, request.user)\n\n const found = await type.find({\n where,\n ctx,\n fields,\n })\n\n if (found.length === 0) {\n throw new Unauthorized()\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n },\n\n async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalInsert({ inputs, ctx, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, inputs)\n\n /* istanbul ignore else */\n if (rule.defaults) {\n for (const input of inputs) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n }\n\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n },\n\n async delete(originalDelete, { where, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalDelete({ where, ctx, fields, ...restOpts })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.delete, where, request.user)\n\n return originalDelete({ where, ctx, fields, ...restOpts })\n },\n\n async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {\n // if (useOriginal(skipAuth, ctx)) {\n // return originalUpdateMany({ ...restOpts, where, ctx, fields })\n // }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user)\n\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n },\n })\n }\n })\n}\n\nasync function fromRuleToWhere(ctx: PlatformaticContext, rule, where, user) {\n if (!rule) {\n throw new Unauthorized()\n }\n const request = getRequestFromContext(ctx)\n /* istanbul ignore next */\n where = where || {}\n\n if (typeof rule === 'object') {\n const { checks } = rule\n\n /* istanbul ignore else */\n if (checks) {\n for (const key of Object.keys(checks)) {\n const clauses = checks[key]\n if (typeof clauses === 'string') {\n // case: \"userId\": \"X-PLATFORMATIC-USER-ID\"\n where[key] = {\n eq: request.user[clauses],\n }\n } else {\n // case:\n // userId: {\n // eq: 'X-PLATFORMATIC-USER-ID'\n // }\n for (const clauseKey of Object.keys(clauses)) {\n const clause = clauses[clauseKey]\n where[key] = {\n [clauseKey]: request.user[clause],\n }\n }\n }\n }\n }\n } else if (typeof rule === 'function') {\n where = await rule({ user, ctx, where })\n }\n return where\n}\n\nasync function findRuleForRequestUser(ctx: PlatformaticContext, rules: PlatformaticRule[], roleKey: string, anonymousRole: string, isRolePath = false) {\n const request = getRequestFromContext(ctx)\n await request.setupDBAuthorizationUser()\n const roles = getRoles(request, roleKey, anonymousRole, isRolePath)\n const rule = findRule(rules, roles)\n if (!rule) {\n ctx.reply.request.log.warn({ roles, rules }, 'no rule for roles')\n throw new Unauthorized()\n }\n ctx.reply.request.log.trace({ roles, rule }, 'found rule')\n return rule\n}\n\nfunction checkFieldsFromRule(rule, fields) {\n if (!rule) {\n throw new Unauthorized()\n }\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n for (const field of fields) {\n if (!fieldsFromRule.includes(field)) {\n throw new UnauthorizedField(field)\n }\n }\n }\n}\n\nconst validateInputs = (inputs, fieldsFromRule) => {\n for (const input of inputs) {\n const inputFields = Object.keys(input)\n for (const inputField of inputFields) {\n if (!fieldsFromRule.includes(inputField)) {\n throw new UnauthorizedField(inputField)\n }\n }\n }\n}\n\nfunction checkInputFromRuleFields(rule, inputs) {\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n if (!Array.isArray(inputs)) {\n // save\n validateInputs([inputs], fieldsFromRule)\n } else {\n // insert\n validateInputs(inputs, fieldsFromRule)\n }\n }\n}\n\nfunction checkSaveMandatoryFieldsInRules(type: Entity, rules) {\n // List of not nullable, not PKs field to validate save/insert when allowed fields are specified on the rule\n const mandatoryFields =\n Object.values(type.fields)\n .filter(k => (!k.isNullable && !k.primaryKey))\n .map(({ camelcase }) => (camelcase))\n\n for (const rule of rules) {\n const { entity, save } = rule\n if (save && save.fields) {\n const fields = save.fields\n for (const mField of mandatoryFields) {\n if (!fields.includes(mField)) {\n throw new MissingNotNullableError(mField, entity)\n }\n }\n }\n }\n}\n\nexport default fp(auth, {name: '@albirex/platformatic-logto'})\n","'use strict'\n\nimport { PlatformaticRule } from '../index.js'\n\nfunction findRule(rules: PlatformaticRule[], roles: string[]) {\n let found = null\n for (const rule of rules) {\n for (const role of roles) {\n if (rule.role === role) {\n found = rule\n break\n }\n }\n if (found) {\n break\n }\n }\n return found\n}\n\nexport default findRule\n","'use strict'\n\nexport function getRequestFromContext (ctx) {\n if (ctx && !ctx.reply) {\n throw new Error('Missing reply in context. You should call this function with { ctx: { reply }}')\n }\n return ctx.reply.request\n}\n\nexport function getRoles (request, roleKey, anonymousRole, isRolePath = false) {\n let output = []\n const user = request.user\n if (!user) {\n output.push(anonymousRole)\n return output\n }\n\n let rolesRaw\n if (isRolePath) {\n const roleKeys = roleKey.split('.')\n rolesRaw = user\n for (const key of roleKeys) {\n rolesRaw = rolesRaw[key]\n }\n } else {\n rolesRaw = user[roleKey]\n }\n\n if (typeof rolesRaw === 'string') {\n output = rolesRaw.split(',')\n } else if (Array.isArray(rolesRaw)) {\n output = rolesRaw\n }\n if (output.length === 0) {\n output.push(anonymousRole)\n }\n\n return output\n}\n","'use strict'\n\nimport createError from '@fastify/error'\n\nconst ERROR_PREFIX = 'PLT_DB_AUTH'\n\nexport const Unauthorized = createError(`${ERROR_PREFIX}_UNAUTHORIZED`, 'operation not allowed', 401)\nexport const UnauthorizedField = createError(`${ERROR_PREFIX}_FIELD_UNAUTHORIZED`, 'field not allowed: %s', 401)\nexport const MissingNotNullableError = createError(`${ERROR_PREFIX}_NOT_NULLABLE_MISSING`, 'missing not nullable field: \"%s\" in save rule for entity \"%s\"')\n"],"mappings":"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","names":["rules"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/utils/find-rule.ts","../src/utils/utils.ts","../src/utils/errors.ts"],"sourcesContent":["import fp from 'fastify-plugin'\nimport * as fastifyUser from 'fastify-user'\n\nimport findRule from './utils/find-rule.js'\nimport { getRequestFromContext, getRoles } from './utils/utils.js'\nimport { Unauthorized, UnauthorizedField, MissingNotNullableError } from './utils/errors.js'\nimport fastifyLogto from '@albirex/fastify-logto';\nimport { FastifyInstance, FastifyPluginAsync } from 'fastify'\nimport type { FastifyUserPluginOptions } from 'fastify-user';\nimport type { Entity, PlatformaticContext } from '@platformatic/sql-mapper'\n\nconst PLT_ADMIN_ROLE = 'platformatic-admin'\n\nexport type PlatformaticRule = {\n role: string;\n entity?: string;\n entities?: string[];\n defaults?: Record<string, string>;\n checks?: boolean;\n find?: boolean;\n save?: boolean;\n delete?: boolean;\n\n};\n\nexport type PlatformaticLogtoAuthOptions = {\n logtoBaseUrl?: string;\n logtoAppId?: string;\n logtoAppSecret?: string;\n adminSecret?: string;\n rolePath?: string;\n roleKey?: string;\n userPath?: string;\n userKey?: string;\n anonymousRole?: string;\n allowAnonymous?: boolean;\n checks?: boolean;\n defaults?: boolean;\n jwtPlugin: FastifyUserPluginOptions\n};\n\nconst auth: FastifyPluginAsync<PlatformaticLogtoAuthOptions> = async (app: FastifyInstance, opts: PlatformaticLogtoAuthOptions) => {\n app.register(fastifyLogto, {\n endpoint: opts.logtoBaseUrl || 'https://auth.example.com',\n appId: opts.logtoAppId || 'your-app-id',\n appSecret: opts.logtoAppSecret || 'your-app-secret',\n });\n\n await app.register(fastifyUser as unknown as FastifyPluginAsync, opts.jwtPlugin);\n\n const adminSecret = opts.adminSecret\n const roleKey = opts.rolePath || opts.roleKey || 'X-PLATFORMATIC-ROLE'\n const userKey = opts.userPath || opts.userKey || 'X-PLATFORMATIC-USER-ID'\n const isRolePath = !!opts.rolePath // if `true` the role is intepreted as path like `user.role`\n const anonymousRole = opts.anonymousRole || 'anonymous'\n\n async function composeLogToRules() {\n const rolesResp = await app.logto.callAPI('/api/roles?type=User', 'GET');\n\n if (!rolesResp.ok) {\n throw rolesResp;\n }\n\n const roles = await rolesResp.json();\n const rules: PlatformaticRule[] = [{\n role: anonymousRole,\n entities: Object.keys(app.platformatic.entities),\n find: opts.allowAnonymous,\n save: opts.allowAnonymous,\n delete: opts.allowAnonymous,\n }];\n\n for (const role of roles) {\n const scopesResp = await app.logto.callAPI(`/api/roles/${role.id}/scopes`, 'GET');\n\n if (!scopesResp.ok) {\n throw scopesResp;\n }\n\n const scopes = await scopesResp.json();\n\n for (const scope of scopes) {\n const roleName = role.name;\n // eslint-disable-next-line prefer-const\n let [scopeAction, entity] = scope.name.split(':');\n\n if (!app.platformatic.entities[entity]) {\n app.log.debug(`Unknown entity '${entity}' in authorization rule`)\n continue;\n }\n\n switch (scopeAction) {\n case 'create':\n scopeAction = 'save'\n break;\n case 'read':\n scopeAction = 'find'\n break;\n case 'update':\n scopeAction = 'updateMany'\n break;\n }\n\n const checkExists = rules.find(r => r.role === roleName && r.entity === entity);\n if (checkExists) {\n if (opts.checks) {\n checkExists[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n checkExists[scopeAction] = true;\n }\n } else {\n const newRule: PlatformaticRule = {\n role: roleName,\n entity,\n };\n\n if (opts.checks) {\n newRule[scopeAction] = {\n checks: {\n userId: userKey\n }\n };\n } else {\n newRule[scopeAction] = true;\n }\n\n if (opts.defaults) {\n newRule.defaults = {\n userId: userKey\n };\n }\n\n rules.push(newRule);\n }\n }\n }\n\n const logRules = rules.reduce((prev, curr) => {\n (prev[curr['role']] ??= []).push(curr);\n return prev;\n }, {})\n\n for (const key in logRules) {\n app.log.info(`Rules set for role ${key}`);\n\n for (const element of logRules[key]) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { entity, entities, role, ...other } = element;\n app.log.info(`\\t${entity ?? entities.join(',')}: ${JSON.stringify(other)}`);\n }\n }\n\n const missingEntities = Object.keys(app.platformatic.entities).filter((e) => !rules.map((r) => r.entity).includes(e));\n\n if (missingEntities.length) {\n app.log.warn(`Missing rules for entities: ${missingEntities.join(', ')}`);\n }\n\n app.log.debug('LogTo calculated rules');\n app.log.debug(rules);\n return rules;\n }\n\n app.decorateRequest('setupDBAuthorizationUser', setupUser)\n\n async function setupUser() {\n // if (!adminSecret) {\n await this.extractUser()\n // }\n\n let forceAdminRole = false\n if (adminSecret && this.headers['x-platformatic-admin-secret'] === adminSecret) {\n if (opts.jwtPlugin.jwt) {\n forceAdminRole = true\n } else {\n this.log.info('admin secret is valid')\n this.user = new Proxy(this.headers, {\n get: (target, key) => {\n let value;\n if (!target[key.toString()]) {\n const newKey = key.toString().toLowerCase()\n value = target[newKey]\n } else {\n value = target[key.toString()]\n }\n\n if (!value && key.toString().toLowerCase() === roleKey.toLowerCase()) {\n value = PLT_ADMIN_ROLE\n }\n return value\n },\n })\n }\n }\n\n if (forceAdminRole) {\n // We replace just the role in `request.user`, all the rest is untouched\n this.user = {\n // ...request.user,\n [roleKey]: PLT_ADMIN_ROLE,\n }\n }\n }\n\n app.addHook('onReady', async function () {\n const rules = await composeLogToRules();\n\n // TODO validate that there is at most a rule for a given role\n const entityRules = {};\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i]\n\n let ruleEntities = null\n if (rule.entity) {\n ruleEntities = [rule.entity]\n } else if (rule.entities) {\n ruleEntities = [...rule.entities]\n } else {\n throw new Error(`Missing entity in authorization rule ${i}`)\n }\n\n for (const ruleEntity of ruleEntities) {\n const newRule = { ...rule, entity: ruleEntity, entities: undefined }\n if (!app.platformatic.entities[newRule.entity]) {\n throw new Error(`Unknown entity '${ruleEntity}' in authorization rule ${i}`)\n }\n\n if (!entityRules[ruleEntity]) {\n entityRules[ruleEntity] = []\n }\n entityRules[ruleEntity].push(newRule)\n }\n }\n\n for (const entityKey of Object.keys(app.platformatic.entities)) {\n const rules = entityRules[entityKey] || []\n const type = app.platformatic.entities[entityKey]\n\n // We have subscriptions!\n let userPropToFillForPublish\n const topicsWithoutChecks = false\n\n // mqtt\n // if (app.platformatic.mq) {\n // for (const rule of rules) {\n // const checks = rule.find?.checks\n // if (typeof checks !== 'object') {\n // topicsWithoutChecks = !!rule.find\n // continue\n // }\n // const keys = Object.keys(checks)\n // if (keys.length !== 1) {\n // throw new Error(`Subscription requires that the role \"${rule.role}\" has only one check in the find rule for entity \"${rule.entity}\"`)\n // }\n // const key = keys[0]\n\n // const val = typeof checks[key] === 'object' ? checks[key].eq : checks[key]\n // if (userPropToFillForPublish && userPropToFillForPublish.val !== val) {\n // throw new Error('Unable to configure subscriptions and authorization due to multiple check clauses in find')\n // }\n // userPropToFillForPublish = { key, val }\n // }\n // }\n\n if (userPropToFillForPublish && topicsWithoutChecks) {\n throw new Error(`Subscription for entity \"${entityKey}\" have conflictling rules across roles`)\n }\n\n // MUST set this after doing the security checks on the subscriptions\n if (adminSecret) {\n rules.push({\n role: PLT_ADMIN_ROLE,\n find: true,\n save: true,\n delete: true,\n })\n }\n\n // If we have `fields` in save rules, we need to check if all the not-nullable\n // fields are specified\n checkSaveMandatoryFieldsInRules(type, rules)\n\n function useOriginal(ctx: PlatformaticContext) {\n return !ctx\n }\n\n app.platformatic.addEntityHooks(entityKey, {\n async find(originalFind, { where, ctx, fields, ...restOpts } = {}) {\n if (useOriginal(ctx)) {\n return originalFind({ ...restOpts, where, ctx, fields })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n checkFieldsFromRule(rule.find, fields || Object.keys(app.platformatic.entities[entityKey].fields))\n where = await fromRuleToWhere(ctx, rule.find, where, request.user)\n\n return originalFind({ ...restOpts, where, ctx, fields })\n },\n async save(originalSave, { input, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalSave({ ctx, input, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, input)\n\n if (rule.defaults) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n\n const hasAllPrimaryKeys = input[type.primaryKey] !== undefined;\n const whereConditions = {}\n whereConditions[type.primaryKey] = { eq: input[type.primaryKey] }\n\n if (hasAllPrimaryKeys) {\n const where = await fromRuleToWhere(ctx, rule.save, whereConditions, request.user)\n\n const found = await type.find({\n where,\n ctx,\n fields,\n })\n\n if (found.length === 0) {\n throw new Unauthorized()\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n }\n\n return originalSave({ input, ctx, fields, ...restOpts })\n },\n\n async insert(originalInsert, { inputs, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n if (!rule.save) {\n throw new Unauthorized()\n }\n\n checkFieldsFromRule(rule.save, fields)\n checkInputFromRuleFields(rule.save, inputs)\n\n /* istanbul ignore else */\n if (rule.defaults) {\n for (const input of inputs) {\n for (const key of Object.keys(rule.defaults)) {\n const defaults = rule.defaults[key]\n if (typeof defaults === 'function') {\n input[key] = await defaults({ user: request.user, ctx, input })\n } else {\n input[key] = request.user[defaults]\n }\n }\n }\n }\n\n return originalInsert({ inputs, ctx, fields, ...restOpts })\n },\n\n async delete(originalDelete, { where, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalDelete({ where, ctx, fields, ...restOpts })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.delete, where, request.user)\n\n return originalDelete({ where, ctx, fields, ...restOpts })\n },\n\n async updateMany(originalUpdateMany, { where, ctx, fields, ...restOpts }) {\n if (useOriginal(ctx)) {\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n }\n const request = getRequestFromContext(ctx)\n const rule = await findRuleForRequestUser(ctx, rules, roleKey, anonymousRole, isRolePath)\n\n where = await fromRuleToWhere(ctx, rule.updateMany, where, request.user)\n\n return originalUpdateMany({ ...restOpts, where, ctx, fields })\n },\n })\n }\n })\n}\n\nasync function fromRuleToWhere(ctx: PlatformaticContext, rule, where, user) {\n if (!rule) {\n throw new Unauthorized()\n }\n const request = getRequestFromContext(ctx)\n /* istanbul ignore next */\n where = where || {}\n\n if (typeof rule === 'object') {\n const { checks } = rule\n\n /* istanbul ignore else */\n if (checks) {\n for (const key of Object.keys(checks)) {\n const clauses = checks[key]\n if (typeof clauses === 'string') {\n // case: \"userId\": \"X-PLATFORMATIC-USER-ID\"\n where[key] = {\n eq: request.user[clauses],\n }\n } else {\n // case:\n // userId: {\n // eq: 'X-PLATFORMATIC-USER-ID'\n // }\n for (const clauseKey of Object.keys(clauses)) {\n const clause = clauses[clauseKey]\n where[key] = {\n [clauseKey]: request.user[clause],\n }\n }\n }\n }\n }\n } else if (typeof rule === 'function') {\n where = await rule({ user, ctx, where })\n }\n return where\n}\n\nasync function findRuleForRequestUser(ctx: PlatformaticContext, rules: PlatformaticRule[], roleKey: string, anonymousRole: string, isRolePath = false) {\n const request = getRequestFromContext(ctx)\n await request.setupDBAuthorizationUser()\n const roles = getRoles(request, roleKey, anonymousRole, isRolePath)\n const rule = findRule(rules, roles)\n if (!rule) {\n ctx.reply.request.log.warn({ roles, rules }, 'no rule for roles')\n throw new Unauthorized()\n }\n ctx.reply.request.log.trace({ roles, rule }, 'found rule')\n return rule\n}\n\nfunction checkFieldsFromRule(rule, fields) {\n if (!rule) {\n throw new Unauthorized()\n }\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n for (const field of fields) {\n if (!fieldsFromRule.includes(field)) {\n throw new UnauthorizedField(field)\n }\n }\n }\n}\n\nconst validateInputs = (inputs, fieldsFromRule) => {\n for (const input of inputs) {\n const inputFields = Object.keys(input)\n for (const inputField of inputFields) {\n if (!fieldsFromRule.includes(inputField)) {\n throw new UnauthorizedField(inputField)\n }\n }\n }\n}\n\nfunction checkInputFromRuleFields(rule, inputs) {\n const { fields: fieldsFromRule } = rule\n /* istanbul ignore else */\n if (fieldsFromRule) {\n if (!Array.isArray(inputs)) {\n // save\n validateInputs([inputs], fieldsFromRule)\n } else {\n // insert\n validateInputs(inputs, fieldsFromRule)\n }\n }\n}\n\nfunction checkSaveMandatoryFieldsInRules(type: Entity, rules) {\n // List of not nullable, not PKs field to validate save/insert when allowed fields are specified on the rule\n const mandatoryFields =\n Object.values(type.fields)\n .filter(k => (!k.isNullable && !k.primaryKey))\n .map(({ camelcase }) => (camelcase))\n\n for (const rule of rules) {\n const { entity, save } = rule\n if (save && save.fields) {\n const fields = save.fields\n for (const mField of mandatoryFields) {\n if (!fields.includes(mField)) {\n throw new MissingNotNullableError(mField, entity)\n }\n }\n }\n }\n}\n\nexport default fp(auth, { name: '@albirex/platformatic-logto' })\n","'use strict'\n\nimport { PlatformaticRule } from '../index.js'\n\nfunction findRule(rules: PlatformaticRule[], roles: string[]) {\n let found = null\n for (const rule of rules) {\n for (const role of roles) {\n if (rule.role === role) {\n found = rule\n break\n }\n }\n if (found) {\n break\n }\n }\n return found\n}\n\nexport default findRule\n","'use strict'\n\nexport function getRequestFromContext (ctx) {\n if (ctx && !ctx.reply) {\n throw new Error('Missing reply in context. You should call this function with { ctx: { reply }}')\n }\n return ctx.reply.request\n}\n\nexport function getRoles (request, roleKey, anonymousRole, isRolePath = false) {\n let output = []\n const user = request.user\n if (!user) {\n output.push(anonymousRole)\n return output\n }\n\n let rolesRaw\n if (isRolePath) {\n const roleKeys = roleKey.split('.')\n rolesRaw = user\n for (const key of roleKeys) {\n rolesRaw = rolesRaw[key]\n }\n } else {\n rolesRaw = user[roleKey]\n }\n\n if (typeof rolesRaw === 'string') {\n output = rolesRaw.split(',')\n } else if (Array.isArray(rolesRaw)) {\n output = rolesRaw\n }\n if (output.length === 0) {\n output.push(anonymousRole)\n }\n\n return output\n}\n","'use strict'\n\nimport createError from '@fastify/error'\n\nconst ERROR_PREFIX = 'PLT_DB_AUTH'\n\nexport const Unauthorized = createError(`${ERROR_PREFIX}_UNAUTHORIZED`, 'operation not allowed', 401)\nexport const UnauthorizedField = createError(`${ERROR_PREFIX}_FIELD_UNAUTHORIZED`, 'field not allowed: %s', 401)\nexport const MissingNotNullableError = createError(`${ERROR_PREFIX}_NOT_NULLABLE_MISSING`, 'missing not nullable field: \"%s\" in save rule for entity \"%s\"')\n"],"mappings":"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","names":["rules"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@albirex/platformatic-logto",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "description": "LogTo roles and scopes integrated in Platformatic authorization",
5
5
  "type": "module",
6
6
  "main": "./lib/index.cjs",
@@ -8,14 +8,9 @@
8
8
  "types": "./lib/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "import": {
12
- "types": "./lib/index.d.ts",
13
- "default": "./lib/index.js"
14
- },
15
- "require": {
16
- "types": "./lib/index.d.cts",
17
- "default": "./lib/index.cjs"
18
- }
11
+ "types": "./lib/index.d.ts",
12
+ "import": "./lib/index.js",
13
+ "require": "./lib/index.cjs"
19
14
  }
20
15
  },
21
16
  "files": [
@@ -43,7 +38,7 @@
43
38
  "typescript-eslint": "^8.16.0"
44
39
  },
45
40
  "dependencies": {
46
- "@albirex/fastify-logto": "^1.3.1",
41
+ "@albirex/fastify-logto": "^1.3.2",
47
42
  "@fastify/error": "^4.1.0",
48
43
  "@logto/js": "^5.1.1",
49
44
  "@logto/node": "^3.1.4",