diff --git a/config/rest-gateway/rest.json.mustache b/config/rest-gateway/rest.json.mustache index 045a000c5..4be203154 100644 --- a/config/rest-gateway/rest.json.mustache +++ b/config/rest-gateway/rest.json.mustache @@ -5,6 +5,10 @@ }, "port": 3000, + "protocol": "{{{restProtocol}}}", + "sslKeyPath": "{{{restSSLPath}}}/{{{restSSLKeyFileName}}}", + "sslCertificatePath": "{{{restSSLPath}}}/{{{restSSLCertificateFileName}}}", + "crossDomain": { "allowedHosts": ["*"], "allowedMethods": ["GET", "POST", "PUT", "OPTIONS"] diff --git a/presets/bootstrap/network.yml b/presets/bootstrap/network.yml index e99b05c17..3c0fc73c0 100644 --- a/presets/bootstrap/network.yml +++ b/presets/bootstrap/network.yml @@ -124,6 +124,14 @@ faucets: BLACKLIST_MOSAIC_IDS: '[]' EXPLORER_URL: 'http://localhost:{{add $index 90}}/' openPort: '{{add $index 100}}' +httpsProxies: + - name: 'https-proxy' + excludeDockerService: true #disabled as default + openPort: 3001 + #domains: 'symbol-node.example.com -> http://rest-gateway:3000' + stage: 'production' + webSocket: 'true' + serverNamesHashBucketSize: 128 inflation: starting-at-height-1: 0 starting-at-height-10000: 0 diff --git a/presets/mainnet/assembly-api.yml b/presets/mainnet/assembly-api.yml index 4d54d6670..c536ba752 100644 --- a/presets/mainnet/assembly-api.yml +++ b/presets/mainnet/assembly-api.yml @@ -20,3 +20,11 @@ gateways: databaseHost: 'db' openPort: true ipv4_address: 172.20.0.25 +httpsProxies: + - name: 'https-proxy' + excludeDockerService: true #disabled as default + openPort: 3001 + #domains: 'symbol-node.example.com -> http://rest-gateway:3000' + stage: 'production' + webSocket: 'true' + serverNamesHashBucketSize: 128 diff --git a/presets/mainnet/assembly-dual.yml b/presets/mainnet/assembly-dual.yml index 104f965cb..9b955d9c8 100644 --- a/presets/mainnet/assembly-dual.yml +++ b/presets/mainnet/assembly-dual.yml @@ -20,3 +20,11 @@ gateways: databaseHost: 'db' openPort: true ipv4_address: 172.20.0.25 +httpsProxies: + - name: 'https-proxy' + excludeDockerService: true #disabled as default + openPort: 3001 + #domains: 'symbol-node.example.com -> http://rest-gateway:3000' + stage: 'production' + webSocket: 'true' + serverNamesHashBucketSize: 128 diff --git a/presets/mainnet/network.yml b/presets/mainnet/network.yml index 4b94b7589..66076c69a 100644 --- a/presets/mainnet/network.yml +++ b/presets/mainnet/network.yml @@ -30,7 +30,7 @@ minVotingKeyLifetime: 112 maxVotingKeyLifetime: 360 votingKeyDesiredLifetime: 360 votingKeyDesiredFutureLifetime: 60 -lastKnownNetworkEpoch: 255 +lastKnownNetworkEpoch: 280 stepDuration: 5m maxBlockFutureTime: 300ms maxAccountRestrictionValues: 100 diff --git a/presets/shared.yml b/presets/shared.yml index 7c2e9a020..8a2b84d40 100644 --- a/presets/shared.yml +++ b/presets/shared.yml @@ -65,12 +65,13 @@ maxChildNamespaces: 256 maxNamespaceDepth: 3 batchVerificationRandomSource: symbolServerImage: symbolplatform/symbol-server:gcc-10-1.0.1.0 -symbolRestImage: symbolplatform/symbol-rest:2.3.6 +symbolRestImage: symbolplatform/symbol-rest:2.3.7-alpha symbolExplorerImage: symbolplatform/symbol-explorer:1.1.0-alpha symbolWalletImage: symbolplatform/symbol-desktop-wallet:1.0.1 symbolFaucetImage: symbolplatform/symbol-faucet:1.0.1-alpha symbolAgentImage: symbolplatform/symbol-node-rewards-agent:2.0.0 mongoImage: mongo:4.4.3-bionic +httpsPortalImage: steveltn/https-portal:1.19 mongoComposeRunParam: --wiredTigerCacheSizeGB 2 logLevel: 'Info' # brokerLogLevel: 'Info' @@ -214,3 +215,7 @@ connectionPoolSize: 10 maxSubscriptions: 300 restExtensions: 'accountLink, aggregate, lockHash, lockSecret, mosaic, metadata, multisig, namespace, receipts, restrictions, transfer, cmc' restDeploymentTool: symbol-bootstrap +restProtocol: HTTP +restSSLPath: '/symbol-workdir' +restSSLKeyFileName: 'restSSL.key' +restSSLCertificateFileName: 'restSSL.crt' diff --git a/presets/testnet/assembly-api.yml b/presets/testnet/assembly-api.yml index 0c52118cd..8c4bb5755 100644 --- a/presets/testnet/assembly-api.yml +++ b/presets/testnet/assembly-api.yml @@ -20,3 +20,11 @@ gateways: databaseHost: 'db' openPort: true ipv4_address: 172.20.0.25 +httpsProxies: + - name: 'https-proxy' + excludeDockerService: true #disabled as default + openPort: 3001 + #domains: 'symbol-node.example.com -> http://rest-gateway:3000' + stage: 'production' + webSocket: 'true' + serverNamesHashBucketSize: 128 diff --git a/presets/testnet/assembly-dual.yml b/presets/testnet/assembly-dual.yml index 6ec842b8b..68663fba6 100644 --- a/presets/testnet/assembly-dual.yml +++ b/presets/testnet/assembly-dual.yml @@ -20,3 +20,11 @@ gateways: databaseHost: 'db' openPort: true ipv4_address: 172.20.0.25 +httpsProxies: + - name: 'https-proxy' + excludeDockerService: true #disabled as default + openPort: 3001 + #domains: 'symbol-node.example.com -> http://rest-gateway:3000' + stage: 'production' + webSocket: 'true' + serverNamesHashBucketSize: 128 diff --git a/presets/testnet/network.yml b/presets/testnet/network.yml index 178f52b99..f368b036a 100644 --- a/presets/testnet/network.yml +++ b/presets/testnet/network.yml @@ -28,7 +28,7 @@ importanceGrouping: 180 votingSetGrouping: 720 votingKeyDesiredLifetime: 720 votingKeyDesiredFutureLifetime: 120 -lastKnownNetworkEpoch: 365 +lastKnownNetworkEpoch: 408 minVotingKeyLifetime: 28 maxVotingKeyLifetime: 720 stepDuration: 4m diff --git a/src/commands/wizard.ts b/src/commands/wizard.ts index 306894619..7ab48fbe6 100644 --- a/src/commands/wizard.ts +++ b/src/commands/wizard.ts @@ -16,7 +16,7 @@ import { Command, flags } from '@oclif/command'; import { IOptionFlag } from '@oclif/command/lib/flags'; -import { existsSync } from 'fs'; +import { existsSync, readFileSync } from 'fs'; import { prompt } from 'inquirer'; import { Account, NetworkType, PublicAccount } from 'symbol-sdk'; import { CustomPreset, PrivateKeySecurityMode } from '../model'; @@ -39,6 +39,11 @@ export const assemblies: Record => { + if (httpsOption === HttpsOption.Native) { + const restSSLKeyBase64 = await Wizard.resolveRestSSLKeyAsBase64(); + const restSSLCertificateBase64 = await Wizard.resolveRestSSLCertAsBase64(); + return { + gateways: [ + { + restProtocol: 'HTTPS', + openPort: 3001, + restSSLKeyBase64, + restSSLCertificateBase64, + }, + ], + }; + } else if (httpsOption === HttpsOption.Automatic) { + return { + httpsProxies: [ + { + excludeDockerService: false, + }, + ], + }; + } else { + // HttpsOption.None + console.log(`Warning! You've chosen to proceed with http, which is less secure in comparison to https.`); + return {}; + } + }; + + const httpsCustomPreset = await resolveHttpsCustomPreset(); const friendlyName = await Wizard.resolveFriendlyName(host || accounts.main.publicKey.substr(0, 7)); const privateKeySecurityMode = await Wizard.resolvePrivateKeySecurityMode(); const voting = await Wizard.isVoting(); @@ -210,7 +246,9 @@ export default class Wizard extends Command { agentPrivateKey: accounts.agent?.privateKey, }, ], + ...httpsCustomPreset, }; + const defaultParams = ConfigService.defaultParams; await BootstrapUtils.writeYaml(customPresetFile, presetContent, password); console.log(); @@ -512,6 +550,37 @@ export default class Wizard extends Command { return host || undefined; } + public static async resolveRestSSLKeyAsBase64(): Promise { + return this.resolveFileContent('base64', 'Enter your SSL key file path:', 'Invalid path, cannot find SSL key file!'); + } + + public static async resolveRestSSLCertAsBase64(): Promise { + return this.resolveFileContent( + 'base64', + 'Enter your SSL Certificate file path:', + 'Invalid path, cannot find SSL certificate file!', + ); + } + + public static async resolveFileContent(encoding: string, message: string, notFoundMessage: string): Promise { + const { value } = await prompt([ + { + name: 'value', + message: message, + type: 'input', + validate: (value) => { + if (!existsSync(value)) { + return notFoundMessage; + } + return true; + }, + }, + ]); + + return readFileSync(value, encoding); + } + + // TODO Refactor this public static isValidHost(input: string): boolean | string { if (input.trim() == '') { return 'Host is required.'; @@ -546,4 +615,28 @@ export default class Wizard extends Command { ]); return friendlyName; } + + public static async resolveHttpsOptions(): Promise { + // TODO work on these messages, should be concise and clearer + console.log( + 'Your REST Gateway should be running on HTTPS (which is a secure protocol) so that it can be recognized by the Symbol Explorer.', + ); + const { value } = await prompt([ + { + name: 'value', + message: 'Select your HTTPS setup method:', + type: 'list', + default: HttpsOption.Native, + choices: [ + { name: 'Native support, I have the SSL certificate and key.', value: HttpsOption.Native }, + { + name: `Automatic, all of your keys and certs will be generated/renewed automatically, using letsencyrpt.`, + value: HttpsOption.Automatic, + }, + { name: 'None', value: HttpsOption.None }, + ], + }, + ]); + return value; + } } diff --git a/src/model/ConfigPreset.ts b/src/model/ConfigPreset.ts index 98478ac52..fce596b3b 100644 --- a/src/model/ConfigPreset.ts +++ b/src/model/ConfigPreset.ts @@ -318,6 +318,12 @@ export interface GatewayConfigPreset { restDeploymentTool: string; restDeploymentToolVersion?: string; // default is dynamic, current bootstrap version restDeploymentToolLastUpdatedDate?: string; // default is dynamic, current datetime + restProtocol: 'HTTPS' | 'HTTP'; + restSSLPath: string; + restSSLKeyFileName: string; + restSSLCertificateFileName: string; + restSSLKeyBase64?: string; + restSSLCertificateBase64?: string; } export interface GatewayPreset extends DockerServicePreset, Partial { @@ -329,6 +335,14 @@ export interface GatewayPreset extends DockerServicePreset, Partial { @@ -449,4 +465,5 @@ export interface CustomPreset extends Partial { explorers?: Partial[]; wallets?: Partial[]; faucets?: Partial[]; + httpsProxies?: Partial[]; } diff --git a/src/service/BootstrapUtils.ts b/src/service/BootstrapUtils.ts index 9a3643abc..cd241b5ad 100644 --- a/src/service/BootstrapUtils.ts +++ b/src/service/BootstrapUtils.ts @@ -304,6 +304,8 @@ export class BootstrapUtils { // Create a promise that rejects in milliseconds return new Promise((resolve) => { setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore resolve(); }, ms); }); diff --git a/src/service/ComposeService.ts b/src/service/ComposeService.ts index 3dc010f0d..84d7d4b7d 100644 --- a/src/service/ComposeService.ts +++ b/src/service/ComposeService.ts @@ -109,6 +109,10 @@ export class ComposeService { }); }; + const resolveHttpsProxyDomains = (fromDomain: string, toDomain: string): string => { + return `${fromDomain} -> ${toDomain}`; + }; + const resolveService = async ( servicePreset: DockerServicePreset, rawService: DockerComposeService, @@ -270,12 +274,11 @@ export class ComposeService { } }), ); - + const restInternalPort = 3000; // Move to shared? await Promise.all( (presetData.gateways || []) .filter((d) => !d.excludeDockerService) .map(async (n) => { - const internalPort = 3000; const volumes = [vol(`../${targetGatewaysFolder}/${n.name}`, nodeWorkingDirectory, false)]; services.push( await resolveService(n, { @@ -285,7 +288,7 @@ export class ComposeService { command: 'npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json', stop_signal: 'SIGINT', working_dir: nodeWorkingDirectory, - ports: resolvePorts([{ internalPort: internalPort, openPort: n.openPort }]), + ports: resolvePorts([{ internalPort: restInternalPort, openPort: n.openPort }]), restart: restart, volumes: volumes, depends_on: [n.databaseHost], @@ -296,6 +299,47 @@ export class ComposeService { }), ); + await Promise.all( + (presetData.httpsProxies || []) + .filter((d) => !d.excludeDockerService) + .map(async (n) => { + const internalPort = 443; + const host = n.host || presetData.nodes?.[0]?.host; + if (!host) { + throw new Error( + `HTTPS Proxy ${n.name} is invalid, 'host' property could not be resolved. It must be set to a valid DNS record.`, + ); + } + const domains: string | undefined = + n.domains || + presetData.gateways?.map((g) => resolveHttpsProxyDomains(host, `http://${g.name}:${restInternalPort}`))[0]; + if (!domains) { + throw new Error(`HTTPS Proxy ${n.name} is invalid, 'domains' property could not be resolved!`); + } + services.push( + await resolveService(n, { + container_name: n.name, + image: presetData.httpsPortalImage, + stop_signal: 'SIGINT', + ports: resolvePorts([ + { internalPort: 80, openPort: true }, + { internalPort: internalPort, openPort: n.openPort }, + ]), + environment: { + DOMAINS: domains, + WEBSOCKET: n.webSocket, + STAGE: n.stage, + SERVER_NAMES_HASH_BUCKET_SIZE: n.serverNamesHashBucketSize, + }, + restart: restart, + depends_on: [presetData.gateways![0].name], + ...this.resolveDebugOptions(presetData.dockerComposeDebugMode, n.dockerComposeDebugMode), + ...n.compose, + }), + ); + }), + ); + await Promise.all( (presetData.wallets || []) .filter((d) => !d.excludeDockerService) diff --git a/src/service/ConfigService.ts b/src/service/ConfigService.ts index e3d04f598..25722781a 100644 --- a/src/service/ConfigService.ts +++ b/src/service/ConfigService.ts @@ -692,6 +692,30 @@ export class ConfigService { [], ['node.crt.pem', 'node.key.pem', 'ca.cert.pem'], ); + + if (gatewayPreset.restProtocol === 'HTTPS') { + if (gatewayPreset.restSSLKeyBase64 && gatewayPreset.restSSLCertificateBase64) { + fs.writeFileSync(join(moveTo, presetData.restSSLKeyFileName), gatewayPreset.restSSLKeyBase64, 'base64'); + fs.writeFileSync( + join(moveTo, presetData.restSSLCertificateFileName), + gatewayPreset.restSSLCertificateBase64, + 'base64', + ); + } else { + if ( + !existsSync(join(moveTo, presetData.restSSLKeyFileName)) && + !existsSync(join(moveTo, presetData.restSSLCertificateFileName)) + ) { + throw new KnownError( + `Native SSL is enabled but restSSLKeyBase64 or restSSLCertificateBase64 properties are not found in the custom-preset file! Either use 'symbol-bootstrap wizard' command to fill those properties in the custom-preset or make sure you copy your SSL key and cert files to ${moveTo} folder.`, + ); + } else { + logger.info( + `Native SSL certificates for gateway ${gatewayPreset.name} have been previously provided. Reusing...`, + ); + } + } + } }), ); } @@ -809,7 +833,10 @@ export class ConfigService { }); (presetData.gateways || []).forEach(({ name }) => { const configFolder = BootstrapUtils.getTargetGatewayFolder(target, false, name); - BootstrapUtils.deleteFolder(configFolder); + BootstrapUtils.deleteFolder(configFolder, [ + join(configFolder, presetData.restSSLKeyFileName), + join(configFolder, presetData.restSSLCertificateFileName), + ]); }); } } diff --git a/src/service/CryptoUtils.ts b/src/service/CryptoUtils.ts index b1aaeef1f..464b3f04e 100644 --- a/src/service/CryptoUtils.ts +++ b/src/service/CryptoUtils.ts @@ -20,6 +20,7 @@ import { KnownError } from './BootstrapUtils'; export class CryptoUtils { private static readonly ENCRYPT_PREFIX = 'ENCRYPTED:'; + private static readonly ENCRYPTABLE_KEYS = ['privateKey', 'restSSLKeyBase64']; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types public static encrypt(value: any, password: string, fieldName?: string): any { @@ -34,7 +35,7 @@ export class CryptoUtils { return _.mapValues(value, (value: any, name: string) => CryptoUtils.encrypt(value, password, name)); } - if (this.isPrivateKeyField(value, fieldName)) { + if (this.isEncryptableKeyField(value, fieldName)) { return CryptoUtils.ENCRYPT_PREFIX + Crypto.encrypt(value, password); } return value; @@ -81,7 +82,7 @@ export class CryptoUtils { const isBlacklisted = !blacklistNames.length || blacklistNames.find((blacklistName) => name.toLowerCase().indexOf(blacklistName.toLowerCase()) > -1); - return !isBlacklisted || !this.isPrivateKeyField(value, name); + return !isBlacklisted || !this.isEncryptableKeyField(value, name); }), (value: any, name: string) => { const isBlacklisted = @@ -106,7 +107,7 @@ export class CryptoUtils { if (_.isObject(value)) { return _.mapValues(value, (value: any, name: string) => CryptoUtils.decrypt(value, password, name)); } - if (this.isPrivateKeyField(value, fieldName) && value.startsWith(CryptoUtils.ENCRYPT_PREFIX)) { + if (this.isEncryptableKeyField(value, fieldName) && value.startsWith(CryptoUtils.ENCRYPT_PREFIX)) { let decryptedValue; try { const encryptedValue = value.substring(CryptoUtils.ENCRYPT_PREFIX.length); @@ -134,13 +135,17 @@ export class CryptoUtils { if (_.isObject(value)) { return _.sum(Object.entries(value).map(([fieldName, value]) => this.encryptedCount(value, fieldName))); } - if (this.isPrivateKeyField(value, fieldName) && value.startsWith(CryptoUtils.ENCRYPT_PREFIX)) { + if (this.isEncryptableKeyField(value, fieldName) && value.startsWith(CryptoUtils.ENCRYPT_PREFIX)) { return 1; } return 0; } - private static isPrivateKeyField(value: any, fieldName: string | undefined) { - return _.isString(value) && fieldName && fieldName.toLowerCase().endsWith('privatekey'); + private static isEncryptableKeyField(value: any, fieldName: string | undefined) { + return ( + _.isString(value) && + fieldName && + CryptoUtils.ENCRYPTABLE_KEYS.some((key) => fieldName.toLowerCase().endsWith(key.toLowerCase())) + ); } } diff --git a/test/certificates/restSsl.crt b/test/certificates/restSsl.crt new file mode 100644 index 000000000..210657448 --- /dev/null +++ b/test/certificates/restSsl.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICEjCCAXsCAg36MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG +A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE +MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl +YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw +ODIyMDUyNjU0WhcNMTcwODIxMDUyNjU0WjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE +CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs +ZS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAm/xmkHmEQrurE/0re/jeFRLl +8ZPjBop7uLHhnia7lQG/5zDtZIUC3RVpqDSwBuw/NTweGyuP+o8AG98HxqxTBwID +AQABMA0GCSqGSIb3DQEBBQUAA4GBABS2TLuBeTPmcaTaUW/LCB2NYOy8GMdzR1mx +8iBIu2H6/E2tiY3RIevV2OW61qY2/XRQg7YPxx3ffeUugX9F4J/iPnnu1zAxxyBy +2VguKv4SWjRFoRkIfIlHX0qVviMhSlNy2ioFLy7JcPZb+v3ftDGywUqcBiVDoea0 +Hn+GmxZA +-----END CERTIFICATE----- diff --git a/test/certificates/restSsl.key b/test/certificates/restSsl.key new file mode 100644 index 000000000..bc4edabce --- /dev/null +++ b/test/certificates/restSsl.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBAJv8ZpB5hEK7qxP9K3v43hUS5fGT4waKe7ix4Z4mu5UBv+cw7WSF +At0Vaag0sAbsPzU8Hhsrj/qPABvfB8asUwcCAwEAAQJAG0r3ezH35WFG1tGGaUOr +QA61cyaII53ZdgCR1IU8bx7AUevmkFtBf+aqMWusWVOWJvGu2r5VpHVAIl8nF6DS +kQIhAMjEJ3zVYa2/Mo4ey+iU9J9Vd+WoyXDQD4EEtwmyG1PpAiEAxuZlvhDIbbce +7o5BvOhnCZ2N7kYb1ZC57g3F+cbJyW8CIQCbsDGHBto2qJyFxbAO7uQ8Y0UVHa0J +BO/g900SAcJbcQIgRtEljIShOB8pDjrsQPxmI1BLhnjD1EhRSubwhDw5AFUCIQCN +A24pDtdOHydwtSB5+zFqFLfmVZplQM/g5kb4so70Yw== +-----END RSA PRIVATE KEY----- diff --git a/test/commands/Wizard.test.ts b/test/commands/Wizard.test.ts index a5fd2d67d..400fde86a 100644 --- a/test/commands/Wizard.test.ts +++ b/test/commands/Wizard.test.ts @@ -82,6 +82,9 @@ describe('Wizard', () => { '\n', 'EEE3F0EF0AB368B8D7AC194D52A8CCFA2D5050B80B9C76E4D2F4D4BF2CD461C1\n', 'y\n', + StdUtils.keys.down, // resolveHttpsOptions select none down 1/2 + StdUtils.keys.down, // resolveHttpsOptions select none down 2/2 + '\n', 'myhostname\n', 'myfriendlyname\n', '\n', @@ -140,6 +143,67 @@ describe('Wizard', () => { '\n', '\n', '\n', + StdUtils.keys.down, // resolveHttpsOptions select none down 1 + StdUtils.keys.down, // resolveHttpsOptions select none down 2 + '\n', + 'myhostname\n', + 'myfriendlyname\n', + '\n', + 'y\n', + // '\n', + // '\n', + // 'y\n', + ]); + + const customPresetFile = `${testFolder}/wizard-custom.yml`; + const password = '11111'; + await Wizard.execute(BootstrapUtils.resolveRootFolder(), { + customPreset: customPresetFile, + network: Network.mainnet, + noPassword: false, + skipPull: true, + target: `${testFolder}/target`, + password: password, + }); + const expectedCustomPreset: CustomPreset = { + assembly: 'dual', + nodes: [ + { + friendlyName: 'myfriendlyname', + host: 'myhostname', + mainPrivateKey: '0000000000000000000000000000000000000000000000000000000000000001', + remotePrivateKey: '0000000000000000000000000000000000000000000000000000000000000004', + transportPrivateKey: '0000000000000000000000000000000000000000000000000000000000000002', + voting: true, + vrfPrivateKey: '0000000000000000000000000000000000000000000000000000000000000003', + }, + ], + preset: Preset.mainnet, + privateKeySecurityMode: PrivateKeySecurityMode.PROMPT_MAIN_TRANSPORT, + }; + const customPreset = BootstrapUtils.loadYaml(customPresetFile, password); + expect(customPreset).deep.eq(expectedCustomPreset); + }); + + it('Enables httpsProxy on rest-gateway', async () => { + const toKey = (prefix: string | number, keySize = 64): string => { + return prefix.toString().padStart(keySize, '0'); + }; + let index = 0; + Wizard.generateAccount = (networkType: NetworkType) => { + return Account.createFromPrivateKey(toKey(++index), networkType); + }; + // assembly + StdUtils.in([ + '\n', + 'y\n', //Are you offline. + '\n', + '\n', + '\n', + '\n', + '\n', + StdUtils.keys.down, // resolveHttpsOptions select Automatic + '\n', 'myhostname\n', 'myfriendlyname\n', '\n', @@ -160,7 +224,9 @@ describe('Wizard', () => { password: password, }); const expectedCustomPreset: CustomPreset = { + preset: Preset.mainnet, assembly: 'dual', + privateKeySecurityMode: PrivateKeySecurityMode.PROMPT_MAIN_TRANSPORT, nodes: [ { friendlyName: 'myfriendlyname', @@ -172,9 +238,84 @@ describe('Wizard', () => { vrfPrivateKey: '0000000000000000000000000000000000000000000000000000000000000003', }, ], + httpsProxies: [ + { + excludeDockerService: false, + }, + ], + }; + console.log(BootstrapUtils.toYaml(expectedCustomPreset)); + const customPreset = BootstrapUtils.loadYaml(customPresetFile, password); + expect(customPreset).deep.eq(expectedCustomPreset); + }); + + it('Enables native SSL support on rest-gateway', async () => { + const toKey = (prefix: string | number, keySize = 64): string => { + return prefix.toString().padStart(keySize, '0'); + }; + let index = 0; + Wizard.generateAccount = (networkType: NetworkType) => { + return Account.createFromPrivateKey(toKey(++index), networkType); + }; + // assembly + StdUtils.in([ + '\n', + 'y\n', //Are you offline. + '\n', + '\n', + '\n', + '\n', + '\n', + '\n', // resolveHttpsOptions select Native + 'myhostname\n', + './test/certificates/restSsl.key\n', + './test/certificates/restSsl.crt\n', + 'myfriendlyname\n', + '\n', + 'y\n', + // '\n', + // '\n', + // 'y\n', + ]); + + const customPresetFile = `${testFolder}/wizard-custom.yml`; + const password = '11111'; + await Wizard.execute(BootstrapUtils.resolveRootFolder(), { + customPreset: customPresetFile, + network: Network.mainnet, + noPassword: false, + skipPull: true, + target: `${testFolder}/target`, + password: password, + }); + const expectedCustomPreset: CustomPreset = { preset: Preset.mainnet, + assembly: 'dual', privateKeySecurityMode: PrivateKeySecurityMode.PROMPT_MAIN_TRANSPORT, + nodes: [ + { + friendlyName: 'myfriendlyname', + host: 'myhostname', + mainPrivateKey: '0000000000000000000000000000000000000000000000000000000000000001', + remotePrivateKey: '0000000000000000000000000000000000000000000000000000000000000004', + transportPrivateKey: '0000000000000000000000000000000000000000000000000000000000000002', + voting: true, + vrfPrivateKey: '0000000000000000000000000000000000000000000000000000000000000003', + }, + ], + gateways: [ + { + restProtocol: 'HTTPS', + openPort: 3001, + restSSLCertificateBase64: + 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFakNDQVhzQ0FnMzZNQTBHQ1NxR1NJYjNEUUVCQlFVQU1JR2JNUXN3Q1FZRFZRUUdFd0pLVURFT01Bd0cKQTFVRUNCTUZWRzlyZVc4eEVEQU9CZ05WQkFjVEIwTm9kVzh0YTNVeEVUQVBCZ05WQkFvVENFWnlZVzVyTkVSRQpNUmd3RmdZRFZRUUxFdzlYWldKRFpYSjBJRk4xY0hCdmNuUXhHREFXQmdOVkJBTVREMFp5WVc1ck5FUkVJRmRsCllpQkRRVEVqTUNFR0NTcUdTSWIzRFFFSkFSWVVjM1Z3Y0c5eWRFQm1jbUZ1YXpSa1pDNWpiMjB3SGhjTk1USXcKT0RJeU1EVXlOalUwV2hjTk1UY3dPREl4TURVeU5qVTBXakJLTVFzd0NRWURWUVFHRXdKS1VERU9NQXdHQTFVRQpDQXdGVkc5cmVXOHhFVEFQQmdOVkJBb01DRVp5WVc1ck5FUkVNUmd3RmdZRFZRUUREQTkzZDNjdVpYaGhiWEJzClpTNWpiMjB3WERBTkJna3Foa2lHOXcwQkFRRUZBQU5MQURCSUFrRUFtL3hta0htRVFydXJFLzByZS9qZUZSTGwKOFpQakJvcDd1TEhobmlhN2xRRy81ekR0WklVQzNSVnBxRFN3QnV3L05Ud2VHeXVQK284QUc5OEh4cXhUQndJRApBUUFCTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUJTMlRMdUJlVFBtY2FUYVVXL0xDQjJOWU95OEdNZHpSMW14CjhpQkl1Mkg2L0UydGlZM1JJZXZWMk9XNjFxWTIvWFJRZzdZUHh4M2ZmZVV1Z1g5RjRKL2lQbm51MXpBeHh5QnkKMlZndUt2NFNXalJGb1JrSWZJbEhYMHFWdmlNaFNsTnkyaW9GTHk3SmNQWmIrdjNmdERHeXdVcWNCaVZEb2VhMApIbitHbXhaQQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==', + restSSLKeyBase64: + 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCT3dJQkFBSkJBSnY4WnBCNWhFSzdxeFA5SzN2NDNoVVM1ZkdUNHdhS2U3aXg0WjRtdTVVQnYrY3c3V1NGCkF0MFZhYWcwc0Fic1B6VThIaHNyai9xUEFCdmZCOGFzVXdjQ0F3RUFBUUpBRzByM2V6SDM1V0ZHMXRHR2FVT3IKUUE2MWN5YUlJNTNaZGdDUjFJVThieDdBVWV2bWtGdEJmK2FxTVd1c1dWT1dKdkd1MnI1VnBIVkFJbDhuRjZEUwprUUloQU1qRUozelZZYTIvTW80ZXkraVU5SjlWZCtXb3lYRFFENEVFdHdteUcxUHBBaUVBeHVabHZoREliYmNlCjdvNUJ2T2huQ1oyTjdrWWIxWkM1N2czRitjYkp5VzhDSVFDYnNER0hCdG8ycUp5RnhiQU83dVE4WTBVVkhhMEoKQk8vZzkwMFNBY0piY1FJZ1J0RWxqSVNoT0I4cERqcnNRUHhtSTFCTGhuakQxRWhSU3Vid2hEdzVBRlVDSVFDTgpBMjRwRHRkT0h5ZHd0U0I1K3pGcUZMZm1WWnBsUU0vZzVrYjRzbzcwWXc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=', + }, + ], }; + + console.log(BootstrapUtils.toYaml(expectedCustomPreset)); const customPreset = BootstrapUtils.loadYaml(customPresetFile, password); expect(customPreset).deep.eq(expectedCustomPreset); }); diff --git a/test/composes/expected-docker-compose-bootstrap-custom-compose.yml b/test/composes/expected-docker-compose-bootstrap-custom-compose.yml index b8a6df29d..bc88b4529 100644 --- a/test/composes/expected-docker-compose-bootstrap-custom-compose.yml +++ b/test/composes/expected-docker-compose-bootstrap-custom-compose.yml @@ -105,7 +105,7 @@ services: rest-gateway-0: container_name: rest-gateway-0 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-docker-compose-bootstrap-custom.yml b/test/composes/expected-docker-compose-bootstrap-custom.yml index 7a21f15eb..8553a3bfc 100644 --- a/test/composes/expected-docker-compose-bootstrap-custom.yml +++ b/test/composes/expected-docker-compose-bootstrap-custom.yml @@ -103,7 +103,7 @@ services: rest-gateway-0: container_name: rest-gateway-0 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-docker-compose-bootstrap-full.yml b/test/composes/expected-docker-compose-bootstrap-full.yml index cb42bb3b5..c669fe5e5 100644 --- a/test/composes/expected-docker-compose-bootstrap-full.yml +++ b/test/composes/expected-docker-compose-bootstrap-full.yml @@ -108,7 +108,7 @@ services: rest-gateway-0: container_name: rest-gateway-0 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-docker-compose-bootstrap-repeat.yml b/test/composes/expected-docker-compose-bootstrap-repeat.yml index a3ab1f359..92b832e13 100644 --- a/test/composes/expected-docker-compose-bootstrap-repeat.yml +++ b/test/composes/expected-docker-compose-bootstrap-repeat.yml @@ -249,7 +249,7 @@ services: rest-gateway-0: container_name: rest-gateway-0 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir @@ -266,7 +266,7 @@ services: rest-gateway-1: container_name: rest-gateway-1 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir @@ -283,7 +283,7 @@ services: rest-gateway-2: container_name: rest-gateway-2 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir @@ -300,7 +300,7 @@ services: rest-gateway-3: container_name: rest-gateway-3 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-docker-compose-bootstrap.yml b/test/composes/expected-docker-compose-bootstrap.yml index f2915689c..560db14b4 100644 --- a/test/composes/expected-docker-compose-bootstrap.yml +++ b/test/composes/expected-docker-compose-bootstrap.yml @@ -87,7 +87,7 @@ services: rest-gateway-0: container_name: rest-gateway-0 user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-mainnet-api-compose.yml b/test/composes/expected-mainnet-api-compose.yml index 602cdd629..42e223d4c 100644 --- a/test/composes/expected-mainnet-api-compose.yml +++ b/test/composes/expected-mainnet-api-compose.yml @@ -44,7 +44,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-mainnet-dual-compose.yml b/test/composes/expected-mainnet-dual-compose.yml index 602cdd629..42e223d4c 100644 --- a/test/composes/expected-mainnet-dual-compose.yml +++ b/test/composes/expected-mainnet-dual-compose.yml @@ -44,7 +44,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-testnet-api-compose.yml b/test/composes/expected-testnet-api-compose.yml index 602cdd629..42e223d4c 100644 --- a/test/composes/expected-testnet-api-compose.yml +++ b/test/composes/expected-testnet-api-compose.yml @@ -44,7 +44,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-testnet-dual-compose.yml b/test/composes/expected-testnet-dual-compose.yml index 602cdd629..42e223d4c 100644 --- a/test/composes/expected-testnet-dual-compose.yml +++ b/test/composes/expected-testnet-dual-compose.yml @@ -44,7 +44,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-testnet-httpsproxy-compose.yml b/test/composes/expected-testnet-httpsproxy-compose.yml new file mode 100644 index 000000000..0660dd8f2 --- /dev/null +++ b/test/composes/expected-testnet-httpsproxy-compose.yml @@ -0,0 +1,85 @@ +version: '2.4' +services: + db: + user: '1000:1000' + environment: + MONGO_INITDB_DATABASE: catapult + container_name: db + image: 'mongo:4.4.3-bionic' + command: mongod --dbpath=/dbdata --bind_ip=db --wiredTigerCacheSizeGB 2 + stop_signal: SIGINT + working_dir: /docker-entrypoint-initdb.d + volumes: + - './mongo:/docker-entrypoint-initdb.d:ro' + - '../databases/db:/dbdata:rw' + node: + user: '1000:1000' + container_name: node + image: 'symbolplatform/symbol-server:gcc-10-1.0.1.0' + command: /bin/bash /symbol-commands/start.sh /usr/catapult ./data server broker node NORMAL true + stop_signal: SIGINT + working_dir: /symbol-workdir + restart: 'on-failure:2' + ports: + - '7900:7900' + volumes: + - '../nodes/node:/symbol-workdir:rw' + - './server:/symbol-commands:ro' + depends_on: + - db + - broker + networks: + default: + aliases: + - symbol-node-2.rockbear.io + hostname: symbol-node-2.rockbear.io + broker: + user: '1000:1000' + container_name: broker + image: 'symbolplatform/symbol-server:gcc-10-1.0.1.0' + working_dir: /symbol-workdir + command: /bin/bash /symbol-commands/start.sh /usr/catapult ./data broker server broker NORMAL + stop_signal: SIGINT + restart: 'on-failure:2' + volumes: + - '../nodes/node:/symbol-workdir:rw' + - './server:/symbol-commands:ro' + depends_on: + - db + rest-gateway: + container_name: rest-gateway + user: '1000:1000' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' + command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json + stop_signal: SIGINT + working_dir: /symbol-workdir + ports: + - '3000:3000' + restart: 'on-failure:2' + volumes: + - '../gateways/rest-gateway:/symbol-workdir:rw' + depends_on: + - db + networks: + default: + ipv4_address: 172.20.0.25 + https-proxy: + container_name: https-proxy + image: 'steveltn/https-portal:1.19' + stop_signal: SIGINT + ports: + - '80:80' + - '3001:443' + environment: + DOMAINS: 'symbol-node-2.rockbear.io -> http://rest-gateway:3000' + WEBSOCKET: 'true' + STAGE: production + SERVER_NAMES_HASH_BUCKET_SIZE: 128 + restart: 'on-failure:2' + depends_on: + - rest-gateway +networks: + default: + ipam: + config: + - subnet: 172.20.0.0/24 diff --git a/test/composes/expected-testnet-native-ssl-compose.yml b/test/composes/expected-testnet-native-ssl-compose.yml new file mode 100644 index 000000000..09dd4d788 --- /dev/null +++ b/test/composes/expected-testnet-native-ssl-compose.yml @@ -0,0 +1,70 @@ +version: '2.4' +services: + db: + user: '1000:1000' + environment: + MONGO_INITDB_DATABASE: catapult + container_name: db + image: 'mongo:4.4.3-bionic' + command: mongod --dbpath=/dbdata --bind_ip=db --wiredTigerCacheSizeGB 2 + stop_signal: SIGINT + working_dir: /docker-entrypoint-initdb.d + volumes: + - './mongo:/docker-entrypoint-initdb.d:ro' + - '../databases/db:/dbdata:rw' + node: + user: '1000:1000' + container_name: node + image: 'symbolplatform/symbol-server:gcc-10-1.0.1.0' + command: /bin/bash /symbol-commands/start.sh /usr/catapult ./data server broker node NORMAL true + stop_signal: SIGINT + working_dir: /symbol-workdir + restart: 'on-failure:2' + ports: + - '7900:7900' + volumes: + - '../nodes/node:/symbol-workdir:rw' + - './server:/symbol-commands:ro' + depends_on: + - db + - broker + networks: + default: + aliases: + - symbol-node-2.rockbear.io + hostname: symbol-node-2.rockbear.io + broker: + user: '1000:1000' + container_name: broker + image: 'symbolplatform/symbol-server:gcc-10-1.0.1.0' + working_dir: /symbol-workdir + command: /bin/bash /symbol-commands/start.sh /usr/catapult ./data broker server broker NORMAL + stop_signal: SIGINT + restart: 'on-failure:2' + volumes: + - '../nodes/node:/symbol-workdir:rw' + - './server:/symbol-commands:ro' + depends_on: + - db + rest-gateway: + container_name: rest-gateway + user: '1000:1000' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' + command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json + stop_signal: SIGINT + working_dir: /symbol-workdir + ports: + - '3001:3000' + restart: 'on-failure:2' + volumes: + - '../gateways/rest-gateway:/symbol-workdir:rw' + depends_on: + - db + networks: + default: + ipv4_address: 172.20.0.25 +networks: + default: + ipam: + config: + - subnet: 172.20.0.0/24 diff --git a/test/composes/expected-testnet-supernode-compose.yml b/test/composes/expected-testnet-supernode-compose.yml index b86054f9d..d994ce4f4 100644 --- a/test/composes/expected-testnet-supernode-compose.yml +++ b/test/composes/expected-testnet-supernode-compose.yml @@ -61,7 +61,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/composes/expected-testnet-voting-compose.yml b/test/composes/expected-testnet-voting-compose.yml index 602cdd629..42e223d4c 100644 --- a/test/composes/expected-testnet-voting-compose.yml +++ b/test/composes/expected-testnet-voting-compose.yml @@ -44,7 +44,7 @@ services: rest-gateway: container_name: rest-gateway user: '1000:1000' - image: 'symbolplatform/symbol-rest:2.3.6' + image: 'symbolplatform/symbol-rest:2.3.7-alpha' command: npm start --prefix /app/catapult-rest/rest /symbol-workdir/rest.json stop_signal: SIGINT working_dir: /symbol-workdir diff --git a/test/reports/bootstrap-voting/rest-gateway-0-rest.json b/test/reports/bootstrap-voting/rest-gateway-0-rest.json index 7ece67cf8..7c8d42755 100644 --- a/test/reports/bootstrap-voting/rest-gateway-0-rest.json +++ b/test/reports/bootstrap-voting/rest-gateway-0-rest.json @@ -4,6 +4,9 @@ "description": "catapult development network" }, "port": 3000, + "protocol": "HTTP", + "sslKeyPath": "/symbol-workdir/restSSL.key", + "sslCertificatePath": "/symbol-workdir/restSSL.crt", "crossDomain": { "allowedHosts": [ "*" diff --git a/test/reports/mainnet-dual-voting/rest-gateway-rest.json b/test/reports/mainnet-dual-voting/rest-gateway-rest.json index 060614d72..0ea8a7b33 100644 --- a/test/reports/mainnet-dual-voting/rest-gateway-rest.json +++ b/test/reports/mainnet-dual-voting/rest-gateway-rest.json @@ -4,6 +4,9 @@ "description": "catapult public main network" }, "port": 3000, + "protocol": "HTTP", + "sslKeyPath": "/symbol-workdir/restSSL.key", + "sslCertificatePath": "/symbol-workdir/restSSL.crt", "crossDomain": { "allowedHosts": [ "*" diff --git a/test/reports/mainnet-dual/rest-gateway-rest.json b/test/reports/mainnet-dual/rest-gateway-rest.json index 060614d72..0ea8a7b33 100644 --- a/test/reports/mainnet-dual/rest-gateway-rest.json +++ b/test/reports/mainnet-dual/rest-gateway-rest.json @@ -4,6 +4,9 @@ "description": "catapult public main network" }, "port": 3000, + "protocol": "HTTP", + "sslKeyPath": "/symbol-workdir/restSSL.key", + "sslCertificatePath": "/symbol-workdir/restSSL.crt", "crossDomain": { "allowedHosts": [ "*" diff --git a/test/reports/testnet-api/rest-gateway-rest.json b/test/reports/testnet-api/rest-gateway-rest.json index d01383936..0a3f459a6 100644 --- a/test/reports/testnet-api/rest-gateway-rest.json +++ b/test/reports/testnet-api/rest-gateway-rest.json @@ -4,6 +4,9 @@ "description": "catapult public test network" }, "port": 3000, + "protocol": "HTTP", + "sslKeyPath": "/symbol-workdir/restSSL.key", + "sslCertificatePath": "/symbol-workdir/restSSL.crt", "crossDomain": { "allowedHosts": [ "*" diff --git a/test/reports/testnet-dual-voting/rest-gateway-rest.json b/test/reports/testnet-dual-voting/rest-gateway-rest.json index 8cbda7298..45e48467a 100644 --- a/test/reports/testnet-dual-voting/rest-gateway-rest.json +++ b/test/reports/testnet-dual-voting/rest-gateway-rest.json @@ -4,6 +4,9 @@ "description": "catapult public test network" }, "port": 3000, + "protocol": "HTTP", + "sslKeyPath": "/symbol-workdir/restSSL.key", + "sslCertificatePath": "/symbol-workdir/restSSL.crt", "crossDomain": { "allowedHosts": [ "*" diff --git a/test/service/ComposeService.test.ts b/test/service/ComposeService.test.ts index 2a831824b..796b8b211 100644 --- a/test/service/ComposeService.test.ts +++ b/test/service/ComposeService.test.ts @@ -158,6 +158,34 @@ ${BootstrapUtils.toYaml(dockerCompose)} await assertDockerCompose(params, 'expected-testnet-supernode-compose.yml'); }); + it('Compose testnet httpsProxy', async () => { + const params = { + ...ConfigService.defaultParams, + ...LinkService.defaultParams, + target: 'target/tests/testnet-https-proxy', + password, + customPreset: './test/unit-test-profiles/https-proxy.yml', + reset: false, + preset: Preset.testnet, + assembly: 'dual', + }; + await assertDockerCompose(params, 'expected-testnet-httpsproxy-compose.yml'); + }); + + it('Compose testnet native ssl', async () => { + const params = { + ...ConfigService.defaultParams, + ...LinkService.defaultParams, + target: 'target/tests/testnet-native-ssl', + password, + customPreset: './test/unit-test-profiles/native-ssl.yml', + reset: false, + preset: Preset.testnet, + assembly: 'dual', + }; + await assertDockerCompose(params, 'expected-testnet-native-ssl-compose.yml'); + }); + it('Compose testnet dual voting', async () => { const params = { ...ConfigService.defaultParams, diff --git a/test/service/VerifyService.test.ts b/test/service/VerifyService.test.ts index 664dfc4de..caca7ea80 100644 --- a/test/service/VerifyService.test.ts +++ b/test/service/VerifyService.test.ts @@ -67,8 +67,8 @@ describe('VerifyService', () => { it('VerifyService verify current installation when too old', async () => { const expectedVersions = { node: '18.0.0', - docker: '19.4.0', - dockerCompose: '1.25.30', + docker: '21.4.0', + dockerCompose: '1.29.5', }; const service = new VerifyService(BootstrapUtils.resolveRootFolder(), expectedVersions); const currentDockerVersion = await service.loadVersionFromCommand('docker --version'); diff --git a/test/supernode.yml b/test/supernode.yml index 1d021f4ff..896bd7559 100644 --- a/test/supernode.yml +++ b/test/supernode.yml @@ -6,7 +6,7 @@ votingKeyDesiredLifetime: 28 # create short voting key files, 28 is the minimun #votingKeyDesiredFutureLifetime: 300 # create files for at least 60 epochs in the future, this will create voting key file 2 and file 3 useExperimentalNativeVotingKeyGeneration: true # Use new native ts generation symbolServerImage: symbolplatform/symbol-server-private:gcc-voting-key-unlink-rollback-f2633f4a4c -symbolRestImage: 'symbolplatform/symbol-rest:2.3.6-alpha' +symbolRestImage: 'symbolplatform/symbol-rest:2.3.7-alpha' nodes: - voting: true rewardProgram: 'supernode' diff --git a/test/unit-test-profiles/https-proxy.yml b/test/unit-test-profiles/https-proxy.yml new file mode 100644 index 000000000..2141153ac --- /dev/null +++ b/test/unit-test-profiles/https-proxy.yml @@ -0,0 +1,11 @@ +privateKeySecurityMode: PROMPT_MAIN_TRANSPORT +nodes: + - host: symbol-node-2.rockbear.io + voting: false + friendlyName: symbol-node-2.rockbear.io + mainPrivateKey: 36AB6EE63C77C59351C68285C981E2F7E00E0065FC408C67C550F54D2B265B96 + vrfPrivateKey: D7DCF460F26ABABD01E58A3F8AA02CFE6AC3A0DB16522BDD5F396D274620310A + remotePrivateKey: 08CFC6BD0ABADEBF5C41371353BB79D572122C4858EE1135184237F3BF8DFF5B + transportPrivateKey: A88098E203E3CBA75433361EF7F59B767A82CEB9766F7735F9BD6AE1B204021A +httpsProxies: + - excludeDockerService: false diff --git a/test/unit-test-profiles/native-ssl.yml b/test/unit-test-profiles/native-ssl.yml new file mode 100644 index 000000000..b004bdb24 --- /dev/null +++ b/test/unit-test-profiles/native-ssl.yml @@ -0,0 +1,16 @@ +privateKeySecurityMode: PROMPT_MAIN_TRANSPORT +nodes: + - host: symbol-node-2.rockbear.io + voting: false + friendlyName: symbol-node-2.rockbear.io + mainPrivateKey: 36AB6EE63C77C59351C68285C981E2F7E00E0065FC408C67C550F54D2B265B96 + vrfPrivateKey: D7DCF460F26ABABD01E58A3F8AA02CFE6AC3A0DB16522BDD5F396D274620310A + remotePrivateKey: 08CFC6BD0ABADEBF5C41371353BB79D572122C4858EE1135184237F3BF8DFF5B + transportPrivateKey: A88098E203E3CBA75433361EF7F59B767A82CEB9766F7735F9BD6AE1B204021A +gateways: + - restProtocol: HTTPS + openPort: 3001 + restSSLCertificateBase64: >- + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFakNDQVhzQ0FnMzZNQTBHQ1NxR1NJYjNEUUVCQlFVQU1JR2JNUXN3Q1FZRFZRUUdFd0pLVURFT01Bd0cKQTFVRUNCTUZWRzlyZVc4eEVEQU9CZ05WQkFjVEIwTm9kVzh0YTNVeEVUQVBCZ05WQkFvVENFWnlZVzVyTkVSRQpNUmd3RmdZRFZRUUxFdzlYWldKRFpYSjBJRk4xY0hCdmNuUXhHREFXQmdOVkJBTVREMFp5WVc1ck5FUkVJRmRsCllpQkRRVEVqTUNFR0NTcUdTSWIzRFFFSkFSWVVjM1Z3Y0c5eWRFQm1jbUZ1YXpSa1pDNWpiMjB3SGhjTk1USXcKT0RJeU1EVXlOalUwV2hjTk1UY3dPREl4TURVeU5qVTBXakJLTVFzd0NRWURWUVFHRXdKS1VERU9NQXdHQTFVRQpDQXdGVkc5cmVXOHhFVEFQQmdOVkJBb01DRVp5WVc1ck5FUkVNUmd3RmdZRFZRUUREQTkzZDNjdVpYaGhiWEJzClpTNWpiMjB3WERBTkJna3Foa2lHOXcwQkFRRUZBQU5MQURCSUFrRUFtL3hta0htRVFydXJFLzByZS9qZUZSTGwKOFpQakJvcDd1TEhobmlhN2xRRy81ekR0WklVQzNSVnBxRFN3QnV3L05Ud2VHeXVQK284QUc5OEh4cXhUQndJRApBUUFCTUEwR0NTcUdTSWIzRFFFQkJRVUFBNEdCQUJTMlRMdUJlVFBtY2FUYVVXL0xDQjJOWU95OEdNZHpSMW14CjhpQkl1Mkg2L0UydGlZM1JJZXZWMk9XNjFxWTIvWFJRZzdZUHh4M2ZmZVV1Z1g5RjRKL2lQbm51MXpBeHh5QnkKMlZndUt2NFNXalJGb1JrSWZJbEhYMHFWdmlNaFNsTnkyaW9GTHk3SmNQWmIrdjNmdERHeXdVcWNCaVZEb2VhMApIbitHbXhaQQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + restSSLKeyBase64: >- + LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCT3dJQkFBSkJBSnY4WnBCNWhFSzdxeFA5SzN2NDNoVVM1ZkdUNHdhS2U3aXg0WjRtdTVVQnYrY3c3V1NGCkF0MFZhYWcwc0Fic1B6VThIaHNyai9xUEFCdmZCOGFzVXdjQ0F3RUFBUUpBRzByM2V6SDM1V0ZHMXRHR2FVT3IKUUE2MWN5YUlJNTNaZGdDUjFJVThieDdBVWV2bWtGdEJmK2FxTVd1c1dWT1dKdkd1MnI1VnBIVkFJbDhuRjZEUwprUUloQU1qRUozelZZYTIvTW80ZXkraVU5SjlWZCtXb3lYRFFENEVFdHdteUcxUHBBaUVBeHVabHZoREliYmNlCjdvNUJ2T2huQ1oyTjdrWWIxWkM1N2czRitjYkp5VzhDSVFDYnNER0hCdG8ycUp5RnhiQU83dVE4WTBVVkhhMEoKQk8vZzkwMFNBY0piY1FJZ1J0RWxqSVNoT0I4cERqcnNRUHhtSTFCTGhuakQxRWhSU3Vid2hEdzVBRlVDSVFDTgpBMjRwRHRkT0h5ZHd0U0I1K3pGcUZMZm1WWnBsUU0vZzVrYjRzbzcwWXc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=