1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-08 19:43:56 +00:00

Merge branch 'master' into feature/maui-migration

Fixed conflicts and added null check on ForwardEmailDomainName

# Conflicts:
#	src/Core/Pages/Vault/CipherAddEditPage.xaml
#	src/Core/Pages/Vault/CipherDetailsPage.xaml
#	src/iOS.Core/Renderers/CollectionView/ExtendedGroupableItemsViewController.cs
This commit is contained in:
Dinis Vieira
2023-11-05 23:59:30 +00:00
124 changed files with 7786 additions and 2159 deletions

View File

@@ -565,13 +565,8 @@ namespace Bit.Core.Services
await UpsertAsync(data);
}
public async Task<ICipherService.ShareWithServerError> ShareWithServerAsync(CipherView cipher, string organizationId, HashSet<string> collectionIds)
public async Task ShareWithServerAsync(CipherView cipher, string organizationId, HashSet<string> collectionIds)
{
if (!await ValidateCanBeSharedWithOrgAsync(cipher, organizationId))
{
return ICipherService.ShareWithServerError.DuplicatedPasskeyInOrg;
}
var attachmentTasks = new List<Task>();
if (cipher.Attachments != null)
{
@@ -592,21 +587,6 @@ namespace Bit.Core.Services
var userId = await _stateService.GetActiveUserIdAsync();
var data = new CipherData(response, userId, collectionIds);
await UpsertAsync(data);
return ICipherService.ShareWithServerError.None;
}
private async Task<bool> ValidateCanBeSharedWithOrgAsync(CipherView cipher, string organizationId)
{
if (!cipher.HasFido2Key)
{
return true;
}
var decCiphers = await GetAllDecryptedAsync();
return !decCiphers
.Where(c => c.OrganizationId == organizationId)
.Any(c => !cipher.Login.MainFido2Key.IsUniqueAgainst(c.Login?.MainFido2Key));
}
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data)
@@ -1177,14 +1157,17 @@ namespace Bit.Core.Services
cipher.Login.Uris.Add(loginUri);
}
}
if (model.Login.HasFido2Keys)
if (model.Login.HasFido2Credentials)
{
cipher.Login.Fido2Keys = new List<Fido2Key>();
foreach (var fido2Key in model.Login.Fido2Keys)
cipher.Login.Fido2Credentials = new List<Fido2Credential>();
foreach (var fido2Credential in model.Login.Fido2Credentials)
{
var fido2KeyDomain = new Fido2Key();
await EncryptObjPropertyAsync(fido2Key, fido2KeyDomain, Fido2Key.EncryptableProperties, key);
cipher.Login.Fido2Keys.Add(fido2KeyDomain);
var fido2CredentialDomain = new Fido2Credential
{
CreationDate = fido2Credential.CreationDate
};
await EncryptObjPropertyAsync(fido2Credential, fido2CredentialDomain, Fido2Credential.EncryptablePropertiesToMap, key);
cipher.Login.Fido2Credentials.Add(fido2CredentialDomain);
}
}
break;

View File

@@ -37,7 +37,7 @@ namespace Bit.Core.Services
_stateService.SetConfigs(_configs);
}
}
catch (ApiException ex) when (ex.Error.StatusCode == System.Net.HttpStatusCode.BadGateway)
catch (ApiException ex) when (ex.Error?.StatusCode == System.Net.HttpStatusCode.BadGateway)
{
// ignore if there is no internet connection and return local configs
}

View File

@@ -719,6 +719,17 @@ namespace Bit.Core.Services
await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile)));
}
public async Task UpdateMasterKeyAndUserKeyAsync(MasterKey masterKey)
{
var userKey = await DecryptUserKeyWithMasterKeyAsync(masterKey);
await SetMasterKeyAsync(masterKey);
var hasKey = await HasUserKeyAsync();
if (!hasKey)
{
await SetUserKeyAsync(userKey);
}
}
// --HELPER METHODS--
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
@@ -1077,6 +1088,12 @@ namespace Bit.Core.Services
{
await _stateService.SetUserKeyBiometricUnlockAsync(userKey, userId);
}
// Clear old enc key only if we don't need to still migrate PIN
if (await _stateService.GetPinProtectedAsync() == null
&& await _stateService.GetPinProtectedKeyAsync() == null)
{
await _stateService.SetEncKeyEncryptedAsync(null, userId);
}
await _stateService.SetKeyEncryptedAsync(null, userId);
// Set encrypted user key just in case the user locks without syncing

