Compare commits

..

24 Commits

Author SHA1 Message Date
Kyle Spearrin
b59433debd New Crowdin translations (#594)
* New translations copy.resx (Bulgarian)

* New translations copy.resx (Bulgarian)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (French)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Turkish)
2019-09-04 13:10:18 -04:00
Kyle Spearrin
fb2db9c652 version bump 2019-09-04 13:02:00 -04:00
Kyle Spearrin
2507f3301b device user agent 2019-09-04 11:52:32 -04:00
Kyle Spearrin
bdad5e4f0a fixes to opening file types on android 2019-08-30 16:43:58 -04:00
Kyle Spearrin
b5dcdc74d7 dark keyboard on dark themes. resolves #588 2019-08-28 20:27:15 -04:00
Kyle Spearrin
e2d1da02d3 more null checking on save 2019-08-27 15:03:33 -04:00
Kyle Spearrin
8253f18312 null check cipher service 2019-08-27 14:55:15 -04:00
kenjirooo
f4a98a2031 Added support for Sleipnir Mobile (https://play.google.com/store/apps/details?id=jp.co.fenrir.android.sleipnir). (#583) 2019-08-22 08:00:03 -04:00
Kyle Spearrin
224845cfd3 bump version 2019-08-12 09:41:12 -04:00
Kyle Spearrin
fc8c2ad67a add back references for autofill projects 2019-08-12 09:36:10 -04:00
Kyle Spearrin
c9d6f58563 delay for 1s on SyncIfNeeded 2019-08-12 09:35:18 -04:00
Kyle Spearrin
325b557506 null check on SyncIfNeeded 2019-08-12 08:51:49 -04:00
Kyle Spearrin
ce751cfc87 fix unlock logic 2019-08-12 08:05:45 -04:00
Kyle Spearrin
0f451fd4b9 set FingerprintUnlockKey before setKey 2019-08-10 00:19:01 -04:00
Kyle Spearrin
b7819838b8 parse fallback package id from first node title 2019-08-01 16:39:01 -04:00
Kyle Spearrin
67c6cf6b8c load previous view/edit page after lock 2019-07-31 16:50:16 -04:00
Kyle Spearrin
d91d71333b LastClipboardValue using static store rather than state 2019-07-31 11:21:07 -04:00
Kyle Spearrin
431804ea80 loop on reset with range instead of clear 2019-07-29 22:35:53 -04:00
Kyle Spearrin
7a7ab7bd0e New Crowdin translations (#570)
* New translations AppResources.resx (French)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Russian)
2019-07-29 15:15:21 -04:00
Kyle Spearrin
b8cdee383b bump version 2019-07-27 12:42:42 -04:00
Kyle Spearrin
580fa02ee1 enable event logging 2019-07-27 12:41:38 -04:00
Kyle Spearrin
421834153d catch InteractionNotAllowed 2019-07-27 12:39:59 -04:00
Kyle Spearrin
011f04e1dc editorconfig 2019-07-26 11:44:43 -04:00
Kyle Spearrin
3d8056704c yubikey token entry is password field 2019-07-25 16:10:46 -04:00
59 changed files with 742 additions and 371 deletions

View File

@@ -1,3 +1,112 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
# (Please don't specify an indent_size here; that has too many unintended consequences.)
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2
# Dotnet code style settings:
[*.{cs,vb}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Suggest more modern language features when available
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
# Prefix private members with underscore
dotnet_naming_rule.private_members_with_underscore.symbols = private_members
dotnet_naming_rule.private_members_with_underscore.style = underscore_prefix
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
dotnet_naming_symbols.private_members.applicable_kinds = field
dotnet_naming_symbols.private_members.applicable_accessibilities = private
dotnet_naming_symbols.private_members.required_modifiers = readonly
dotnet_naming_style.underscore_prefix.capitalization = camel_case
dotnet_naming_style.underscore_prefix.required_prefix = _
dotnet_naming_style.underscore_prefix.required_suffix =
dotnet_naming_style.underscore_prefix.word_separator =
# Async methods should have "Async" suffix
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion
dotnet_naming_symbols.any_async_methods.applicable_kinds = method
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = *
dotnet_naming_symbols.any_async_methods.required_modifiers = async
dotnet_naming_style.end_in_async.required_prefix =
dotnet_naming_style.end_in_async.required_suffix = Async
dotnet_naming_style.end_in_async.capitalization = pascal_case
dotnet_naming_style.end_in_async.word_separator =
# CSharp code style settings:
[*.cs]
# Prefer "var" everywhere
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
# Prefer method-like constructs to have a expression-body
csharp_style_expression_bodied_methods = true:none
csharp_style_expression_bodied_constructors = true:none
csharp_style_expression_bodied_operators = true:none
# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
# All files
[*]
guidelines = 120
guidelines = 120

View File

@@ -21,6 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E3996
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
appveyor.yml = appveyor.yml
CONTRIBUTING.md = CONTRIBUTING.md

View File

@@ -63,6 +63,9 @@ namespace Bit.Droid.Accessibility
new Browser("com.kiwibrowser.browser", "url_bar"),
new Browser("com.ecosia.android", "url_bar"),
new Browser("com.qwant.liberty", "url_bar_title"),
new Browser("jp.co.fenrir.android.sleipnir", "url_text"),
new Browser("jp.co.fenrir.android.sleipnir_black", "url_text"),
new Browser("jp.co.fenrir.android.sleipnir_test", "url_text"),
}.ToDictionary(n => n.PackageName);
// Known packages to skip

View File

@@ -145,6 +145,7 @@
<Compile Include="Utilities\AndroidHelpers.cs" />
<Compile Include="Utilities\CustomFingerprintDialogFragment.cs" />
<Compile Include="Utilities\HockeyAppCrashManagerListener.cs" />
<Compile Include="Utilities\StaticStore.cs" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\FontAwesome.ttf" />

View File

@@ -97,11 +97,20 @@ namespace Bit.Droid.Autofill
public void Parse()
{
string titlePackageId = null;
for(var i = 0; i < _structure.WindowNodeCount; i++)
{
var node = _structure.GetWindowNodeAt(i);
if(i == 0)
{
titlePackageId = GetTitlePackageId(node);
}
ParseNode(node.RootViewNode);
}
if(string.IsNullOrWhiteSpace(PackageName) && string.IsNullOrWhiteSpace(Website))
{
PackageName = titlePackageId;
}
if(!AutofillHelpers.TrustedBrowsers.Contains(PackageName) &&
!AutofillHelpers.CompatBrowsers.Contains(PackageName))
{
@@ -146,5 +155,22 @@ namespace Bit.Droid.Autofill
Website = string.Format("{0}://{1}", scheme, node.WebDomain);
}
}
private string GetTitlePackageId(WindowNode node)
{
if(node != null && !string.IsNullOrWhiteSpace(node.Title))
{
var slashPosition = node.Title.IndexOf('/');
if(slashPosition > -1)
{
var packageId = node.Title.Substring(0, slashPosition);
if(packageId.Contains("."))
{
return packageId;
}
}
}
return null;
}
}
}

View File

@@ -36,7 +36,6 @@ namespace Bit.Droid
private IUserService _userService;
private IAppIdService _appIdService;
private IStorageService _storageService;
private IStateService _stateService;
private IEventService _eventService;
private PendingIntent _lockAlarmPendingIntent;
private PendingIntent _clearClipboardPendingIntent;
@@ -67,7 +66,6 @@ namespace Bit.Droid
_userService = ServiceContainer.Resolve<IUserService>("userService");
_appIdService = ServiceContainer.Resolve<IAppIdService>("appIdService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
TabLayoutResource = Resource.Layout.Tabbar;
@@ -378,7 +376,7 @@ namespace Bit.Droid
{
return;
}
await _stateService.SaveAsync(Constants.LastClipboardValueKey, data.Item1);
StaticStore.LastClipboardValue = data.Item1;
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);

View File

@@ -40,7 +40,8 @@ namespace Bit.Droid
if(ServiceContainer.RegisteredServices.Count == 0)
{
RegisterLocalServices();
ServiceContainer.Init();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent);
if(App.Migration.MigrationHelpers.NeedsMigration())
{
var task = App.Migration.MigrationHelpers.PerformMigrationAsync();
@@ -155,4 +156,4 @@ namespace Bit.Droid
await ServiceContainer.Resolve<IEnvironmentService>("environmentService").SetUrlsFromStorageAsync();
}
}
}
}

View File

@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="1"
android:versionName="2.1.2"
android:versionName="2.2.2"
package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />

View File

@@ -2,22 +2,21 @@
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Bit.Droid.Utilities;
namespace Bit.Droid.Receivers
{
[BroadcastReceiver(Name = "com.x8bit.bitwarden.ClearClipboardAlarmReceiver", Exported = false)]
public class ClearClipboardAlarmReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
public override void OnReceive(Context context, Intent intent)
{
var stateService = ServiceContainer.Resolve<IStateService>("stateService");
var clipboardManager = context.GetSystemService(Context.ClipboardService) as ClipboardManager;
var lastClipboardValue = await stateService.GetAsync<string>(Constants.LastClipboardValueKey);
await stateService.RemoveAsync(Constants.LastClipboardValueKey);
if(lastClipboardValue == clipboardManager.Text)
if(StaticStore.LastClipboardValue != null && StaticStore.LastClipboardValue == clipboardManager.Text)
{
clipboardManager.Text = string.Empty;
}
StaticStore.LastClipboardValue = null;
}
}
}

View File

