Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5501ab9083 | ||
|
|
660a21deb1 | ||
|
|
be7949b909 | ||
|
|
a688656f6d | ||
|
|
62365529cc | ||
|
|
dcea869098 | ||
|
|
634a8702cd | ||
|
|
fee993c309 | ||
|
|
bf76707e92 | ||
|
|
da847f6567 | ||
|
|
7a5d25f2e3 | ||
|
|
bf0dedd447 | ||
|
|
3f7dcc6acf | ||
|
|
2efe8b4186 | ||
|
|
068f5771b2 | ||
|
|
c2b1be288e | ||
|
|
163ad248af | ||
|
|
4598c3d852 | ||
|
|
a1dec131c7 | ||
|
|
133585f46a | ||
|
|
3ea81ce2fb | ||
|
|
590fe211c4 | ||
|
|
78cda03d61 | ||
|
|
e126cbf644 | ||
|
|
cc12ae7712 | ||
|
|
e8486abccf | ||
|
|
15f074a45b | ||
|
|
a426d98e92 | ||
|
|
45d171e0e3 | ||
|
|
5950c33a43 |
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>(),
|
||||
|
||||
@@ -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);
|
||||
|
||||
58
src/Android/MyVaultTileService.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
28
src/Android/Resources/Resource.Designer.cs
generated
@@ -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;
|
||||
|
||||
|
||||
BIN
src/Android/Resources/drawable/shield.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
{
|
||||
}
|
||||
}
|
||||
10
src/App/Abstractions/Repositories/ISyncApiRepository.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
{
|
||||
// Folder deprecated
|
||||
//Folder = 0,
|
||||
Login = 1
|
||||
Login = 1,
|
||||
SecureNote = 2,
|
||||
Card = 3
|
||||
}
|
||||
}
|
||||
|
||||
9
src/App/Enums/FieldType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Enums
|
||||
{
|
||||
public enum FieldType : byte
|
||||
{
|
||||
Text = 0,
|
||||
Hidden = 1,
|
||||
Boolean = 2
|
||||
}
|
||||
}
|
||||
11
src/App/Models/Api/CipherDataModel.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
11
src/App/Models/Api/FieldDataModel.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class FolderDataModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
63
src/App/Models/Api/Request/CipherRequest.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
12
src/App/Models/Api/Response/SyncResponse.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
248
src/App/Pages/Vault/VaultCustomFieldsPage.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,6 @@ namespace Bit.App.Repositories
|
||||
: base(connectivity, httpService, tokenService)
|
||||
{ }
|
||||
|
||||
protected override string ApiRoute => "/folders";
|
||||
protected override string ApiRoute => "folders";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
63
src/App/Repositories/SyncApiRepository.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
27
src/App/Resources/AppResources.Designer.cs
generated
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
0
src/App/Resources/AppResources.da.Designer.cs
generated
Normal file
1042
src/App/Resources/AppResources.da.resx
Normal 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
0
src/App/Resources/AppResources.vi.Designer.cs
generated
Normal file
1042
src/App/Resources/AppResources.vi.resx
Normal 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 800 B |
|
Before Width: | Height: | Size: 863 B After Width: | Height: | Size: 863 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |