@lightdash/common 0.1369.3 → 0.1370.0
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/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) => {
|