Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 45080ea

Browse files
committed
Allow reverseProxy to terminate SSL
1 parent a4bc81e commit 45080ea

File tree

15 files changed

+113
-32
lines changed

15 files changed

+113
-32
lines changed

clients/nodejs/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ const $ = {};
170170

171171
const clientConfigBuilder = Nimiq.Client.Configuration.builder();
172172
clientConfigBuilder.protocol(config.protocol, config.host, config.port, config.tls.key, config.tls.cert);
173-
if (config.reverseProxy.enabled) clientConfigBuilder.reverseProxy(config.reverseProxy.port, config.reverseProxy.header, ...config.reverseProxy.addresses);
173+
if (config.reverseProxy.enabled) clientConfigBuilder.reverseProxy(config.reverseProxy.port, config.reverseProxy.header, config.reverseProxy.terminatesSsl, ...config.reverseProxy.addresses);
174174
if (config.passive) clientConfigBuilder.feature(Nimiq.Client.Feature.PASSIVE);
175175
if (config.type === 'full' || config.type === 'light') clientConfigBuilder.feature(Nimiq.Client.Feature.MEMPOOL);
176176
const clientConfig = clientConfigBuilder.build();
@@ -200,7 +200,7 @@ const $ = {};
200200
$.mempool = $.consensus.mempool;
201201
$.network = $.consensus.network;
202202

203-
Nimiq.Log.i(TAG, `Peer address: ${networkConfig.peerAddress.toString()} - public key: ${networkConfig.keyPair.publicKey.toHex()}`);
203+
Nimiq.Log.i(TAG, `Peer address: ${networkConfig.publicPeerAddress.toString()} - public key: ${networkConfig.keyPair.publicKey.toHex()}`);
204204

205205
// TODO: Wallet key.
206206
$.walletStore = await new Nimiq.WalletStore();

clients/nodejs/modules/Config.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const TAG = 'Config';
2222
* @property {{enabled: boolean, port: number}} uiServer
2323
* @property {{enabled: boolean, port: number, password: string}} metricsServer
2424
* @property {{seed: string, address: string}} wallet
25-
* @property {{enabled: boolean, port: number, address: string, addresses: Array.<string>, header: string}} reverseProxy
25+
* @property {{enabled: boolean, port: number, address: string, addresses: Array.<string>, header: string, terminatesSsl: boolean}} reverseProxy
2626
* @property {{level: string, tags: object}} log
2727
* @property {Array.<{host: string, port: number, publicKey: string, protocol: string}>} seedPeers
2828
* @property {object} constantOverrides
@@ -83,7 +83,8 @@ const DEFAULT_CONFIG = /** @type {Config} */ {
8383
port: 8444,
8484
address: '::ffff:127.0.0.1', // deprecated
8585
addresses: [],
86-
header: 'x-forwarded-for'
86+
header: 'x-forwarded-for',
87+
terminatesSsl: false
8788
},
8889
log: {
8990
level: 'info',
@@ -163,7 +164,8 @@ const CONFIG_TYPES = {
163164
port: 'number',
164165
address: 'string', // deprecated
165166
addresses: {type: 'array', inner: 'string'},
166-
header: 'string'
167+
header: 'string',
168+
terminatesSsl: 'boolean'
167169
}
168170
},
169171
log: {

clients/nodejs/modules/MetricsServer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class MetricsServer {
7979

8080
get _desc() {
8181
return {
82-
peer: this._network._networkConfig.peerAddress.toString()
82+
peer: this._network._networkConfig.internalPeerAddress.toString()
8383
};
8484
}
8585

clients/nodejs/sample.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@
191191
// Possible values: any valid HTTP header name
192192
// Default: "x-forwarded-for"
193193
//header: "x-forwarded-for"
194+
195+
// Set termination of SSL on the reverse proxy.
196+
// Default: false
197+
//terminatesSsl: true,
194198
},
195199

196200
// Configure log output. All output will go to STDOUT.

dist/types.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ declare class ClientConfigurationBuilder {
131131
public volatile(volatile?: boolean): this;
132132
public blockConfirmations(confirmations: number): this;
133133
public feature(...feature: Client.Feature[]): this;
134-
public reverseProxy(port: number, header: string, ...addresses: string[]): this;
134+
public reverseProxy(port: number, header: string, terminatesSsl: boolean, ...addresses: string[]): this;
135135
public build(): Client.Configuration;
136136
public instantiateClient(): Client;
137137
}
@@ -4014,13 +4014,13 @@ export class NetworkConfig {
40144014
export class WsNetworkConfig extends NetworkConfig {
40154015
public protocol: number;
40164016
public port: number;
4017-
public reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string };
4017+
public reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string, terminatesSsl: boolean };
40184018
public peerAddress: WsPeerAddress | WssPeerAddress;
40194019
public secure: boolean;
40204020
constructor(
40214021
host: string,
40224022
port: number,
4023-
reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string },
4023+
reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string, terminatesSsl: boolean },
40244024
);
40254025
}
40264026

