snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
const restrictedRolePermissions = new Map<string, Set<string>>();
export const AuthorizationUtils = class {
static addRolePermissionWhiteList(roleId: string, list: string[]): void {
if (!roleId) {
throw new Error('invalid-param');
}
if (!list) {
throw new Error('invalid-param');
}
if (!restrictedRolePermissions.has(roleId)) {
restrictedRolePermissions.set(roleId, new Set());
}
const rules = restrictedRolePermissions.get(roleId);
for (const permissionId of list) {
rules?.add(permissionId);
}
}
static isPermissionRestrictedForRole(permissionId: string, roleId: string): boolean {
if (!roleId || !permissionId) {
throw new Error('invalid-param');
}
if (!restrictedRolePermissions.has(roleId)) {
return false;
}
const rules = restrictedRolePermissions.get(roleId);
if (!rules?.size) {
return false;
}
return !rules.has(permissionId);
}
static isPermissionRestrictedForRoleList(permissionId: string, roleList: string[]): boolean {
if (!roleList || !permissionId) {
throw new Error('invalid-param');
}
for (const roleId of roleList) {
if (this.isPermissionRestrictedForRole(permissionId, roleId)) {
return true;
}
}
return false;
}
static hasRestrictionsToRole(roleId: string): boolean {
return restrictedRolePermissions.has(roleId);
}
};

View File

@@ -0,0 +1,101 @@
import type { IPermission, IRole, IUser } from '@rocket.chat/core-typings';
import { AuthorizationUtils } from './AuthorizationUtils';
export type AuthorizationDeps = {
/** The currently logged-in user id, or undefined. */
getCurrentUserId: () => IUser['_id'] | undefined;
/** The role ids assigned to a given user (Users scope). */
getUserRoles: (userId: IUser['_id']) => IRole['_id'][] | undefined;
/** Lookup a permission by id. */
getPermission: (permissionId: IPermission['_id']) => IPermission | undefined;
/** The scope of a role; defaults to 'Users' when the role is unknown. */
getRoleScope: (roleId: IRole['_id']) => IRole['scope'] | undefined;
/** Whether a subscription scoped to `rid` grants `roleId`. */
hasSubscriptionRole: (rid: string, roleId: IRole['_id']) => boolean;
/** Whether the permissions cache is hydrated; otherwise checks short-circuit to false. */
isReady: () => boolean;
};
export type AuthorizationFunctions = {
hasRole: (userId: IUser['_id'], roleId: IRole['_id'], scope?: string) => boolean;
hasAllPermission: (permissions: IPermission['_id'] | IPermission['_id'][], scope?: string, scopedRoles?: IRole['_id'][]) => boolean;
hasAtLeastOnePermission: (permissions: IPermission['_id'] | IPermission['_id'][], scope?: string) => boolean;
/** Alias of hasAllPermission, kept for parity with the previous API. */
hasPermission: (permissions: IPermission['_id'] | IPermission['_id'][], scope?: string, scopedRoles?: IRole['_id'][]) => boolean;
userHasAllPermission: (
permissions: IPermission['_id'] | IPermission['_id'][],
scope: string | undefined,
userId: IUser['_id'],
) => boolean;
};
/**
* Pure factory for the client-side authorization helpers. All store access is
* threaded through the {@link AuthorizationDeps} accessors, so the returned
* functions are testable in isolation and reusable across any state backend.
*/
export const createAuthorizationFunctions = (deps: AuthorizationDeps): AuthorizationFunctions => {
const hasRole = (userId: IUser['_id'], roleId: IRole['_id'], scope?: string): boolean => {
const roleScope = deps.getRoleScope(roleId) ?? 'Users';
switch (roleScope) {
case 'Subscriptions':
if (!scope) return false;
return deps.hasSubscriptionRole(scope, roleId);
case 'Users':
return deps.getUserRoles(userId)?.includes(roleId) ?? false;
default:
return false;
}
};
const checkPermissions = (
permissionIds: IPermission['_id'][],
scope: string | undefined,
userId: IUser['_id'],
scopedRoles: IRole['_id'][] | undefined,
quantifier: (this: IPermission['_id'][], predicate: (id: IPermission['_id']) => boolean) => boolean,
): boolean => {
const userRoles = deps.getUserRoles(userId);
return quantifier.call(permissionIds, (permissionId) => {
if (userRoles && AuthorizationUtils.isPermissionRestrictedForRoleList(permissionId, userRoles)) {
return false;
}
const roles = deps.getPermission(permissionId)?.roles ?? [];
return roles.some((roleId) => {
if (scopedRoles?.includes(roleId)) return true;
return hasRole(userId, roleId, scope);
});
});
};
const validatePermissions = (
permissions: IPermission['_id'] | IPermission['_id'][],
scope: string | undefined,
quantifier: (this: IPermission['_id'][], predicate: (id: IPermission['_id']) => boolean) => boolean,
userId: IUser['_id'] | undefined,
scopedRoles?: IRole['_id'][],
): boolean => {
if (!userId) return false;
if (!deps.isReady()) return false;
const ids = ([] as IPermission['_id'][]).concat(permissions);
return checkPermissions(ids, scope, userId, scopedRoles, quantifier);
};
const hasAllPermission: AuthorizationFunctions['hasAllPermission'] = (permissions, scope, scopedRoles) =>
validatePermissions(permissions, scope, Array.prototype.every, deps.getCurrentUserId(), scopedRoles);
const hasAtLeastOnePermission: AuthorizationFunctions['hasAtLeastOnePermission'] = (permissions, scope) =>
validatePermissions(permissions, scope, Array.prototype.some, deps.getCurrentUserId());
const userHasAllPermission: AuthorizationFunctions['userHasAllPermission'] = (permissions, scope, userId) =>
validatePermissions(permissions, scope, Array.prototype.every, userId);
return {
hasRole,
hasAllPermission,
hasAtLeastOnePermission,
hasPermission: hasAllPermission,
userHasAllPermission,
};
};

View File

@@ -0,0 +1,14 @@
import type { ISetting } from '@rocket.chat/core-typings';
export const getSettingPermissionId = function (settingId: ISetting['_id']) {
// setting-based permissions
return `change-setting-${settingId}`;
};
export const CONSTANTS = {
SETTINGS_LEVEL: 'settings',
} as const;
export const confirmationRequiredPermissions = ['access-permissions'];
export { AuthorizationUtils } from './AuthorizationUtils';