Skip to content

Commit 0a3760d

Browse files
Merge branch 'main' into feature/RI-3997_Display_indexes_in_Workbench_and_Analytics
2 parents 378a80e + 84cb39b commit 0a3760d

File tree

99 files changed

+4175
-1120
lines changed

Some content is hidden

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

99 files changed

+4175
-1120
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ aliases:
8888
- mods-preview # OSS Standalone and all preview modules
8989
- oss-st-6-tls # OSS Standalone v6 with TLS enabled
9090
- oss-st-6-tls-auth # OSS Standalone v6 with TLS auth required
91+
- oss-st-6-tls-auth-ssh # OSS Standalone v6 with TLS auth required through ssh
9192
- oss-clu # OSS Cluster
9293
- oss-clu-tls # OSS Cluster with TLS enabled
9394
- oss-sent # OSS Sentinel

redisinsight/api/config/default.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default {
5555
staticContent: !!process.env.SERVER_STATIC_CONTENT || false,
5656
buildType: process.env.BUILD_TYPE || 'ELECTRON',
5757
appVersion: process.env.APP_VERSION || '2.0.0',
58-
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 10000,
58+
requestTimeout: parseInt(process.env.REQUEST_TIMEOUT, 10) || 25000,
5959
excludeRoutes: [],
6060
excludeAuthRoutes: [],
6161
},
@@ -108,14 +108,14 @@ export default {
108108
},
109109
guides: {
110110
updateUrl: process.env.GUIDES_UPDATE_URL
111-
|| 'https://github.com/RedisInsight/Guides/releases/download/latest',
111+
|| 'https://github.com/RedisInsight/Guides/releases/download/release',
112112
zip: process.env.GUIDES_ZIP || dataZipFileName,
113113
buildInfo: process.env.GUIDES_CHECKSUM || buildInfoFileName,
114114
devMode: !!process.env.GUIDES_DEV_PATH,
115115
},
116116
tutorials: {
117117
updateUrl: process.env.TUTORIALS_UPDATE_URL
118-
|| 'https://github.com/RedisInsight/Tutorials/releases/download/latest',
118+
|| 'https://github.com/RedisInsight/Tutorials/releases/download/release',
119119
zip: process.env.TUTORIALS_ZIP || dataZipFileName,
120120
buildInfo: process.env.TUTORIALS_CHECKSUM || buildInfoFileName,
121121
devMode: !!process.env.TUTORIALS_DEV_PATH,

redisinsight/api/config/ormconfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { SettingsEntity } from 'src/modules/settings/entities/settings.entity';
1010
import { CaCertificateEntity } from 'src/modules/certificate/entities/ca-certificate.entity';
1111
import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity';
1212
import { DatabaseEntity } from 'src/modules/database/entities/database.entity';
13+
import { SshOptionsEntity } from 'src/modules/ssh/entities/ssh-options.entity';
1314
import migrations from '../migration';
1415
import * as config from '../src/utils/config';
1516

@@ -31,6 +32,7 @@ const ormConfig = {
3132
PluginStateEntity,
3233
NotificationEntity,
3334
DatabaseAnalysisEntity,
35+
SshOptionsEntity,
3436
],
3537
migrations,
3638
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class sshOptions1673035852335 implements MigrationInterface {
4+
name = 'sshOptions1673035852335'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`CREATE TABLE "ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"))`);
8+
await queryRunner.query(`CREATE TABLE "temporary_database_instance" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "name" varchar NOT NULL, "username" varchar, "password" varchar, "tls" boolean, "verifyServerCert" boolean, "lastConnection" datetime, "caCertId" varchar, "clientCertId" varchar, "connectionType" varchar NOT NULL DEFAULT ('STANDALONE'), "nodes" varchar DEFAULT ('[]'), "nameFromProvider" varchar, "sentinelMasterName" varchar, "sentinelMasterUsername" varchar, "sentinelMasterPassword" varchar, "provider" varchar DEFAULT ('UNKNOWN'), "modules" varchar NOT NULL DEFAULT ('[]'), "db" integer, "encryption" varchar, "tlsServername" varchar, "new" boolean, "ssh" boolean, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
9+
await queryRunner.query(`INSERT INTO "temporary_database_instance"("id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new" FROM "database_instance"`);
10+
await queryRunner.query(`DROP TABLE "database_instance"`);
11+
await queryRunner.query(`ALTER TABLE "temporary_database_instance" RENAME TO "database_instance"`);
12+
await queryRunner.query(`CREATE TABLE "temporary_ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"), CONSTRAINT "FK_fe3c3f8b1246e4824a3fb83047d" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`);
13+
await queryRunner.query(`INSERT INTO "temporary_ssh_options"("id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId") SELECT "id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId" FROM "ssh_options"`);
14+
await queryRunner.query(`DROP TABLE "ssh_options"`);
15+
await queryRunner.query(`ALTER TABLE "temporary_ssh_options" RENAME TO "ssh_options"`);
16+
}
17+
18+
public async down(queryRunner: QueryRunner): Promise<void> {
19+
await queryRunner.query(`ALTER TABLE "ssh_options" RENAME TO "temporary_ssh_options"`);
20+
await queryRunner.query(`CREATE TABLE "ssh_options" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "encryption" varchar, "username" varchar, "password" varchar, "privateKey" varchar, "passphrase" varchar, "databaseId" varchar, CONSTRAINT "REL_fe3c3f8b1246e4824a3fb83047" UNIQUE ("databaseId"))`);
21+
await queryRunner.query(`INSERT INTO "ssh_options"("id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId") SELECT "id", "host", "port", "encryption", "username", "password", "privateKey", "passphrase", "databaseId" FROM "temporary_ssh_options"`);
22+
await queryRunner.query(`DROP TABLE "temporary_ssh_options"`);
23+
await queryRunner.query(`ALTER TABLE "database_instance" RENAME TO "temporary_database_instance"`);
24+
await queryRunner.query(`CREATE TABLE "database_instance" ("id" varchar PRIMARY KEY NOT NULL, "host" varchar NOT NULL, "port" integer NOT NULL, "name" varchar NOT NULL, "username" varchar, "password" varchar, "tls" boolean, "verifyServerCert" boolean, "lastConnection" datetime, "caCertId" varchar, "clientCertId" varchar, "connectionType" varchar NOT NULL DEFAULT ('STANDALONE'), "nodes" varchar DEFAULT ('[]'), "nameFromProvider" varchar, "sentinelMasterName" varchar, "sentinelMasterUsername" varchar, "sentinelMasterPassword" varchar, "provider" varchar DEFAULT ('UNKNOWN'), "modules" varchar NOT NULL DEFAULT ('[]'), "db" integer, "encryption" varchar, "tlsServername" varchar, "new" boolean, CONSTRAINT "FK_d1bc747b5938e22b4b708d8e9a5" FOREIGN KEY ("caCertId") REFERENCES "ca_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_3b9b625266c00feb2d66a9f36e4" FOREIGN KEY ("clientCertId") REFERENCES "client_certificate" ("id") ON DELETE SET NULL ON UPDATE NO ACTION)`);
25+
await queryRunner.query(`INSERT INTO "database_instance"("id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new") SELECT "id", "host", "port", "name", "username", "password", "tls", "verifyServerCert", "lastConnection", "caCertId", "clientCertId", "connectionType", "nodes", "nameFromProvider", "sentinelMasterName", "sentinelMasterUsername", "sentinelMasterPassword", "provider", "modules", "db", "encryption", "tlsServername", "new" FROM "temporary_database_instance"`);
26+
await queryRunner.query(`DROP TABLE "temporary_database_instance"`);
27+
await queryRunner.query(`DROP TABLE "ssh_options"`);
28+
}
29+
30+
}

redisinsight/api/migration/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { databaseAnalysisExpirationGroups1664886479051 } from './1664886479051-d
2222
import { workbenchExecutionTime1667368983699 } from './1667368983699-workbench-execution-time';
2323
import { database1667477693934 } from './1667477693934-database';
2424
import { databaseNew1670252337342 } from './1670252337342-database-new';
25+
import { sshOptions1673035852335 } from './1673035852335-ssh-options';
2526
import { workbenchAndAnalysisDbIndex1673934231410 } from './1673934231410-workbench_and_analysis_db';
2627

2728
export default [
@@ -50,4 +51,5 @@ export default [
5051
database1667477693934,
5152
databaseNew1670252337342,
5253
workbenchAndAnalysisDbIndex1673934231410,
54+
sshOptions1673035852335,
5355
];

redisinsight/api/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"body-parser": "^1.19.0",
5454
"class-transformer": "^0.2.3",
5555
"class-validator": "^0.12.2",
56+
"detect-port": "^1.5.1",
5657
"dotenv": "^16.0.0",
5758
"express": "^4.17.1",
5859
"fs-extra": "^10.0.0",
@@ -67,6 +68,7 @@
6768
"socket.io": "^4.4.0",
6869
"source-map-support": "^0.5.19",
6970
"sqlite3": "^5.0.11",
71+
"ssh2": "^1.11.0",
7072
"swagger-ui-express": "^4.1.4",
7173
"typeorm": "^0.3.9",
7274
"uuid": "^8.3.2",
@@ -84,6 +86,7 @@
8486
"@types/lodash": "^4.14.167",
8587
"@types/node": "14.14.10",
8688
"@types/socket.io": "^3.0.2",
89+
"@types/ssh2": "^1.11.6",
8790
"@types/supertest": "^2.0.8",
8891
"@typescript-eslint/eslint-plugin": "^4.8.1",
8992
"@typescript-eslint/parser": "^4.8.1",

redisinsight/api/src/__mocks__/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const mockRepository = jest.fn(() => ({
5454
findOneBy: jest.fn(),
5555
find: jest.fn(),
5656
findByIds: jest.fn(),
57+
merge: jest.fn(),
5758
create: jest.fn(),
5859
save: jest.fn(),
5960
insert: jest.fn(),

redisinsight/api/src/__mocks__/databases.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import { pick } from 'lodash';
99
import { RedisDatabaseInfoResponse } from 'src/modules/database/dto/redis-info.dto';
1010
import { DatabaseOverview } from 'src/modules/database/models/database-overview';
1111
import { ClientContext, ClientMetadata } from 'src/common/models';
12+
import {
13+
mockSshOptionsBasic,
14+
mockSshOptionsBasicEntity,
15+
mockSshOptionsPrivateKey,
16+
mockSshOptionsPrivateKeyEntity,
17+
} from 'src/__mocks__/ssh';
1218

1319
export const mockDatabaseId = 'a77b23c1-7816-4ea4-b61f-d37795a0f805-db-id';
1420

@@ -34,6 +40,29 @@ export const mockDatabaseEntity = Object.assign(new DatabaseEntity(), {
3440
encryption: null,
3541
});
3642

43+
export const mockDatabaseWithSshBasic = Object.assign(new Database(), {
44+
...mockDatabase,
45+
ssh: true,
46+
sshOptions: mockSshOptionsBasic,
47+
});
48+
49+
export const mockDatabaseWithSshBasicEntity = Object.assign(new DatabaseEntity(), {
50+
...mockDatabaseWithSshBasic,
51+
encryption: null,
52+
sshOptions: mockSshOptionsBasicEntity,
53+
});
54+
55+
export const mockDatabaseWithSshPrivateKey = Object.assign(new Database(), {
56+
...mockDatabase,
57+
ssh: true,
58+
sshOptions: mockSshOptionsPrivateKey,
59+
});
60+
61+
export const mockDatabaseWithSshPrivateKeyEntity = Object.assign(new DatabaseEntity(), {
62+
...mockDatabaseWithSshPrivateKey,
63+
sshOptions: mockSshOptionsPrivateKeyEntity,
64+
});
65+
3766
export const mockDatabaseWithAuth = Object.assign(new Database(), {
3867
...mockDatabase,
3968
username: 'some username',
@@ -181,6 +210,7 @@ export const mockDatabaseService = jest.fn(() => ({
181210

182211
export const mockDatabaseConnectionService = jest.fn(() => ({
183212
getOrCreateClient: jest.fn().mockResolvedValue(mockIORedisClient),
213+
createClient: jest.fn().mockResolvedValue(mockIORedisClient),
184214
}));
185215

186216
export const mockDatabaseInfoProvider = jest.fn(() => ({

redisinsight/api/src/__mocks__/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export * from './redis-enterprise';
1818
export * from './redis-sentinel';
1919
export * from './database-import';
2020
export * from './redis-client';
21+
export * from './ssh';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { EncryptionStrategy } from 'src/modules/encryption/models';
2+
import { SshOptions } from 'src/modules/ssh/models/ssh-options';
3+
import { SshOptionsEntity } from 'src/modules/ssh/entities/ssh-options.entity';
4+
5+
export const mockSshOptionsId = 'a77b23c1-7816-4ea4-b61f-d37795a0f805-ssh-id';
6+
7+
export const mockSshOptionsUsernamePlain = 'ssh-username';
8+
export const mockSshOptionsUsernameEncrypted = 'ssh.username.ENCRYPTED';
9+
export const mockSshOptionsPasswordPlain = 'ssh-password';
10+
export const mockSshOptionsPasswordEncrypted = 'ssh.password.ENCRYPTED';
11+
export const mockSshOptionsPrivateKeyPlain = '-----BEGIN OPENSSH PRIVATE KEY-----\nssh-private-key';
12+
export const mockSshOptionsPrivateKeyEncrypted = 'ssh.privateKey.ENCRYPTED';
13+
export const mockSshOptionsPassphrasePlain = 'ssh-passphrase';
14+
export const mockSshOptionsPassphraseEncrypted = 'ssh.passphrase.ENCRYPTED';
15+
16+
export const mockSshOptionsBasic = Object.assign(new SshOptions(), {
17+
id: mockSshOptionsId,
18+
host: 'ssh.host.test',
19+
port: 22,
20+
username: mockSshOptionsUsernamePlain,
21+
password: mockSshOptionsPasswordPlain,
22+
privateKey: null,
23+
passphrase: null,
24+
});
25+
26+
export const mockSshOptionsBasicEntity = Object.assign(new SshOptionsEntity(), {
27+
...mockSshOptionsBasic,
28+
username: mockSshOptionsUsernameEncrypted,
29+
password: mockSshOptionsPasswordEncrypted,
30+
encryption: EncryptionStrategy.KEYTAR,
31+
});
32+
33+
export const mockSshOptionsPrivateKey = Object.assign(new SshOptions(), {
34+
...mockSshOptionsBasic,
35+
password: null,
36+
privateKey: mockSshOptionsPrivateKeyPlain,
37+
passphrase: mockSshOptionsPassphrasePlain,
38+
});
39+
40+
export const mockSshOptionsPrivateKeyEntity = Object.assign(new SshOptionsEntity(), {
41+
...mockSshOptionsBasicEntity,
42+
password: null,
43+
privateKey: mockSshOptionsPrivateKeyEncrypted,
44+
passphrase: mockSshOptionsPassphraseEncrypted,
45+
});
46+
47+
export const mockSshTunnelProvider = jest.fn(() => {
48+
49+
});

0 commit comments

Comments
 (0)