@@ -40,6 +40,7 @@ namespace Bit.Droid.Services
private ProgressDialog _progressDialog;
private bool _cameraPermissionsDenied;
private Toast _toast;
private string _userAgent;
public DeviceActionService(
IStorageService storageService,
@@ -61,6 +62,19 @@ namespace Bit.Droid.Services
});
}
public string DeviceUserAgent
{
get
{
if(string.IsNullOrWhiteSpace(_userAgent))
{
_userAgent = $"Bitwarden_Mobile/{Xamarin.Essentials.AppInfo.VersionString} " +
$"(Android {Build.VERSION.Release}; SDK {Build.VERSION.Sdk}; Model {Build.Model})";
}
return _userAgent;
}
}
public DeviceType DeviceType => DeviceType.Android;
public void Toast(string text, bool longDuration = false)
@@ -114,38 +128,14 @@ namespace Bit.Droid.Services
public bool OpenFile(byte[] fileData, string id, string fileName)
{
if(!CanOpenFile(fileName))
{
return false;
}
var extension = MimeTypeMap.GetFileExtensionFromUrl(fileName.Replace(' ', '_').ToLower());
if(extension == null)
{
return false;
}
var mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
if(mimeType == null)
{
return false;
}
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var cachePath = activity.CacheDir;
var filePath = Path.Combine(cachePath.Path, fileName);
File.WriteAllBytes(filePath, fileData);
var file = new Java.IO.File(cachePath, fileName);
if(!file.IsFile)
{
return false;
}
try
{
var intent = new Intent(Intent.ActionView);
var uri = FileProvider.GetUriForFile(activity.ApplicationContext,
"com.x8bit.bitwarden.fileprovider", file);
intent.SetDataAndType(uri, mimeType);
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var intent = BuildOpenFileIntent(fileData, fileName);
if(intent == null)
{
return false;
}
activity.StartActivity(intent);
return true;
}
@@ -154,22 +144,57 @@ namespace Bit.Droid.Services
}
public bool CanOpenFile(string fileName)
{
try
{
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var intent = BuildOpenFileIntent(new byte[0], string.Concat("opentest_", fileName));
if(intent == null)
{
return false;
}
var activities = activity.PackageManager.QueryIntentActivities(intent,
PackageInfoFlags.MatchDefaultOnly);
return (activities?.Count ?? 0) > 0;
}
catch { }
return false;
}
private Intent BuildOpenFileIntent(byte[] fileData, string fileName)
{
var extension = MimeTypeMap.GetFileExtensionFromUrl(fileName.Replace(' ', '_').ToLower());
if(extension == null)
{
return false;
return null;
}
var mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
if(mimeType == null)
{
return false;
return null;
}
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var intent = new Intent(Intent.ActionView);
intent.SetType(mimeType);
var activities = activity.PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
return (activities?.Count ?? 0) > 0;
var cachePath = activity.CacheDir;
var filePath = Path.Combine(cachePath.Path, fileName);
File.WriteAllBytes(filePath, fileData);
var file = new Java.IO.File(cachePath, fileName);
if(!file.IsFile)
{
return null;
}
try
{
var intent = new Intent(Intent.ActionView);
var uri = FileProvider.GetUriForFile(activity.ApplicationContext,
"com.x8bit.bitwarden.fileprovider", file);
intent.SetDataAndType(uri, mimeType);
intent.SetFlags(ActivityFlags.GrantReadUriPermission);
return intent;
}
catch { }
return null;
}
public async Task ClearCacheAsync()
@@ -185,7 +210,8 @@ namespace Bit.Droid.Services
public Task SelectFileAsync()
{
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var hasStorageWritePermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.WriteExternalStorage);
var hasStorageWritePermission = !_cameraPermissionsDenied &&
HasPermission(Manifest.Permission.WriteExternalStorage);
var additionalIntents = new List<IParcelable>();
if(activity.PackageManager.HasSystemFeature(PackageManager.FeatureCamera))
{
@@ -543,7 +569,8 @@ namespace Bit.Droid.Services
try
{
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
var afm = (AutofillManager)activity.GetSystemService(Java.Lang.Class.FromType(typeof(AutofillManager)));
var afm = (AutofillManager)activity.GetSystemService(
Java.Lang.Class.FromType(typeof(AutofillManager)));
return afm.IsEnabled && afm.HasEnabledAutofillServices;
}
catch
@@ -684,4 +711,4 @@ namespace Bit.Droid.Services
clipboardManager.Text = text;
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace Bit.Droid.Utilities
{
public static class StaticStore
{
public static string LastClipboardValue { get; set; }
}
}

View File

@@ -6,6 +6,7 @@ namespace Bit.App.Abstractions
{
public interface IDeviceActionService
{
string DeviceUserAgent { get; }
DeviceType DeviceType { get; }
void Toast(string text, bool longDuration = false);
bool LaunchApp(string appName);

View File

@@ -89,18 +89,7 @@ namespace Bit.App
}
else if(message.Command == "locked")
{
await _stateService.PurgeAsync();
var autoPromptFingerprint = !(message.Data as bool?).GetValueOrDefault();
if(autoPromptFingerprint && Device.RuntimePlatform == Device.iOS)
{
var lockOptions = await _storageService.GetAsync<int?>(Constants.LockOptionKey);
if(lockOptions == 0)
{
autoPromptFingerprint = false;
}
}
var lockPage = new LockPage(_appOptions, autoPromptFingerprint);
Device.BeginInvokeOnMainThread(() => Current.MainPage = new NavigationPage(lockPage));
await LockedAsync(!(message.Data as bool?).GetValueOrDefault());
}
else if(message.Command == "lockVault")
{
@@ -378,8 +367,9 @@ namespace Bit.App
Task.Run(async () =>
{
var lastSync = await _syncService.GetLastSyncAsync();
if(DateTime.UtcNow - lastSync > TimeSpan.FromMinutes(30))
if(lastSync == null || ((DateTime.UtcNow - lastSync) > TimeSpan.FromMinutes(30)))
{
await Task.Delay(1000);
await _syncService.FullSyncAsync(false);
}
});
@@ -398,5 +388,45 @@ namespace Bit.App
await _storageService.RemoveAsync(Constants.ClearCiphersCacheKey);
}
}
private async Task LockedAsync(bool autoPromptFingerprint)
{
await _stateService.PurgeAsync();
if(autoPromptFingerprint && Device.RuntimePlatform == Device.iOS)
{
var lockOptions = await _storageService.GetAsync<int?>(Constants.LockOptionKey);
if(lockOptions == 0)
{
autoPromptFingerprint = false;
}
}
PreviousPageInfo lastPageBeforeLock = null;
if(Current.MainPage is TabbedPage tabbedPage && tabbedPage.Navigation.ModalStack.Count > 0)
{
var topPage = tabbedPage.Navigation.ModalStack[tabbedPage.Navigation.ModalStack.Count - 1];
if(topPage is NavigationPage navPage)
{
if(navPage.CurrentPage is ViewPage viewPage)
{
lastPageBeforeLock = new PreviousPageInfo
{
Page = "view",
CipherId = viewPage.ViewModel.CipherId
};
}
else if(navPage.CurrentPage is AddEditPage addEditPage && addEditPage.ViewModel.EditMode)
{
lastPageBeforeLock = new PreviousPageInfo
{
Page = "edit",
CipherId = addEditPage.ViewModel.CipherId
};
}
}
}
await _storageService.SaveAsync(Constants.PreviousPageKey, lastPageBeforeLock);
var lockPage = new LockPage(_appOptions, autoPromptFingerprint);
Device.BeginInvokeOnMainThread(() => Current.MainPage = new NavigationPage(lockPage));
}
}
}

View File

@@ -160,6 +160,12 @@ namespace Bit.App.Migration
await tokenService.SetTokensAsync(oldToken, oldRefreshToken);
await userService.SetInformationAsync(oldUserId, oldEmail, oldKdf, oldKdfIterations);
// Save fingerprint
if(oldFingerprint)
{
await storageService.SaveAsync(Constants.FingerprintUnlockKey, true);
}
var newKey = new Core.Models.Domain.SymmetricCryptoKey(oldKey.Key);
await cryptoService.SetKeyAsync(newKey);
// Key hash is unavailable in old version, store old key until we can move it to key hash
@@ -167,13 +173,8 @@ namespace Bit.App.Migration
await cryptoService.SetEncKeyAsync(oldEncKey);
await cryptoService.SetEncPrivateKeyAsync(oldEncPrivateKey);
// Save fingerprint/pin
if(oldFingerprint)
{
await storageService.SaveAsync(Constants.FingerprintUnlockKey, true);
}
else if(!string.IsNullOrWhiteSpace(oldPin))
// Save pin
if(!oldFingerprint && !string.IsNullOrWhiteSpace(oldPin))
{
var pinKey = await cryptoService.MakePinKeyAysnc(oldPin, oldEmail, oldKdf, oldKdfIterations);
var pinProtectedKey = await cryptoService.EncryptAsync(oldKeyBytes, pinKey);

View File

@@ -0,0 +1,9 @@
namespace Bit.App.Models
{
public class PreviousPageInfo
{
public string Page { get; set; }
public string CipherId { get; set; }
public string SearchText { get; set; }
}
}

View File

@@ -1,4 +1,7 @@
using Bit.App.Models;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
@@ -7,6 +10,7 @@ namespace Bit.App.Pages
{
public partial class LockPage : BaseContentPage
{
private readonly IStorageService _storageService;
private readonly AppOptions _appOptions;
private readonly bool _autoPromptFingerprint;
private readonly LockPageViewModel _vm;
@@ -16,28 +20,13 @@ namespace Bit.App.Pages
public LockPage(AppOptions appOptions = null, bool autoPromptFingerprint = true)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_appOptions = appOptions;
_autoPromptFingerprint = autoPromptFingerprint;
InitializeComponent();
_vm = BindingContext as LockPageViewModel;
_vm.Page = this;
_vm.UnlockedAction = () => Device.BeginInvokeOnMainThread(() =>
{
if(_appOptions != null)
{
if(_appOptions.FromAutofillFramework && _appOptions.SaveType.HasValue)
{
Application.Current.MainPage = new NavigationPage(new AddEditPage(appOptions: _appOptions));
return;
}
else if(_appOptions.Uri != null)
{
Application.Current.MainPage = new NavigationPage(new AutofillCiphersPage(_appOptions));
return;
}
}
Application.Current.MainPage = new TabsPage(_appOptions);
});
_vm.UnlockedAction = () => Device.BeginInvokeOnMainThread(async () => await UnlockedAsync());
MasterPasswordEntry = _masterPassword;
PinEntry = _pin;
}
@@ -107,5 +96,28 @@ namespace Bit.App.Pages
await _vm.PromptFingerprintAsync();
}
}
private async Task UnlockedAsync()
{
if(_appOptions != null)
{
if(_appOptions.FromAutofillFramework && _appOptions.SaveType.HasValue)
{
Application.Current.MainPage = new NavigationPage(new AddEditPage(appOptions: _appOptions));
return;
}
else if(_appOptions.Uri != null)
{
Application.Current.MainPage = new NavigationPage(new AutofillCiphersPage(_appOptions));
return;
}
}
var previousPage = await _storageService.GetAsync<PreviousPageInfo>(Constants.PreviousPageKey);
if(previousPage != null)
{
await _storageService.RemoveAsync(Constants.PreviousPageKey);
}
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
}
}
}

View File

@@ -287,6 +287,8 @@ namespace Bit.App.Pages
private async Task DoContinueAsync()
{
_lockService.PinLocked = false;
_lockService.FingerprintLocked = false;
var disableFavicon = await _storageService.GetAsync<bool?>(Constants.DisableFaviconKey);
await _stateService.SaveAsync(Constants.DisableFaviconKey, disableFavicon.GetValueOrDefault());
_messagingService.Send("unlocked");

View File

@@ -76,6 +76,9 @@
x:Name="_yubikeyTokenEntry"
Text="{Binding Token}"
StyleClass="box-value"
IsPassword="True"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
ReturnType="Go"
ReturnCommand="{Binding SubmitCommand}" />
</StackLayout>

View File

@@ -10,9 +10,9 @@ namespace Bit.App.Pages
private NavigationPage _groupingsPage;
private NavigationPage _generatorPage;
public TabsPage(AppOptions appOptions = null)
public TabsPage(AppOptions appOptions = null, PreviousPageInfo previousPage = null)
{
_groupingsPage = new NavigationPage(new GroupingsPage(true))
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
{
Title = AppResources.MyVault,
Icon = "lock.png"

View File

@@ -131,6 +131,7 @@ namespace Bit.App.Pages
}
public bool FromAutofillFramework { get; set; }
public AddEditPageViewModel ViewModel => _vm;
protected override async void OnAppearing()
{

View File

@@ -401,12 +401,13 @@ namespace Bit.App.Pages
return false;
}
Cipher.Fields = Fields != null && Fields.Any() ? Fields.Select(f => f.Field).ToList() : null;
Cipher.Fields = Fields != null && Fields.Any() ?
Fields.Where(f => f != null).Select(f => f.Field).ToList() : null;
if(Cipher.Login != null)
{
Cipher.Login.Uris = Uris?.ToList();
if(!EditMode && Cipher.Type == CipherType.Login && (Cipher.Login.Uris?.Count ?? 0) == 1 &&
string.IsNullOrWhiteSpace(Cipher.Login.Uris.First().Uri))
string.IsNullOrWhiteSpace(Cipher.Login.Uris.First()?.Uri))
{
Cipher.Login.Uris = null;
}
@@ -414,7 +415,7 @@ namespace Bit.App.Pages
if(!EditMode && Cipher.OrganizationId != null)
{
if(!Collections?.Any(c => c.Checked) ?? true)
if(!Collections?.Any(c => c?.Checked ?? false) ?? true)
{
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.SelectOneCollection,
AppResources.Ok);
@@ -422,7 +423,8 @@ namespace Bit.App.Pages
}
Cipher.CollectionIds = Collections.Any() ?
new HashSet<string>(Collections.Where(c => c.Checked).Select(c => c.Collection.Id)) : null;
new HashSet<string>(Collections.Where(c => c?.Checked ?? false &&
c.Collection != null).Select(c => c.Collection.Id)) : null;
}
var cipher = await _cipherService.EncryptAsync(Cipher);

View File

@@ -1,5 +1,6 @@
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions;
@@ -22,8 +23,10 @@ namespace Bit.App.Pages
private readonly GroupingsPageViewModel _vm;
private readonly string _pageName;
private PreviousPageInfo _previousPage;
public GroupingsPage(bool mainPage, CipherType? type = null, string folderId = null,
string collectionId = null, string pageTitle = null)
string collectionId = null, string pageTitle = null, PreviousPageInfo previousPage = null)
{
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
InitializeComponent();
@@ -41,6 +44,7 @@ namespace Bit.App.Pages
_vm.Type = type;
_vm.FolderId = folderId;
_vm.CollectionId = collectionId;
_previousPage = previousPage;
if(pageTitle != null)
{
_vm.PageTitle = pageTitle;
@@ -125,6 +129,7 @@ namespace Bit.App.Pages
await _syncService.FullSyncAsync(true);
}
}
await ShowPreviousPageAsync();
}, _mainContent);
if(!_vm.MainPage)
@@ -244,5 +249,22 @@ namespace Bit.App.Pages
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
private async Task ShowPreviousPageAsync()
{
if(_previousPage == null)
{
return;
}
if(_previousPage.Page == "view" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
{
await Navigation.PushModalAsync(new NavigationPage(new ViewPage(_previousPage.CipherId)));
}
else if(_previousPage.Page == "edit" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
{
await Navigation.PushModalAsync(new NavigationPage(new AddEditPage(_previousPage.CipherId)));
}
_previousPage = null;
}
}
}

View File

@@ -39,6 +39,8 @@ namespace Bit.App.Pages
}
}
public ViewPageViewModel ViewModel => _vm;
protected override async void OnAppearing()
{
base.OnAppearing();

View File

@@ -753,7 +753,7 @@
<value>Status</value>
</data>
<data name="BitwardenAutofillServiceAlert2" xml:space="preserve">
<value>Die einfachste Möglichkeit, neue Anmeldedaten zu Ihrem Tresor hinzuzufügen, ist der automatische Fülldienst von Bitwarden. Erfahren Sie mehr über den automatische Fülldienst von Bitwarden, indem Sie zu dem "Einstellungen"-Bildschirm navigieren.</value>
<value>Die einfachste Möglichkeit, neue Anmeldedaten zu Ihrem Tresor hinzuzufügen, ist der automatische Fülldienst von Bitwarden. Erfahren Sie mehr über den automatischen Fülldienst von Bitwarden, indem Sie zu dem "Einstellungen"-Bildschirm navigieren.</value>
</data>
<data name="Autofill" xml:space="preserve">
<value>Auto-Ausfüllen</value>
@@ -1302,7 +1302,7 @@
<value>Passwort AutoFill</value>
</data>
<data name="BitwardenAutofillAlert2" xml:space="preserve">
<value>Die einfachste Möglichkeit, neue Anmeldedaten zu Ihrem Tresor hinzuzufügen, ist die Bitwardenerweiterung zum Automatische Füllen. Erfahren Sie mehr über die Bitwardenerweiterung zum Automatische Füllen, indem Sie zu dem "Einstellungen"-Bildschirm navigieren.</value>
<value>Die einfachste Möglichkeit, neue Anmeldedaten zu Ihrem Tresor hinzuzufügen, ist der automatische Fülldienst von Bitwarden. Erfahren Sie mehr über den automatischen Fülldienst von Bitwarden, indem Sie zu dem "Einstellungen"-Bildschirm navigieren.</value>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>Ungültige E-Mail-Adresse.</value>
@@ -1376,16 +1376,16 @@
<value>Nach oben bewegen</value>
</data>
<data name="Miscellaneous" xml:space="preserve">
<value>Verschiedenes</value>
<value>Sonstiges</value>
</data>
<data name="Ownership" xml:space="preserve">
<value>Besitzer</value>
<value>Besitz</value>
</data>
<data name="WhoOwnsThisItem" xml:space="preserve">
<value>Wer besitzt diesen Eintrag?</value>
</data>
<data name="NoCollectionsToList" xml:space="preserve">
<value>Keine Sammlungen zum Auflisten.</value>
<value>Keine Sammlungen vorhanden.</value>
</data>
<data name="ItemShared" xml:space="preserve">
<value>Eintrag wurde geteilt.</value>
@@ -1400,7 +1400,7 @@
<value>Eintrag teilen</value>
</data>
<data name="NoOrgsToList" xml:space="preserve">
<value>Keine Organisationen zum Auflisten.</value>
<value>Keine Organisationen vorhanden.</value>
</data>
<data name="ShareDesc" xml:space="preserve">
<value>Wählen Sie eine Organisation, mit der Sie dieses Eintrag teilen möchten. Teilen überträgt den Besitz des Eintrages an die Organisation. Sie werden nicht mehr der direkte Bestitzer dieses Eintrages sein, sobald es geteilt wurde.</value>
@@ -1564,7 +1564,7 @@
<comment>ex. Uppercase the first character of a word.</comment>
</data>
<data name="IncludeNumber" xml:space="preserve">
<value>Zahl hinzufügen</value>
<value>Ziffer hinzufügen</value>
</data>
<data name="Download" xml:space="preserve">
<value>Herunterladen</value>

View File

@@ -406,7 +406,7 @@
<value>سرویس پر کردن خودکار</value>
</data>
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
<value>از تکرار کاراکترهای یک شکل اجتناب کن</value>
<value>از کاراکترهای مبهم اجتناب شود</value>
</data>
<data name="BitwardenAppExtension" xml:space="preserve">
<value>افزونه اپلیکیشن Bitwarden</value>
@@ -783,7 +783,7 @@
<value>اسکن زمانی که در فیلد پسورد متمرکز شده</value>
</data>
<data name="AutofillPasswordFieldDescription" xml:space="preserve">
<value>فقط صفحه را برای فیلدها و پیشنهاد دادن پر کردن خودکار اسکن میکند هر حتی اگر شما یک فیلد رمز عبور را انتخاب کرده باشید. این تنظیم به افزایش عمر باتری کمک میکند.</value>
<value>فقط زمانی که شما یک فیلد رمز عبور را انتخاب کنید صفحه را برای فیلدها و اعلانیه پیشنهاد پر کردن خودکار اسکن میکند. این تنظیم به افزایش عمر باتری کمک میکند.</value>
</data>
<data name="AutofillPersistNotification" xml:space="preserve">
<value>اطلاعیه ثابت</value>

View File

@@ -1275,19 +1275,19 @@
<value>Your logins are now easily accessable right from your keyboard while logging into apps and websites.</value>
</data>
<data name="AutofillSetup2" xml:space="preserve">
<value>We recommend disabling any other AutoFill apps under Settings if you do not plan to use them.</value>
<value>Suosittelemme poistamaan muut AutoFill-sovellukset käytöstä asetuksista, jos et aio käyttää niitä.</value>
</data>
<data name="BitwardenAutofillDescription" xml:space="preserve">
<value>Access your vault directly from your keyboard to quickly autofill passwords.</value>
<value>Käytä holviasi suoraan näppäimistöltä täyttääksesi salasanat automaattisesti.</value>
</data>
<data name="AutofillTurnOn" xml:space="preserve">
<value>To enable password autofill on your device, follow these instructions:</value>
<value>Ota salasanojen automattinen täyttäminen käyttöön seuraavasti:</value>
</data>
<data name="AutofillTurnOn1" xml:space="preserve">
<value>1. Siirry iOS:n Asetukset-sovellukseen</value>
</data>
<data name="AutofillTurnOn2" xml:space="preserve">
<value>2. Tap "Passwords &amp; Accounts"</value>
<value>2. Napauta "Salasanat ja tilit"</value>
</data>
<data name="AutofillTurnOn3" xml:space="preserve">
<value>3. Tap "AutoFill Passwords"</value>
@@ -1557,20 +1557,20 @@
<value>Automaattinen täyttö tekee Bitwarden-holviiisi pääsystä muista ohjelmista ja sivustoista helppoa. Et näytä kytkeneen automaattista täyttöä päälle. Voit tehdä sen Asetukset-näytöstä.</value>
</data>
<data name="ThemeAppliedOnRestart" xml:space="preserve">
<value>Your theme changes will apply when the app is restarted.</value>
<value>Teemamuutokset tulevat voimaan, kun sovellus käynnistetään uudelleen.</value>
</data>
<data name="Capitalize" xml:space="preserve">
<value>Capitalize</value>
<value>Jokainen sana isolla alkukirjaimella</value>
<comment>ex. Uppercase the first character of a word.</comment>
</data>
<data name="IncludeNumber" xml:space="preserve">
<value>Include Number</value>
<value>Sisällytä numero</value>
</data>
<data name="Download" xml:space="preserve">
<value>Download</value>
<value>Lataa</value>
</data>
<data name="Shared" xml:space="preserve">
<value>Shared</value>
<value>Jaettu</value>
</data>
<data name="ToggleVisibility" xml:space="preserve">
<value>Toggle Visiblity</value>

View File

@@ -222,7 +222,7 @@
<value>Dossier supprimé.</value>
</data>
<data name="FolderNone" xml:space="preserve">
<value>Pas de dossier</value>
<value>Aucun dossier</value>
<comment>Items that have no folder specified go in this special "catch-all" folder.</comment>
</data>
<data name="Folders" xml:space="preserve">
@@ -356,7 +356,7 @@
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
</data>
<data name="ValueHasBeenCopied" xml:space="preserve">
<value>{0} a été copié.</value>
<value>{0} a été copié(e).</value>
<comment>Confirmation message after suceessfully copying a value to the clipboard.</comment>
</data>
<data name="VerifyFingerprint" xml:space="preserve">
@@ -1548,7 +1548,7 @@
<value>Désactiver la demande d'enregistrement</value>
</data>
<data name="DisableSavePromptDescription" xml:space="preserve">
<value>La "Demande d'enregistrement" vous invite automatiquement à enregistrer de nouveaux éléments dans votre coffre-fort à chaque fois que vous les entrez pour la première fois.</value>
<value>La "Demande d'enregistrement" vous invite automatiquement à enregistrer de nouveaux éléments dans votre coffre à chaque fois que vous les entrez pour la première fois.</value>
</data>
<data name="LockOptionOnRestart" xml:space="preserve">
<value>Au redémarrage de l'application</value>

View File

@@ -1305,237 +1305,237 @@
<value>The easiest way to add new logins to your vault is by using the Bitwarden Password AutoFill extension. Learn more about using the Bitwarden Password AutoFill extension by navigating to the "Settings" screen.</value>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>Invalid email address.</value>
<value>Érvénytelen e-mail cím.</value>
</data>
<data name="Cards" xml:space="preserve">
<value>Cards</value>
<value>Kártyák</value>
</data>
<data name="Identities" xml:space="preserve">
<value>Identities</value>
<value>Azonosságok</value>
</data>
<data name="Logins" xml:space="preserve">
<value>Logins</value>
<value>Bejelentkezések</value>
</data>
<data name="SecureNotes" xml:space="preserve">
<value>Secure Notes</value>
<value>Biztonságos jegyzetek</value>
</data>
<data name="AllItems" xml:space="preserve">
<value>All Items</value>
<value>Összes elem</value>
</data>
<data name="URIs" xml:space="preserve">
<value>URIs</value>
<value>URI-k</value>
<comment>Plural form of a URI</comment>
</data>
<data name="CheckingPassword" xml:space="preserve">
<value>Checking password...</value>
<value>Jelszó ellenőrzése...</value>
<comment>A loading message when doing an exposed password check.</comment>
</data>
<data name="CheckPassword" xml:space="preserve">
<value>Check if password has been exposed.</value>
<value>Ellenőrizd, hogy kompromittálódott-e a jelszó.</value>
</data>
<data name="PasswordExposed" xml:space="preserve">
<value>This password has been exposed {0} time(s) in data breaches. You should change it.</value>
<value>Ez a jelszó {0} alkalommal kompromittálódott adatszivárgásban. Változtasd meg!</value>
</data>
<data name="PasswordSafe" xml:space="preserve">
<value>This password was not found in any known data breaches. It should be safe to use.</value>
<value>Ez a jelszó nem érintett egyetlen ismert adatszivárgásban sem. Biztonságos a használata.</value>
</data>
<data name="IdentityName" xml:space="preserve">
<value>Identity Name</value>
<value>Identitásnév</value>
</data>
<data name="Value" xml:space="preserve">
<value>Value</value>
<value>Érték</value>
</data>
<data name="PasswordHistory" xml:space="preserve">
<value>Password History</value>
<value>Jelszó előzmények</value>
</data>
<data name="Types" xml:space="preserve">
<value>Types</value>
<value>Típusok</value>
</data>
<data name="NoPasswordsToList" xml:space="preserve">
<value>No passwords to list.</value>
<value>Nincs megjeleníthető jelszó.</value>
</data>
<data name="NoItemsToList" xml:space="preserve">
<value>There are no items to list.</value>
<value>Nincsenek megjeleníthető tételek.</value>
</data>
<data name="SearchCollection" xml:space="preserve">
<value>Search collection</value>
<value>Gyűjtemény keresése</value>
</data>
<data name="SearchFolder" xml:space="preserve">
<value>Search folder</value>
<value>Mappa keresése</value>
</data>
<data name="SearchType" xml:space="preserve">
<value>Search type</value>
<value>Típus keresése</value>
</data>
<data name="Type" xml:space="preserve">
<value>Type</value>
<value>Típus</value>
</data>
<data name="MoveDown" xml:space="preserve">
<value>Move Down</value>
<value>Lefelé mozgatás</value>
</data>
<data name="MoveUp" xml:space="preserve">
<value>Move Up</value>
<value>Mozgatás felfelé</value>
</data>
<data name="Miscellaneous" xml:space="preserve">
<value>Miscellaneous</value>
<value>Egyebek</value>
</data>
<data name="Ownership" xml:space="preserve">
<value>Ownership</value>
<value>Tulajdonjog</value>
</data>
<data name="WhoOwnsThisItem" xml:space="preserve">
<value>Who owns this item?</value>
<value>Kié ez a tétel?</value>
</data>
<data name="NoCollectionsToList" xml:space="preserve">
<value>There are no collections to list.</value>
<value>Nincsenek megjeleníthető gyűjtemények.</value>
</data>
<data name="ItemShared" xml:space="preserve">
<value>Item has been shared.</value>
<value>Elem meg lett osztva.</value>
</data>
<data name="SelectOneCollection" xml:space="preserve">
<value>You must select at least one collection.</value>
<value>Legalább egy gyűjteményt ki kell választanod.</value>
</data>
<data name="Share" xml:space="preserve">
<value>Share</value>
<value>Megosztás</value>
</data>
<data name="ShareItem" xml:space="preserve">
<value>Share Item</value>
<value>Elem megosztása</value>
</data>
<data name="NoOrgsToList" xml:space="preserve">
<value>No organizations to list.</value>
<value>Nincs megjeleníthető szervezet.</value>
</data>
<data name="ShareDesc" xml:space="preserve">
<value>Choose an organization that you wish to share this item with. Sharing transfers ownership of the item to the organization. You will no longer be the direct owner of this item once it has been shared.</value>
</data>
<data name="NumberOfWords" xml:space="preserve">
<value>Number of Words</value>
<value>Szavak száma</value>
</data>
<data name="Passphrase" xml:space="preserve">
<value>Passphrase</value>
<value>Kulcsszó</value>
</data>
<data name="WordSeparator" xml:space="preserve">
<value>Word Separator</value>
<value>Szó elválasztó</value>
</data>
<data name="Clear" xml:space="preserve">
<value>Clear</value>
<value>Töröl</value>
<comment>To clear something out. example: To clear browser history.</comment>
</data>
<data name="Generator" xml:space="preserve">
<value>Generator</value>
<value>Generátor</value>
<comment>Short for "Password Generator"</comment>
</data>
<data name="NoFoldersToList" xml:space="preserve">
<value>There are no folders to list.</value>
<value>Nincsenek megjeleníthető mappák.</value>
</data>
<data name="FingerprintPhrase" xml:space="preserve">
<value>Fingerprint Phrase</value>
<value>Ujjlenyomat mondat</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="YourAccountsFingerprint" xml:space="preserve">
<value>Your account's fingerprint phrase</value>
<value>A fiókod ujjlenyomat mondata</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="ShareVaultConfirmation" xml:space="preserve">
<value>Bitwarden allows you to share your vault with others by using an organization account. Would you like to visit the bitwarden.com website to learn more?</value>
<value>Bitwarden lehetővé teszi egy szervezeti fiók használatával a fiók megosztását másokkal. Szeretnél többet megtudni a bitwarden.com weboldalon?</value>
</data>
<data name="ExportVault" xml:space="preserve">
<value>Export Vault</value>
<value>Széf exportálása</value>
</data>
<data name="LockNow" xml:space="preserve">
<value>Lock Now</value>
<value>Zárolás most</value>
</data>
<data name="PIN" xml:space="preserve">
<value>PIN</value>
</data>
<data name="Unlock" xml:space="preserve">
<value>Unlock</value>
<value>Feloldás</value>
</data>
<data name="LockOption30Minutes" xml:space="preserve">
<value>30 minutes</value>
<value>30 perc</value>
</data>
<data name="LockOption5Minutes" xml:space="preserve">
<value>5 minutes</value>
<value>5 perc</value>
</data>
<data name="SetPINDescription" xml:space="preserve">
<value>Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</value>
</data>
<data name="LoggedInAsOn" xml:space="preserve">
<value>Logged in as {0} on {1}.</value>
<value>Bejelentkezve, mint {0} - {1}.</value>
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
</data>
<data name="VaultLockedMasterPassword" xml:space="preserve">
<value>Your vault is locked. Verify your master password to continue.</value>
<value>A széfed zárolva van. A folytatáshoz add meg a mesterjelszót.</value>
</data>
<data name="VaultLockedPIN" xml:space="preserve">
<value>Your vault is locked. Verify your PIN code to continue.</value>
<value>A széfed zárolva van. A folytatáshoz add meg a PIN kódot.</value>
</data>
<data name="Dark" xml:space="preserve">
<value>Dark</value>
<value>Sötét</value>
<comment>A dark color</comment>
</data>
<data name="Light" xml:space="preserve">
<value>Light</value>
<value>Világos</value>
<comment>A light color</comment>
</data>
<data name="FiveMinutes" xml:space="preserve">
<value>5 minutes</value>
<value>5 perc</value>
</data>
<data name="OneMinute" xml:space="preserve">
<value>1 minute</value>
<value>1 perc</value>
</data>
<data name="TenSeconds" xml:space="preserve">
<value>10 seconds</value>
<value>10 másodperc</value>
</data>
<data name="ThirtySeconds" xml:space="preserve">
<value>30 seconds</value>
<value>30 másodperc</value>
</data>
<data name="TwentySeconds" xml:space="preserve">
<value>20 seconds</value>
<value>20 másodperc</value>
</data>
<data name="TwoMinutes" xml:space="preserve">
<value>2 minutes</value>
<value>2 perc</value>
</data>
<data name="ClearClipboard" xml:space="preserve">
<value>Clear Clipboard</value>
<value>Vágólap ürítése</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="ClearClipboardDescription" xml:space="preserve">
<value>Automatically clear copied values from your clipboard.</value>
<value>Automatikusan törli a vágólapra másolt értékeket.</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="DefaultUriMatchDetection" xml:space="preserve">
<value>Default URI Match Detection</value>
<value>Alapértelmezett találatfelismerés</value>
<comment>Default URI match detection for auto-fill.</comment>
</data>
<data name="DefaultUriMatchDetectionDescription" xml:space="preserve">
<value>Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill.</value>
</data>
<data name="Theme" xml:space="preserve">
<value>Theme</value>
<value>Téma</value>
<comment>Color theme</comment>
</data>
<data name="ThemeDescription" xml:space="preserve">
<value>Change the application's color theme.</value>
<value>Az alkalmazás színének megváltoztatása.</value>
</data>
<data name="RestartIsRequired" xml:space="preserve">
<value>Restart is required.</value>
<value>Újraindítás szükséges.</value>
<comment>Referring to restarting the application.</comment>
</data>
<data name="Restarting" xml:space="preserve">
<value>Restarting...</value>
<value>Újraindítás...</value>
</data>
<data name="CopyNotes" xml:space="preserve">
<value>Copy Notes</value>
<value>Jegyzetek másolása</value>
</data>
<data name="Exit" xml:space="preserve">
<value>Exit</value>
<value>Kilépés</value>
</data>
<data name="ExitConfirmation" xml:space="preserve">
<value>Are you sure you want to exit Bitwarden?</value>
<value>Biztos vagy benne, hogy kilépsz?</value>
</data>
<data name="PINRequireMasterPasswordRestart" xml:space="preserve">
<value>You you want to require unlocking with your master password when the application is restarted?</value>
</data>
<data name="Black" xml:space="preserve">
<value>Black</value>
<value>Fekete</value>
<comment>The color black</comment>
</data>
<data name="BlacklistedUris" xml:space="preserve">
@@ -1551,7 +1551,7 @@
<value>The "Save Prompt" automatically prompts you to save new items to your vault whenever you enter them for the first time.</value>
</data>
<data name="LockOptionOnRestart" xml:space="preserve">
<value>On App Restart</value>
<value>Újraindításkor</value>
</data>
<data name="AutofillServiceNotEnabled" xml:space="preserve">
<value>Auto-fill makes it easy to securely access your Bitwarden vault from other websites and apps. It looks like you have not enabled an auto-fill service for Bitwarden. Enable auto-fill for Bitwarden from the "Settings" screen.</value>
@@ -1560,17 +1560,17 @@
<value>Your theme changes will apply when the app is restarted.</value>
</data>
<data name="Capitalize" xml:space="preserve">
<value>Capitalize</value>
<value>Nagy kezdőbetű</value>
<comment>ex. Uppercase the first character of a word.</comment>
</data>
<data name="IncludeNumber" xml:space="preserve">
<value>Include Number</value>
<value>Tartalmazzon számot</value>
</data>
<data name="Download" xml:space="preserve">
<value>Download</value>
<value>Letöltés</value>
</data>
<data name="Shared" xml:space="preserve">
<value>Shared</value>
<value>Megosztott</value>
</data>
<data name="ToggleVisibility" xml:space="preserve">
<value>Toggle Visiblity</value>

View File

@@ -412,7 +412,7 @@
<value>Bitwarden App Extension</value>
</data>
<data name="BitwardenAppExtensionAlert2" xml:space="preserve">
<value>Bitwarden App Extension から新しいログイン情報を保管庫に追加するのが一番簡単です。設定画面で App Extension の詳細を確認できます。</value>
<value>ログイン情報を保管庫に追加する一番簡単な方法はApp Extensionを使うことです。詳しくは「設定」画面に進んでください。</value>
</data>
<data name="BitwardenAppExtensionDescription" xml:space="preserve">
<value>Safari などのアプリで Bitwarden を使ってログイン情報を自動入力します。</value>
@@ -753,7 +753,7 @@
<value>状態</value>
</data>
<data name="BitwardenAutofillServiceAlert2" xml:space="preserve">
<value>Bitwarden 自動入力サービスから新しいログイン情報を保管庫に追加するのが一番簡単です。設定画面で自動入力サービスの詳細を確認できます。</value>
<value>ログイン情報を保管庫に追加する一番簡単な方法はBitwardenの自動入力機能を使うことです。詳しくは「設定画面に進んでください。</value>
</data>
<data name="Autofill" xml:space="preserve">
<value>自動入力</value>
@@ -1302,7 +1302,7 @@
<value>パスワード自動入力</value>
</data>
<data name="BitwardenAutofillAlert2" xml:space="preserve">
<value>Bitwarden パスワード自動入力拡張機能を使うと、簡単に新しいログイン情報を保管庫に追加できます。設定画面で詳しい使い方をご覧ください。</value>
<value>ログイン情報を保管庫に加える一番簡単な方法は、Bitwardenパスワード自動入力拡張機能を使うことです。詳しい情報は「設定画面でご覧ください。</value>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>無効なメールアドレスです。</value>
@@ -1317,7 +1317,7 @@
<value>ログイン</value>
</data>
<data name="SecureNotes" xml:space="preserve">
<value>セキュアメモ</value>
<value>秘密のメモ</value>
</data>
<data name="AllItems" xml:space="preserve">
<value>すべてのアイテム</value>
@@ -1334,10 +1334,10 @@
<value>パスワードが漏洩していないか確認する</value>
</data>
<data name="PasswordExposed" xml:space="preserve">
<value>このパスワードは過去に {0} 回漏洩したことがあるため、変更するべきです。</value>
<value>このパスワードは過去に {0} 回漏洩しています。変更するべきです。</value>
</data>
<data name="PasswordSafe" xml:space="preserve">
<value>このパスワードは過去に漏洩したデータにはないため、安全であると思われます。</value>
<value>このパスワードは過去に漏洩したデータにはありません。安全だと思われます。</value>
</data>
<data name="IdentityName" xml:space="preserve">
<value>固有名</value>
@@ -1364,7 +1364,7 @@
<value>フォルダーの検索</value>
</data>
<data name="SearchType" xml:space="preserve">
<value>検索の種類</value>
<value>タイプの検索</value>
</data>
<data name="Type" xml:space="preserve">
<value>タイプ</value>
@@ -1391,7 +1391,7 @@
<value>アイテムを共有しました。</value>
</data>
<data name="SelectOneCollection" xml:space="preserve">
<value>最低でも一つのコレクションを選んでください。</value>
<value>コレクションを最低1つは選んでください。</value>
</data>
<data name="Share" xml:space="preserve">
<value>共有</value>
@@ -1419,18 +1419,18 @@
<comment>To clear something out. example: To clear browser history.</comment>
</data>
<data name="Generator" xml:space="preserve">
<value>ジェネレーター</value>
<value>パスワード生成</value>
<comment>Short for "Password Generator"</comment>
</data>
<data name="NoFoldersToList" xml:space="preserve">
<value>表示するフォルダーがありません。</value>
</data>
<data name="FingerprintPhrase" xml:space="preserve">
<value>パスフレーズ</value>
<value>指紋句</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="YourAccountsFingerprint" xml:space="preserve">
<value>アカウントのパスフレーズ</value>
<value>アカウントの指紋句</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="ShareVaultConfirmation" xml:space="preserve">
@@ -1498,7 +1498,7 @@
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="ClearClipboardDescription" xml:space="preserve">
<value>選択した時間が経過した後、自動的にクリップボード消去します。</value>
<value>コピー内容をクリップボードから自動的に消去します。</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="DefaultUriMatchDetection" xml:space="preserve">
@@ -1506,7 +1506,7 @@
<comment>Default URI match detection for auto-fill.</comment>
</data>
<data name="DefaultUriMatchDetectionDescription" xml:space="preserve">
<value>自動入力などのアクションをする時に、デフォルトでどの方法で URI一致検出するか選択します。</value>
<value>自動入力などを行うときにデフォルトで使うURI一致検出方法を選択します。</value>
</data>
<data name="Theme" xml:space="preserve">
<value>テーマ</value>
@@ -1542,19 +1542,19 @@
<value>URI ブラックリスト</value>
</data>
<data name="BlacklistedUrisDescription" xml:space="preserve">
<value>URIs that are blacklisted will not offer auto-fill. The list of apps should be comma separated. Ex: "https://twitter.com, androidapp://com.twitter.android".</value>
<value>ブラックリストに入れたURIでは自動入力を行いません。リストはコンマで区切ってください。"https://twitter.com, androidapp://com.twitter.android"</value>
</data>
<data name="DisableSavePrompt" xml:space="preserve">
<value>保存プロンプトを無効化</value>
</data>
<data name="DisableSavePromptDescription" xml:space="preserve">
<value>保存プロンプトは、新しいアイテム入力したときに保管庫に保存するかどうか尋ねるため、自動的に表示されます。</value>
<value>保存プロンプトは、新しいアイテム入力された場合に自動的に表示され、保管庫に保存するよう促します。</value>
</data>
<data name="LockOptionOnRestart" xml:space="preserve">
<value>アプリ再起動時</value>
</data>
<data name="AutofillServiceNotEnabled" xml:space="preserve">
<value>自動入力を使うと、他のウェブサイトやアプリから Bitwarden 保管庫に、より安全・簡単にアクセスできます。現在 Bitwarden の自動入力サービスを有効にていないようです。設定画面で自動入力を有効化できます。</value>
<value>自動入力を使えば、他のウェブサイトやアプリから Bitwarden保管庫に簡単に安全にアクセスできます。いまのところ自動入力は有効になっていないようです。自動入力を有効にするには設定画面に行ってください。</value>
</data>
<data name="ThemeAppliedOnRestart" xml:space="preserve">
<value>アプリを再起動するとテーマの変更が反映されます。</value>

View File

@@ -1557,20 +1557,20 @@
<value>Auto-utfylling gjør det lett å få sikker tilgang til Bitwarden-hvelvet ditt fra andre nettsteder og apper. Det ser ut til at du ikke har skrudd på noen auto-utfyllingstjenester for Bitwarden. Du kan skru på auto-utfylling for Bitwarden i «Innstillinger»-menyen.</value>
</data>
<data name="ThemeAppliedOnRestart" xml:space="preserve">
<value>Your theme changes will apply when the app is restarted.</value>
<value>Temaendringene dine vil gjelde når appen startes på nytt.</value>
</data>
<data name="Capitalize" xml:space="preserve">
<value>Capitalize</value>
<value>Stor forbokstav</value>
<comment>ex. Uppercase the first character of a word.</comment>
</data>
<data name="IncludeNumber" xml:space="preserve">
<value>Include Number</value>
<value>Inkluder nummer</value>
</data>
<data name="Download" xml:space="preserve">
<value>Download</value>
<value>Last ned</value>
</data>
<data name="Shared" xml:space="preserve">
<value>Shared</value>
<value>Delt</value>
</data>
<data name="ToggleVisibility" xml:space="preserve">
<value>Toggle Visiblity</value>

View File

@@ -356,7 +356,7 @@
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
</data>
<data name="ValueHasBeenCopied" xml:space="preserve">
<value>{0} foi copiado.</value>
<value>{0} foi copiado(a).</value>
<comment>Confirmation message after suceessfully copying a value to the clipboard.</comment>
</data>
<data name="VerifyFingerprint" xml:space="preserve">

View File

@@ -412,7 +412,7 @@
<value>Extensia aplicaţiei Bitwarden</value>
</data>
<data name="BitwardenAppExtensionAlert2" xml:space="preserve">
<value>The easiest way to add new logins to your vault is from the Bitwarden App Extension. Learn more about using the Bitwarden App Extension by navigating to the "Settings" screen.</value>
<value>Cea mai ușoară modalitate de a adăuga noi autentificări în seif este din extensia aplicaţiei Bitwarden. Aflați mai multe despre utilizarea extensiei aplicaţiei Bitwarden accesând ecranul "Setări".</value>
</data>
<data name="BitwardenAppExtensionDescription" xml:space="preserve">
<value>Utilizați Bitwarden în Safari și în alte aplicații pentru a completa automat datele de autentificare.</value>
@@ -753,7 +753,7 @@
<value>Stare</value>
</data>
<data name="BitwardenAutofillServiceAlert2" xml:space="preserve">
<value>The easiest way to add new logins to your vault is from the Bitwarden Auto-fill Service. Learn more about using the Bitwarden Auto-fill Service by navigating to the "Settings" screen.</value>
<value>Cea mai ușoară modalitate de a adăuga noi autentificări în seif este din Serviciul de completare automată Bitwarden. Aflați mai multe despre utilizarea Serviciului de completare automată Bitwarden accesând ecranul "Setări".</value>
</data>
<data name="Autofill" xml:space="preserve">
<value>Completare automată</value>
@@ -1302,120 +1302,120 @@
<value>Auto Completare Parolă</value>
</data>
<data name="BitwardenAutofillAlert2" xml:space="preserve">
<value>The easiest way to add new logins to your vault is by using the Bitwarden Password AutoFill extension. Learn more about using the Bitwarden Password AutoFill extension by navigating to the "Settings" screen.</value>
<value>Cea mai ușoară modalitate de a adăuga noi autentificări în seif este din extensia aplicaţiei Bitwarden. Aflați mai multe despre utilizarea extensiei aplicaţiei Bitwarden accesând ecranul "Setări".</value>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>Invalid email address.</value>
<value>Adresă de email greșită.</value>
</data>
<data name="Cards" xml:space="preserve">
<value>Cards</value>
<value>Carduri</value>
</data>
<data name="Identities" xml:space="preserve">
<value>Identities</value>
<value>Identități</value>
</data>
<data name="Logins" xml:space="preserve">
<value>Logins</value>
<value>Autentificări</value>
</data>
<data name="SecureNotes" xml:space="preserve">
<value>Secure Notes</value>
<value>Notițe securizate</value>
</data>
<data name="AllItems" xml:space="preserve">
<value>All Items</value>
<value>Toate elementele</value>
</data>
<data name="URIs" xml:space="preserve">
<value>URIs</value>
<value>URI-uri</value>
<comment>Plural form of a URI</comment>
</data>
<data name="CheckingPassword" xml:space="preserve">
<value>Checking password...</value>
<value>Verificare parolă...</value>
<comment>A loading message when doing an exposed password check.</comment>
</data>
<data name="CheckPassword" xml:space="preserve">
<value>Check if password has been exposed.</value>
<value>Verificare dacă parola a fost dezvăluită.</value>
</data>
<data name="PasswordExposed" xml:space="preserve">
<value>This password has been exposed {0} time(s) in data breaches. You should change it.</value>
<value>Această parolă a fost dezvăluită de {0} ori într-o breșă de date. Ar trebui să o schimbați.</value>
</data>
<data name="PasswordSafe" xml:space="preserve">
<value>This password was not found in any known data breaches. It should be safe to use.</value>
<value>Aceasta parola nu a fost găsită în nicio breșă de date cunoscută. Ar trebui să fie sigură pentru a fi utilizată.</value>
</data>
<data name="IdentityName" xml:space="preserve">
<value>Identity Name</value>
<value>Numele Identității</value>
</data>
<data name="Value" xml:space="preserve">
<value>Value</value>
<value>Valoare</value>
</data>
<data name="PasswordHistory" xml:space="preserve">
<value>Password History</value>
<value>Istoric parole</value>
</data>
<data name="Types" xml:space="preserve">
<value>Types</value>
<value>Tipuri</value>
</data>
<data name="NoPasswordsToList" xml:space="preserve">
<value>No passwords to list.</value>
<value>Nicio parolă.</value>
</data>
<data name="NoItemsToList" xml:space="preserve">
<value>There are no items to list.</value>
<value>Nu există niciun articol de afișat.</value>
</data>
<data name="SearchCollection" xml:space="preserve">
<value>Search collection</value>
<value>Căutare colecție</value>
</data>
<data name="SearchFolder" xml:space="preserve">
<value>Search folder</value>
<value>Căutare dosar</value>
</data>
<data name="SearchType" xml:space="preserve">
<value>Search type</value>
<value>Tipul de căutare</value>
</data>
<data name="Type" xml:space="preserve">
<value>Type</value>
<value>Tip</value>
</data>
<data name="MoveDown" xml:space="preserve">
<value>Move Down</value>
<value>Mută în jos</value>
</data>
<data name="MoveUp" xml:space="preserve">
<value>Move Up</value>
<value>Mută în sus</value>
</data>
<data name="Miscellaneous" xml:space="preserve">
<value>Miscellaneous</value>
<value>Diverse</value>
</data>
<data name="Ownership" xml:space="preserve">
<value>Ownership</value>
<value>Proprietate</value>
</data>
<data name="WhoOwnsThisItem" xml:space="preserve">
<value>Who owns this item?</value>
<value>Cine deține acest element?</value>
</data>
<data name="NoCollectionsToList" xml:space="preserve">
<value>There are no collections to list.</value>
<value>Nu există colecții în listă.</value>
</data>
<data name="ItemShared" xml:space="preserve">
<value>Item has been shared.</value>
<value>Articolul a fost distribuit.</value>
</data>
<data name="SelectOneCollection" xml:space="preserve">
<value>You must select at least one collection.</value>
<value>Este nevoie să alegeți măcar o colecție.</value>
</data>
<data name="Share" xml:space="preserve">
<value>Share</value>
<value>Distribuire</value>
</data>
<data name="ShareItem" xml:space="preserve">
<value>Share Item</value>
<value>Distribuie element</value>
</data>
<data name="NoOrgsToList" xml:space="preserve">
<value>No organizations to list.</value>
<value>Nu există organizații care să fie afișate.</value>
</data>
<data name="ShareDesc" xml:space="preserve">
<value>Choose an organization that you wish to share this item with. Sharing transfers ownership of the item to the organization. You will no longer be the direct owner of this item once it has been shared.</value>
<value>Alegeți o organizație căreia doriți să îi distribuiți acest element. Distribuirea transferă proprietatea asupra obiectului către organizație. Nu veți mai fi proprietarul direct al acestui element odată ce a fost distribuit.</value>
</data>
<data name="NumberOfWords" xml:space="preserve">
<value>Number of Words</value>
<value>Număr de cuvinte</value>
</data>
<data name="Passphrase" xml:space="preserve">
<value>Passphrase</value>
<value>Frază de acces</value>
</data>
<data name="WordSeparator" xml:space="preserve">
<value>Word Separator</value>
<value>Separator cuvânt</value>
</data>
<data name="Clear" xml:space="preserve">
<value>Clear</value>
<value>Ştergere</value>
<comment>To clear something out. example: To clear browser history.</comment>
</data>
<data name="Generator" xml:space="preserve">
@@ -1423,154 +1423,154 @@
<comment>Short for "Password Generator"</comment>
</data>
<data name="NoFoldersToList" xml:space="preserve">
<value>There are no folders to list.</value>
<value>Nu există dosare de afișat.</value>
</data>
<data name="FingerprintPhrase" xml:space="preserve">
<value>Fingerprint Phrase</value>
<value>Frază amprentă</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="YourAccountsFingerprint" xml:space="preserve">
<value>Your account's fingerprint phrase</value>
<value>Fraza amprentă a contului</value>
<comment>A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing.</comment>
</data>
<data name="ShareVaultConfirmation" xml:space="preserve">
<value>Bitwarden allows you to share your vault with others by using an organization account. Would you like to visit the bitwarden.com website to learn more?</value>
<value>Bitwarden vă permite să vă împărtășiți seiful cu alte persoane utilizând un cont pentru organizații. Doriți să vizitați site-ul bitwarden.com pentru a afla mai multe?</value>
</data>
<data name="ExportVault" xml:space="preserve">
<value>Export Vault</value>
<value>Export seif</value>
</data>
<data name="LockNow" xml:space="preserve">
<value>Lock Now</value>
<value>Blocați acum</value>
</data>
<data name="PIN" xml:space="preserve">
<value>PIN</value>
</data>
<data name="Unlock" xml:space="preserve">
<value>Unlock</value>
<value>Deblocare</value>
</data>
<data name="LockOption30Minutes" xml:space="preserve">
<value>30 minutes</value>
<value>30 de minute</value>
</data>
<data name="LockOption5Minutes" xml:space="preserve">
<value>5 minutes</value>
<value>5 minute</value>
</data>
<data name="SetPINDescription" xml:space="preserve">
<value>Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</value>
<value>Setaţi codul PIN de deblocare Bitwarden. Setările codului PIN vor fi resetate dacă vă deconectaţi vreodată din aplicație.</value>
</data>
<data name="LoggedInAsOn" xml:space="preserve">
<value>Logged in as {0} on {1}.</value>
<value>Autentificat ca {0} în {1}.</value>
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
</data>
<data name="VaultLockedMasterPassword" xml:space="preserve">
<value>Your vault is locked. Verify your master password to continue.</value>
<value>Seiful dvs. este blocat. Verificaţi parola principală pentru a continua.</value>
</data>
<data name="VaultLockedPIN" xml:space="preserve">
<value>Your vault is locked. Verify your PIN code to continue.</value>
<value>Seiful dvs. este blocat. Verificaţi codul PIN pentru a continua.</value>
</data>
<data name="Dark" xml:space="preserve">
<value>Dark</value>
<value>Întunecată</value>
<comment>A dark color</comment>
</data>
<data name="Light" xml:space="preserve">
<value>Light</value>
<value>Luminoasă</value>
<comment>A light color</comment>
</data>
<data name="FiveMinutes" xml:space="preserve">
<value>5 minutes</value>
<value>5 minute</value>
</data>
<data name="OneMinute" xml:space="preserve">
<value>1 minute</value>
<value>1 minut</value>
</data>
<data name="TenSeconds" xml:space="preserve">
<value>10 seconds</value>
<value>10 secunde</value>
</data>
<data name="ThirtySeconds" xml:space="preserve">
<value>30 seconds</value>
<value>30 de secunde</value>
</data>
<data name="TwentySeconds" xml:space="preserve">
<value>20 seconds</value>
<value>20 de secunde</value>
</data>
<data name="TwoMinutes" xml:space="preserve">
<value>2 minutes</value>
<value>2 minute</value>
</data>
<data name="ClearClipboard" xml:space="preserve">
<value>Clear Clipboard</value>
<value>Goliţi Clipboardul</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="ClearClipboardDescription" xml:space="preserve">
<value>Automatically clear copied values from your clipboard.</value>
<value>Şterge automat valorile copiate din clipboard.</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="DefaultUriMatchDetection" xml:space="preserve">
<value>Default URI Match Detection</value>
<value>Detectare de potrivire URI implicită</value>
<comment>Default URI match detection for auto-fill.</comment>
</data>
<data name="DefaultUriMatchDetectionDescription" xml:space="preserve">
<value>Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill.</value>
<value>Alege modul în care se gestionează detectarea de potrivire de URI pentru autentificări la acțiuni precum cea de auto-completare.</value>
</data>
<data name="Theme" xml:space="preserve">
<value>Theme</value>
<value>Temă</value>
<comment>Color theme</comment>
</data>
<data name="ThemeDescription" xml:space="preserve">
<value>Change the application's color theme.</value>
<value>Schimbă tema de culori a aplicației.</value>
</data>
<data name="RestartIsRequired" xml:space="preserve">
<value>Restart is required.</value>
<value>Repornire necesară.</value>
<comment>Referring to restarting the application.</comment>
</data>
<data name="Restarting" xml:space="preserve">
<value>Restarting...</value>
<value>Repornire...</value>
</data>
<data name="CopyNotes" xml:space="preserve">
<value>Copy Notes</value>
<value>Copiere note</value>
</data>
<data name="Exit" xml:space="preserve">
<value>Exit</value>
<value>Ieșire</value>
</data>
<data name="ExitConfirmation" xml:space="preserve">
<value>Are you sure you want to exit Bitwarden?</value>
<value>Sunteți sigur că doriți să ieșiți?</value>
</data>
<data name="PINRequireMasterPasswordRestart" xml:space="preserve">
<value>You you want to require unlocking with your master password when the application is restarted?</value>
</data>
<data name="Black" xml:space="preserve">
<value>Black</value>
<value>Neagră</value>
<comment>The color black</comment>
</data>
<data name="BlacklistedUris" xml:space="preserve">
<value>Blacklisted URIs</value>
<value>URI-uri în lista neagră</value>
</data>
<data name="BlacklistedUrisDescription" xml:space="preserve">
<value>URIs that are blacklisted will not offer auto-fill. The list of apps should be comma separated. Ex: "https://twitter.com, androidapp://com.twitter.android".</value>
</data>
<data name="DisableSavePrompt" xml:space="preserve">
<value>Disable Save Prompt</value>
<value>Dezactivați solicitarea de salvare</value>
</data>
<data name="DisableSavePromptDescription" xml:space="preserve">
<value>The "Save Prompt" automatically prompts you to save new items to your vault whenever you enter them for the first time.</value>
<value>"Notificarea de salvare" solicită automat salvarea de noi elemente în seiful dvs. de fiecare dată când le introduceți pentru prima dată.</value>
</data>
<data name="LockOptionOnRestart" xml:space="preserve">
<value>On App Restart</value>
<value>La repornirea aplicației</value>
</data>
<data name="AutofillServiceNotEnabled" xml:space="preserve">
<value>Auto-fill makes it easy to securely access your Bitwarden vault from other websites and apps. It looks like you have not enabled an auto-fill service for Bitwarden. Enable auto-fill for Bitwarden from the "Settings" screen.</value>
<value>Completarea automată simplifică accesarea securizată a seifului Bitwarden de pe alte site-uri web și aplicații. Se pare că nu ați activat un serviciu de completare automată pentru Bitwarden. Activați completarea automată pentru Bitwarden din ecranul „Setări”.</value>
</data>
<data name="ThemeAppliedOnRestart" xml:space="preserve">
<value>Your theme changes will apply when the app is restarted.</value>
<value>Modificările temei se vor aplica după repornirea aplicației.</value>
</data>
<data name="Capitalize" xml:space="preserve">
<value>Capitalize</value>
<value>Majuscule</value>
<comment>ex. Uppercase the first character of a word.</comment>
</data>
<data name="IncludeNumber" xml:space="preserve">
<value>Include Number</value>
<value>Include număr</value>
</data>
<data name="Download" xml:space="preserve">
<value>Download</value>
<value>Descărcare</value>
</data>
<data name="Shared" xml:space="preserve">
<value>Shared</value>
<value>Distribuit</value>
</data>
<data name="ToggleVisibility" xml:space="preserve">
<value>Toggle Visiblity</value>

View File

@@ -356,7 +356,7 @@
<comment>Validation message for when a form field is left blank and is required to be entered.</comment>
</data>
<data name="ValueHasBeenCopied" xml:space="preserve">
<value>{0} скопирован(о).</value>
<value>{0} скопирован(-о).</value>
<comment>Confirmation message after suceessfully copying a value to the clipboard.</comment>
</data>
<data name="VerifyFingerprint" xml:space="preserve">
@@ -534,7 +534,7 @@
<value>Немедленно</value>
</data>
<data name="LockOptions" xml:space="preserve">
<value>Настройки блокировки</value>
<value>Параметры блокировки</value>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Вход...</value>
@@ -874,7 +874,7 @@
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Ключ аутентификатора (TOTP)</value>
<value>Ключ проверки подлинности (TOTP)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Код подтверждения (TOTP)</value>
@@ -905,7 +905,7 @@
<value>Копировать TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>Если к вашему логину прикреплен ключ аутентификации, то код подтверждения TOTP будет скопирован при автозаполнении логина.</value>
<value>Если к вашему логину прикреплен ключ проверки подлинности, то код подтверждения TOTP будет скопирован при автозаполнении логина.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Отключить копирование TOTP</value>
@@ -1334,7 +1334,7 @@
<value>Проверьте, не скомпрометирован ли пароль.</value>
</data>
<data name="PasswordExposed" xml:space="preserve">
<value>Этот пароль был найден в базах утечек {0} раз(а). Вы должны изменить его.</value>
<value>Этот пароль был найден в базах утечек {0} раз(-а). Вы должны изменить его.</value>
</data>
<data name="PasswordSafe" xml:space="preserve">
<value>Этот пароль не был найден в известных базах утечек. Можно продолжать его использовать.</value>
@@ -1458,7 +1458,7 @@
<value>Установите PIN-код для разблокировки Bitwarden. Настройки PIN-кода будут сброшены, если вы когда-либо полностью выйдете из приложения.</value>
</data>
<data name="LoggedInAsOn" xml:space="preserve">
<value>Вы вошли как {0} на {1}.</value>
<value>Выполнен вход на {1} как {0}.</value>
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
</data>
<data name="VaultLockedMasterPassword" xml:space="preserve">

View File

@@ -1340,13 +1340,13 @@
<value>This password was not found in any known data breaches. It should be safe to use.</value>
</data>
<data name="IdentityName" xml:space="preserve">
<value>Identity Name</value>
<value>Kimlik Adı</value>
</data>
<data name="Value" xml:space="preserve">
<value>Değer</value>
</data>
<data name="PasswordHistory" xml:space="preserve">
<value>Password History</value>
<value>Parola Geçmişi</value>
</data>
<data name="Types" xml:space="preserve">
<value>Types</value>
@@ -1358,7 +1358,7 @@
<value>There are no items to list.</value>
</data>
<data name="SearchCollection" xml:space="preserve">
<value>Search collection</value>
<value>Koleksiyon ara</value>
</data>
<data name="SearchFolder" xml:space="preserve">
<value>Search folder</value>

View File

@@ -24,7 +24,6 @@
public static string PushInitialPromptShownKey = "pushInitialPromptShown";
public static string ThemeKey = "theme";
public static string ClearClipboardKey = "clearClipboard";
public static string LastClipboardValueKey = "lastClipboardValue";
public static string LastBuildKey = "lastBuild";
public static string OldUserIdKey = "userId";
public static string AddSitePromptShownKey = "addSitePromptShown";
@@ -33,6 +32,7 @@
public static string MigratedFromV1AutofillPromptShown = "migratedV1AutofillPromptShown";
public static string TriedV1Resync = "triedV1Resync";
public static string EventCollectionKey = "eventCollection";
public static string PreviousPageKey = "previousPage";
public const int SelectFileRequestCode = 42;
public const int SelectFilePermissionRequestCode = 43;
}

