Compare commits

...

30 Commits

Author SHA1 Message Date
Kyle Spearrin
5501ab9083 bump build 2017-09-29 17:42:11 -04:00
Kyle Spearrin
660a21deb1 info.plist updates 2017-09-29 17:22:52 -04:00
Kyle Spearrin
be7949b909 remove old icons 2017-09-29 17:15:16 -04:00
Kyle Spearrin
a688656f6d asset catalog with app icons 2017-09-29 17:14:52 -04:00
Kyle Spearrin
62365529cc Revert "asset catalog with app icon for itunes"
This reverts commit dcea869098.
2017-09-29 17:10:12 -04:00
Kyle Spearrin
dcea869098 asset catalog with app icon for itunes 2017-09-29 16:29:29 -04:00
Kyle Spearrin
634a8702cd autofill adjustments 2017-09-29 15:12:33 -04:00
Kyle Spearrin
fee993c309 new review link for ios 11 2017-09-28 23:26:59 -04:00
Kyle Spearrin
bf76707e92 shorthand null check 2017-09-28 22:56:36 -04:00
Kyle Spearrin
da847f6567 ios extension autofill fixes 2017-09-28 22:54:46 -04:00
Kyle Spearrin
7a5d25f2e3 version bump 2017-09-28 16:54:51 -04:00
Kyle Spearrin
bf0dedd447 new languages 2017-09-27 23:26:03 -04:00
Kyle Spearrin
3f7dcc6acf New Crowdin translations (#138)
* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Chinese Simplified)
2017-09-27 23:17:34 -04:00
Kyle Spearrin
2efe8b4186 switch back to bearer 2017-09-27 23:06:41 -04:00
Kyle Spearrin
068f5771b2 make notes editor taller 2017-09-27 14:36:55 -04:00
Kyle Spearrin
c2b1be288e remove MovementMethod to enable highlight 2017-09-27 14:36:42 -04:00
Kyle Spearrin
163ad248af autofill custom fields for iOS extension 2017-09-26 14:38:12 -04:00
Kyle Spearrin
4598c3d852 resources for test project 2017-09-26 12:42:50 -04:00
Kyle Spearrin
a1dec131c7 dont automatically use latest target framework 2017-09-26 12:20:20 -04:00
Kyle Spearrin
133585f46a revert to 7.1 2017-09-26 11:57:49 -04:00
Kyle Spearrin
3ea81ce2fb reveal hidden value for custom fields 2017-09-26 11:06:50 -04:00
Kyle Spearrin
590fe211c4 edit custom fields 2017-09-25 17:13:20 -04:00
Kyle Spearrin
78cda03d61 cleanup login view of custom fields. 2017-09-25 15:05:36 -04:00
Kyle Spearrin
e126cbf644 sync and display custom fields for login 2017-09-22 17:32:20 -04:00
Kyle Spearrin
cc12ae7712 sub-classed login props for cipher req 2017-09-21 10:50:15 -04:00
Kyle Spearrin
e8486abccf change login to cipher apis 2017-09-20 17:37:09 -04:00
Kyle Spearrin
15f074a45b remove duplicate / from API routes 2017-09-20 13:23:47 -04:00
Kyle Spearrin
a426d98e92 change syncing to use new sync api 2017-09-20 13:17:05 -04:00
Kyle Spearrin
45d171e0e3 notes keyboard type is "Text" for auto-cap 2017-09-19 16:34:29 -04:00
Kyle Spearrin
5950c33a43 qs tile to quickly launch my vault (android) 2017-09-19 15:55:15 -04:00
134 changed files with 4872 additions and 841 deletions

View File

