summaryrefslogtreecommitdiff
path: root/remoting
diff options
context:
space:
mode:
Diffstat (limited to 'remoting')
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/Chromoting.java16
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/Desktop.java16
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/HostInfo.java42
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/HostListLoader.java7
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/ThirdPartyTokenFetcher.java65
-rw-r--r--remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java8
-rw-r--r--remoting/client/jni/chromoting_jni_instance.cc38
-rw-r--r--remoting/client/jni/chromoting_jni_instance.h4
-rw-r--r--remoting/client/jni/chromoting_jni_runtime.cc4
-rwxr-xr-xremoting/host/linux/linux_me2me_host.py44
-rwxr-xr-xremoting/webapp/build-webapp.py2
-rw-r--r--remoting/webapp/html/ui_me2me.html25
12 files changed, 171 insertions, 100 deletions
diff --git a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
index 42d66035fe..1928f3c715 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
@@ -281,9 +281,12 @@ public class Chromoting extends Activity implements JniInterface.ConnectionListe
@Override
public void onCancel(DialogInterface dialog) {
JniInterface.disconnectFromHost();
+ mTokenFetcher = null;
}
});
SessionConnector connector = new SessionConnector(this, this, mHostListLoader);
+ assert mTokenFetcher == null;
+ mTokenFetcher = createTokenFetcher(host);
connector.connectToHost(mAccount.name, mToken, host);
}
@@ -459,9 +462,7 @@ public class Chromoting extends Activity implements JniInterface.ConnectionListe
}
}
- public void fetchThirdPartyToken(String tokenUrl, String clientId, String scope) {
- assert mTokenFetcher == null;
-
+ private ThirdPartyTokenFetcher createTokenFetcher(HostInfo host) {
ThirdPartyTokenFetcher.Callback callback = new ThirdPartyTokenFetcher.Callback() {
public void onTokenFetched(String code, String accessToken) {
// The native client sends the OAuth authorization code to the host as the token so
@@ -476,10 +477,11 @@ public class Chromoting extends Activity implements JniInterface.ConnectionListe
JniInterface.nativeOnThirdPartyTokenFetched(token, sharedSecret);
}
};
-
- mTokenFetcher = new ThirdPartyTokenFetcher(this, tokenUrl, clientId, scope, callback);
- mTokenFetcher.fetchToken();
+ return new ThirdPartyTokenFetcher(this, host.getTokenUrlPatterns(), callback);
}
-
+ public void fetchThirdPartyToken(String tokenUrl, String clientId, String scope) {
+ assert mTokenFetcher != null;
+ mTokenFetcher.fetchToken(tokenUrl, clientId, scope);
+ }
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
index f7fad3fa50..8868d5ad95 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -210,40 +210,38 @@ public class Desktop extends Activity implements View.OnSystemUiVisibilityChange
mPressedTextKeys.add(keyCode);
int[] codePoints = { unicode };
JniInterface.sendTextEvent(new String(codePoints, 0, 1));
- return super.dispatchKeyEvent(event);
+ return true;
}
if (!pressed && mPressedTextKeys.contains(keyCode)) {
mPressedTextKeys.remove(keyCode);
- return super.dispatchKeyEvent(event);
+ return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_AT:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, pressed);
- break;
+ return true;
case KeyEvent.KEYCODE_POUND:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, pressed);
- break;
+ return true;
case KeyEvent.KEYCODE_STAR:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, pressed);
- break;
+ return true;
case KeyEvent.KEYCODE_PLUS:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, pressed);
- break;
+ return true;
default:
// We try to send all other key codes to the host directly.
- JniInterface.sendKeyEvent(keyCode, pressed);
+ return JniInterface.sendKeyEvent(keyCode, pressed);
}
-
- return super.dispatchKeyEvent(event);
}
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/HostInfo.java b/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
index 229764ff24..ebc08299f7 100644
--- a/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
+++ b/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
@@ -4,6 +4,12 @@
package org.chromium.chromoting;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
/** Class to represent a Host returned by {@link HostListLoader}. */
public class HostInfo {
public final String name;
@@ -11,12 +17,46 @@ public class HostInfo {
public final String jabberId;
public final String publicKey;
public final boolean isOnline;
+ private final ArrayList<String> mTokenUrlPatterns;
- public HostInfo(String name, String id, String jabberId, String publicKey, boolean isOnline) {
+ public HostInfo(String name,
+ String id,
+ String jabberId,
+ String publicKey,
+ ArrayList<String> tokenUrlPatterns,
+ boolean isOnline) {
this.name = name;
this.id = id;
this.jabberId = jabberId;
this.publicKey = publicKey;
+ this.mTokenUrlPatterns = tokenUrlPatterns;
this.isOnline = isOnline;
}
+
+ public ArrayList<String> getTokenUrlPatterns() {
+ return new ArrayList<String>(mTokenUrlPatterns);
+ }
+
+ public static HostInfo create(JSONObject json) throws JSONException {
+ assert json != null;
+
+ ArrayList<String> tokenUrlPatterns = new ArrayList<String>();
+ JSONArray jsonPatterns = json.optJSONArray("tokenUrlPatterns");
+
+ if (jsonPatterns != null) {
+ for (int i = 0; i < jsonPatterns.length(); i++) {
+ String pattern = jsonPatterns.getString(i);
+ if (pattern != null && !pattern.isEmpty()) {
+ tokenUrlPatterns.add(pattern);
+ }
+ }
+ }
+ return new HostInfo(
+ json.getString("hostName"),
+ json.getString("hostId"),
+ json.optString("jabberId"),
+ json.optString("publicKey"),
+ tokenUrlPatterns,
+ json.optString("status").equals("ONLINE"));
+ }
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/HostListLoader.java b/remoting/android/java/src/org/chromium/chromoting/HostListLoader.java
index 8f3b6bd257..bfcdfd8ada 100644
--- a/remoting/android/java/src/org/chromium/chromoting/HostListLoader.java
+++ b/remoting/android/java/src/org/chromium/chromoting/HostListLoader.java
@@ -145,12 +145,7 @@ public class HostListLoader {
// attempt will fail because of the missing keys. The failed attempt will
// trigger reloading of the host-list, by which time the keys will hopefully be
// present, and the retried connection can succeed.
- HostInfo host = new HostInfo(
- hostJson.getString("hostName"),
- hostJson.getString("hostId"),
- hostJson.optString("jabberId"),
- hostJson.optString("publicKey"),
- hostJson.optString("status").equals("ONLINE"));
+ HostInfo host = HostInfo.create(hostJson);
hostList.add(host);
++index;
}
diff --git a/remoting/android/java/src/org/chromium/chromoting/ThirdPartyTokenFetcher.java b/remoting/android/java/src/org/chromium/chromoting/ThirdPartyTokenFetcher.java
index a00038b175..ab593b849f 100644
--- a/remoting/android/java/src/org/chromium/chromoting/ThirdPartyTokenFetcher.java
+++ b/remoting/android/java/src/org/chromium/chromoting/ThirdPartyTokenFetcher.java
@@ -10,10 +10,12 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import java.security.SecureRandom;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -51,46 +53,42 @@ public class ThirdPartyTokenFetcher {
*/
private final String mState;
- /** URL of the third party login page. */
- private final String mTokenUrl;
-
- /** The client identifier. See http://tools.ietf.org/html/rfc6749#section-2.2. */
- private final String mClientId;
-
- /** The scope of access request. See http://tools.ietf.org/html/rfc6749#section-3.3. */
- private final String mScope;
-
private final Callback mCallback;
+ /** The list of TokenUrls allowed by the domain. */
+ private final ArrayList<String> mTokenUrlPatterns;
+
private final String mRedirectUriScheme;
private final String mRedirectUri;
public ThirdPartyTokenFetcher(Activity context,
- String tokenUrl,
- String clientId,
- String scope,
+ ArrayList<String> tokenUrlPatterns,
Callback callback) {
this.mContext = context;
- this.mTokenUrl = tokenUrl;
- this.mClientId = clientId;
this.mState = generateXsrfToken();
- this.mScope = scope;
this.mCallback = callback;
+ this.mTokenUrlPatterns = tokenUrlPatterns;
this.mRedirectUriScheme = context.getApplicationContext().getPackageName();
this.mRedirectUri = mRedirectUriScheme + "://" + REDIRECT_URI_HOST;
}
- public void fetchToken() {
- Uri.Builder uriBuilder = Uri.parse(mTokenUrl).buildUpon();
- uriBuilder.appendQueryParameter("redirect_uri", this.mRedirectUri);
- uriBuilder.appendQueryParameter("scope", mScope);
- uriBuilder.appendQueryParameter("client_id", mClientId);
- uriBuilder.appendQueryParameter("state", mState);
- uriBuilder.appendQueryParameter("response_type", RESPONSE_TYPE);
+ /**
+ * @param tokenUrl URL of the third party login page.
+ * @param clientId The client identifier. See http://tools.ietf.org/html/rfc6749#section-2.2.
+ * @param scope The scope of access request. See http://tools.ietf.org/html/rfc6749#section-3.3.
+ */
+ public void fetchToken(String tokenUrl, String clientId, String scope) {
+ if (!isValidTokenUrl(tokenUrl)) {
+ failFetchToken(
+ "Token URL does not match the domain\'s allowed URL patterns." +
+ " URL: " + tokenUrl +
+ ", patterns: " + TextUtils.join(",", this.mTokenUrlPatterns));
+ return;
+ }
- Uri uri = uriBuilder.build();
+ Uri uri = buildRequestUri(tokenUrl, clientId, scope);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
Log.i("ThirdPartyAuth", "fetchToken() url:" + uri);
OAuthRedirectActivity.setEnabled(mContext, true);
@@ -102,6 +100,27 @@ public class ThirdPartyTokenFetcher {
}
}
+ private Uri buildRequestUri(String tokenUrl, String clientId, String scope) {
+ Uri.Builder uriBuilder = Uri.parse(tokenUrl).buildUpon();
+ uriBuilder.appendQueryParameter("redirect_uri", this.mRedirectUri);
+ uriBuilder.appendQueryParameter("scope", scope);
+ uriBuilder.appendQueryParameter("client_id", clientId);
+ uriBuilder.appendQueryParameter("state", mState);
+ uriBuilder.appendQueryParameter("response_type", RESPONSE_TYPE);
+
+ return uriBuilder.build();
+ }
+
+ /** Verifies the host-supplied URL matches the domain's allowed URL patterns. */
+ private boolean isValidTokenUrl(String tokenUrl) {
+ for (String pattern : mTokenUrlPatterns) {
+ if (tokenUrl.matches(pattern)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isValidIntent(Intent intent) {
assert intent != null;
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
index 6691e4f577..6d1dfd1274 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -322,16 +322,16 @@ public class JniInterface {
private static native void nativeSendMouseWheelEvent(int deltaX, int deltaY);
/** Presses or releases the specified (nonnegative) key. Called on the UI thread. */
- public static void sendKeyEvent(int keyCode, boolean keyDown) {
+ public static boolean sendKeyEvent(int keyCode, boolean keyDown) {
if (!sConnected) {
- return;
+ return false;
}
- nativeSendKeyEvent(keyCode, keyDown);
+ return nativeSendKeyEvent(keyCode, keyDown);
}
/** Passes key press information to the native handling code. */
- private static native void nativeSendKeyEvent(int keyCode, boolean keyDown);
+ private static native boolean nativeSendKeyEvent(int keyCode, boolean keyDown);
/** Sends TextEvent to the host. Called on the UI thread. */
public static void sendTextEvent(String text) {
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index 9a929dd037..32aaa4be2c 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -210,23 +210,15 @@ void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
connection_->input_stub()->InjectMouseEvent(event);
}
-void ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) {
- if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
- jni_runtime_->network_task_runner()->PostTask(
- FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEvent,
- this, key_code, key_down));
- return;
- }
-
- uint32 usb_code = AndroidKeycodeToUsbKeycode(key_code);
- if (usb_code) {
- protocol::KeyEvent event;
- event.set_usb_keycode(usb_code);
- event.set_pressed(key_down);
- connection_->input_stub()->InjectKeyEvent(event);
- } else {
+bool ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) {
+ uint32 usb_key_code = AndroidKeycodeToUsbKeycode(key_code);
+ if (!usb_key_code) {
LOG(WARNING) << "Ignoring unknown keycode: " << key_code;
+ return false;
}
+
+ SendKeyEventInternal(usb_key_code, key_down);
+ return true;
}
void ChromotingJniInstance::SendTextEvent(const std::string& text) {
@@ -449,6 +441,22 @@ void ChromotingJniInstance::SetDeviceName(const std::string& device_name) {
device_name_ = device_name;
}
+void ChromotingJniInstance::SendKeyEventInternal(int usb_key_code,
+ bool key_down) {
+ if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
+ jni_runtime_->network_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&ChromotingJniInstance::SendKeyEventInternal,
+ this, usb_key_code, key_down));
+ return;
+ }
+
+
+ protocol::KeyEvent event;
+ event.set_usb_keycode(usb_key_code);
+ event.set_pressed(key_down);
+ connection_->input_stub()->InjectKeyEvent(event);
+}
+
void ChromotingJniInstance::EnableStatsLogging(bool enabled) {
DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h
index 8fb60232df..91919b27e5 100644
--- a/remoting/client/jni/chromoting_jni_instance.h
+++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -87,7 +87,7 @@ class ChromotingJniInstance
void SendMouseWheelEvent(int delta_x, int delta_y);
// Sends the provided keyboard scan code to the host.
- void SendKeyEvent(int key_code, bool key_down);
+ bool SendKeyEvent(int key_code, bool key_down);
void SendTextEvent(const std::string& text);
@@ -136,6 +136,8 @@ class ChromotingJniInstance
// Sets the device name. Can be called on any thread.
void SetDeviceName(const std::string& device_name);
+ void SendKeyEventInternal(int usb_key_code, bool key_down);
+
// Enables or disables periodic logging of performance statistics. Called on
// the network thread.
void EnableStatsLogging(bool enabled);
diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc
index cc84d4e791..f7a3ff1ea9 100644
--- a/remoting/client/jni/chromoting_jni_runtime.cc
+++ b/remoting/client/jni/chromoting_jni_runtime.cc
@@ -129,11 +129,11 @@ static void SendMouseWheelEvent(JNIEnv* env,
delta_x, delta_y);
}
-static void SendKeyEvent(JNIEnv* env,
+static jboolean SendKeyEvent(JNIEnv* env,
jclass clazz,
jint keyCode,
jboolean keyDown) {
- remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
+ return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
keyCode, keyDown);
}
diff --git a/remoting/host/linux/linux_me2me_host.py b/remoting/host/linux/linux_me2me_host.py
index 8f87dce0fb..082ecc0edb 100755
--- a/remoting/host/linux/linux_me2me_host.py
+++ b/remoting/host/linux/linux_me2me_host.py
@@ -500,14 +500,15 @@ class Desktop:
self.host_proc.stdin.close()
-def get_daemon_pid():
+def get_daemon_proc():
"""Checks if there is already an instance of this script running, and returns
- its PID.
+ a psutil.Process instance for it.
Returns:
- The process ID of the existing daemon process, or 0 if the daemon is not
- running.
+ A Process instance for the existing daemon process, or None if the daemon
+ is not running.
"""
+
uid = os.getuid()
this_pid = os.getpid()
@@ -535,11 +536,11 @@ def get_daemon_pid():
if len(cmdline) < 2:
continue
if cmdline[0] == sys.executable and cmdline[1] == sys.argv[0]:
- return process.pid
+ return process
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
- return 0
+ return None
def choose_x_session():
@@ -977,8 +978,8 @@ Web Store: https://chrome.google.com/remotedesktop"""
# Check for a modal command-line option (start, stop, etc.)
if options.get_status:
- pid = get_daemon_pid()
- if pid != 0:
+ proc = get_daemon_proc()
+ if proc is not None:
print "STARTED"
elif is_supported_platform():
print "STOPPED"
@@ -989,23 +990,28 @@ Web Store: https://chrome.google.com/remotedesktop"""
# TODO(sergeyu): Remove --check-running once NPAPI plugin and NM host are
# updated to always use get-status flag instead.
if options.check_running:
- pid = get_daemon_pid()
- return 0 if pid != 0 else 1
+ proc = get_daemon_proc()
+ return 1 if proc is None else 0
if options.stop:
- pid = get_daemon_pid()
- if pid == 0:
+ proc = get_daemon_proc()
+ if proc is None:
print "The daemon is not currently running"
else:
- print "Killing process %s" % pid
- os.kill(pid, signal.SIGTERM)
+ print "Killing process %s" % proc.pid
+ proc.terminate()
+ try:
+ proc.wait(timeout=30)
+ except psutil.TimeoutExpired:
+ print "Timed out trying to kill daemon process"
+ return 1
return 0
if options.reload:
- pid = get_daemon_pid()
- if pid == 0:
+ proc = get_daemon_proc()
+ if proc is None:
return 1
- os.kill(pid, signal.SIGHUP)
+ proc.send_signal(signal.SIGHUP)
return 0
if options.add_user:
@@ -1097,8 +1103,8 @@ Web Store: https://chrome.google.com/remotedesktop"""
# Determine whether a desktop is already active for the specified host
# host configuration.
- pid = get_daemon_pid()
- if pid != 0:
+ proc = get_daemon_proc()
+ if proc is not None:
# Debian policy requires that services should "start" cleanly and return 0
# if they are already running.
print "Service already running."
diff --git a/remoting/webapp/build-webapp.py b/remoting/webapp/build-webapp.py
index 4cbe4f0c46..df934f83b9 100755
--- a/remoting/webapp/build-webapp.py
+++ b/remoting/webapp/build-webapp.py
@@ -272,7 +272,7 @@ def main():
arg_type = ''
files = []
locales = []
- for arg in sys.argv[8:]:
+ for arg in sys.argv[7:]:
if arg in ['--locales']:
arg_type = arg
elif arg_type == '--locales':
diff --git a/remoting/webapp/html/ui_me2me.html b/remoting/webapp/html/ui_me2me.html
index 057157aa18..ca2cc46b18 100644
--- a/remoting/webapp/html/ui_me2me.html
+++ b/remoting/webapp/html/ui_me2me.html
@@ -41,6 +41,19 @@ found in the LICENSE file.
id="host-list-refresh-failed-button"></button>
</div>
+ <div id="host-list-empty" hidden>
+ <div id="host-list-empty-hosting-supported"
+ class="host-list-empty-instructions"
+ i18n-content="HOST_LIST_EMPTY_HOSTING_SUPPORTED"
+ i18n-value-name-1="HOME_DAEMON_START_BUTTON">
+ </div>
+ <div id="host-list-empty-hosting-unsupported"
+ class="host-list-empty-instructions"
+ i18n-content="HOST_LIST_EMPTY_HOSTING_UNSUPPORTED"
+ i18n-value-name-1="HOME_DAEMON_START_BUTTON">
+ </div>
+ </div>
+
<div id="daemon-control" data-daemon-state="enabled disabled" hidden>
<div class="section-row no-non-local-hosts"
data-daemon-state="disabled">
@@ -88,18 +101,6 @@ found in the LICENSE file.
i18n-content="HOME_DAEMON_MANAGE_PAIRINGS"></a>
</div>
</div> <!-- enabled -->
- <div id="host-list-empty" hidden>
- <div id="host-list-empty-hosting-supported"
- class="host-list-empty-instructions"
- i18n-content="HOST_LIST_EMPTY_HOSTING_SUPPORTED"
- i18n-value-name-1="HOME_DAEMON_START_BUTTON">
- </div>
- <div id="host-list-empty-hosting-unsupported"
- class="host-list-empty-instructions"
- i18n-content="HOST_LIST_EMPTY_HOSTING_UNSUPPORTED"
- i18n-value-name-1="HOME_DAEMON_START_BUTTON">
- </div>
- </div>
</div> <!-- daemon-control -->
</div> <!-- me2me-content -->