1
0
mirror of https://github.com/bitwarden/mobile synced 2026-02-03 10:03:16 +00:00

Compare commits

..

9 Commits

Author SHA1 Message Date
Carlos Gonçalves
485aca083b Merge branch 'main' into vault/pm-2572 2024-06-11 14:11:28 +01:00
Carlos Gonçalves
290266c262 PM-2572 Fix pr comment 2024-05-29 13:27:59 +01:00
Carlos Gonçalves
c40eb9d3db PM-2572 Fix pr comments 2024-05-28 21:31:28 +01:00
Carlos Gonçalves
df9fcd1aca Merge branch 'main' into vault/pm-2572 2024-05-28 18:35:02 +01:00
Carlos Gonçalves
890eff79a2 PM-2572 Fix pr comments 2024-05-28 18:34:41 +01:00
Carlos Gonçalves
265c95b494 PM-2572 Code refactor 2024-05-28 10:59:40 +01:00
Carlos Gonçalves
25e394eb5e Minor change 2024-05-13 18:12:41 +01:00
Carlos Gonçalves
354aec09d9 Minor refactor 2024-05-13 18:03:43 +01:00
Carlos Gonçalves
4332e7a498 PM-2572 Added cipherKey to Attachment and logic to use it 2024-05-13 16:59:39 +01:00
30 changed files with 251 additions and 53 deletions

View File