@@ -16,7 +16,7 @@
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
@@ -308,6 +308,7 @@
<Compile Include="Controls\ExtendedTextCellRenderer.cs" />
<Compile Include="Controls\ExtendedPickerRenderer.cs" />
<Compile Include="Controls\ExtendedEntryRenderer.cs" />
<Compile Include="MyVaultTileService.cs" />
<Compile Include="Services\HttpService.cs" />
<Compile Include="Services\AndroidKeyStoreStorageService.cs" />
<Compile Include="Services\LocalizeService.cs" />
@@ -944,6 +945,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\shield.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@@ -11,7 +11,7 @@ using XLabs.Ioc;
namespace Bit.Android
{
[Service(Permission = "android.permission.BIND_ACCESSIBILITY_SERVICE", Label = "bitwarden")]
[Service(Permission = global::Android.Manifest.Permission.BindAccessibilityService, Label = "bitwarden")]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
public class AutofillService : AccessibilityService

View File

@@ -57,7 +57,6 @@ namespace Bit.Android.Controls
// For Scrolling in Editor innner area
Control.VerticalScrollBarEnabled = true;
Control.MovementMethod = ScrollingMovementMethod.Instance;
Control.ScrollBarStyle = ScrollbarStyles.InsideInset;
// Force scrollbars to be displayed

View File

@@ -74,6 +74,7 @@ namespace Bit.Android
_settings = Resolver.Resolve<ISettings>();
LoadApplication(new App.App(
uri,
Intent.GetBooleanExtra("myVaultTile", false),
Resolver.Resolve<IAuthService>(),
Resolver.Resolve<IConnectivity>(),
Resolver.Resolve<IUserDialogs>(),

View File

@@ -220,7 +220,6 @@ namespace Bit.Android
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
@@ -228,6 +227,7 @@ namespace Bit.Android
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossSettings.Current);

View File

@@ -0,0 +1,58 @@
using Android.App;
using Android.Content;
using Android.Service.QuickSettings;
using Java.Lang;
namespace Bit.Android
{
[Service(Permission = global::Android.Manifest.Permission.BindQuickSettingsTile,
Label = "@string/MyVault", Icon = "@drawable/shield")]
[IntentFilter(new string[] { ActionQsTile })]
public class MyVaultTileService : TileService
{
public override void OnTileAdded()
{
base.OnTileAdded();
}
public override void OnStartListening()
{
base.OnStartListening();
}
public override void OnStopListening()
{
base.OnStopListening();
}
public override void OnTileRemoved()
{
base.OnTileRemoved();
}
public override void OnClick()
{
base.OnClick();
if(IsLocked)
{
UnlockAndRun(new Runnable(() =>
{
LaunchMyVault();
}));
}
else
{
LaunchMyVault();
}
}
private void LaunchMyVault()
{
var intent = new Intent(this, typeof(SplashActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
intent.PutExtra("myVaultTile", true);
StartActivityAndCollapse(intent);
}
}
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.10.0" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.11.0" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />

View File

@@ -2769,8 +2769,8 @@ namespace Bit.Android
// aapt resource value: 0x7f0200e7
public const int notification_sm = 2130837735;
// aapt resource value: 0x7f0200f9
public const int notification_template_icon_bg = 2130837753;
// aapt resource value: 0x7f0200fa
public const int notification_template_icon_bg = 2130837754;
// aapt resource value: 0x7f0200e8
public const int paperclip = 2130837736;
@@ -2797,31 +2797,34 @@ namespace Bit.Android
public const int share_tools = 2130837743;
// aapt resource value: 0x7f0200f0
public const int splash_screen = 2130837744;
public const int shield = 2130837744;
// aapt resource value: 0x7f0200f1
public const int star = 2130837745;
public const int splash_screen = 2130837745;
// aapt resource value: 0x7f0200f2
public const int star_selected = 2130837746;
public const int star = 2130837746;
// aapt resource value: 0x7f0200f3
public const int tools = 2130837747;
public const int star_selected = 2130837747;
// aapt resource value: 0x7f0200f4
public const int tools_selected = 2130837748;
public const int tools = 2130837748;
// aapt resource value: 0x7f0200f5
public const int trash = 2130837749;
public const int tools_selected = 2130837749;
// aapt resource value: 0x7f0200f6
public const int upload = 2130837750;
public const int trash = 2130837750;
// aapt resource value: 0x7f0200f7
public const int user = 2130837751;
public const int upload = 2130837751;
// aapt resource value: 0x7f0200f8
public const int yubikey = 2130837752;
public const int user = 2130837752;
// aapt resource value: 0x7f0200f9
public const int yubikey = 2130837753;
static Drawable()
{
@@ -3756,6 +3759,9 @@ namespace Bit.Android
// aapt resource value: 0x7f080046
public const int Hello = 2131230790;
// aapt resource value: 0x7f08009a
public const int MyVault = 2131230874;
// aapt resource value: 0x7f08002e
public const int abc_action_bar_home_description = 2131230766;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -5,4 +5,7 @@
accessibility service by tapping the toggle switch above, then press OK on the confirmation pop-up. You can then press
the back button twice to return to the main bitwarden app.
</string>
<string name="MyVault">
My Vault
</string>
</resources>

View File

@@ -7,8 +7,8 @@ using System.Threading.Tasks;
namespace Bit.Android
{
[Activity(Theme = "@style/BitwardenTheme.Splash",
MainLauncher = true,
[Activity(Theme = "@style/BitwardenTheme.Splash",
MainLauncher = true,
NoHistory = true,
WindowSoftInputMode = global::Android.Views.SoftInput.StateHidden)]
public class SplashActivity : AppCompatActivity
@@ -23,7 +23,9 @@ namespace Bit.Android
base.OnResume();
var startupWork = new Task(() =>
{
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
var mainIntent = new Intent(Application.Context, typeof(MainActivity));
mainIntent.PutExtra("myVaultTile", Intent.GetBooleanExtra("myVaultTile", false));
StartActivity(mainIntent);
});
startupWork.Start();

View File

@@ -10,6 +10,5 @@ namespace Bit.App.Abstractions
Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj);
Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync();
Task<ApiResult<ProfileResponse>> GetProfileAsync();
Task<ApiResult<KeysResponse>> GetKeys();
}
}

View File

@@ -4,10 +4,8 @@ using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ICipherApiRepository
public interface ICipherApiRepository : IApiRepository<CipherRequest, CipherResponse, string>
{
Task<ApiResult<CipherResponse>> GetByIdAsync(string id);
Task<ApiResult<ListResponse<CipherResponse>>> GetAsync();
Task<ApiResult<CipherResponse>> PostAttachmentAsync(string cipherId, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(string cipherId, string attachmentId);
}

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ILoginApiRepository : IApiRepository<LoginRequest, LoginResponse, string>
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISyncApiRepository
{
Task<ApiResult<SyncResponse>> Get();
}
}

View File

@@ -12,7 +12,7 @@ namespace Bit.App.Abstractions
Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString);
Task<ApiResult<LoginResponse>> SaveAsync(Login login);
Task<ApiResult<CipherResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName);

View File

@@ -35,6 +35,7 @@ namespace Bit.App
public App(
string uri,
bool myVault,
IAuthService authService,
IConnectivity connectivity,
IUserDialogs userDialogs,
@@ -71,7 +72,7 @@ namespace Bit.App
}
else if(authService.IsAuthenticated)
{
MainPage = new MainPage();
MainPage = new MainPage(myVault: myVault);
}
else
{

View File

@@ -36,6 +36,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
<Compile Include="Abstractions\Repositories\ISyncApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
@@ -86,6 +87,7 @@
<Compile Include="Controls\PinControl.cs" />
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
<Compile Include="Controls\VaultListViewCell.cs" />
<Compile Include="Enums\FieldType.cs" />
<Compile Include="Enums\TwoFactorProviderType.cs" />
<Compile Include="Enums\EncryptionType.cs" />
<Compile Include="Enums\OrganizationUserType.cs" />
@@ -97,13 +99,14 @@
<Compile Include="Abstractions\Services\ILocalizeService.cs" />
<Compile Include="Models\Api\ApiError.cs" />
<Compile Include="Models\Api\ApiResult.cs" />
<Compile Include="Models\Api\FolderDataModel.cs" />
<Compile Include="Models\Api\CipherDataModel.cs" />
<Compile Include="Models\Api\FieldDataModel.cs" />
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
<Compile Include="Models\Api\Request\FolderRequest.cs" />
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
<Compile Include="Models\Api\Request\TwoFactorEmailRequest.cs" />
<Compile Include="Models\Api\Request\RegisterRequest.cs" />
<Compile Include="Models\Api\Request\LoginRequest.cs" />
<Compile Include="Models\Api\Request\CipherRequest.cs" />
<Compile Include="Models\Api\Request\PasswordHintRequest.cs" />
<Compile Include="Models\Api\Request\TokenRequest.cs" />
<Compile Include="Models\Api\Response\AttachmentResponse.cs" />
@@ -113,15 +116,16 @@
<Compile Include="Models\Api\Response\FolderResponse.cs" />
<Compile Include="Models\Api\Response\ListResponse.cs" />
<Compile Include="Models\Api\Response\DeviceResponse.cs" />
<Compile Include="Models\Api\Response\LoginResponse.cs" />
<Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" />
<Compile Include="Models\Api\Response\KeysResponse.cs" />
<Compile Include="Models\Api\Response\SyncResponse.cs" />
<Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" />
<Compile Include="Models\CipherString.cs" />
<Compile Include="Models\Data\AttachmentData.cs" />
<Compile Include="Models\Attachment.cs" />
<Compile Include="Models\Field.cs" />
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
<Compile Include="Models\SymmetricCryptoKey.cs" />
<Compile Include="Models\Data\SettingsData.cs" />
@@ -164,11 +168,13 @@
<Compile Include="Pages\Settings\SettingsSyncPage.cs" />
<Compile Include="Pages\Settings\SettingsPage.cs" />
<Compile Include="Pages\Settings\SettingsListFoldersPage.cs" />
<Compile Include="Pages\Vault\VaultCustomFieldsPage.cs" />
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
<Compile Include="Pages\Vault\VaultAttachmentsPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" />
<Compile Include="Repositories\SyncApiRepository.cs" />
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
<Compile Include="Repositories\SettingsApiRepository.cs" />
<Compile Include="Repositories\ApiRepository.cs" />
@@ -177,13 +183,11 @@
<Compile Include="Repositories\BaseApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ILoginApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IConnectApiRepository.cs" />
<Compile Include="Repositories\DeviceApiRepository.cs" />
<Compile Include="Repositories\CipherApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" />
<Compile Include="Repositories\SettingsRepository.cs" />
<Compile Include="Repositories\LoginApiRepository.cs" />
<Compile Include="Repositories\FolderApiRepository.cs" />
<Compile Include="Repositories\LoginRepository.cs" />
<Compile Include="Repositories\FolderRepository.cs" />
@@ -194,6 +198,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.cs.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.da.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.da.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -299,6 +308,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.uk.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.vi.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.vi.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.zh-Hans.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -352,6 +366,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.da.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.es.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
@@ -432,6 +450,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.uk.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.vi.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.vi.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.zh-Hans.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>

View File

@@ -4,6 +4,8 @@
{
// Folder deprecated
//Folder = 0,
Login = 1
Login = 1,
SecureNote = 2,
Card = 3
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.App.Enums
{
public enum FieldType : byte
{
Text = 0,
Hidden = 1,
Boolean = 2
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public abstract class CipherDataModel
{
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Bit.App.Enums;
namespace Bit.App.Models.Api
{
public class FieldDataModel
{
public FieldType Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
}

View File

@@ -1,7 +0,0 @@
namespace Bit.App.Models.Api
{
public class FolderDataModel
{
public string Name { get; set; }
}
}

View File

@@ -1,12 +1,10 @@
namespace Bit.App.Models.Api
{
public class LoginDataModel
public class LoginDataModel : CipherDataModel
{
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
}
}

View File

@@ -0,0 +1,63 @@
using Bit.App.Enums;
using System.Collections.Generic;
using System.Linq;
namespace Bit.App.Models.Api
{
public class CipherRequest
{
public CipherRequest(Login login)
{
Type = CipherType.Login;
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Favorite = login.Favorite;
if(login.Fields != null)
{
Fields = login.Fields.Select(f => new FieldDataModel
{
Name = f.Name?.EncryptedString,
Value = f.Value?.EncryptedString,
Type = f.Type
});
}
switch(Type)
{
case CipherType.Login:
Login = new LoginType(login);
break;
default:
break;
}
}
public CipherType Type { get; set; }
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public bool Favorite { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; }
public LoginType Login { get; set; }
public class LoginType
{
public LoginType(Login login)
{
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Totp = login.Totp?.EncryptedString;
}
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Totp { get; set; }
}
}
}

View File

@@ -1,28 +0,0 @@
namespace Bit.App.Models.Api
{
public class LoginRequest
{
public LoginRequest(Login login)
{
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Totp = login.Totp?.EncryptedString;
Favorite = login.Favorite;
}
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public bool Favorite { get; set; }
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public class LoginResponse
{
public string Id { get; set; }
public string FolderId { get; set; }
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<AttachmentResponse> Attachments { get; set; }
public DateTime RevisionDate { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public class SyncResponse
{
public ProfileResponse Profile { get; set; }
public IEnumerable<FolderResponse> Folders { get; set; }
public IEnumerable<CipherResponse> Ciphers { get; set; }
public DomainsResponse Domains { get; set; }
}
}

View File

@@ -2,6 +2,8 @@
using SQLite;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using System.Linq;
namespace Bit.App.Models.Data
{
@@ -11,41 +13,6 @@ namespace Bit.App.Models.Data
public LoginData()
{ }
public LoginData(Login login, string userId)
{
Id = login.Id;
FolderId = login.FolderId;
UserId = userId;
OrganizationId = login.OrganizationId;
Name = login.Name?.EncryptedString;
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Totp = login?.Notes?.EncryptedString;
Favorite = login.Favorite;
Edit = login.Edit;
OrganizationUseTotp = login.OrganizationUseTotp;
}
public LoginData(LoginResponse login, string userId)
{
Id = login.Id;
FolderId = login.FolderId;
UserId = userId;
OrganizationId = login.OrganizationId;
Name = login.Name;
Uri = login.Uri;
Username = login.Username;
Password = login.Password;
Notes = login.Notes;
Totp = login.Totp;
Favorite = login.Favorite;
RevisionDateTime = login.RevisionDate;
Edit = login.Edit;
OrganizationUseTotp = login.OrganizationUseTotp;
}
public LoginData(CipherResponse cipher, string userId)
{
if(cipher.Type != Enums.CipherType.Login)
@@ -69,6 +36,15 @@ namespace Bit.App.Models.Data
Edit = cipher.Edit;
OrganizationUseTotp = cipher.OrganizationUseTotp;
RevisionDateTime = cipher.RevisionDate;
if(data.Fields != null && data.Fields.Any())
{
try
{
Fields = JsonConvert.SerializeObject(data.Fields);
}
catch(JsonSerializationException) { }
}
}
[PrimaryKey]
@@ -83,6 +59,7 @@ namespace Bit.App.Models.Data
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public string Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }

21
src/App/Models/Field.cs Normal file
View File

@@ -0,0 +1,21 @@
using Bit.App.Enums;
using Bit.App.Models.Api;
namespace Bit.App.Models
{
public class Field
{
public Field() { }
public Field(FieldDataModel model)
{
Type = model.Type;
Name = new CipherString(model.Name);
Value = new CipherString(model.Value);
}
public FieldType Type { get; set; }
public CipherString Name { get; set; }
public CipherString Value { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
@@ -26,24 +27,16 @@ namespace Bit.App.Models
Edit = data.Edit;
OrganizationUseTotp = data.OrganizationUseTotp;
Attachments = attachments?.Select(a => new Attachment(a));
}
public Login(LoginResponse response)
{
Id = response.Id;
UserId = response.UserId;
OrganizationId = response.OrganizationId;
FolderId = response.FolderId;
Name = response.Name != null ? new CipherString(response.Name) : null;
Uri = response.Uri != null ? new CipherString(response.Uri) : null;
Username = response.Username != null ? new CipherString(response.Username) : null;
Password = response.Password != null ? new CipherString(response.Password) : null;
Notes = response.Notes != null ? new CipherString(response.Notes) : null;
Totp = response.Totp != null ? new CipherString(response.Totp) : null;
Favorite = response.Favorite;
Edit = response.Edit;
OrganizationUseTotp = response.OrganizationUseTotp;
Attachments = response.Attachments?.Select(a => new Attachment(a));
if(!string.IsNullOrWhiteSpace(data.Fields))
{
try
{
var fieldModels = JsonConvert.DeserializeObject<IEnumerable<FieldDataModel>>(data.Fields);
Fields = fieldModels?.Select(f => new Field(f));
}
catch(JsonSerializationException) { }
}
}
public string Id { get; set; }
@@ -56,19 +49,10 @@ namespace Bit.App.Models
public CipherString Password { get; set; }
public CipherString Notes { get; set; }
public CipherString Totp { get; set; }
public IEnumerable<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
public LoginRequest ToLoginRequest()
{
return new LoginRequest(this);
}
public LoginData ToLoginData(string userId)
{
return new LoginData(this, userId);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.ComponentModel;
using Bit.App.Resources;
using Xamarin.Forms;
using System.Collections.Generic;
using Bit.App.Enums;
namespace Bit.App.Models.Page
{
@@ -17,6 +18,7 @@ namespace Bit.App.Models.Page
private int _totpSec = 30;
private bool _revealPassword;
private List<Attachment> _attachments;
private List<Field> _fields;
public VaultViewLoginPageModel() { }
@@ -144,12 +146,10 @@ namespace Bit.App.Models.Page
_revealPassword = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideImage)));
}
}
public string MaskedPassword => RevealPassword ? Password : Password == null ? null : new string('●', Password.Length);
public string ShowHideText => RevealPassword ? AppResources.Hide : AppResources.Show;
public ImageSource ShowHideImage => RevealPassword ? ImageSource.FromFile("eye_slash") : ImageSource.FromFile("eye");
public string TotpCode
@@ -189,6 +189,18 @@ namespace Bit.App.Models.Page
}
public bool ShowAttachments => (Attachments?.Count ?? 0) > 0;
public List<Field> Fields
{
get { return _fields; }
set
{
_fields = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Fields)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowFields)));
}
}
public bool ShowFields => (Fields?.Count ?? 0) > 0;
public void Update(Login login)
{
Name = login.Name?.Decrypt(login.OrganizationId);
@@ -217,6 +229,25 @@ namespace Bit.App.Models.Page
{
login.Attachments = null;
}
if(login.Fields != null)
{
var fields = new List<Field>();
foreach(var field in login.Fields)
{
fields.Add(new Field
{
Name = field.Name?.Decrypt(login.OrganizationId),
Value = field.Value?.Decrypt(login.OrganizationId),
Type = field.Type
});
}
Fields = fields;
}
else
{
login.Fields = null;
}
}
public class Attachment
@@ -227,5 +258,27 @@ namespace Bit.App.Models.Page
public long Size { get; set; }
public string Url { get; set; }
}
public class Field
{
private string _maskedValue;
public string Name { get; set; }
public string Value { get; set; }
public string MaskedValue
{
get
{
if(_maskedValue == null && Value != null)
{
_maskedValue = new string('●', Value.Length);
}
return _maskedValue;
}
}
public FieldType Type { get; set; }
public bool Revealed { get; set; }
}
}
}

View File

@@ -7,7 +7,7 @@ namespace Bit.App.Pages
{
public class MainPage : ExtendedTabbedPage
{
public MainPage(string uri = null)
public MainPage(string uri = null, bool myVault = false)
{
TintColor = Color.FromHex("3c8dbc");
@@ -33,7 +33,7 @@ namespace Bit.App.Pages
Children.Add(toolsNavigation);
Children.Add(settingsNavigation);
if(uri != null)
if(myVault || uri != null)
{
SelectedItem = vaultNavigation;
}

View File

@@ -20,6 +20,7 @@ namespace Bit.App.Pages
private readonly IFingerprint _fingerprint;
private readonly IPushNotification _pushNotification;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly IDeviceInfoService _deviceInfoService;
// TODO: Model binding context?
@@ -31,6 +32,7 @@ namespace Bit.App.Pages
_fingerprint = Resolver.Resolve<IFingerprint>();
_pushNotification = Resolver.Resolve<IPushNotification>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
Init();
}
@@ -213,7 +215,7 @@ namespace Bit.App.Pages
SyncCell.Tapped += SyncCell_Tapped;
LockCell.Tapped += LockCell_Tapped;
LogOutCell.Tapped += LogOutCell_Tapped;
AboutCell.Tapped += AboutCell_Tapped;
AboutCell.Tapped += AboutCell_Tapped;
HelpCell.Tapped += HelpCell_Tapped;
FeaturesCell.Tapped += FeaturesCell_Tapped;
@@ -328,8 +330,15 @@ namespace Bit.App.Pages
_googleAnalyticsService.TrackAppEvent("OpenedSetting", "RateApp");
if(Device.RuntimePlatform == Device.iOS)
{
Device.OpenUri(new Uri($"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
if(_deviceInfoService.Version < 11)
{
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
}
else
{
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/us/app/id1137397744?action=write-review"));
}
}
else if(Device.RuntimePlatform == Device.Android)
{

View File

@@ -61,6 +61,7 @@ namespace Bit.App.Pages
private void Init()
{
NotesCell = new FormEditorCell(height: 180);
NotesCell.Editor.Keyboard = Keyboard.Text;
TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor,
useButton: _deviceInfo.HasCamera);

View File

@@ -0,0 +1,248 @@
using System;
using System.Linq;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Utilities;
using Plugin.Connectivity.Abstractions;
using Bit.App.Models;
using Bit.App.Enums;
using System.Collections.Generic;
namespace Bit.App.Pages
{
public class VaultCustomFieldsPage : ExtendedContentPage
{
private readonly ILoginService _loginService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly string _loginId;
private Login _login;
private DateTime? _lastAction;
public VaultCustomFieldsPage(string loginId)
: base(true)
{
_loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>();
_connectivity = Resolver.Resolve<IConnectivity>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
public ToolbarItem SaveToolbarItem { get; set; }
public Label NoDataLabel { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
private void Init()
{
FieldsSection = new TableSection(" ");
Table = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = true,
HasUnevenRows = true,
Root = new TableRoot
{
FieldsSection
}
};
NoDataLabel = new Label
{
Text = AppResources.NoCustomFields,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
Margin = new Thickness(10, 40, 10, 0)
};
SaveToolbarItem = new ToolbarItem(AppResources.Save, null, async () =>
{
if(_lastAction.LastActionWasRecent() || _login == null)
{
return;
}
_lastAction = DateTime.UtcNow;
if(!_connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(FieldsSection.Count > 0)
{
var fields = new List<Field>();
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entryCell)
{
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(entryCell.Label.Text) ? null :
entryCell.Label.Text.Encrypt(_login.OrganizationId),
Value = string.IsNullOrWhiteSpace(entryCell.Entry.Text) ? null :
entryCell.Entry.Text.Encrypt(_login.OrganizationId),
Type = entryCell.Entry.IsPassword ? FieldType.Hidden : FieldType.Text
});
}
else if(cell is ExtendedSwitchCell switchCell)
{
var value = switchCell.On ? "true" : "false";
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(switchCell.Text) ? null :
switchCell.Text.Encrypt(_login.OrganizationId),
Value = value.Encrypt(_login.OrganizationId),
Type = FieldType.Boolean
});
}
}
_login.Fields = fields;
}
else
{
_login.Fields = null;
}
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(_login);
_userDialogs.HideLoading();
if(saveTask.Succeeded)
{
_userDialogs.Toast(AppResources.CustomFieldsUpdated);
_googleAnalyticsService.TrackAppEvent("UpdatedCustomFields");
await Navigation.PopForDeviceAsync();
}
else if(saveTask.Errors.Count() > 0)
{
await _userDialogs.AlertAsync(saveTask.Errors.First().Message, AppResources.AnErrorHasOccurred);
}
else
{
await _userDialogs.AlertAsync(AppResources.AnErrorHasOccurred);
}
}, ToolbarItemOrder.Default, 0);
Title = AppResources.CustomFields;
Content = Table;
if(Device.RuntimePlatform == Device.iOS)
{
Table.RowHeight = -1;
Table.EstimatedRowHeight = 44;
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
_login = await _loginService.GetByIdAsync(_loginId);
if(_login == null)
{
await Navigation.PopForDeviceAsync();
return;
}
if(_login.Fields != null && _login.Fields.Any())
{
Content = Table;
ToolbarItems.Add(SaveToolbarItem);
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel));
}
foreach(var field in _login.Fields)
{
var label = field.Name?.Decrypt(_login.OrganizationId) ?? string.Empty;
var value = field.Value?.Decrypt(_login.OrganizationId);
switch(field.Type)
{
case FieldType.Text:
case FieldType.Hidden:
var hidden = field.Type == FieldType.Hidden;
var textFieldCell = new FormEntryCell(label, isPassword: hidden, useButton: hidden);
textFieldCell.Entry.Text = value;
textFieldCell.Entry.DisableAutocapitalize = true;
textFieldCell.Entry.Autocorrect = false;
if(hidden)
{
textFieldCell.Entry.FontFamily = Helpers.OnPlatform(
iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
textFieldCell.Button.Image = "eye";
textFieldCell.Button.Command = new Command(() =>
{
textFieldCell.Entry.InvokeToggleIsPassword();
textFieldCell.Button.Image =
"eye" + (!textFieldCell.Entry.IsPasswordFromToggled ? "_slash" : string.Empty);
});
}
if(Device.RuntimePlatform == Device.Android && textFieldCell.Button != null)
{
textFieldCell.Button.WidthRequest = 40;
}
textFieldCell.InitEvents();
FieldsSection.Add(textFieldCell);
break;
case FieldType.Boolean:
var switchFieldCell = new ExtendedSwitchCell
{
Text = label,
On = value == "true"
};
FieldsSection.Add(switchFieldCell);
break;
default:
continue;
}
}
}
else
{
Content = NoDataLabel;
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close));
}
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.Dispose();
}
}
}
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage,
AppResources.Ok);
}
}
}

