From 8b443dc9d54ee3df5c8b4966b3be503b354f995a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 2 Jun 2018 08:47:41 -0400 Subject: [PATCH 01/26] GUACAMOLE-422: Add timezone selection for RDP connections. --- .../org/apache/guacamole/auth/jdbc/user/ModeledUser.java | 6 +++++- .../main/resources/org/apache/guacamole/protocols/rdp.json | 4 ++++ guacamole/src/main/webapp/translations/en.json | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index b7924edd9..a2e0fadbb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -113,7 +113,8 @@ public class ModeledUser extends ModeledPermissions implements User { new TextField(User.Attribute.FULL_NAME), new EmailField(User.Attribute.EMAIL_ADDRESS), new TextField(User.Attribute.ORGANIZATION), - new TextField(User.Attribute.ORGANIZATIONAL_ROLE) + new TextField(User.Attribute.ORGANIZATIONAL_ROLE), + new TimeZoneField(TIMEZONE_ATTRIBUTE_NAME) )); /** @@ -349,6 +350,9 @@ public class ModeledUser extends ModeledPermissions implements User { // Set role attribute attributes.put(User.Attribute.ORGANIZATIONAL_ROLE, getModel().getOrganizationalRole()); + // Set timezone attribute + attributes.put(TIMEZONE_ATTRIBUTE_NAME, getModel().getTimeZone()); + } /** diff --git a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json index e3de15f40..f082ba28a 100644 --- a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json +++ b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/rdp.json @@ -195,6 +195,10 @@ { "name" : "static-channels", "type" : "TEXT" + }, + { + "name" : "timezone", + "type" : "TIMEZONE" } ] }, diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index 9fc69efca..8815dd975 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -415,6 +415,7 @@ "FIELD_HEADER_REMOTE_APP_ARGS" : "Parameters:", "FIELD_HEADER_REMOTE_APP_DIR" : "Working directory:", "FIELD_HEADER_REMOTE_APP" : "Program:", + "FIELD_HEADER_TIMEZONE" : "Timezone:", "FIELD_HEADER_SECURITY" : "Security mode:", "FIELD_HEADER_SERVER_LAYOUT" : "Keyboard layout:", "FIELD_HEADER_SFTP_DIRECTORY" : "Default upload directory:", From ea913c98fe4dcab7591df30f8b18466075b0c64a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sat, 2 Jun 2018 21:04:01 -0400 Subject: [PATCH 02/26] GUACAMOLE-422: Implement client-side timezone detection. --- guacamole/pom.xml | 8 ++++++++ .../directives/guacSettingsPreferences.js | 1 + .../settings/services/preferenceService.js | 19 ++++++++++++++++++- .../app/settings/styles/preferences.css | 2 +- .../templates/settingsPreferences.html | 15 ++++++++++++--- guacamole/src/main/webapp/index.html | 3 +++ .../src/main/webapp/translations/en.json | 3 ++- 7 files changed, 45 insertions(+), 6 deletions(-) diff --git a/guacamole/pom.xml b/guacamole/pom.xml index 705009360..74c601aab 100644 --- a/guacamole/pom.xml +++ b/guacamole/pom.xml @@ -493,6 +493,14 @@ + + + + org.webjars.npm + jstz + 1.0.10 + + diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js index 71e7af73e..4aeef47f4 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js @@ -38,6 +38,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe // Required services var $translate = $injector.get('$translate'); var authenticationService = $injector.get('authenticationService'); + var formService = $injector.get('formService'); var guacNotification = $injector.get('guacNotification'); var languageService = $injector.get('languageService'); var permissionService = $injector.get('permissionService'); diff --git a/guacamole/src/main/webapp/app/settings/services/preferenceService.js b/guacamole/src/main/webapp/app/settings/services/preferenceService.js index bcd86336b..38241e1c6 100644 --- a/guacamole/src/main/webapp/app/settings/services/preferenceService.js +++ b/guacamole/src/main/webapp/app/settings/services/preferenceService.js @@ -98,6 +98,17 @@ angular.module('settings').provider('preferenceService', ['$injector', return language.replace(/-/g, '_'); }; + + /** + * Return the timezone detected for the current browser session + * by the JSTZ timezone library. + * + * @returns String + * The name of the currently-detected timezone. + */ + var getDetectedTimezone = function getDetectedTimezone() { + return jstz.determine().name(); + }; /** * All currently-set preferences, as name/value pairs. Each property name @@ -128,7 +139,13 @@ angular.module('settings').provider('preferenceService', ['$injector', * * @type String */ - language : getDefaultLanguageKey() + language : getDefaultLanguageKey(), + + /** + * The timezone set by the uesr. + * @type String + */ + timezone : getDetectedTimezone() }; diff --git a/guacamole/src/main/webapp/app/settings/styles/preferences.css b/guacamole/src/main/webapp/app/settings/styles/preferences.css index ed8460dd4..9a966b552 100644 --- a/guacamole/src/main/webapp/app/settings/styles/preferences.css +++ b/guacamole/src/main/webapp/app/settings/styles/preferences.css @@ -18,7 +18,7 @@ */ .preferences .update-password .form, -.preferences .language .form { +.preferences .locale .form { padding-left: 0.5em; border-left: 3px solid rgba(0, 0, 0, 0.125); } \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html index 826a5cd20..8c924539b 100644 --- a/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html +++ b/guacamole/src/main/webapp/app/settings/templates/settingsPreferences.html @@ -1,8 +1,8 @@
- -
-

{{'SETTINGS_PREFERENCES.HELP_LANGUAGE' | translate}}

+ +
+

{{'SETTINGS_PREFERENCES.HELP_LOCALE' | translate}}

@@ -13,6 +13,15 @@
+ + +
+ + +
diff --git a/guacamole/src/main/webapp/index.html b/guacamole/src/main/webapp/index.html index 1d51606a9..e675546c6 100644 --- a/guacamole/src/main/webapp/index.html +++ b/guacamole/src/main/webapp/index.html @@ -85,6 +85,9 @@ + + + diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index 8815dd975..e0e42214f 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -755,6 +755,7 @@ "FIELD_HEADER_PASSWORD_OLD" : "Current Password:", "FIELD_HEADER_PASSWORD_NEW" : "New Password:", "FIELD_HEADER_PASSWORD_NEW_AGAIN" : "Confirm New Password:", + "FIELD_HEADER_TIMEZONE" : "Timezone:", "FIELD_HEADER_USERNAME" : "Username:", "HELP_DEFAULT_INPUT_METHOD" : "The default input method determines how keyboard events are received by Guacamole. Changing this setting may be necessary when using a mobile device, or when typing through an IME. This setting can be overridden on a per-connection basis within the Guacamole menu.", @@ -762,7 +763,7 @@ "HELP_INPUT_METHOD_NONE" : "@:CLIENT.HELP_INPUT_METHOD_NONE", "HELP_INPUT_METHOD_OSK" : "@:CLIENT.HELP_INPUT_METHOD_OSK", "HELP_INPUT_METHOD_TEXT" : "@:CLIENT.HELP_INPUT_METHOD_TEXT", - "HELP_LANGUAGE" : "Select a different language below to change the language of all text within Guacamole. Available choices will depend on which languages are installed.", + "HELP_LOCALE" : "Options below are related to the locale of the user and will impact how various parts of the interface are displayed.", "HELP_MOUSE_MODE_ABSOLUTE" : "@:CLIENT.HELP_MOUSE_MODE_ABSOLUTE", "HELP_MOUSE_MODE_RELATIVE" : "@:CLIENT.HELP_MOUSE_MODE_RELATIVE", "HELP_UPDATE_PASSWORD" : "If you wish to change your password, enter your current password and the desired new password below, and click \"Update Password\". The change will take effect immediately.", From 50c2161ec8c822662eaa3f90b212ba402c33834d Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 3 Jun 2018 08:41:35 -0400 Subject: [PATCH 03/26] GUACAMOLE-422: Add tunnel parameter for sending the timezone. --- guacamole/src/main/webapp/app/client/types/ManagedClient.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guacamole/src/main/webapp/app/client/types/ManagedClient.js b/guacamole/src/main/webapp/app/client/types/ManagedClient.js index a9bc3beac..b4637e989 100644 --- a/guacamole/src/main/webapp/app/client/types/ManagedClient.js +++ b/guacamole/src/main/webapp/app/client/types/ManagedClient.js @@ -42,6 +42,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', var authenticationService = $injector.get('authenticationService'); var connectionGroupService = $injector.get('connectionGroupService'); var connectionService = $injector.get('connectionService'); + var preferenceService = $injector.get('preferenceService'); var requestService = $injector.get('requestService'); var tunnelService = $injector.get('tunnelService'); var guacAudio = $injector.get('guacAudio'); @@ -225,6 +226,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector', + "&GUAC_WIDTH=" + Math.floor(optimal_width) + "&GUAC_HEIGHT=" + Math.floor(optimal_height) + "&GUAC_DPI=" + Math.floor(optimal_dpi) + + "&GUAC_TIMEZONE=" + encodeURIComponent(preferenceService.preferences.timezone) + (connectionParameters ? '&' + connectionParameters : ''); // Add audio mimetypes to connect string From 8ad65d6e6c9d43a8d532196044a3f134b14b763d Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 3 Jun 2018 08:48:46 -0400 Subject: [PATCH 04/26] GUACAMOLE-422: Add field for timezone for SSH connections. --- .../main/resources/org/apache/guacamole/protocols/ssh.json | 6 +++++- guacamole/src/main/webapp/translations/en.json | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json index a71e1fbbc..30857d7e0 100644 --- a/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json +++ b/guacamole-ext/src/main/resources/org/apache/guacamole/protocols/ssh.json @@ -89,9 +89,13 @@ "options" : [ "", "127", "8" ] }, { - "name" : "terminal-type", + "name" : "terminal-type", "type" : "ENUM", "options" : [ "", "xterm", "xterm-256color", "vt220", "vt100", "ansi", "linux" ] + }, + { + "name" : "timezone", + "type" : "TIMEZONE" } ] }, diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index e0e42214f..291f67b9a 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -506,6 +506,7 @@ "FIELD_HEADER_SERVER_ALIVE_INTERVAL" : "Server keepalive interval:", "FIELD_HEADER_SFTP_ROOT_DIRECTORY" : "File browser root directory:", "FIELD_HEADER_TERMINAL_TYPE" : "Terminal type:", + "FIELD_HEADER_TIMEZONE" : "Timezone:", "FIELD_HEADER_TYPESCRIPT_NAME" : "Typescript name:", "FIELD_HEADER_TYPESCRIPT_PATH" : "Typescript path:", From 047ed7ac9c19ae97cb89fe6436f4235d40f5ff6f Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 3 Jun 2018 14:59:47 -0400 Subject: [PATCH 05/26] GUACAMOLE-422: Add timezone to tunnel connections. --- .../AbstractGuacamoleTunnelService.java | 9 +++++++ .../protocol/GuacamoleClientInformation.java | 25 +++++++++++++++++++ .../guacamole/tunnel/TunnelRequest.java | 18 ++++++++++++- .../tunnel/TunnelRequestService.java | 5 ++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 20ac29995..2b11d4f1b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -476,6 +476,15 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS activeConnections.put(connection.getIdentifier(), activeConnection); activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection); config = getGuacamoleConfiguration(activeConnection.getUser(), connection); + + // If timezone is provided by tunnel parameter, and not + // overriden by connection parameter, set it. + String tzTunnel = info.getTimezone(); + String tzParam = config.getParameter("timezone"); + if ((tzParam == null || tzParam.isEmpty()) + && tzTunnel != null && !tzTunnel.isEmpty()) + config.setParameter("timezone", tzTunnel); + } // If we ARE joining an active connection, generate a configuration diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index d90d05d3f..c1e7ae066 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -58,6 +58,11 @@ public class GuacamoleClientInformation { * The list of image mimetypes reported by the client to be supported. */ private final List imageMimetypes = new ArrayList(); + + /** + * The timezone report by the client. + */ + private String timezone = ""; /** * Returns the optimal screen width requested by the client, in pixels. @@ -144,5 +149,25 @@ public class GuacamoleClientInformation { public List getImageMimetypes() { return imageMimetypes; } + + /** + * Return the timezone as reported by the client. + * + * @returns + * A string value of the timezone reported by the client. + */ + public String getTimezone() { + return timezone; + } + + /** + * Set the string value of the timezone. + * + * @param timezone + * The string value of the timezone reported by the client. + */ + public void setTimezone(String timezone) { + this.timezone = timezone; + } } diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java index 8c23dabad..1355a150e 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java @@ -95,6 +95,11 @@ public abstract class TunnelRequest { * once for each mimetype. */ public static final String IMAGE_PARAMETER = "GUAC_IMAGE"; + + /** + * The name of the parameter specifying the timezone of the client. + */ + public static final String TIMEZONE_PARAMETER = "GUAC_TIMEZONE"; /** * All supported object types that can be used as the destination of a @@ -365,5 +370,16 @@ public abstract class TunnelRequest { public List getImageMimetypes() { return getParameterValues(IMAGE_PARAMETER); } - + + /** + * Returns the value of the timezone parameter declared within the + * tunnel request. + * + * @return + * The string value of the timezone parameter as reported by + * the client. + */ + public String getTimezone() { + return getParameter(TIMEZONE_PARAMETER); + } } diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java index 1479d8243..9f0fdfaf3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java @@ -166,6 +166,11 @@ public class TunnelRequestService { List imageMimetypes = request.getImageMimetypes(); if (imageMimetypes != null) info.getImageMimetypes().addAll(imageMimetypes); + + // Get the timezone value + String timezone = request.getTimezone(); + if (timezone != null & !timezone.isEmpty()) + info.setTimezone(timezone); return info; } From f1bce5173f0218e25cf8eb1f9e3fbf57d2e942d9 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 3 Jun 2018 15:02:03 -0400 Subject: [PATCH 06/26] GUACAMOLE-422: Correct javadoc tag. --- .../apache/guacamole/protocol/GuacamoleClientInformation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index c1e7ae066..4c90847f5 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -153,7 +153,7 @@ public class GuacamoleClientInformation { /** * Return the timezone as reported by the client. * - * @returns + * @return * A string value of the timezone reported by the client. */ public String getTimezone() { From 0968145160899ba39fcccc5106acad0cc0ca3b9a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 4 Jun 2018 06:37:31 -0400 Subject: [PATCH 07/26] GUACAMOLE-422: Revert weird addition of timezone field in JDBC module. --- .../org/apache/guacamole/auth/jdbc/user/ModeledUser.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index a2e0fadbb..b7924edd9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -113,8 +113,7 @@ public class ModeledUser extends ModeledPermissions implements User { new TextField(User.Attribute.FULL_NAME), new EmailField(User.Attribute.EMAIL_ADDRESS), new TextField(User.Attribute.ORGANIZATION), - new TextField(User.Attribute.ORGANIZATIONAL_ROLE), - new TimeZoneField(TIMEZONE_ATTRIBUTE_NAME) + new TextField(User.Attribute.ORGANIZATIONAL_ROLE) )); /** @@ -350,9 +349,6 @@ public class ModeledUser extends ModeledPermissions implements User { // Set role attribute attributes.put(User.Attribute.ORGANIZATIONAL_ROLE, getModel().getOrganizationalRole()); - // Set timezone attribute - attributes.put(TIMEZONE_ATTRIBUTE_NAME, getModel().getTimeZone()); - } /** From 5ac98e441cc5884eacac12a0f5714709bffc446d Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 4 Jun 2018 06:45:10 -0400 Subject: [PATCH 08/26] GUACAMOLE-422: Remove extra space in pom.xml --- guacamole/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/guacamole/pom.xml b/guacamole/pom.xml index 74c601aab..7a686065c 100644 --- a/guacamole/pom.xml +++ b/guacamole/pom.xml @@ -501,7 +501,6 @@ 1.0.10 - From d194e0754f9fa82825dc498f40ab1d0f8f9ea6d7 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Sun, 24 Mar 2019 21:58:38 -0400 Subject: [PATCH 09/26] GUACAMOLE-422: Add timezone instruction to handshake, remove kludge from JDBC module. --- .../auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java | 9 --------- .../guacamole/protocol/ConfiguredGuacamoleSocket.java | 7 +++++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 2b11d4f1b..20ac29995 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -476,15 +476,6 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS activeConnections.put(connection.getIdentifier(), activeConnection); activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection); config = getGuacamoleConfiguration(activeConnection.getUser(), connection); - - // If timezone is provided by tunnel parameter, and not - // overriden by connection parameter, set it. - String tzTunnel = info.getTimezone(); - String tzParam = config.getParameter("timezone"); - if ((tzParam == null || tzParam.isEmpty()) - && tzTunnel != null && !tzTunnel.isEmpty()) - config.setParameter("timezone", tzTunnel); - } // If we ARE joining an active connection, generate a configuration diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index cf43b68f1..46fcfce3b 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -184,6 +184,13 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { "image", info.getImageMimetypes().toArray(new String[0]) )); + + // Send client timezone + writer.writeInstruction( + new GuacamoleInstruction( + "timezone", + info.getTimezone() + )); // Send args writer.writeInstruction(new GuacamoleInstruction("connect", arg_values)); From d3e00abab771ca113beaa1514aeed734d461195d Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 Mar 2019 21:52:46 -0400 Subject: [PATCH 10/26] GUACAMOLE-422: Only send timezone if it's there. --- .../protocol/ConfiguredGuacamoleSocket.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index 46fcfce3b..b14f9aa19 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -185,12 +185,15 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { info.getImageMimetypes().toArray(new String[0]) )); - // Send client timezone - writer.writeInstruction( - new GuacamoleInstruction( - "timezone", - info.getTimezone() - )); + // Send client timezone, if available + String timezone = info.getTimezone(); + if (timezone != null && !timezone.isEmpty()) { + writer.writeInstruction( + new GuacamoleInstruction( + "timezone", + info.getTimezone() + )); + } // Send args writer.writeInstruction(new GuacamoleInstruction("connect", arg_values)); From c5a7ab757f753742a5b20bf96481bd7befab9246 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Sat, 30 Mar 2019 17:24:26 -0400 Subject: [PATCH 11/26] GUACAMOLE-422: Implement protocol version support in the client. --- .../protocol/ConfiguredGuacamoleSocket.java | 37 ++- .../protocol/GuacamoleProtocolVersion.java | 224 ++++++++++++++++++ 2 files changed, 252 insertions(+), 9 deletions(-) create mode 100644 guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index b14f9aa19..a9b9898d7 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -19,7 +19,6 @@ package org.apache.guacamole.protocol; - import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; @@ -56,6 +55,15 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { */ private String id; + /** + * The protocol version that will be used to communicate with guacd. The + * default is 1.0.0, and, if the server does not provide a specific version + * it will be assumed that it operates at this version and certain features + * may be unavailable. + */ + private GuacamoleProtocolVersion protocol = + GuacamoleProtocolVersion.VERSION_1_0_0; + /** * Waits for the instruction having the given opcode, returning that * instruction once it has been read. If the instruction is never read, @@ -137,6 +145,13 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { // Build args list off provided names and config List arg_names = args.getArgs(); + + // Check for protocol version as first argument + if (arg_names.get(0).startsWith("VERSION_")) { + String protocolArg = arg_names.get(0); + protocol = GuacamoleProtocolVersion.valueOf(protocolArg); + } + String[] arg_values = new String[arg_names.size()]; for (int i=0; i otherVersion.getMajor()) + return true; + + // Major version is less than or equal to. + else { + + // Major version is less than + if (major < otherVersion.getMajor()) + return false; + + // Major version is equal, minor version is greater + if (minor > otherVersion.getMinor()) + return true; + + // Minor version is less than or equal to. + else { + + // Minor version is less than + if (minor < otherVersion.getMinor()) + return false; + + // Patch version is greater or equal + if (patch >= otherVersion.getPatch()) + return true; + } + } + + // Version is either less than or equal to. + return false; + + } + + /** + * Parses the given string version, returning the GuacamoleProtocolVersion + * object that matches the string version. If a matching version is not + * found an exception is thrown. + * + * @param version + * The String representation of a version to parse. + * + * @return + * The GuacamoleProtocolVersion that matches the string version + * that has been provided. + * + * @throws GuacamoleException + * If the string version does not match any known enum values. + */ + public static GuacamoleProtocolVersion parseVersion(String version) + throws GuacamoleException { + + for (GuacamoleProtocolVersion v : GuacamoleProtocolVersion.values()) { + if (v.getVersion().equals(version)) + return v; + } + + throw new GuacamoleUnsupportedException("Version " + version + + " of Guacamole protocol is not valid."); + + } + + /** + * Parse the version provided as individual version components to the + * matching enum version. If a match is not found an exception is + * thrown. + * + * @param major + * The integer major version. + * + * @param minor + * The integer minor version. + * + * @param patch + * The integer patch version. + * + * @return + * The GuacamoleProtocolVersion that matches the individual components + * that were provided. + * + * @throws GuacamoleException + * If the provided components do not match any known enum value. + */ + public static GuacamoleProtocolVersion parseVersion(int major, int minor, int patch) + throws GuacamoleException { + + for (GuacamoleProtocolVersion v : GuacamoleProtocolVersion.values()) { + if (v.getMajor() == major + && v.getMinor() == minor + && v.getPatch() == patch) + return v; + } + + throw new GuacamoleUnsupportedException("Version " + + Integer.toString(major) + "." + + Integer.toString(minor) + "." + + Integer.toString(patch) + + " is not valid."); + + } + +} From 644e69de0ad753e11632703d34c53cba0028b8fb Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 17 Apr 2019 15:19:38 -0400 Subject: [PATCH 12/26] GUACAMOLE-422: Tweak to checking for protocol version. --- .../protocol/ConfiguredGuacamoleSocket.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index a9b9898d7..c7544faa2 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -146,17 +146,17 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { // Build args list off provided names and config List arg_names = args.getArgs(); - // Check for protocol version as first argument - if (arg_names.get(0).startsWith("VERSION_")) { - String protocolArg = arg_names.get(0); - protocol = GuacamoleProtocolVersion.valueOf(protocolArg); - } - String[] arg_values = new String[arg_names.size()]; for (int i=0; i Date: Wed, 17 Apr 2019 15:32:31 -0400 Subject: [PATCH 13/26] GUACAMOLE-422: Clean up style and extra code. --- .../protocol/ConfiguredGuacamoleSocket.java | 1 - .../protocol/GuacamoleClientInformation.java | 2 +- .../protocol/GuacamoleProtocolVersion.java | 94 ++----------------- .../directives/guacSettingsPreferences.js | 1 - 4 files changed, 7 insertions(+), 91 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index c7544faa2..98c054df6 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -145,7 +145,6 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { // Build args list off provided names and config List arg_names = args.getArgs(); - String[] arg_values = new String[arg_names.size()]; for (int i=0; i imageMimetypes = new ArrayList(); /** - * The timezone report by the client. + * The timezone reported by the client. */ private String timezone = ""; diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index f2bb935f5..2c84516e3 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -29,12 +29,11 @@ import org.apache.guacamole.GuacamoleUnsupportedException; */ public enum GuacamoleProtocolVersion { - VERSION_1_0_0("1.0.0", 1, 0, 0), + // Version 1.0.0 and older. + VERSION_1_0_0(1, 0, 0), - VERSION_1_1_0("1.1.0", 1, 1, 0); - - // The string representation of the version. - private final String version; + // Version 1.1.0 + VERSION_1_1_0(1, 1, 0); // The major version number. private final int major; @@ -47,10 +46,7 @@ public enum GuacamoleProtocolVersion { /** * Generate a new GuacamoleProtocolVersion object with the given - * string version, major version, and minor version. - * - * @param version - * The String representation of the version. + * major version, minor version, and patch version. * * @param major * The integer representation of the major version component. @@ -61,23 +57,12 @@ public enum GuacamoleProtocolVersion { * @param patch * The integer representation of the patch version component. */ - GuacamoleProtocolVersion(String version, int major, int minor, int patch) { - this.version = version; + GuacamoleProtocolVersion(int major, int minor, int patch) { this.major = major; this.minor = minor; this.patch = patch; } - /** - * Return the string representation of the version. - * - * @return - * The string representation of the version. - */ - public String getVersion() { - return version; - } - /** * Return the major version number. * @@ -154,71 +139,4 @@ public enum GuacamoleProtocolVersion { } - /** - * Parses the given string version, returning the GuacamoleProtocolVersion - * object that matches the string version. If a matching version is not - * found an exception is thrown. - * - * @param version - * The String representation of a version to parse. - * - * @return - * The GuacamoleProtocolVersion that matches the string version - * that has been provided. - * - * @throws GuacamoleException - * If the string version does not match any known enum values. - */ - public static GuacamoleProtocolVersion parseVersion(String version) - throws GuacamoleException { - - for (GuacamoleProtocolVersion v : GuacamoleProtocolVersion.values()) { - if (v.getVersion().equals(version)) - return v; - } - - throw new GuacamoleUnsupportedException("Version " + version - + " of Guacamole protocol is not valid."); - - } - - /** - * Parse the version provided as individual version components to the - * matching enum version. If a match is not found an exception is - * thrown. - * - * @param major - * The integer major version. - * - * @param minor - * The integer minor version. - * - * @param patch - * The integer patch version. - * - * @return - * The GuacamoleProtocolVersion that matches the individual components - * that were provided. - * - * @throws GuacamoleException - * If the provided components do not match any known enum value. - */ - public static GuacamoleProtocolVersion parseVersion(int major, int minor, int patch) - throws GuacamoleException { - - for (GuacamoleProtocolVersion v : GuacamoleProtocolVersion.values()) { - if (v.getMajor() == major - && v.getMinor() == minor - && v.getPatch() == patch) - return v; - } - - throw new GuacamoleUnsupportedException("Version " - + Integer.toString(major) + "." - + Integer.toString(minor) + "." - + Integer.toString(patch) - + " is not valid."); - - } - } diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js index 4aeef47f4..71e7af73e 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsPreferences.js @@ -38,7 +38,6 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe // Required services var $translate = $injector.get('$translate'); var authenticationService = $injector.get('authenticationService'); - var formService = $injector.get('formService'); var guacNotification = $injector.get('guacNotification'); var languageService = $injector.get('languageService'); var permissionService = $injector.get('permissionService'); From 377e93c518fbee77fbfe04970d30d9b721bcaedf Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 24 Apr 2019 22:31:55 -0400 Subject: [PATCH 14/26] GUACAMOLE-422: Fix assignment of protocol version value in socket. --- .../org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java | 1 + 1 file changed, 1 insertion(+) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index 98c054df6..48844afdf 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -155,6 +155,7 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { if (i == 0 && arg_name.startsWith("VERSION_")) { protocol = GuacamoleProtocolVersion.valueOf(arg_name); arg_values[i] = protocol.toString(); + continue; } // Get defined value for name From 381bca07fdeceb8907eae93f9c8153ce60b17473 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 6 May 2019 11:27:04 -0400 Subject: [PATCH 15/26] GUACAMOLE-422: Add JSTZ license. --- guacamole/src/licenses/LICENSE | 30 +++++++++++++++++++ .../src/licenses/bundled/jstz-1.0.10/LICENSE | 22 ++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE diff --git a/guacamole/src/licenses/LICENSE b/guacamole/src/licenses/LICENSE index 51f5b2171..0a6d4072e 100644 --- a/guacamole/src/licenses/LICENSE +++ b/guacamole/src/licenses/LICENSE @@ -605,6 +605,36 @@ licenses; we recommend you read them, as their terms may differ from the terms above. +JSTZ (http://webjars.org/) +-------------------------- + + Version: 1.0.10 + From: 'WebJars' (http://webjars.org/) + License(s): + MIT (bundled/jstz-1.0.10/LICENSE) + +Copyright (c) 2012 Jon Nylander, project maintained at +https://bitbucket.org/pellepim/jstimezonedetect + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to +do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Logback (http://logback.qos.ch/) -------------------------------- diff --git a/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE b/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE new file mode 100644 index 000000000..c48af16c6 --- /dev/null +++ b/guacamole/src/licenses/bundled/jstz-1.0.10/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2012 Jon Nylander, project maintained at +https://bitbucket.org/pellepim/jstimezonedetect + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to +do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file From d534a7085d17f19aac963c62e843a3b17e650a57 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 6 May 2019 11:29:09 -0400 Subject: [PATCH 16/26] GUACAMOLE-422: Update documentation and style; tweaks to GuacamoleProtocolVersion implementation. --- .../protocol/ConfiguredGuacamoleSocket.java | 2 +- .../protocol/GuacamoleClientInformation.java | 3 +- .../protocol/GuacamoleProtocolVersion.java | 49 ++++++++++++++++--- .../guacamole/tunnel/TunnelRequest.java | 6 +-- .../settings/services/preferenceService.js | 3 +- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index 48844afdf..b014ffbc2 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -153,7 +153,7 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { // Check for protocol version as first argument if (i == 0 && arg_name.startsWith("VERSION_")) { - protocol = GuacamoleProtocolVersion.valueOf(arg_name); + protocol = GuacamoleProtocolVersion.getVersion(arg_name); arg_values[i] = protocol.toString(); continue; } diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index 3e351cc7c..1a1d9e306 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -151,7 +151,8 @@ public class GuacamoleClientInformation { } /** - * Return the timezone as reported by the client. + * Return the timezone as reported by the client, or an empty String if + * one is not set. * * @return * A string value of the timezone reported by the client. diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index 2c84516e3..8be7ac629 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -19,9 +19,6 @@ package org.apache.guacamole.protocol; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleUnsupportedException; - /** * An enum that defines the available Guacamole protocol versions that can be * used between guacd and clients, and provides convenience methods for parsing @@ -29,19 +26,35 @@ import org.apache.guacamole.GuacamoleUnsupportedException; */ public enum GuacamoleProtocolVersion { - // Version 1.0.0 and older. + /** + * Protocol version 1.0.0 and older. Any client that doesn't explicitly + * set the protocol version will negotiate down to this protocol version. + * This requires that handshake instructions be ordered correctly, and + * lacks support for certain protocol-related features introduced in later + * versions. + */ VERSION_1_0_0(1, 0, 0), - // Version 1.1.0 + /** + * Protocol version 1.1.0, which introduces Client-Server version + * detection, arbitrary handshake instruction order, and support + * for passing the client timezone to the server during the handshake. + */ VERSION_1_1_0(1, 1, 0); - // The major version number. + /** + * The major version component of the protocol version. + */ private final int major; - // The minor version number. + /** + * The minor version component of the protocol version. + */ private final int minor; - // The patch version number. + /** + * The patch version component of the protocol version. + */ private final int patch; /** @@ -139,4 +152,24 @@ public enum GuacamoleProtocolVersion { } + /** + * Parse the String format of the version provided and return the + * the enum value matching that version. If no value is provided, return + * null. + * + * @param version + * The String format of the version to parse. + * + * @return + * The enum value that matches the specified version. + */ + public static GuacamoleProtocolVersion getVersion(String version) { + + if (version == null || version.isEmpty()) + return null; + + return valueOf(version); + + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java index 1355a150e..74e3b4dcf 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java @@ -372,11 +372,11 @@ public abstract class TunnelRequest { } /** - * Returns the value of the timezone parameter declared within the - * tunnel request. + * Returns the tz database value of the timezone declared by the client + * within the tunnel request. * * @return - * The string value of the timezone parameter as reported by + * The tz database value of the timezone parameter as reported by * the client. */ public String getTimezone() { diff --git a/guacamole/src/main/webapp/app/settings/services/preferenceService.js b/guacamole/src/main/webapp/app/settings/services/preferenceService.js index 38241e1c6..161df5b93 100644 --- a/guacamole/src/main/webapp/app/settings/services/preferenceService.js +++ b/guacamole/src/main/webapp/app/settings/services/preferenceService.js @@ -104,7 +104,8 @@ angular.module('settings').provider('preferenceService', ['$injector', * by the JSTZ timezone library. * * @returns String - * The name of the currently-detected timezone. + * The name of the currently-detected timezone in tz database + * format. */ var getDetectedTimezone = function getDetectedTimezone() { return jstz.determine().name(); From ed7a99a11b61462b4e071c38b2f398a4bd357610 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 6 May 2019 11:58:59 -0400 Subject: [PATCH 17/26] GUACAMOLE-422: More documentation updates. --- .../protocol/GuacamoleProtocolVersion.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index 8be7ac629..d72b2b6c2 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -77,29 +77,30 @@ public enum GuacamoleProtocolVersion { } /** - * Return the major version number. + * Return the major version component of the protocol version. * * @return - * The integer major version. + * The integer major version component. */ public int getMajor() { return major; } /** - * Return the minor version number. + * Return the minor version component of the protocol version. * * @return - * The integer minor version. + * The integer minor version component. */ public int getMinor() { return minor; } /** - * Return the patch version number. + * Return the patch version component of the protocol version. + * * @return - * The integer patch version. + * The integer patch version component. */ public int getPatch() { return patch; From 74c07c893adc4d6e26314a8a297dde194f2c189f Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 6 May 2019 12:18:52 -0400 Subject: [PATCH 18/26] GUACAMOLE-422: Implement GuacamoleProtocolCapability enum. --- .../protocol/ConfiguredGuacamoleSocket.java | 5 +- .../protocol/GuacamoleProtocolCapability.java | 77 +++++++++++++++++++ .../protocol/GuacamoleProtocolVersion.java | 17 ++++ 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index b014ffbc2..0480d19fa 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -200,9 +200,8 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { info.getImageMimetypes().toArray(new String[0]) )); - // Protocol version 1.1.0 and higher options - - if (protocol.atLeast(GuacamoleProtocolVersion.VERSION_1_1_0)) { + // Check for support for timezone handshake + if (protocol.isSupported(GuacamoleProtocolCapability.TIMEZONE_HANDSHAKE)) { // Send client timezone, if available String timezone = info.getTimezone(); if (timezone != null && !timezone.isEmpty()) { diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java new file mode 100644 index 000000000..6d4bdd169 --- /dev/null +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolCapability.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.protocol; + +/** + * An enum that specifies protocol capabilities that can be used to help + * detect whether or not a particular protocol version contains a capability. + */ +public enum GuacamoleProtocolCapability { + + /** + * Whether or not the protocol supports arbitrary ordering of the + * handshake instructions. This was introduced in VERSION_1_1_0. + */ + ARBITRARY_HANDSHAKE_ORDER(GuacamoleProtocolVersion.VERSION_1_1_0), + + /** + * Whether or not the protocol supports the ability to dynamically + * detect the version client and server are running in order to allow + * compatibility between differing client and server versions. This + * was introduced in VERSION_1_1_0. + */ + PROTOCOL_VERSION_DETECTION(GuacamoleProtocolVersion.VERSION_1_1_0), + + /** + * Whether or not the protocol supports the timezone instruction during + * the Client-Server handshake phase. This was introduced in + * VERSION_1_1_0. + */ + TIMEZONE_HANDSHAKE(GuacamoleProtocolVersion.VERSION_1_1_0); + + /** + * The minimum protocol version required to support this capability. + */ + private final GuacamoleProtocolVersion version; + + /** + * Create a new enum value with the given protocol version as the minimum + * required to support the capability. + * + * @param version + * The minimum required protocol version for supporting the + * capability. + */ + GuacamoleProtocolCapability(GuacamoleProtocolVersion version) { + this.version = version; + } + + /** + * Returns the minimum protocol version required to support this + * capability. + * + * @return + * The minimum protocol version required to support this capability. + */ + public GuacamoleProtocolVersion getVersion() { + return version; + } + +} diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index d72b2b6c2..41143c8b7 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -173,4 +173,21 @@ public enum GuacamoleProtocolVersion { } + /** + * Returns true if the specified capability is supported in the current + * protocol version, otherwise false. + * + * @param capability + * The protocol capability that is being checked for support. + * + * @return + * True if the capability is supported in the current version, + * otherwise false. + */ + public boolean isSupported(GuacamoleProtocolCapability capability) { + + return atLeast(capability.getVersion()); + + } + } From f4b41e8b19c69589eaf919f39c070ecdfcfb9926 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 6 May 2019 16:25:08 -0400 Subject: [PATCH 19/26] GUACAMOLE-422: Use null exclusively for missing timezone. --- .../guacamole/protocol/ConfiguredGuacamoleSocket.java | 2 +- .../guacamole/protocol/GuacamoleClientInformation.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index 0480d19fa..450cef7f5 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -204,7 +204,7 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { if (protocol.isSupported(GuacamoleProtocolCapability.TIMEZONE_HANDSHAKE)) { // Send client timezone, if available String timezone = info.getTimezone(); - if (timezone != null && !timezone.isEmpty()) { + if (timezone != null) { writer.writeInstruction( new GuacamoleInstruction( "timezone", diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index 1a1d9e306..65d7ad7eb 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -62,7 +62,7 @@ public class GuacamoleClientInformation { /** * The timezone reported by the client. */ - private String timezone = ""; + private String timezone; /** * Returns the optimal screen width requested by the client, in pixels. @@ -151,8 +151,8 @@ public class GuacamoleClientInformation { } /** - * Return the timezone as reported by the client, or an empty String if - * one is not set. + * Return the timezone as reported by the client, or null if the timezone + * is not set. Valid timezones are specified in tz database format. * * @return * A string value of the timezone reported by the client. @@ -162,7 +162,9 @@ public class GuacamoleClientInformation { } /** - * Set the string value of the timezone. + * Set the string value of the timezone, or null if the timezone will not + * be provided by the client. Valid timezones are specified in tz + * database format. * * @param timezone * The string value of the timezone reported by the client. From 12ea1cb5ddbdf56169e3aeed0c91cdc467c31284 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 6 May 2019 16:29:03 -0400 Subject: [PATCH 20/26] GUACAMOLE-422: Document valid timezone values for setting timezone. --- .../apache/guacamole/protocol/GuacamoleClientInformation.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index 65d7ad7eb..524eac8f4 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -167,7 +167,9 @@ public class GuacamoleClientInformation { * database format. * * @param timezone - * The string value of the timezone reported by the client. + * The string value of the timezone reported by the client, in tz + * database format, or null if the timezone is not provided by the + * client. */ public void setTimezone(String timezone) { this.timezone = timezone; From 786041668e7b36f01fbd998d13d68164ea7b5642 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 10 May 2019 12:08:19 -0400 Subject: [PATCH 21/26] GUACAMOLE-422: Fix JSTZ license information. --- guacamole/src/licenses/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole/src/licenses/LICENSE b/guacamole/src/licenses/LICENSE index 0a6d4072e..a2cd63d26 100644 --- a/guacamole/src/licenses/LICENSE +++ b/guacamole/src/licenses/LICENSE @@ -609,7 +609,7 @@ JSTZ (http://webjars.org/) -------------------------- Version: 1.0.10 - From: 'WebJars' (http://webjars.org/) + From: 'Jon Nylander' (https://pellepim.bitbucket.io/jstz/) License(s): MIT (bundled/jstz-1.0.10/LICENSE) From 06315a88b3e8cdd10dea32b163e007f83b81fcc1 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 10 May 2019 12:09:06 -0400 Subject: [PATCH 22/26] GUACAMOLE-422: Fix JSTZ license information, round 2. --- guacamole/src/licenses/LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guacamole/src/licenses/LICENSE b/guacamole/src/licenses/LICENSE index a2cd63d26..1e228d2e5 100644 --- a/guacamole/src/licenses/LICENSE +++ b/guacamole/src/licenses/LICENSE @@ -605,8 +605,8 @@ licenses; we recommend you read them, as their terms may differ from the terms above. -JSTZ (http://webjars.org/) --------------------------- +JSTZ (https://pellepim.bitbucket.io/jstz/) +------------------------------------------ Version: 1.0.10 From: 'Jon Nylander' (https://pellepim.bitbucket.io/jstz/) From dd9062a841bbb03ec93165386fe423f2ecb9999a Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 10 May 2019 12:33:59 -0400 Subject: [PATCH 23/26] GUACAMOLE-422: Update comments and internals of protocol methods. --- .../protocol/GuacamoleClientInformation.java | 7 +-- .../protocol/GuacamoleProtocolVersion.java | 47 +++++++------------ 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java index 524eac8f4..6d54a2f6c 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleClientInformation.java @@ -152,7 +152,8 @@ public class GuacamoleClientInformation { /** * Return the timezone as reported by the client, or null if the timezone - * is not set. Valid timezones are specified in tz database format. + * is not set. Valid timezones are specified in IANA zone key format, + * also known as Olson time zone database or TZ Database. * * @return * A string value of the timezone reported by the client. @@ -163,8 +164,8 @@ public class GuacamoleClientInformation { /** * Set the string value of the timezone, or null if the timezone will not - * be provided by the client. Valid timezones are specified in tz - * database format. + * be provided by the client. Valid timezones are specified in IANA zone + * key format (aka Olson time zone database or tz database). * * @param timezone * The string value of the timezone reported by the client, in tz diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index 41143c8b7..05da0600b 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -120,36 +120,16 @@ public enum GuacamoleProtocolVersion { */ public boolean atLeast(GuacamoleProtocolVersion otherVersion) { - // Major version is greater - if (major > otherVersion.getMajor()) - return true; + // If major is not the same, compare first + if (major != otherVersion.getMajor()) + return major > otherVersion.getMajor(); - // Major version is less than or equal to. - else { - - // Major version is less than - if (major < otherVersion.getMajor()) - return false; - - // Major version is equal, minor version is greater - if (minor > otherVersion.getMinor()) - return true; - - // Minor version is less than or equal to. - else { - - // Minor version is less than - if (minor < otherVersion.getMinor()) - return false; - - // Patch version is greater or equal - if (patch >= otherVersion.getPatch()) - return true; - } - } + // Major is the same, but minor is not, so compare minor versions + if (minor != otherVersion.getMinor()) + return minor > otherVersion.getMinor(); - // Version is either less than or equal to. - return false; + // Major and minor are identical, so compare and return patch + return patch >= otherVersion.getPatch(); } @@ -162,14 +142,21 @@ public enum GuacamoleProtocolVersion { * The String format of the version to parse. * * @return - * The enum value that matches the specified version. + * The enum value that matches the specified version, VERSION_1_0_0 + * if no match is found, or null if no comparison version is provided. */ public static GuacamoleProtocolVersion getVersion(String version) { if (version == null || version.isEmpty()) return null; - return valueOf(version); + try { + return valueOf(version); + } + // If nothing matches, then return the most compatible version. + catch (IllegalArgumentException e) { + return GuacamoleProtocolVersion.VERSION_1_0_0; + } } From b0698585f08b5d652883257c6e95fc3392e9b55c Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 10 May 2019 12:37:56 -0400 Subject: [PATCH 24/26] GUACAMOLE-422: Resolve commit conflict due to translation updates. --- guacamole/src/main/webapp/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole/src/main/webapp/translations/en.json b/guacamole/src/main/webapp/translations/en.json index 291f67b9a..a0a547888 100644 --- a/guacamole/src/main/webapp/translations/en.json +++ b/guacamole/src/main/webapp/translations/en.json @@ -506,7 +506,7 @@ "FIELD_HEADER_SERVER_ALIVE_INTERVAL" : "Server keepalive interval:", "FIELD_HEADER_SFTP_ROOT_DIRECTORY" : "File browser root directory:", "FIELD_HEADER_TERMINAL_TYPE" : "Terminal type:", - "FIELD_HEADER_TIMEZONE" : "Timezone:", + "FIELD_HEADER_TIMEZONE" : "Time zone ($TZ):", "FIELD_HEADER_TYPESCRIPT_NAME" : "Typescript name:", "FIELD_HEADER_TYPESCRIPT_PATH" : "Typescript path:", From 3c1f64ec612f93361773bb2b5f10028a0da6f1a1 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Fri, 10 May 2019 12:41:43 -0400 Subject: [PATCH 25/26] GUACAMOLE-422: Update timezone format comments in AngularJS component. --- .../webapp/app/settings/services/preferenceService.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/guacamole/src/main/webapp/app/settings/services/preferenceService.js b/guacamole/src/main/webapp/app/settings/services/preferenceService.js index 161df5b93..9c4d5fc94 100644 --- a/guacamole/src/main/webapp/app/settings/services/preferenceService.js +++ b/guacamole/src/main/webapp/app/settings/services/preferenceService.js @@ -104,8 +104,8 @@ angular.module('settings').provider('preferenceService', ['$injector', * by the JSTZ timezone library. * * @returns String - * The name of the currently-detected timezone in tz database - * format. + * The name of the currently-detected timezone in IANA zone key + * format (Olson time zone database). */ var getDetectedTimezone = function getDetectedTimezone() { return jstz.determine().name(); @@ -143,7 +143,9 @@ angular.module('settings').provider('preferenceService', ['$injector', language : getDefaultLanguageKey(), /** - * The timezone set by the uesr. + * The timezone set by the user, in IANA zone key format (Olson time + * zone database). + * * @type String */ timezone : getDetectedTimezone() From 1e13bdd319bdfd18bb6cb86147a1987400bceea3 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Sun, 2 Jun 2019 20:03:40 -0400 Subject: [PATCH 26/26] GUACAMOLE-422: Implement retrieval of most compatible version. --- .../protocol/GuacamoleProtocolVersion.java | 86 +++++++++++++++++-- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java index 05da0600b..3b38c427a 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleProtocolVersion.java @@ -19,6 +19,9 @@ package org.apache.guacamole.protocol; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * An enum that defines the available Guacamole protocol versions that can be * used between guacd and clients, and provides convenience methods for parsing @@ -42,6 +45,16 @@ public enum GuacamoleProtocolVersion { */ VERSION_1_1_0(1, 1, 0); + /** + * A regular expression that matches the VERSION_X_Y_Z pattern, where + * X is the major version component, Y is the minor version component, + * and Z is the patch version component. This expression puts each of + * the version components in their own group so that they can be easily + * used later. + */ + private static final Pattern VERSION_PATTERN = + Pattern.compile("^VERSION_([0-9]+)_([0-9]+)_([0-9]+)$"); + /** * The major version component of the protocol version. */ @@ -118,21 +131,54 @@ public enum GuacamoleProtocolVersion { * @return * True if this object is greater than or equal to the other version. */ - public boolean atLeast(GuacamoleProtocolVersion otherVersion) { + private boolean atLeast(GuacamoleProtocolVersion otherVersion) { - // If major is not the same, compare first + // If major is not the same, return inequality if (major != otherVersion.getMajor()) - return major > otherVersion.getMajor(); + return this.major > major; - // Major is the same, but minor is not, so compare minor versions + // Major is the same, but minor is not, return minor inequality if (minor != otherVersion.getMinor()) - return minor > otherVersion.getMinor(); + return this.minor > minor; - // Major and minor are identical, so compare and return patch + // Major and minor are equal, so return patch inequality return patch >= otherVersion.getPatch(); } + /** + * Compare this version with the major, minor, and patch components + * provided to the method, and determine if this version is compatible + * with the provided version, returning a boolean true if it is compatible, + * otherwise false. This version is compatible with the version specified + * by the provided components if the major, minor, and patch components + * are equivalent or less than those provided. + * + * @param major + * The major version component to compare for compatibility. + * + * @param minor + * The minor version component to compare for compatibility. + * + * @param patch + * The patch version component to compare for compatibility. + * + * @return + * True if this version is compatibility with the version components + * provided, otherwise false. + */ + private boolean isCompatible(int major, int minor, int patch) { + + if (this.major != major) + return this.major < major; + + if (this.minor != minor) + return this.minor < minor; + + return this.patch <= patch; + + } + /** * Parse the String format of the version provided and return the * the enum value matching that version. If no value is provided, return @@ -147,15 +193,39 @@ public enum GuacamoleProtocolVersion { */ public static GuacamoleProtocolVersion getVersion(String version) { + // If nothing is passed in, return null if (version == null || version.isEmpty()) return null; + // Check the string against the pattern matcher + Matcher versionMatcher = VERSION_PATTERN.matcher(version); + + // If there is no RegEx match, return null + if (!versionMatcher.matches()) + return null; + try { + // Try the valueOf function return valueOf(version); + } - // If nothing matches, then return the most compatible version. + + // If nothing matches, find the closest compatible version. catch (IllegalArgumentException e) { - return GuacamoleProtocolVersion.VERSION_1_0_0; + int myMajor = Integer.parseInt(versionMatcher.group(1)); + int myMinor = Integer.parseInt(versionMatcher.group(2)); + int myPatch = Integer.parseInt(versionMatcher.group(3)); + + GuacamoleProtocolVersion myVersion = VERSION_1_0_0; + + // Loop through possible versions, grabbing the latest compatible + for (GuacamoleProtocolVersion v : values()) { + if (v.isCompatible(myMajor, myMinor, myPatch)) + myVersion = v; + } + + return myVersion; + } }