Example #1
0
        public ActionResult <MilvanethProtocol> AuthFinish(MilvanethProtocol data)
        {
            if (!(data?.Data is ClientResponse response) || !response.Check())
            {
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.DATA_INVALID_INPUT,
                        ReportTime = _time.SafeNow,
                    }
                });
            }

            try
            {
                if (!_srp.DoServerValidate(response.SessionId, response.ClientToken, response.ClientEvidence, out var accountId))
                {
                    if (accountId != 0)
                    {
                        var accountData = _context.AccountData.Single(x => x.AccountId == accountId);

                        if (accountData.PasswordRetry > GlobalConfig.ACCOUNT_PASSWORD_RETRY_TOLERANCE && accountData.LastRetry.HasValue &&
                            (_time.UtcNow - accountData.LastRetry.Value).Seconds < GlobalConfig.ACCOUNT_PASSWORD_RETRY_COOLDOWN)
                        {
                            return(new MilvanethProtocol
                            {
                                Context = null,
                                Data = new ServerResponse
                                {
                                    Message = GlobalMessage.OP_PASSWORD_RETRY_TOO_MUCH,
                                    ReportTime = _time.SafeNow,
                                }
                            });
                        }

                        if (accountData.PasswordRetry == null)
                        {
                            accountData.PasswordRetry = 1;
                        }
                        accountData.PasswordRetry += 1;
                        accountData.LastRetry      = _time.UtcNow;

                        _context.AccountData.Update(accountData);

                        _context.SaveChanges();
                    }

                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.DATA_RECORD_MISMATCH,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                var account = _context.AccountData.Include(x => x.PrivilegeLevelNavigation).Single(x => x.AccountId == accountId);

                if (account.PasswordRetry > GlobalConfig.ACCOUNT_PASSWORD_RETRY_TOLERANCE && account.LastRetry.HasValue &&
                    (_time.UtcNow - account.LastRetry.Value).Seconds < GlobalConfig.ACCOUNT_PASSWORD_RETRY_COOLDOWN)
                {
                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.OP_PASSWORD_RETRY_TOO_MUCH,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                account.PasswordRetry = 0;

                _context.AccountData.Update(account);

                _context.AccountLog.Add(new AccountLog
                {
                    ReportTime = _time.UtcNow,
                    AccountId  = account.AccountId,
                    Message    = GlobalOperation.AUTH_FINISH,
                    Detail     = "Finish login via auth/finish",
                    IpAddress  = _accessor.GetIp()
                });

                _context.SaveChanges();

                var key = _api.Sign(_authToken, 1, account, _time.UtcNow, _time.UtcNow.AddSeconds(GlobalConfig.TOKEN_ACCOUNT_LIFE_TIME));

                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.OK_SUCCESS,
                        ReportTime = _time.SafeNow,
                        AuthToken = key.Key
                    }
                });
            }
            catch (Exception e)
            {
                Log.Error(e, "Error in AUTH/FINISH");
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.OP_INVALID,
                        ReportTime = _time.SafeNow,
                    }
                });
            }
        }
Example #2
0
        public ActionResult <MilvanethProtocol> SessionCreate(MilvanethProtocol data)
        {
            if (!(data?.Data is AuthRequest request) || !request.Check())
            {
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new AuthResponse
                    {
                        Message = GlobalMessage.DATA_INVALID_INPUT,
                        ReportTime = _time.SafeNow,
                    }
                });
            }

            try
            {
                var key = _context.KeyStore
                          .Include(x => x.HoldingAccountNavigation)
                          .ThenInclude(x => x.PrivilegeLevelNavigation)
                          .Include(x => x.UsageNavigation)
                          .Single(x => x.Key.SequenceEqual(request.AuthToken));

                _auth.EnsureKey(key, new KeyUsage {
                    CreateSession = true
                }, GlobalOperation.SESSION_CREATE, 0, "Create session via session/create",
                                _accessor.GetIp());

                var account = key.HoldingAccountNavigation;

                _auth.EnsureAccount(account, new PrivilegeConfig {
                    AccessData = true
                }, GlobalOperation.SESSION_CREATE, 0,
                                    "Create session via session/create", _accessor.GetIp());

                var renew = _api.Sign(_renewToken, 1, account, _time.UtcNow,
                                      _time.UtcNow.AddSeconds(GlobalConfig.TOKEN_RENEW_LIFE_TIME));

                var access = _token.Sign(new TokenPayload(_time.UtcNow.AddSeconds(GlobalConfig.TOKEN_DATA_LIFE_TIME),
                                                          account.AccountId, TokenPurpose.AccessToken, renew.KeyId));

                _context.SaveChanges();

                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new AuthResponse
                    {
                        Message = GlobalMessage.OK_SUCCESS,
                        ReportTime = _time.SafeNow,
                        RenewToken = renew.Key,
                        SessionToken = access
                    }
                });
            }
            catch (Exception e)
            {
                Log.Error(e, "Error in SESSION/CREATE");
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerChallenge
                    {
                        Message = GlobalMessage.OP_INVALID,
                        ReportTime = _time.SafeNow,
                    }
                });
            }
        }
