Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
564f337
#RI-4798, #RI-4767 capi keys storage
Aug 3, 2023
b7c6e43
Merge branch 'feature/RI-4617-sign-in-users' into feature/RI-4767-sto…
Aug 3, 2023
be51777
add migrations
Aug 3, 2023
02f944b
add telemetry + fix tests
Aug 4, 2023
be96aa6
#RI-4797 - Display and delete CAPI keys
rsergeenko Aug 7, 2023
3e4f1fe
#RI-4797 - fix pr comments
rsergeenko Aug 7, 2023
d7fdb3e
Merge pull request #2437 from RedisInsight/fe/feature/RI-4797-store-a…
rsergeenko Aug 7, 2023
7cfd53e
#RI-4806 - move components after feature flag
rsergeenko Aug 7, 2023
548e191
Merge pull request #2438 from RedisInsight/fe/feature/RI-4806
rsergeenko Aug 7, 2023
1bbc174
#RI-4831 - fix closing dialog
rsergeenko Aug 8, 2023
c6d3ff1
Merge pull request #2440 from RedisInsight/fe/bugfix/RI-4831
rsergeenko Aug 8, 2023
dc11456
#RI-4833 - fixes related to oath api keys settings
rsergeenko Aug 9, 2023
44f8a83
Merge branch 'feature/RI-4617-sign-in-users' into feature/RI-4767-sto…
rsergeenko Aug 9, 2023
264319f
update interfaces
rsergeenko Aug 9, 2023
b1c3654
Merge pull request #2445 from RedisInsight/fe/bugfix/RI-4833
rsergeenko Aug 9, 2023
9a9f16e
#RI-4838 - fix closing processing message on error
rsergeenko Aug 9, 2023
bffe4ec
Merge pull request #2446 from RedisInsight/fe/bugfix/RI-4838
rsergeenko Aug 9, 2023
1eb900e
avoid encryption error shown to user
Aug 9, 2023
ff8357e
invalidate capi keys for /plans endpoint
Aug 9, 2023
58bd665
Merge pull request #2450 from RedisInsight/be/bugfix/RI-4839-get-plan…
Aug 9, 2023
a4c1777
#RI-4838 - add custom error message for fetch plans
rsergeenko Aug 10, 2023
c5baafa
#RI-4838 - remove unused import
rsergeenko Aug 10, 2023
2eaa99b
Merge pull request #2451 from RedisInsight/fe/bugfix/RI-4838
vlad-dargel Aug 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions redisinsight/api/config/ormconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-conf
import { CloudDatabaseDetailsEntity } from 'src/modules/cloud/database/entities/cloud-database-details.entity';
import migrations from '../migration';
import * as config from '../src/utils/config';
import { CloudCapiKeyEntity } from 'src/modules/cloud/capi-key/entity/cloud-capi-key.entity';

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

Expand All @@ -46,6 +47,7 @@ const ormConfig = {
FeatureEntity,
FeaturesConfigEntity,
CloudDatabaseDetailsEntity,
CloudCapiKeyEntity,
],
migrations,
};
Expand Down
14 changes: 14 additions & 0 deletions redisinsight/api/migration/1691061058385-cloud-capi-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class CloudCapiKeys1691061058385 implements MigrationInterface {
name = 'CloudCapiKeys1691061058385'

public async up(queryRunner: QueryRunner): Promise<void> {
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"))`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "cloud_capi_key"`);
}

}
2 changes: 2 additions & 0 deletions redisinsight/api/migration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { DatabaseRedisServer1686719451753 } from './1686719451753-database-redis
import { DatabaseRecommendationUnique1687435940110 } from './1687435940110-database-recommendation-unique';
import { CloudDatabaseDetails1687166457712 } from './1687166457712-cloud-database-details';
import { FreeCloudDatabase1688989337247 } from './1688989337247-freeCloudDatabase';
import { CloudCapiKeys1691061058385 } from './1691061058385-cloud-capi-keys';

