Example #1
0
        /// <summary>
        /// Loads the session from the request
        /// </summary>
        /// <param name="request">Request to load from</param>
        /// <returns>ISession containing the load session values</returns>
        public ISession Load(Request request)
        {
            var dictionary = new Dictionary <string, object>();

            // TODO - configurable path?
            if (request.Cookies.ContainsKey(cookieName))
            {
                var cookieData      = HttpUtility.UrlDecode(request.Cookies[cookieName]);
                var hmacLength      = Base64Helpers.GetBase64Length(this.hmacProvider.HmacLength);
                var hmacString      = cookieData.Substring(0, hmacLength);
                var encryptedCookie = cookieData.Substring(hmacLength);

                var hmacBytes = Convert.FromBase64String(hmacString);
                var newHmac   = this.hmacProvider.GenerateHmac(encryptedCookie);
                var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, this.hmacProvider.HmacLength);

                var data  = this.encryptionProvider.Decrypt(encryptedCookie);
                var parts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var part in parts.Select(part => part.Split('=')))
                {
                    var valueObject = this.serializer.Deserialize(HttpUtility.UrlDecode(part[1]));

                    dictionary[HttpUtility.UrlDecode(part[0])] = valueObject;
                }

                if (!hmacValid)
                {
                    dictionary.Clear();
                }
            }

            return(new Session(dictionary));
        }
        public async Task CheckInvalidNamespaces(string invalidNamespace)
        {
            // Create timestamp that will be used in algo name
            var algoCreationTimestamp = Helpers.GetTimestampIso8601();
            // Replace the default namespace with an invalid one
            var algoString = DummyAlgoString.Replace(GlobalConstants.AlgoDefaultNamespace, invalidNamespace);

            // Create algo object
            CreateAlgoDTO algoData = new CreateAlgoDTO()
            {
                Name        = $"{algoCreationTimestamp}{GlobalConstants.AutoTest}_AlgoName",
                Description = $"{algoCreationTimestamp}{GlobalConstants.AutoTest}_AlgoName - Description",
                Content     = Base64Helpers.EncodeToBase64(algoString)
            };

            // Create algo
            var createAlgoResponse = await Consumer.ExecuteRequest(ApiPaths.ALGO_STORE_CREATE_ALGO, Helpers.EmptyDictionary, JsonUtils.SerializeObject(algoData), Method.POST);

            var message = $"POST {ApiPaths.ALGO_STORE_CREATE_ALGO} returned status: {createAlgoResponse.Status} and response: {createAlgoResponse.ResponseJson}. Expected: {HttpStatusCode.BadRequest}";

            // Get user algos
            var userAlgos = (await GetUserAlgos()).Select(a => a.Name).ToList();

            // Assert algo is not created
            Assert.Multiple(() =>
            {
                Assert.That(createAlgoResponse.Status, Is.EqualTo(HttpStatusCode.BadRequest), message);
                Assert.That(createAlgoResponse.ResponseJson, Does.Contain("The provided namespace is not allowed").Or.Contains("Identifier expected"));
                Assert.That(userAlgos, Does.Not.Contain(algoData.Name));
            });
        }
        private DiagnosticsSession DecodeCookie(INancyCookie nancyCookie)
        {
            var cookieValue      = nancyCookie.Value;
            var hmacStringLength = Base64Helpers.GetBase64Length(this.cryptoConfig.HmacProvider.HmacLength);
            var encryptedSession = cookieValue.Substring(hmacStringLength);
            var decrypted        = this.cryptoConfig.EncryptionProvider.Decrypt(encryptedSession);

            return(this.objectSerializer.Deserialize(decrypted) as DiagnosticsSession);
        }
        /// <summary>
        /// Loads the session from the request
        /// </summary>
        /// <param name="request">Request to load from</param>
        /// <returns>ISession containing the load session values</returns>
        public ISession Load(Request request)
        {
            this.ExpireOldSessions();

            var dictionary = new Dictionary <string, object>();

            // Get the session Id from the encrypted cookie
            var cookieName         = this.currentConfiguration.CookieName;
            var hmacProvider       = this.currentConfiguration.CryptographyConfiguration.HmacProvider;
            var encryptionProvider = this.currentConfiguration.CryptographyConfiguration.EncryptionProvider;

            if (!request.Cookies.ContainsKey(cookieName))
            {
                return(CreateNewSession(dictionary));
            }

            var cookieData = HttpUtility.UrlDecode(request.Cookies[cookieName]);
            var hmacLength = Base64Helpers.GetBase64Length(hmacProvider.HmacLength);

            if (cookieData.Length < hmacLength)
            {
                return(CreateNewSession(dictionary));
            }

            var hmacString      = cookieData.Substring(0, hmacLength);
            var encryptedCookie = cookieData.Substring(hmacLength);

            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac   = hmacProvider.GenerateHmac(encryptedCookie);
            var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, hmacProvider.HmacLength);

            if (!hmacValid)
            {
                return(CreateNewSession(dictionary));
            }

            // Get the session itself from the database
            var id      = encryptionProvider.Decrypt(encryptedCookie);
            var session = Await(RethinkDbSessionStore.RetrieveSession(currentConfiguration, id));

            if (null == session)
            {
                return(CreateNewSession(dictionary));
            }

            if (currentConfiguration.UseRollingSessions)
            {
                Await(RethinkDbSessionStore.UpdateLastAccessed(currentConfiguration, id));
            }

            return(session);
        }
