-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from DiUS/iot-tunnel
Ideally [this issue in the SDK](aws/aws-iot-device-sdk-js#357) would have been resolved before the merge, but on the balance of things I'd rather get this feature onto main before the holiday break, even if it means living with the Horrible Workaround(tm) for a while.
- Loading branch information
Showing
6 changed files
with
255 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* Copyright(C) 2019-2020 DiUS Computing Pty Ltd */ | ||
'use strict'; | ||
const child_process = require('child_process'); | ||
|
||
function SecureTunnel(thing, portmappings, localproxy, caDir) { | ||
this._thing = thing; | ||
this._localproxy = localproxy || 'localproxy'; | ||
this._caDir = caDir; | ||
this._mappings = {}; | ||
try { | ||
portmappings.split(',').forEach(portmap => { | ||
const [ key, port ] = portmap.split('='); | ||
this._mappings[key] = +port; | ||
if (isNaN(this._mappings[key])) | ||
throw new Error(`invalid port number: ${port}`); | ||
}); | ||
} | ||
catch(e) { | ||
console.error( | ||
`Error parsing '${thing}' portmappings "${portmappings}": ${e}`); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
|
||
SecureTunnel.prototype.thing = function() { | ||
return this._thing; | ||
} | ||
|
||
|
||
SecureTunnel.prototype.topic = function() { | ||
return `$aws/things/${this._thing}/tunnels/notify`; | ||
} | ||
|
||
|
||
SecureTunnel.prototype.handleMessage = function(buf) { | ||
try { | ||
const tunnelConfig = JSON.parse(buf); | ||
if (tunnelConfig.clientMode != 'destination') | ||
throw new Error(`unsupported mode '${tunnelConfig.clientMode}'`); | ||
|
||
this.launch( | ||
tunnelConfig.clientAccessToken, | ||
tunnelConfig.services, | ||
tunnelConfig.region); | ||
} | ||
catch(e) { | ||
console.error(`Unable to open tunnel for ${this._thing}: ${e}`); | ||
} | ||
} | ||
|
||
|
||
SecureTunnel.prototype.launch = function(accessToken, serviceList, region) { | ||
if (this._proc != null) { | ||
console.warn(`Stopping previous tunnel proxy for '${this._thing}'.`); | ||
this._proc.kill(); | ||
} | ||
|
||
const enabled = []; | ||
for (const svc of serviceList) { | ||
if (this._mappings[svc] != null) | ||
enabled.push(`${svc}=${this._mappings[svc]}`); | ||
else | ||
console.warn( | ||
`Requested tunnel service '${svc}' for '${this._thing}' not mapped!`); | ||
} | ||
if (enabled.length == 0) | ||
throw new Error(`requested services not available!`); | ||
|
||
const args = [ '-d', enabled.join(','), ]; | ||
if (this._caDir != null) { | ||
args.push('-c'); | ||
args.push(this._caDir); | ||
} | ||
const env = { | ||
AWSIOT_TUNNEL_ACCESS_TOKEN: accessToken, | ||
AWSIOT_TUNNEL_REGION: region, | ||
}; | ||
|
||
this._proc = child_process.spawn( | ||
this._localproxy, args, { env, stdio: 'inherit', detached: true }); | ||
const pid = this._proc.pid; | ||
console.info(`Starting tunnel proxy for '${this._thing}' with services "${serviceList.join(', ')}", pid ${pid}.`); | ||
this._proc.on('exit', (code, sig) => { | ||
const msg = `Tunnel proxy for '${this._thing}', pid ${pid} exited`; | ||
if (code != null) | ||
console.info(`${msg} with code ${code}.`); | ||
else | ||
console.info(`${msg} due to ${sig}.`); | ||
// Clean up, but only if this._proc has already been replaced | ||
if (this._proc != null && this._proc.pid == pid) | ||
this._proc = null; | ||
}); | ||
|
||
this._proc.unref(); // don't wait for proxy exit before we can exit | ||
} | ||
|
||
|
||
SecureTunnel.prototype.terminate = function() { | ||
if (this._proc != null) { | ||
console.info(`Terminating tunnel proxy for '${this._thing}', pid ${this._proc.pid} on request...`); | ||
this._proc.kill(); | ||
} | ||
} | ||
|
||
|
||
function applyHorribleReservedTopicWorkaround() { | ||
const substring = String.prototype.substring; | ||
String.prototype.substring = function(x, y) { | ||
var res = substring.call(this, x, y); | ||
if (x == 0 && y == 12 && res == '$aws/things/') { | ||
res = 'OneUglyHack!'; | ||
} | ||
return res; | ||
} | ||
} | ||
|
||
|
||
module.exports = { | ||
SecureTunnel, | ||
applyHorribleReservedTopicWorkaround, | ||
}; |