Skip to content

Commit f726a96

Browse files
authored
Merge pull request #2431 from RedisInsight/feature/RI-4767-store-api-keys-locally
#RI-4798, #RI-4767 capi keys storage
2 parents 21a9d9b + 2eaa99b commit f726a96

File tree

110 files changed

+3162
-610
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+3162
-610
lines changed

redisinsight/api/config/ormconfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-conf
2020
import { CloudDatabaseDetailsEntity } from 'src/modules/cloud/database/entities/cloud-database-details.entity';
2121
import migrations from '../migration';
2222
import * as config from '../src/utils/config';
23+
import { CloudCapiKeyEntity } from 'src/modules/cloud/capi-key/entity/cloud-capi-key.entity';
2324

2425
const dbConfig = config.get('db');
2526

@@ -46,6 +47,7 @@ const ormConfig = {
4647
FeatureEntity,
4748
FeaturesConfigEntity,
4849
CloudDatabaseDetailsEntity,
50+
CloudCapiKeyEntity,
4951
],
5052
migrations,
5153
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class CloudCapiKeys1691061058385 implements MigrationInterface {
4+
name = 'CloudCapiKeys1691061058385'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`CREATE TABLE "cloud_capi_key" ("id" varchar PRIMARY KEY NOT NULL, "userId" varchar NOT NULL, "name" varchar NOT NULL, "cloudAccountId" integer NOT NULL, "cloudUserId" integer NOT NULL, "capiKey" varchar, "capiSecret" varchar, "valid" boolean DEFAULT (1), "encryption" varchar, "createdAt" datetime, "lastUsed" datetime, CONSTRAINT "UQ_9de67df9deb5d91c09c03b8d719" UNIQUE ("userId", "cloudAccountId", "cloudUserId"))`);
8+
}
9+
10+
public async down(queryRunner: QueryRunner): Promise<void> {
11+
await queryRunner.query(`DROP TABLE "cloud_capi_key"`);
12+
}
13+
14+
}

redisinsight/api/migration/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { DatabaseRedisServer1686719451753 } from './1686719451753-database-redis
3636
import { DatabaseRecommendationUnique1687435940110 } from './1687435940110-database-recommendation-unique';
3737
import { CloudDatabaseDetails1687166457712 } from './1687166457712-cloud-database-details';
3838
import { FreeCloudDatabase1688989337247 } from './1688989337247-freeCloudDatabase';
39+
import { CloudCapiKeys1691061058385 } from './1691061058385-cloud-capi-keys';
3940

