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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
52
src/Core/Services/EmailForwarders/ForwardEmailForwarder.cs
Normal file
52
src/Core/Services/EmailForwarders/ForwardEmailForwarder.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user