Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
chore(vendor): update @lightbasenl/backend
Browse files Browse the repository at this point in the history
_This PR is created by sync and will be force-pushed daily. Overwriting any manual changes done to this PR._

- feat(backend): add hook to be called in `authRequireUser` on a successful check (lightbasenl/platform-components@90f5223)
- chore: make compatible with new and old lint configs (lightbasenl/platform-components@445035b)
- chore(deps): Bump @lightbase/pull-through-cache from 0.2.0 to 0.2.1 in the production group (lightbasenl/platform-components#1326) (lightbasenl/platform-components@83e6a49)
- chore(backend): remove duplicate check on `requiredPermissions` (lightbasenl/platform-components@387fa87)
- feat(backend): support `oneOfRequiredPermissions` (lightbasenl/platform-components@f78adcc)
- feat(feature-flag,multitenant): report cache events as Sentry metric (lightbasenl/platform-components@22ebc13)- Failed to execute `npx compas lint`. Sync is not able to correct this, so human checks and fixes are necessary for this PR.
  • Loading branch information
github-actions[bot] committed Jul 24, 2024
1 parent 07e7822 commit 9a65eba
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 26 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions vendor/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"scripts": {},
"dependencies": {
"@lightbase/pull-through-cache": "0.1.2",
"@lightbase/pull-through-cache": "0.2.1",
"@xmldom/xmldom": "0.8.10",
"bcrypt": "5.1.1",
"rate-limiter-flexible": "5.0.3",
Expand All @@ -30,5 +30,5 @@
"url": "https://github.com/lightbasenl/platform-components.git",
"directory": "packages/backend"
},
"gitHead": "b335a6c8aa6f5e14489b582b02b6fa45beda00b6"
"gitHead": "ec78a715b0421e9b0ba377bc4fc9880fb6323de4"
}
2 changes: 2 additions & 0 deletions vendor/backend/src/auth/keycloak-based/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ export async function authKeycloakBasedVerifyAndReadToken(
} catch (e) {
throw AppError.validationError(
"authKeycloakBased.verifyAndReadToken.invalidToken",
{},
e,
);
}
}
Expand Down
5 changes: 3 additions & 2 deletions vendor/backend/src/auth/permissions/controller.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable jsdoc/check-types */
import { newEventFromEvent } from "@compas/stdlib";
import { backendGetTenantAndUser } from "../../events.js";
import { sql } from "../../services.js";
Expand All @@ -19,8 +20,8 @@ import {

/**
* @typedef {(tenants:
* QueryResultBackendTenant[]) =>
* PermissionMandatoryRole[]} PermissionBuildMandatoryRoles
* Array<QueryResultBackendTenant>) =>
* Array<PermissionMandatoryRole>} PermissionBuildMandatoryRoles
*/

/**
Expand Down
54 changes: 39 additions & 15 deletions vendor/backend/src/auth/user.events.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable jsdoc/check-types */

import {
AppError,
eventStart,
Expand All @@ -10,6 +12,7 @@ import {
import { query, queueWorkerAddJob } from "@compas/store";
import speakeasy from "speakeasy";
import {
onAuthRequireUserCallback,
queries,
queryPermission,
queryRole,
Expand Down Expand Up @@ -89,7 +92,10 @@ const authQueries = {
* @property {boolean|undefined} [requireDigidBased]
* @property {boolean|undefined} [requireKeycloakBased]
* @property {boolean|undefined} [requirePasswordBased]
* @property {AuthPermissionIdentifier[]|undefined} [requiredPermissions]
* @property {AuthPermissionIdentifier[]|undefined} [requiredPermissions] Require all
* provided permissions
* @property {AuthPermissionIdentifier[]|undefined} [oneOfRequiredPermissions] Require
* one of the provided permissions
*/

/**
Expand Down Expand Up @@ -271,12 +277,12 @@ export async function authCreateUser(event, sql, data, options) {
* isVerified?: boolean,
* },
* withPermissions?: {
* permissions?: AuthPermissionIdentifier[],
* roles?: string[],
* permissions?: Array<AuthPermissionIdentifier>,
* roles?: Array<string>,
* },
* withMultitenant?: {
* syncUsersAcrossAllTenants?: boolean,
* tenants?: string[],
* tenants?: Array<string>,
* }
* }} options
* @returns {Promise<QueryResultAuthUser>}
Expand Down Expand Up @@ -633,8 +639,8 @@ export async function authRequireUser(
}

if (
Array.isArray(options.requiredPermissions) &&
options.requiredPermissions.length > 0
Array.isArray(options.requiredPermissions) ||
Array.isArray(options.oneOfRequiredPermissions)
) {
const permissionSet = new Set();
// @ts-expect-error
Expand All @@ -645,20 +651,38 @@ export async function authRequireUser(
}
}

const missingPermissions = [];
for (const requiredPermission of options.requiredPermissions) {
if (!permissionSet.has(requiredPermission)) {
missingPermissions.push(requiredPermission);
if (options.requiredPermissions) {
const missingPermissions = [];
for (const requiredPermission of options.requiredPermissions) {
if (!permissionSet.has(requiredPermission)) {
missingPermissions.push(requiredPermission);
}
}
}

if (missingPermissions.length > 0) {
throw AppError.validationError(`${eventKey}.missingPermissions`, {
missingPermissions,
});
if (missingPermissions.length > 0) {
throw AppError.validationError(`${eventKey}.missingPermissions`, {
missingPermissions,
});
}
} else if (options.oneOfRequiredPermissions) {
let hasOnePermission = false;
for (const requiredPermission of options.oneOfRequiredPermissions) {
if (permissionSet.has(requiredPermission)) {
hasOnePermission = true;
break;
}
}

if (!hasOnePermission) {
throw AppError.validationError(`${eventKey}.missingPermissions`, {
missingPermissions: options.oneOfRequiredPermissions,
});
}
}
}

onAuthRequireUserCallback(user);

eventStop(event);

return user;
Expand Down
4 changes: 4 additions & 0 deletions vendor/backend/src/feature-flag/cache.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AppError } from "@compas/stdlib";
import { PullThroughCache } from "@lightbase/pull-through-cache";
import { queryFeatureFlag, sql } from "../services.js";
import { cacheEventToSentryMetric } from "../util.js";

/**
* Short TTL feature flag cache. Keeps all flags for 5 seconds in memory,
Expand All @@ -16,6 +17,9 @@ export const featureFlagCache = new PullThroughCache()
})
.withFetcher({
fetcher: featureFlagFetcher,
})
.withEventCallback({
callback: cacheEventToSentryMetric("featureFlag"),
});

/**
Expand Down
3 changes: 1 addition & 2 deletions vendor/backend/src/feature-flag/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ export async function featureFlagSetDynamic(

if (featureFlagCache.isEnabled()) {
// Clear the cache if enabled. This method function is often only used in test code, which most likely disables the cache anyways.
featureFlagCache.disable();
featureFlagCache.enable();
featureFlagCache.clearAll();
}

eventStop(event);
Expand Down
4 changes: 4 additions & 0 deletions vendor/backend/src/multitenant/cache.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isNil, uuid } from "@compas/stdlib";
import { PullThroughCache } from "@lightbase/pull-through-cache";
import { queryTenant, sql, tenantBuilder } from "../services.js";
import { cacheEventToSentryMetric } from "../util.js";

/**
* Frequently sampled tenant cache.
Expand All @@ -19,6 +20,9 @@ export const tenantCache = new PullThroughCache()
})
.withFetcher({
fetcher: tenantFetcher,
})
.withEventCallback({
callback: cacheEventToSentryMetric("tenant"),
});

/**
Expand Down
10 changes: 10 additions & 0 deletions vendor/backend/src/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ export let userBuilder = {
*/
export let tenantBuilder = {};

/**
* @type {(user: QueryResultAuthUser) => void}}
*/
// eslint-disable-next-line no-unused-vars
export let onAuthRequireUserCallback = (_user) => {};

/** @type {import("@compas/store").SessionTransportSettings} */
// @ts-expect-error
//
Expand Down Expand Up @@ -162,6 +168,7 @@ export let sessionDurationCallback = () => ({
* @param {{
* userBuilder?: AuthUserQueryBuilder,
* tenantBuilder?: BackendTenantQueryBuilder,
* onAuthRequireUserCallback?: (user: QueryResultAuthUser) => void,
* shouldPasswordBasedForcePasswordResetAfterSixMonths?: boolean,
* shouldPasswordBasedRollingLoginAttemptBlock?: boolean,
* shouldPasswordBasedUpdatePasswordRemoveCurrentSession?: boolean,
Expand Down Expand Up @@ -277,6 +284,9 @@ export async function backendInitServices(other) {
tenantBuilder = { ...other.tenantBuilder, ...tenantBuilder };
}

onAuthRequireUserCallback =
other.onAuthRequireUserCallback ?? onAuthRequireUserCallback;

passwordBasedForcePasswordResetAfterSixMonths =
other.shouldPasswordBasedForcePasswordResetAfterSixMonths ?? false;
passwordBasedRollingLoginAttemptBlock =
Expand Down
21 changes: 20 additions & 1 deletion vendor/backend/src/util.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
import { existsSync } from "node:fs";
import { AppError, isNil, pathJoin } from "@compas/stdlib";
import { _compasSentryExport, AppError, isNil, pathJoin } from "@compas/stdlib";

/**
* Count the different PullThroughCache events as their own metric
*
* @param {string} cacheName
* @returns {(function(string): void)}
*/
export function cacheEventToSentryMetric(cacheName) {
return (event) => {
if (_compasSentryExport?.metrics?.increment) {
_compasSentryExport.metrics.increment(`cache.${event}`, 1, {
tags: {
cacheName,
},
unit: "none",
});
}
};
}

/**
* Takes an AppError and normalizes it to a 401, to simplify frontend error handling on
Expand Down

0 comments on commit 9a65eba

Please sign in to comment.