View File

@@ -25,18 +25,22 @@ namespace Bit.Core.Services
private readonly ITokenService _tokenService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly Func<bool, Task> _logoutCallbackAsync;
private string _deviceType;
public ApiService(
ITokenService tokenService,
IPlatformUtilsService platformUtilsService,
Func<bool, Task> logoutCallbackAsync)
Func<bool, Task> logoutCallbackAsync,
string customUserAgent = null)
{
_tokenService = tokenService;
_platformUtilsService = platformUtilsService;
_logoutCallbackAsync = logoutCallbackAsync;
var device = _platformUtilsService.GetDevice();
_deviceType = device.ToString();
_httpClient.DefaultRequestHeaders.Add("Device-Type", device.ToString());
if(!string.IsNullOrWhiteSpace(customUserAgent))
{
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(customUserAgent);
}
}
public bool UrlsSet { get; private set; }
@@ -86,7 +90,6 @@ namespace Bit.Core.Services
Content = new FormUrlEncodedContent(request.ToIdentityToken(_platformUtilsService.IdentityClientId))
};
requestMessage.Headers.Add("Accept", "application/json");
requestMessage.Headers.Add("Device-Type", _deviceType);
HttpResponseMessage response;
try
@@ -304,7 +307,6 @@ namespace Bit.Core.Services
{
requestMessage.Method = HttpMethod.Post;
requestMessage.RequestUri = new Uri(string.Concat(EventsBaseUrl, "/collect"));
requestMessage.Headers.Add("Device-Type", _deviceType);
var authHeader = await GetActiveBearerTokenAsync();
requestMessage.Headers.Add("Authorization", string.Concat("Bearer ", authHeader));
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(request, _jsonSettings),
@@ -377,7 +379,6 @@ namespace Bit.Core.Services
}
}
requestMessage.Headers.Add("Device-Type", _deviceType);
if(authed)
{
var authHeader = await GetActiveBearerTokenAsync();
@@ -432,7 +433,6 @@ namespace Bit.Core.Services
})
};
requestMessage.Headers.Add("Accept", "application/json");
requestMessage.Headers.Add("Device-Type", _deviceType);
HttpResponseMessage response;
try

