This repository has been archived by the owner on Mar 13, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
policy_roles_adapter.js
156 lines (132 loc) · 5.82 KB
/
policy_roles_adapter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Permissions} from 'mattermost-redux/constants/index';
const MAPPING = {
enableTeamCreation: {
true: [{roleName: 'system_user', permission: Permissions.CREATE_TEAM, shouldHave: true}],
false: [{roleName: 'system_user', permission: Permissions.CREATE_TEAM, shouldHave: false}],
},
editOthersPosts: {
true: [
{roleName: 'system_admin', permission: Permissions.EDIT_OTHERS_POSTS, shouldHave: true},
{roleName: 'team_admin', permission: Permissions.EDIT_OTHERS_POSTS, shouldHave: true},
],
false: [
{roleName: 'team_admin', permission: Permissions.EDIT_OTHERS_POSTS, shouldHave: false},
{roleName: 'system_admin', permission: Permissions.EDIT_OTHERS_POSTS, shouldHave: true},
],
},
enableOnlyAdminIntegrations: {
true: [
{roleName: 'team_user', permission: Permissions.MANAGE_INCOMING_WEBHOOKS, shouldHave: false},
{roleName: 'team_user', permission: Permissions.MANAGE_OUTGOING_WEBHOOKS, shouldHave: false},
{roleName: 'team_user', permission: Permissions.MANAGE_SLASH_COMMANDS, shouldHave: false},
{roleName: 'system_user', permission: Permissions.MANAGE_OAUTH, shouldHave: false},
],
false: [
{roleName: 'team_user', permission: Permissions.MANAGE_INCOMING_WEBHOOKS, shouldHave: true},
{roleName: 'team_user', permission: Permissions.MANAGE_OUTGOING_WEBHOOKS, shouldHave: true},
{roleName: 'team_user', permission: Permissions.MANAGE_SLASH_COMMANDS, shouldHave: true},
{roleName: 'system_user', permission: Permissions.MANAGE_OAUTH, shouldHave: true},
],
},
};
/**
* Get the roles that were changed (but unsaved) for given mapping key/values.
*
* @param {object} mappingValues key/value to indicate which mapping items to use to update the roles.
* @param {object} roles same structure as returned by mattermost-redux `getRoles`.
* @return {object} the updated roles (only) in the same structure as returned by mattermost-redux `getRoles`.
*/
export function rolesFromMapping(mappingValues, roles) {
const rolesClone = JSON.parse(JSON.stringify(roles));
// Purge roles that aren't present in MAPPING, we don't care about them.
purgeNonPertinentRoles(rolesClone);
Object.keys(MAPPING).forEach((mappingKey) => {
const value = mappingValues[mappingKey];
if (value) {
mutateRolesBasedOnMapping(mappingKey, value, rolesClone);
}
});
// Purge roles that didn't have permissions changes, we don't care about them.
Object.entries(rolesClone).forEach(([roleName, roleClone]) => {
const originalPermissionSet = new Set(roles[roleName].permissions);
const newPermissionSet = new Set(roleClone.permissions);
const difference = [...newPermissionSet].filter((x) => !originalPermissionSet.has(x));
if (originalPermissionSet.size === newPermissionSet.size && difference.length === 0) {
delete rolesClone[roleName];
}
});
return rolesClone;
}
/**
* Get the mapping value that matches for a given set of roles.
*
* @param {string} key to match under in the mapping.
* @param {object} roles same structure as returned by mattermost-redux `getRoles`.
* @return {string} the value that the roles/permissions assignment match in the mapping.
*/
export function mappingValueFromRoles(key, roles) {
for (const o of mappingPartIterator(MAPPING[key], roles)) {
if (o.allConditionsAreMet) {
return o.value;
}
}
throw new Error(`No matching mapping value found for key '${key}' with the given roles.`);
}
function purgeNonPertinentRoles(roles) {
const pertinentRoleNames = roleNamesInMapping();
Object.keys(roles).forEach((key) => {
if (!pertinentRoleNames.includes(key)) {
delete roles[key];
}
});
}
function mutateRolesBasedOnMapping(mappingKey, value, roles) {
const roleRules = MAPPING[mappingKey][value];
if (typeof roleRules === 'undefined') {
throw new Error(`Value '${value}' not present in MAPPING for key '${mappingKey}'.`);
}
roleRules.forEach((item) => {
const role = roles[item.roleName];
if (item.shouldHave) {
addPermissionToRole(item.permission, role);
} else {
removePermissionFromRole(item.permission, role);
}
});
}
// Returns a set of the role names present in MAPPING.
function roleNamesInMapping() {
let roleNames = [];
Object.values(MAPPING).forEach((v1) => {
Object.values(v1).forEach((v2) => {
const names = v2.map((item) => item.roleName); // eslint-disable-line max-nested-callbacks
roleNames = roleNames.concat(names);
});
});
return [...new Set(roleNames.map((item) => item))];
}
function* mappingPartIterator(mappingPart, roles) {
for (const value in mappingPart) {
if (mappingPart.hasOwnProperty(value)) {
const roleRules = mappingPart[value];
const hasUnmetCondition = roleRules.some((item) => {
const role = roles[item.roleName];
return (item.shouldHave && !role.permissions.includes(item.permission)) || (!item.shouldHave && role.permissions.includes(item.permission));
});
yield {value, allConditionsAreMet: !hasUnmetCondition};
}
}
}
function addPermissionToRole(permission, role) {
if (!role.permissions.includes(permission)) {
role.permissions.push(permission);
}
}
function removePermissionFromRole(permission, role) {
const permissionIndex = role.permissions.indexOf(permission);
if (permissionIndex !== -1) {
role.permissions.splice(permissionIndex, 1);
}
}