4041
export default [
4142
initialMigration1614164490968,
@@ -76,4 +77,5 @@ export default [
7677
DatabaseRecommendationUnique1687435940110,
7778
CloudDatabaseDetails1687166457712,
7879
FreeCloudDatabase1688989337247,
80+
CloudCapiKeys1691061058385,
7981
];
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto';
2+
import { CloudCapiKey, ICloudApiCapiAccessKey, ICloudApiCapiKey } from 'src/modules/cloud/capi-key/model';
3+
import { mockServer } from 'src/__mocks__/server';
4+
5+
export const mockCloudCapiAuthDto: CloudCapiAuthDto = {
6+
capiKey: 'capi_key',
7+
capiSecret: 'capi_secret_key',
8+
};
9+
10+
export const mockCloudApiCapiAccessKey: ICloudApiCapiAccessKey = {
11+
accessKey: mockCloudCapiAuthDto.capiKey,
12+
};
13+
14+
export const mockCloudApiCapiKey: ICloudApiCapiKey = {
15+
id: 3001,
16+
name: 'capi-key-name',
17+
user_account: 40131,
18+
secret_key: mockCloudCapiAuthDto.capiSecret,
19+
};
20+
21+
export const mockCloudCapiKey = Object.assign(new CloudCapiKey(), {
22+
id: '56070e1e-cc50-41c2-b695-585405736af4',
23+
name: `RedisInsight-${mockServer.id.slice(0, 13)}-1577836800000`,
24+
userId: '84cece4b-b074-49be-88e0-44c5f3f59123',
25+
cloudUserId: 10001,
26+
cloudAccountId: 20001,
27+
capiKey: mockCloudCapiAuthDto.capiKey,
28+
capiSecret: mockCloudCapiAuthDto.capiSecret,
29+
valid: true,
30+
createdAt: new Date('2020-01-01T00:00:00.000Z'),
31+
lastUsed: new Date(),
32+
});
33+
34+
export const mockCloudCapiKeyApiProvider = jest.fn(() => ({
35+
enableCapi: jest.fn().mockResolvedValue(mockCloudApiCapiAccessKey.accessKey),
36+
createCapiKey: jest.fn().mockResolvedValue(mockCloudApiCapiKey),
37+
}));
38+
39+
export const mockCloudCapiKeyService = jest.fn(() => ({
40+
getCapiCredentials: jest.fn().mockResolvedValue(mockCloudCapiAuthDto),
41+
handleCapiKeyUnauthorizedError: jest.fn().mockImplementation((e) => e),
42+
}));
43+
44+
export const mockCloudCapiKeyAnalytics = jest.fn(() => ({
45+
sendCloudAccountKeyGenerated: jest.fn(),
46+
sendCloudAccountKeyGenerationFailed: jest.fn(),
47+
}));

redisinsight/api/src/__mocks__/cloud-user.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@ import {
22
CloudAccountInfo,
33
CloudUser,
44
CloudUserAccount,
5-
ICloudApiAccount, ICloudApiCapiAccessKey,
6-
ICloudApiCapiKey,
5+
ICloudApiAccount,
76
ICloudApiCsrfToken,
87
ICloudApiUser,
98
ICloudCapiAccount,
109
} from 'src/modules/cloud/user/models';
11-
import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto';
1210
import { ICloudApiCredentials } from 'src/modules/cloud/common/models';
1311
import config from 'src/utils/config';
1412
import { classToPlain } from 'class-transformer';
13+
import { mockCloudApiCapiAccessKey, mockCloudCapiAuthDto } from 'src/__mocks__/cloud-capi-key';
1514

1615
const serverConfig = config.get('server');
1716

@@ -51,11 +50,6 @@ export const mockCloudUserCapiService = jest.fn(() => ({
5150
}));
5251

5352
// ======================================= API =======================================
54-
export const mockCloudCapiAuthDto: CloudCapiAuthDto = {
55-
capiKey: 'capi_key',
56-
capiSecret: 'capi_secret_key',
57-
};
58-
5953
export const mockCloudCapiHeaders = {
6054
headers: {
6155
'x-api-key': mockCloudCapiAuthDto.capiKey,
@@ -64,10 +58,6 @@ export const mockCloudCapiHeaders = {
6458
},
6559
};
6660

67-
export const mockCloudApiCapiAccessKey: ICloudApiCapiAccessKey = {
68-
accessKey: mockCloudCapiAuthDto.capiKey,
69-
};
70-
7161
export const mockCloudApiCsrfToken: ICloudApiCsrfToken = {
7262
csrf_token: 'csrf_p6vA6A5tF36Jf6twH2cBOqtt7n',
7363
};
@@ -91,13 +81,6 @@ export const mockCloudUserAccount = Object.assign(new CloudUserAccount(), {
9181
// name: mockCloudCapiAccount2.name,
9282
// });
9383

94-
export const mockCloudApiCapiKey: ICloudApiCapiKey = {
95-
id: 3001,
96-
name: 'capi-key-name',
97-
user_account: mockCloudUserAccount.id,
98-
secret_key: mockCloudCapiAuthDto.capiSecret,
99-
};
100-
10184
export const mockCloudApiHeaders = {
10285
headers: {
10386
authorization: `Bearer ${mockCloudApiAuthDto.accessToken}`,

redisinsight/api/src/__mocks__/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export * from './database-recommendation';
2424
export * from './feature';
2525
export * from './triggered-functions';
2626
export * from './cloud-autodiscovery';
27+
export * from './cloud-capi-key';
2728
export * from './cloud-database';
2829
export * from './cloud-subscription';
2930
export * from './cloud-task';

redisinsight/api/src/__mocks__/server.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { Server } from 'src/modules/server/models/server';
22
import { ServerEntity } from 'src/modules/server/entities/server.entity';
3+
import { mockControlGroup, mockControlNumber } from 'src/__mocks__/feature';
4+
import { EncryptionStrategy } from 'src/modules/encryption/models';
5+
import config from 'src/utils/config';
6+
import { GetServerInfoResponse } from 'src/modules/server/dto/server.dto';
7+
8+
const SERVER_CONFIG = config.get('server');
39

410
export const mockServerId = 'a77b23c1-7816-4ea4-b61f-d37a0f805ser';
511

@@ -13,7 +19,25 @@ export const mockServerEntity = Object.assign(new ServerEntity(), {
1319
createDateTime: mockServer.createDateTime,
1420
});
1521

22+
export const mockGetServerInfoResponse = Object.assign(new GetServerInfoResponse(), {
23+
...mockServer,
24+
appVersion: SERVER_CONFIG.appVersion,
25+
osPlatform: process.platform,
26+
buildType: SERVER_CONFIG.buildType,
27+
appType: SERVER_CONFIG.buildType,
28+
controlGroup: mockControlGroup,
29+
controlNumber: mockControlNumber,
30+
encryptionStrategies: [
31+
EncryptionStrategy.PLAIN,
32+
EncryptionStrategy.KEYTAR,
33+
],
34+
});
35+
1636
export const mockServerRepository = jest.fn(() => ({
1737
exists: jest.fn().mockResolvedValue(true),
1838
getOrCreate: jest.fn().mockResolvedValue(mockServer),
1939
}));
40+
41+
export const mockServerService = jest.fn(() => ({
42+
getInfo: jest.fn().mockResolvedValue(mockGetServerInfoResponse),
43+
}));

redisinsight/api/src/app.module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { BulkActionsModule } from 'src/modules/bulk-actions/bulk-actions.module'
1616
import { ClusterMonitorModule } from 'src/modules/cluster-monitor/cluster-monitor.module';
1717
import { DatabaseAnalysisModule } from 'src/modules/database-analysis/database-analysis.module';
1818
import { TriggeredFunctionsModule } from 'src/modules/triggered-functions/triggered-functions.module';
19-
import { ServerModule } from 'src/modules/server/server.module';
2019
import { LocalDatabaseModule } from 'src/local-database.module';
2120
import { CoreModule } from 'src/core.module';
2221
import { AutodiscoveryModule } from 'src/modules/autodiscovery/autodiscovery.module';
@@ -40,7 +39,6 @@ const PATH_CONFIG = config.get('dir_path');
4039
imports: [
4140
LocalDatabaseModule,
4241
CoreModule,
43-
ServerModule.register(),
4442
RouterModule.forRoutes(routes),
4543
AutodiscoveryModule,
4644
RedisEnterpriseModule,

redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ export class SingleUserAuthMiddleware implements NestMiddleware {
1919
await this.sessionService.createSession(plainToClass(Session, {
2020
id: DEFAULT_SESSION_ID,
2121
userId: DEFAULT_USER_ID,
22-
data: {},
22+
data: {
23+
cloud: {
24+
accessToken: process.env.MOCK_AKEY || undefined,
25+
},
26+
},
2327
}));
2428
}
2529

redisinsight/api/src/constants/custom-error-codes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export enum CustomErrorCodes {
1313
CloudOauthUnknownAuthorizationRequest = 11_007,
1414
CloudOauthUnexpectedError = 11_008,
1515
CloudOauthMissedRequiredData = 11_009,
16+
CloudCapiUnauthorized = 11_021,
17+
CloudCapiKeyUnauthorized = 11_022,
18+
CloudCapiKeyNotFound = 11_023,
1619

1720
// Cloud Job errors [11100, 11199]
1821
CloudJobUnexpectedError = 11_100,

0 commit comments

Comments
 (0)