api-key.e2e-spec.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { DeletionResult, LanguageCode } from '@vendure/common/lib/generated-types';
  2. import { SUPER_ADMIN_USER_IDENTIFIER } from '@vendure/common/lib/shared-constants';
  3. import { createTestEnvironment } from '@vendure/testing';
  4. import path from 'path';
  5. import { afterAll, beforeAll, describe, it } from 'vitest';
  6. import { initialData } from '../../../e2e-common/e2e-initial-data';
  7. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  8. import { graphql } from './graphql/graphql-admin';
  9. describe('ApiKey resolver', () => {
  10. const config = testConfig();
  11. config.authOptions.tokenMethod = ['cookie', 'bearer', 'api-key'];
  12. const { server, adminClient } = createTestEnvironment(config);
  13. const adminApiUrl = `http://localhost:${config.apiOptions.port}/${String(config.apiOptions.adminApiPath)}`;
  14. let createdApiKeyId: string;
  15. beforeAll(async () => {
  16. await server.init({
  17. initialData,
  18. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  19. customerCount: 1,
  20. });
  21. await adminClient.asSuperAdmin();
  22. }, TEST_SETUP_TIMEOUT_MS);
  23. afterAll(async () => {
  24. await server.destroy();
  25. });
  26. it('createApiKey', async ({ expect }) => {
  27. const result = await adminClient.query(CREATE_API_KEY, {
  28. input: {
  29. roleIds: ['1'],
  30. translations: [{ languageCode: LanguageCode.en, name: 'Test API Key' }],
  31. },
  32. });
  33. expect(result.createApiKey.apiKey).toBeDefined();
  34. createdApiKeyId = result.createApiKey.entityId;
  35. });
  36. it('apiKey', async ({ expect }) => {
  37. const result = await adminClient.query(API_KEY, { id: createdApiKeyId });
  38. expect(result.apiKey).toBeDefined();
  39. expect(result.apiKey?.id).toBe(createdApiKeyId);
  40. expect(result.apiKey?.name).toBe('Test API Key');
  41. expect(result.apiKey?.translations.find(t => t.languageCode === LanguageCode.en)).toBeDefined();
  42. });
  43. it('apiKeys', async ({ expect }) => {
  44. const result = await adminClient.query(API_KEYS);
  45. expect(result.apiKeys.items.length).toBeGreaterThan(0);
  46. expect(result.apiKeys.items.some((k: any) => k.id === createdApiKeyId)).toBe(true);
  47. });
  48. it('updateApiKey', async ({ expect }) => {
  49. const result = await adminClient.query(UPDATE_API_KEY, {
  50. input: {
  51. id: createdApiKeyId,
  52. // TODO roles
  53. translations: [
  54. { languageCode: LanguageCode.en, name: 'Updated API Key' },
  55. { languageCode: LanguageCode.de, name: 'Neuer Eintrag' },
  56. ],
  57. },
  58. });
  59. expect(result.updateApiKey.id).toBe(createdApiKeyId);
  60. expect(result.updateApiKey.name).toBe('Updated API Key');
  61. expect(result.updateApiKey.translations.find(t => t.languageCode === LanguageCode.de)?.name).toBe(
  62. 'Neuer Eintrag',
  63. );
  64. });
  65. it('deleteApiKey', async ({ expect }) => {
  66. const result = await adminClient.query(DELETE_API_KEY, { ids: [createdApiKeyId] });
  67. expect(result.deleteApiKeys?.[0]?.result).toBe(DeletionResult.DELETED);
  68. // Should not be found anymore
  69. const { apiKey } = await adminClient.query(API_KEY, { id: createdApiKeyId });
  70. expect(apiKey).toBeNull();
  71. });
  72. it('rotateApiKey', async ({ expect }) => {
  73. const apiKey = await adminClient.query(CREATE_API_KEY, {
  74. input: {
  75. roleIds: ['1'],
  76. translations: [{ languageCode: LanguageCode.en, name: 'Test API Key' }],
  77. },
  78. });
  79. const result = await adminClient.query(ROTATE_API_KEY, { id: apiKey.createApiKey.entityId });
  80. expect(result.rotateApiKey.apiKey).toBeDefined();
  81. expect(apiKey.createApiKey.apiKey).not.toBe(result.rotateApiKey.apiKey);
  82. });
  83. it('API-Key usage life cycle: Read, Rotate, Delete', async ({ expect }) => {
  84. const { apiKey, entityId } = (
  85. await adminClient.query(CREATE_API_KEY, {
  86. input: {
  87. roleIds: ['1'],
  88. translations: [{ languageCode: LanguageCode.en, name: 'Test API Key' }],
  89. },
  90. })
  91. ).createApiKey;
  92. type _fetchResponse =
  93. | {
  94. data?: { administrator?: { user?: { identifier?: string } } };
  95. errors?: any[];
  96. }
  97. | undefined;
  98. const fetchConfig = {
  99. method: 'POST',
  100. headers: {
  101. 'Content-Type': 'application/json',
  102. [String(config.authOptions.apiKeyHeaderKey)]: apiKey,
  103. },
  104. body: '{ "query": "query { administrator(id: 1) { user { identifier } } }" }',
  105. };
  106. // (1/4): Successfully read
  107. const readOk01 = (await fetch(adminApiUrl, fetchConfig).then(res => res.json())) as _fetchResponse;
  108. expect(readOk01?.data?.administrator?.user?.identifier).toBe(SUPER_ADMIN_USER_IDENTIFIER);
  109. // (2/4): Fail to read due to rotation of key
  110. const rotate = await adminClient.query(ROTATE_API_KEY, { id: entityId });
  111. const readErr01 = (await fetch(adminApiUrl, fetchConfig).then(res => res.json())) as _fetchResponse;
  112. expect(readErr01?.errors).toBeDefined();
  113. expect(readErr01?.data?.administrator?.user?.identifier).toBeUndefined();
  114. // (3/4): Successfully read via rotated key
  115. fetchConfig.headers[String(config.authOptions.apiKeyHeaderKey)] = rotate.rotateApiKey.apiKey;
  116. const readOk02 = (await fetch(adminApiUrl, fetchConfig).then(res => res.json())) as _fetchResponse;
  117. expect(readOk02?.data?.administrator?.user?.identifier).toBe(SUPER_ADMIN_USER_IDENTIFIER);
  118. // (4/4): Fail to read due to deletion
  119. const deletion = await adminClient.query(DELETE_API_KEY, { ids: [entityId] });
  120. expect(deletion.deleteApiKeys?.[0]?.result).toBe(DeletionResult.DELETED);
  121. const readErr02 = (await fetch(adminApiUrl, fetchConfig).then(res => res.json())) as _fetchResponse;
  122. expect(readErr02?.errors).toBeDefined();
  123. expect(readErr02?.data?.administrator?.user?.identifier).toBeUndefined();
  124. });
  125. });
  126. export const CREATE_API_KEY = graphql(`
  127. mutation CreateApiKey($input: CreateApiKeyInput!) {
  128. createApiKey(input: $input) {
  129. apiKey
  130. entityId
  131. }
  132. }
  133. `);
  134. export const API_KEY = graphql(`
  135. query ApiKey($id: ID!) {
  136. apiKey(id: $id) {
  137. id
  138. name
  139. translations {
  140. id
  141. languageCode
  142. name
  143. }
  144. }
  145. }
  146. `);
  147. export const API_KEYS = graphql(`
  148. query ApiKeys($options: ApiKeyListOptions) {
  149. apiKeys(options: $options) {
  150. items {
  151. id
  152. name
  153. }
  154. totalItems
  155. }
  156. }
  157. `);
  158. export const UPDATE_API_KEY = graphql(`
  159. mutation UpdateApiKey($input: UpdateApiKeyInput!) {
  160. updateApiKey(input: $input) {
  161. id
  162. name
  163. translations {
  164. id
  165. languageCode
  166. name
  167. }
  168. }
  169. }
  170. `);
  171. export const DELETE_API_KEY = graphql(`
  172. mutation DeleteApiKey($ids: [ID!]!) {
  173. deleteApiKeys(ids: $ids) {
  174. result
  175. message
  176. }
  177. }
  178. `);
  179. export const ROTATE_API_KEY = graphql(`
  180. mutation RotateApiKey($id: ID!) {
  181. rotateApiKey(id: $id) {
  182. apiKey
  183. }
  184. }
  185. `);