View File

@@ -0,0 +1,52 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Core.Services.EmailForwarders
{
public class ForwardEmailForwarderOptions : ForwarderOptions
{
public string DomainName { get; set; }
}
public class ForwardEmailForwarder : BaseForwarder<ForwardEmailForwarderOptions>
{
private readonly string _domain;
protected override string RequestUri => $"https://api.forwardemail.net/v1/domains/{_domain}/aliases";
public ForwardEmailForwarder(string domain)
{
_domain = domain;
}
protected override bool CanGenerate(ForwardEmailForwarderOptions options)
{
return !string.IsNullOrWhiteSpace(options.ApiKey) && !string.IsNullOrWhiteSpace(options.DomainName);
}
protected override void ConfigureHeaders(HttpRequestHeaders headers, ForwardEmailForwarderOptions options)
{
headers.Add("Authorization", $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes(options.ApiKey + ":"))}");
}
protected override Task<HttpContent> GetContentAsync(IApiService apiService, ForwardEmailForwarderOptions options)
{
return Task.FromResult<HttpContent>(new StringContent(
JsonConvert.SerializeObject(
new
{
description = "Generated by Bitwarden."
}), Encoding.UTF8, "application/json"));
}
protected override string HandleResponse(JObject result)
{
return $"{result["name"]}@{result["domain"]?["name"] ?? _domain}";
}
}
}

View File

@@ -51,13 +51,7 @@ namespace Bit.App.Services
{
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
await _cryptoService.SetMasterKeyAsync(masterKey);
var hasKey = await _cryptoService.HasUserKeyAsync();
if (!hasKey)
{
await _cryptoService.SetUserKeyAsync(userKey);
}
await _cryptoService.UpdateMasterKeyAndUserKeyAsync(masterKey);
}
return passwordValid;

View File

@@ -48,12 +48,14 @@ namespace Bit.Core.Services
}
else
{
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, null);
var masterKey = await _cryptoService.GetOrDeriveMasterKeyAsync(secret);
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, masterKey);
if (!passwordValid)
{
await InvalidSecretErrorAsync(verificationType);
return false;
}
await _cryptoService.UpdateMasterKeyAndUserKeyAsync(masterKey);
}
return true;

View File

@@ -141,6 +141,13 @@ namespace Bit.Core.Services
.GenerateAsync(_apiService, (AnonAddyForwarderOptions)options.GetForwarderOptions());
}
if (options.ServiceType == ForwardedEmailServiceType.ForwardEmail)
{
var forwardedEmailOptions = (ForwardEmailForwarderOptions)options.GetForwarderOptions();
return await new ForwardEmailForwarder(forwardedEmailOptions.DomainName)
.GenerateAsync(_apiService, forwardedEmailOptions);
}
BaseForwarder<ForwarderOptions> simpleForwarder = null;
switch (options.ServiceType)

View File

@@ -3,7 +3,6 @@ using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
namespace Bit.Core.Services
{
@@ -56,8 +55,15 @@ namespace Bit.Core.Services
public long? DelayLockAndLogoutMs { get; set; }
/// <summary>
/// Determine if the current or provided account is locked.
/// </summary>
/// <param name="userId">
/// Optional specified user, must be provided if not the current account.
/// </param>
public async Task<bool> IsLockedAsync(string userId = null)
{
// If biometrics are used, we can use the flag to determine locked state
var biometricSet = await IsBiometricLockSetAsync(userId);
if (biometricSet && await _stateService.GetBiometricLockedAsync(userId))
{
@@ -68,18 +74,21 @@ namespace Bit.Core.Services
{
try
{
// Filter out accounts without auto key
if (!await _cryptoService.HasAutoUnlockKeyAsync(userId))
{
return true;
}
// Inactive accounts with an auto key aren't locked, but we shouldn't set user key
if (userId != null && await _stateService.GetActiveUserIdAsync() != userId)
{
await _cryptoService.SetUserKeyAsync(await _cryptoService.GetAutoUnlockKeyAsync(userId),
userId);
return false;
}
await _cryptoService.SetUserKeyAsync(await _cryptoService.GetAutoUnlockKeyAsync(userId), userId);
}
catch (LegacyUserException)
{
// Legacy users must migrate on web vault before login
await LogOutAsync(false, userId);
}