View File

@@ -31,8 +31,6 @@ namespace Bit.Core.Services
public async Task CollectAsync(EventType eventType, string cipherId = null, bool uploadImmediately = false)
{
return;
// TODO
var authed = await _userService.IsAuthenticatedAsync();
if(!authed)
{
@@ -76,8 +74,6 @@ namespace Bit.Core.Services
public async Task UploadEventsAsync()
{
return;
// TODO
var authed = await _userService.IsAuthenticatedAsync();
if(!authed)
{

View File

@@ -30,7 +30,16 @@ namespace Bit.Core.Utilities
public void ResetWithRange(IEnumerable<T> range)
{
Items.Clear();
// Maybe a fix for https://forums.xamarin.com/discussion/19114/invalid-number-of-rows-in-section
// Items.Clear();
if(Items.Count > 0)
{
var count = Items.Count;
for(var i = 0; i < count; i++)
{
Items.RemoveAt(0);
}
}
AddRange(range);
}
}

View File

@@ -11,7 +11,7 @@ namespace Bit.Core.Utilities
public static Dictionary<string, object> RegisteredServices { get; set; } = new Dictionary<string, object>();
public static bool Inited { get; set; }
public static void Init()
public static void Init(string customUserAgent = null)
{
if(Inited)
{
@@ -31,7 +31,8 @@ namespace Bit.Core.Utilities
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(storageService, secureStorageService, cryptoFunctionService);
var tokenService = new TokenService(storageService);
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) => Task.FromResult(0));
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) => Task.FromResult(0),
customUserAgent);
var appIdService = new AppIdService(storageService);
var userService = new UserService(storageService, tokenService);
var settingsService = new SettingsService(userService, storageService);

View File

@@ -1,4 +1,5 @@
using AuthenticationServices;
using AuthenticationServices;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
@@ -191,8 +192,8 @@ namespace Bit.iOS.Autofill
private async Task ProvideCredentialAsync()
{
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
var cipher = await cipherService.GetAsync(_context.CredentialIdentity.RecordIdentifier);
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService", true);
var cipher = await cipherService?.GetAsync(_context.CredentialIdentity.RecordIdentifier);
if(cipher == null || cipher.Type != Bit.Core.Enums.CipherType.Login)
{
var err = new NSError(new NSString("ASExtensionErrorDomain"),
@@ -265,7 +266,8 @@ namespace Bit.iOS.Autofill
ServiceContainer.Reset();
}
iOSCoreHelpers.RegisterLocalServices();
ServiceContainer.Init();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent);
if(!_initedHockeyApp)
{
iOSCoreHelpers.RegisterHockeyApp();
@@ -283,4 +285,4 @@ namespace Bit.iOS.Autofill
}
}
}
}
}