@@ -85,6 +85,11 @@ jobs:
- name: Set up MSBuild
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
# This step might be obsolete at some point as .NET MAUI workloads
# are starting to come pre-installed on the GH Actions build agents.
- name: Install MAUI Workload
run: dotnet workload install maui --ignore-failed-sources
- name: Setup Windows builder
run: choco install checksum --no-progress
@@ -140,7 +145,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((11000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
@@ -307,6 +312,11 @@ jobs:
- name: Set up MSBuild
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
# This step might be obsolete at some point as .NET MAUI workloads
# are starting to come pre-installed on the GH Actions build agents.
- name: Install MAUI Workload
run: dotnet workload install maui --ignore-failed-sources
- name: Setup Windows builder
run: choco install checksum --no-progress
@@ -344,7 +354,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((11000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
@@ -509,7 +519,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((8000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
echo "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist

View File

@@ -72,7 +72,6 @@ jobs:
workflow: build.yml
workflow_conclusion: success
branch: ${{ steps.branch.outputs.branch-name }}
skip_unpack: true
- name: Dry Run - Download all artifacts
if: ${{ inputs.release_type == 'Dry Run' }}
@@ -81,15 +80,9 @@ jobs:
workflow: build.yml
workflow_conclusion: success
branch: main
skip_unpack: true
- name: Unzip release assets
run: |
unzip bw-android-apk-sha256.txt.zip -d bw-android-apk-sha256.txt
unzip bw-fdroid-apk-sha256.txt.zip -d bw-fdroid-apk-sha256.txt
unzip com.x8bit.bitwarden-fdroid.apk.zip -d com.x8bit.bitwarden-fdroid.apk
unzip com.x8bit.bitwarden.aab.zip -d com.x8bit.bitwarden.aab
unzip com.x8bit.bitwarden.apk.zip -d com.x8bit.bitwarden.apk
- name: Prep Bitwarden iOS release asset
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release
if: ${{ inputs.release_type != 'Dry Run' }}

View File

@@ -1,5 +1,5 @@
<?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="2024.7.0" 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="2024.6.0" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.6.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleIconName</key>

View File

@@ -41,6 +41,7 @@ namespace Bit.Core.Abstractions
Task<CipherResponse> PutShareCipherAsync(string id, CipherShareRequest request);
Task PutDeleteCipherAsync(string id);
Task<CipherResponse> PutRestoreCipherAsync(string id);
Task<bool> HasUnassignedCiphersAsync();
Task RefreshIdentityTokenAsync();
Task<SsoPrevalidateResponse> PreValidateSsoAsync(string identifier);
Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path,

View File

@@ -36,5 +36,6 @@ namespace Bit.Core.Abstractions
Task RestoreWithServerAsync(string id);
Task<string> CreateNewLoginForPasskeyAsync(Fido2ConfirmNewCredentialParams newPasskeyParams);
Task CopyTotpCodeIfNeededAsync(CipherView cipher);
Task<bool> VerifyOrganizationHasUnassignedItemsAsync();
}
}

View File

@@ -187,6 +187,8 @@ namespace Bit.Core.Abstractions
Task<BwRegion?> GetPreAuthRegionAsync();
Task SetPreAuthRegionAsync(BwRegion value);
Task ReloadStateAsync();
Task<bool> GetShouldCheckOrganizationUnassignedItemsAsync(string userId = null);
Task SetShouldCheckOrganizationUnassignedItemsAsync(bool shouldCheck, string userId = null);
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
Task<string> GetPinProtectedAsync(string userId = null);
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]

View File

@@ -45,6 +45,8 @@ namespace Bit.Core
public const string PasswordlessLoginRequestKey = "passwordlessLoginRequest";
public const string PreLoginEmailKey = "preLoginEmailKey";
public const string ConfigsKey = "configsKey";
public const string DisplayEuEnvironmentFlag = "display-eu-environment";
public const string UnassignedItemsBannerFlag = "unassigned-items-banner";
public const string RegionEnvironment = "regionEnvironment";
public const string DuoCallback = "bitwarden://duo-callback";
public const string NavigateToMessageCommand = "navigateTo";
@@ -137,6 +139,7 @@ namespace Bit.Core
public static string ShouldConnectToWatchKey(string userId) => $"shouldConnectToWatch_{userId}";
public static string ScreenCaptureAllowedKey(string userId) => $"screenCaptureAllowed_{userId}";
public static string PendingAdminAuthRequest(string userId) => $"pendingAdminAuthRequest_{userId}";
public static string ShouldCheckOrganizationUnassignedItemsKey(string userId) => $"shouldCheckOrganizationUnassignedItems_{userId}";
[Obsolete]
public static string KeyKey(string userId) => $"key_{userId}";
[Obsolete]

View File

@@ -27,6 +27,7 @@ namespace Bit.App.Models
public bool HideAccountSwitcher { get; set; }
public OtpData? OtpData { get; set; }
public bool HasUnlockedInThisTransaction { get; set; }
public bool HasJustLoggedInOrUnlocked { get; set; }
public void SetAllFrom(AppOptions o)
{

View File

@@ -25,6 +25,7 @@ namespace Bit.App.Pages
private bool _rememberEmail;
private string _email;
private string _selectedEnvironmentName;
private bool _displayEuEnvironment;
public HomeViewModel()
{
@@ -115,6 +116,7 @@ namespace Bit.App.Pages
{
Email = await _stateService.GetRememberedEmailAsync();
RememberEmail = !string.IsNullOrEmpty(Email);
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag, forceRefresh: true);
}
public async Task ContinueToLoginStepAsync()
@@ -156,7 +158,11 @@ namespace Bit.App.Pages
public async Task ShowEnvironmentPickerAsync()
{
var options = new string[] { BwRegion.US.Domain(), BwRegion.EU.Domain(), AppResources.SelfHosted };
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag);
var options = _displayEuEnvironment
? new string[] { BwRegion.US.Domain(), BwRegion.EU.Domain(), AppResources.SelfHosted }
: new string[] { BwRegion.US.Domain(), AppResources.SelfHosted };
await MainThread.InvokeOnMainThreadAsync(async () =>
{
var result = await _deviceActionService.Value.DisplayActionSheetAsync(AppResources.LoggingInOn, AppResources.Cancel, null, options);

View File

@@ -232,6 +232,11 @@ namespace Bit.App.Pages
return;
}
var previousPage = await AppHelpers.ClearPreviousPage();
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
App.MainPage = new TabsPage(_appOptions, previousPage);
}
}

View File

@@ -35,6 +35,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -196,6 +196,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -56,6 +56,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -71,6 +71,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -207,6 +207,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -33,7 +33,7 @@ namespace Bit.App.Pages
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
_stateService = ServiceContainer.Resolve<IStateService>();
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage, appOptions: appOptions))
{
Title = AppResources.MyVault,
IconImageSource = "lock.png"

View File

@@ -28,7 +28,7 @@ namespace Bit.App.Pages
public GroupingsPage(bool mainPage, CipherType? type = null, string folderId = null,
string collectionId = null, string pageTitle = null, string vaultFilterSelection = null,
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false)
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false, AppOptions appOptions = null)
{
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
InitializeComponent();
@@ -51,6 +51,7 @@ namespace Bit.App.Pages
_vm.CollectionId = collectionId;
_vm.Deleted = deleted;
_vm.ShowTotp = showTotp;
_vm.AppOptions = appOptions;
_previousPage = previousPage;
if (pageTitle != null)
{
@@ -161,6 +162,8 @@ namespace Bit.App.Pages
return;
}
await _vm.CheckOrganizationUnassignedItemsAsync();
// Push registration
var lastPushRegistration = await _stateService.GetPushLastRegistrationDateAsync();
lastPushRegistration = lastPushRegistration.GetValueOrDefault(DateTime.MinValue);

View File

@@ -46,6 +46,8 @@ namespace Bit.App.Pages
private readonly IPasswordRepromptService _passwordRepromptService;
private readonly IOrganizationService _organizationService;
private readonly IPolicyService _policyService;
private readonly IConfigService _configService;
private readonly IEnvironmentService _environmentService;
private readonly ILogger _logger;
public GroupingsPageViewModel()
@@ -62,6 +64,8 @@ namespace Bit.App.Pages
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
_configService = ServiceContainer.Resolve<IConfigService>();
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
_logger = ServiceContainer.Resolve<ILogger>("logger");
Loading = true;
@@ -105,6 +109,7 @@ namespace Bit.App.Pages
public List<Core.Models.View.CollectionView> Collections { get; set; }
public List<TreeNode<Core.Models.View.CollectionView>> NestedCollections { get; set; }
public AppOptions AppOptions { get; internal set; }
protected override ICipherService cipherService => _cipherService;
protected override IPolicyService policyService => _policyService;
protected override IOrganizationService organizationService => _organizationService;
@@ -700,5 +705,59 @@ namespace Bit.App.Pages
var folders = decFolders.Where(f => _allCiphers.Any(c => c.FolderId == f.Id)).ToList();
return folders.Any() ? folders : null;
}
internal async Task CheckOrganizationUnassignedItemsAsync()
{
try
{
if (AppOptions?.HasJustLoggedInOrUnlocked != true)
{
return;
}
AppOptions.HasJustLoggedInOrUnlocked = false;
if (!await _configService.GetFeatureFlagBoolAsync(Core.Constants.UnassignedItemsBannerFlag)
||
!await _stateService.GetShouldCheckOrganizationUnassignedItemsAsync())
{
return;
}
var waitSyncTask = Task.Run(async () =>
{
while (_syncService.SyncInProgress)
{
await Task.Delay(100);
}
});
await waitSyncTask.WaitAsync(TimeSpan.FromMinutes(5));
if (!await _cipherService.VerifyOrganizationHasUnassignedItemsAsync())
{
return;
}
var message = _environmentService.SelectedRegion == Core.Enums.Region.SelfHosted
? AppResources.OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong
: AppResources.OrganizationUnassignedItemsMessageUSEUDescriptionLong;
var response = await _deviceActionService.DisplayAlertAsync(AppResources.Notice,
message,
null,
AppResources.RemindMeLater,
AppResources.Ok);
if (response == AppResources.Ok)
{
await _stateService.SetShouldCheckOrganizationUnassignedItemsAsync(false);
}
}
catch (TimeoutException) { }
catch (Exception ex)
{
_logger.Exception(ex);
}
}
}
}