Example #3
0
        public ActionResult <MilvanethProtocol> AccountRecoveryEmail(MilvanethProtocol data)
        {
            if (!(data?.Data is RecoveryEmail email) || !email.Check())
            {
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.DATA_INVALID_INPUT,
                        ReportTime = _time.SafeNow,
                    }
                });
            }

            try
            {
                var user = _context.AccountData.Include(x => x.PrivilegeLevelNavigation).SingleOrDefault(x => x.AccountName == email.Username);

                if (user == null)
                {
                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.DATA_NO_SUCH_USER,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                _auth.EnsureAccount(user, new PrivilegeConfig {
                    AccountOperation = true
                }, GlobalOperation.ACCOUNT_RECOVERY_EMAIL, 0, "Recovery account via account/recovery with email", _accessor.GetIp());

                if (user.Email == null)
                {
                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.DATA_NO_EMAIL_RECORDED,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                var record = _context.EmailVerifyCode.OrderByDescending(x => x.SendTime).FirstOrDefault();

                if (string.IsNullOrEmpty(email.Code))
                {
                    if (record != null && record.SendTime.AddSeconds(GlobalConfig.ACCOUNT_VERIFY_CODE_COOLDOWN) > _time.UtcNow)
                    {
                        return(new MilvanethProtocol
                        {
                            Context = null,
                            Data = new ServerResponse
                            {
                                Message = GlobalMessage.RATE_LIMIT,
                                ReportTime = _time.SafeNow,
                            }
                        });
                    }

                    if (user.Email.Equals(email.Email, StringComparison.InvariantCultureIgnoreCase))
                    {
                        string code;
                        if (record != null && record.ValidTo > _time.UtcNow.AddSeconds(3 * GlobalConfig.ACCOUNT_VERIFY_CODE_COOLDOWN))
                        {
                            code = record.Code;

                            record.SendTime = _time.UtcNow;

                            _context.EmailVerifyCode.Update(record);
                        }
                        else
                        {
                            using (var cryptoRng = new RNGCryptoServiceProvider())
                            {
                                var seed = new byte[5];
                                cryptoRng.GetBytes(seed);
                                code = Helper.ToCode(seed);
                            }

                            _context.EmailVerifyCode.Add(new EmailVerifyCode
                            {
                                AccountId   = user.AccountId,
                                Email       = user.Email,
                                FailedRetry = 0,
                                ValidTo     = _time.UtcNow.AddSeconds(GlobalConfig.ACCOUNT_VERIFY_CODE_LIFE_TIME),
                                Code        = code,
                                SendTime    = _time.UtcNow
                            });
                        }

                        _context.SaveChanges();

                        _mail.SendCode(user.Email, user.DisplayName, code);
                    }
                    else
                    {
                        var rand = new Random();
                        // prevent timing attack
                        Thread.Sleep(1000 + rand.Next(3000));
                    }

                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.OK_SUCCESS,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                if (record == null || record.ValidTo < _time.UtcNow || record.FailedRetry >= 5)
                {
                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.DATA_INVALID_INPUT,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                if (record.Code != email.Code.ToUpperInvariant())
                {
                    record.FailedRetry += 1;

                    _context.EmailVerifyCode.Update(record);

                    _context.SaveChanges();

                    return(new MilvanethProtocol
                    {
                        Context = null,
                        Data = new ServerResponse
                        {
                            Message = GlobalMessage.DATA_INVALID_CAPTCHA,
                            ReportTime = _time.SafeNow,
                        }
                    });
                }

                var recovery = _api.Sign(_changeToken, 1, user, _time.UtcNow, _time.UtcNow.AddSeconds(GlobalConfig.TOKEN_ACCOUNT_LIFE_TIME));

                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.OK_SUCCESS,
                        ReportTime = _time.SafeNow,
                        AuthToken = recovery.Key,
                    }
                });
            }
            catch (Exception e)
            {
                Log.Error(e, "Error in ACCOUNT/RECOVERYMAIL");
                return(new MilvanethProtocol
                {
                    Context = null,
                    Data = new ServerResponse
                    {
                        Message = GlobalMessage.OP_INVALID,
                        ReportTime = _time.SafeNow,
                    }
                });
            }
        }