// Communication private void TrySend(byte[] buffer, bool doEncryption) { byte[] b = buffer; if (doEncryption && serverEncryptor != null) { b = serverEncryptor.AESEncryptBytes(buffer); } WriteResult result = client.SendWithTimeout(maxPingMs, b); if (result.Status != WriteResultStatus.Success) { throw new FailedSendingException($"Could not send data ({result.Status})."); } }
private async Task EstablishConnection() { await Task.Run(() => { CommunicationResult res = null; byte[] buffer = null; // Deny, accept, or askpass res = TryRead(1, maxPingMs + Settings.SettingsData.MaxPermissionAskWaitMs); // Denied switch (res.Instruction) { case TTInstruction.Connection_RefuseBusy: throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it's busy right now."); case TTInstruction.Connection_RefuseDeny: throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it hasn't allowed you to send them files."); } // Encryption DataEncryptor encryptor = null; if (serverDevice.EncryptionEnabled) { // Check if server also has password set if (res.Instruction != TTInstruction.Connection_AskPass) { TrySend(new byte[] { (byte)TTInstruction.Connection_RefusePass }, false); throw new FailedConnectingException($"Connection to {serverDevice.Name} refused because you have set a password and it has none."); } // Send password encryptor = new DataEncryptor(serverDevice.EncryptionPassword); byte[] timePassword = TTNet.GenerateTimePasswordBytes(); buffer = new byte[1] { (byte)TTInstruction.Connection_SendPass }.ToList().Concat(encryptor.AESEncryptBytes(timePassword)).ToArray(); TrySend(buffer, false); // Receive password response res = TryRead(1); if (res.Instruction != TTInstruction.Connection_AcceptPass) { throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because you do not have the right password."); } // Receive password try { res = TryRead(TTNet.TimePasswordLength + 1); } catch (Exception e) { OnRecordableEvent("Caught " + e.Message, Console.ConsoleMessageType.Error); throw new Exception(); } // Check password byte[] receivedTimePassword = encryptor.AESDecryptBytes(res.Data); if (Enumerable.SequenceEqual(timePassword, receivedTimePassword) || !TTNet.CheckTimePasswordValid(receivedTimePassword, serverDevice, maxPingMs)) { // TODO Send RefusePass to server throw new FailedConnectingException($"Connection to {serverDevice.Name} refused because it did not have the correct password."); } } else { // Check if server also doesn't use password if (res.Instruction != TTInstruction.Connection_Accept) { TrySend(new byte[] { (byte)TTInstruction.Connection_RefuseDeny }, false); // TODO Doesn't work, server doesn't recognize this scenario throw new FailedConnectingException($"Connection to {serverDevice.Name} failed because it requires a password and none is set."); } } // Send connection accept TrySend(new byte[] { (byte)TTInstruction.Connection_Accept }, false); serverEncryptor = encryptor; OnRecordableEvent($"Established { (serverDevice.EncryptionEnabled ? "secure " : "")}connection with {serverDevice.Name}.", Console.ConsoleMessageType.Common); }); }
private async Task EstablishConnection(string ipPort) { await Task.Run(() => { if (ipPort == null || ipPort == "") { throw new FailedConnectingException("Wrong IP."); } string[] ipParts = ipPort.Split(':'); if (ipParts.Length != 2) { throw new FailedConnectingException("Wrong IP."); } IPAddress deviceIP; if (!IPAddress.TryParse(ipParts[0], out deviceIP)) { throw new FailedConnectingException("Unknown IP."); } Device remoteDevice = Settings.SettingsData.GetDevice(deviceIP); if (remoteDevice == null) { throw new FailedConnectingException("Unknown IP."); } CommunicationResult res = null; byte[] buffer = null; // Check busy if (IsBusy) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseBusy }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because busy."); } // Check permission if (remoteDevice.ReceiveMode == DeviceReceiveMode.Deny) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseDeny }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it's not allowed."); } if (remoteDevice.ReceiveMode == DeviceReceiveMode.AskEachTime) { timer = new Timer(Settings.SettingsData.MaxPermissionAskWaitMs); timer.Elapsed += Events_TimerPermissionAskTimeout; timer.Start(); bool allowed = false; Application.Current.Dispatcher.Invoke(() => { confirmationDialog = new Settings.ConfirmationDialog("Accept connection?", $"Do you want to accept a connection from '{remoteDevice.Name}'?", "Yes", "No"); confirmationDialog.Owner = Application.Current.MainWindow; allowed = confirmationDialog.ShowDialog() ?? false; }); timer.Stop(); timer.Dispose(); if (!allowed) { timer.Stop(); timer.Dispose(); TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseDeny }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because you refused it."); } } // Encryption DataEncryptor encryptor = null; if (remoteDevice.EncryptionEnabled) { encryptor = new DataEncryptor(remoteDevice.EncryptionPassword); // Ask for password TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_AskPass }); // Receive password res = TryRead(ipPort, 1 + TTNet.TimePasswordLength, false); if (res.Instruction != TTInstruction.Connection_SendPass) { if (res.Instruction == TTInstruction.Connection_RefuseDeny) { throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused refused because it did not have a password."); } } // Check password byte[] receivedTimePassword = encryptor.AESDecryptBytes(res.Data); if (!TTNet.CheckTimePasswordValid(receivedTimePassword, remoteDevice, maxPingMs)) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefusePass }); throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it did not have the correct password."); } TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_AcceptPass }); // Send password byte[] timePassword = TTNet.GenerateTimePasswordBytes(); buffer = new byte[1] { (byte)TTInstruction.Connection_SendPass }.ToList().Concat(encryptor.AESEncryptBytes(timePassword)).ToArray(); TrySend(ipPort, buffer); } else { // Send connection accept TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_Accept }); } // Wait if client accepted connection res = TryRead(ipPort, 1, false); if (res.Instruction != TTInstruction.Connection_Accept) { if (res.Instruction == TTInstruction.Connection_RefusePass) { throw new FailedConnectingException($"Connection from {remoteDevice.Name} refused because it requires a password and none is set."); } } // Check busy again if (IsBusy) { TrySend(ipPort, new byte[] { (byte)TTInstruction.Connection_RefuseBusy }); throw new FailedConnectingException($"Refused connection from {remoteDevice.Name} because busy."); } clientDevice = remoteDevice; clientIpPort = ipPort; clientEncryptor = encryptor; OnRecordableEvent($"Established { (clientDevice.EncryptionEnabled ? "secure " : "")}connection with {remoteDevice.Name}.", Console.ConsoleMessageType.Common); }); }