View File

@@ -1328,7 +1328,7 @@ namespace Bit.Core.Resources.Localization {
}
/// <summary>
/// Looks up a localized string similar to Bitwarden help center.
/// Looks up a localized string similar to Bitwarden Help Center.
/// </summary>
public static string BitwardenHelpCenter {
get {
@@ -4929,6 +4929,15 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Notice.
/// </summary>
public static string Notice {
get {
return ResourceManager.GetString("Notice", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This account has two-step login set up, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app)..
/// </summary>
@@ -5164,6 +5173,24 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
/// </summary>
public static string OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong {
get {
return ResourceManager.GetString("OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
/// </summary>
public static string OrganizationUnassignedItemsMessageUSEUDescriptionLong {
get {
return ResourceManager.GetString("OrganizationUnassignedItemsMessageUSEUDescriptionLong", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Organization identifier.
/// </summary>
@@ -5849,6 +5876,15 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Remind me later.
/// </summary>
public static string RemindMeLater {
get {
return ResourceManager.GetString("RemindMeLater", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove.
/// </summary>

View File

@@ -2818,7 +2818,7 @@ Haluatko vaihtaa tähän tiliin?</value>
<value>Tekstinsisäistä automattitäyttöä käytetään, jos aktiivinen näppäimistö tukee sitä. Muussa tapauksessa käytetään ponnahdusvalintaa.</value>
</data>
<data name="AdditionalOptions" xml:space="preserve">
<value>Lisävalinnat</value>
<value>Lisäasetukset</value>
</data>
<data name="ContinueToWebApp" xml:space="preserve">
<value>Avataanko verkkosovellus?</value>

View File

@@ -2769,7 +2769,7 @@ Do you want to switch to this account?</value>
<value>Account security</value>
</data>
<data name="BitwardenHelpCenter" xml:space="preserve">
<value>Bitwarden help center</value>
<value>Bitwarden Help Center</value>
</data>
<data name="ContactBitwardenSupport" xml:space="preserve">
<value>Contact Bitwarden support</value>
@@ -2975,6 +2975,18 @@ Do you want to switch to this account?</value>
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
</data>
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="RemindMeLater" xml:space="preserve">
<value>Remind me later</value>
</data>
<data name="Notice" xml:space="preserve">
<value>Notice</value>
</data>
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
<value>Passkeys not supported for this app</value>
</data>

View File

@@ -2838,7 +2838,7 @@ Bu hesaba geçmek ister misiniz?</value>
<value>App Store'a gitmek ister misiniz?</value>
</data>
<data name="ContinueToDeviceSettings" xml:space="preserve">
<value>Cihaz ayarlarına gidilsin mi?</value>
<value>Continue to device Settings?</value>
</data>
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
<value>Bitwarden web uygulamasında iki aşamalı girişi ayarlayarak hesabınızın güvenliğini artırabilirsiniz.</value>
@@ -2933,11 +2933,11 @@ Bu hesaba geçmek ister misiniz?</value>
<value>Geçiş anahtarı okuma hatası</value>
</data>
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
<value>{0} için geçiş anahtarı oluşturulamadı. Daha sonra tekrar deneyin.</value>
<value>There was a problem creating a passkey for {0}. Try again later.</value>
<comment>The parameter is the RpId</comment>
</data>
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
<value>{0} için geçiş anahtarı okunamadı. Daha sonra tekrar deneyin.</value>
<value>There was a problem reading your passkey for {0}. Try again later.</value>
<comment>The parameter is the RpId</comment>
</data>
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
@@ -2962,16 +2962,16 @@ Bu hesaba geçmek ister misiniz?</value>
<value>1. Go to your device's Settings &gt; Passwords &gt; Password Options</value>
</data>
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
<value>Oto-Doldurma'yı Etkinleştir</value>
<value>2. Turn on AutoFill</value>
</data>
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
<value>Parolalarınızı ve geçiş anahtarlarını kullanmak için "Bitwarden" seçin</value>
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
<value>Geçiş anahtarınız Bitwarden kasasına kaydedilecektir</value>
<value>Your passkey will be saved to your Bitwarden vault</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
<value>{0} için geçiş anahtarınız Bitwarden kasasına kaydedilecektir</value>
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
</data>
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
@@ -2989,18 +2989,18 @@ Bu hesaba geçmek ister misiniz?</value>
<value>Bu uygulamada geçiş anahtarları desteklenmiyor</value>
</data>
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü tarayıcı ayrıcalıklı değil</value>
<value>Passkey operation failed because browser is not privileged</value>
</data>
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü tarayıcı imzası uyumsuz</value>
<value>Passkey operation failed because browser signature does not match</value>
</data>
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü varlık bağlantıları eksik</value>
<value>Passkey operation failed because of missing asset links</value>
</data>
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü uygulama varlık bağlantılarında bulunamadı</value>
<value>Passkey operation failed because app not found in asset links</value>
</data>
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü uygulama doğrulanamadı</value>
<value>Passkey operation failed because app could not be verified</value>
</data>
</root>

View File

@@ -2695,7 +2695,7 @@
<value>批准后,您将收到通知。 </value>
</data>
<data name="TroubleLoggingIn" xml:space="preserve">
<value>登录遇到问题</value>
<value>登录遇到问题?</value>
</data>
<data name="LoggingInAsX" xml:space="preserve">
<value>正登录为 {0}</value>

View File

@@ -334,6 +334,11 @@ namespace Bit.Core.Services
return SendAsync<object, CipherResponse>(HttpMethod.Put, string.Concat("/ciphers/", id, "/restore"), null, true, true);
}
public Task<bool> HasUnassignedCiphersAsync()
{
return SendAsync<object, bool>(HttpMethod.Get, "/ciphers/has-unassigned-ciphers", null, true, true);
}
#endregion
#region Attachments APIs

View File

@@ -1,4 +1,4 @@
#define ENABLE_NEW_CIPHER_KEY_ENCRYPTION_ON_CREATION
//#define ENABLE_NEW_CIPHER_KEY_ENCRYPTION_ON_CREATION
using System;
using System.Collections.Generic;
@@ -114,7 +114,7 @@ namespace Bit.Core.Services
public async Task<Cipher> EncryptAsync(CipherView model, SymmetricCryptoKey key = null,
Cipher originalCipher = null)
{
// Adjust password history and attachments
// Adjust password history
if (model.Id != null)
{
if (originalCipher == null)
@@ -169,9 +169,6 @@ namespace Bit.Core.Services
}
}
}
//adjust attachments
model.Attachments = existingCipher.Attachments;
}
if (!model.PasswordHistory?.Any() ?? false)
{
@@ -574,28 +571,39 @@ namespace Bit.Core.Services
await UpsertAsync(data);
}
public async Task ShareWithServerAsync(CipherView cipher, string organizationId, HashSet<string> collectionIds)
public async Task ShareWithServerAsync(CipherView cipherView, string organizationId, HashSet<string> collectionIds)
{
var attachmentTasks = new List<Task>();
if (cipher.Attachments != null)
Cipher cipher = null;
//If the cipher doesn't have a key, we update it
if(cipherView.Key == null && await ShouldUseCipherKeyEncryptionAsync())
{
foreach (var attachment in cipher.Attachments)
await UpdateAndUpsertAsync(cipherView, cipher => _apiService.PutCipherAsync(cipherView.Id, new CipherRequest(cipher)));
cipher = await GetAsync(cipherView.Id);
cipherView = await cipher.DecryptAsync();
}
if (cipherView.Attachments != null)
{
foreach (var attachment in cipherView.Attachments)
{
if (attachment.Key == null)
{
attachmentTasks.Add(ShareAttachmentWithServerAsync(attachment, cipher.Id, organizationId));
attachmentTasks.Add(ShareAttachmentWithServerAsync(attachment, cipherView.Id, organizationId));
}
}
}
await Task.WhenAll(attachmentTasks);
cipher.OrganizationId = organizationId;
cipher.CollectionIds = collectionIds;
var encCipher = await EncryptAsync(cipher);
var request = new CipherShareRequest(encCipher);
var response = await _apiService.PutShareCipherAsync(cipher.Id, request);
var userId = await _stateService.GetActiveUserIdAsync();
var data = new CipherData(response, userId, collectionIds);
await UpsertAsync(data);
cipherView.OrganizationId = organizationId;
cipherView.CollectionIds = collectionIds;
await UpdateAndUpsertAsync(cipherView, cipher => _apiService.PutShareCipherAsync(cipherView.Id, new CipherShareRequest(cipher)), collectionIds);
async Task UpdateAndUpsertAsync(CipherView cipherView, Func<Cipher,Task<CipherResponse>> callPutCipherApi, HashSet<string> collectionIds = null)
{
var cipher = await EncryptAsync(cipherView);
var response = await callPutCipherApi(cipher);
var data = new CipherData(response, await _stateService.GetActiveUserIdAsync(), collectionIds);
await UpsertAsync(data);
}
}
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, CipherView cipherView, string filename, byte[] data)
@@ -838,6 +846,24 @@ namespace Bit.Core.Services
await ClearCacheAsync();
}
public async Task<bool> VerifyOrganizationHasUnassignedItemsAsync()
{
var organizations = await _stateService.GetOrganizationsAsync();
if (organizations?.Any() != true)
{
return false;
}
try
{
return await _apiService.HasUnassignedCiphersAsync();
}
catch (ApiException ex) when (ex.Error?.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
return false;
}
}
// Helpers
private async Task<Tuple<SymmetricCryptoKey, EncString, SymmetricCryptoKey>> MakeAttachmentKeyAsync(string organizationId, Cipher cipher = null, CipherView cipherView = null)

View File

@@ -1384,6 +1384,16 @@ namespace Bit.Core.Services
await _storageMediatorService.SaveAsync(Constants.RegionEnvironment, value);
}
public async Task<bool> GetShouldCheckOrganizationUnassignedItemsAsync(string userId = null)
{
return await _storageMediatorService.GetAsync<bool?>(await ComposeKeyAsync(Constants.ShouldCheckOrganizationUnassignedItemsKey, userId)) ?? true;
}
public async Task SetShouldCheckOrganizationUnassignedItemsAsync(bool shouldCheck, string userId = null)
{
await _storageMediatorService.SaveAsync<bool?>(await ComposeKeyAsync(Constants.ShouldCheckOrganizationUnassignedItemsKey, userId), shouldCheck);
}
// Helpers
[Obsolete("Use IStorageMediatorService instead")]

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.autofill</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.6.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleLocalizations</key>

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.find-login-action-extension</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.6.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>MinimumOSVersion</key>