diff --git a/src/App/Pages/Vault/CipherAddEditPage.xaml b/src/App/Pages/Vault/CipherAddEditPage.xaml
index ec28d128a..7785457b0 100644
--- a/src/App/Pages/Vault/CipherAddEditPage.xaml
+++ b/src/App/Pages/Vault/CipherAddEditPage.xaml
@@ -12,6 +12,7 @@
xmlns:dts="clr-namespace:Bit.App.Lists.DataTemplateSelectors"
xmlns:il="clr-namespace:Bit.App.Lists.ItemLayouts.CustomFields"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
+ xmlns:appResources="clr-namespace:Bit.App.Resources"
x:DataType="pages:CipherAddEditPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -28,6 +29,8 @@
+
+
diff --git a/src/App/Pages/Vault/CipherDetailsPage.xaml b/src/App/Pages/Vault/CipherDetailsPage.xaml
index e95c2add4..467be7a77 100644
--- a/src/App/Pages/Vault/CipherDetailsPage.xaml
+++ b/src/App/Pages/Vault/CipherDetailsPage.xaml
@@ -11,6 +11,7 @@
xmlns:dts="clr-namespace:Bit.App.Lists.DataTemplateSelectors"
xmlns:il="clr-namespace:Bit.App.Lists.ItemLayouts.CustomFields"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
+ xmlns:appResources="clr-namespace:Bit.App.Resources"
x:DataType="pages:CipherDetailsPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -23,6 +24,7 @@
+
+ IsVisible="{Binding Cipher.Login.MainFido2Credential, Converter={StaticResource notNull}, FallbackValue=False}" />
diff --git a/src/App/Utilities/DateTimeConverter.cs b/src/App/Utilities/DateTimeConverter.cs
index cd8f2cec4..499429028 100644
--- a/src/App/Utilities/DateTimeConverter.cs
+++ b/src/App/Utilities/DateTimeConverter.cs
@@ -7,6 +7,8 @@ namespace Bit.App.Utilities
{
public class DateTimeConverter : IValueConverter
{
+ public string Format { get; set; } = "{0} {1}";
+
private readonly ILocalizeService _localizeService;
public DateTimeConverter()
@@ -26,7 +28,7 @@ namespace Bit.App.Utilities
return string.Empty;
}
var d = ((DateTime)value).ToLocalTime();
- return string.Format("{0} {1}",
+ return string.Format(Format,
_localizeService.GetLocaleShortDate(d),
_localizeService.GetLocaleShortTime(d));
}
diff --git a/src/Core/Models/Api/Fido2CredentialApi.cs b/src/Core/Models/Api/Fido2CredentialApi.cs
index 8ebc63dbf..7953e06a1 100644
--- a/src/Core/Models/Api/Fido2CredentialApi.cs
+++ b/src/Core/Models/Api/Fido2CredentialApi.cs
@@ -1,4 +1,5 @@
-using Bit.Core.Models.Domain;
+using System;
+using Bit.Core.Models.Domain;
namespace Bit.Core.Models.Api
{
@@ -21,6 +22,7 @@ namespace Bit.Core.Models.Api
UserHandle = fido2Key.UserHandle?.EncryptedString;
UserName = fido2Key.UserName?.EncryptedString;
Counter = fido2Key.Counter?.EncryptedString;
+ CreationDate = fido2Key.CreationDate;
}
public string CredentialId { get; set; }
@@ -34,5 +36,6 @@ namespace Bit.Core.Models.Api
public string UserHandle { get; set; }
public string UserName { get; set; }
public string Counter { get; set; }
+ public DateTime CreationDate { get; set; }
}
}
diff --git a/src/Core/Models/Data/Fido2CredentialData.cs b/src/Core/Models/Data/Fido2CredentialData.cs
index 2e63e7aa5..846df59f4 100644
--- a/src/Core/Models/Data/Fido2CredentialData.cs
+++ b/src/Core/Models/Data/Fido2CredentialData.cs
@@ -1,4 +1,5 @@
-using Bit.Core.Models.Api;
+using System;
+using Bit.Core.Models.Api;
namespace Bit.Core.Models.Data
{
@@ -19,6 +20,7 @@ namespace Bit.Core.Models.Data
UserHandle = apiData.UserHandle;
UserName = apiData.UserName;
Counter = apiData.Counter;
+ CreationDate = apiData.CreationDate;
}
public string CredentialId { get; set; }
@@ -32,5 +34,6 @@ namespace Bit.Core.Models.Data
public string UserHandle { get; set; }
public string UserName { get; set; }
public string Counter { get; set; }
+ public DateTime CreationDate { get; set; }
}
}
diff --git a/src/Core/Models/Domain/Fido2Credential.cs b/src/Core/Models/Domain/Fido2Credential.cs
index b606aa0dd..7c6928204 100644
--- a/src/Core/Models/Domain/Fido2Credential.cs
+++ b/src/Core/Models/Domain/Fido2Credential.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.View;
@@ -7,7 +9,7 @@ namespace Bit.Core.Models.Domain
{
public class Fido2Credential : Domain
{
- public static HashSet EncryptableProperties => new HashSet
+ public static HashSet EncryptablePropertiesToMap => new HashSet
{
nameof(CredentialId),
nameof(Discoverable),
@@ -22,11 +24,18 @@ namespace Bit.Core.Models.Domain
nameof(Counter)
};
+ public static HashSet NonEncryptablePropertiesToMap => new HashSet
+ {
+ nameof(CreationDate)
+ };
+
+ public static HashSet AllPropertiesToMap => new HashSet(EncryptablePropertiesToMap.Concat(NonEncryptablePropertiesToMap));
+
public Fido2Credential() { }
public Fido2Credential(Fido2CredentialData data, bool alreadyEncrypted = false)
{
- BuildDomainModel(this, data, EncryptableProperties, alreadyEncrypted);
+ BuildDomainModel(this, data, AllPropertiesToMap, alreadyEncrypted, NonEncryptablePropertiesToMap);
}
public EncString CredentialId { get; set; }
@@ -40,16 +49,17 @@ namespace Bit.Core.Models.Domain
public EncString UserHandle { get; set; }
public EncString UserName { get; set; }
public EncString Counter { get; set; }
+ public DateTime CreationDate { get; set; }
public async Task DecryptAsync(string orgId, SymmetricCryptoKey key = null)
{
- return await DecryptObjAsync(new Fido2CredentialView(), this, EncryptableProperties, orgId, key);
+ return await DecryptObjAsync(new Fido2CredentialView(this), this, EncryptablePropertiesToMap, orgId, key);
}
public Fido2CredentialData ToFido2CredentialData()
{
var data = new Fido2CredentialData();
- BuildDataModel(this, data, EncryptableProperties);
+ BuildDataModel(this, data, AllPropertiesToMap, NonEncryptablePropertiesToMap);
return data;
}
}
diff --git a/src/Core/Models/View/Fido2CredentialView.cs b/src/Core/Models/View/Fido2CredentialView.cs
index 390a3bf7d..049d82047 100644
--- a/src/Core/Models/View/Fido2CredentialView.cs
+++ b/src/Core/Models/View/Fido2CredentialView.cs
@@ -1,10 +1,21 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using Bit.Core.Enums;
+using Bit.Core.Models.Domain;
namespace Bit.Core.Models.View
{
public class Fido2CredentialView : ItemView, ILaunchableView
{
+ public Fido2CredentialView()
+ {
+ }
+
+ public Fido2CredentialView(Fido2Credential fido2Credential)
+ {
+ CreationDate = fido2Credential.CreationDate;
+ }
+
public string CredentialId { get; set; }
public string Discoverable { get; set; }
public string KeyType { get; set; } = Constants.DefaultFido2CredentialType;
@@ -16,6 +27,7 @@ namespace Bit.Core.Models.View
public string UserHandle { get; set; }
public string UserName { get; set; }
public string Counter { get; set; }
+ public DateTime CreationDate { get; set; }
public override string SubTitle => UserName;
public override List> LinkedFieldOptions => new List>();
diff --git a/src/Core/Services/CipherService.cs b/src/Core/Services/CipherService.cs
index e3d59d195..c17c172e7 100644
--- a/src/Core/Services/CipherService.cs
+++ b/src/Core/Services/CipherService.cs
@@ -1161,8 +1161,11 @@ namespace Bit.Core.Services
cipher.Login.Fido2Credentials = new List();
foreach (var fido2Credential in model.Login.Fido2Credentials)
{
- var fido2CredentialDomain = new Fido2Credential();
- await EncryptObjPropertyAsync(fido2Credential, fido2CredentialDomain, Fido2Credential.EncryptableProperties, key);
+ var fido2CredentialDomain = new Fido2Credential
+ {
+ CreationDate = fido2Credential.CreationDate
+ };
+ await EncryptObjPropertyAsync(fido2Credential, fido2CredentialDomain, Fido2Credential.EncryptablePropertiesToMap, key);
cipher.Login.Fido2Credentials.Add(fido2CredentialDomain);
}
}