mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-04-13 11:10:02 -04:00
Add Dropbox Passwords import method (#1114)
This commit is contained in:
committed by
Leendert de Borst
parent
29d38759eb
commit
783b2d44ef
@@ -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<ImportServiceDropbox> Logger
|
||||
|
||||
<ImportServiceCard
|
||||
ServiceName="Dropbox Passwords"
|
||||
Description="@Localizer["DropboxDescription"]"
|
||||
LogoUrl="img/importers/dropbox.svg"
|
||||
ProcessFileCallback="ProcessFile">
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">@Localizer["DropboxInstructionsPart1"]</p>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">@Localizer["UploadFileInstructionCommon"]</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 DropboxImporter.ImportFromCsvAsync(fileContents);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
<ImportServiceBitwarden />
|
||||
<ImportServiceChrome />
|
||||
<ImportServiceDashlane />
|
||||
<ImportServiceDropbox />
|
||||
<ImportServiceFirefox />
|
||||
<ImportServiceKeePass />
|
||||
<ImportServiceKeePassXC />
|
||||
|
||||
@@ -226,6 +226,15 @@
|
||||
<value>If you have a CSV file back-up of your AliasVault database (from a different AliasVault server), you can import it here.</value>
|
||||
<comment>AliasVault import instructions</comment>
|
||||
</data>
|
||||
<!-- Dropbox -->
|
||||
<data name="DropboxDescription" xml:space="preserve">
|
||||
<value>Import passwords from Dropbox Passwords</value>
|
||||
<comment>Description for Dropbox import service</comment>
|
||||
</data>
|
||||
<data name="DropboxInstructionsPart1" xml:space="preserve">
|
||||
<value>In order to import your Dropbox Passwords, you need to export them as a CSV file. You can do this by opening Dropbox Passwords, going to 'Account' > 'Export' (to .CSV).</value>
|
||||
<comment>Dropbox export instructions part 1</comment>
|
||||
</data>
|
||||
<!-- Common text that can be reused -->
|
||||
<data name="UploadFileInstructionCommon" xml:space="preserve">
|
||||
<value>Once you have exported the file, you can upload it below.</value>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="43px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 43 40" version="1.1" height="40px">
|
||||
<path d="m12.5 0l-12.5 8.1 8.7 7 12.5-7.8-8.7-7.3zm-12.5 21.9l12.5 8.2 8.7-7.3-12.5-7.7-8.7 6.8zm21.2 0.9l8.8 7.3 12.4-8.1-8.6-6.9-12.6 7.7zm21.2-14.7l-12.4-8.1-8.8 7.3 12.6 7.8 8.6-7zm-21.1 16.3l-8.8 7.3-3.7-2.5v2.8l12.5 7.5 12.5-7.5v-2.8l-3.8 2.5-8.7-7.3z" fill="#007EE5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 441 B |
@@ -62,13 +62,14 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="TestData\Exports\bitwarden.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\chrome.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\dashlane.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\dropbox.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\firefox.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\strongbox.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\keepass.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\keepassxc.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\1password_8.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\protonpass.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\dashlane.csv" />
|
||||
<EmbeddedResource Include="TestData\Exports\lastpass.csv" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Name,URL,Username,Password,Notes
|
||||
Gmail,https://gmail.com,testuser@gmail.com,gmailpass123,Important email account
|
||||
Facebook,https://facebook.com,fbuser,fbpass456,Social media account
|
||||
GitHub,https://github.com,devuser,devpass789,Development platform
|
||||
Secure Note,,,,Important information stored securely
|
||||
Test Site,https://test.example.com,testlogin,testpassword,Test notes for example site
|
||||
|
@@ -592,6 +592,56 @@ public class ImportExportTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for importing credentials from Dropbox CSV and ensuring all values are present.
|
||||
/// </summary>
|
||||
/// <returns>Async task.</returns>
|
||||
[Test]
|
||||
public async Task ImportCredentialsFromDropboxCsv()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = await ResourceReaderUtility.ReadEmbeddedResourceStringAsync("AliasVault.UnitTests.TestData.Exports.dropbox.csv");
|
||||
|
||||
// Act
|
||||
var importedCredentials = await DropboxImporter.ImportFromCsvAsync(fileContent);
|
||||
|
||||
// Assert
|
||||
Assert.That(importedCredentials, Has.Count.EqualTo(5));
|
||||
|
||||
// Test Gmail credential
|
||||
var gmailCredential = importedCredentials.First(c => c.ServiceName == "Gmail");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(gmailCredential.ServiceName, Is.EqualTo("Gmail"));
|
||||
Assert.That(gmailCredential.ServiceUrl, Is.EqualTo("https://gmail.com"));
|
||||
Assert.That(gmailCredential.Username, Is.EqualTo("testuser@gmail.com"));
|
||||
Assert.That(gmailCredential.Password, Is.EqualTo("gmailpass123"));
|
||||
Assert.That(gmailCredential.Notes, Is.EqualTo("Important email account"));
|
||||
});
|
||||
|
||||
// Test GitHub credential
|
||||
var githubCredential = importedCredentials.First(c => c.ServiceName == "GitHub");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(githubCredential.ServiceName, Is.EqualTo("GitHub"));
|
||||
Assert.That(githubCredential.ServiceUrl, Is.EqualTo("https://github.com"));
|
||||
Assert.That(githubCredential.Username, Is.EqualTo("devuser"));
|
||||
Assert.That(githubCredential.Password, Is.EqualTo("devpass789"));
|
||||
Assert.That(githubCredential.Notes, Is.EqualTo("Development platform"));
|
||||
});
|
||||
|
||||
// Test Secure Note (no login credentials)
|
||||
var secureNoteCredential = importedCredentials.First(c => c.ServiceName == "Secure Note");
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(secureNoteCredential.ServiceName, Is.EqualTo("Secure Note"));
|
||||
Assert.That(secureNoteCredential.ServiceUrl, Is.Null);
|
||||
Assert.That(secureNoteCredential.Username, Is.Empty);
|
||||
Assert.That(secureNoteCredential.Password, Is.Empty);
|
||||
Assert.That(secureNoteCredential.Notes, Is.EqualTo("Important information stored securely"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test case for getting the CSV template structure.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="DropboxImporter.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. 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;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using System.Globalization;
|
||||
|
||||
/// <summary>
|
||||
/// Imports credentials from Dropbox Passwords.
|
||||
/// </summary>
|
||||
public static class DropboxImporter
|
||||
{
|
||||
/// <summary>
|
||||
/// Imports Dropbox 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)
|
||||
{
|
||||
using var reader = new StringReader(fileContent);
|
||||
using var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture));
|
||||
|
||||
var credentials = new List<ImportedCredential>();
|
||||
await foreach (var record in csv.GetRecordsAsync<DropboxCsvRecord>())
|
||||
{
|
||||
// Skip empty records (records with no title)
|
||||
if (string.IsNullOrWhiteSpace(record.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var credential = new ImportedCredential
|
||||
{
|
||||
ServiceName = record.Name,
|
||||
ServiceUrl = NormalizeUrl(record.Url),
|
||||
Username = record.Username,
|
||||
Password = record.Password,
|
||||
Notes = record.Notes
|
||||
};
|
||||
|
||||
credentials.Add(credential);
|
||||
}
|
||||
|
||||
if (credentials.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No records found in the CSV file.");
|
||||
}
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes URL values from Dropbox CSV format.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL from the CSV record.</param>
|
||||
/// <returns>The normalized URL or null if it's empty or invalid.</returns>
|
||||
private static string? NormalizeUrl(string? url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="DropboxCsvRecord.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
|
||||
namespace AliasVault.ImportExport.Models.Imports;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Dropbox CSV record that is being imported from a Dropbox CSV export file.
|
||||
/// </summary>
|
||||
public class DropboxCsvRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the title/service name (e.g., "Facebook", "Gmail").
|
||||
/// </summary>
|
||||
[Name("Name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the service URL.
|
||||
/// </summary>
|
||||
[Name("URL")]
|
||||
public string? Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username/login.
|
||||
/// </summary>
|
||||
[Name("Username")]
|
||||
public string? Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password.
|
||||
/// </summary>
|
||||
[Name("Password")]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets any additional notes.
|
||||
/// </summary>
|
||||
[Name("Notes")]
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user