@lightdash/common 0.1369.3 → 0.1370.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/authorization/index.d.ts +8 -1
- package/dist/authorization/index.js +23 -7
- package/dist/authorization/organizationMemberAbility.d.ts +12 -1
- package/dist/authorization/organizationMemberAbility.js +24 -8
- package/dist/authorization/organizationMemberAbility.test.js +54 -3
- package/dist/authorization/types.d.ts +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/types/organizationMemberProfile.d.ts +1 -0
- package/dist/types/organizationMemberProfile.js +3 -1
- package/package.json +1 -1
@@ -1,6 +1,13 @@
|
|
1
1
|
import { AbilityBuilder } from '@casl/ability';
|
2
2
|
import { type ProjectMemberProfile } from '../types/projectMemberProfile';
|
3
3
|
import { type LightdashUser } from '../types/user';
|
4
|
+
import { type OrganizationMemberAbilitiesArgs } from './organizationMemberAbility';
|
4
5
|
import { type MemberAbility } from './types';
|
5
|
-
|
6
|
+
type UserAbilityBuilderArgs = {
|
7
|
+
user: Pick<LightdashUser, 'role' | 'organizationUuid' | 'userUuid'>;
|
8
|
+
projectProfiles: Pick<ProjectMemberProfile, 'projectUuid' | 'role' | 'userUuid'>[];
|
9
|
+
permissionsConfig: OrganizationMemberAbilitiesArgs['permissionsConfig'];
|
10
|
+
};
|
11
|
+
export declare const getUserAbilityBuilder: ({ user, projectProfiles, permissionsConfig, }: UserAbilityBuilderArgs) => AbilityBuilder<MemberAbility>;
|
6
12
|
export declare const defineUserAbility: (user: Pick<LightdashUser, 'role' | 'organizationUuid' | 'userUuid'>, projectProfiles: Pick<ProjectMemberProfile, 'projectUuid' | 'role' | 'userUuid'>[]) => MemberAbility;
|
13
|
+
export {};
|
@@ -1,16 +1,22 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.defineUserAbility = exports.getUserAbilityBuilder = void 0;
|
4
|
+
const tslib_1 = require("tslib");
|
4
5
|
const ability_1 = require("@casl/ability");
|
5
|
-
const organizationMemberAbility_1 = require("./organizationMemberAbility");
|
6
|
+
const organizationMemberAbility_1 = tslib_1.__importDefault(require("./organizationMemberAbility"));
|
6
7
|
const projectMemberAbility_1 = require("./projectMemberAbility");
|
7
|
-
const getUserAbilityBuilder = (user, projectProfiles) => {
|
8
|
+
const getUserAbilityBuilder = ({ user, projectProfiles, permissionsConfig, }) => {
|
8
9
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
9
10
|
if (user.role && user.organizationUuid) {
|
10
|
-
organizationMemberAbility_1.
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
(0, organizationMemberAbility_1.default)({
|
12
|
+
role: user.role,
|
13
|
+
member: {
|
14
|
+
organizationUuid: user.organizationUuid,
|
15
|
+
userUuid: user.userUuid,
|
16
|
+
},
|
17
|
+
builder,
|
18
|
+
permissionsConfig,
|
19
|
+
});
|
14
20
|
projectProfiles.forEach((projectProfile) => {
|
15
21
|
projectMemberAbility_1.projectMemberAbilities[projectProfile.role](projectProfile, builder);
|
16
22
|
});
|
@@ -18,8 +24,18 @@ const getUserAbilityBuilder = (user, projectProfiles) => {
|
|
18
24
|
return builder;
|
19
25
|
};
|
20
26
|
exports.getUserAbilityBuilder = getUserAbilityBuilder;
|
27
|
+
// Defines user ability for test purposes
|
21
28
|
const defineUserAbility = (user, projectProfiles) => {
|
22
|
-
const builder = (0, exports.getUserAbilityBuilder)(
|
29
|
+
const builder = (0, exports.getUserAbilityBuilder)({
|
30
|
+
user,
|
31
|
+
projectProfiles,
|
32
|
+
permissionsConfig: {
|
33
|
+
pat: {
|
34
|
+
enabled: false,
|
35
|
+
allowedOrgRoles: [],
|
36
|
+
},
|
37
|
+
},
|
38
|
+
});
|
23
39
|
return builder.build();
|
24
40
|
};
|
25
41
|
exports.defineUserAbility = defineUserAbility;
|
@@ -1,4 +1,15 @@
|
|
1
1
|
import { type AbilityBuilder } from '@casl/ability';
|
2
2
|
import { type OrganizationMemberProfile, type OrganizationMemberRole } from '../types/organizationMemberProfile';
|
3
3
|
import { type MemberAbility } from './types';
|
4
|
-
export
|
4
|
+
export type OrganizationMemberAbilitiesArgs = {
|
5
|
+
role: OrganizationMemberRole;
|
6
|
+
member: Pick<OrganizationMemberProfile, 'organizationUuid' | 'userUuid'>;
|
7
|
+
builder: Pick<AbilityBuilder<MemberAbility>, 'can'>;
|
8
|
+
permissionsConfig: {
|
9
|
+
pat: {
|
10
|
+
enabled: boolean;
|
11
|
+
allowedOrgRoles: OrganizationMemberRole[];
|
12
|
+
};
|
13
|
+
};
|
14
|
+
};
|
15
|
+
export default function applyOrganizationMemberAbilities({ role, member, builder, permissionsConfig, }: OrganizationMemberAbilitiesArgs): void;
|
@@ -1,10 +1,14 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.organizationMemberAbilities = void 0;
|
4
3
|
const projects_1 = require("../types/projects");
|
5
4
|
const space_1 = require("../types/space");
|
6
|
-
|
7
|
-
|
5
|
+
const applyOrganizationMemberDynamicAbilities = ({ role, builder: { can }, permissionsConfig, }) => {
|
6
|
+
if (permissionsConfig.pat.enabled &&
|
7
|
+
permissionsConfig.pat.allowedOrgRoles.includes(role)) {
|
8
|
+
can('manage', 'PersonalAccessToken', {});
|
9
|
+
}
|
10
|
+
};
|
11
|
+
const applyOrganizationMemberStaticAbilities = {
|
8
12
|
member(member, { can }) {
|
9
13
|
can('view', 'OrganizationMemberProfile', {
|
10
14
|
organizationUuid: member.organizationUuid,
|
@@ -17,7 +21,7 @@ exports.organizationMemberAbilities = {
|
|
17
21
|
});
|
18
22
|
},
|
19
23
|
viewer(member, { can }) {
|
20
|
-
|
24
|
+
applyOrganizationMemberStaticAbilities.member(member, { can });
|
21
25
|
can('view', 'Dashboard', {
|
22
26
|
organizationUuid: member.organizationUuid,
|
23
27
|
isPrivate: false,
|
@@ -65,7 +69,7 @@ exports.organizationMemberAbilities = {
|
|
65
69
|
});
|
66
70
|
},
|
67
71
|
interactive_viewer(member, { can }) {
|
68
|
-
|
72
|
+
applyOrganizationMemberStaticAbilities.viewer(member, { can });
|
69
73
|
can('create', 'Job');
|
70
74
|
can('view', 'Job', { userUuid: member.userUuid });
|
71
75
|
can('view', 'UnderlyingData', {
|
@@ -142,7 +146,9 @@ exports.organizationMemberAbilities = {
|
|
142
146
|
});
|
143
147
|
},
|
144
148
|
editor(member, { can }) {
|
145
|
-
|
149
|
+
applyOrganizationMemberStaticAbilities.interactive_viewer(member, {
|
150
|
+
can,
|
151
|
+
});
|
146
152
|
can('create', 'Space', {
|
147
153
|
organizationUuid: member.organizationUuid,
|
148
154
|
});
|
@@ -167,7 +173,7 @@ exports.organizationMemberAbilities = {
|
|
167
173
|
});
|
168
174
|
},
|
169
175
|
developer(member, { can }) {
|
170
|
-
|
176
|
+
applyOrganizationMemberStaticAbilities.editor(member, { can });
|
171
177
|
can('manage', 'VirtualView', {
|
172
178
|
organizationUuid: member.organizationUuid,
|
173
179
|
});
|
@@ -211,7 +217,7 @@ exports.organizationMemberAbilities = {
|
|
211
217
|
});
|
212
218
|
},
|
213
219
|
admin(member, { can }) {
|
214
|
-
|
220
|
+
applyOrganizationMemberStaticAbilities.developer(member, { can });
|
215
221
|
can('manage', 'Dashboard', {
|
216
222
|
organizationUuid: member.organizationUuid,
|
217
223
|
});
|
@@ -251,3 +257,13 @@ exports.organizationMemberAbilities = {
|
|
251
257
|
});
|
252
258
|
},
|
253
259
|
};
|
260
|
+
function applyOrganizationMemberAbilities({ role, member, builder, permissionsConfig, }) {
|
261
|
+
applyOrganizationMemberStaticAbilities[role](member, builder);
|
262
|
+
applyOrganizationMemberDynamicAbilities({
|
263
|
+
role,
|
264
|
+
member,
|
265
|
+
builder,
|
266
|
+
permissionsConfig,
|
267
|
+
});
|
268
|
+
}
|
269
|
+
exports.default = applyOrganizationMemberAbilities;
|
@@ -1,14 +1,26 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const tslib_1 = require("tslib");
|
3
4
|
const ability_1 = require("@casl/ability");
|
5
|
+
const organizationMemberProfile_1 = require("../types/organizationMemberProfile");
|
4
6
|
const projects_1 = require("../types/projects");
|
5
7
|
const space_1 = require("../types/space");
|
6
|
-
const organizationMemberAbility_1 = require("./organizationMemberAbility");
|
8
|
+
const organizationMemberAbility_1 = tslib_1.__importDefault(require("./organizationMemberAbility"));
|
7
9
|
const organizationMemberAbility_mock_1 = require("./organizationMemberAbility.mock");
|
8
|
-
const defineAbilityForOrganizationMember = (member) => {
|
10
|
+
const defineAbilityForOrganizationMember = (member, permissionsConfig) => {
|
9
11
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
10
12
|
if (member) {
|
11
|
-
|
13
|
+
(0, organizationMemberAbility_1.default)({
|
14
|
+
role: member.role,
|
15
|
+
member,
|
16
|
+
builder,
|
17
|
+
permissionsConfig: permissionsConfig ?? {
|
18
|
+
pat: {
|
19
|
+
enabled: true,
|
20
|
+
allowedOrgRoles: Object.values(organizationMemberProfile_1.OrganizationMemberRole),
|
21
|
+
},
|
22
|
+
},
|
23
|
+
});
|
12
24
|
}
|
13
25
|
return builder.build();
|
14
26
|
};
|
@@ -1001,4 +1013,43 @@ describe('Organization member permissions', () => {
|
|
1001
1013
|
});
|
1002
1014
|
});
|
1003
1015
|
});
|
1016
|
+
// test permissionsConfig
|
1017
|
+
describe('Personal Access Tokens permissions', () => {
|
1018
|
+
it('cannot create a personal access token as PAT is disabled', () => {
|
1019
|
+
const ability = defineAbilityForOrganizationMember(organizationMemberAbility_mock_1.ORGANIZATION_ADMIN, {
|
1020
|
+
pat: {
|
1021
|
+
enabled: false,
|
1022
|
+
allowedOrgRoles: Object.values(organizationMemberProfile_1.OrganizationMemberRole),
|
1023
|
+
},
|
1024
|
+
});
|
1025
|
+
expect(ability.can('create', (0, ability_1.subject)('PersonalAccessToken', {
|
1026
|
+
organizationUuid: organizationMemberAbility_mock_1.ORGANIZATION_ADMIN.organizationUuid,
|
1027
|
+
userUuid: organizationMemberAbility_mock_1.ORGANIZATION_ADMIN.userUuid,
|
1028
|
+
}))).toEqual(false);
|
1029
|
+
});
|
1030
|
+
it('cannot create a personal access token as PAT allowed roles dont match', () => {
|
1031
|
+
const ability = defineAbilityForOrganizationMember(organizationMemberAbility_mock_1.ORGANIZATION_DEVELOPER, {
|
1032
|
+
pat: {
|
1033
|
+
enabled: true,
|
1034
|
+
allowedOrgRoles: [organizationMemberProfile_1.OrganizationMemberRole.ADMIN],
|
1035
|
+
},
|
1036
|
+
});
|
1037
|
+
expect(ability.can('create', (0, ability_1.subject)('PersonalAccessToken', {
|
1038
|
+
organizationUuid: organizationMemberAbility_mock_1.ORGANIZATION_DEVELOPER.organizationUuid,
|
1039
|
+
userUuid: organizationMemberAbility_mock_1.ORGANIZATION_DEVELOPER.userUuid,
|
1040
|
+
}))).toEqual(false);
|
1041
|
+
});
|
1042
|
+
it('can create a personal access token as PAT is enabled', () => {
|
1043
|
+
const ability = defineAbilityForOrganizationMember(organizationMemberAbility_mock_1.ORGANIZATION_ADMIN, {
|
1044
|
+
pat: {
|
1045
|
+
enabled: true,
|
1046
|
+
allowedOrgRoles: [organizationMemberProfile_1.OrganizationMemberRole.ADMIN],
|
1047
|
+
},
|
1048
|
+
});
|
1049
|
+
expect(ability.can('create', (0, ability_1.subject)('PersonalAccessToken', {
|
1050
|
+
organizationUuid: organizationMemberAbility_mock_1.ORGANIZATION_ADMIN.organizationUuid,
|
1051
|
+
userUuid: organizationMemberAbility_mock_1.ORGANIZATION_ADMIN.userUuid,
|
1052
|
+
}))).toEqual(true);
|
1053
|
+
});
|
1054
|
+
});
|
1004
1055
|
});
|
@@ -8,7 +8,7 @@ interface Project {
|
|
8
8
|
interface Organization {
|
9
9
|
organizationUuid: string;
|
10
10
|
}
|
11
|
-
type Subject = Project | Organization | OrganizationMemberProfile | 'Project' | 'Organization' | 'OrganizationMemberProfile' | 'Dashboard' | 'Space' | 'SavedChart' | 'InviteLink' | 'Job' | 'SqlRunner' | 'Analytics' | 'Explore' | 'UnderlyingData' | 'ExportCsv' | 'CsvJobResult' | 'PinnedItems' | 'Validation' | 'Group' | 'ChangeCsvResults' | 'ScheduledDeliveries' | 'DashboardComments' | 'CustomSql' | 'CompileProject' | 'SemanticViewer' | 'VirtualView' | 'Tags' | 'all';
|
11
|
+
type Subject = Project | Organization | OrganizationMemberProfile | 'Project' | 'Organization' | 'OrganizationMemberProfile' | 'Dashboard' | 'Space' | 'SavedChart' | 'InviteLink' | 'Job' | 'SqlRunner' | 'Analytics' | 'Explore' | 'UnderlyingData' | 'ExportCsv' | 'CsvJobResult' | 'PinnedItems' | 'Validation' | 'Group' | 'ChangeCsvResults' | 'ScheduledDeliveries' | 'DashboardComments' | 'CustomSql' | 'CompileProject' | 'SemanticViewer' | 'VirtualView' | 'Tags' | 'PersonalAccessToken' | 'all';
|
12
12
|
type PossibleAbilities = [
|
13
13
|
AbilityAction,
|
14
14
|
Subject | ForcedSubject<Exclude<Subject, 'all'>>
|
package/dist/index.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.getRoleDescription = exports.isOrganizationMemberProfileWithGroups = exports.OrganizationMemberRole = void 0;
|
3
|
+
exports.getRoleDescription = exports.isOrganizationMemberProfileWithGroups = exports.isOrganizationMemberRole = exports.OrganizationMemberRole = void 0;
|
4
4
|
var OrganizationMemberRole;
|
5
5
|
(function (OrganizationMemberRole) {
|
6
6
|
OrganizationMemberRole["MEMBER"] = "member";
|
@@ -10,6 +10,8 @@ var OrganizationMemberRole;
|
|
10
10
|
OrganizationMemberRole["DEVELOPER"] = "developer";
|
11
11
|
OrganizationMemberRole["ADMIN"] = "admin";
|
12
12
|
})(OrganizationMemberRole = exports.OrganizationMemberRole || (exports.OrganizationMemberRole = {}));
|
13
|
+
const isOrganizationMemberRole = (x) => Object.values(OrganizationMemberRole).includes(x);
|
14
|
+
exports.isOrganizationMemberRole = isOrganizationMemberRole;
|
13
15
|
const isOrganizationMemberProfileWithGroups = (obj) => 'groups' in obj;
|
14
16
|
exports.isOrganizationMemberProfileWithGroups = isOrganizationMemberProfileWithGroups;
|
15
17
|
const getRoleDescription = (role) => {
|