View File

@@ -11,9 +11,9 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.autofill</string>
<key>CFBundleShortVersionString</key>
<string>2.1.2</string>
<string>2.2.2</string>
<key>CFBundleVersion</key>
<string>53</string>
<string>56</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Bit.iOS.Autofill.Models;
using Foundation;
using UIKit;
@@ -27,6 +27,10 @@ namespace Bit.iOS.Autofill
CancelBarButton.Title = AppResources.Cancel;
SearchBar.Placeholder = AppResources.Search;
SearchBar.BackgroundColor = SearchBar.BarTintColor = ThemeHelpers.ListHeaderBackgroundColor;
if(!ThemeHelpers.LightTheme)
{
SearchBar.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 44;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using UIKit;
using Foundation;
using Bit.iOS.Core.Views;
@@ -194,6 +194,8 @@ namespace Bit.iOS.Core.Controllers
private void DoContinue()
{
_lockService.PinLocked = false;
_lockService.FingerprintLocked = false;
MasterPasswordCell.TextField.ResignFirstResponder();
Success();
}

View File

@@ -8,6 +8,7 @@ using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.iOS.Core.Utilities;
using Bit.iOS.Core.Views;
using CoreGraphics;
using Foundation;
@@ -25,6 +26,7 @@ namespace Bit.iOS.Core.Services
private readonly IMessagingService _messagingService;
private Toast _toast;
private UIAlertController _progressAlert;
private string _userAgent;
public DeviceActionService(
IStorageService storageService,
@@ -34,6 +36,19 @@ namespace Bit.iOS.Core.Services
_messagingService = messagingService;
}
public string DeviceUserAgent
{
get
{
if(string.IsNullOrWhiteSpace(_userAgent))
{
_userAgent = $"Bitwarden_Mobile/{Xamarin.Essentials.AppInfo.VersionString} " +
$"(iOS {UIDevice.CurrentDevice.SystemVersion}; Model {UIDevice.CurrentDevice.Model})";
}
return _userAgent;
}
}
public DeviceType DeviceType => DeviceType.iOS;
public bool LaunchApp(string appName)
@@ -203,6 +218,10 @@ namespace Bit.iOS.Core.Services
{
input.KeyboardType = UIKeyboardType.NumberPad;
}
if(!ThemeHelpers.LightTheme)
{
input.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
});
var vc = GetPresentedViewController();
vc?.PresentViewController(alert, true, null);
@@ -256,7 +275,7 @@ namespace Bit.iOS.Core.Services
public int SystemMajorVersion()
{
var versionParts = UIDevice.CurrentDevice.SystemVersion.Split('.');
if(versionParts.Length > 0 && int.TryParse(versionParts[0], out int version))
if(versionParts.Length > 0 && int.TryParse(versionParts[0], out var version))
{
return version;
}
@@ -469,4 +488,4 @@ namespace Bit.iOS.Core.Services
}
}
}
}
}