@@ -4031,7 +4031,7 @@ export class WssNetworkConfig extends WsNetworkConfig {
40314031
port: number,
40324032
key: string,
40334033
cert: string,
4034-
reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string },
4034+
reverseProxy: { enabled: boolean, port: number, addresses: string[], header: string, terminatesSsl: boolean },
40354035
);
40364036
}
40374037

src/main/generic/api/Configuration.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,17 @@ Client.ConfigurationBuilder = class ConfigurationBuilder {
184184
/**
185185
* @param {number} port
186186
* @param {string} header
187+
* @param {boolean} terminatesSsl
187188
* @param {...string} addresses
188189
* @returns {Client.ConfigurationBuilder}
189190
*/
190-
reverseProxy(port, header, ...addresses) {
191+
reverseProxy(port, header, terminatesSsl, ...addresses) {
191192
if (this._protocol !== 'ws' && this._protocol !== 'wss') throw new Error('Protocol must be ws or wss for reverse proxy.');
192193
this._reverseProxy = {
193194
enabled: true,
194195
port: this._requiredType(port, 'port', 'number'),
195196
header: this._requiredType(header, 'header', 'string'),
197+
terminatesSsl,
196198
addresses: addresses
197199
};
198200
return this;

src/main/generic/api/NetworkClient.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Client.Network = class Network {
6363
*/
6464
async getOwnAddress() {
6565
const consensus = await this._client._consensus;
66-
return new Client.BasicAddress(consensus.network.config.peerAddress);
66+
return new Client.BasicAddress(consensus.network.config.publicPeerAddress);
6767
}
6868

6969
/**

src/main/generic/network/NetworkConfig.js

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,14 @@ class NetworkConfig {
128128
/**
129129
* @type {PeerAddress}
130130
*/
131-
get peerAddress() {
131+
get internalPeerAddress() {
132+
throw new Error('Not implemented');
133+
}
134+
135+
/**
136+
* @type {PeerAddress}
137+
*/
138+
get publicPeerAddress() {
132139
throw new Error('Not implemented');
133140
}
134141

@@ -157,7 +164,7 @@ class WsNetworkConfig extends NetworkConfig {
157164
* @constructor
158165
* @param {string} host
159166
* @param {number} port
160-
* @param {{enabled: boolean, port: number, addresses: Array.<string>, header: string}} reverseProxy
167+
* @param {{enabled: boolean, port: number, addresses: Array.<string>, header: string, terminatesSsl: boolean}} reverseProxy
161168
*/
162169
constructor(host, port, reverseProxy) {
163170
super(Protocol.WS | Protocol.WSS);
@@ -182,7 +189,7 @@ class WsNetworkConfig extends NetworkConfig {
182189
}
183190

184191
/**
185-
* @type {{enabled: boolean, port: number, addresses: Array.<string>, header: string}}
192+
* @type {{enabled: boolean, port: number, addresses: Array.<string>, header: string, terminatesSsl: boolean}}
186193
*/
187194
get reverseProxy() {
188195
return this._reverseProxy;
@@ -192,13 +199,41 @@ class WsNetworkConfig extends NetworkConfig {
192199
* @type {WsPeerAddress|WssPeerAddress}
193200
* @override
194201
*/
195-
get peerAddress() {
202+
get internalPeerAddress() {
196203
if (!this._services || !this._keyPair) {
197204
throw new Error('PeerAddress is not configured.');
198205
}
199206

200-
const port = this._reverseProxy.enabled ? this._reverseProxy.port : this._port;
201207
const peerAddress = new WsPeerAddress(
208+
this._services.provided, Date.now(), NetAddress.UNSPECIFIED,
209+
this.publicKey, /*distance*/ 0,
210+
this._host, this._port);
211+
212+
if (!peerAddress.globallyReachable()) {
213+
throw new Error('PeerAddress not globally reachable.');
214+
}
215+
216+
peerAddress.signature = Signature.create(this._keyPair.privateKey, this.publicKey, peerAddress.serializeContent());
217+
return peerAddress;
218+
}
219+
220+
/**
221+
* @type {WsPeerAddress|WssPeerAddress}
222+
* @override
223+
*/
224+
get publicPeerAddress() {
225+
if (!this._services || !this._keyPair) {
226+
throw new Error('PeerAddress is not configured.');
227+
}
228+
229+
const port = this._reverseProxy.enabled ? this._reverseProxy.port : this._port;
230+
let _PeerAddress;
231+
if (this._reverseProxy.enabled && this._reverseProxy.terminatesSsl) {
232+
_PeerAddress = WssPeerAddress;
233+
} else {
234+
_PeerAddress = WsPeerAddress;
235+
}
236+
const peerAddress = new _PeerAddress(
202237
this._services.provided, Date.now(), NetAddress.UNSPECIFIED,
203238
this.publicKey, /*distance*/ 0,
204239
this._host, port);
@@ -260,7 +295,29 @@ class WssNetworkConfig extends WsNetworkConfig {
260295
* @type {WsPeerAddress|WssPeerAddress}
261296
* @override
262297
*/
263-
get peerAddress() {
298+
get internalPeerAddress() {
299+
if (!this._services || !this._keyPair) {
300+
throw new Error('PeerAddress is not configured.');
301+
}
302+
303+
const peerAddress = new WssPeerAddress(
304+
this._services.provided, Date.now(), NetAddress.UNSPECIFIED,
305+
this.publicKey, /*distance*/ 0,
306+
this._host, this._port);
307+
308+
if (!peerAddress.globallyReachable()) {
309+
throw new Error('PeerAddress not globally reachable.');
310+
}
311+
312+
peerAddress.signature = Signature.create(this._keyPair.privateKey, this.publicKey, peerAddress.serializeContent());
313+
return peerAddress;
314+
}
315+
316+
/**
317+
* @type {WsPeerAddress|WssPeerAddress}
318+
* @override
319+
*/
320+
get publicPeerAddress() {
264321
if (!this._services || !this._keyPair) {
265322
throw new Error('PeerAddress is not configured.');
266323
}
@@ -321,7 +378,7 @@ class RtcNetworkConfig extends NetworkConfig {
321378
* @type {RtcPeerAddress}
322379
* @override
323380
*/
324-
get peerAddress() {
381+
get internalPeerAddress() {
325382
if (!this._services || !this._keyPair) {
326383
throw new Error('PeerAddress is not configured.');
327384
}
@@ -332,6 +389,14 @@ class RtcNetworkConfig extends NetworkConfig {
332389
peerAddress.signature = Signature.create(this._keyPair.privateKey, this.publicKey, peerAddress.serializeContent());
333390
return peerAddress;
334391
}
392+
393+
/**
394+
* @type {RtcPeerAddress}
395+
* @override
396+
*/
397+
get publicPeerAddress() {
398+
return this.internalPeerAddress;
399+
}
335400
}
336401
Class.register(RtcNetworkConfig);
337402

@@ -356,7 +421,7 @@ class DumbNetworkConfig extends NetworkConfig {
356421
* @type {DumbPeerAddress}
357422
* @override
358423
*/
359-
get peerAddress() {
424+
get internalPeerAddress() {
360425
if (!this._services || !this._keyPair) {
361426
throw new Error('PeerAddress is not configured.');
362427
}
@@ -367,5 +432,13 @@ class DumbNetworkConfig extends NetworkConfig {
367432
peerAddress.signature = Signature.create(this._keyPair.privateKey, this.publicKey, peerAddress.serializeContent());
368433
return peerAddress;
369434
}
435+
436+
/**
437+
* @type {DumbPeerAddress}
438+
* @override
439+
*/
440+
get publicPeerAddress() {
441+
return this.internalPeerAddress;
442+
}
370443
}
371444
Class.register(DumbNetworkConfig);

src/main/generic/network/address/PeerAddressBook.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ class PeerAddressBook extends Observable {
303303
*/
304304
_add(channel, peerAddress) {
305305
// Ignore our own address.
306-
if (this._networkConfig.peerAddress.equals(peerAddress)) {
306+
if (this._networkConfig.publicPeerAddress.equals(peerAddress)) {
307307
return false;
308308
}
309309

src/main/generic/network/connection/ConnectionPool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ class ConnectionPool extends Observable {
546546

547547
case PeerConnectionState.NEGOTIATING:
548548
// The peer with the lower peerId accepts this connection and closes his stored connection.
549-
if (this._networkConfig.peerAddress.peerId.compare(peer.peerAddress.peerId) < 0) {
549+
if (this._networkConfig.publicPeerAddress.peerId.compare(peer.peerAddress.peerId) < 0) {
550550
storedConnection.peerChannel.close(CloseType.SIMULTANEOUS_CONNECTION,
551551
'simultaneous connection (post handshake) - lower peerId');
552552
Assert.that(!this.getConnectionByPeerAddress(peer.peerAddress), 'PeerConnection not removed');

src/main/generic/network/connection/NetworkAgent.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class NetworkAgent extends Observable {
130130
// Kick off the handshake by telling the peer our version, network address & blockchain head hash.
131131
// Some browsers (Firefox, Safari) send the data-channel-open event too early, so sending the version message might fail.
132132
// Try again in this case.
133-
if (!this._channel.version(this._networkConfig.peerAddress, this._blockchain.headHash, this._challengeNonce, this._networkConfig.appAgent)) {
133+
if (!this._channel.version(this._networkConfig.publicPeerAddress, this._blockchain.headHash, this._challengeNonce, this._networkConfig.appAgent)) {
134134
this._versionAttempts++;
135135
if (this._versionAttempts >= NetworkAgent.VERSION_ATTEMPTS_MAX || this._channel.closed) {
136136
this._channel.close(CloseType.SENDING_OF_VERSION_MESSAGE_FAILED, 'sending of version message failed');
@@ -303,7 +303,7 @@ class NetworkAgent extends Observable {
303303
}
304304

305305
// Verify signature
306-
const data = BufferUtils.concatTypedArrays(this._networkConfig.peerAddress.peerId.serialize(), this._challengeNonce);
306+
const data = BufferUtils.concatTypedArrays(this._networkConfig.publicPeerAddress.peerId.serialize(), this._challengeNonce);
307307
if (!msg.signature.verify(msg.publicKey, data)) {
308308
this._channel.close(CloseType.INVALID_SIGNATURE_IN_VERACK_MESSAGE, 'Invalid signature in verack message');
309309
return;
@@ -330,7 +330,7 @@ class NetworkAgent extends Observable {
330330

331331
// Regularly announce our address.
332332
this._timers.setInterval('announce-addr',
333-
() => this._channel.addr([this._networkConfig.peerAddress]),
333+
() => this._channel.addr([this._networkConfig.publicPeerAddress]),
334334
NetworkAgent.ANNOUNCE_ADDR_INTERVAL);
335335

336336
// Tell listeners that the handshake with this peer succeeded.

src/main/generic/network/websocket/WebSocketConnector.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ class WebSocketConnector extends Observable {
1212
this._protocolPrefix = protocolPrefix;
1313
this._networkConfig = networkConfig;
1414

15-
if (networkConfig.peerAddress.protocol === this._protocol) {
15+
if (networkConfig.internalPeerAddress.protocol === this._protocol) {
1616
this._wss = WebSocketFactory.newWebSocketServer(networkConfig);
1717
this._wss.on('connection', (ws, req) => this._onConnection(ws, req));
1818

19-
Log.d(WebSocketConnector, `${this._protocolPrefix.toUpperCase()}-Connector listening on port ${networkConfig.peerAddress.port}`);
19+
Log.d(WebSocketConnector, `${this._protocolPrefix.toUpperCase()}-Connector listening on port ${networkConfig.internalPeerAddress.port}`);
2020
}
2121

2222
/** @type {HashMap.<PeerAddress, WebSocket>} */

src/test/specs/generic/api/Client.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('Client', () => {
88
const name = 'volatile' + consensus.charAt(0).toUpperCase() + consensus.slice(1);
99
const promise = Consensus[name]();
1010
promise.then((c) => {
11-
Log.d('Client.spec', `${consensus}-consensus uses ${c.network.config.peerAddress}`);
11+
Log.d('Client.spec', `${consensus}-consensus uses ${c.network.config.publicPeerAddress}`);
1212
});
1313
return promise;
1414
}

src/test/specs/generic/network/ConnectionPool.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ describe('ConnectionPool', () => {
444444
netConfig1._keyPair = KeyPair.generate();
445445

446446
const sameIP1 = await Consensus.volatileFull(netConfig1);
447-
sameIP1.network._connections.connectOutbound(netConfig.peerAddress);
447+
sameIP1.network._connections.connectOutbound(netConfig.publicPeerAddress);
448448

449449
const conn = await new Promise(resolve => consensus.network._connections.on('connection', (conn) => { resolve(conn); }));
450450
await new Promise(resolve => sameIP1.on('established', () => {
@@ -456,7 +456,7 @@ describe('ConnectionPool', () => {
456456
netConfig2._keyPair = KeyPair.generate();
457457

458458
const sameIP2 = await Consensus.volatileFull(netConfig2);
459-
sameIP2.network._connections.connectOutbound(netConfig.peerAddress);
459+
sameIP2.network._connections.connectOutbound(netConfig.publicPeerAddress);
460460

461461
const disconnected = new Promise(resolve => sameIP2.network.on('disconnected', resolve));
462462
sameIP2.on('established', done.fail);

src/test/specs/generic/network/MockNetwork.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,14 @@ class MockNetwork {
421421
MockNetwork._lossrate = lossrate;
422422

423423
spyOn(WebSocketFactory, 'newWebSocketServer').and.callFake((netconfig) => {
424-
const peerAddress = netconfig.peerAddress;
424+
const peerAddress = netconfig.publicPeerAddress;
425425
const server = new MockWebSocketServer();
426426
MockNetwork._servers.set(`wss://${peerAddress.host}:${peerAddress.port}`, server);
427427
return server;
428428
});
429429

430430
spyOn(WebSocketFactory, 'newWebSocket').and.callFake((url, options, netconfig) => {
431-
const peerAddress = netconfig.peerAddress;
431+
const peerAddress = netconfig.publicPeerAddress;
432432
const seed = peerAddress.protocol === Protocol.WSS ?
433433
`wss://${peerAddress.host}:${peerAddress.port}` :
434434
`reserved${MockNetwork._clientSerial++}.test`;

0 commit comments

Comments
 (0)