mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
6 Commits
feature/ma
...
v2023.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08d07603a8 | ||
|
|
b9bb21b1db | ||
|
|
39d275453e | ||
|
|
e23ab78bd8 | ||
|
|
4ed5980cb5 | ||
|
|
8c273f7d93 |
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2023.2.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2023.3.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ namespace Bit.App
|
|||||||
Id = loginRequestData.Id,
|
Id = loginRequestData.Id,
|
||||||
IpAddress = loginRequestData.RequestIpAddress,
|
IpAddress = loginRequestData.RequestIpAddress,
|
||||||
Email = await _stateService.GetEmailAsync(),
|
Email = await _stateService.GetEmailAsync(),
|
||||||
FingerprintPhrase = loginRequestData.RequestFingerprint,
|
FingerprintPhrase = loginRequestData.FingerprintPhrase,
|
||||||
RequestDate = loginRequestData.CreationDate,
|
RequestDate = loginRequestData.CreationDate,
|
||||||
DeviceType = loginRequestData.RequestDeviceType,
|
DeviceType = loginRequestData.RequestDeviceType,
|
||||||
Origin = loginRequestData.Origin
|
Origin = loginRequestData.Origin
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace Bit.App.Pages
|
|||||||
private string _masterPassword;
|
private string _masterPassword;
|
||||||
private bool _isEmailEnabled;
|
private bool _isEmailEnabled;
|
||||||
private bool _isKnownDevice;
|
private bool _isKnownDevice;
|
||||||
|
private bool _isExecutingLogin;
|
||||||
|
|
||||||
public LoginPageViewModel()
|
public LoginPageViewModel()
|
||||||
{
|
{
|
||||||
@@ -149,15 +150,21 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
Email = await _stateService.GetRememberedEmailAsync();
|
Email = await _stateService.GetRememberedEmailAsync();
|
||||||
}
|
}
|
||||||
var deviceIdentifier = await _appIdService.GetAppIdAsync();
|
|
||||||
IsKnownDevice = await _apiService.GetKnownDeviceAsync(Email, deviceIdentifier);
|
|
||||||
CanRemoveAccount = await _stateService.GetActiveUserEmailAsync() != Email;
|
CanRemoveAccount = await _stateService.GetActiveUserEmailAsync() != Email;
|
||||||
await _deviceActionService.HideLoadingAsync();
|
IsKnownDevice = await _apiService.GetKnownDeviceAsync(Email, await _appIdService.GetAppIdAsync());
|
||||||
|
}
|
||||||
|
catch (ApiException apiEx) when (apiEx.Error.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
|
{
|
||||||
|
_logger.Exception(apiEx);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
HandleException(ex);
|
HandleException(ex);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LogInAsync(bool showLoading = true, bool checkForExistingAccount = false)
|
public async Task LogInAsync(bool showLoading = true, bool checkForExistingAccount = false)
|
||||||
@@ -192,6 +199,7 @@ namespace Bit.App.Pages
|
|||||||
ShowPassword = false;
|
ShowPassword = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_isExecutingLogin = true;
|
||||||
if (checkForExistingAccount)
|
if (checkForExistingAccount)
|
||||||
{
|
{
|
||||||
var userId = await _stateService.GetUserIdAsync(Email);
|
var userId = await _stateService.GetUserIdAsync(Email);
|
||||||
@@ -253,14 +261,21 @@ namespace Bit.App.Pages
|
|||||||
AppResources.AnErrorHasOccurred, AppResources.Ok);
|
AppResources.AnErrorHasOccurred, AppResources.Ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isExecutingLogin = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetPasswordField()
|
public void ResetPasswordField()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MasterPassword = string.Empty;
|
if (!_isExecutingLogin)
|
||||||
ShowPassword = false;
|
{
|
||||||
|
MasterPassword = string.Empty;
|
||||||
|
ShowPassword = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ namespace Bit.App.Pages
|
|||||||
var response = await _authService.PasswordlessCreateLoginRequestAsync(_email);
|
var response = await _authService.PasswordlessCreateLoginRequestAsync(_email);
|
||||||
if (response != null)
|
if (response != null)
|
||||||
{
|
{
|
||||||
FingerprintPhrase = response.RequestFingerprint;
|
FingerprintPhrase = response.FingerprintPhrase;
|
||||||
_requestId = response.Id;
|
_requestId = response.Id;
|
||||||
_requestAccessCode = response.RequestAccessCode;
|
_requestAccessCode = response.RequestAccessCode;
|
||||||
_requestKeyPair = response.RequestKeyPair;
|
_requestKeyPair = response.RequestKeyPair;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
Padding="0, 10, 0 ,0"
|
Padding="0, 10, 0 ,0"
|
||||||
FontAttributes="Bold"/>
|
FontAttributes="Bold"/>
|
||||||
<controls:MonoLabel
|
<controls:MonoLabel
|
||||||
FormattedText="{Binding RequestFingerprint}"
|
FormattedText="{Binding FingerprintPhrase}"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
FontSize="Small"
|
FontSize="Small"
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace Bit.App.Pages
|
|||||||
Id = loginRequestData.Id,
|
Id = loginRequestData.Id,
|
||||||
IpAddress = loginRequestData.RequestIpAddress,
|
IpAddress = loginRequestData.RequestIpAddress,
|
||||||
Email = await _stateService.GetEmailAsync(),
|
Email = await _stateService.GetEmailAsync(),
|
||||||
FingerprintPhrase = loginRequestData.RequestFingerprint,
|
FingerprintPhrase = loginRequestData.FingerprintPhrase,
|
||||||
RequestDate = loginRequestData.CreationDate,
|
RequestDate = loginRequestData.CreationDate,
|
||||||
DeviceType = loginRequestData.RequestDeviceType,
|
DeviceType = loginRequestData.RequestDeviceType,
|
||||||
Origin = loginRequestData.Origin
|
Origin = loginRequestData.Origin
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Bit.Core.Models.Response
|
|||||||
public string PublicKey { get; set; }
|
public string PublicKey { get; set; }
|
||||||
public string RequestDeviceType { get; set; }
|
public string RequestDeviceType { get; set; }
|
||||||
public string RequestIpAddress { get; set; }
|
public string RequestIpAddress { get; set; }
|
||||||
public string RequestFingerprint { get; set; }
|
public string FingerprintPhrase { get; set; }
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public string MasterPasswordHash { get; set; }
|
public string MasterPasswordHash { get; set; }
|
||||||
public DateTime CreationDate { get; set; }
|
public DateTime CreationDate { get; set; }
|
||||||
|
|||||||
@@ -494,18 +494,21 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task<List<PasswordlessLoginResponse>> GetPasswordlessLoginRequestsAsync()
|
public async Task<List<PasswordlessLoginResponse>> GetPasswordlessLoginRequestsAsync()
|
||||||
{
|
{
|
||||||
return await _apiService.GetAuthRequestAsync();
|
var response = await _apiService.GetAuthRequestAsync();
|
||||||
|
return await PopulateFingerprintPhrasesAsync(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<PasswordlessLoginResponse>> GetActivePasswordlessLoginRequestsAsync()
|
public async Task<List<PasswordlessLoginResponse>> GetActivePasswordlessLoginRequestsAsync()
|
||||||
{
|
{
|
||||||
var requests = await GetPasswordlessLoginRequestsAsync();
|
var requests = await GetPasswordlessLoginRequestsAsync();
|
||||||
return requests.Where(r => !r.IsAnswered && !r.IsExpired).OrderByDescending(r => r.CreationDate).ToList();
|
var activeRequests = requests.Where(r => !r.IsAnswered && !r.IsExpired).OrderByDescending(r => r.CreationDate).ToList();
|
||||||
|
return await PopulateFingerprintPhrasesAsync(activeRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id)
|
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginRequestByIdAsync(string id)
|
||||||
{
|
{
|
||||||
return await _apiService.GetAuthRequestAsync(id);
|
var response = await _apiService.GetAuthRequestAsync(id);
|
||||||
|
return await PopulateFingerprintPhraseAsync(response, await _stateService.GetEmailAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginResponseAsync(string id, string accessCode)
|
public async Task<PasswordlessLoginResponse> GetPasswordlessLoginResponseAsync(string id, string accessCode)
|
||||||
@@ -520,7 +523,8 @@ namespace Bit.Core.Services
|
|||||||
var encryptedKey = await _cryptoService.RsaEncryptAsync(masterKey.EncKey, publicKey);
|
var encryptedKey = await _cryptoService.RsaEncryptAsync(masterKey.EncKey, publicKey);
|
||||||
var encryptedMasterPassword = await _cryptoService.RsaEncryptAsync(Encoding.UTF8.GetBytes(await _stateService.GetKeyHashAsync()), publicKey);
|
var encryptedMasterPassword = await _cryptoService.RsaEncryptAsync(Encoding.UTF8.GetBytes(await _stateService.GetKeyHashAsync()), publicKey);
|
||||||
var deviceId = await _appIdService.GetAppIdAsync();
|
var deviceId = await _appIdService.GetAppIdAsync();
|
||||||
return await _apiService.PutAuthRequestAsync(id, encryptedKey.EncryptedString, encryptedMasterPassword.EncryptedString, deviceId, requestApproved);
|
var response = await _apiService.PutAuthRequestAsync(id, encryptedKey.EncryptedString, encryptedMasterPassword.EncryptedString, deviceId, requestApproved);
|
||||||
|
return await PopulateFingerprintPhraseAsync(response, await _stateService.GetEmailAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PasswordlessLoginResponse> PasswordlessCreateLoginRequestAsync(string email)
|
public async Task<PasswordlessLoginResponse> PasswordlessCreateLoginRequestAsync(string email)
|
||||||
@@ -538,9 +542,30 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
response.RequestKeyPair = keyPair;
|
response.RequestKeyPair = keyPair;
|
||||||
response.RequestAccessCode = accessCode;
|
response.RequestAccessCode = accessCode;
|
||||||
|
response.FingerprintPhrase = fingerprintPhrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<List<PasswordlessLoginResponse>> PopulateFingerprintPhrasesAsync(List<PasswordlessLoginResponse> passwordlessLoginList)
|
||||||
|
{
|
||||||
|
if (passwordlessLoginList == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var userEmail = await _stateService.GetEmailAsync();
|
||||||
|
foreach (var passwordlessLogin in passwordlessLoginList)
|
||||||
|
{
|
||||||
|
await PopulateFingerprintPhraseAsync(passwordlessLogin, userEmail);
|
||||||
|
}
|
||||||
|
return passwordlessLoginList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<PasswordlessLoginResponse> PopulateFingerprintPhraseAsync(PasswordlessLoginResponse passwordlessLogin, string userEmail)
|
||||||
|
{
|
||||||
|
passwordlessLogin.FingerprintPhrase = string.Join("-", await _cryptoService.GetFingerprintAsync(userEmail, CoreHelpers.Base64UrlDecode(passwordlessLogin.PublicKey)));
|
||||||
|
return passwordlessLogin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,10 +394,10 @@ namespace Bit.Core.Services
|
|||||||
// use values from first userId to apply globals
|
// use values from first userId to apply globals
|
||||||
if (firstUserId != null)
|
if (firstUserId != null)
|
||||||
{
|
{
|
||||||
var theme = await GetValueAsync<int?>(Storage.LiteDb, V3Keys.ThemeKey(firstUserId));
|
var theme = await GetValueAsync<string>(Storage.LiteDb, V3Keys.ThemeKey(firstUserId));
|
||||||
await SetValueAsync(Storage.LiteDb, V4Keys.ThemeKey, theme);
|
await SetValueAsync(Storage.LiteDb, V4Keys.ThemeKey, theme);
|
||||||
|
|
||||||
var autoDarkTheme = await GetValueAsync<int?>(Storage.LiteDb, V3Keys.AutoDarkThemeKey(firstUserId));
|
var autoDarkTheme = await GetValueAsync<string>(Storage.LiteDb, V3Keys.AutoDarkThemeKey(firstUserId));
|
||||||
await SetValueAsync(Storage.LiteDb, V4Keys.AutoDarkThemeKey, autoDarkTheme);
|
await SetValueAsync(Storage.LiteDb, V4Keys.AutoDarkThemeKey, autoDarkTheme);
|
||||||
|
|
||||||
var disableFavicon = await GetValueAsync<bool?>(Storage.LiteDb, V3Keys.DisableFaviconKey(firstUserId));
|
var disableFavicon = await GetValueAsync<bool?>(Storage.LiteDb, V3Keys.DisableFaviconKey(firstUserId));
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden.autofill</string>
|
<string>com.8bit.bitwarden.autofill</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2023.2.1</string>
|
<string>2023.3.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>CFBundleLocalizations</key>
|
<key>CFBundleLocalizations</key>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden.find-login-action-extension</string>
|
<string>com.8bit.bitwarden.find-login-action-extension</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2023.2.1</string>
|
<string>2023.3.1</string>
|
||||||
<key>CFBundleLocalizations</key>
|
<key>CFBundleLocalizations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>XPC!</string>
|
<string>XPC!</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2023.2.1</string>
|
<string>2023.3.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden</string>
|
<string>com.8bit.bitwarden</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2023.2.1</string>
|
<string>2023.3.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>CFBundleIconName</key>
|
<key>CFBundleIconName</key>
|
||||||
|
|||||||
Reference in New Issue
Block a user