View File

@@ -45,6 +45,7 @@ namespace Bit.App.Pages
public FormPickerCell FolderCell { get; private set; }
public ExtendedTextCell GenerateCell { get; private set; }
public ExtendedTextCell AttachmentsCell { get; private set; }
public ExtendedTextCell CustomFieldsCell { get; private set; }
public ExtendedTextCell DeleteCell { get; private set; }
private void Init()
@@ -56,7 +57,8 @@ namespace Bit.App.Pages
return;
}
NotesCell = new FormEditorCell(height: 180);
NotesCell = new FormEditorCell(height: 300);
NotesCell.Editor.Keyboard = Keyboard.Text;
NotesCell.Editor.Text = login.Notes?.Decrypt(login.OrganizationId);
TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor,
@@ -124,6 +126,12 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
CustomFieldsCell = new ExtendedTextCell
{
Text = AppResources.CustomFields,
ShowDisclousure = true
};
DeleteCell = new ExtendedTextCell { Text = AppResources.Delete, TextColor = Color.Red };
var table = new ExtendedTableView
@@ -146,7 +154,8 @@ namespace Bit.App.Pages
TotpCell,
FolderCell,
favoriteCell,
AttachmentsCell
AttachmentsCell,
CustomFieldsCell
},
new TableSection(AppResources.Notes)
{
@@ -225,7 +234,7 @@ namespace Bit.App.Pages
if(saveTask.Succeeded)
{
_userDialogs.Toast(AppResources.LoginUpdated);
_googleAnalyticsService.TrackAppEvent("EditeLogin");
_googleAnalyticsService.TrackAppEvent("EditedLogin");
await Navigation.PopForDeviceAsync();
}
else if(saveTask.Errors.Count() > 0)
@@ -279,6 +288,10 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped += AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped += CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped += DeleteCell_Tapped;
@@ -312,6 +325,10 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped -= AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped -= CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped -= DeleteCell_Tapped;
@@ -368,6 +385,12 @@ namespace Bit.App.Pages
await Navigation.PushModalAsync(page);
}
private async void CustomFieldsCell_Tapped(object sender, EventArgs e)
{
var page = new ExtendedNavigationPage(new VaultCustomFieldsPage(_loginId));
await Navigation.PushModalAsync(page);
}
private async void DeleteCell_Tapped(object sender, EventArgs e)
{
if(!_connectivity.IsConnected)

View File

@@ -11,6 +11,7 @@ using Bit.App.Utilities;
using System.Collections.Generic;
using Bit.App.Models;
using System.Linq;
using Bit.App.Enums;
namespace Bit.App.Pages
{
@@ -39,12 +40,14 @@ namespace Bit.App.Pages
private TableSection LoginInformationSection { get; set; }
private TableSection NotesSection { get; set; }
private TableSection AttachmentsSection { get; set; }
private TableSection FieldsSection { get; set; }
public LabeledValueCell UsernameCell { get; set; }
public LabeledValueCell PasswordCell { get; set; }
public LabeledValueCell UriCell { get; set; }
public LabeledValueCell NotesCell { get; set; }
public LabeledValueCell TotpCodeCell { get; set; }
private EditLoginToolBarItem EditItem { get; set; }
public List<LabeledValueCell> FieldsCells { get; set; }
public List<AttachmentViewCell> AttachmentCells { get; set; }
private void Init()
@@ -255,6 +258,35 @@ namespace Bit.App.Pages
Table.Root.Add(AttachmentsSection);
}
if(Table.Root.Contains(FieldsSection))
{
Table.Root.Remove(FieldsSection);
}
if(Model.ShowFields)
{
FieldsSection = new TableSection(AppResources.CustomFields);
foreach(var field in Model.Fields)
{
FieldViewCell fieldCell;
switch(field.Type)
{
case FieldType.Text:
fieldCell = new FieldViewCell(this, field, null);
break;
case FieldType.Hidden:
fieldCell = new FieldViewCell(this, field, null, null);
break;
case FieldType.Boolean:
fieldCell = new FieldViewCell(this, field);
break;
default:
continue;
}
FieldsSection.Add(fieldCell);
}
Table.Root.Add(FieldsSection);
}
base.OnAppearing();
}
@@ -322,8 +354,8 @@ namespace Bit.App.Pages
private void Copy(string copyText, string alertLabel)
{
_deviceActionService.CopyToClipboard(copyText);
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
_deviceActionService.CopyToClipboard(copyText);
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
}
private void TotpTick(string totpKey)
@@ -387,5 +419,60 @@ namespace Bit.App.Pages
_tapped?.Invoke();
}
}
public class FieldViewCell : LabeledValueCell
{
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field)
: base(field.Name, field.Value == "true" ? "✓" : "-")
{
Init(page, field, null);
}
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, bool? a)
: base(field.Name, field.Value, AppResources.Copy)
{
Init(page, field, Button1);
}
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, bool? a, bool? b)
: base(field.Name, field.MaskedValue, string.Empty, AppResources.Copy)
{
Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular",
Android: "monospace", WinPhone: "Courier");
if(Device.RuntimePlatform == Device.iOS)
{
Button1.Margin = new Thickness(10, 0);
}
Button1.WidthRequest = 40;
Button1.Image = "eye";
Button1.Command = new Command(() =>
{
field.Revealed = !field.Revealed;
if(field.Revealed)
{
Button1.Image = "eye_slash";
Value.Text = field.Value;
}
else
{
Button1.Image = "eye";
Value.Text = field.MaskedValue;
}
});
Init(page, field, Button2);
}
private void Init(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, ExtendedButton copyButton)
{
Value.LineBreakMode = LineBreakMode.WordWrap;
if(copyButton != null)
{
copyButton.Command = new Command(() => page.Copy(field.Value, field.Name));
copyButton.WidthRequest = 59;
}
}
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/accounts";
protected override string ApiRoute => "accounts";
public virtual async Task<ApiResult> PostRegisterAsync(RegisterRequest requestObj)
{
@@ -172,45 +172,5 @@ namespace Bit.App.Repositories
}
}
}
public virtual async Task<ApiResult<KeysResponse>> GetKeys()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<KeysResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<KeysResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/keys")),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<KeysResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<KeysResponse>(responseContent);
return ApiResult<KeysResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<KeysResponse>();
}
}
}
}
}

View File

@@ -5,12 +5,11 @@ using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using Plugin.Connectivity.Abstractions;
using System.Globalization;
using System.IO;
namespace Bit.App.Repositories
{
public class CipherApiRepository : BaseApiRepository, ICipherApiRepository
public class CipherApiRepository : ApiRepository<CipherRequest, CipherResponse, string>, ICipherApiRepository
{
public CipherApiRepository(
IConnectivity connectivity,
@@ -19,88 +18,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/ciphers";
public virtual async Task<ApiResult<CipherResponse>> GetByIdAsync(string id)
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<CipherResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<CipherResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/", id)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<CipherResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<CipherResponse>();
}
}
}
public virtual async Task<ApiResult<ListResponse<CipherResponse>>> GetAsync()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<ListResponse<CipherResponse>>();
}
var tokenStateResponse = await HandleTokenStateAsync<ListResponse<CipherResponse>>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(string.Format("{0}{1}?includeFolders=false&includeShared=true",
client.BaseAddress, ApiRoute)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<ListResponse<CipherResponse>>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<ListResponse<CipherResponse>>();
}
}
}
protected override string ApiRoute => "ciphers";
public virtual async Task<ApiResult<CipherResponse>> PostAttachmentAsync(string cipherId, byte[] data,
string fileName)

View File

@@ -20,7 +20,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/connect";
protected override string ApiRoute => "connect";
public virtual async Task<ApiResult<TokenResponse>> PostTokenAsync(TokenRequest requestObj)
{

View File

@@ -18,7 +18,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/devices";
protected override string ApiRoute => "devices";
public virtual async Task<ApiResult> PutTokenAsync(string identifier, DeviceTokenRequest request)
{

View File

@@ -14,6 +14,6 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/folders";
protected override string ApiRoute => "folders";
}
}

View File

@@ -1,19 +0,0 @@
using System;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Plugin.Connectivity.Abstractions;
namespace Bit.App.Repositories
{
public class LoginApiRepository : ApiRepository<LoginRequest, LoginResponse, string>, ILoginApiRepository
{
public LoginApiRepository(
IConnectivity connectivity,
IHttpService httpService,
ITokenService tokenService)
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/logins";
}
}

View File