View File

@@ -34,9 +34,9 @@ namespace Bit.iOS.Core.Services
var formattedKey = string.Format(_keyFormat, appId, key);
byte[] dataBytes = null;
using(var existingRecord = GetKeyRecord(formattedKey))
using(var record = SecKeyChain.QueryAsRecord(existingRecord, out SecStatusCode resultCode))
using(var record = SecKeyChain.QueryAsRecord(existingRecord, out var resultCode))
{
if(resultCode == SecStatusCode.ItemNotFound)
if(resultCode == SecStatusCode.ItemNotFound || resultCode == SecStatusCode.InteractionNotAllowed)
{
return (T)(object)null;
}
@@ -116,7 +116,7 @@ namespace Bit.iOS.Core.Services
private SecRecord GetExistingRecord(string key)
{
var existingRecord = GetKeyRecord(key);
SecKeyChain.QueryAsRecord(existingRecord, out SecStatusCode resultCode);
SecKeyChain.QueryAsRecord(existingRecord, out var resultCode);
return resultCode == SecStatusCode.Success ? existingRecord : null;
}

View File

@@ -41,6 +41,11 @@ namespace Bit.iOS.Core.Views
BackgroundColor = ThemeHelpers.BackgroundColor
};
if(!ThemeHelpers.LightTheme)
{
TextView.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
ContentView.Add(TextView);
ContentView.AddConstraints(new NSLayoutConstraint[] {
NSLayoutConstraint.Create(TextView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, 15f),
@@ -78,6 +83,11 @@ namespace Bit.iOS.Core.Views
BackgroundColor = ThemeHelpers.BackgroundColor
};
if(!ThemeHelpers.LightTheme)
{
TextField.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
if(useLabelAsPlaceholder)
{
TextField.Placeholder = labelName;

View File

@@ -41,6 +41,11 @@ namespace Bit.iOS.Core.Views
BackgroundColor = ThemeHelpers.BackgroundColor
};
if(!ThemeHelpers.LightTheme)
{
TextField.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
var width = (float)UIScreen.MainScreen.Bounds.Width;
var toolbar = new UIToolbar(new RectangleF(0, 0, width, 44))
{

View File

@@ -11,9 +11,9 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.find-login-action-extension</string>
<key>CFBundleShortVersionString</key>
<string>2.1.2</string>
<string>2.2.2</string>
<key>CFBundleVersion</key>
<string>53</string>
<string>56</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using Foundation;
using UIKit;
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using Bit.iOS.Core.Models;
using Bit.Core.Utilities;
using Bit.Core.Abstractions;
using Bit.App.Abstractions;
namespace Bit.iOS.Extension
{
@@ -386,7 +387,8 @@ namespace Bit.iOS.Extension
ServiceContainer.Reset();
}
iOSCoreHelpers.RegisterLocalServices();
ServiceContainer.Init();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent);
if(!_initedHockeyApp)
{
iOSCoreHelpers.RegisterHockeyApp();
@@ -408,4 +410,4 @@ namespace Bit.iOS.Extension
return userService.IsAuthenticatedAsync().GetAwaiter().GetResult();
}
}
}
}

View File

@@ -287,7 +287,8 @@ namespace Bit.iOS
iOSCoreHelpers.RegisterLocalServices();
RegisterPush();
ServiceContainer.Init();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent);
iOSCoreHelpers.RegisterHockeyApp();
_pushHandler = new iOSPushNotificationHandler(
ServiceContainer.Resolve<IPushNotificationListenerService>("pushNotificationListenerService"));