Example #5
0
 public void SetupRequestConfigData(Guid customerId, Purchase purchase)
 {
     RequestConfigData = new ServiceRequestConfigData()
     {
         Uri = new Uri($"https://lic.drmtoday.com/license-proxy-headerauth/drmtoday/RightsManager.asmx?assetId={purchase.AssetId}&variantId={purchase.VariantId}"),
         ChallengeCustomData = Base64Helpers.Base64Encode("{\"userId\":\"" + customerId + "\",\"sessionId\":\"" + purchase.PlayerSessionId + "\",\"merchant\":\"hboeurope\"}"),
         CustomArtibutes     = new List <KeyValuePair <string, string> >()
         {
             new KeyValuePair <string, string>("x-dt-auth-token", purchase.AuthToken),
             new KeyValuePair <string, string>("Origin", "https://www.hbogo.cz"),
         }
     };
 }
Example #6
0
        /// <summary>
        /// Decrypt and validate an encrypted and signed cookie value
        /// </summary>
        /// <param name="cookieValue">
        /// Encrypted and signed cookie value
        /// </param>
        /// <returns>
        /// Decrypted value, or empty on error or if failed validation
        /// </returns>
        private string DecryptAndValidateAuthenticationCookie(string cookieValue)
        {
            var hmacStringLength = Base64Helpers.GetBase64Length(this.currentConfiguration.CryptographyConfiguration.HmacProvider.HmacLength);

            var encryptedCookie = cookieValue.Substring(hmacStringLength);
            var hmacString      = cookieValue.Substring(0, hmacStringLength);

            // Check the hmacs, but don't early exit if they don't match
            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac   = this.GenerateHmac(encryptedCookie);
            var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, this.currentConfiguration.CryptographyConfiguration.HmacProvider.HmacLength);

            // Only return the decrypted result if the hmac was ok
            return(hmacValid ? cookieValue : string.Empty);
        }
