public ActionResult PostRecovery([FromHeader(Name = "Recovery-Code")] Guid recoveryCode) { byte[] tokenData = new byte[256]; Rng.GetBytes(tokenData); string secretToken = Convert.ToBase64String(tokenData); if (ApplicationStateAccess.TryGetAccountDevice(recoveryCode, out var existingAccountDevice) && ApplicationStateAccess.TryGetAccount(existingAccountDevice, out var existingAccount)) { var newAccountDevice = new AccountDevice(existingAccountDevice.DeviceId, secretToken, Guid.NewGuid()); var registrationResponseDto = new RegistrationResponseDto { DeviceId = newAccountDevice.DeviceId, RecoveryCode = newAccountDevice.RecoveryCode, SecretToken = newAccountDevice.SecretToken, InitialState = existingAccount.SyncStates.First() }; existingAccount.Devices.Add(newAccountDevice); existingAccount.Devices.Remove(existingAccountDevice); Console.WriteLine($"Recovered device from recovery code {recoveryCode}. New AccountDevice DeviceId:{newAccountDevice.DeviceId} RecoveryCode:{newAccountDevice.RecoveryCode} SecretToken:{newAccountDevice.SecretToken}"); return(new JsonResult(registrationResponseDto)); } return(BadRequest($"This recovery code does not match to any known account device")); }
public ActionResult Post([FromBody] StateResponseDto stateResponseChange, [FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Recovery-Code")] Guid recoveryCode) { stateResponseChange.Guid = stateResponseChange.Guid; stateResponseChange.VersionNumber = 1; byte[] tokenData = new byte[256]; Rng.GetBytes(tokenData); string secretToken = Convert.ToBase64String(tokenData); var newDevice = new AccountDevice(deviceId, secretToken, recoveryCode); var newAccount = new Account(Guid.NewGuid(), new List <AccountDevice>(new[] { newDevice }), stateResponseChange); ApplicationStateAccess.RegisterNewAccount(newDevice, newAccount, recoveryCode); var registrationResponseDto = new RegistrationResponseDto { DeviceId = deviceId, RecoveryCode = recoveryCode, SecretToken = secretToken, InitialState = stateResponseChange }; Console.WriteLine($"Register new device. DeviceId:{deviceId} RecoveryCode:{recoveryCode} SecretToken:{secretToken}"); return(new JsonResult(registrationResponseDto)); }
public static bool TryGetAccountDevice(Guid recoveryCode, out AccountDevice accountDevice) { lock (dbLock) { var dbState = GetDbState(); return(dbState.RecoveryCodeToAccountDevice.TryGetValue(recoveryCode, out accountDevice)); } }
public static bool TryGetAccount(AccountDevice accountDevice, out Account account) { lock (dbLock) { var dbState = GetDbState(); account = dbState.Accounts.FirstOrDefault(x => x.Devices.Contains(accountDevice)); return(account != null); } }
public static void RegisterNewAccount(AccountDevice device, Account account, Guid recoveryCode) { lock (dbLock) { var dbState = GetDbState(); dbState.Accounts.Add(account); dbState.RecoveryCodeToAccountDevice[recoveryCode] = device; WriteDbState(dbState); } }
public ActionResult PostState([FromBody] StateResponseDto stateResponseChange, [FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Authorization")] string token) { var newKey = new AccountDevice(deviceId, token, Guid.Empty); if (!ApplicationStateAccess.TryGetAccount(newKey, out var account)) { return(new UnauthorizedResult()); } if (account.SyncStates.Last().VersionNumber + 1 != stateResponseChange.VersionNumber) { return(BadRequest( $"The Version Number of '{stateResponseChange.VersionNumber}' is not expected. Expected:{account.SyncStates.Last().VersionNumber + 1}")); } ApplicationStateAccess.AddSyncStateToAccount(account, stateResponseChange); return(new JsonResult(account.SyncStates.Last())); }
public ActionResult Get([FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Authorization")] string token) { var accountDevice = new AccountDevice(deviceId, token, Guid.Empty); if (!ApplicationStateAccess.TryGetAccount(accountDevice, out var account)) { return(new UnauthorizedResult()); } var lastState = account.SyncStates.Last(); return(new JsonResult(new VersionResponseDto { Guid = lastState.Guid, VersionNumber = lastState.VersionNumber })); }
public ActionResult GetCode([FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Authorization")] string token) { var accountDevice = new AccountDevice(deviceId, token, Guid.Empty); if (!ApplicationStateAccess.TryGetAccount(accountDevice, out var account)) { return(new UnauthorizedResult()); } byte[] tokenData = new byte[4]; Rng.GetBytes(tokenData); var timedAccountCode = new TimedAccountCode(ByteArrayToHexString(tokenData), DateTimeOffset.UtcNow.AddMinutes(1), account.Id); ApplicationStateAccess.AddTimedAccountCode(timedAccountCode); return(new JsonResult(new AccountCodeResponseDto { Code = timedAccountCode.Code, ValidUntil = timedAccountCode.ValidUntil })); }
public ActionResult PostCode([FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Recovery-Code")] Guid recoveryCode, [FromHeader(Name = "Account-Code")] string accountCode) { byte[] tokenData = new byte[256]; Rng.GetBytes(tokenData); string secretToken = Convert.ToBase64String(tokenData); var accountDevice = new AccountDevice(deviceId, secretToken, recoveryCode); if (ApplicationStateAccess.TryAddAccountDevice(accountDevice, accountCode) && ApplicationStateAccess.TryGetAccount(accountDevice, out var account)) { var registrationResponseDto = new RegistrationResponseDto { DeviceId = accountDevice.DeviceId, RecoveryCode = accountDevice.RecoveryCode, SecretToken = accountDevice.SecretToken, InitialState = account.SyncStates.First() }; return(new JsonResult(registrationResponseDto)); } return(NotFound()); }
public static bool TryAddAccountDevice(AccountDevice accountDevice, string accountCode) { timedAccountCodes = timedAccountCodes.Where(x => x.ValidUntil > DateTimeOffset.UtcNow).ToList(); var foundTimedAccountCode = timedAccountCodes.FirstOrDefault(x => x.Code == accountCode); if (foundTimedAccountCode != null) { lock (dbLock) { var dbState = GetDbState(); var existingAccount = dbState.Accounts.FirstOrDefault(x => x.Id == foundTimedAccountCode.AccountId); if (existingAccount != null) { existingAccount.Devices.Add(accountDevice); WriteDbState(dbState); return(true); } } } return(false); }
public ActionResult GetStates([FromHeader(Name = "Device-ID")] Guid deviceId, [FromHeader(Name = "Authorization")] string token, [FromQuery(Name = "fromVersion")] int fromVersion) { var accountDevice = new AccountDevice(deviceId, token, Guid.Empty); if (!ApplicationStateAccess.TryGetAccount(accountDevice, out var account)) { return(new UnauthorizedResult()); } if (fromVersion == 0) { var remainingStates = account.SyncStates.ToArray(); var response = new StatesResponseDto { FromVersionNumber = fromVersion, States = remainingStates }; return(new JsonResult(response)); } else { int fromIndex = account.SyncStates.FindIndex(0, existingDto => existingDto.VersionNumber == fromVersion); if (fromIndex > -1) { var remainingStates = account.SyncStates.Skip(fromIndex + 1).ToArray(); var response = new StatesResponseDto { FromVersionNumber = fromVersion, States = remainingStates }; return(new JsonResult(response)); } return(BadRequest($"Unable to find existing State for VersionId:{fromVersion}")); } }
protected bool Equals(AccountDevice other) { return(DeviceId.Equals(other.DeviceId) && string.Equals(SecretToken, other.SecretToken)); }