nassh 0.8.22.3: add support for new relay dance
Convert the old relay-host and relay-port prefs into a single
'relay-options' pref. The 'relay-options' pref has always existed,
but never had a field in the connect dialog.
Old host/port preferences are merged into the options pref.
Add a canned configuration that corresponds to the correct settings
for google corp access on the new relay proxy front-end.
Fix the inifinite backoff.
Change-Id: I43de6205e5120d89a2b001bc5d242b453fba7401
Reviewed-on: https://chromium-review.googlesource.com/178097
Reviewed-by: Marvelous Marius <mschilder@chromium.org>
Tested-by: Robert Ginda <rginda@chromium.org>
diff --git a/nassh/_locales/en/messages.json b/nassh/_locales/en/messages.json
index 1b2adf3..4c10132 100644
--- a/nassh/_locales/en/messages.json
+++ b/nassh/_locales/en/messages.json
@@ -116,24 +116,14 @@
"description": "Text use as the aria-label for the 'port' field."
},
- "FIELD_RELAY_HOST_PLACEHOLDER": {
- "message": "relay hostname",
- "description": "Text use as the placeholder for the 'relay-host' field."
+ "FIELD_RELAY_OPTIONS_PLACEHOLDER": {
+ "message": "relay options",
+ "description": "Text use as the placeholder for the 'relay-options' field."
},
- "FIELD_RELAY_HOST_ARIA_LABEL": {
- "message": "relay host",
- "description": "Text use as the aria-label for the 'relay-host' field."
- },
-
- "FIELD_RELAY_PORT_ARIA_LABEL": {
- "message": "port",
- "description": "Text use as the aria-label for the 'relay-port' field."
- },
-
- "FIELD_RELAY_PORT_PLACEHOLDER": {
- "message": "port",
- "description": "Text use as the placeholder for the 'relay-port' field."
+ "FIELD_RELAY_OPTIONS_ARIA_LABEL": {
+ "message": "relay options",
+ "description": "Text use as the aria-label for the 'relay-options' field."
},
"IDENTITY_LABEL": {
diff --git a/nassh/doc/changelog.txt b/nassh/doc/changelog.txt
index 9a6715d..b8364e2 100644
--- a/nassh/doc/changelog.txt
+++ b/nassh/doc/changelog.txt
@@ -1,3 +1,9 @@
+0.8.22.3, 2013-11-26, Learn the new relay dance.
+
+* Update the google relay code to understand the new proxy front-end to the
+ relay servers. Should be backwards compatible. Googlers can now specify
+ the relay option "--config=google" to magically specify the correct config.
+
0.8.22.2, 2013-11-26, Crosh polish.
* Display reconnect menu on non-zero exit status.
diff --git a/nassh/html/nassh_connect_dialog.html b/nassh/html/nassh_connect_dialog.html
index 94c109e..d193ab2 100644
--- a/nassh/html/nassh_connect_dialog.html
+++ b/nassh/html/nassh_connect_dialog.html
@@ -35,10 +35,8 @@
min='1' max='65535'>
</x-hbox>
<x-hbox>
- <input x-box id='field-relay-host' x-flex='1' type='text'>
- <input x-box id='field-relay-port' type='number' min='1' max='65535'
- i18n='{"aria-label": "$id"}'
- min='1' max='65535'>
+ <input x-box id='field-relay-options' x-flex='1' type='text'
+ i18n='{"aria-label": "$id", "placeholder": "$id"}'>
</x-hbox>
<br>
<x-hbox x-align='baseline'>
diff --git a/nassh/js/nassh_command_instance.js b/nassh/js/nassh_command_instance.js
index a6bea6e..dcbd8b8 100644
--- a/nassh/js/nassh_command_instance.js
+++ b/nassh/js/nassh_command_instance.js
@@ -376,8 +376,6 @@
username: prefs.get('username'),
hostname: prefs.get('hostname'),
port: prefs.get('port'),
- relayHost: prefs.get('relay-host'),
- relayPort: prefs.get('relay-port'),
relayOptions: prefs.get('relay-options'),
identity: prefs.get('identity'),
argstr: prefs.get('argstr'),
@@ -415,12 +413,19 @@
// some callers may come directly to connectToDestination.
document.location.hash = destination;
+ var relayOptions = '';
+ if (ary[4]) {
+ relayOptions = '--proxy-host=' + ary[4];
+
+ if (ary[5])
+ relayOptions += ' --proxy-port=' + ary[5];
+ }
+
return this.connectTo({
username: ary[1],
hostname: ary[2],
port: ary[3],
- relayHost: ary[4],
- relayPort: ary[5]
+ relayOptions: relayOptions
});
};
@@ -444,10 +449,8 @@
return;
}
- if (params.relayHost) {
+ if (params.relayOptions) {
this.relay_ = new nassh.GoogleRelay(this.io,
- params.relayHost,
- params.relayPort,
params.relayOptions);
this.io.println(nassh.msg(
'INITIALIZING_RELAY',
diff --git a/nassh/js/nassh_connect_dialog.js b/nassh/js/nassh_connect_dialog.js
index a0ed6bf..1135dde 100644
--- a/nassh/js/nassh_connect_dialog.js
+++ b/nassh/js/nassh_connect_dialog.js
@@ -218,7 +218,7 @@
});
// These fields interact with each-other's placeholder text.
- ['description', 'username', 'hostname', 'port', 'relay-host', 'relay-port'
+ ['description', 'username', 'hostname', 'port'
].forEach(function(name) {
var field = this.$f(name);
@@ -243,7 +243,7 @@
this.maybeDirty_.bind(this, name));
}.bind(this));
- ['description', 'username', 'hostname', 'port', 'relay-host', 'relay-port',
+ ['description', 'username', 'hostname', 'port', 'relay-options',
'identity', 'argstr', 'terminal-profile'
].forEach(function(name) {
addListeners(this.$f(name), ['focus', 'blur'],
@@ -329,14 +329,14 @@
var prefs = this.currentProfileRecord_.prefs;
- ['description', 'username', 'hostname', 'port', 'relay-host', 'relay-port',
+ ['description', 'username', 'hostname', 'port', 'relay-options',
'identity', 'argstr', 'terminal-profile'].forEach(function(name) {
if (name == 'identity' && this.$f('identity').selectedIndex === 0)
return;
var value = this.$f(name).value;
- if (name == 'port' || name == 'relay-port')
+ if (name == 'port')
value = value ? parseInt(value) : '';
if ((!prefs && !value) || (prefs && value == prefs.get(name)))
@@ -410,7 +410,7 @@
* to bulk-default.
*/
nassh.ConnectDialog.prototype.maybeCopyPlaceholders_ = function() {
- ['description', 'username', 'hostname', 'port', 'relay-host', 'relay-port'
+ ['description', 'username', 'hostname', 'port'
].forEach(this.maybeCopyPlaceholder_.bind(this));
this.syncButtons_();
};
@@ -458,7 +458,7 @@
// Copy the remaining match elements into the appropriate placeholder
// attribute. Set the default placeholder text from this.str.placeholders
// for any field that was not matched.
- ['username', 'hostname', 'port', 'relay-host', 'relay-port',
+ ['username', 'hostname', 'port'
].forEach(function(name) {
var value = ary.shift();
if (!value) {
@@ -484,10 +484,6 @@
var v = this.$f('port').value;
if (v)
placeholder += ':' + v;
-
- v = this.$f('relay-host').value;
- if (v)
- placeholder += '@' + v;
} else {
placeholder = this.msg('FIELD_DESCRIPTION_PLACEHOLDER');
}
@@ -499,8 +495,8 @@
* Sync the form with the current profile record.
*/
nassh.ConnectDialog.prototype.syncForm_ = function() {
- ['description', 'username', 'hostname', 'port', 'argstr', 'relay-host',
- 'relay-port', 'identity', 'terminal-profile'
+ ['description', 'username', 'hostname', 'port', 'argstr', 'relay-options',
+ 'identity', 'terminal-profile'
].forEach(function(n) {
var emptyValue = '';
if (n == 'identity')
diff --git a/nassh/js/nassh_google_relay.js b/nassh/js/nassh_google_relay.js
index 4be9b50..1dd782f 100644
--- a/nassh/js/nassh_google_relay.js
+++ b/nassh/js/nassh_google_relay.js
@@ -68,16 +68,53 @@
* 6. Writes are queued up and sent to /write.
*/
-nassh.GoogleRelay = function(io, proxyHost, proxyPort, options) {
+nassh.GoogleRelay = function(io, optionString) {
this.io = io;
- this.proxyHost = proxyHost;
- this.proxyPort = proxyPort || 8022;
- this.useSecure = options.search('--use-ssl') != -1;
- this.useWebsocket = !(options.search('--use-xhr') != -1);
+ this.options = nassh.GoogleRelay.parseOptionString(optionString);
+ this.proxyHost = this.options['--proxy-host'];
+ this.proxyPort = this.options['--proxy-port'] || 8022;
+ this.useSecure = this.options['--use-ssl'];
+ this.useWebsocket = !this.options['--use-xhr'];
this.relayServer = null;
this.relayServerSocket = null;
};
+nassh.GoogleRelay.parseOptionString = function(optionString) {
+ var rv = {};
+
+ var optionList = optionString.split(/\s+/g);
+ for (var i = 0; i < optionList.length; i++) {
+ var option = optionList[i];
+ if (option.substr(0, 1) != '-') {
+ // Bare option overrides --host.
+ rv['--proxy-host'] = option;
+ } else {
+ var pos = option.indexOf('=');
+ if (pos != -1) {
+ rv[option.substr(0, pos)] = option.substr(pos + 1);
+ } else {
+ var ary = option.match(/--no-(.*)/);
+ if (ary) {
+ rv['--' + ary[1]] = false;
+ } else {
+ rv[option] = true;
+ }
+ }
+ }
+ }
+
+ if (rv['--config'] == 'google') {
+ if (!('--proxy-host' in rv))
+ rv['--proxy-host'] = 'spdy-proxy.ext.google.com';
+ if (!('--use-ssl' in rv))
+ rv['--use-ssl'] = true;
+ if (!('--relay-prefix-field' in rv))
+ rv['--relay-prefix-field'] = '2';
+ }
+
+ return rv;
+};
+
/**
* The pattern for the cookie server's url.
*/
@@ -128,9 +165,32 @@
// if we succeed at finding a relay host.
var relayHost = sessionStorage.getItem('googleRelay.relayHost');
var relayPort = sessionStorage.getItem('googleRelay.relayPort') ||
- (this.useWebsocket ? 8022 : 8023);
+ (this.useXHR ? 8023 : 8022);
if (relayHost) {
+ var relayPrefixField = parseInt(this.options['--relay-prefix-field']);
+ if (relayPrefixField) {
+ // If this option is set, we're supposed to assume the relayHost is a
+ // '.' delimited list of fields (like a hostname), isolate the field
+ // at the 1-based relayPrefixField position, and create the actual
+ // relayHost by prepending this field to the original proxyHost.
+ //
+ // TODO(rginda): Yes, this is a kludge. Returning the correct hostname
+ // from the proxy is sometimes difficult, for a reason unknown to me.
+ var relayPrefix = relayHost.split(/\./g)[relayPrefixField - 1];
+ if (relayPrefix) {
+ if (this.proxyHost.substr(0, relayPrefix.length + 1) !=
+ relayPrefix + '.') {
+ // Only add the prefix if the proxyHost doesn't already include it.
+ relayHost = relayPrefix + '.' + this.proxyHost;
+ }
+ } else {
+ console.warn('Error getting relay prefix field: ' + relayPrefixField +
+ ' from: ' + relayHost);
+ this.relayHost = null;
+ }
+ }
+
var expectedResumePath =
sessionStorage.getItem('googleRelay.resumePath');
if (expectedResumePath == resumePath) {
@@ -138,7 +198,7 @@
var pattern = this.relayServerPattern;
this.relayServer = lib.f.replaceVars(pattern,
{host: relayHost, port: relayPort, protocol: protocol});
- if (this.useWebsocket) {
+ if (!this.useXHR) {
protocol = this.useSecure ? 'wss' : 'ws';
this.relayServerSocket = lib.f.replaceVars(pattern,
{host: relayHost, port: relayPort, protocol: protocol});
diff --git a/nassh/js/nassh_preference_manager.js b/nassh/js/nassh_preference_manager.js
index 0b8e0a2..3f78661 100644
--- a/nassh/js/nassh_preference_manager.js
+++ b/nassh/js/nassh_preference_manager.js
@@ -107,3 +107,37 @@
nassh.ProfilePreferenceManager.prototype = {
__proto__: lib.PreferenceManager.prototype
};
+
+nassh.ProfilePreferenceManager.prototype.readStorage = function(opt_callback) {
+ var appendOption = function(str) {
+ var options = this.get('relay-options');
+ if (options) {
+ options += ' ' + str;
+ } else {
+ options = str;
+ }
+
+ this.set('relay-option', options);
+ }.bind(this);
+
+ var onRead = function() {
+ var host = this.get('relay-host');
+ if (host) {
+ console.warn('Merging relay-host preference with relay-options');
+ this.reset('relay-host');
+ appendOption('--proxy-host=' + host);
+ }
+
+ var port = this.get('relay-port');
+ if (port) {
+ this.reset('relay-port');
+ console.warn('Merging relay-host preference with relay-options');
+ appendOption('--proxy-port=' + port);
+ }
+
+ if (opt_callback)
+ opt_callback();
+ }.bind(this);
+
+ lib.PreferenceManager.prototype.readStorage.call(this, onRead);
+};
diff --git a/nassh/js/nassh_stream_google_relay.js b/nassh/js/nassh_stream_google_relay.js
index 14071af..e378cf8 100644
--- a/nassh/js/nassh_stream_google_relay.js
+++ b/nassh/js/nassh_stream_google_relay.js
@@ -153,7 +153,9 @@
if (!this.backoffMS_) {
this.backoffMS_ = 1;
} else {
- this.backoffMS_ = this.backoffMS_ * 2 + 93; // Exponential backoff.
+ this.backoffMS_ = this.backoffMS_ * 2 + 13;
+ if (this.backoffMS_ > 10000)
+ this.backoffMS_ = 10000 - (x % 9000);
}
var requestType = isRead ? 'read' : 'write';
diff --git a/nassh/manifest.json b/nassh/manifest.json
index e077f15..c23c6a7 100644
--- a/nassh/manifest.json
+++ b/nassh/manifest.json
@@ -4,7 +4,7 @@
"manifest_version": 2,
"content_security_policy": "script-src 'self'; object-src 'self'",
"name": "Secure Shell (tot)",
- "version": "0.8.22.2",
+ "version": "0.8.22.3",
"default_locale": "en",
"icons": {
"128": "images/dev/icon-128.png",