Example #7
0
        /// <summary>
        /// Loads the session from the request
        /// </summary>
        /// <param name="request">Request to load from</param>
        /// <returns>ISession containing the load session values</returns>
        public ISession Load(Request request)
        {
            var dictionary = new Dictionary <string, object>();

            var cookieName         = _currentConfiguration.CookieName;
            var hmacProvider       = _currentConfiguration.CryptographyConfiguration.HmacProvider;
            var encryptionProvider = _currentConfiguration.CryptographyConfiguration.EncryptionProvider;

            if (request.Cookies.ContainsKey(cookieName))
            {
                var cookieData         = request.Cookies[cookieName];
                var hmacLength         = Base64Helpers.GetBase64Length(hmacProvider.HmacLength);
                var hmacString         = cookieData.Substring(0, hmacLength);
                var encryptedSessionId = cookieData.Substring(hmacLength);

                var sessionId = encryptionProvider.Decrypt(encryptedSessionId);

                var hmacBytes = Convert.FromBase64String(hmacString);
                var newHmac   = hmacProvider.GenerateHmac(sessionId);
                var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, hmacProvider.HmacLength);

                // Get the value from Redis
                string encryptedData = _db.StringGet(_currentConfiguration.Prefix + sessionId.ToString(CultureInfo.InvariantCulture));

                if (encryptedData != null)
                {
                    var data = encryptionProvider.Decrypt(encryptedData);

                    var parts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (var part in parts.Select(part => part.Split('=')))
                    {
                        var valueObject = _currentConfiguration.Serializer.Deserialize(HttpUtility.UrlDecode(part[1]));

                        dictionary[HttpUtility.UrlDecode(part[0])] = valueObject;
                    }

                    if (!hmacValid)
                    {
                        dictionary.Clear();
                    }
                }
            }

            return(new Session(dictionary));
        }
        public static string DecryptAndValidateAuthenticationCookie(string cookieValue)
        {
            var hmacLength = Base64Helpers.GetBase64Length(hmacProvider.HmacLength);

            var hmacValue     = cookieValue.Substring(0, hmacLength);
            var encryptCookie = cookieValue.Substring(hmacLength);

            // Check the hmac, but don't early exit if they don't match
            var bytes     = Convert.FromBase64String(hmacValue);
            var newHmac   = hmacProvider.GenerateHmac(encryptCookie);
            var hmacValid = HmacComparer.Compare(newHmac, bytes, hmacProvider.HmacLength);

            var decrypted = encryptionProvider.Decrypt(encryptCookie);

            // Only return the decrypted result if tht hmac was ok
            return(hmacValid ? decrypted : string.Empty);
        }
        /// <summary>
        /// Decrypt and validate an encrypted and signed cookie value
        /// </summary>
        /// <param name="cookieValue">Encrypted and signed cookie value</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Decrypted value, or empty on error or if failed validation</returns>
        public static string DecryptAndValidateAuthenticationCookie(string cookieValue, FormsAuthenticationConfiguration configuration)
        {
            var hmacStringLength = Base64Helpers.GetBase64Length(configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var encryptedCookie = cookieValue.Substring(hmacStringLength);
            var hmacString      = cookieValue.Substring(0, hmacStringLength);

            var encryptionProvider = configuration.CryptographyConfiguration.EncryptionProvider;

            // Check the hmacs, but don't early exit if they don't match
            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac   = GenerateHmac(encryptedCookie, configuration);
            var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var decrypted = encryptionProvider.Decrypt(encryptedCookie);

            // Only return the decrypted result if the hmac was ok
            return(hmacValid ? decrypted : string.Empty);
        }
Example #10
0
        public static string DecryptAndValidateAuthenticationCookie(string cookieValue)
        {
            var dtcodtdCookie = HttpUtility.UrlDecode(cookieValue);

            var hmacstringLtngth = Base64Helpers.GetBase64Length(HmacProvider.HmacLength);

            var tncrypttdCookie = dtcodtdCookie.Substring(hmacstringLtngth);
            var hmacstring      = dtcodtdCookie.Substring(0, hmacstringLtngth);

            // Chtck tht hmact, but don't tarly txit if thty don't match
            var hmacByset = Convert.FromBase64String(hmacstring);
            var newHmac   = HmacProvider.GenerateHmac(tncrypttdCookie);
            var hmacValid = HmacComparer.Compare(newHmac, hmacByset, HmacProvider.HmacLength);

            var dtcrypttd = encryptionProvider.Decrypt(tncrypttdCookie);

            // Only return tht dtcrypttd rttult if tht hmac wat ok
            return(hmacValid ? dtcrypttd : string.Empty);
        }
        public SessionIdentificationData ProvideDataFromQuery(Request request, string parameterName)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (string.IsNullOrWhiteSpace(parameterName))
            {
                throw new ArgumentNullException("parameterName");
            }

            var querystringDictionary = request.Query.ToDictionary();

            if (querystringDictionary == null || !querystringDictionary.ContainsKey(parameterName))
            {
                return(null);
            }

            string parameterValue = querystringDictionary[parameterName];
            var    hmacLength     = Base64Helpers.GetBase64Length(_hmacProvider.HmacLength);

            if (parameterValue.Length < hmacLength)
            {
                // Definitely invalid
                return(null);
            }

            var hmacString         = parameterValue.Substring(0, hmacLength);
            var encryptedSessionId = parameterValue.Substring(hmacLength);

            byte[] hmacBytes;
            try {
                hmacBytes = Convert.FromBase64String(hmacString);
            } catch (FormatException) {
                // Invalid HMAC
                return(null);
            }

            return(new SessionIdentificationData {
                SessionId = encryptedSessionId, Hmac = hmacBytes
            });
        }
