1
0

role.e2e-spec.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. /* eslint-disable @typescript-eslint/no-non-null-assertion */
  2. import { omit } from '@vendure/common/lib/omit';
  3. import {
  4. CUSTOMER_ROLE_CODE,
  5. DEFAULT_CHANNEL_CODE,
  6. SUPER_ADMIN_ROLE_CODE,
  7. } from '@vendure/common/lib/shared-constants';
  8. import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN } from '@vendure/testing';
  9. import gql from 'graphql-tag';
  10. import path from 'path';
  11. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  12. import { initialData } from '../../../e2e-common/e2e-initial-data';
  13. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  14. import { ROLE_FRAGMENT } from './graphql/fragments';
  15. import * as Codegen from './graphql/generated-e2e-admin-types';
  16. import { CurrencyCode, DeletionResult, LanguageCode, Permission } from './graphql/generated-e2e-admin-types';
  17. import {
  18. CREATE_ADMINISTRATOR,
  19. CREATE_CHANNEL,
  20. CREATE_ROLE,
  21. GET_CHANNELS,
  22. UPDATE_ADMINISTRATOR,
  23. UPDATE_ROLE,
  24. } from './graphql/shared-definitions';
  25. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  26. import { sortById } from './utils/test-order-utils';
  27. describe('Role resolver', () => {
  28. const { server, adminClient } = createTestEnvironment(testConfig());
  29. let createdRole: Codegen.RoleFragment;
  30. let defaultRoles: Codegen.RoleFragment[];
  31. beforeAll(async () => {
  32. await server.init({
  33. initialData,
  34. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  35. customerCount: 1,
  36. });
  37. await adminClient.asSuperAdmin();
  38. }, TEST_SETUP_TIMEOUT_MS);
  39. afterAll(async () => {
  40. await server.destroy();
  41. });
  42. it('roles', async () => {
  43. const result = await adminClient.query<Codegen.GetRolesQuery, Codegen.GetRolesQueryVariables>(
  44. GET_ROLES,
  45. );
  46. defaultRoles = result.roles.items;
  47. expect(result.roles.items.length).toBe(2);
  48. expect(result.roles.totalItems).toBe(2);
  49. });
  50. it('createRole with invalid permission', async () => {
  51. try {
  52. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  53. CREATE_ROLE,
  54. {
  55. input: {
  56. code: 'test',
  57. description: 'test role',
  58. permissions: ['ReadCatalogx' as any],
  59. },
  60. },
  61. );
  62. fail('Should have thrown');
  63. } catch (e: any) {
  64. expect(e.response.errors[0]?.extensions.code).toBe('BAD_USER_INPUT');
  65. }
  66. });
  67. it('createRole with no permissions includes Authenticated', async () => {
  68. const { createRole } = await adminClient.query<
  69. Codegen.CreateRoleMutation,
  70. Codegen.CreateRoleMutationVariables
  71. >(CREATE_ROLE, {
  72. input: {
  73. code: 'test',
  74. description: 'test role',
  75. permissions: [],
  76. },
  77. });
  78. expect(omit(createRole, ['channels'])).toEqual({
  79. code: 'test',
  80. description: 'test role',
  81. id: 'T_3',
  82. permissions: [Permission.Authenticated],
  83. });
  84. });
  85. it('createRole deduplicates permissions', async () => {
  86. const { createRole } = await adminClient.query<
  87. Codegen.CreateRoleMutation,
  88. Codegen.CreateRoleMutationVariables
  89. >(CREATE_ROLE, {
  90. input: {
  91. code: 'test2',
  92. description: 'test role2',
  93. permissions: [Permission.ReadSettings, Permission.ReadSettings],
  94. },
  95. });
  96. expect(omit(createRole, ['channels'])).toEqual({
  97. code: 'test2',
  98. description: 'test role2',
  99. id: 'T_4',
  100. permissions: [Permission.Authenticated, Permission.ReadSettings],
  101. });
  102. });
  103. it('createRole with permissions', async () => {
  104. const result = await adminClient.query<
  105. Codegen.CreateRoleMutation,
  106. Codegen.CreateRoleMutationVariables
  107. >(CREATE_ROLE, {
  108. input: {
  109. code: 'test',
  110. description: 'test role',
  111. permissions: [Permission.ReadCustomer, Permission.UpdateCustomer],
  112. },
  113. });
  114. createdRole = result.createRole;
  115. expect(createdRole).toEqual({
  116. code: 'test',
  117. description: 'test role',
  118. id: 'T_5',
  119. permissions: [Permission.Authenticated, Permission.ReadCustomer, Permission.UpdateCustomer],
  120. channels: [
  121. {
  122. code: DEFAULT_CHANNEL_CODE,
  123. id: 'T_1',
  124. token: 'e2e-default-channel',
  125. },
  126. ],
  127. });
  128. });
  129. it('role', async () => {
  130. const result = await adminClient.query<Codegen.GetRoleQuery, Codegen.GetRoleQueryVariables>(
  131. GET_ROLE,
  132. {
  133. id: createdRole.id,
  134. },
  135. );
  136. expect(result.role).toEqual(createdRole);
  137. });
  138. describe('updateRole', () => {
  139. it('updates role', async () => {
  140. const result = await adminClient.query<
  141. Codegen.UpdateRoleMutation,
  142. Codegen.UpdateRoleMutationVariables
  143. >(UPDATE_ROLE, {
  144. input: {
  145. id: createdRole.id,
  146. code: 'test-modified',
  147. description: 'test role modified',
  148. permissions: [
  149. Permission.ReadCustomer,
  150. Permission.UpdateCustomer,
  151. Permission.DeleteCustomer,
  152. ],
  153. },
  154. });
  155. expect(omit(result.updateRole, ['channels'])).toEqual({
  156. code: 'test-modified',
  157. description: 'test role modified',
  158. id: 'T_5',
  159. permissions: [
  160. Permission.Authenticated,
  161. Permission.ReadCustomer,
  162. Permission.UpdateCustomer,
  163. Permission.DeleteCustomer,
  164. ],
  165. });
  166. });
  167. it('works with partial input', async () => {
  168. const result = await adminClient.query<
  169. Codegen.UpdateRoleMutation,
  170. Codegen.UpdateRoleMutationVariables
  171. >(UPDATE_ROLE, {
  172. input: {
  173. id: createdRole.id,
  174. code: 'test-modified-again',
  175. },
  176. });
  177. expect(result.updateRole.code).toBe('test-modified-again');
  178. expect(result.updateRole.description).toBe('test role modified');
  179. expect(result.updateRole.permissions).toEqual([
  180. Permission.Authenticated,
  181. Permission.ReadCustomer,
  182. Permission.UpdateCustomer,
  183. Permission.DeleteCustomer,
  184. ]);
  185. });
  186. it('deduplicates permissions', async () => {
  187. const result = await adminClient.query<
  188. Codegen.UpdateRoleMutation,
  189. Codegen.UpdateRoleMutationVariables
  190. >(UPDATE_ROLE, {
  191. input: {
  192. id: createdRole.id,
  193. permissions: [
  194. Permission.Authenticated,
  195. Permission.Authenticated,
  196. Permission.ReadCustomer,
  197. Permission.ReadCustomer,
  198. ],
  199. },
  200. });
  201. expect(result.updateRole.permissions).toEqual([
  202. Permission.Authenticated,
  203. Permission.ReadCustomer,
  204. ]);
  205. });
  206. it(
  207. 'does not allow setting non-assignable permissions - Owner',
  208. assertThrowsWithMessage(async () => {
  209. await adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  210. UPDATE_ROLE,
  211. {
  212. input: {
  213. id: createdRole.id,
  214. permissions: [Permission.Owner],
  215. },
  216. },
  217. );
  218. }, 'The permission "Owner" may not be assigned'),
  219. );
  220. it(
  221. 'does not allow setting non-assignable permissions - Public',
  222. assertThrowsWithMessage(async () => {
  223. await adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  224. UPDATE_ROLE,
  225. {
  226. input: {
  227. id: createdRole.id,
  228. permissions: [Permission.Public],
  229. },
  230. },
  231. );
  232. }, 'The permission "Public" may not be assigned'),
  233. );
  234. it(
  235. 'does not allow setting SuperAdmin permission',
  236. assertThrowsWithMessage(async () => {
  237. await adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  238. UPDATE_ROLE,
  239. {
  240. input: {
  241. id: createdRole.id,
  242. permissions: [Permission.SuperAdmin],
  243. },
  244. },
  245. );
  246. }, 'The permission "SuperAdmin" may not be assigned'),
  247. );
  248. it(
  249. 'is not allowed for SuperAdmin role',
  250. assertThrowsWithMessage(async () => {
  251. const superAdminRole = defaultRoles.find(r => r.code === SUPER_ADMIN_ROLE_CODE);
  252. if (!superAdminRole) {
  253. fail('Could not find SuperAdmin role');
  254. return;
  255. }
  256. return adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  257. UPDATE_ROLE,
  258. {
  259. input: {
  260. id: superAdminRole.id,
  261. code: 'superadmin-modified',
  262. description: 'superadmin modified',
  263. permissions: [Permission.Authenticated],
  264. },
  265. },
  266. );
  267. }, `The role "${SUPER_ADMIN_ROLE_CODE}" cannot be modified`),
  268. );
  269. it(
  270. 'is not allowed for Customer role',
  271. assertThrowsWithMessage(async () => {
  272. const customerRole = defaultRoles.find(r => r.code === CUSTOMER_ROLE_CODE);
  273. if (!customerRole) {
  274. fail('Could not find Customer role');
  275. return;
  276. }
  277. return adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  278. UPDATE_ROLE,
  279. {
  280. input: {
  281. id: customerRole.id,
  282. code: 'customer-modified',
  283. description: 'customer modified',
  284. permissions: [Permission.Authenticated, Permission.DeleteAdministrator],
  285. },
  286. },
  287. );
  288. }, `The role "${CUSTOMER_ROLE_CODE}" cannot be modified`),
  289. );
  290. });
  291. it(
  292. 'deleteRole is not allowed for Customer role',
  293. assertThrowsWithMessage(async () => {
  294. const customerRole = defaultRoles.find(r => r.code === CUSTOMER_ROLE_CODE);
  295. if (!customerRole) {
  296. fail('Could not find Customer role');
  297. return;
  298. }
  299. return adminClient.query<Codegen.DeleteRoleMutation, Codegen.DeleteRoleMutationVariables>(
  300. DELETE_ROLE,
  301. {
  302. id: customerRole.id,
  303. },
  304. );
  305. }, `The role "${CUSTOMER_ROLE_CODE}" cannot be deleted`),
  306. );
  307. it(
  308. 'deleteRole is not allowed for SuperAdmin role',
  309. assertThrowsWithMessage(async () => {
  310. const superAdminRole = defaultRoles.find(r => r.code === SUPER_ADMIN_ROLE_CODE);
  311. if (!superAdminRole) {
  312. fail('Could not find Customer role');
  313. return;
  314. }
  315. return adminClient.query<Codegen.DeleteRoleMutation, Codegen.DeleteRoleMutationVariables>(
  316. DELETE_ROLE,
  317. {
  318. id: superAdminRole.id,
  319. },
  320. );
  321. }, `The role "${SUPER_ADMIN_ROLE_CODE}" cannot be deleted`),
  322. );
  323. it('deleteRole deletes a role', async () => {
  324. const { deleteRole } = await adminClient.query<
  325. Codegen.DeleteRoleMutation,
  326. Codegen.DeleteRoleMutationVariables
  327. >(DELETE_ROLE, {
  328. id: createdRole.id,
  329. });
  330. expect(deleteRole.result).toBe(DeletionResult.DELETED);
  331. const { role } = await adminClient.query<Codegen.GetRoleQuery, Codegen.GetRoleQueryVariables>(
  332. GET_ROLE,
  333. {
  334. id: createdRole.id,
  335. },
  336. );
  337. expect(role).toBeNull();
  338. });
  339. describe('multi-channel', () => {
  340. let secondChannel: Codegen.ChannelFragment;
  341. let multiChannelRole: Codegen.CreateRoleMutation['createRole'];
  342. beforeAll(async () => {
  343. const { createChannel } = await adminClient.query<
  344. Codegen.CreateChannelMutation,
  345. Codegen.CreateChannelMutationVariables
  346. >(CREATE_CHANNEL, {
  347. input: {
  348. code: 'second-channel',
  349. token: 'second-channel-token',
  350. defaultLanguageCode: LanguageCode.en,
  351. currencyCode: CurrencyCode.GBP,
  352. pricesIncludeTax: true,
  353. defaultShippingZoneId: 'T_1',
  354. defaultTaxZoneId: 'T_1',
  355. },
  356. });
  357. secondChannel = createChannel as any;
  358. });
  359. it('createRole with specified channel', async () => {
  360. const result = await adminClient.query<
  361. Codegen.CreateRoleMutation,
  362. Codegen.CreateRoleMutationVariables
  363. >(CREATE_ROLE, {
  364. input: {
  365. code: 'multi-test',
  366. description: 'multi channel test role',
  367. permissions: [Permission.ReadCustomer],
  368. channelIds: [secondChannel.id],
  369. },
  370. });
  371. multiChannelRole = result.createRole;
  372. expect(multiChannelRole).toEqual({
  373. code: 'multi-test',
  374. description: 'multi channel test role',
  375. id: 'T_6',
  376. permissions: [Permission.Authenticated, Permission.ReadCustomer],
  377. channels: [
  378. {
  379. code: 'second-channel',
  380. id: 'T_2',
  381. token: 'second-channel-token',
  382. },
  383. ],
  384. });
  385. });
  386. it('updateRole with specified channel', async () => {
  387. const { updateRole } = await adminClient.query<
  388. Codegen.UpdateRoleMutation,
  389. Codegen.UpdateRoleMutationVariables
  390. >(UPDATE_ROLE, {
  391. input: {
  392. id: multiChannelRole.id,
  393. channelIds: ['T_1', 'T_2'],
  394. },
  395. });
  396. expect(updateRole.channels.sort(sortById)).toEqual([
  397. {
  398. code: DEFAULT_CHANNEL_CODE,
  399. id: 'T_1',
  400. token: 'e2e-default-channel',
  401. },
  402. {
  403. code: 'second-channel',
  404. id: 'T_2',
  405. token: 'second-channel-token',
  406. },
  407. ]);
  408. });
  409. });
  410. // https://github.com/vendurehq/vendure/issues/1874
  411. describe('role escalation', () => {
  412. let defaultChannel: Codegen.GetChannelsQuery['channels']['items'][number];
  413. let secondChannel: Codegen.GetChannelsQuery['channels']['items'][number];
  414. let limitedAdmin: Codegen.CreateAdministratorMutation['createAdministrator'];
  415. let orderReaderRole: Codegen.CreateRoleMutation['createRole'];
  416. let adminCreatorRole: Codegen.CreateRoleMutation['createRole'];
  417. let adminCreatorAdministrator: Codegen.CreateAdministratorMutation['createAdministrator'];
  418. beforeAll(async () => {
  419. const { channels } = await adminClient.query<Codegen.GetChannelsQuery>(GET_CHANNELS);
  420. defaultChannel = channels.items.find(c => c.token === E2E_DEFAULT_CHANNEL_TOKEN)!;
  421. secondChannel = channels.items.find(c => c.token !== E2E_DEFAULT_CHANNEL_TOKEN)!;
  422. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  423. await adminClient.asSuperAdmin();
  424. const { createRole } = await adminClient.query<
  425. Codegen.CreateRoleMutation,
  426. Codegen.CreateRoleMutationVariables
  427. >(CREATE_ROLE, {
  428. input: {
  429. code: 'second-channel-admin-manager',
  430. description: '',
  431. channelIds: [secondChannel.id],
  432. permissions: [
  433. Permission.CreateAdministrator,
  434. Permission.ReadAdministrator,
  435. Permission.UpdateAdministrator,
  436. Permission.DeleteAdministrator,
  437. ],
  438. },
  439. });
  440. const { createAdministrator } = await adminClient.query<
  441. Codegen.CreateAdministratorMutation,
  442. Codegen.CreateAdministratorMutationVariables
  443. >(CREATE_ADMINISTRATOR, {
  444. input: {
  445. firstName: 'channel2',
  446. lastName: 'admin manager',
  447. emailAddress: 'channel2@test.com',
  448. roleIds: [createRole.id],
  449. password: 'test',
  450. },
  451. });
  452. limitedAdmin = createAdministrator;
  453. const { createRole: createRole2 } = await adminClient.query<
  454. Codegen.CreateRoleMutation,
  455. Codegen.CreateRoleMutationVariables
  456. >(CREATE_ROLE, {
  457. input: {
  458. code: 'second-channel-order-manager',
  459. description: '',
  460. channelIds: [secondChannel.id],
  461. permissions: [Permission.ReadOrder],
  462. },
  463. });
  464. orderReaderRole = createRole2;
  465. adminClient.setChannelToken(secondChannel.token);
  466. await adminClient.asUserWithCredentials(limitedAdmin.emailAddress, 'test');
  467. });
  468. it('limited admin cannot view Roles which require permissions they do not have', async () => {
  469. const result = await adminClient.query<Codegen.GetRolesQuery, Codegen.GetRolesQueryVariables>(
  470. GET_ROLES,
  471. );
  472. const roleCodes = result.roles.items.map(r => r.code);
  473. expect(roleCodes).toEqual(['second-channel-admin-manager']);
  474. });
  475. it('limited admin cannot view Role which requires permissions they do not have', async () => {
  476. const result = await adminClient.query<Codegen.GetRoleQuery, Codegen.GetRoleQueryVariables>(
  477. GET_ROLE,
  478. { id: orderReaderRole.id },
  479. );
  480. expect(result.role).toBeNull();
  481. });
  482. it(
  483. 'limited admin cannot create Role with SuperAdmin permission',
  484. assertThrowsWithMessage(async () => {
  485. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  486. CREATE_ROLE,
  487. {
  488. input: {
  489. code: 'evil-superadmin',
  490. description: '',
  491. channelIds: [secondChannel.id],
  492. permissions: [Permission.SuperAdmin],
  493. },
  494. },
  495. );
  496. }, 'The permission "SuperAdmin" may not be assigned'),
  497. );
  498. it(
  499. 'limited admin cannot create Administrator with SuperAdmin role',
  500. assertThrowsWithMessage(async () => {
  501. const superAdminRole = defaultRoles.find(r => r.code === SUPER_ADMIN_ROLE_CODE)!;
  502. await adminClient.query<
  503. Codegen.CreateAdministratorMutation,
  504. Codegen.CreateAdministratorMutationVariables
  505. >(CREATE_ADMINISTRATOR, {
  506. input: {
  507. firstName: 'Dr',
  508. lastName: 'Evil',
  509. emailAddress: 'drevil@test.com',
  510. roleIds: [superAdminRole.id],
  511. password: 'test',
  512. },
  513. });
  514. }, 'Active user does not have sufficient permissions'),
  515. );
  516. it(
  517. 'limited admin cannot create Role with permissions it itself does not have',
  518. assertThrowsWithMessage(async () => {
  519. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  520. CREATE_ROLE,
  521. {
  522. input: {
  523. code: 'evil-order-manager',
  524. description: '',
  525. channelIds: [secondChannel.id],
  526. permissions: [Permission.ReadOrder],
  527. },
  528. },
  529. );
  530. }, 'Active user does not have sufficient permissions'),
  531. );
  532. it(
  533. 'limited admin cannot create Role on channel it does not have permissions on',
  534. assertThrowsWithMessage(async () => {
  535. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  536. CREATE_ROLE,
  537. {
  538. input: {
  539. code: 'evil-order-manager',
  540. description: '',
  541. channelIds: [defaultChannel.id],
  542. permissions: [Permission.CreateAdministrator],
  543. },
  544. },
  545. );
  546. }, 'You are not currently authorized to perform this action'),
  547. );
  548. it(
  549. 'limited admin cannot create Administrator with a Role with greater permissions than they themselves have',
  550. assertThrowsWithMessage(async () => {
  551. await adminClient.query<
  552. Codegen.CreateAdministratorMutation,
  553. Codegen.CreateAdministratorMutationVariables
  554. >(CREATE_ADMINISTRATOR, {
  555. input: {
  556. firstName: 'Dr',
  557. lastName: 'Evil',
  558. emailAddress: 'drevil@test.com',
  559. roleIds: [orderReaderRole.id],
  560. password: 'test',
  561. },
  562. });
  563. }, 'Active user does not have sufficient permissions'),
  564. );
  565. it('limited admin can create Role with permissions it itself has', async () => {
  566. const { createRole } = await adminClient.query<
  567. Codegen.CreateRoleMutation,
  568. Codegen.CreateRoleMutationVariables
  569. >(CREATE_ROLE, {
  570. input: {
  571. code: 'good-admin-creator',
  572. description: '',
  573. channelIds: [secondChannel.id],
  574. permissions: [Permission.CreateAdministrator],
  575. },
  576. });
  577. expect(createRole.code).toBe('good-admin-creator');
  578. adminCreatorRole = createRole;
  579. });
  580. it('limited admin can create Administrator with permissions it itself has', async () => {
  581. const { createAdministrator } = await adminClient.query<
  582. Codegen.CreateAdministratorMutation,
  583. Codegen.CreateAdministratorMutationVariables
  584. >(CREATE_ADMINISTRATOR, {
  585. input: {
  586. firstName: 'Admin',
  587. lastName: 'Creator',
  588. emailAddress: 'admincreator@test.com',
  589. roleIds: [adminCreatorRole.id],
  590. password: 'test',
  591. },
  592. });
  593. expect(createAdministrator.emailAddress).toBe('admincreator@test.com');
  594. adminCreatorAdministrator = createAdministrator;
  595. });
  596. it(
  597. 'limited admin cannot update Role with permissions it itself lacks',
  598. assertThrowsWithMessage(async () => {
  599. await adminClient.query<Codegen.UpdateRoleMutation, Codegen.UpdateRoleMutationVariables>(
  600. UPDATE_ROLE,
  601. {
  602. input: {
  603. id: adminCreatorRole.id,
  604. permissions: [Permission.ReadOrder],
  605. },
  606. },
  607. );
  608. }, 'Active user does not have sufficient permissions'),
  609. );
  610. it(
  611. 'limited admin cannot update Administrator with Role containing permissions it itself lacks',
  612. assertThrowsWithMessage(async () => {
  613. await adminClient.query<
  614. Codegen.UpdateAdministratorMutation,
  615. Codegen.UpdateAdministratorMutationVariables
  616. >(UPDATE_ADMINISTRATOR, {
  617. input: {
  618. id: adminCreatorAdministrator.id,
  619. roleIds: [adminCreatorRole.id, orderReaderRole.id],
  620. },
  621. });
  622. }, 'Active user does not have sufficient permissions'),
  623. );
  624. });
  625. describe('roles query', () => {
  626. let limitedChannelAdmin: Codegen.CreateAdministratorMutation['createAdministrator'];
  627. beforeAll(async () => {
  628. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  629. await adminClient.asSuperAdmin();
  630. // Create roles that will be hidden from limited admin
  631. await adminClient.query<Codegen.CreateRoleMutation, Codegen.CreateRoleMutationVariables>(
  632. CREATE_ROLE,
  633. {
  634. input: {
  635. code: 'hidden-role',
  636. description: 'Hidden role',
  637. // Some permission the limited admin user doesn't have, so the role is hidden
  638. permissions: [Permission.ReadOrder],
  639. },
  640. },
  641. );
  642. // Create a role to assign to the limited admin user
  643. const visibleRole = await adminClient.query<
  644. Codegen.CreateRoleMutation,
  645. Codegen.CreateRoleMutationVariables
  646. >(CREATE_ROLE, {
  647. input: {
  648. code: 'visible-role',
  649. description: 'Visible role',
  650. permissions: [Permission.ReadAdministrator],
  651. },
  652. });
  653. const { createAdministrator } = await adminClient.query<
  654. Codegen.CreateAdministratorMutation,
  655. Codegen.CreateAdministratorMutationVariables
  656. >(CREATE_ADMINISTRATOR, {
  657. input: {
  658. firstName: 'Limited',
  659. lastName: 'Admin',
  660. emailAddress: 'limited@test.com',
  661. roleIds: [visibleRole.createRole.id],
  662. password: 'test',
  663. },
  664. });
  665. limitedChannelAdmin = createAdministrator;
  666. });
  667. it('should return only visible roles with correct pagination', async () => {
  668. // Login as limited admin
  669. await adminClient.asUserWithCredentials(limitedChannelAdmin.emailAddress, 'test');
  670. // Query first page with pagination, sorted by createdAt ASC
  671. const result = await adminClient.query<Codegen.GetRolesQuery, Codegen.GetRolesQueryVariables>(
  672. GET_ROLES,
  673. {
  674. options: {
  675. take: 2,
  676. },
  677. },
  678. );
  679. // Should have at least visible role and test role created earlier
  680. expect(result.roles.items).toHaveLength(2);
  681. expect(result.roles.totalItems).toBe(2);
  682. // The returned role should be one that the limited admin can see
  683. const roleCodes = result.roles.items.map(r => r.code);
  684. expect(roleCodes).toContain('visible-role');
  685. expect(roleCodes).not.toContain('hidden-role');
  686. });
  687. afterAll(async () => {
  688. await adminClient.asSuperAdmin();
  689. });
  690. });
  691. });
  692. export const GET_ROLES = gql`
  693. query GetRoles($options: RoleListOptions) {
  694. roles(options: $options) {
  695. items {
  696. ...Role
  697. }
  698. totalItems
  699. }
  700. }
  701. ${ROLE_FRAGMENT}
  702. `;
  703. export const GET_ROLE = gql`
  704. query GetRole($id: ID!) {
  705. role(id: $id) {
  706. ...Role
  707. }
  708. }
  709. ${ROLE_FRAGMENT}
  710. `;
  711. export const DELETE_ROLE = gql`
  712. mutation DeleteRole($id: ID!) {
  713. deleteRole(id: $id) {
  714. result
  715. message
  716. }
  717. }
  718. `;