예제 #1
0
        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"));
        }
예제 #2
0
        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);
     }
 }
예제 #6
0
        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()));
        }
예제 #7
0
        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
            }));
        }
예제 #8
0
        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
            }));
        }
예제 #9
0
        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);
        }
예제 #11
0
        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}"));
            }
        }
예제 #12
0
 protected bool Equals(AccountDevice other)
 {
     return(DeviceId.Equals(other.DeviceId) && string.Equals(SecretToken, other.SecretToken));
 }