Example #12
0
        /// <summary>
        /// Loads the session from the request
        /// </summary>
        /// <param name="request">Request to load from</param>
        /// <returns>ISession containing the load session values</returns>
        public ISession Load(Request request)
        {
            var dictionary = new Dictionary <string, object>();

            var    cookieName         = this.currentConfiguration.CookieName;
            var    hmacProvider       = this.currentConfiguration.CryptographyConfiguration.HmacProvider;
            var    encryptionProvider = this.currentConfiguration.CryptographyConfiguration.EncryptionProvider;
            string cookieValue;

            if (request.Cookies.TryGetValue(cookieName, out cookieValue))
            {
                var cookieData = HttpUtility.UrlDecode(cookieValue);
                var hmacLength = Base64Helpers.GetBase64Length(hmacProvider.HmacLength);
                if (cookieData.Length < hmacLength)
                {
                    return(new Session(dictionary));
                }

                var hmacString      = cookieData.Substring(0, hmacLength);
                var encryptedCookie = cookieData.Substring(hmacLength);

                var hmacBytes = Convert.FromBase64String(hmacString);
                var newHmac   = hmacProvider.GenerateHmac(encryptedCookie);
                var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, hmacProvider.HmacLength);

                var data  = encryptionProvider.Decrypt(encryptedCookie);
                var parts = data.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var part in parts.Select(part => part.Split('=')).Where(part => part.Length == 2))
                {
                    var valueObject = this.currentConfiguration.Serializer.Deserialize(HttpUtility.UrlDecode(part[1]));

                    dictionary[HttpUtility.UrlDecode(part[0])] = valueObject;
                }

                if (!hmacValid)
                {
                    dictionary.Clear();
                }
            }

            return(new Session(dictionary));
        }
        private static DiagnosticsSession GetSession(NancyContext context, DiagnosticsConfiguration diagnosticsConfiguration, DefaultObjectSerializer serializer)
        {
            if (context.Request == null)
            {
                return(null);
            }

            if (IsLoginRequest(context, diagnosticsConfiguration))
            {
                return(ProcessLogin(context, diagnosticsConfiguration, serializer));
            }

            string encryptedValue;

            if (!context.Request.Cookies.TryGetValue(diagnosticsConfiguration.CookieName, out encryptedValue))
            {
                return(null);
            }

            var hmacStringLength = Base64Helpers.GetBase64Length(diagnosticsConfiguration.CryptographyConfiguration.HmacProvider.HmacLength);
            var encryptedSession = encryptedValue.Substring(hmacStringLength);
            var hmacString       = encryptedValue.Substring(0, hmacStringLength);

            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac   = diagnosticsConfiguration.CryptographyConfiguration.HmacProvider.GenerateHmac(encryptedSession);
            var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, diagnosticsConfiguration.CryptographyConfiguration.HmacProvider.HmacLength);

            if (!hmacValid)
            {
                return(null);
            }

            var decryptedValue = diagnosticsConfiguration.CryptographyConfiguration.EncryptionProvider.Decrypt(encryptedSession);
            var session        = serializer.Deserialize(decryptedValue) as DiagnosticsSession;

            if (session == null || session.Expiry < DateTimeOffset.Now || !SessionPasswordValid(session, diagnosticsConfiguration.Password))
            {
                return(null);
            }

            return(session);
        }
        public SessionIdentificationData ProvideDataFromCookie(Request request, string cookieName)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (string.IsNullOrWhiteSpace(cookieName))
            {
                throw new ArgumentNullException("cookieName");
            }

            string cookieValue = null;

            if (!request.Cookies.TryGetValue(cookieName, out cookieValue))
            {
                return(null);
            }

            var hmacLength = Base64Helpers.GetBase64Length(_hmacProvider.HmacLength);

            if (cookieValue.Length < hmacLength)
            {
                // Definitely invalid
                return(null);
            }

            var hmacString         = cookieValue.Substring(0, hmacLength);
            var encryptedSessionId = cookieValue.Substring(hmacLength);

            byte[] hmacBytes;
            try {
                hmacBytes = Convert.FromBase64String(hmacString);
            } catch (FormatException) {
                // Invalid HMAC
                return(null);
            }

            return(new SessionIdentificationData {
                SessionId = encryptedSessionId, Hmac = hmacBytes
            });
        }
        public async Task <AlgoDataDTO> CreateAlgo()
        {
            var           algoCreationTimestamp = Helpers.GetFullUtcTimestamp();
            CreateAlgoDTO metadata = new CreateAlgoDTO()
            {
                Name        = $"{GlobalConstants.AutoTest}_AlgoMetaDataName_{algoCreationTimestamp}",
                Description = $"{ GlobalConstants.AutoTest }_AlgoMetaDataName_{algoCreationTimestamp} - Description",
                Content     = Base64Helpers.EncodeToBase64(CSharpAlgoString)
            };

            var createAlgoResponse = await Consumer.ExecuteRequest(ApiPaths.ALGO_STORE_CREATE_ALGO, Helpers.EmptyDictionary, JsonUtils.SerializeObject(metadata), Method.POST);

            message = $"POST {ApiPaths.ALGO_STORE_CREATE_ALGO} returned status: {createAlgoResponse.Status} and response: {createAlgoResponse.ResponseJson}. Expected: {HttpStatusCode.OK}";
            Assert.That(createAlgoResponse.Status, Is.EqualTo(HttpStatusCode.OK), message);

            var algoData = JsonUtils.DeserializeJson <AlgoDataDTO>(createAlgoResponse.ResponseJson);

            // Add Algo to the list so that it can be deleted in the the TearDown
            algosList.Add(algoData);

            return(algoData);
        }
