/** * Connects to the hub. Errors if there is already a hub connection. * Will cancel a pending reconnection if there is one. This method is * not guaranteed to connect on first try. */ public async void Connect() { if (hubConnectionHandler != null) { throw new Exception("Already connected."); } if (!league.IsConnected) { return; } try { DebugLogger.Global.WriteMessage("Connecting to Rift..."); // Cancel pending reconnect if there is one. if (reconnectCancellationTokenSource != null) { DebugLogger.Global.WriteMessage($"Canceling older reconnect to Rift."); reconnectCancellationTokenSource.Cancel(); reconnectCancellationTokenSource = null; } // Ensure that our token is still valid... bool valid = false; // in case first startup and hub token is empty if (!Persistence.GetHubToken().IsNullOrEmpty()) { DebugLogger.Global.WriteMessage("Requesting hub token.."); var response = await httpClient.GetStringAsync(App.HUB + "/check?token=" + Persistence.GetHubToken()); valid = response == "true"; DebugLogger.Global.WriteMessage($"Hub token validity: {(valid ? "valid" : "invalid")}."); } // ... and request a new one if it isn't. if (!valid) { DebugLogger.Global.WriteMessage($"Requesting hub token.."); var payload = string.Format("{{\"pubkey\":\"{0}\"}}", CryptoHelpers.ExportPublicKey()); var responseBlob = await httpClient.PostAsync(App.HUB + "/register", new StringContent(payload, Encoding.UTF8, "application/json")); var response = SimpleJson.DeserializeObject <dynamic>(await responseBlob.Content.ReadAsStringAsync()); if (!response["ok"]) { throw new Exception("Could not receive JWT from Rift"); } Persistence.SetHubToken(response["token"]); DebugLogger.Global.WriteMessage($"Hub token: {response["token"]}."); } // Connect to hub. Will error if token is invalid or server is down, which will prompt a reconnection. hubConnectionHandler = new HubConnectionHandler(league); hubConnectionHandler.OnClose += CloseAndReconnect; // We assume to be connected. if (isNewLaunch) { DebugLogger.Global.WriteMessage($"Creating New Launch popup."); //app.ShowNotification("Connected to League. Click here for instructions on how to control your League client from your phone."); isNewLaunch = false; } hasTriedImmediateReconnect = false; } catch (Exception e) { DebugLogger.Global.WriteError($"Connection to Rift failed, an exception occurred: {e.ToString()}"); // Something happened that we didn't anticipate for. // Just try again in a bit. CloseAndReconnect(); } }
/** * Handles a message incoming through rift. First checks its opcode, then possibly decrypts the contents. */ public void HandleMessage(dynamic msg) { if (key != null) { try { var contents = CryptoHelpers.DecryptAES(key, (string)msg); this.HandleMimicMessage(SimpleJson.DeserializeObject(contents)); } catch { // Ignore message. return; } } if (!(msg is JsonArray)) { return; } if (msg[0] == (long)MobileOpcode.Secret) { var info = CryptoHelpers.DecryptRSA((string)msg[1]); if (info == null) { this.SendRaw("[" + MobileOpcode.SecretResponse + ",false]"); return; } dynamic contents = SimpleJson.DeserializeObject(info); if (contents["secret"] == null || contents["identity"] == null || contents["device"] == null || contents["browser"] == null) { return; } // If this device is already approved, immediately respond. if (Persistence.IsDeviceApproved(contents["identity"])) { this.key = Convert.FromBase64String((string)contents["secret"]); this.SendRaw("[" + (long)MobileOpcode.SecretResponse + ",true]"); } else { // Note: UI prompt needs to happen on an STA thread. var promptThread = new Thread(() => { // Else, prompt the user. var window = new DeviceConnectionPrompt((string)contents["device"], (string)contents["browser"], result => { // If approved, save the device identity and set the key. if (result) { this.key = Convert.FromBase64String((string)contents["secret"]); Persistence.ApproveDevice(contents["identity"]); } // Send the result of the prompt to the device. this.SendRaw("[" + (long)MobileOpcode.SecretResponse + "," + result.ToString().ToLower() + "]"); }); window.Show(); window.Focus(); Dispatcher.Run(); }); promptThread.SetApartmentState(ApartmentState.STA); promptThread.Start(); } } }