sync and display custom fields for login
This commit is contained in:
parent
cc12ae7712
commit
e126cbf644
|
@ -87,6 +87,7 @@
|
||||||
<Compile Include="Controls\PinControl.cs" />
|
<Compile Include="Controls\PinControl.cs" />
|
||||||
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
|
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
|
||||||
<Compile Include="Controls\VaultListViewCell.cs" />
|
<Compile Include="Controls\VaultListViewCell.cs" />
|
||||||
|
<Compile Include="Enums\FieldType.cs" />
|
||||||
<Compile Include="Enums\TwoFactorProviderType.cs" />
|
<Compile Include="Enums\TwoFactorProviderType.cs" />
|
||||||
<Compile Include="Enums\EncryptionType.cs" />
|
<Compile Include="Enums\EncryptionType.cs" />
|
||||||
<Compile Include="Enums\OrganizationUserType.cs" />
|
<Compile Include="Enums\OrganizationUserType.cs" />
|
||||||
|
@ -98,7 +99,8 @@
|
||||||
<Compile Include="Abstractions\Services\ILocalizeService.cs" />
|
<Compile Include="Abstractions\Services\ILocalizeService.cs" />
|
||||||
<Compile Include="Models\Api\ApiError.cs" />
|
<Compile Include="Models\Api\ApiError.cs" />
|
||||||
<Compile Include="Models\Api\ApiResult.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\DeviceTokenRequest.cs" />
|
||||||
<Compile Include="Models\Api\Request\FolderRequest.cs" />
|
<Compile Include="Models\Api\Request\FolderRequest.cs" />
|
||||||
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
|
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
|
||||||
|
@ -123,6 +125,7 @@
|
||||||
<Compile Include="Models\CipherString.cs" />
|
<Compile Include="Models\CipherString.cs" />
|
||||||
<Compile Include="Models\Data\AttachmentData.cs" />
|
<Compile Include="Models\Data\AttachmentData.cs" />
|
||||||
<Compile Include="Models\Attachment.cs" />
|
<Compile Include="Models\Attachment.cs" />
|
||||||
|
<Compile Include="Models\Field.cs" />
|
||||||
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
|
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
|
||||||
<Compile Include="Models\SymmetricCryptoKey.cs" />
|
<Compile Include="Models\SymmetricCryptoKey.cs" />
|
||||||
<Compile Include="Models\Data\SettingsData.cs" />
|
<Compile Include="Models\Data\SettingsData.cs" />
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
{
|
{
|
||||||
// Folder deprecated
|
// Folder deprecated
|
||||||
//Folder = 0,
|
//Folder = 0,
|
||||||
Login = 1
|
Login = 1,
|
||||||
|
SecureNote = 2,
|
||||||
|
Card = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Bit.App.Enums
|
||||||
|
{
|
||||||
|
public enum FieldType : byte
|
||||||
|
{
|
||||||
|
Text = 0,
|
||||||
|
Hidden = 1,
|
||||||
|
Boolean = 2
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
namespace Bit.App.Models.Api
|
||||||
{
|
{
|
||||||
public class LoginDataModel
|
public class LoginDataModel : CipherDataModel
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
public string Notes { get; set; }
|
|
||||||
public string Totp { get; set; }
|
public string Totp { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
using SQLite;
|
using SQLite;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Bit.App.Models.Data
|
namespace Bit.App.Models.Data
|
||||||
{
|
{
|
||||||
|
@ -11,23 +13,6 @@ namespace Bit.App.Models.Data
|
||||||
public LoginData()
|
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(CipherResponse cipher, string userId)
|
public LoginData(CipherResponse cipher, string userId)
|
||||||
{
|
{
|
||||||
if(cipher.Type != Enums.CipherType.Login)
|
if(cipher.Type != Enums.CipherType.Login)
|
||||||
|
@ -51,6 +36,15 @@ namespace Bit.App.Models.Data
|
||||||
Edit = cipher.Edit;
|
Edit = cipher.Edit;
|
||||||
OrganizationUseTotp = cipher.OrganizationUseTotp;
|
OrganizationUseTotp = cipher.OrganizationUseTotp;
|
||||||
RevisionDateTime = cipher.RevisionDate;
|
RevisionDateTime = cipher.RevisionDate;
|
||||||
|
|
||||||
|
if(data.Fields != null && data.Fields.Any())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Fields = JsonConvert.SerializeObject(data.Fields);
|
||||||
|
}
|
||||||
|
catch(JsonSerializationException) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
@ -65,6 +59,7 @@ namespace Bit.App.Models.Data
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
public string Notes { get; set; }
|
public string Notes { get; set; }
|
||||||
public string Totp { get; set; }
|
public string Totp { get; set; }
|
||||||
|
public string Fields { get; set; }
|
||||||
public bool Favorite { get; set; }
|
public bool Favorite { get; set; }
|
||||||
public bool Edit { get; set; }
|
public bool Edit { get; set; }
|
||||||
public bool OrganizationUseTotp { get; set; }
|
public bool OrganizationUseTotp { get; set; }
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
using Bit.App.Enums;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class 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.Api;
|
||||||
using Bit.App.Models.Data;
|
using Bit.App.Models.Data;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -26,6 +27,16 @@ namespace Bit.App.Models
|
||||||
Edit = data.Edit;
|
Edit = data.Edit;
|
||||||
OrganizationUseTotp = data.OrganizationUseTotp;
|
OrganizationUseTotp = data.OrganizationUseTotp;
|
||||||
Attachments = attachments?.Select(a => new Attachment(a));
|
Attachments = 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; }
|
public string Id { get; set; }
|
||||||
|
@ -38,14 +49,10 @@ namespace Bit.App.Models
|
||||||
public CipherString Password { get; set; }
|
public CipherString Password { get; set; }
|
||||||
public CipherString Notes { get; set; }
|
public CipherString Notes { get; set; }
|
||||||
public CipherString Totp { get; set; }
|
public CipherString Totp { get; set; }
|
||||||
|
public IEnumerable<Field> Fields { get; set; }
|
||||||
public bool Favorite { get; set; }
|
public bool Favorite { get; set; }
|
||||||
public bool Edit { get; set; }
|
public bool Edit { get; set; }
|
||||||
public bool OrganizationUseTotp { get; set; }
|
public bool OrganizationUseTotp { get; set; }
|
||||||
public IEnumerable<Attachment> Attachments { get; set; }
|
public IEnumerable<Attachment> Attachments { get; set; }
|
||||||
|
|
||||||
public LoginData ToLoginData(string userId)
|
|
||||||
{
|
|
||||||
return new LoginData(this, userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.ComponentModel;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Bit.App.Enums;
|
||||||
|
|
||||||
namespace Bit.App.Models.Page
|
namespace Bit.App.Models.Page
|
||||||
{
|
{
|
||||||
|
@ -17,6 +18,7 @@ namespace Bit.App.Models.Page
|
||||||
private int _totpSec = 30;
|
private int _totpSec = 30;
|
||||||
private bool _revealPassword;
|
private bool _revealPassword;
|
||||||
private List<Attachment> _attachments;
|
private List<Attachment> _attachments;
|
||||||
|
private List<Field> _fields;
|
||||||
|
|
||||||
public VaultViewLoginPageModel() { }
|
public VaultViewLoginPageModel() { }
|
||||||
|
|
||||||
|
@ -144,12 +146,10 @@ namespace Bit.App.Models.Page
|
||||||
_revealPassword = value;
|
_revealPassword = value;
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText)));
|
|
||||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideImage)));
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideImage)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string MaskedPassword => RevealPassword ? Password : Password == null ? null : new string('●', Password.Length);
|
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 ImageSource ShowHideImage => RevealPassword ? ImageSource.FromFile("eye_slash") : ImageSource.FromFile("eye");
|
||||||
|
|
||||||
public string TotpCode
|
public string TotpCode
|
||||||
|
@ -189,6 +189,18 @@ namespace Bit.App.Models.Page
|
||||||
}
|
}
|
||||||
public bool ShowAttachments => (Attachments?.Count ?? 0) > 0;
|
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)
|
public void Update(Login login)
|
||||||
{
|
{
|
||||||
Name = login.Name?.Decrypt(login.OrganizationId);
|
Name = login.Name?.Decrypt(login.OrganizationId);
|
||||||
|
@ -217,6 +229,25 @@ namespace Bit.App.Models.Page
|
||||||
{
|
{
|
||||||
login.Attachments = null;
|
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
|
public class Attachment
|
||||||
|
@ -227,5 +258,26 @@ namespace Bit.App.Models.Page
|
||||||
public long Size { get; set; }
|
public long Size { get; set; }
|
||||||
public string Url { 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; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ using Bit.App.Utilities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Bit.App.Enums;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -39,12 +40,14 @@ namespace Bit.App.Pages
|
||||||
private TableSection LoginInformationSection { get; set; }
|
private TableSection LoginInformationSection { get; set; }
|
||||||
private TableSection NotesSection { get; set; }
|
private TableSection NotesSection { get; set; }
|
||||||
private TableSection AttachmentsSection { get; set; }
|
private TableSection AttachmentsSection { get; set; }
|
||||||
|
private TableSection FieldsSection { get; set; }
|
||||||
public LabeledValueCell UsernameCell { get; set; }
|
public LabeledValueCell UsernameCell { get; set; }
|
||||||
public LabeledValueCell PasswordCell { get; set; }
|
public LabeledValueCell PasswordCell { get; set; }
|
||||||
public LabeledValueCell UriCell { get; set; }
|
public LabeledValueCell UriCell { get; set; }
|
||||||
public LabeledValueCell NotesCell { get; set; }
|
public LabeledValueCell NotesCell { get; set; }
|
||||||
public LabeledValueCell TotpCodeCell { get; set; }
|
public LabeledValueCell TotpCodeCell { get; set; }
|
||||||
private EditLoginToolBarItem EditItem { get; set; }
|
private EditLoginToolBarItem EditItem { get; set; }
|
||||||
|
public List<LabeledValueCell> FieldsCells { get; set; }
|
||||||
public List<AttachmentViewCell> AttachmentCells { get; set; }
|
public List<AttachmentViewCell> AttachmentCells { get; set; }
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
|
@ -255,6 +258,53 @@ namespace Bit.App.Pages
|
||||||
Table.Root.Add(AttachmentsSection);
|
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)
|
||||||
|
{
|
||||||
|
LabeledValueCell fieldCell;
|
||||||
|
ExtendedButton copyButton = null;
|
||||||
|
switch(field.Type)
|
||||||
|
{
|
||||||
|
case FieldType.Text:
|
||||||
|
fieldCell = new LabeledValueCell(field.Name, field.Value, AppResources.Copy);
|
||||||
|
copyButton = fieldCell.Button1;
|
||||||
|
break;
|
||||||
|
case FieldType.Hidden:
|
||||||
|
fieldCell = new LabeledValueCell(field.Name, field.MaskedValue, string.Empty, AppResources.Copy);
|
||||||
|
copyButton = fieldCell.Button2;
|
||||||
|
fieldCell.Value.FontFamily =
|
||||||
|
Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
|
||||||
|
if(Device.RuntimePlatform == Device.iOS)
|
||||||
|
{
|
||||||
|
fieldCell.Button1.Margin = new Thickness(10, 0);
|
||||||
|
}
|
||||||
|
// TODO: show/hide image toggle
|
||||||
|
break;
|
||||||
|
case FieldType.Boolean:
|
||||||
|
fieldCell = new LabeledValueCell(field.Name, field.Value == "true" ? "✓" : "-");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCell.Value.LineBreakMode = LineBreakMode.WordWrap;
|
||||||
|
if(copyButton != null)
|
||||||
|
{
|
||||||
|
copyButton.Command = new Command(() => Copy(field.Value, field.Name));
|
||||||
|
copyButton.WidthRequest = 59;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldsSection.Add(fieldCell);
|
||||||
|
}
|
||||||
|
Table.Root.Add(FieldsSection);
|
||||||
|
}
|
||||||
|
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,8 +372,8 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
private void Copy(string copyText, string alertLabel)
|
private void Copy(string copyText, string alertLabel)
|
||||||
{
|
{
|
||||||
_deviceActionService.CopyToClipboard(copyText);
|
_deviceActionService.CopyToClipboard(copyText);
|
||||||
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TotpTick(string totpKey)
|
private void TotpTick(string totpKey)
|
||||||
|
|
|
@ -718,6 +718,15 @@ 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>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Delete.
|
/// Looks up a localized string similar to Delete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1030,4 +1030,7 @@
|
||||||
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
|
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
|
||||||
<value>Tap this notification to view logins from your vault.</value>
|
<value>Tap this notification to view logins from your vault.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CustomFields" xml:space="preserve">
|
||||||
|
<value>Custom Fields</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
Loading…
Reference in New Issue