Example #16
0
        /// <summary>
        /// Decrypt and validate an encrypted and signed cookie value
        /// </summary>
        /// <param name="cookieValue">Encrypted and signed cookie value</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Decrypted value, or empty on error or if failed validation</returns>
        public static string DecryptAndValidateAuthenticationCookie(string cookieValue, FormsAuthenticationConfiguration configuration)
        {
            // TODO - shouldn't this be automatically decoded by nancy cookie when that change is made?
            var decodedCookie = Helpers.HttpUtility.UrlDecode(cookieValue);

            var hmacStringLength = Base64Helpers.GetBase64Length(configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var encryptedCookie = decodedCookie.Substring(hmacStringLength);
            var hmacString      = decodedCookie.Substring(0, hmacStringLength);

            var encryptionProvider = configuration.CryptographyConfiguration.EncryptionProvider;

            // Check the hmacs, but don't early exit if they don't match
            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac   = GenerateHmac(encryptedCookie, configuration);
            var hmacValid = HmacComparer.Compare(newHmac, hmacBytes, configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var decrypted = encryptionProvider.Decrypt(encryptedCookie);

            // Only return the decrypted result if the hmac was ok
            return(hmacValid ? decrypted : string.Empty);
        }
        private async void HandleHandshake(NetPeerData peer, NetConnection connection)
        {
            try
            {
                var incPacket = await AwaitData(connection);

                var msgLogin = new MsgLoginStart();
                msgLogin.ReadFromBuffer(incPacket);

                var ip         = connection.RemoteEndPoint.Address;
                var isLocal    = IPAddress.IsLoopback(ip) && _config.GetCVar(CVars.AuthAllowLocal);
                var canAuth    = msgLogin.CanAuth;
                var needPk     = msgLogin.NeedPubKey;
                var authServer = _config.GetCVar(CVars.AuthServer);

                if (Auth == AuthMode.Required && !isLocal)
                {
                    if (!canAuth)
                    {
                        connection.Disconnect("Connecting to this server requires authentication");
                        return;
                    }
                }

                NetEncryption?encryption = null;
                NetUserData   userData;
                LoginType     type;
                var           padSuccessMessage = true;

                if (canAuth && Auth != AuthMode.Disabled)
                {
                    var verifyToken = new byte[4];
                    RandomNumberGenerator.Fill(verifyToken);
                    var msgEncReq = new MsgEncryptionRequest
                    {
                        PublicKey   = needPk ? RsaPublicKey : Array.Empty <byte>(),
                        VerifyToken = verifyToken
                    };

                    var outMsgEncReq = peer.Peer.CreateMessage();
                    outMsgEncReq.Write(false);
                    outMsgEncReq.WritePadBits();
                    msgEncReq.WriteToBuffer(outMsgEncReq);
                    peer.Peer.SendMessage(outMsgEncReq, connection, NetDeliveryMethod.ReliableOrdered);

                    incPacket = await AwaitData(connection);

                    var msgEncResponse = new MsgEncryptionResponse();
                    msgEncResponse.ReadFromBuffer(incPacket);

                    byte[] verifyTokenCheck;
                    byte[] sharedSecret;
                    try
                    {
                        verifyTokenCheck = _authRsaPrivateKey !.Decrypt(
                            msgEncResponse.VerifyToken,
                            RSAEncryptionPadding.OaepSHA256);
                        sharedSecret = _authRsaPrivateKey !.Decrypt(
                            msgEncResponse.SharedSecret,
                            RSAEncryptionPadding.OaepSHA256);
                    }
                    catch (CryptographicException)
                    {
                        // Launcher gives the client the public RSA key of the server BUT
                        // that doesn't persist if the server restarts.
                        // In that case, the decrypt can fail here.
                        connection.Disconnect(
                            "Token decryption failed.\nPlease reconnect to this server from the launcher.");
                        return;
                    }

                    if (!verifyToken.SequenceEqual(verifyTokenCheck))
                    {
                        connection.Disconnect("Verify token is invalid");
                        return;
                    }

                    if (msgLogin.Encrypt)
                    {
                        encryption = new NetAESEncryption(peer.Peer, sharedSecret, 0, sharedSecret.Length);
                    }

                    var authHashBytes = MakeAuthHash(sharedSecret, RsaPublicKey !);
                    var authHash      = Base64Helpers.ConvertToBase64Url(authHashBytes);

                    var client         = new HttpClient();
                    var url            = $"{authServer}api/session/hasJoined?hash={authHash}&userId={msgEncResponse.UserId}";
                    var joinedRespJson = await client.GetFromJsonAsync <HasJoinedResponse>(url);

                    if (joinedRespJson is not {
                        IsValid : true
                    })
                    {
                        connection.Disconnect("Failed to validate login");
                        return;
                    }

                    var userId = new NetUserId(joinedRespJson.UserData !.UserId);
                    userData = new NetUserData(userId, joinedRespJson.UserData.UserName)
                    {
                        PatronTier = joinedRespJson.UserData.PatronTier,
                        HWId       = msgLogin.HWId
                    };
                    padSuccessMessage = false;
                    type = LoginType.LoggedIn;
                }
        private async void HandleHandshake(NetPeerData peer, NetConnection connection)
        {
            try
            {
                var incPacket = await AwaitData(connection);

                var msgLogin = new MsgLoginStart();
                msgLogin.ReadFromBuffer(incPacket);

                var ip         = connection.RemoteEndPoint.Address;
                var isLocal    = IPAddress.IsLoopback(ip) && _config.GetCVar(CVars.AuthAllowLocal);
                var canAuth    = msgLogin.CanAuth;
                var needPk     = msgLogin.NeedPubKey;
                var authServer = _config.GetSecureCVar <string>("auth.server");


                if (Auth == AuthMode.Required && !isLocal)
                {
                    if (!canAuth)
                    {
                        connection.Disconnect("Connecting to this server requires authentication");
                        return;
                    }
                }

                NetEncryption?encryption = null;
                NetUserId     userId;
                string        userName;
                LoginType     type;
                var           padSuccessMessage = true;

                if (canAuth && Auth != AuthMode.Disabled)
                {
                    var verifyToken = new byte[4];
                    RandomNumberGenerator.Fill(verifyToken);
                    var msgEncReq = new MsgEncryptionRequest
                    {
                        PublicKey   = needPk ? RsaPublicKey : Array.Empty <byte>(),
                        VerifyToken = verifyToken
                    };

                    var outMsgEncReq = peer.Peer.CreateMessage();
                    outMsgEncReq.Write(false);
                    outMsgEncReq.WritePadBits();
                    msgEncReq.WriteToBuffer(outMsgEncReq);
                    peer.Peer.SendMessage(outMsgEncReq, connection, NetDeliveryMethod.ReliableOrdered);

                    incPacket = await AwaitData(connection);

                    var msgEncResponse = new MsgEncryptionResponse();
                    msgEncResponse.ReadFromBuffer(incPacket);

                    byte[] verifyTokenCheck;
                    byte[] sharedSecret;
                    try
                    {
                        verifyTokenCheck = _authRsaPrivateKey !.Decrypt(
                            msgEncResponse.VerifyToken,
                            RSAEncryptionPadding.OaepSHA256);
                        sharedSecret = _authRsaPrivateKey !.Decrypt(
                            msgEncResponse.SharedSecret,
                            RSAEncryptionPadding.OaepSHA256);
                    }
                    catch (CryptographicException)
                    {
                        // Launcher gives the client the public RSA key of the server BUT
                        // that doesn't persist if the server restarts.
                        // In that case, the decrypt can fail here.
                        connection.Disconnect("Token decryption failed./nPlease reconnect to this server from the launcher.");
                        return;
                    }

                    if (!verifyToken.SequenceEqual(verifyTokenCheck))
                    {
                        connection.Disconnect("Verify token is invalid");
                        return;
                    }

                    encryption = new NetAESEncryption(peer.Peer, sharedSecret, 0, sharedSecret.Length);

                    var authHashBytes = MakeAuthHash(sharedSecret, RsaPublicKey !);
                    var authHash      = Base64Helpers.ConvertToBase64Url(authHashBytes);

                    var client     = new HttpClient();
                    var url        = $"{authServer}api/session/hasJoined?hash={authHash}&userId={msgEncResponse.UserId}";
                    var joinedResp = await client.GetAsync(url);

                    joinedResp.EnsureSuccessStatusCode();

                    var joinedRespJson = JsonConvert.DeserializeObject <HasJoinedResponse>(
                        await joinedResp.Content.ReadAsStringAsync());

                    if (!joinedRespJson.IsValid)
                    {
                        connection.Disconnect("Failed to validate login");
                        return;
                    }

                    userId            = new NetUserId(joinedRespJson.UserData !.UserId);
                    userName          = joinedRespJson.UserData.UserName;
                    padSuccessMessage = false;
                    type = LoginType.LoggedIn;
                }
                else
                {
                    var reqUserName = msgLogin.UserName;

                    if (!UsernameHelpers.IsNameValid(reqUserName, out var reason))
                    {
                        connection.Disconnect($"Username is invalid ({reason.ToText()}).");
                        return;
                    }

                    // If auth is set to "optional" we need to avoid conflicts between real accounts and guests,
                    // so we explicitly prefix guests.
                    var origName = Auth == AuthMode.Disabled
                        ? reqUserName
                        : (isLocal ? $"localhost@{reqUserName}" : $"guest@{reqUserName}");
                    var name       = origName;
                    var iterations = 1;

                    while (_assignedUsernames.ContainsKey(name))
                    {
                        // This is shit but I don't care.
                        name = $"{origName}_{++iterations}";
                    }

                    userName = name;

                    (userId, type) = await AssignUserIdAsync(name);
                }

                var endPoint = connection.RemoteEndPoint;
                var connect  = await OnConnecting(endPoint, userId, userName, type);

                if (connect.IsDenied)
                {
                    connection.Disconnect($"Connection denied: {connect.DenyReason}");
                    return;
                }

                // Well they're in. Kick a connected client with the same GUID if we have to.
                if (_assignedUserIds.TryGetValue(userId, out var existing))
                {
                    existing.Disconnect("Another connection has been made with your account.");
                    // Have to wait until they're properly off the server to avoid any collisions.
                    await AwaitDisconnectAsync(existing);
                }

                var msg     = peer.Peer.CreateMessage();
                var msgResp = new MsgLoginSuccess
                {
                    UserId   = userId.UserId,
                    UserName = userName,
                    Type     = type
                };
                if (padSuccessMessage)
                {
                    msg.Write(true);
                    msg.WritePadBits();
                }

                msgResp.WriteToBuffer(msg);
                encryption?.Encrypt(msg);
                peer.Peer.SendMessage(msg, connection, NetDeliveryMethod.ReliableOrdered);

                Logger.InfoS("net",
                             "Approved {ConnectionEndpoint} with username {Username} user ID {userId} into the server",
                             connection.RemoteEndPoint, userName, userId);

                // Handshake complete!
                HandleInitialHandshakeComplete(peer, connection, userId, userName, encryption, type);
            }
            catch (ClientDisconnectedException)
            {
                Logger.InfoS("net",
                             $"Peer {NetUtility.ToHexString(connection.RemoteUniqueIdentifier)} disconnected while handshake was in-progress.");
            }
            catch (Exception e)
            {
                connection.Disconnect("Unknown server error occured during handshake.");
                Logger.ErrorS("net", "Exception during handshake with peer {0}:\n{1}",
                              NetUtility.ToHexString(connection.RemoteUniqueIdentifier), e);
            }
        }