export default [
initialMigration1614164490968,
Expand Down Expand Up @@ -76,4 +77,5 @@ export default [
DatabaseRecommendationUnique1687435940110,
CloudDatabaseDetails1687166457712,
FreeCloudDatabase1688989337247,
CloudCapiKeys1691061058385,
];
47 changes: 47 additions & 0 deletions redisinsight/api/src/__mocks__/cloud-capi-key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto';
import { CloudCapiKey, ICloudApiCapiAccessKey, ICloudApiCapiKey } from 'src/modules/cloud/capi-key/model';
import { mockServer } from 'src/__mocks__/server';

export const mockCloudCapiAuthDto: CloudCapiAuthDto = {
capiKey: 'capi_key',
capiSecret: 'capi_secret_key',
};

export const mockCloudApiCapiAccessKey: ICloudApiCapiAccessKey = {
accessKey: mockCloudCapiAuthDto.capiKey,
};

export const mockCloudApiCapiKey: ICloudApiCapiKey = {
id: 3001,
name: 'capi-key-name',
user_account: 40131,
secret_key: mockCloudCapiAuthDto.capiSecret,
};

export const mockCloudCapiKey = Object.assign(new CloudCapiKey(), {
id: '56070e1e-cc50-41c2-b695-585405736af4',
name: `RedisInsight-${mockServer.id.slice(0, 13)}-1577836800000`,
userId: '84cece4b-b074-49be-88e0-44c5f3f59123',
cloudUserId: 10001,
cloudAccountId: 20001,
capiKey: mockCloudCapiAuthDto.capiKey,
capiSecret: mockCloudCapiAuthDto.capiSecret,
valid: true,
createdAt: new Date('2020-01-01T00:00:00.000Z'),
lastUsed: new Date(),
});

export const mockCloudCapiKeyApiProvider = jest.fn(() => ({
enableCapi: jest.fn().mockResolvedValue(mockCloudApiCapiAccessKey.accessKey),
createCapiKey: jest.fn().mockResolvedValue(mockCloudApiCapiKey),
}));

export const mockCloudCapiKeyService = jest.fn(() => ({
getCapiCredentials: jest.fn().mockResolvedValue(mockCloudCapiAuthDto),
handleCapiKeyUnauthorizedError: jest.fn().mockImplementation((e) => e),
}));

export const mockCloudCapiKeyAnalytics = jest.fn(() => ({
sendCloudAccountKeyGenerated: jest.fn(),
sendCloudAccountKeyGenerationFailed: jest.fn(),
}));
21 changes: 2 additions & 19 deletions redisinsight/api/src/__mocks__/cloud-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import {
CloudAccountInfo,
CloudUser,
CloudUserAccount,
ICloudApiAccount, ICloudApiCapiAccessKey,
ICloudApiCapiKey,
ICloudApiAccount,
ICloudApiCsrfToken,
ICloudApiUser,
ICloudCapiAccount,
} from 'src/modules/cloud/user/models';
import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto';
import { ICloudApiCredentials } from 'src/modules/cloud/common/models';
import config from 'src/utils/config';
import { classToPlain } from 'class-transformer';
import { mockCloudApiCapiAccessKey, mockCloudCapiAuthDto } from 'src/__mocks__/cloud-capi-key';

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

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

// ======================================= API =======================================
export const mockCloudCapiAuthDto: CloudCapiAuthDto = {
capiKey: 'capi_key',
capiSecret: 'capi_secret_key',
};

export const mockCloudCapiHeaders = {
headers: {
'x-api-key': mockCloudCapiAuthDto.capiKey,
Expand All @@ -64,10 +58,6 @@ export const mockCloudCapiHeaders = {
},
};

export const mockCloudApiCapiAccessKey: ICloudApiCapiAccessKey = {
accessKey: mockCloudCapiAuthDto.capiKey,
};

export const mockCloudApiCsrfToken: ICloudApiCsrfToken = {
csrf_token: 'csrf_p6vA6A5tF36Jf6twH2cBOqtt7n',
};
Expand All @@ -91,13 +81,6 @@ export const mockCloudUserAccount = Object.assign(new CloudUserAccount(), {
// name: mockCloudCapiAccount2.name,
// });

export const mockCloudApiCapiKey: ICloudApiCapiKey = {
id: 3001,
name: 'capi-key-name',
user_account: mockCloudUserAccount.id,
secret_key: mockCloudCapiAuthDto.capiSecret,
};

export const mockCloudApiHeaders = {
headers: {
authorization: `Bearer ${mockCloudApiAuthDto.accessToken}`,
Expand Down
1 change: 1 addition & 0 deletions redisinsight/api/src/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export * from './database-recommendation';
export * from './feature';
export * from './triggered-functions';
export * from './cloud-autodiscovery';
export * from './cloud-capi-key';
export * from './cloud-database';
export * from './cloud-subscription';
export * from './cloud-task';
Expand Down
24 changes: 24 additions & 0 deletions redisinsight/api/src/__mocks__/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Server } from 'src/modules/server/models/server';
import { ServerEntity } from 'src/modules/server/entities/server.entity';
import { mockControlGroup, mockControlNumber } from 'src/__mocks__/feature';
import { EncryptionStrategy } from 'src/modules/encryption/models';
import config from 'src/utils/config';
import { GetServerInfoResponse } from 'src/modules/server/dto/server.dto';

const SERVER_CONFIG = config.get('server');

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

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

export const mockGetServerInfoResponse = Object.assign(new GetServerInfoResponse(), {
...mockServer,
appVersion: SERVER_CONFIG.appVersion,
osPlatform: process.platform,
buildType: SERVER_CONFIG.buildType,
appType: SERVER_CONFIG.buildType,
controlGroup: mockControlGroup,
controlNumber: mockControlNumber,
encryptionStrategies: [
EncryptionStrategy.PLAIN,
EncryptionStrategy.KEYTAR,
],
});

export const mockServerRepository = jest.fn(() => ({
exists: jest.fn().mockResolvedValue(true),
getOrCreate: jest.fn().mockResolvedValue(mockServer),
}));

export const mockServerService = jest.fn(() => ({
getInfo: jest.fn().mockResolvedValue(mockGetServerInfoResponse),
}));
2 changes: 0 additions & 2 deletions redisinsight/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { BulkActionsModule } from 'src/modules/bulk-actions/bulk-actions.module'
import { ClusterMonitorModule } from 'src/modules/cluster-monitor/cluster-monitor.module';
import { DatabaseAnalysisModule } from 'src/modules/database-analysis/database-analysis.module';
import { TriggeredFunctionsModule } from 'src/modules/triggered-functions/triggered-functions.module';
import { ServerModule } from 'src/modules/server/server.module';
import { LocalDatabaseModule } from 'src/local-database.module';
import { CoreModule } from 'src/core.module';
import { AutodiscoveryModule } from 'src/modules/autodiscovery/autodiscovery.module';
Expand All @@ -40,7 +39,6 @@ const PATH_CONFIG = config.get('dir_path');
imports: [
LocalDatabaseModule,
CoreModule,
ServerModule.register(),
RouterModule.forRoutes(routes),
AutodiscoveryModule,
RedisEnterpriseModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export class SingleUserAuthMiddleware implements NestMiddleware {
await this.sessionService.createSession(plainToClass(Session, {
id: DEFAULT_SESSION_ID,
userId: DEFAULT_USER_ID,
data: {},
data: {
cloud: {
accessToken: process.env.MOCK_AKEY || undefined,
},
},
}));
}

Expand Down
3 changes: 3 additions & 0 deletions redisinsight/api/src/constants/custom-error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export enum CustomErrorCodes {
CloudOauthUnknownAuthorizationRequest = 11_007,
CloudOauthUnexpectedError = 11_008,
CloudOauthMissedRequiredData = 11_009,
CloudCapiUnauthorized = 11_021,
CloudCapiKeyUnauthorized = 11_022,
CloudCapiKeyNotFound = 11_023,

// Cloud Job errors [11100, 11199]
CloudJobUnexpectedError = 11_100,
Expand Down
2 changes: 2 additions & 0 deletions redisinsight/api/src/constants/error-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export default {
UNDEFINED_WINDOW_ID: 'Undefined window id.',
LIBRARY_NOT_EXIST: 'This library does not exist.',

CLOUD_CAPI_UNAUTHORIZED: 'Authorization failed',
CLOUD_CAPI_KEY_UNAUTHORIZED: 'Unable to authorize such CAPI key',
CLOUD_API_UNAUTHORIZED: 'Authorization failed',
CLOUD_API_FORBIDDEN: 'Access denied',
CLOUD_API_BAD_REQUEST: 'Bad request',
Expand Down
4 changes: 4 additions & 0 deletions redisinsight/api/src/constants/telemetry-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export enum TelemetryEvents {
CloudFreeDatabaseCreated = 'CLOUD_FREE_DATABASE_CREATED',
CloudFreeDatabaseFailed = 'CLOUD_FREE_DATABASE_FAILED',

// Event for cloud CAPI keys
CloudAccountKeyGenerated = 'CLOUD_ACCOUNT_KEY_GENERATED',
CloudAccountKeyGenerationFailed = 'CLOUD_ACCOUNT_KEY_GENERATION_FAILED',

// Events for cli tool
CliClientCreated = 'CLI_CLIENT_CREATED',
CliClientCreationFailed = 'CLI_CLIENT_CREATION_FAILED',
Expand Down
3 changes: 3 additions & 0 deletions redisinsight/api/src/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { NestjsFormDataModule } from 'nestjs-form-data';
import { FeatureModule } from 'src/modules/feature/feature.module';
import { AuthModule } from 'src/modules/auth/auth.module';
import { SessionModule } from 'src/modules/session/session.module';
import { ServerModule } from 'src/modules/server/server.module';

@Global()
@Module({
Expand All @@ -29,6 +30,7 @@ import { SessionModule } from 'src/modules/session/session.module';
FeatureModule.register(),
AuthModule.register(),
SessionModule.register(),
ServerModule.register(),
],
exports: [
EncryptionModule,
Expand All @@ -41,6 +43,7 @@ import { SessionModule } from 'src/modules/session/session.module';
NestjsFormDataModule,
FeatureModule,
SessionModule,
ServerModule,
],
})
export class CoreModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export abstract class TelemetryBaseService {
this.eventEmitter.emit(AppAnalyticsEvents.Track, {
event,
eventData: {
error: exception.getResponse()['error'] || exception.message,
error: exception.getResponse?.()['error'] || exception.message,
...eventData,
command: isString(eventData['command']) ? eventData['command'].toUpperCase() : eventData['command'],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import { CloudSubscriptionModule } from 'src/modules/cloud/subscription/cloud-su
import { CloudUserModule } from 'src/modules/cloud/user/cloud-user.module';
import { MeCloudAutodiscoveryController } from 'src/modules/cloud/autodiscovery/me.cloud.autodiscovery.controller';
import { MeCloudAutodiscoveryService } from 'src/modules/cloud/autodiscovery/me.cloud-autodiscovery.service';
import { CloudCapiKeyModule } from 'src/modules/cloud/capi-key/cloud-capi-key.module';

@Module({
imports: [
CloudDatabaseModule,
CloudSubscriptionModule,
CloudUserModule,
CloudCapiKeyModule,
],
controllers: [
CloudAutodiscoveryController,
Expand Down
Loading