@@ -17,7 +17,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/settings";
protected override string ApiRoute => "settings";
public virtual async Task<ApiResult<DomainsResponse>> GetDomains(bool excluded = false)
{

View File

@@ -0,0 +1,63 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Plugin.Connectivity.Abstractions;
using Newtonsoft.Json;
namespace Bit.App.Repositories
{
public class SyncApiRepository : BaseApiRepository, ISyncApiRepository
{
public SyncApiRepository(
IConnectivity connectivity,
IHttpService httpService,
ITokenService tokenService)
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "sync";
public virtual async Task<ApiResult<SyncResponse>> Get()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<SyncResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<SyncResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<SyncResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<SyncResponse>(responseContent);
return ApiResult<SyncResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<SyncResponse>();
}
}
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Bit.App.Repositories
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "/two-factor";
protected override string ApiRoute => "two-factor";
public virtual async Task<ApiResult> PostSendEmailLoginAsync(TwoFactorEmailRequest requestObj)
{

View File

@@ -718,6 +718,24 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Custom Fields.
/// </summary>
public static string CustomFields {
get {
return ResourceManager.GetString("CustomFields", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Custom fields updated..
/// </summary>
public static string CustomFieldsUpdated {
get {
return ResourceManager.GetString("CustomFieldsUpdated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete.
/// </summary>
@@ -1717,6 +1735,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to No custom fields. You can fully manage custom fields from the web vault or browser extension..
/// </summary>
public static string NoCustomFields {
get {
return ResourceManager.GetString("NoCustomFields", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There are no favorites in your vault..
/// </summary>

View File

@@ -209,7 +209,7 @@
<value>Nahlaste chybu přímo v našem GitHub repositáři.</value>
</data>
<data name="FingerprintDirection" xml:space="preserve">
<value>Použijte svůj otisk prstu k ověření.</value>
<value>Pro ověření použijte otisk prstu.</value>
</data>
<data name="Folder" xml:space="preserve">
<value>Složka</value>
@@ -352,7 +352,7 @@
<comment>Label for a uri/url.</comment>
</data>
<data name="UseFingerprintToUnlock" xml:space="preserve">
<value>Pro odemknutí použít otisk prstu</value>
<value>Odemknout otiskem prstu</value>
</data>
<data name="Username" xml:space="preserve">
<value>Uživatelské jméno</value>
@@ -398,7 +398,7 @@
<value>Účet</value>
</data>
<data name="AccountCreated" xml:space="preserve">
<value>Váš nový účet byl vytvořen! Můžete se přihlásit.</value>
<value>Váš účet byl vytvořen! Můžete se přihlásit.</value>
</data>
<data name="AddALogin" xml:space="preserve">
<value>Přidat přihlašovací údaje</value>
@@ -413,7 +413,7 @@
<value>Služba automatického vyplňování</value>
</data>
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
<value>Nepoužít snadno zaměnitelné znaky</value>
<value>Nepoužít zaměnitelné znaky</value>
</data>
<data name="BitwardenAppExtension" xml:space="preserve">
<value>Rozšíření aplikace bitwarden</value>
@@ -474,7 +474,7 @@
<value>Povolit automatickou synchronizaci</value>
</data>
<data name="EnterEmailForHint" xml:space="preserve">
<value>Zadejte emailovou adresu pro zaslání nápovědy k vašemu hlavnímu heslu.</value>
<value>Zadejte emailovou adresu pro zaslání nápovědy k hlavnímu heslu.</value>
</data>
<data name="ExntesionReenable" xml:space="preserve">
<value>Znovu zapnout rozšíření aplikace</value>
@@ -572,7 +572,7 @@
<value>Potvrzení hesla se neshoduje.</value>
</data>
<data name="MasterPasswordDescription" xml:space="preserve">
<value>Hlavní heslo je heslo, které používáte k přístupu do vašeho trezoru. Je velmi důležité, abyste své hlavní heslo nezapomněli. Neexistuje totiž žádný způsob, jak heslo obnovit v případě, že jste na něj zapomněli.</value>
<value>Hlavní heslo je heslo, které používáte k přístupu do vašeho trezoru. Je velmi důležité, abyste jej nezapomněli. Neexistuje totiž žádný způsob, jak heslo obnovit v případě, že jste na něj zapomněli.</value>
</data>
<data name="MasterPasswordHint" xml:space="preserve">
<value>Nápověda k hlavnímu heslu (volitelné)</value>
@@ -635,7 +635,7 @@
<value>Generátor hesla</value>
</data>
<data name="PasswordGeneratorDescription" xml:space="preserve">
<value>Vygenerujte si silné a unikátní heslo pro vaše přihlašovací údaje.</value>
<value>Vygenerujte si silné a unikátní heslo pro přihlašovací údaje.</value>
</data>
<data name="PasswordHint" xml:space="preserve">
<value>Nápověda k heslu</value>
@@ -736,7 +736,7 @@
<value>Webová aplikace</value>
</data>
<data name="WebVaultDescription" xml:space="preserve">
<value>Spravujte vaše přihlašovací údaje z jakéhokoliv prohlížeče pomocí webové aplikace bitwarden.</value>
<value>Spravujte přihlašovací údaje z jakéhokoliv prohlížeče pomocí webové aplikace bitwarden.</value>
</data>
<data name="Lost2FAApp" xml:space="preserve">
<value>Ztratili jste ověřovací aplikaci?</value>
@@ -1028,6 +1028,15 @@
<value>URL serveru webového trezoru</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Klepnutím na toto oznámení zobrazíte přihlašovací údaje z trezoru.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1005,7 +1005,7 @@
<value>Para usuarios avanzados. Puedes especificar la URL base de cada servicio de forma independiente.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>La URLs del entorno han sido guardadas.</value>
<value>Las URLs del entorno han sido guardadas.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} no está formateado correctamente.</value>
@@ -1028,6 +1028,15 @@
<value>URL del servidor de la bóveda web</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Pulsa en esta notificación para ver las entradas de tu bóveda.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1028,6 +1028,15 @@
<value>URL poslužitelja web trezora</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Dodirnite ovu obavijest za pregled prijava iz trezora.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About" xml:space="preserve">
<value>About</value>
<value>Névjegy</value>
</data>
<data name="Add" xml:space="preserve">
<value>Hozzáadás</value>
@@ -196,7 +196,7 @@
<value>Írjon nekünk E-mailt közvetlenül a segítség kéréshez vagy visszajelzés beküldéséhez.</value>
</data>
<data name="EnterPIN" xml:space="preserve">
<value>Enter your PIN code.</value>
<value>Add meg a PIN-kódodat.</value>
</data>
<data name="Favorites" xml:space="preserve">
<value>Kedvencek</value>
@@ -303,48 +303,48 @@
<comment>Acknowledgement.</comment>
</data>
<data name="DisableGA" xml:space="preserve">
<value>Disable Analytics</value>
<value>Analitika kikapcsolása</value>
</data>
<data name="Password" xml:space="preserve">
<value>Password</value>
<value>Jelszó</value>
<comment>Label for a password.</comment>
</data>
<data name="Save" xml:space="preserve">
<value>Save</value>
<value>Mentés</value>
<comment>Button text for a save operation (verb).</comment>
</data>
<data name="Saving" xml:space="preserve">
<value>Saving...</value>
<value>Mentés...</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="Settings" xml:space="preserve">
<value>Settings</value>
<value>Beállítások</value>
<comment>The title for the settings page.</comment>
</data>
<data name="Show" xml:space="preserve">
<value>Show</value>
<value>Mutat</value>
<comment>Reveal a hidden value (password).</comment>
</data>
<data name="LoginDeleted" xml:space="preserve">
<value>Login has been deleted.</value>
<value>A bejelentkezés törölve.</value>
<comment>Confirmation message after successfully deleting a login.</comment>
</data>
<data name="LoginNoName" xml:space="preserve">
<value>No Name</value>
<value>Nincs név</value>
<comment>Title text to display when there is no name given for a login.</comment>
</data>
<data name="Submit" xml:space="preserve">
<value>Submit</value>
<value>Mehet</value>
</data>
<data name="Sync" xml:space="preserve">
<value>Sync</value>
<value>Szinkronizálás</value>
<comment>The title for the sync page.</comment>
</data>
<data name="ThankYou" xml:space="preserve">
<value>Thank You</value>
<value>Köszönjük</value>
</data>
<data name="Tools" xml:space="preserve">
<value>Tools</value>
<value>Eszközök</value>
<comment>The title for the tools page.</comment>
</data>
<data name="URI" xml:space="preserve">
@@ -352,682 +352,691 @@
<comment>Label for a uri/url.</comment>
</data>
<data name="UseFingerprintToUnlock" xml:space="preserve">
<value>Use Fingerprint to Unlock</value>
<value>Ujjlenyomat használata feloldáshoz</value>
</data>
<data name="Username" xml:space="preserve">
<value>Username</value>
<value>Felhasználónév</value>
<comment>Label for a username.</comment>
</data>
<data name="ValidationFieldRequired" xml:space="preserve">
<value>The {0} field is required.</value>
<value>A(z) {0} mező megadása kötelező.</value>
<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} has been copied.</value>
<value>{0} a vágólapra másolva.</value>
<comment>Confirmation message after suceessfully copying a value to the clipboard.</comment>
</data>
<data name="VerifyFingerprint" xml:space="preserve">
<value>Verify Fingerprint</value>
<value>Ujjlenyomat megerősítése</value>
</data>
<data name="VerifyMasterPassword" xml:space="preserve">
<value>Verify Master Password</value>
<value>Mester jelszó megerősítése</value>
</data>
<data name="VerifyPIN" xml:space="preserve">
<value>Verify PIN</value>
<value>PIN megerősítése</value>
</data>
<data name="Version" xml:space="preserve">
<value>Version</value>
<value>Verzió</value>
</data>
<data name="View" xml:space="preserve">
<value>View</value>
<value>Megtekintés</value>
</data>
<data name="VisitOurWebsite" xml:space="preserve">
<value>Visit Our Website</value>
<value>Látogasd meg a weboldalunkat</value>
</data>
<data name="VisitOurWebsiteDescription" xml:space="preserve">
<value>Visit our website to get help, news, email us, and/or learn more about how to use bitwarden.</value>
<value>Látogasd meg a weboldalunkat segítség kéréshez, hírekért, küldj nekünk e-mailt és/vagy tanuld meg hogyan használd a bitwarden-t.</value>
</data>
<data name="Website" xml:space="preserve">
<value>Website</value>
<value>Weboldal</value>
<comment>Label for a website.</comment>
</data>
<data name="Yes" xml:space="preserve">
<value>Yes</value>
<value>Igen</value>
</data>
<data name="Account" xml:space="preserve">
<value>Account</value>
<value>Fiók</value>
</data>
<data name="AccountCreated" xml:space="preserve">
<value>Your new account has been created! You may now log in.</value>
<value>Fiókodat létrehoztuk. Most már be tudsz jelentkezni.</value>
</data>
<data name="AddALogin" xml:space="preserve">
<value>Add a Login</value>
<value>Bejelentkezés hozzáadása</value>
</data>
<data name="AppExtension" xml:space="preserve">
<value>App Extension</value>
<value>App kiterjesztés</value>
</data>
<data name="AutofillDescription" xml:space="preserve">
<value>Use the bitwarden accessibility service to auto-fill your logins across apps and the web.</value>
<value>Használ a bitwarden kisegítő szolgáltatást, mely automatikusan kitölti a bejelentkezési adataidat akár egy app-ban, akár webes felületeken.</value>
</data>
<data name="AutofillService" xml:space="preserve">
<value>Auto-fill Service</value>
<value>Automatikus kitöltő szolgáltatás</value>
</data>
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
<value>Avoid Ambiguous Characters</value>
<value>Félreérthető karakterek mellőzése</value>
</data>
<data name="BitwardenAppExtension" xml:space="preserve">
<value>bitwarden App Extension</value>
<value>bitwarden alkalmazás</value>
</data>
<data name="BitwardenAppExtensionAlert" 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 "Tools" screen.</value>
<value>A legegyszerűbb módja új bejelentkezési adatok hozzáadásának a széfedhez, a bitwarden alkalmazás. Az alkalmazás használatáról az "Eszközök" képernyőn tudhatsz meg többet.</value>
</data>
<data name="BitwardenAppExtensionDescription" xml:space="preserve">
<value>Use bitwarden in Safari and other apps to auto-fill your logins.</value>
<value>Használd a bitwarden automatikus kitöltő szolgáltatását a Safari-ban és más alkalmazásokban.</value>
</data>
<data name="BitwardenAutofillService" xml:space="preserve">
<value>bitwarden Auto-fill Service</value>
<value>Bitwarden automatikus kitöltő szolgáltatás</value>
</data>
<data name="BitwardenAutofillServiceDescription" xml:space="preserve">
<value>Use the bitwarden accessibility service to auto-fill your logins.</value>
<value>A bitwarden kisegítő szolgáltatás használata bejelentkezések automatikus kitöltéséhez.</value>
</data>
<data name="ChangeEmail" xml:space="preserve">
<value>Change Email</value>
<value>E-mail cím módosítása</value>
</data>
<data name="ChangeEmailConfirmation" xml:space="preserve">
<value>You can change your email address on the bitwarden.com web vault. Do you want to visit the website now?</value>
<value>E-mail címedet a bitwarden.com webes széfében tudod megváltoztatni. Szeretnéd meglátogatni most a weboldalt?</value>
</data>
<data name="ChangeMasterPassword" xml:space="preserve">
<value>Change Master Password</value>
<value>Mesterjelszó módosítása</value>
</data>
<data name="ChangePasswordConfirmation" xml:space="preserve">
<value>You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?</value>
<value>Mesterjelszavadat a bitwarden.com webes széfében tudod megváltoztatni. Szeretnéd meglátogatni most a weboldalt?</value>
</data>
<data name="Close" xml:space="preserve">
<value>Close</value>
<value>Bezár</value>
</data>
<data name="ComingSoon" xml:space="preserve">
<value>Coming Soon!</value>
<value>Hamarosan!</value>
</data>
<data name="Continue" xml:space="preserve">
<value>Continue</value>
<value>Folytatás</value>
</data>
<data name="Copied" xml:space="preserve">
<value>Copied!</value>
<value>Másolva!</value>
</data>
<data name="CopiedPassword" xml:space="preserve">
<value>Copied password!</value>
<value>Jelszó másolva!</value>
</data>
<data name="CopiedUsername" xml:space="preserve">
<value>Copied username!</value>
<value>Másolt felhasználónév!</value>
</data>
<data name="CreateAccount" xml:space="preserve">
<value>Create Account</value>
<value>Fiók létrehozása</value>
</data>
<data name="CreatingAccount" xml:space="preserve">
<value>Creating account...</value>
<value>Fiók létrehozása...</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="EditLogin" xml:space="preserve">
<value>Edit Login</value>
<value>Bejelentkezés szerkesztése</value>
</data>
<data name="EnableAutomaticSyncing" xml:space="preserve">
<value>Enable Automatic Syncing</value>
<value>Automatikus szinkronizálás engedélyezése</value>
</data>
<data name="EnterEmailForHint" xml:space="preserve">
<value>Enter your account email address to receive your master password hint.</value>
<value>Írd be a fiókod e-mail címét, hogy megkapd a mesterjelszó emlékeztetőt.</value>
</data>
<data name="ExntesionReenable" xml:space="preserve">
<value>Re-enable App Extension</value>
<value>Alkalmazás újra engedélyezése</value>
</data>
<data name="ExtensionAlmostDone" xml:space="preserve">
<value>Almost done!</value>
<value>Mindjárt kész!</value>
</data>
<data name="ExtensionEnable" xml:space="preserve">
<value>Enable App Extension</value>
<value>Bővítmény engedélyezése</value>
</data>
<data name="ExtensionInSafari" xml:space="preserve">
<value>In Safari, find bitwarden using the share icon (hint: scroll to the right on the bottom row of the menu).</value>
<value>A Safari-ban a bitwarden-t a megosztás ikon alatt találod (Tipp: a menü alsó sorában gördítsd jobbra).</value>
<comment>Safari is the name of apple's web browser</comment>
</data>
<data name="ExtensionInstantAccess" xml:space="preserve">
<value>Get instant access to your passwords!</value>
<value>Kérj azonnali hozzáférést a jelszavakhoz!</value>
</data>
<data name="ExtensionReady" xml:space="preserve">
<value>You're ready to log in!</value>
<value>Készen állsz a bejelentkezéshez!</value>
</data>
<data name="ExtensionSeeApps" xml:space="preserve">
<value>See Supported Apps</value>
<value>Lásd: támogatott alkalmazások</value>
</data>
<data name="ExtensionSetup" xml:space="preserve">
<value>Your logins are now easily accessable from Safari, Chrome, and other supported apps.</value>
<value>A bejelentkezéseid mostantól könnyen hozzáférhetők a Safari-ból, Chrome-ból és más támogatott alkalmazásból.</value>
</data>
<data name="ExtensionSetup2" xml:space="preserve">
<value>In Safari and Chrome, find bitwarden using the share icon (hint: scroll to the right on the bottom row of the share menu).</value>
<value>A Safari-ban és a Chrome-ban a bitwarden-t a megosztás ikon alatt találod (Tipp: a menü alsó sorában gördítsd jobbra).</value>
</data>
<data name="ExtensionTapIcon" xml:space="preserve">
<value>Tap the bitwarden icon in the menu to launch the extension.</value>
<value>A bővítmény elindításához bökj a bitwarden ikonra a menüben.</value>
</data>
<data name="ExtensionTurnOn" xml:space="preserve">
<value>To turn on bitwarden in Safari and other apps, tap the "more" icon on the bottom row of the menu.</value>
<value>A bitwarden Safari-ban és más alkalmazásokban való bekapcsolásához bökj az "Egyéb" ikonra a menü alsó sorában.</value>
</data>
<data name="Favorite" xml:space="preserve">
<value>Favorite</value>
<value>Kedvenc</value>
</data>
<data name="Fingerprint" xml:space="preserve">
<value>Fingerprint</value>
<value>Ujjlenyomat</value>
</data>
<data name="GeneratePassword" xml:space="preserve">
<value>Generate Password</value>
<value>Jelszó generálása</value>
</data>
<data name="GetPasswordHint" xml:space="preserve">
<value>Get your master password hint</value>
<value>Kérj mesterjelszó emlékeztetőt</value>
</data>
<data name="ImportLogins" xml:space="preserve">
<value>Import Logins</value>
<value>Bejelentkezések importálása</value>
</data>
<data name="ImportLoginsConfirmation" xml:space="preserve">
<value>You can bulk import logins from the bitwarden.com web vault. Do you want to visit the website now?</value>
<value>Több bejelentkezést egyszerre a bitwarden.com webes széfében tudsz importálni. Szeretnéd meglátogatni a most a weboldalt?</value>
</data>
<data name="ImportLoginsDescription" xml:space="preserve">
<value>Quickly bulk import your logins from other password management apps.</value>
<value>Több bejelentkezés gyors importálása egyszerre egy másik jelszókezelő alkalmazásból.</value>
</data>
<data name="LastSync" xml:space="preserve">
<value>Last Sync:</value>
<value>Utolsó szinkronizálás:</value>
</data>
<data name="Length" xml:space="preserve">
<value>Length</value>
<value>Hossz</value>
</data>
<data name="Lock" xml:space="preserve">
<value>Lock</value>
<value>Lezárás</value>
</data>
<data name="LockOption15Minutes" xml:space="preserve">
<value>15 minutes</value>
<value>15 perc</value>
</data>
<data name="LockOption1Hour" xml:space="preserve">
<value>1 hour</value>
<value>1 óra</value>
</data>
<data name="LockOption1Minute" xml:space="preserve">
<value>1 minute</value>
<value>1 perc</value>
</data>
<data name="LockOption4Hours" xml:space="preserve">
<value>4 hours</value>
<value>4 óra</value>
</data>
<data name="LockOptionImmediately" xml:space="preserve">
<value>Immediately</value>
<value>Azonnal</value>
</data>
<data name="LockOptions" xml:space="preserve">
<value>Lock Options</value>
<value>Zárolási beállítások</value>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Logging in...</value>
<value>Bejelentkezés...</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="LoginOrCreateNewAccount" xml:space="preserve">
<value>Log in or create a new account to access your secure vault.</value>
<value>Jelentkezz be vagy készíts új fiókot a biztonsági széfed eléréshez.</value>
</data>
<data name="Manage" xml:space="preserve">
<value>Manage</value>
<value>Kezelés</value>
</data>
<data name="MasterPasswordConfirmationValMessage" xml:space="preserve">
<value>Password confirmation is not correct.</value>
<value>A megadott két jelszó nem egyezik.</value>
</data>
<data name="MasterPasswordDescription" xml:space="preserve">
<value>The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it.</value>
<value>A mesterjelszó az a jelszó amit a széfed eléréséhez fogsz használni. Nagyon fontos, hogy ne felejtsd el a mesterjelszavad, mert nincs lehetőséged visszaállítani ha elfelejtetted.</value>
</data>
<data name="MasterPasswordHint" xml:space="preserve">
<value>Master Password Hint (optional)</value>
<value>Mesterjelszó emlékeztető (nem kötelező)</value>
</data>
<data name="MasterPasswordHintDescription" xml:space="preserve">
<value>A master password hint can help you remember your password if you forget it.</value>
<value>A mesterjelszó emlékeztető segíthet emlékezni a jelszavadra ha elfejetetted volna.</value>
</data>
<data name="MasterPasswordLengthValMessage" xml:space="preserve">
<value>Master password must be at least 8 characters long.</value>
<value>Mesterjelszónak legalább 8 karakter hosszúnak kell lennie.</value>
</data>
<data name="MinNumbers" xml:space="preserve">
<value>Minimum Numbers</value>
<value>Kevesebb szám</value>
<comment>Minimum numeric characters for password generator settings</comment>
</data>
<data name="MinSpecial" xml:space="preserve">
<value>Minimum Special</value>
<value>Kevesebb különleges karakter</value>
<comment>Minimum special characters for password generator settings</comment>
</data>
<data name="MoreSettings" xml:space="preserve">
<value>More Settings</value>
<value>További beállítások</value>
</data>
<data name="MustLogInMainApp" xml:space="preserve">
<value>You must log into the main bitwarden app before you can use the extension.</value>
<value>A bővítmény használata előtt be kell lépned a bitwarden alkalmazásba.</value>
</data>
<data name="Never" xml:space="preserve">
<value>Never</value>
<value>Soha</value>
</data>
<data name="NewLoginCreated" xml:space="preserve">
<value>New login created.</value>
<value>Új bejelentkezés létrehozva.</value>
</data>
<data name="NoFavorites" xml:space="preserve">
<value>There are no favorites in your vault.</value>
<value>Nincsenek kedvencek a széfedben.</value>
</data>
<data name="NoLogins" xml:space="preserve">
<value>There are no logins in your vault.</value>
<value>Nincsenek bejelentkezések a széfedben.</value>
</data>
<data name="NoLoginsTap" xml:space="preserve">
<value>There are no logins in your vault for this website. Tap to add one.</value>
<value>Ehhez a weboldalhoz nincs bejelentkezés a széfedben. Bökj ide, ha létrehoznál egyet.</value>
</data>
<data name="NoUsernamePasswordConfigured" xml:space="preserve">
<value>This login does not have a username or password configured.</value>
<value>Ehhez a bejelentkezéshez nem lett felhasználónév vagy jelszó beállítva.</value>
</data>
<data name="OkGotIt" xml:space="preserve">
<value>Ok, got it!</value>
<value>Ok, megvan!</value>
<comment>Confirmation, like "Ok, I understand it"</comment>
</data>
<data name="OptionDefaults" xml:space="preserve">
<value>Option defaults are set from the main bitwarden app's password generator tool.</value>
<value>A beállítások alapértelmezései beállítva a fő bitwarden alkalmazás jelszó generátor eszközéből.</value>
</data>
<data name="Options" xml:space="preserve">
<value>Options</value>
<value>Beállítások</value>
</data>
<data name="Other" xml:space="preserve">
<value>Other</value>
<value>Egyéb</value>
</data>
<data name="PasswordGenerated" xml:space="preserve">
<value>Password generated.</value>
<value>Jelszó generálva.</value>
</data>
<data name="PasswordGenerator" xml:space="preserve">
<value>Password Generator</value>
<value>Jelszó generátor</value>
</data>
<data name="PasswordGeneratorDescription" xml:space="preserve">
<value>Automatically generate strong, unique passwords for your logins.</value>
<value>Automatikusan létrehoz erős, egyedi jelszavakat a bejelentkezéseidhez.</value>
</data>
<data name="PasswordHint" xml:space="preserve">
<value>Password Hint</value>
<value>Jelszó emlékeztető</value>
</data>
<data name="PasswordHintAlert" xml:space="preserve">
<value>We've sent you an email with your master password hint.</value>
<value>Elküldtünk neked egy E-mailt mely tartalmazza a mesterjelszó emlékeztetődet.</value>
</data>
<data name="PasswordOverrideAlert" xml:space="preserve">
<value>Are you sure you want to overwrite the current password?</value>
<value>Biztosan felül akarod írni a jelenlegi jelszót?</value>
</data>
<data name="PushNotificationAlert" xml:space="preserve">
<value>bitwarden keeps your vault automatically synced by using push notifications. For the best possible experience, please select "Ok" on the following prompt when asked to enable push notifications.</value>
<value>A bitwarden a push értesítések használatával biztosítja a széfed automatikus szinkronizálását. A lehető legjobb élmény érdekében kérjük, válaszd ki az "Ok" opciót a következő értesítéskor, amikor felkér a push értesítések engedélyezésére.</value>
<comment>Push notifications for apple products</comment>
</data>
<data name="RateTheApp" xml:space="preserve">
<value>Rate the App</value>
<value>Az alkalmazás értékelése</value>
</data>
<data name="RateTheAppDescription" xml:space="preserve">
<value>Please consider helping us out with a good review!</value>
<value>Egy jó értékeléssel mindig segíted a munkánkat!</value>
</data>
<data name="RateTheAppDescriptionAppStore" xml:space="preserve">
<value>App Store ratings are reset with every new version of bitwarden. Please consider helping us out with a good review!</value>
<value>Az App áruházban az értékelések mindig alaphelyzetre állnak egy új verzió megjelenésével. Egy jó értékeléssel mindig segíted a munkánkat!</value>
</data>
<data name="RegeneratePassword" xml:space="preserve">
<value>Regenerate Password</value>
<value>Jelszó újragenerálása</value>
</data>
<data name="RetypeMasterPassword" xml:space="preserve">
<value>Re-type Master Password</value>
<value>Írd be újra a mesterjelszavad</value>
</data>
<data name="SearchVault" xml:space="preserve">
<value>Search vault</value>
<value>Keresés a széfben</value>
</data>
<data name="Security" xml:space="preserve">
<value>Security</value>
<value>Biztonság</value>
</data>
<data name="SeeDevProgress" xml:space="preserve">
<value>See Development Progress</value>
<value>Fejlesztési folyamat megtekintése</value>
</data>
<data name="Select" xml:space="preserve">
<value>Select</value>
<value>Kijelölés</value>
</data>
<data name="SetPIN" xml:space="preserve">
<value>Set PIN</value>
<value>PIN beállítása</value>
</data>
<data name="SetPINDirection" xml:space="preserve">
<value>Enter a 4 digit PIN code to unlock the app with.</value>
<value>Egy 4 számjegyű PIN-kód beállítása az alkalmazás kinyitásához.</value>
</data>
<data name="LoginInformation" xml:space="preserve">
<value>Login Information</value>
<value>Bejelentkezési információk</value>
</data>
<data name="LoginUpdated" xml:space="preserve">
<value>Login updated.</value>
<value>Bejelentkezés frissítve.</value>
</data>
<data name="Submitting" xml:space="preserve">
<value>Submitting...</value>
<value>Küldés...</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="Syncing" xml:space="preserve">
<value>Syncing...</value>
<value>Szinkronizálás...</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="SyncingComplete" xml:space="preserve">
<value>Syncing complete.</value>
<value>Szinkronizálás befejezve.</value>
</data>
<data name="SyncingFailed" xml:space="preserve">
<value>Syncing failed.</value>
<value>Szinkronizáció sikertelen.</value>
</data>
<data name="SyncVaultNow" xml:space="preserve">
<value>Sync Vault Now</value>
<value>Széf szinkronizálása most</value>
</data>
<data name="TouchID" xml:space="preserve">
<value>Touch ID</value>
<comment>What Apple calls their fingerprint reader.</comment>
</data>
<data name="TwoStepLogin" xml:space="preserve">
<value>Two-step Login</value>
<value>Kétlépcsős bejelentkezés</value>
</data>
<data name="TwoStepLoginConfirmation" xml:space="preserve">
<value>Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be enabled on the bitwarden.com web vault. Do you want to visit the website now?</value>
<value>A kétlépcsős bejelentkezés biztonságosabbá teszi a fiókodat azáltal, hogy meg kell erősítened a bejelentkezésedet egy másik eszközzel mint például biztonsági kulcs, hitelesítő alkalmazás, SMS, telefon hívás vagy e-mail. Kétlépcsős bejelentkezést a bitwarden.com webes széfében tudod megváltoztatni. Szeretnéd meglátogatni most a weboldalt?</value>
</data>
<data name="UnlockWith" xml:space="preserve">
<value>Unlock with {0}</value>
<value>Kinyitás ezzel: {0}</value>
</data>
<data name="UnlockWithPIN" xml:space="preserve">
<value>Unlock with PIN Code</value>
<value>Kinyitás PIN-kóddal</value>
</data>
<data name="Validating" xml:space="preserve">
<value>Validating</value>
<value>Hitelesítés</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="VerificationCode" xml:space="preserve">
<value>Verification Code</value>
<value>Hitelesítő kód</value>
</data>
<data name="ViewLogin" xml:space="preserve">
<value>View Login</value>
<value>Bejelentkezés megtekintése</value>
</data>
<data name="WebVault" xml:space="preserve">
<value>bitwarden Web Vault</value>
<value>bitwarden webes széf</value>
</data>
<data name="WebVaultDescription" xml:space="preserve">
<value>Manage your logins from any web browser with the bitwarden web vault.</value>
<value>Kezeld az összes bejelentkezésedet bármely böngészőből a bitwarden webes széfével.</value>
</data>
<data name="Lost2FAApp" xml:space="preserve">
<value>Lost authenticator app?</value>
<value>Elveszett hitelesítő alkalmazás?</value>
</data>
<data name="Logins" xml:space="preserve">
<value>Logins</value>
<value>Bejelentkezések</value>
<comment>Screen title</comment>
</data>
<data name="ExtensionActivated" xml:space="preserve">
<value>Extension Activated!</value>
<value>Kiterjesztés aktiválva!</value>
</data>
<data name="Icons" xml:space="preserve">
<value>Icons</value>
<value>Ikonok</value>
</data>
<data name="Translations" xml:space="preserve">
<value>Translations</value>
<value>Fordítások</value>
</data>
<data name="LoginsForUri" xml:space="preserve">
<value>Logins for {0}</value>
<value>Bejelentkezés ehhez: {0}</value>
<comment>This is used for the autofill service. ex. "Logins for twitter.com"</comment>
</data>
<data name="NoLoginsForUri" xml:space="preserve">
<value>There are no logins in your vault for {0}.</value>
<value>Nincs mentett bejelentkezési adat ehhez: {0}.</value>
<comment>This is used for the autofill service. ex. "There are no logins in your vault for twitter.com".</comment>
</data>
<data name="BitwardenAutofillServiceNotification" xml:space="preserve">
<value>When you see a bitwarden auto-fill notification, you can tap it to launch the auto-fill service.</value>
<value>Ha látsz egy bitwarden auto-kitöltés értesítést, érintsd meg azt az automatikus kitöltési szolgáltatás elindításához.</value>
</data>
<data name="BitwardenAutofillServiceNotificationContent" xml:space="preserve">
<value>Tap this notification to auto-fill a login from your vault.</value>
<value>Az értesítést megéríntétésvel automatikusan kitöltésre kerül egy bejelentkezés a széfedből.</value>
</data>
<data name="BitwardenAutofillServiceOpenSettings" xml:space="preserve">
<value>Open Accessibility Settings</value>
<value>Kisegítő lehetőségek megnyitása</value>
</data>
<data name="BitwardenAutofillServiceStep1" xml:space="preserve">
<value>1. On the Android Accessibility Settings screen, touch "bitwarden" under the Services heading.</value>
<value>1. az Android kisegítő szolgáltatások képernyőn válaszd ki a "bitwarden"-t a Szolgáltatások fejléc alatt.</value>
</data>
<data name="BitwardenAutofillServiceStep2" xml:space="preserve">
<value>2. Switch on the toggle and press OK to accept.</value>
<value>2. A felugró ablakban a jóváhagyáshoz bökj az OK gombra.</value>
</data>
<data name="Disabled" xml:space="preserve">
<value>Disabled</value>
<value>Letiltva</value>
</data>
<data name="Enabled" xml:space="preserve">
<value>Enabled</value>
<value>Engedélyezve</value>
</data>
<data name="Status" xml:space="preserve">
<value>Status</value>
<value>Állapot</value>
</data>
<data name="Beta" xml:space="preserve">
<value>Beta</value>
<value>Béta</value>
</data>
<data name="BitwardenAutofillServiceAlert" 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 "Tools" screen.</value>
<value>A legegyszerűbb módja új bejelentkezési adatok hozzáadásának a bitwarden automatikus kitöltö szolgáltatás. Az automatikus kitöltő szolgáltatás használatáról az "Eszközök" képernyőn tudhatsz meg többet.</value>
</data>
<data name="Autofill" xml:space="preserve">
<value>Auto-fill</value>
<value>Automatikus kitöltés</value>
</data>
<data name="AutofillOrView" xml:space="preserve">
<value>Do you want to auto-fill or view this login?</value>
<value>Szeretnéd automatikusan kitölteni ezt a belentkezést, vagy megnézed inkább?</value>
</data>
<data name="BitwardenAutofillServiceMatchConfirm" xml:space="preserve">
<value>Are you sure you want to auto-fill this login? It is not a complete match for "{0}".</value>
<value>Biztos, hogy automatikusan kitöltöd ezt a bejelentkezést? Nem egyezik teljesen ehhez: {0}.</value>
</data>
<data name="MatchingLogins" xml:space="preserve">
<value>Matching Logins</value>
<value>Egyező bejelentkezések</value>
</data>
<data name="PossibleMatchingLogins" xml:space="preserve">
<value>Possible Matching Logins</value>
<value>Lehetséges bejelentkezések</value>
</data>
<data name="Search" xml:space="preserve">
<value>Search</value>
<value>Keresés</value>
</data>
<data name="BitwardenAutofillServiceSearch" xml:space="preserve">
<value>You are searching for an auto-fill login for "{0}".</value>
<value>Egy bejelentkezést keresel ehhez: "{0}".</value>
</data>
<data name="ShareVault" xml:space="preserve">
<value>Share Your Vault</value>
<value>Széfed megosztása</value>
</data>
<data name="ShareVaultDescription" xml:space="preserve">
<value>Create an organization to securely share your logins with other users.</value>
<value>Hozz létre egy szervezetet, hogy biztonságosan megoszthasd bejelentkezéseidet másokkal.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Analitikát használunk arra, hogy többet többet tudjunk arról hogyan használod az alkalmazást, hogy jobbá tudjuk azt. Az adatok gyűjtése teljesen névtelen.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Features</value>
<value>Funkciók</value>
</data>
<data name="AutofillPasswordField" xml:space="preserve">
<value>Scan When Password Field Focused</value>
<value>Szkennelés, amikor a jelszó mezőre fókuszált</value>
</data>
<data name="AutofillPasswordFieldDescription" xml:space="preserve">
<value>Only scan the screen for fields and offer an auto-fill notification whenever you select a password field. This setting may help conserve battery life.</value>
<value>Csak akkor szkennelje az ablakot és ajánljon automatikus kitöltést, amikor a jelszó mező van kijelölve. Ez a beállítás segíthet megnövelni az akku élettartamát.</value>
</data>
<data name="AutofillPersistNotification" xml:space="preserve">
<value>Persist Notification</value>
<value>Állandó értestés</value>
</data>
<data name="AutofillPersistNotificationDescription" xml:space="preserve">
<value>Always offer an auto-fill notification and only scan for fields after attempting an auto-fill. This setting may help conserve battery life.</value>
<value>Mindig mutatja az automatikus kitöltés értesítést és csak az automatikus kitöltés megkísérlése után szkenneli a mezőket. Ez a beállítás segíthet megnövelni az akku élettartamát.</value>
</data>
<data name="AutofillAlways" xml:space="preserve">
<value>Always Scan</value>
<value>Mindig szkennel</value>
</data>
<data name="AutofillAlwaysDescription" xml:space="preserve">
<value>Always scan the screen for fields and only offer an auto-fill notification if password fields are found. This is the default setting.</value>
<value>Mindig szkenneli a mezőket a képernyőn és csak akkor ajánl automatikus kitöltést, ha jelszó mezőt talál. Ez az alapértelmezett beállítás.</value>
</data>
<data name="CannotOpenApp" xml:space="preserve">
<value>Cannot open the app "{0}".</value>
<value>Nem lehet megnyitni a(z) "{0}" alkalmazást.</value>
<comment>Message shown when trying to launch an app that does not exist on the user's device.</comment>
</data>
<data name="AuthenticatorAppTitle" xml:space="preserve">
<value>Authenticator App</value>
<value>Hitelesítő alkalmazás</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Enter the 6 digit verification code from your authenticator app.</value>
<value>Add meg a 6 számjegyű ellenőrző kódot a hitelesítő alkalmazásodból.</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeEmail" xml:space="preserve">
<value>Enter the 6 digit verification code that was emailed to {0}.</value>
<value>Add meg a 6 számjegyű ellenőrző kódot ami a(z) {0} e-mail címre lett küldve.</value>
<comment>For 2FA</comment>
</data>
<data name="LoginUnavailable" xml:space="preserve">
<value>Login Unavailable</value>
<value>Bejelentkezés nem érhető el</value>
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
<value>This account has two-step login enabled, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app).</value>
<value>Ennél a fióknál a kétlépcsős bejelentkezés engedélyezve lett, azonban a beállított kétlépcsős szolgáltatók egyike sem támogatott ezen az eszközön. Használj támogatott eszközt és/vagy olyan szolgáltatókat, amelyek jobb támogatást élveznek az eszközökön (például egy hitelesítő alkalmazás).</value>
</data>
<data name="RecoveryCodeTitle" xml:space="preserve">
<value>Recovery Code</value>
<value>Helyreállító kód</value>
<comment>For 2FA</comment>
</data>
<data name="RememberMe" xml:space="preserve">
<value>Remember me</value>
<value>Emlékezz rám</value>
<comment>Remember my two-step login</comment>
</data>
<data name="SendVerificationCodeAgain" xml:space="preserve">
<value>Send verification code email again</value>
<value>Megerősítő kód újraküldése email-ben</value>
<comment>For 2FA</comment>
</data>
<data name="TwoStepLoginOptions" xml:space="preserve">
<value>Two-step Login Options</value>
<value>Kétlépcsős bejelentkezés opciók</value>
</data>
<data name="UseAnotherTwoStepMethod" xml:space="preserve">
<value>Use another two-step login method</value>
<value>Más kétlépcsős bejelentkezés használata</value>
</data>
<data name="VerificationEmailNotSent" xml:space="preserve">
<value>Could not send verification email. Try again.</value>
<value>Nem sikerült elküldeni a megerősítő e-mailt. Próbáld újra.</value>
<comment>For 2FA</comment>
</data>
<data name="VerificationEmailSent" xml:space="preserve">
<value>Verification email sent.</value>
<value>Megerősítő e-mail elküldve.</value>
<comment>For 2FA</comment>
</data>
<data name="YubiKeyInstruction" xml:space="preserve">
<value>Hold your YubiKey NEO against the back of the device to continue.</value>
<value>A folytatáshoz tartsd a YubiKey NEO-t a készülék hátuljához.</value>
</data>
<data name="YubiKeyTitle" xml:space="preserve">
<value>YubiKey NEO Security Key</value>
<value>YubiKey NEO biztonsági kulcs</value>
<comment>"YubiKey NEO" is the product name and should not be translated.</comment>
</data>
<data name="AddNewAttachment" xml:space="preserve">
<value>Add New Attachment</value>
<value>Melléklet hozzáadása</value>
</data>
<data name="Attachments" xml:space="preserve">
<value>Attachments</value>
<value>Mellékletek</value>
</data>
<data name="UnableToDownloadFile" xml:space="preserve">
<value>Unable to download file.</value>
<value>Nem lehet letölteni a fájlt.</value>
</data>
<data name="UnableToOpenFile" xml:space="preserve">
<value>Your device cannot open this type of file.</value>
<value>A készülék nem tudja megnyitni az ilyen típusú fájlt.</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
<value>Letöltés...</value>
<comment>Message shown when downloading a file</comment>
</data>
<data name="AttachmentLargeWarning" xml:space="preserve">
<value>This attachment is {0} in size. Are you sure you want to download it onto your device?</value>
<value>Ez a melléklet {0} méretű. Biztosan le akarod tölteni a készülékedre?</value>
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Authenticator Key (TOTP)</value>
<value>Hitelesítő kulcs (egyszeri-idő alapú)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Verification Code (TOTP)</value>
<value>Ellenőrző kód (egyszeri-idő alapú)</value>
<comment>Totp code label</comment>
</data>
<data name="AuthenticatorKeyAdded" xml:space="preserve">
<value>Authenticator key added.</value>
<value>Hitelesítő kulcs hozzáadva.</value>
</data>
<data name="AuthenticatorKeyReadError" xml:space="preserve">
<value>Cannot read authenticator key.</value>
<value>Nem lehet olvasni a hitelesítő kulcsot.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Scanning will happen automatically.</value>
<value>A szkennelés automatikusan megtörténik.</value>
</data>
<data name="CameraInstructionTop" xml:space="preserve">
<value>Point your camera at the QR code.</value>
<value>Irányítsd a kamerát a QR-kódra.</value>
</data>
<data name="ScanQrTitle" xml:space="preserve">
<value>Scan QR Code</value>
<value>QR kód beolvasása</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Kamera</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Képek</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>Egyszeri jelszó másolva!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Egyszeri jelszó másolása</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Ha a bejelentkezésedhez csatolva van egy hitelesítő kód, az egyszeri ellenőrző kód automatikusan másolva lesz a vágólapra a bejelentkezés automatikus kitöltése esetén.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Egyszeri jelszó automatikus másolás tiltása</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>A funkció használatához prémium tagság szükséges.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Melléklet hozzáadva</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Melléklet törölve</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Fájl kiválasztása</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Fájl</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Nincs kiválasztott fájl</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Nincsenek mellékletek.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Fájl forrás</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Ez a funkció nem érhető el</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>Maximális fájl méret 100 MB.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Ez a funkció nem használható, amíg nem frissíted a titkosítási kulcsodat.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Tudj meg többet</value>
</data>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
<value>API szerver URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
<value>Egyéni környezet</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
<value>Haladó felhasználóknak. Minden egyes szolgáltatásnak külön megadhatod az alap URL-t.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
<value>A környezet URL-ek el lettek mentve.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<value>{0} nem megfelelő formátumú.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<value>Identitás szerver URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
<value>Saját üzemeltetésű környezet</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
<value>Add meg az alap URL-t a helyileg üzemeltetett bitwarden telepítéshez.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
<value>Szerver URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
<value>Webes széf szerver URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Az értesítés megérintésével megnézheted a széfedben tárolt bejelentkezéseket.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1028,6 +1028,15 @@
<value>URL-ul serverului seifului web</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Atingeți această notificare pentru a vizualiza autentificările din seiful dvs.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -193,10 +193,10 @@
<value>Напишите нам</value>
</data>
<data name="EmailUsDescription" xml:space="preserve">
<value>Напишите нам на email, чтобы получить помощь или оставить отзыв.</value>
<value>Чтобы получить помощь или оставить отзыв, отправьте нам письмо.</value>
</data>
<data name="EnterPIN" xml:space="preserve">
<value>Введите ваш PIN-код.</value>
<value>Введите PIN-код.</value>
</data>
<data name="Favorites" xml:space="preserve">
<value>Избранное</value>
@@ -474,7 +474,7 @@
<value>Включить автоматическую синхронизацию</value>
</data>
<data name="EnterEmailForHint" xml:space="preserve">
<value>Введите Ваш email для получения подсказки мастер-пароля.</value>
<value>Введите свой email для получения подсказки мастер-пароля.</value>
</data>
<data name="ExntesionReenable" xml:space="preserve">
<value>Повторно включить расширение</value>
@@ -1028,6 +1028,15 @@
<value>URL-адрес сервера веб-хранилища</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Коснитесь этого уведомления, чтобы посмотреть логины из вашего хранилища.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1028,6 +1028,15 @@
<value>Webbvalv server-URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Tryck på den här aviseringen för att visa inloggningar från ditt valv.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -1028,6 +1028,15 @@
<value>URL-адреса сервера веб-сховища</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>Торкніться цього сповіщення для перегляду записів з вашого сховища.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1030,4 +1030,13 @@
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -996,38 +996,47 @@
<value>了解更多</value>
</data>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
<value>API 伺服器 URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
<value>自訂環境</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
<value>適用於進階使用者。你可以單獨指定各個服務的基礎 URL。</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
<value>環境 URL 已儲存。</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<value>{0} 的格式不正確。</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<value>身分伺服器 URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
<value>自我託管的環境</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
<value>指定自己設定、託管的 bitwarden 環境之基礎 URL。</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
<value>伺服器 URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
<value>Web 保存庫伺服器 URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
<value>按此自動填寫來自密碼庫的登入資料。</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -18,7 +18,6 @@ namespace Bit.App.Services
private readonly ILoginRepository _loginRepository;
private readonly IAttachmentRepository _attachmentRepository;
private readonly IAuthService _authService;
private readonly ILoginApiRepository _loginApiRepository;
private readonly ICipherApiRepository _cipherApiRepository;
private readonly ISettingsService _settingsService;
private readonly ICryptoService _cryptoService;
@@ -27,7 +26,6 @@ namespace Bit.App.Services
ILoginRepository loginRepository,
IAttachmentRepository attachmentRepository,
IAuthService authService,
ILoginApiRepository loginApiRepository,
ICipherApiRepository cipherApiRepository,
ISettingsService settingsService,
ICryptoService cryptoService)
@@ -35,7 +33,6 @@ namespace Bit.App.Services
_loginRepository = loginRepository;
_attachmentRepository = attachmentRepository;
_authService = authService;
_loginApiRepository = loginApiRepository;
_cipherApiRepository = cipherApiRepository;
_settingsService = settingsService;
_cryptoService = cryptoService;
@@ -215,18 +212,18 @@ namespace Bit.App.Services
return new Tuple<IEnumerable<Login>, IEnumerable<Login>>(matchingLogins, matchingFuzzyLogins);
}
public async Task<ApiResult<LoginResponse>> SaveAsync(Login login)
public async Task<ApiResult<CipherResponse>> SaveAsync(Login login)
{
ApiResult<LoginResponse> response = null;
var request = new LoginRequest(login);
ApiResult<CipherResponse> response = null;
var request = new CipherRequest(login);
if(login.Id == null)
{
response = await _loginApiRepository.PostAsync(request);
response = await _cipherApiRepository.PostAsync(request);
}
else
{
response = await _loginApiRepository.PutAsync(login.Id, request);
response = await _cipherApiRepository.PutAsync(login.Id, request);
}
if(response.Succeeded)
@@ -253,7 +250,7 @@ namespace Bit.App.Services
public async Task<ApiResult> DeleteAsync(string id)
{
var response = await _loginApiRepository.DeleteAsync(id);
var response = await _cipherApiRepository.DeleteAsync(id);
if(response.Succeeded)
{
await _loginRepository.DeleteAsync(id);

View File

@@ -16,9 +16,9 @@ namespace Bit.App.Services
{
private readonly ICipherApiRepository _cipherApiRepository;
private readonly IFolderApiRepository _folderApiRepository;
private readonly ILoginApiRepository _loginApiRepository;
private readonly IAccountsApiRepository _accountsApiRepository;
private readonly ISettingsApiRepository _settingsApiRepository;
private readonly ISyncApiRepository _syncApiRepository;
private readonly IFolderRepository _folderRepository;
private readonly ILoginRepository _loginRepository;
private readonly IAttachmentRepository _attachmentRepository;
@@ -31,9 +31,9 @@ namespace Bit.App.Services
public SyncService(
ICipherApiRepository cipherApiRepository,
IFolderApiRepository folderApiRepository,
ILoginApiRepository loginApiRepository,
IAccountsApiRepository accountsApiRepository,
ISettingsApiRepository settingsApiRepository,
ISyncApiRepository syncApiRepository,
IFolderRepository folderRepository,
ILoginRepository loginRepository,
IAttachmentRepository attachmentRepository,
@@ -45,9 +45,9 @@ namespace Bit.App.Services
{
_cipherApiRepository = cipherApiRepository;
_folderApiRepository = folderApiRepository;
_loginApiRepository = loginApiRepository;
_accountsApiRepository = accountsApiRepository;
_settingsApiRepository = settingsApiRepository;
_syncApiRepository = syncApiRepository;
_folderRepository = folderRepository;
_loginRepository = loginRepository;
_attachmentRepository = attachmentRepository;
@@ -268,29 +268,23 @@ namespace Bit.App.Services
var now = DateTime.UtcNow;
// Just check profile first to make sure we'll have a success with the API
var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false);
if(!CheckSuccess(profile, !string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
_appSettingsService.SecurityStamp != profile.Result.SecurityStamp))
var syncResponse = await _syncApiRepository.Get();
if(!CheckSuccess(syncResponse,
!string.IsNullOrWhiteSpace(_appSettingsService.SecurityStamp) &&
syncResponse.Result?.Profile != null &&
_appSettingsService.SecurityStamp != syncResponse.Result.Profile.SecurityStamp))
{
return false;
}
var ciphers = await _cipherApiRepository.GetAsync().ConfigureAwait(false);
var folders = await _folderApiRepository.GetAsync().ConfigureAwait(false);
var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false);
if(!CheckSuccess(ciphers) || !CheckSuccess(folders) || !CheckSuccess(domains))
{
return false;
}
var loginsDict = ciphers.Result.Data.Where(c => c.Type == Enums.CipherType.Login).ToDictionary(s => s.Id);
var foldersDict = folders.Result.Data.ToDictionary(f => f.Id);
var loginsDict = syncResponse.Result.Ciphers.Where(c => c.Type == Enums.CipherType.Login)
.ToDictionary(s => s.Id);
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
var loginTask = SyncLoginsAsync(loginsDict);
var folderTask = SyncFoldersAsync(foldersDict);
var domainsTask = SyncDomainsAsync(domains.Result);
var profileTask = SyncProfileKeysAsync(profile.Result);
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile);
await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false);
if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null ||
@@ -436,6 +430,11 @@ namespace Bit.App.Services
private async Task SyncDomainsAsync(DomainsResponse serverDomains)
{
if(serverDomains == null)
{
return;
}
var eqDomains = new List<IEnumerable<string>>();
if(serverDomains.EquivalentDomains != null)
{
@@ -460,6 +459,11 @@ namespace Bit.App.Services
private Task SyncProfileKeysAsync(ProfileResponse profile)
{
if(profile == null)
{
return Task.FromResult(0);
}
if(!string.IsNullOrWhiteSpace(profile.Key))
{
_cryptoService.SetEncKey(new CipherString(profile.Key));

View File

@@ -15,7 +15,7 @@ namespace Bit.App
if(!string.IsNullOrWhiteSpace(tokenService.Token))
{
Headers.Add("Authorization", $"Bearer3 {tokenService.Token}");
Headers.Add("Authorization", $"Bearer {tokenService.Token}");
}
if(!string.IsNullOrWhiteSpace(appIdService.AppId))
{

View File

@@ -11,11 +11,11 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.10.0</string>
<string>1.11.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>18</string>
<string>20</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>

View File

@@ -20,6 +20,7 @@ using Bit.App.Resources;
using Bit.iOS.Core.Controllers;
using SimpleInjector;
using XLabs.Ioc.SimpleInjectorContainer;
using System.Collections.Generic;
namespace Bit.iOS.Extension
{
@@ -191,12 +192,13 @@ namespace Bit.iOS.Extension
}
}
public void CompleteUsernamePasswordRequest(string username, string password, string totp)
public void CompleteUsernamePasswordRequest(string username, string password,
List<Tuple<string, string>> fields, string totp)
{
NSDictionary itemData = null;
if(_context.ProviderType == UTType.PropertyList)
{
var fillScript = new FillScript(_context.Details, username, password);
var fillScript = new FillScript(_context.Details, username, password, fields);
var scriptJson = JsonConvert.SerializeObject(fillScript, _jsonSettings);
var scriptDict = new NSDictionary(Constants.AppExtensionWebViewPageFillScript, scriptJson);
itemData = new NSDictionary(NSJavaScriptExtension.FinalizeArgumentKey, scriptDict);
@@ -210,7 +212,7 @@ namespace Bit.iOS.Extension
else if(_context.ProviderType == Constants.UTTypeAppExtensionFillBrowserAction
|| _context.ProviderType == Constants.UTTypeAppExtensionFillWebViewAction)
{
var fillScript = new FillScript(_context.Details, username, password);
var fillScript = new FillScript(_context.Details, username, password, fields);
var scriptJson = JsonConvert.SerializeObject(fillScript, _jsonSettings);
itemData = new NSDictionary(Constants.AppExtensionWebViewPageFillScript, scriptJson);
}
@@ -258,7 +260,7 @@ namespace Bit.iOS.Extension
NSRunLoop.Main.BeginInvokeOnMainThread(() =>
{
Resolver.ResetResolver();
ExtensionContext.CompleteRequest(returningItems, null);
ExtensionContext?.CompleteRequest(returningItems, null);
});
});
}
@@ -294,11 +296,11 @@ namespace Bit.iOS.Extension
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
container.RegisterSingleton<ICipherApiRepository, CipherApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossConnectivity.Current);

View File

@@ -177,7 +177,7 @@ namespace Bit.iOS.Extension
else if(LoadingController != null)
{
LoadingController.CompleteUsernamePasswordRequest(UsernameCell.TextField.Text, PasswordCell.TextField.Text,
null);
null, null);
}
}
else if(saveTask.Result.Errors.Count() > 0)

View File

@@ -207,7 +207,8 @@ namespace Bit.iOS.Extension
totp = GetTotp(item);
}
_controller.LoadingController.CompleteUsernamePasswordRequest(item.Username, item.Password, totp);
_controller.LoadingController.CompleteUsernamePasswordRequest(item.Username, item.Password,
item.Fields.Value, totp);
}
else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Password) ||
!string.IsNullOrWhiteSpace(item.Totp.Value))

View File

@@ -2,12 +2,17 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
namespace Bit.iOS.Extension.Models
{
public class FillScript
{
public FillScript(PageDetails pageDetails, string fillUsername, string fillPassword)
private static string[] _usernameFieldNames = new[]{ "username", "user name", "email",
"email address", "e-mail", "e-mail address", "userid", "user id" };
public FillScript(PageDetails pageDetails, string fillUsername, string fillPassword,
List<Tuple<string, string>> fillFields)
{
if(pageDetails == null)
{
@@ -16,6 +21,35 @@ namespace Bit.iOS.Extension.Models
DocumentUUID = pageDetails.DocumentUUID;
var filledFields = new Dictionary<string, PageDetails.Field>();
if(fillFields?.Any() ?? false)
{
var fieldNames = fillFields.Select(f => f.Item1?.ToLower()).ToArray();
foreach(var field in pageDetails.Fields.Where(f => f.Viewable))
{
if(filledFields.ContainsKey(field.OpId))
{
continue;
}
var matchingIndex = FindMatchingFieldIndex(field, fieldNames);
if(matchingIndex > -1)
{
filledFields.Add(field.OpId, field);
Script.Add(new List<string> { "click_on_opid", field.OpId });
Script.Add(new List<string> { "fill_by_opid", field.OpId, fillFields[matchingIndex].Item2 });
}
}
}
if(string.IsNullOrWhiteSpace(fillPassword))
{
// No password for this login. Maybe they just wanted to auto-fill some custom fields?
SetFillScriptForFocus(filledFields);
return;
}
List<PageDetails.Field> usernames = new List<PageDetails.Field>();
List<PageDetails.Field> passwords = new List<PageDetails.Field>();
@@ -76,38 +110,160 @@ namespace Bit.iOS.Extension.Models
}
}
foreach(var username in usernames)
if(!passwordFields.Any())
{
// No password fields on this page. Let's try to just fuzzy fill the username.
var usernameFieldNamesList = _usernameFieldNames.ToList();
foreach(var f in pageDetails.Fields)
{
if(f.Viewable && (f.Type == "text" || f.Type == "email" || f.Type == "tel") &&
FieldIsFuzzyMatch(f, usernameFieldNamesList))
{
usernames.Add(f);
}
}
}
foreach(var username in usernames.Where(u => !filledFields.ContainsKey(u.OpId)))
{
filledFields.Add(username.OpId, username);
Script.Add(new List<string> { "click_on_opid", username.OpId });
Script.Add(new List<string> { "fill_by_opid", username.OpId, fillUsername });
}
foreach(var password in passwords)
foreach(var password in passwords.Where(p => !filledFields.ContainsKey(p.OpId)))
{
filledFields.Add(password.OpId, password);
Script.Add(new List<string> { "click_on_opid", password.OpId });
Script.Add(new List<string> { "fill_by_opid", password.OpId, fillPassword });
}
if(passwords.Any())
{
AutoSubmit = new Submit { FocusOpId = passwords.First().OpId };
}
SetFillScriptForFocus(filledFields);
}
private PageDetails.Field FindUsernameField(PageDetails pageDetails, PageDetails.Field passwordField, bool canBeHidden,
bool checkForm)
{
return pageDetails.Fields.LastOrDefault(f =>
(!checkForm || f.Form == passwordField.Form)
&& (canBeHidden || f.Viewable)
&& f.ElementNumber < passwordField.ElementNumber
&& (f.Type == "text" || f.Type == "email" || f.Type == "tel"));
PageDetails.Field usernameField = null;
foreach(var f in pageDetails.Fields)
{
if(f.ElementNumber >= passwordField.ElementNumber)
{
break;
}
if((!checkForm || f.Form == passwordField.Form)
&& (canBeHidden || f.Viewable)
&& f.ElementNumber < passwordField.ElementNumber
&& (f.Type == "text" || f.Type == "email" || f.Type == "tel"))
{
usernameField = f;
if(FindMatchingFieldIndex(f, _usernameFieldNames) > -1)
{
// We found an exact match. No need to keep looking.
break;
}
}
}
return usernameField;
}
private int FindMatchingFieldIndex(PageDetails.Field field, string[] names)
{
var matchingIndex = -1;
if(!string.IsNullOrWhiteSpace(field.HtmlId))
{
matchingIndex = Array.IndexOf(names, field.HtmlId.ToLower());
}
if(matchingIndex < 0 && !string.IsNullOrWhiteSpace(field.HtmlName))
{
matchingIndex = Array.IndexOf(names, field.HtmlName.ToLower());
}
if(matchingIndex < 0 && !string.IsNullOrWhiteSpace(field.LabelTag))
{
matchingIndex = Array.IndexOf(names, CleanLabel(field.LabelTag));
}
if(matchingIndex < 0 && !string.IsNullOrWhiteSpace(field.Placeholder))
{
matchingIndex = Array.IndexOf(names, field.Placeholder.ToLower());
}
return matchingIndex;
}
private bool FieldIsFuzzyMatch(PageDetails.Field field, List<string> names)
{
if(!string.IsNullOrWhiteSpace(field.HtmlId) && FuzzyMatch(names, field.HtmlId.ToLower()))
{
return true;
}
if(!string.IsNullOrWhiteSpace(field.HtmlName) && FuzzyMatch(names, field.HtmlName.ToLower()))
{
return true;
}
if(!string.IsNullOrWhiteSpace(field.LabelTag) && FuzzyMatch(names, CleanLabel(field.LabelTag)))
{
return true;
}
if(!string.IsNullOrWhiteSpace(field.Placeholder) && FuzzyMatch(names, field.Placeholder.ToLower()))
{
return true;
}
return false;
}
private bool FuzzyMatch(List<string> options, string value)
{
if((!options?.Any() ?? true) || string.IsNullOrWhiteSpace(value))
{
return false;
}
return options.Any(o => value.Contains(o));
}
private void SetFillScriptForFocus(IDictionary<string, PageDetails.Field> filledFields)
{
if(!filledFields.Any())
{
return;
}
PageDetails.Field lastField = null, lastPasswordField = null;
foreach(var field in filledFields)
{
if(field.Value.Viewable)
{
lastField = field.Value;
if(field.Value.Type == "password")
{
lastPasswordField = field.Value;
}
}
}
// Prioritize password field over others.
if(lastPasswordField != null)
{
Script.Add(new List<string> { "focus_by_opid", lastPasswordField.OpId });
}
else if(lastField != null)
{
Script.Add(new List<string> { "focus_by_opid", lastField.OpId });
}
}
private string CleanLabel(string label)
{
return Regex.Replace(label, @"(?:\r\n|\r|\n)", string.Empty).Trim().ToLower();
}
[JsonProperty(PropertyName = "script")]
public List<List<string>> Script { get; set; } = new List<List<string>>();
[JsonProperty(PropertyName = "autosubmit")]
public Submit AutoSubmit { get; set; }
[JsonProperty(PropertyName = "documentUUID")]
public object DocumentUUID { get; set; }
[JsonProperty(PropertyName = "properties")]
@@ -116,12 +272,5 @@ namespace Bit.iOS.Extension.Models
public object Options { get; set; } = new { animate = false };
[JsonProperty(PropertyName = "metadata")]
public object MetaData { get; set; } = new object();
public class Submit
{
[JsonProperty(PropertyName = "focusOpid")]
public string FocusOpId { get; set; }
}
}
}

View File

@@ -1,5 +1,7 @@
using Bit.App.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Bit.iOS.Extension.Models
{
@@ -13,6 +15,22 @@ namespace Bit.iOS.Extension.Models
Password = login.Password?.Decrypt(login.OrganizationId);
Uri = login.Uri?.Decrypt(login.OrganizationId);
Totp = new Lazy<string>(() => login.Totp?.Decrypt(login.OrganizationId));
Fields = new Lazy<List<Tuple<string, string>>>(() =>
{
if(!login.Fields?.Any() ?? true)
{
return null;
}
var fields = new List<Tuple<string, string>>();
foreach(var field in login.Fields)
{
fields.Add(new Tuple<string, string>(
field.Name?.Decrypt(login.OrganizationId),
field.Value?.Decrypt(login.OrganizationId)));
}
return fields;
});
}
public string Id { get; set; }
@@ -21,5 +39,6 @@ namespace Bit.iOS.Extension.Models
public string Password { get; set; }
public string Uri { get; set; }
public Lazy<string> Totp { get; set; }
public Lazy<List<Tuple<string, string>>> Fields { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -36,6 +37,9 @@ namespace Bit.iOS.Extension.Models
public string HtmlClass { get; set; }
public string LabelRight { get; set; }
public string LabelLeft { get; set; }
[JsonProperty("label-tag")]
public string LabelTag { get; set; }
public string Placeholder { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public bool Disabled { get; set; }

View File

@@ -59,6 +59,7 @@ namespace Bit.iOS
LoadApplication(new App.App(
null,
false,
Resolver.Resolve<IAuthService>(),
Resolver.Resolve<IConnectivity>(),
Resolver.Resolve<IUserDialogs>(),
@@ -276,7 +277,6 @@ namespace Bit.iOS
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
@@ -284,6 +284,7 @@ namespace Bit.iOS
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossConnectivity.Current);

View File

@@ -28,28 +28,11 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string>
<key>CFBundleVersion</key>
<string>18</string>
<key>CFBundleIconFiles</key>
<array>
<string>Icon-72@2x.png</string>
<string>Icon-72.png</string>
<string>Icon@2x.png</string>
<string>Icon.png</string>
<string>Icon-60@2x.png</string>
<string>Icon-76.png</string>
<string>Icon-76@2x.png</string>
<string>Icon-83.5@2x.png</string>
<string>Icon-Small-50@2x.png</string>
<string>Icon-Small-50.png</string>
<string>Icon-Small-40.png</string>
<string>Icon-Small-40@2x.png</string>
<string>Icon-Small.png</string>
<string>Icon-Small@2x.png</string>
</array>
<string>20</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>CFBundleShortVersionString</key>
<string>1.10.0</string>
<string>1.11.0</string>
<key>UIMainStoryboardFile~ipad</key>
<string>LaunchScreen</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
@@ -110,5 +93,9 @@
<string>This app does not require access to the photo library.</string>
<key>NSCameraUsageDescription</key>
<string>Scan QR codes</string>
<key>XSAppIconAssets</key>
<string>Resources/Assets.xcassets/AppIcons.appiconset</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
</dict>
</plist>

View File

@@ -0,0 +1,117 @@
{
"images": [
{
"scale": "2x",
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-40.png"
},
{
"scale": "3x",
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-60.png"
},
{
"scale": "2x",
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-58.png"
},
{
"scale": "3x",
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-87.png"
},
{
"scale": "2x",
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-80.png"
},
{
"scale": "3x",
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-120.png"
},
{
"scale": "2x",
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-120.png"
},
{
"scale": "3x",
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-180.png"
},
{
"scale": "1x",
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-20.png"
},
{
"scale": "2x",
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-40.png"
},
{
"scale": "1x",
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-29.png"
},
{
"scale": "2x",
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-58.png"
},
{
"scale": "1x",
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-40.png"
},
{
"scale": "2x",
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-80.png"
},
{
"scale": "1x",
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-76.png"
},
{
"scale": "2x",
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-152.png"
},
{
"scale": "2x",
"size": "83.5x83.5",
"idiom": "ipad",
"filename": "Icon-167.png"
},
{
"scale": "1x",
"size": "1024x1024",
"idiom": "ios-marketing",
"filename": "Icon-1024.png"
}
],
"properties": {},
"info": {
"version": 1,
"author": "xcode"
}
}

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

View File

Before

Width:  |  Height:  |  Size: 863 B

After

Width:  |  Height:  |  Size: 863 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Some files were not shown because too many files have changed in this diff Show More