2016-05-02 09:52:09 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Bit.App.Abstractions;
|
|
|
|
|
using Bit.App.Models.Api;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
using Plugin.Settings.Abstractions;
|
2017-04-20 05:04:43 +03:00
|
|
|
|
using Bit.App.Models;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Xamarin.Forms;
|
|
|
|
|
using PushNotification.Plugin.Abstractions;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
|
|
|
|
namespace Bit.App.Services
|
|
|
|
|
{
|
|
|
|
|
public class AuthService : IAuthService
|
|
|
|
|
{
|
2016-07-19 02:16:27 +03:00
|
|
|
|
private const string EmailKey = "email";
|
2016-05-03 00:50:16 +03:00
|
|
|
|
private const string UserIdKey = "userId";
|
2016-08-06 04:59:25 +03:00
|
|
|
|
private const string PreviousUserIdKey = "previousUserId";
|
2016-06-12 07:49:35 +03:00
|
|
|
|
private const string PinKey = "pin";
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
|
|
|
|
private readonly ISecureStorageService _secureStorage;
|
2017-02-04 09:12:25 +03:00
|
|
|
|
private readonly ITokenService _tokenService;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
private readonly ISettings _settings;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
private readonly ICryptoService _cryptoService;
|
2017-02-04 09:12:25 +03:00
|
|
|
|
private readonly IConnectApiRepository _connectApiRepository;
|
2017-04-20 05:04:43 +03:00
|
|
|
|
private readonly IAppIdService _appIdService;
|
|
|
|
|
private readonly IDeviceInfoService _deviceInfoService;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-07-19 02:16:27 +03:00
|
|
|
|
private string _email;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
private string _userId;
|
2016-08-06 04:59:25 +03:00
|
|
|
|
private string _previousUserId;
|
2016-06-12 07:49:35 +03:00
|
|
|
|
private string _pin;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
|
2016-05-02 09:52:09 +03:00
|
|
|
|
public AuthService(
|
2016-05-03 00:50:16 +03:00
|
|
|
|
ISecureStorageService secureStorage,
|
2017-02-04 09:12:25 +03:00
|
|
|
|
ITokenService tokenService,
|
2016-05-03 00:50:16 +03:00
|
|
|
|
ISettings settings,
|
2016-05-02 09:52:09 +03:00
|
|
|
|
ICryptoService cryptoService,
|
2017-04-20 05:04:43 +03:00
|
|
|
|
IConnectApiRepository connectApiRepository,
|
|
|
|
|
IAppIdService appIdService,
|
|
|
|
|
IDeviceInfoService deviceInfoService)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
|
|
|
|
_secureStorage = secureStorage;
|
2017-02-04 09:12:25 +03:00
|
|
|
|
_tokenService = tokenService;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
_settings = settings;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
_cryptoService = cryptoService;
|
2017-02-04 09:12:25 +03:00
|
|
|
|
_connectApiRepository = connectApiRepository;
|
2017-04-20 05:04:43 +03:00
|
|
|
|
_appIdService = appIdService;
|
|
|
|
|
_deviceInfoService = deviceInfoService;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string UserId
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-08-30 06:06:29 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(_userId))
|
2016-05-03 00:50:16 +03:00
|
|
|
|
{
|
|
|
|
|
return _userId;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 06:06:29 +03:00
|
|
|
|
var userId = _settings.GetValueOrDefault(UserIdKey, string.Empty);
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(userId))
|
|
|
|
|
{
|
|
|
|
|
_userId = userId;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 00:50:16 +03:00
|
|
|
|
return _userId;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if(value != null)
|
|
|
|
|
{
|
|
|
|
|
_settings.AddOrUpdateValue(UserIdKey, value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-08-06 04:59:25 +03:00
|
|
|
|
PreviousUserId = _userId;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
_settings.Remove(UserIdKey);
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
2016-06-12 07:49:35 +03:00
|
|
|
|
|
|
|
|
|
_userId = value;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-06 04:59:25 +03:00
|
|
|
|
public string PreviousUserId
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-08-30 06:06:29 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(_previousUserId))
|
2016-08-06 04:59:25 +03:00
|
|
|
|
{
|
|
|
|
|
return _previousUserId;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 06:06:29 +03:00
|
|
|
|
var previousUserId = _settings.GetValueOrDefault(PreviousUserIdKey, string.Empty);
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(previousUserId))
|
|
|
|
|
{
|
|
|
|
|
_previousUserId = previousUserId;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-06 04:59:25 +03:00
|
|
|
|
return _previousUserId;
|
|
|
|
|
}
|
|
|
|
|
private set
|
|
|
|
|
{
|
|
|
|
|
if(value != null)
|
|
|
|
|
{
|
|
|
|
|
_settings.AddOrUpdateValue(PreviousUserIdKey, value);
|
|
|
|
|
_previousUserId = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool UserIdChanged => PreviousUserId != UserId;
|
|
|
|
|
|
2016-07-19 02:16:27 +03:00
|
|
|
|
public string Email
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2016-08-30 06:06:29 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(_email))
|
2016-07-19 02:16:27 +03:00
|
|
|
|
{
|
|
|
|
|
return _email;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 06:06:29 +03:00
|
|
|
|
var email = _settings.GetValueOrDefault(EmailKey, string.Empty);
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(email))
|
|
|
|
|
{
|
|
|
|
|
_email = email;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-19 02:16:27 +03:00
|
|
|
|
return _email;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if(value != null)
|
|
|
|
|
{
|
|
|
|
|
_settings.AddOrUpdateValue(EmailKey, value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_settings.Remove(EmailKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_email = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-02 09:52:09 +03:00
|
|
|
|
public bool IsAuthenticated
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2017-02-08 05:19:23 +03:00
|
|
|
|
return _cryptoService.Key != null &&
|
|
|
|
|
(!string.IsNullOrWhiteSpace(_tokenService.Token) ||
|
|
|
|
|
!string.IsNullOrWhiteSpace(_tokenService.AuthBearer)) &&
|
2017-02-04 09:12:25 +03:00
|
|
|
|
!string.IsNullOrWhiteSpace(UserId);
|
2016-07-23 09:17:11 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-06-12 07:49:35 +03:00
|
|
|
|
public string PIN
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if(_pin != null)
|
|
|
|
|
{
|
|
|
|
|
return _pin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var pinBytes = _secureStorage.Retrieve(PinKey);
|
|
|
|
|
if(pinBytes == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_pin = Encoding.UTF8.GetString(pinBytes, 0, pinBytes.Length);
|
|
|
|
|
return _pin;
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if(value != null)
|
|
|
|
|
{
|
|
|
|
|
var pinBytes = Encoding.UTF8.GetBytes(value);
|
|
|
|
|
_secureStorage.Store(PinKey, pinBytes);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_secureStorage.Delete(PinKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_pin = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 00:50:16 +03:00
|
|
|
|
public void LogOut()
|
|
|
|
|
{
|
2017-02-04 09:12:25 +03:00
|
|
|
|
_tokenService.Token = null;
|
|
|
|
|
_tokenService.RefreshToken = null;
|
|
|
|
|
_tokenService.AuthBearer = null;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
UserId = null;
|
2016-07-19 02:16:27 +03:00
|
|
|
|
Email = null;
|
2016-05-03 00:50:16 +03:00
|
|
|
|
_cryptoService.Key = null;
|
2016-08-06 06:58:31 +03:00
|
|
|
|
_settings.Remove(Constants.FirstVaultLoad);
|
2017-02-18 07:03:54 +03:00
|
|
|
|
_settings.Remove(Constants.PushLastRegistrationDate);
|
|
|
|
|
_settings.Remove(Constants.Locked);
|
2016-05-03 00:50:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-20 05:04:43 +03:00
|
|
|
|
public async Task<FullLoginResult> TokenPostAsync(string email, string masterPassword)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2017-04-20 05:04:43 +03:00
|
|
|
|
var result = new FullLoginResult();
|
|
|
|
|
|
|
|
|
|
var normalizedEmail = email.Trim().ToLower();
|
|
|
|
|
var key = _cryptoService.MakeKeyFromPassword(masterPassword, normalizedEmail);
|
|
|
|
|
|
|
|
|
|
var request = new TokenRequest
|
|
|
|
|
{
|
|
|
|
|
Email = normalizedEmail,
|
|
|
|
|
MasterPasswordHash = _cryptoService.HashPasswordBase64(key, masterPassword),
|
|
|
|
|
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = await _connectApiRepository.PostTokenAsync(request);
|
|
|
|
|
if(!response.Succeeded)
|
|
|
|
|
{
|
|
|
|
|
result.Success = false;
|
|
|
|
|
result.ErrorMessage = response.Errors.FirstOrDefault()?.Message;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.Success = true;
|
|
|
|
|
if(response.Result.TwoFactorProviders != null && response.Result.TwoFactorProviders.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
result.Key = key;
|
|
|
|
|
result.MasterPasswordHash = request.MasterPasswordHash;
|
|
|
|
|
result.TwoFactorRequired = true;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProcessLoginSuccess(key, response.Result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<LoginResult> TokenPostTwoFactorAsync(string token, string email, string masterPasswordHash,
|
|
|
|
|
byte[] key)
|
|
|
|
|
{
|
|
|
|
|
var result = new LoginResult();
|
|
|
|
|
|
|
|
|
|
var request = new TokenRequest
|
|
|
|
|
{
|
|
|
|
|
Email = email.Trim().ToLower(),
|
|
|
|
|
MasterPasswordHash = masterPasswordHash,
|
|
|
|
|
Token = token.Trim().Replace(" ", ""),
|
|
|
|
|
Provider = 0, // Authenticator app (only 1 provider for now, so hard coded)
|
|
|
|
|
Device = new DeviceRequest(_appIdService, _deviceInfoService)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var response = await _connectApiRepository.PostTokenAsync(request);
|
|
|
|
|
if(!response.Succeeded)
|
|
|
|
|
{
|
|
|
|
|
result.Success = false;
|
|
|
|
|
result.ErrorMessage = response.Errors.FirstOrDefault()?.Message;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.Success = true;
|
|
|
|
|
ProcessLoginSuccess(key, response.Result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ProcessLoginSuccess(byte[] key, TokenResponse response)
|
|
|
|
|
{
|
|
|
|
|
_cryptoService.Key = key;
|
|
|
|
|
_tokenService.Token = response.AccessToken;
|
|
|
|
|
_tokenService.RefreshToken = response.RefreshToken;
|
|
|
|
|
UserId = _tokenService.TokenUserId;
|
|
|
|
|
Email = _tokenService.TokenEmail;
|
|
|
|
|
_settings.AddOrUpdateValue(Constants.LastLoginEmail, Email);
|
2016-07-23 09:17:11 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|