View File

@@ -11,9 +11,9 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string>
<key>CFBundleShortVersionString</key>
<string>2.1.2</string>
<string>2.2.2</string>
<key>CFBundleVersion</key>
<string>53</string>
<string>56</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleURLTypes</key>

View File

@@ -20,6 +20,7 @@ namespace Bit.iOS.Renderers
Control.TextContainerInset = new UIEdgeInsets(0, 0, 0, 0);
Control.TextContainer.LineFragmentPadding = 0;
UpdateTintColor();
UpdateKeyboardAppearance();
}
}
@@ -36,5 +37,13 @@ namespace Bit.iOS.Renderers
{
Control.TintColor = Element.TextColor.ToUIColor();
}
private void UpdateKeyboardAppearance()
{
if(!Core.Utilities.ThemeHelpers.LightTheme)
{
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
}
}
}

View File

@@ -18,6 +18,7 @@ namespace Bit.iOS.Renderers
Control.ClearButtonMode = UITextFieldViewMode.WhileEditing;
UpdateTintColor();
UpdateFontSize();
UpdateKeyboardAppearance();
iOSHelpers.SetBottomBorder(Control);
}
}
@@ -57,5 +58,13 @@ namespace Bit.iOS.Renderers
{
Control.TintColor = Element.TextColor.ToUIColor();
}
private void UpdateKeyboardAppearance()
{
if(!Core.Utilities.ThemeHelpers.LightTheme)
{
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
}
}
}

View File

@@ -17,6 +17,15 @@ namespace Bit.iOS.Renderers
var descriptor = UIFontDescriptor.PreferredBody;
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
iOSHelpers.SetBottomBorder(Control);
UpdateKeyboardAppearance();
}
}
private void UpdateKeyboardAppearance()
{
if(!Core.Utilities.ThemeHelpers.LightTheme)
{
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
}
}

View File

@@ -0,0 +1,28 @@
using Bit.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
namespace Bit.iOS.Renderers
{
public class CustomSearchBarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if(e.NewElement is SearchBar)
{
UpdateKeyboardAppearance();
}
}
private void UpdateKeyboardAppearance()
{
if(!Core.Utilities.ThemeHelpers.LightTheme)
{
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
}
}
}
}

View File

@@ -137,6 +137,7 @@
<Compile Include="Migration\KeyChainStorageService.cs" />
<Compile Include="NFCReaderDelegate.cs" />
<Compile Include="Renderers\CustomButtonRenderer.cs" />
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
<Compile Include="Renderers\CustomPickerRenderer.cs" />
<Compile Include="Renderers\CustomEntryRenderer.cs" />

View File

@@ -118,38 +118,34 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden — управител на пароли</value>
<comment>Max 30 characters</comment>
</data>
<data name="Description" xml:space="preserve">
<value>Bitwarden is the easiest and safest way to store all of your logins and passwords while conveniently keeping them synced between all of your devices. The Bitwarden app extension allows you to quickly log into any website through Safari or Chrome and is supported by hundreds of other popular apps.
Password theft is a serious problem. The websites and apps that you use are under attack every day. Security breaches occur and your passwords are stolen. When you reuse the same passwords across apps and websites hackers can easily access your email, bank, and other important accounts.
Security experts recommend that you use a different, randomly generated password for every account that you create. But how do you manage all those passwords? Bitwarden makes it easy for you to create, store, and access your passwords.
Bitwarden stores all of your logins in an encrypted vault that syncs across all of your devices. Since it's fully encrypted before it ever leaves your device, only you have access to your data. Not even the team at Bitwarden can read your data, even if we wanted to. Your data is sealed with AES-256 bit encryption, salted hashing, and PBKDF2 SHA-256.
Bitwarden is 100% open source software. The source code for Bitwarden is hosted on GitHub and everyone is free to review, audit, and contribute to the Bitwarden codebase.</value>
<value>Bitwarden е най-лесният и надежден начин да съхранявате регистрации и пароли като ги синхронизирате на всички свои устройства. Разширението към програмите позволява бързо автоматично попълване на данни и пароли в Safari, Chrome и другите приложения.
Кражбата на пароли е тежък проблем. Сайтовете в Интернет, програмите и мобилните приложения биват атакувани всеки ден. Пробивите в сигурността са факт и паролите биват откраднати. Ако използвате една и съща парола в много програми или сайтове, злонамерени лица могат лесно да достъпят вашата е-поща, електронно банкиране и други важни регистрации.
Експертите по сигурността препоръчват да ползвате различна, случайно генерирана парола за всяка отделна регистрация. Как да управлявате всичките тези пароли? Bitwarden ви позволява лесно да ги създавате, съхранявате и ползвате.
Bitwarden съхранява всички данни в шифриран трезор, който се синхронизира на всички устройства, които ползвате. Шифрирането се извършва преди данните да напуснат устройството ви — така само вие имате достъп до тях. Дори и екипът на Bitwarden не може да прочете данните, дори и да се опита. Данните са защитени чрез AES с 256-битов ключ, контролни суми с добавени случайни данни и удължаване на ключа с PBKDF2 SHA-256.
Bitwarden е със 100% отворен код! Изходният код е наличен в сайта GitHub и всеки може да го преглежда, извърши одит и даже да допринесе за Bitwarden.</value>
<comment>Max 4000 characters</comment>
</data>
<data name="Keywords" xml:space="preserve">
<value>bit warden,8bit,password,free password manager,password manager,login manager</value>
<value>bit warden,8bit,password,free password manager,password manager,login manager,бит,уордън,уордан,страж, защита,пароли,карти,номера,управление,мениджър,шифриране,безплатен,свободен,регистрации,сайт</value>
<comment>Max 100 characters</comment>
</data>
<data name="Screenshot1" xml:space="preserve">
<value>Manage all your logins and passwords from a secure vault</value>
<value>Управление на всички регистрации и пароли чрез защитен трезор</value>
</data>
<data name="Screenshot2" xml:space="preserve">
<value>Automatically generate strong, random, and secure passwords</value>
<value>Автоматично създаване на силни, надеждни, случайни пароли</value>
</data>
<data name="Screenshot3" xml:space="preserve">
<value>Protect your vault with Touch ID, PIN code, or master password</value>
<value>Достъп до трезора с пръстов отпечатък — Touch ID, ПИН или главна парола</value>
</data>
<data name="Screenshot4" xml:space="preserve">
<value>Auto-fill logins from Safari, Chrome, and hundreds of other apps</value>
<value>Бързо автоматично попълване на данни и пароли в Safari, Chrome и другите приложения</value>
</data>
<data name="Screenshot5" xml:space="preserve">
<value>Sync and access your vault from multiple devices</value>
<value>Удобен достъп до трезора, който се синхронизира от всички устройства</value>
</data>
</root>

View File

@@ -118,11 +118,11 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Title" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden — управител на пароли</value>
<comment>Max 30 characters</comment>
</data>
<data name="ShortDescription" xml:space="preserve">
<value>Bitwarden is a login and password manager that helps keep you safe while online.</value>
<value>Bitwarden съхранява данните за регистрации и паролите в надежден трезор. Само вие имате достъп до него, което ви защитава онлайн.</value>
<comment>Max 80 characters</comment>
</data>
<data name="FullDesciption" xml:space="preserve">
@@ -138,26 +138,25 @@ Bitwarden is 100% open source software. The source code for Bitwarden is hosted
<comment>Max 4000 characters</comment>
</data>
<data name="FeatureGraphic" xml:space="preserve">
<value>A secure and free password manager for all of your devices</value>
<value>Сигурен и свободен управител на пароли за всички устройства</value>
</data>
<data name="Screenshot1" xml:space="preserve">
<value>Manage all your logins and passwords from a secure vault</value>
<value>Управление на всички регистрации и пароли чрез защитен трезор</value>
</data>
<data name="Screenshot2" xml:space="preserve">
<value>Automatically generate strong, random, and secure passwords</value>
<value>Автоматично създаване на силни, надеждни, случайни пароли</value>
</data>
<data name="Screenshot3" xml:space="preserve">
<value>Protect your vault with fingerprint, PIN code, or master password</value>
<value>Достъп до трезора с пръстов отпечатък, ПИН или главна парола</value>
</data>
<data name="Screenshot4" xml:space="preserve">
<value>Quickly auto-fill logins from within your web browser and other apps</value>
<value>Бързо автоматично попълване на данни и пароли в уеб браузъра и другите приложения</value>
</data>
<data name="Screenshot5" xml:space="preserve">
<value>Sync and access your vault from multiple devices
- Phone
- Tablet
- Desktop
- Web</value>
<value>Удобен достъп до трезора, който се синхронизира от всички устройства:
телефони;
таблети;
компютри;
уеб.</value>
</data>
</root>

View File

@@ -118,11 +118,11 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Title" xml:space="preserve">
<value>bitwarden Jelszókezelő</value>
<value>Bitwarden Jelszó Kezelő</value>
<comment>Max 30 characters</comment>
</data>
<data name="ShortDescription" xml:space="preserve">
<value>A bitwarden egy jelszókezelő app, mely biztonságban tart amikor online vagy.</value>
<value>Bitwarden egy bejelentkezés és jelszó kezelő, amely segít neked biztonságban lenni, amíg online vagy.</value>
<comment>Max 80 characters</comment>
</data>
<data name="FullDesciption" xml:space="preserve">