mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-05-18 21:40:41 -04:00
Add NordPass import method (#1474)
This commit is contained in:
committed by
Leendert de Borst
parent
d44319feaf
commit
215835340a
@@ -0,0 +1,25 @@
|
||||
@using AliasVault.ImportExport.Models
|
||||
@using AliasVault.ImportExport.Importers
|
||||
@using Microsoft.Extensions.Localization
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject GlobalNotificationService GlobalNotificationService
|
||||
@inject IStringLocalizerFactory LocalizerFactory
|
||||
@inject ILogger<ImportServiceNordPass> Logger
|
||||
|
||||
<ImportServiceCard
|
||||
ServiceName="NordPass"
|
||||
Description="@Localizer["NordPassDescription"]"
|
||||
LogoUrl="img/importers/nordpass.svg"
|
||||
ProcessFileCallback="ProcessFile">
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">@Localizer["NordPassInstructionsPart1"]</p>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">@Localizer["NordPassInstructionsPart2"]</p>
|
||||
</ImportServiceCard>
|
||||
|
||||
@code {
|
||||
private IStringLocalizer Localizer => LocalizerFactory.Create("Components.Main.Settings.ImportExport.ImportServices", "AliasVault.Client");
|
||||
|
||||
private static async Task<List<ImportedCredential>> ProcessFile(string fileContents)
|
||||
{
|
||||
return await NordPassImporter.ImportFromCsvAsync(fileContents);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
<ImportServiceKeePass />
|
||||
<ImportServiceKeePassXC />
|
||||
<ImportServiceLastPass />
|
||||
<ImportServiceNordPass />
|
||||
<ImportServiceProtonPass />
|
||||
<ImportServiceStrongbox />
|
||||
<ImportServiceAliasVault />
|
||||
|
||||
@@ -191,6 +191,19 @@
|
||||
<value>Once you have exported the file, you can upload it below.</value>
|
||||
<comment>KeePassXC export instructions part 2</comment>
|
||||
</data>
|
||||
<!-- NordPass -->
|
||||
<data name="NordPassDescription" xml:space="preserve">
|
||||
<value>Import passwords from NordPass</value>
|
||||
<comment>Description for NordPass import service</comment>
|
||||
</data>
|
||||
<data name="NordPassInstructionsPart1" xml:space="preserve">
|
||||
<value>In order to import your NordPass passwords, you need to export them as a CSV file. You can do this by opening the NordPass app or web vault, going to 'Settings' > 'Export Items', and selecting the CSV format.</value>
|
||||
<comment>NordPass export instructions part 1</comment>
|
||||
</data>
|
||||
<data name="NordPassInstructionsPart2" xml:space="preserve">
|
||||
<value>Once you have exported the file, you can upload it below.</value>
|
||||
<comment>NordPass export instructions part 2</comment>
|
||||
</data>
|
||||
<!-- Proton Pass -->
|
||||
<data name="ProtonPassDescription" xml:space="preserve">
|
||||
<value>Import passwords from Proton Pass</value>
|
||||
|
||||
@@ -2712,6 +2712,11 @@ video {
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.hover\:border-gray-300:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:border-orange-400:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(251 146 60 / var(--tw-border-opacity));
|
||||
@@ -2727,11 +2732,6 @@ video {
|
||||
border-color: rgb(244 149 65 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:border-gray-300:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-blue-600:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
|
||||
@@ -3622,6 +3622,11 @@ video {
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark\:hover\:border-gray-500:hover:is(.dark *) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(107 114 128 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark\:hover\:border-orange-500:hover:is(.dark *) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(249 115 22 / var(--tw-border-opacity));
|
||||
@@ -3632,11 +3637,6 @@ video {
|
||||
border-color: rgb(244 149 65 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark\:hover\:border-gray-500:hover:is(.dark *) {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(107 114 128 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.dark\:hover\:bg-blue-500:hover:is(.dark *) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><path d="M506 116v280c0 60.71-49.29 110-110 110H116C55.29 506 6 456.71 6 396V116C6 55.289 55.29 6 116 6h280c60.71 0 110 49.289 110 110z" fill="#00cfb6"/><path d="M89.05 290.616a167.348 167.348 0 0031.783 98.434l80.131-130.713 28.885 49.582-7.936-36.887 34.082-57.808 55.107 94.695-7.862-36.523 7.75-13.124 80.177 130.778a167.348 167.348 0 0031.783-98.434c0-92.601-74.746-167.665-166.955-167.665-92.198-.019-166.945 75.055-166.945 167.665" fill="#fff" fill-rule="nonzero"/></svg>
|
||||
|
After Width: | Height: | Size: 626 B |
@@ -72,6 +72,7 @@
|
||||
<EmbeddedResource Include="TestData\Exports\1password_8.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\protonpass.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\lastpass.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\nordpass.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\aliasvault_mobile_app_export.csv" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
name,url,additional_urls,username,password,note,cardholdername,cardnumber,cvc,pin,expirydate,zipcode,folder,full_name,phone_number,email,address1,address2,city,country,state,type,custom_fields
|
||||
Password title,http://google.nl,,email@example.tld,password,,,,,,,,Business,,,,,,,,,password,"[{""type"":""text"",""label"":""CustomFieldName1"",""value"":""Test""}]"
|
||||
SecureNote1,,,,,"This is my secure note content
|
||||
|
||||
Test test",,,,,,,,,,,,,,,,note,
|
||||
Creditcard Visa,,,,,,Holdername,1234123412341234123,1231,1231,12/28,1231AB,,,,,,,,,,credit_card,
|
||||
Business,,,,,,,,,,,,,,,,,,,,,folder,
|
||||
Root item,,,rootuser,rootpass,,,,,,,,,,,,,,,,,password,
|
||||
|
@@ -667,6 +667,135 @@ public class ImportExportTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for importing credentials from NordPass CSV and ensuring all values are present.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
[Test]
|
||||
public async Task ImportCredentialsFromNordPassCsv()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = await ResourceReaderUtility.ReadEmbeddedResourceStringAsync("AliasVault.UnitTests.TestData.Exports.nordpass.csv");
|
||||
|
||||
// Act
|
||||
var importedCredentials = await NordPassImporter.ImportFromCsvAsync(fileContent);
|
||||
|
||||
// Assert - Should import 4 records (folder entry is skipped)
|
||||
Assert.That(importedCredentials, Has.Count.EqualTo(4));
|
||||
|
||||
// Test regular password credential
|
||||
var passwordCredential = importedCredentials.First(c => c.ServiceName == "Password title");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(passwordCredential.ServiceName, Is.EqualTo("Password title"));
|
||||
Assert.That(passwordCredential.ServiceUrl, Is.EqualTo("http://google.nl"));
|
||||
Assert.That(passwordCredential.Username, Is.EqualTo("email@example.tld"));
|
||||
Assert.That(passwordCredential.Password, Is.EqualTo("password"));
|
||||
Assert.That(passwordCredential.FolderPath, Is.EqualTo("Business"));
|
||||
Assert.That(passwordCredential.ItemType, Is.EqualTo(ImportedItemType.Login));
|
||||
Assert.That(passwordCredential.Notes, Does.Contain("[{\"type\":\"text\",\"label\":\"CustomFieldName1\",\"value\":\"Test\"}]"));
|
||||
});
|
||||
|
||||
// Test secure note
|
||||
var secureNote = importedCredentials.First(c => c.ServiceName == "SecureNote1");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(secureNote.ServiceName, Is.EqualTo("SecureNote1"));
|
||||
Assert.That(secureNote.ServiceUrl, Is.Null);
|
||||
Assert.That(secureNote.Username, Is.Empty);
|
||||
Assert.That(secureNote.Password, Is.Empty);
|
||||
Assert.That(secureNote.ItemType, Is.EqualTo(ImportedItemType.Note));
|
||||
Assert.That(secureNote.Notes, Does.Contain("This is my secure note content"));
|
||||
Assert.That(secureNote.Notes, Does.Contain("Test test"));
|
||||
});
|
||||
|
||||
// Test credit card
|
||||
var creditCard = importedCredentials.First(c => c.ServiceName == "Creditcard Visa");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(creditCard.ServiceName, Is.EqualTo("Creditcard Visa"));
|
||||
Assert.That(creditCard.ItemType, Is.EqualTo(ImportedItemType.Creditcard));
|
||||
Assert.That(creditCard.Creditcard, Is.Not.Null);
|
||||
Assert.That(creditCard.Creditcard!.CardholderName, Is.EqualTo("Holdername"));
|
||||
Assert.That(creditCard.Creditcard.Number, Is.EqualTo("1234123412341234123"));
|
||||
Assert.That(creditCard.Creditcard.Cvv, Is.EqualTo("1231"));
|
||||
Assert.That(creditCard.Creditcard.Pin, Is.EqualTo("1231"));
|
||||
Assert.That(creditCard.Creditcard.ExpiryMonth, Is.EqualTo("12"));
|
||||
Assert.That(creditCard.Creditcard.ExpiryYear, Is.EqualTo("28"));
|
||||
});
|
||||
|
||||
// Test root item (no folder)
|
||||
var rootItem = importedCredentials.First(c => c.ServiceName == "Root item");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(rootItem.ServiceName, Is.EqualTo("Root item"));
|
||||
Assert.That(rootItem.Username, Is.EqualTo("rootuser"));
|
||||
Assert.That(rootItem.Password, Is.EqualTo("rootpass"));
|
||||
Assert.That(rootItem.FolderPath, Is.Null);
|
||||
Assert.That(rootItem.ItemType, Is.EqualTo(ImportedItemType.Login));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for NordPass folder import.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
[Test]
|
||||
public async Task NordPassFolderImport()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = await ResourceReaderUtility.ReadEmbeddedResourceStringAsync("AliasVault.UnitTests.TestData.Exports.nordpass.csv");
|
||||
|
||||
// Act
|
||||
var importedCredentials = await NordPassImporter.ImportFromCsvAsync(fileContent);
|
||||
|
||||
// Assert - verify folder path is extracted
|
||||
var folderNames = BaseImporter.CollectUniqueFolderNames(importedCredentials);
|
||||
Assert.That(folderNames, Does.Contain("Business"));
|
||||
|
||||
var credentialWithFolder = importedCredentials.First(c => c.FolderPath == "Business");
|
||||
Assert.That(credentialWithFolder.ServiceName, Is.EqualTo("Password title"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for NordPass credit card detection and parsing.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
[Test]
|
||||
public async Task NordPassCreditCardDetectionAndParsing()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = await ResourceReaderUtility.ReadEmbeddedResourceStringAsync("AliasVault.UnitTests.TestData.Exports.nordpass.csv");
|
||||
|
||||
// Act
|
||||
var importedCredentials = await NordPassImporter.ImportFromCsvAsync(fileContent);
|
||||
|
||||
// Assert - verify credit card is detected and parsed
|
||||
var creditCardCredential = importedCredentials.First(c => c.ServiceName == "Creditcard Visa");
|
||||
Assert.That(creditCardCredential.ItemType, Is.EqualTo(ImportedItemType.Creditcard));
|
||||
Assert.That(creditCardCredential.Creditcard, Is.Not.Null);
|
||||
Assert.That(creditCardCredential.Creditcard!.CardholderName, Is.EqualTo("Holdername"));
|
||||
Assert.That(creditCardCredential.Creditcard.Number, Is.EqualTo("1234123412341234123"));
|
||||
Assert.That(creditCardCredential.Creditcard.Cvv, Is.EqualTo("1231"));
|
||||
Assert.That(creditCardCredential.Creditcard.Pin, Is.EqualTo("1231"));
|
||||
Assert.That(creditCardCredential.Creditcard.ExpiryMonth, Is.EqualTo("12"));
|
||||
Assert.That(creditCardCredential.Creditcard.ExpiryYear, Is.EqualTo("28"));
|
||||
|
||||
// Convert to item and verify fields
|
||||
var items = BaseImporter.ConvertToItem([creditCardCredential]);
|
||||
var creditCardItem = items[0];
|
||||
Assert.That(creditCardItem.ItemType, Is.EqualTo(ItemType.CreditCard));
|
||||
|
||||
var cardNumber = creditCardItem.FieldValues.FirstOrDefault(fv => fv.FieldKey == FieldKey.CardNumber);
|
||||
Assert.That(cardNumber?.Value, Is.EqualTo("1234123412341234123"));
|
||||
|
||||
var cardholderName = creditCardItem.FieldValues.FirstOrDefault(fv => fv.FieldKey == FieldKey.CardCardholderName);
|
||||
Assert.That(cardholderName?.Value, Is.EqualTo("Holdername"));
|
||||
|
||||
var cardPin = creditCardItem.FieldValues.FirstOrDefault(fv => fv.FieldKey == FieldKey.CardPin);
|
||||
Assert.That(cardPin?.Value, Is.EqualTo("1231"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for importing credentials from AliasVault Mobile App CSV export and ensuring all values are present.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="NordPassImporter.cs" company="aliasvault">
|
||||
// Copyright (c) aliasvault. All rights reserved.
|
||||
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.ImportExport.Importers;
|
||||
|
||||
using AliasVault.ImportExport.Models;
|
||||
using AliasVault.ImportExport.Models.Imports;
|
||||
|
||||
/// <summary>
|
||||
/// Imports credentials from NordPass.
|
||||
/// </summary>
|
||||
public static class NordPassImporter
|
||||
{
|
||||
/// <summary>
|
||||
/// Imports NordPass CSV file and converts contents to list of ImportedCredential model objects.
|
||||
/// </summary>
|
||||
/// <param name="fileContent">The content of the CSV file.</param>
|
||||
/// <returns>The imported list of ImportedCredential objects.</returns>
|
||||
public static async Task<List<ImportedCredential>> ImportFromCsvAsync(string fileContent)
|
||||
{
|
||||
var records = await BaseImporter.ImportCsvDataAsync<NordPassCsvRecord>(fileContent);
|
||||
|
||||
var credentials = new List<ImportedCredential>();
|
||||
foreach (var record in records)
|
||||
{
|
||||
// Skip folder entries - NordPass exports folder rows with type "folder" which are not credentials.
|
||||
if (string.Equals(record.Type, "folder", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemType = MapNordPassType(record.Type);
|
||||
ImportedCreditcard? creditcard = null;
|
||||
|
||||
// Parse credit card data if any credit card fields are present.
|
||||
if (HasCreditcardData(record))
|
||||
{
|
||||
creditcard = ParseCreditcard(record);
|
||||
itemType ??= ImportedItemType.Creditcard;
|
||||
}
|
||||
|
||||
// Build notes, appending custom fields if present.
|
||||
var notes = record.Note;
|
||||
if (!string.IsNullOrWhiteSpace(record.CustomFields))
|
||||
{
|
||||
notes = string.IsNullOrWhiteSpace(notes)
|
||||
? record.CustomFields
|
||||
: notes + Environment.NewLine + record.CustomFields;
|
||||
}
|
||||
|
||||
var credential = new ImportedCredential
|
||||
{
|
||||
ServiceName = record.Name,
|
||||
ServiceUrl = string.IsNullOrWhiteSpace(record.Url) ? null : record.Url,
|
||||
Email = record.Email,
|
||||
Username = record.Username,
|
||||
Password = record.Password,
|
||||
Notes = notes,
|
||||
FolderPath = string.IsNullOrWhiteSpace(record.Folder) ? null : record.Folder,
|
||||
ItemType = itemType,
|
||||
Creditcard = creditcard,
|
||||
};
|
||||
|
||||
credentials.Add(credential);
|
||||
}
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps NordPass type values to ImportedItemType.
|
||||
/// NordPass types: password, note, credit_card, identity.
|
||||
/// </summary>
|
||||
private static ImportedItemType? MapNordPassType(string? nordPassType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(nordPassType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return nordPassType.ToLowerInvariant() switch
|
||||
{
|
||||
"password" => ImportedItemType.Login,
|
||||
"note" => ImportedItemType.Note,
|
||||
"credit_card" => ImportedItemType.Creditcard,
|
||||
"identity" => ImportedItemType.Alias,
|
||||
_ => ImportedItemType.Login,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the NordPass record contains credit card data.
|
||||
/// </summary>
|
||||
private static bool HasCreditcardData(NordPassCsvRecord record)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(record.CardNumber) ||
|
||||
!string.IsNullOrWhiteSpace(record.CardholderName) ||
|
||||
!string.IsNullOrWhiteSpace(record.Cvc) ||
|
||||
!string.IsNullOrWhiteSpace(record.ExpiryDate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses credit card data from a NordPass record.
|
||||
/// </summary>
|
||||
private static ImportedCreditcard ParseCreditcard(NordPassCsvRecord record)
|
||||
{
|
||||
var creditcard = new ImportedCreditcard
|
||||
{
|
||||
CardholderName = record.CardholderName,
|
||||
Number = record.CardNumber,
|
||||
Cvv = record.Cvc,
|
||||
Pin = record.Pin,
|
||||
};
|
||||
|
||||
// Parse expiry date - NordPass uses various formats, commonly "MM/YYYY" or "MMYYYY".
|
||||
if (!string.IsNullOrWhiteSpace(record.ExpiryDate))
|
||||
{
|
||||
ParseExpiryDate(record.ExpiryDate, creditcard);
|
||||
}
|
||||
|
||||
return creditcard;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses NordPass expiry date string into month and year components.
|
||||
/// Handles formats like "MM/YYYY", "MM/YY", and "MMYYYY".
|
||||
/// </summary>
|
||||
private static void ParseExpiryDate(string expiryDate, ImportedCreditcard creditcard)
|
||||
{
|
||||
if (expiryDate.Contains('/'))
|
||||
{
|
||||
var parts = expiryDate.Split('/');
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
creditcard.ExpiryMonth = parts[0].Trim().PadLeft(2, '0');
|
||||
creditcard.ExpiryYear = parts[1].Trim();
|
||||
}
|
||||
}
|
||||
else if (expiryDate.Length == 6)
|
||||
{
|
||||
// Format: MMYYYY
|
||||
creditcard.ExpiryMonth = expiryDate[..2];
|
||||
creditcard.ExpiryYear = expiryDate[2..];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="NordPassCsvRecord.cs" company="aliasvault">
|
||||
// Copyright (c) aliasvault. All rights reserved.
|
||||
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.ImportExport.Models.Imports;
|
||||
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a NordPass CSV record that is being imported from a NordPass CSV export file.
|
||||
/// </summary>
|
||||
public class NordPassCsvRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the item.
|
||||
/// </summary>
|
||||
[Name("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL of the item.
|
||||
/// </summary>
|
||||
[Name("url")]
|
||||
public string Url { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the additional URLs of the item.
|
||||
/// </summary>
|
||||
[Name("additional_urls")]
|
||||
public string? AdditionalUrls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username of the item.
|
||||
/// </summary>
|
||||
[Name("username")]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password of the item.
|
||||
/// </summary>
|
||||
[Name("password")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets any additional notes.
|
||||
/// </summary>
|
||||
[Name("note")]
|
||||
public string? Note { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cardholder name (for credit card items).
|
||||
/// </summary>
|
||||
[Name("cardholdername")]
|
||||
public string? CardholderName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the card number (for credit card items).
|
||||
/// </summary>
|
||||
[Name("cardnumber")]
|
||||
public string? CardNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CVC/CVV code (for credit card items).
|
||||
/// </summary>
|
||||
[Name("cvc")]
|
||||
public string? Cvc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the PIN (for credit card items).
|
||||
/// </summary>
|
||||
[Name("pin")]
|
||||
public string? Pin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expiry date (for credit card items).
|
||||
/// </summary>
|
||||
[Name("expirydate")]
|
||||
public string? ExpiryDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the zip code (for identity items).
|
||||
/// </summary>
|
||||
[Name("zipcode")]
|
||||
public string? ZipCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the folder name.
|
||||
/// </summary>
|
||||
[Name("folder")]
|
||||
public string? Folder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the full name (for identity items).
|
||||
/// </summary>
|
||||
[Name("full_name")]
|
||||
public string? FullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the phone number (for identity items).
|
||||
/// </summary>
|
||||
[Name("phone_number")]
|
||||
public string? PhoneNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the email address (for identity items).
|
||||
/// </summary>
|
||||
[Name("email")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the first address line (for identity items).
|
||||
/// </summary>
|
||||
[Name("address1")]
|
||||
public string? Address1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the second address line (for identity items).
|
||||
/// </summary>
|
||||
[Name("address2")]
|
||||
public string? Address2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the city (for identity items).
|
||||
/// </summary>
|
||||
[Name("city")]
|
||||
public string? City { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the country (for identity items).
|
||||
/// </summary>
|
||||
[Name("country")]
|
||||
public string? Country { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the state (for identity items).
|
||||
/// </summary>
|
||||
[Name("state")]
|
||||
public string? State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the item (e.g., password, note, card, identity).
|
||||
/// </summary>
|
||||
[Name("type")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets custom fields as a JSON or delimited string.
|
||||
/// </summary>
|
||||
[Name("custom_fields")]
|
||||
public string? CustomFields { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user