public static UserCapsula Run(Stream stream, Action <string> log, ServerConfig config) { ClientHandshake clientHandshake = TextEncoder.ReadClientHandshake(stream); X509Certificate2 clientCertificate = X509Certificate2Utils.ImportFromPem(clientHandshake.PemCertificate); log($"Logging user sent username {clientHandshake.UserName}\n Certificate:\n {clientHandshake.PemCertificate}"); log("Generating random bytes"); byte[] randomBytes = LUtils.GenerateRandomBytes(TcpConstants.HANDSHAKE_LENGHT); log("Sending encrypted bytes"); BinaryEncoder.SendBytes(stream, RSAEncoder.Encrypt(randomBytes, clientCertificate)); ServerHandshake errorHandshake = new ServerHandshake() { Errors = "", NewUser = false, Succeeded = false, UserId = -1, UserName = "" }; byte[] received = BinaryEncoder.ReceiveBytes(stream); if (!randomBytes.SequenceEqual(received)) { log("Sending error to client."); errorHandshake.Errors = "Client's certificate verification failed."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Certificate verification succeeded."); Users user; String message; Clients client; bool newUser = false; using (Context context = new Context(config)) { SHA1 sha = new SHA1CryptoServiceProvider(); byte[] hash = sha.ComputeHash(clientCertificate.RawData); user = context.Users.SingleOrDefault(u => u.PublicCertificateSha1.SequenceEqual(hash)); if (user == null) { log("User doesn't exist yet. I'll try to create him."); newUser = true; log("Checking the uniquity of username."); String userName = clientHandshake.UserName; if (context.Users.SingleOrDefault(u => u.UserName.Equals(userName)) != null) { log("Username isn't unique."); errorHandshake.Errors = "Username isn't unique."; TextEncoder.SendJson(stream, errorHandshake); throw new Exception(errorHandshake.Errors); } log("Creating user."); user = new Users() { PublicCertificate = clientHandshake.PemCertificate, PublicCertificateSha1 = hash, UserName = clientHandshake.UserName }; context.Users.Add(user); context.SaveChanges(); message = "User successfully created."; log("User successfully created."); } else { message = "User exists."; log("User exists."); } client = new Clients() { UserId = user.Id }; if (clientHandshake.ClientId == null) { context.Add(client); context.SaveChanges(); log($"Added client with Id {client.Id}."); } else { log($"Client with Id {client.Id} has logged in."); } } ServerHandshake toSend = new ServerHandshake() { Errors = message, NewUser = newUser, Succeeded = true, UserId = user.Id, UserName = user.UserName, ClientId = client.Id }; TextEncoder.SendJson(stream, toSend); UserCapsula ret = new UserCapsula(user, clientCertificate); log($"Handshake successeded. User {ret.UserName} with id {ret.UserId} has logged in"); return(ret); }
public void Run(TcpClient client) { try { logger.Log(this, String.Format("Godot has been activated. Client IP address is {0}", LUtils.GetIpAddress(client))); godotCounter.IncreaseRunning(); stream = new SslStream(client.GetStream(), false, CertificateValidation); stream.AuthenticateAsServer(serverCert, true, SslProtocols.Tls12, false); logger.Log(this, "SSL authentication completed. Starting Handshake."); this.user = Handshake.Run(stream, Log, config); InitSync(); bool running = true; while (running) { ConnectionCommand command = TextEncoder.ReadCommand(stream); switch (command) { case ConnectionCommand.TRUST_CONTACT: Log("TRUST_CONTACT command received."); TrustContact(); break; case ConnectionCommand.UNTRUST_CONTACT: Log("UNTRUST_CONTACT command received."); UntrustContact(); break; case ConnectionCommand.PULL: #if (DEBUG) Log("PULL command received."); #endif Push(); break; case ConnectionCommand.PUSH: #if (DEBUG) Log("PUSH command received."); #endif Pull(); break; case ConnectionCommand.CREATE_ONLIVE_TUNNEL: Log("CREATE_ONLIVE_TUNNEL command received."); CreateOnliveTunnel(); break; case ConnectionCommand.END_CONNECTION: Log("END_CONNECTION command received."); running = false; break; default: throw new ChatovatkoException(this, "Received unknown command."); } } } catch (Exception ex) { logger.Log(this, String.Format("Godot has crashed. Exception:\n{0}\n{1}\n{2}", ex.GetType().Name, ex.Message, ex.StackTrace)); } finally { stream.Close(); client.Close(); godotCounter.IncreaseDestroyed(); logger.Log(this, "Godot has died."); } }