public override State Advance(TwoFactorAuth owner) { var names = owner._settings.Devices.Select(i => i.Name).ToArray(); var validAnswers = Enumerable.Range(0, owner._settings.Devices.Length) .Select(i => Ui.Answer.Device0 + i) .Concat(new[] { Ui.Answer.Email }) .ToArray(); var answer = owner._ui.AskToChooseOob(names, owner._settings.Email, validAnswers); if (answer == Ui.Answer.Email) { Remote.AuthSendEmail(owner._clientInfo, owner._settings.Email, owner._settings.TransactionId, owner._http); return(new WaitForEmail()); } var deviceIndex = answer - Ui.Answer.Device0; if (deviceIndex >= 0 && deviceIndex < owner._settings.Devices.Length) { Remote.AuthSendPush(owner._clientInfo, owner._settings.Devices[deviceIndex].Id, owner._settings.TransactionId, owner._http); return(new WaitForOob(deviceIndex)); } throw new InvalidOperationException(string.Format("Invalid answer '{0}'", answer)); }
public override State Advance(TwoFactorAuth owner) { var validAnswers = new[] { Ui.Answer.Check, Ui.Answer.Resend, Ui.Answer.Email }; var answer = owner._ui.AskToWaitForOob(owner._settings.Devices[_deviceIndex].Name, owner._settings.Email, validAnswers); switch (answer) { case Ui.Answer.Check: return(Check(owner)); case Ui.Answer.Resend: Remote.AuthSendPush(owner._clientInfo, owner._settings.Devices[_deviceIndex].Id, owner._settings.TransactionId, owner._http); return(this); case Ui.Answer.Email: Remote.AuthSendEmail(owner._clientInfo, owner._settings.Email, owner._settings.TransactionId, owner._http); return(new WaitForEmail()); } throw new InvalidOperationException(string.Format("Invalid answer '{0}'", answer)); }
public override State Advance(TwoFactorAuth owner) { Remote.AuthSendPush(owner._clientInfo, owner._settings.Devices[_deviceIndex].Id, owner._settings.TransactionId, owner._http); return(new WaitForOob(_deviceIndex)); }
public override State Advance(TwoFactorAuth owner) { Remote.AuthSendEmail(owner._clientInfo, owner._settings.Email, owner._settings.TransactionId, owner._http); return(new WaitForEmail()); }
// TODO: Shared code for most states. It's not really good that it's in the base class. protected State Check(TwoFactorAuth owner) { var result = Remote.AuthCheck(owner._clientInfo, owner._settings.TransactionId, owner._http); if (result == null) { return(new Failure("Failed")); } return(new Done(result)); }
public virtual State Advance(TwoFactorAuth owner) { throw new InvalidOperationException("Unreachable code"); }
// TODO: Write a test that runs the whole sequence and checks the result. public static Vault Open(string username, string password, Ui ui, ISecureStorage storage, IHttpClient http) { // Step 1: Register a new deice or use the existing one from the previous run. var deviceInfo = LoadDeviceInfo(storage) ?? Remote.RegisetNewDevice("truekey-sharp", http); // Step 2: Parse the token to decode OTP information. var otpInfo = Crypto.ParseClientToken(deviceInfo.Token); // Step 3: Validate the OTP info to make sure it's got only the // things we support at the moment. Crypto.ValidateOtpInfo(otpInfo); // Store the token and ID for the next time. StoreDeviceInfo(deviceInfo, storage); // Bundle up everything in one place var clientInfo = new Remote.ClientInfo(username, "truekey-sharp", deviceInfo, otpInfo); // Step 4: Auth step 1 gives us a transaction id to pass along to the next step. var transactionId = Remote.AuthStep1(clientInfo, http); // Step 5: Auth step 2 gives us the instructions on what to do next. For a new client that // would be some form of second factor auth. For a known client that would be a // pair of OAuth tokens. var whatsNext = Remote.AuthStep2(clientInfo, password, transactionId, http); // The device is trusted if it's already authenticated at this point and // no second factor is needed. var isTrusted = whatsNext.IsAuthenticated; // Step 6: Auth FSM -- walk through all the auth steps until we're done. var oauthToken = TwoFactorAuth.Start(clientInfo, whatsNext, ui, http); // Step 7: Save this device as trusted not to repeat the two factor dance next times. if (!isTrusted) { Remote.SaveDeviceAsTrusted(clientInfo, transactionId, oauthToken, http); } // Step 8: Get the vault from the server. var encryptedVault = Remote.GetVault(oauthToken, http); // Step 9: Compute the master key. var masterKey = Crypto.DecryptMasterKey(password, encryptedVault.MasterKeySalt, encryptedVault.EncryptedMasterKey); // Step 10: Decrypt the accounts. var accounts = encryptedVault.EncryptedAccounts .Select(i => new Account( i.Id, i.Name, i.Username, Crypto.Decrypt(masterKey, i.EncryptedPassword).ToUtf8(), i.Url, Crypto.Decrypt(masterKey, i.EncryptedNote).ToUtf8())) .ToArray(); return(new Vault(accounts)); }