mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Merge branch 'feature/pm-1208-f3-options' into feature/pm-2293-admin-approval
# Conflicts: # src/App/Pages/Accounts/LoginApproveDeviceViewModel.cs # src/App/Resources/AppResources.resx
This commit is contained in:
@@ -11,6 +11,7 @@ using Bit.Core.Services;
|
|||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
using Xamarin.CommunityToolkit.ObjectModel;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Essentials;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,9 +93,10 @@ namespace Bit.Core.Abstractions
|
|||||||
Task<PasswordlessLoginResponse> PutAuthRequestAsync(string id, string key, string masterPasswordHash, string deviceIdentifier, bool requestApproved);
|
Task<PasswordlessLoginResponse> PutAuthRequestAsync(string id, string key, string masterPasswordHash, string deviceIdentifier, bool requestApproved);
|
||||||
Task<PasswordlessLoginResponse> PostCreateRequestAsync(PasswordlessCreateLoginRequest passwordlessCreateLoginRequest);
|
Task<PasswordlessLoginResponse> PostCreateRequestAsync(PasswordlessCreateLoginRequest passwordlessCreateLoginRequest);
|
||||||
Task<bool> GetKnownDeviceAsync(string email, string deviceIdentifier);
|
Task<bool> GetKnownDeviceAsync(string email, string deviceIdentifier);
|
||||||
|
Task<DeviceResponse> GetDeviceByIdentifierAsync(string deviceIdentifier);
|
||||||
|
Task<DeviceResponse> UpdateTrustedDeviceKeysAsync(string deviceIdentifier, TrustedDeviceKeysRequest deviceRequest);
|
||||||
Task<OrganizationDomainSsoDetailsResponse> GetOrgDomainSsoDetailsAsync(string email);
|
Task<OrganizationDomainSsoDetailsResponse> GetOrgDomainSsoDetailsAsync(string email);
|
||||||
Task<bool> GetDevicesExistenceByTypes(DeviceType[] deviceTypes);
|
Task<bool> GetDevicesExistenceByTypes(DeviceType[] deviceTypes);
|
||||||
Task<DeviceResponse> PutUpdateTrustedDeviceKeys(UpdateTrustedDeviceKeysRequest request);
|
|
||||||
Task<ConfigResponse> GetConfigsAsync();
|
Task<ConfigResponse> GetConfigsAsync();
|
||||||
Task<string> GetFastmailAccountIdAsync(string apiKey);
|
Task<string> GetFastmailAccountIdAsync(string apiKey);
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/Core/Abstractions/IDeviceTrustCryptoService.cs
Normal file
11
src/Core/Abstractions/IDeviceTrustCryptoService.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
|
|
||||||
|
namespace Bit.Core.Abstractions
|
||||||
|
{
|
||||||
|
public interface IDeviceTrustCryptoService
|
||||||
|
{
|
||||||
|
Task<SymmetricCryptoKey> GetDeviceKeyAsync();
|
||||||
|
Task<DeviceResponse> TrustDeviceAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,8 @@ namespace Bit.Core.Abstractions
|
|||||||
Task SetOrgKeysEncryptedAsync(Dictionary<string, string> value, string userId = null);
|
Task SetOrgKeysEncryptedAsync(Dictionary<string, string> value, string userId = null);
|
||||||
Task<string> GetPrivateKeyEncryptedAsync(string userId = null);
|
Task<string> GetPrivateKeyEncryptedAsync(string userId = null);
|
||||||
Task SetPrivateKeyEncryptedAsync(string value, string userId = null);
|
Task SetPrivateKeyEncryptedAsync(string value, string userId = null);
|
||||||
|
Task<SymmetricCryptoKey> GetDeviceKeyAsync(string userId = null);
|
||||||
|
Task SetDeviceKeyAsync(SymmetricCryptoKey value, string userId = null);
|
||||||
Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null);
|
Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null);
|
||||||
Task SetAutofillBlacklistedUrisAsync(List<string> value, string userId = null);
|
Task SetAutofillBlacklistedUrisAsync(List<string> value, string userId = null);
|
||||||
Task<bool?> GetAutofillTileAddedAsync();
|
Task<bool?> GetAutofillTileAddedAsync();
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
public static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}";
|
public static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}";
|
||||||
public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}";
|
public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}";
|
||||||
public static string EncKeyKey(string userId) => $"encKey_{userId}";
|
public static string EncKeyKey(string userId) => $"encKey_{userId}";
|
||||||
|
public static string DeviceKeyKey(string userId) => $"deviceKey_{userId}";
|
||||||
public static string KeyHashKey(string userId) => $"keyHash_{userId}";
|
public static string KeyHashKey(string userId) => $"keyHash_{userId}";
|
||||||
public static string PinProtectedKey(string userId) => $"pinProtectedKey_{userId}";
|
public static string PinProtectedKey(string userId) => $"pinProtectedKey_{userId}";
|
||||||
public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}";
|
public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}";
|
||||||
|
|||||||
10
src/Core/Models/Request/TrustedDeviceKeysRequest.cs
Normal file
10
src/Core/Models/Request/TrustedDeviceKeysRequest.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
namespace Bit.Core.Models.Request
|
||||||
|
{
|
||||||
|
public class TrustedDeviceKeysRequest
|
||||||
|
{
|
||||||
|
public string EncryptedUserKey { get; set; }
|
||||||
|
public string EncryptedPublicKey { get; set; }
|
||||||
|
public string EncryptedPrivateKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
namespace Bit.Core.Models.Request
|
|
||||||
{
|
|
||||||
public class UpdateTrustedDeviceKeysRequest
|
|
||||||
{
|
|
||||||
public string DeviceIdentifier { get; set; }
|
|
||||||
public string DevicePublicKeyEncryptedUserKey { get; set; }
|
|
||||||
public string UserKeyEncryptedDevicePublicKey { get; set; }
|
|
||||||
public string DeviceKeyEncryptedDevicePrivateKey { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,17 +1,13 @@
|
|||||||
using System;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Enums;
|
|
||||||
|
|
||||||
namespace Bit.Core.Models.Response
|
public class DeviceResponse
|
||||||
{
|
{
|
||||||
public class DeviceResponse
|
public string Id { get; set; }
|
||||||
{
|
public int Name { get; set; }
|
||||||
public string Id { get; set; }
|
public string Identifier { get; set; }
|
||||||
public string UserId { get; set; }
|
public DeviceType Type { get; set; }
|
||||||
public string Name { get; set; }
|
public string CreationDate { get; set; }
|
||||||
public string Identifier { get; set; }
|
public string EncryptedUserKey { get; set; }
|
||||||
public DeviceType Type { get; set; }
|
public string EncryptedPublicKey { get; set; }
|
||||||
public string CreationDate { get; set; }
|
public string EncryptedPrivateKey { get; set; }
|
||||||
public string RevisionDate { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -419,10 +419,14 @@ namespace Bit.Core.Services
|
|||||||
HttpMethod.Post, "/devices/exist-by-types", deviceTypes, true, true);
|
HttpMethod.Post, "/devices/exist-by-types", deviceTypes, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<DeviceResponse> PutUpdateTrustedDeviceKeys(UpdateTrustedDeviceKeysRequest request)
|
public Task<DeviceResponse> GetDeviceByIdentifierAsync(string deviceIdentifier)
|
||||||
{
|
{
|
||||||
return SendAsync<UpdateTrustedDeviceKeysRequest, DeviceResponse>(
|
return SendAsync<object, DeviceResponse>(HttpMethod.Get, $"/devices/identifier/{deviceIdentifier}", null, true, true);
|
||||||
HttpMethod.Put, $"/devices/${request.DeviceIdentifier}/keys", request, true, true);
|
}
|
||||||
|
|
||||||
|
public Task<DeviceResponse> UpdateTrustedDeviceKeysAsync(string deviceIdentifier, TrustedDeviceKeysRequest trustedDeviceKeysRequest)
|
||||||
|
{
|
||||||
|
return SendAsync<TrustedDeviceKeysRequest, DeviceResponse>(HttpMethod.Put, $"/devices/{deviceIdentifier}/keys", trustedDeviceKeysRequest, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
81
src/Core/Services/DeviceTrustCryptoService.cs
Normal file
81
src/Core/Services/DeviceTrustCryptoService.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
|
using Bit.Core.Models.Request;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class DeviceTrustCryptoService : IDeviceTrustCryptoService
|
||||||
|
{
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IAppIdService _appIdService;
|
||||||
|
private readonly ICryptoFunctionService _cryptoFunctionService;
|
||||||
|
private readonly ICryptoService _cryptoService;
|
||||||
|
private readonly IStateService _stateService;
|
||||||
|
|
||||||
|
private const int DEVICE_KEY_SIZE = 64;
|
||||||
|
|
||||||
|
public DeviceTrustCryptoService(
|
||||||
|
IApiService apiService,
|
||||||
|
IAppIdService appIdService,
|
||||||
|
ICryptoFunctionService cryptoFunctionService,
|
||||||
|
ICryptoService cryptoService,
|
||||||
|
IStateService stateService)
|
||||||
|
{
|
||||||
|
_apiService = apiService;
|
||||||
|
_appIdService = appIdService;
|
||||||
|
_cryptoFunctionService = cryptoFunctionService;
|
||||||
|
_cryptoService = cryptoService;
|
||||||
|
_stateService = stateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SymmetricCryptoKey> GetDeviceKeyAsync()
|
||||||
|
{
|
||||||
|
return await _stateService.GetDeviceKeyAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetDeviceKeyAsync(SymmetricCryptoKey deviceKey)
|
||||||
|
{
|
||||||
|
await _stateService.SetDeviceKeyAsync(deviceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DeviceResponse> TrustDeviceAsync()
|
||||||
|
{
|
||||||
|
// Attempt to get user key
|
||||||
|
var userKey = await _cryptoService.GetEncKeyAsync();
|
||||||
|
if (userKey == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Generate deviceKey
|
||||||
|
var deviceKey = await MakeDeviceKeyAsync();
|
||||||
|
|
||||||
|
// Generate asymmetric RSA key pair: devicePrivateKey, devicePublicKey
|
||||||
|
var (devicePublicKey, devicePrivateKey) = await _cryptoFunctionService.RsaGenerateKeyPairAsync(2048);
|
||||||
|
|
||||||
|
// Send encrypted keys to server
|
||||||
|
var deviceIdentifier = await _appIdService.GetAppIdAsync();
|
||||||
|
var deviceRequest = new TrustedDeviceKeysRequest
|
||||||
|
{
|
||||||
|
EncryptedUserKey = (await _cryptoService.RsaEncryptAsync(userKey.EncKey, devicePublicKey)).EncryptedString,
|
||||||
|
EncryptedPublicKey = (await _cryptoService.EncryptAsync(devicePublicKey, userKey)).EncryptedString,
|
||||||
|
EncryptedPrivateKey = (await _cryptoService.EncryptAsync(devicePrivateKey, deviceKey)).EncryptedString,
|
||||||
|
};
|
||||||
|
|
||||||
|
var deviceResponse = await _apiService.UpdateTrustedDeviceKeysAsync(deviceIdentifier, deviceRequest);
|
||||||
|
|
||||||
|
// Store device key if successful
|
||||||
|
await SetDeviceKeyAsync(deviceKey);
|
||||||
|
return deviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<SymmetricCryptoKey> MakeDeviceKeyAsync()
|
||||||
|
{
|
||||||
|
// Create 512-bit device key
|
||||||
|
var randomBytes = await _cryptoFunctionService.RandomBytesAsync(DEVICE_KEY_SIZE);
|
||||||
|
return new SymmetricCryptoKey(randomBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -482,6 +482,17 @@ namespace Bit.Core.Services
|
|||||||
await SetValueAsync(Constants.EncPrivateKeyKey(reconciledOptions.UserId), value, reconciledOptions);
|
await SetValueAsync(Constants.EncPrivateKeyKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<SymmetricCryptoKey> GetDeviceKeyAsync(string userId = null)
|
||||||
|
{
|
||||||
|
var deviceKeyB64 = await _storageMediatorService.GetAsync<string>(Constants.DeviceKeyKey(userId), true);
|
||||||
|
return new SymmetricCryptoKey(Convert.FromBase64String(deviceKeyB64));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetDeviceKeyAsync(SymmetricCryptoKey value, string userId = null)
|
||||||
|
{
|
||||||
|
await _storageMediatorService.SaveAsync(Constants.DeviceKeyKey(userId), value.KeyB64, true);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null)
|
public async Task<List<string>> GetAutofillBlacklistedUrisAsync(string userId = null)
|
||||||
{
|
{
|
||||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||||
|
|||||||
Reference in New Issue
Block a user