mirror of
https://github.com/bitwarden/mobile
synced 2025-12-25 12:43:39 +00:00
In-app vault export support (#729)
* First pass at vault export UI * Password validation via cryptoService * Export service framework * support for constructing json export data * Support for constructing csv export data * Cleanup and simplification * Completion of vault export feature * Formatting and simplification * Use dialog instead of toast for invalid master password entry
This commit is contained in:
11
src/Core/Abstractions/IExportService.cs
Normal file
11
src/Core/Abstractions/IExportService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface IExportService
|
||||
{
|
||||
Task<string> GetExport(string format = "csv");
|
||||
Task<string> GetOrganizationExport(string organizationId, string format = "csv");
|
||||
string GetFileName(string prefix = null, string extension = "csv");
|
||||
}
|
||||
}
|
||||
@@ -33,5 +33,6 @@
|
||||
public static string PreviousPageKey = "previousPage";
|
||||
public const int SelectFileRequestCode = 42;
|
||||
public const int SelectFilePermissionRequestCode = 43;
|
||||
public const int SaveFileRequestCode = 44;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="15.0.0" />
|
||||
<PackageReference Include="LiteDB" Version="4.1.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
||||
|
||||
42
src/Core/Models/Export/Card.cs
Normal file
42
src/Core/Models/Export/Card.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Card
|
||||
{
|
||||
public Card() { }
|
||||
|
||||
public Card(CardView obj)
|
||||
{
|
||||
CardholderName = obj.CardholderName;
|
||||
Brand = obj.Brand;
|
||||
Number = obj.Number;
|
||||
ExpMonth = obj.ExpMonth;
|
||||
ExpYear = obj.ExpYear;
|
||||
Code = obj.Code;
|
||||
}
|
||||
|
||||
public string CardholderName { get; set; }
|
||||
public string Brand { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
|
||||
public static CardView ToView(Card req, CardView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new CardView();
|
||||
}
|
||||
|
||||
view.CardholderName = req.CardholderName;
|
||||
view.Brand = req.Brand;
|
||||
view.Number = req.Number;
|
||||
view.ExpMonth = req.ExpMonth;
|
||||
view.ExpYear = req.ExpYear;
|
||||
view.Code = req.Code;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
97
src/Core/Models/Export/Cipher.cs
Normal file
97
src/Core/Models/Export/Cipher.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Cipher
|
||||
{
|
||||
public Cipher() { }
|
||||
|
||||
public Cipher(CipherView obj)
|
||||
{
|
||||
OrganizationId = obj.OrganizationId;
|
||||
FolderId = obj.FolderId;
|
||||
Type = obj.Type;
|
||||
Name = obj.Name;
|
||||
Notes = obj.Notes;
|
||||
Favorite = obj.Favorite;
|
||||
|
||||
Fields = obj.Fields?.Select(f => new Field(f)).ToList();
|
||||
|
||||
switch(obj.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
Login = new Login(obj.Login);
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
SecureNote = new SecureNote(obj.SecureNote);
|
||||
break;
|
||||
case CipherType.Card:
|
||||
Card = new Card(obj.Card);
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
Identity = new Identity(obj.Identity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public string OrganizationId { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public CipherType Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public List<Field> Fields { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Login Login { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public SecureNote SecureNote { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Card Card { get; set; }
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Identity Identity { get; set; }
|
||||
|
||||
public CipherView ToView(Cipher req, CipherView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new CipherView();
|
||||
}
|
||||
|
||||
view.Type = req.Type;
|
||||
view.FolderId = req.FolderId;
|
||||
if(view.OrganizationId == null)
|
||||
{
|
||||
view.OrganizationId = req.OrganizationId;
|
||||
}
|
||||
|
||||
view.Name = req.Name;
|
||||
view.Notes = req.Notes;
|
||||
view.Favorite = req.Favorite;
|
||||
|
||||
view.Fields = req.Fields?.Select(f => Field.ToView(f)).ToList();
|
||||
|
||||
switch(req.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
view.Login = Login.ToView(req.Login);
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
view.SecureNote = SecureNote.ToView(req.SecureNote);
|
||||
break;
|
||||
case CipherType.Card:
|
||||
view.Card = Card.ToView(req.Card);
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
view.Identity = Identity.ToView(req.Identity);
|
||||
break;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Core/Models/Export/CipherWithId.cs
Normal file
20
src/Core/Models/Export/CipherWithId.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Models.View;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class CipherWithId : Cipher
|
||||
{
|
||||
public CipherWithId(CipherView obj) : base(obj)
|
||||
{
|
||||
Id = obj.Id;
|
||||
CollectionIds = obj.CollectionIds;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = int.MinValue)]
|
||||
public string Id { get; set; }
|
||||
[JsonProperty(Order = int.MaxValue)]
|
||||
public HashSet<string> CollectionIds { get; set; }
|
||||
}
|
||||
}
|
||||
37
src/Core/Models/Export/Collection.cs
Normal file
37
src/Core/Models/Export/Collection.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Collection
|
||||
{
|
||||
public Collection() { }
|
||||
|
||||
public Collection(CollectionView obj)
|
||||
{
|
||||
OrganizationId = obj.OrganizationId;
|
||||
Name = obj.Name;
|
||||
ExternalId = obj.ExternalId;
|
||||
}
|
||||
|
||||
public string OrganizationId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
public CollectionView ToView(Collection req, CollectionView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new CollectionView();
|
||||
}
|
||||
|
||||
view.Name = req.Name;
|
||||
view.ExternalId = req.ExternalId;
|
||||
if(view.OrganizationId == null)
|
||||
{
|
||||
view.OrganizationId = req.OrganizationId;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Core/Models/Export/CollectionWithId.cs
Normal file
16
src/Core/Models/Export/CollectionWithId.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Bit.Core.Models.View;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class CollectionWithId : Collection
|
||||
{
|
||||
public CollectionWithId(CollectionView obj) : base(obj)
|
||||
{
|
||||
Id = obj.Id;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = int.MinValue)]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
34
src/Core/Models/Export/Field.cs
Normal file
34
src/Core/Models/Export/Field.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
public Field() { }
|
||||
|
||||
public Field(FieldView obj)
|
||||
{
|
||||
Name = obj.Name;
|
||||
Value = obj.Value;
|
||||
Type = obj.Type;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
public FieldType Type { get; set; }
|
||||
|
||||
public static FieldView ToView(Field req, FieldView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new FieldView();
|
||||
}
|
||||
|
||||
view.Type = req.Type;
|
||||
view.Value = req.Value;
|
||||
view.Name = req.Name;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/Core/Models/Export/Folder.cs
Normal file
27
src/Core/Models/Export/Folder.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Folder
|
||||
{
|
||||
public Folder() { }
|
||||
|
||||
public Folder(FolderView obj)
|
||||
{
|
||||
Name = obj.Name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public FolderView ToView(Folder req, FolderView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new FolderView();
|
||||
}
|
||||
|
||||
view.Name = req.Name;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Core/Models/Export/FolderWithId.cs
Normal file
16
src/Core/Models/Export/FolderWithId.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Bit.Core.Models.View;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class FolderWithId : Folder
|
||||
{
|
||||
public FolderWithId(FolderView obj) : base(obj)
|
||||
{
|
||||
Id = obj.Id;
|
||||
}
|
||||
|
||||
[JsonProperty(Order = int.MinValue)]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
78
src/Core/Models/Export/Identity.cs
Normal file
78
src/Core/Models/Export/Identity.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Identity
|
||||
{
|
||||
public Identity() { }
|
||||
|
||||
public Identity(IdentityView obj)
|
||||
{
|
||||
Title = obj.Title;
|
||||
FirstName = obj.FirstName;
|
||||
MiddleName = obj.MiddleName;
|
||||
LastName = obj.LastName;
|
||||
Address1 = obj.Address1;
|
||||
Address2 = obj.Address2;
|
||||
Address3 = obj.Address3;
|
||||
City = obj.City;
|
||||
State = obj.State;
|
||||
PostalCode = obj.PostalCode;
|
||||
Country = obj.Country;
|
||||
Company = obj.Company;
|
||||
Email = obj.Email;
|
||||
Phone = obj.Phone;
|
||||
SSN = obj.SSN;
|
||||
Username = obj.Username;
|
||||
PassportNumber = obj.PassportNumber;
|
||||
LicenseNumber = obj.LicenseNumber;
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string MiddleName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Address1 { get; set; }
|
||||
public string Address2 { get; set; }
|
||||
public string Address3 { get; set; }
|
||||
public string City { get; set; }
|
||||
public string State { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string Company { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string SSN { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string PassportNumber { get; set; }
|
||||
public string LicenseNumber { get; set; }
|
||||
|
||||
public static IdentityView ToView(Identity req, IdentityView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new IdentityView();
|
||||
}
|
||||
|
||||
view.Title = req.Title;
|
||||
view.FirstName = req.FirstName;
|
||||
view.MiddleName = req.MiddleName;
|
||||
view.LastName = req.LastName;
|
||||
view.Address1 = req.Address1;
|
||||
view.Address2 = req.Address2;
|
||||
view.Address3 = req.Address3;
|
||||
view.City = req.City;
|
||||
view.State = req.State;
|
||||
view.PostalCode = req.PostalCode;
|
||||
view.Country = req.Country;
|
||||
view.Company = req.Company;
|
||||
view.Email = req.Email;
|
||||
view.Phone = req.Phone;
|
||||
view.SSN = req.SSN;
|
||||
view.Username = req.Username;
|
||||
view.PassportNumber = req.PassportNumber;
|
||||
view.LicenseNumber = req.LicenseNumber;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/Core/Models/Export/Login.cs
Normal file
40
src/Core/Models/Export/Login.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class Login
|
||||
{
|
||||
public Login() { }
|
||||
|
||||
public Login(LoginView obj)
|
||||
{
|
||||
Uris = obj.Uris?.Select(u => new LoginUri(u)).ToList();
|
||||
|
||||
Username = obj.Username;
|
||||
Password = obj.Password;
|
||||
Totp = obj.Totp;
|
||||
}
|
||||
|
||||
public List<LoginUri> Uris { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Totp { get; set; }
|
||||
|
||||
public static LoginView ToView(Login req, LoginView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new LoginView();
|
||||
}
|
||||
|
||||
view.Uris = req.Uris?.Select(u => LoginUri.ToView(u)).ToList();
|
||||
|
||||
view.Username = req.Username;
|
||||
view.Password = req.Password;
|
||||
view.Totp = req.Totp;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/Core/Models/Export/LoginUri.cs
Normal file
31
src/Core/Models/Export/LoginUri.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class LoginUri
|
||||
{
|
||||
public LoginUri() { }
|
||||
|
||||
public LoginUri(LoginUriView obj)
|
||||
{
|
||||
Match = obj.Match;
|
||||
Uri = obj.Uri;
|
||||
}
|
||||
|
||||
public UriMatchType? Match { get; set; }
|
||||
public string Uri { get; set; }
|
||||
|
||||
public static LoginUriView ToView(LoginUri req, LoginUriView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new LoginUriView();
|
||||
}
|
||||
|
||||
view.Match = req.Match;
|
||||
view.Uri = req.Uri;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Core/Models/Export/SecureNote.cs
Normal file
28
src/Core/Models/Export/SecureNote.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
|
||||
namespace Bit.Core.Models.Export
|
||||
{
|
||||
public class SecureNote
|
||||
{
|
||||
public SecureNote() { }
|
||||
|
||||
public SecureNote(SecureNoteView obj)
|
||||
{
|
||||
Type = obj.Type;
|
||||
}
|
||||
|
||||
public SecureNoteType Type { get; set; }
|
||||
|
||||
public SecureNoteView ToView(SecureNote req, SecureNoteView view = null)
|
||||
{
|
||||
if(view == null)
|
||||
{
|
||||
view = new SecureNoteView();
|
||||
}
|
||||
|
||||
view.Type = req.Type;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
193
src/Core/Services/ExportService.cs
Normal file
193
src/Core/Services/ExportService.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Export;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class ExportService : IExportService
|
||||
{
|
||||
private readonly IFolderService _folderService;
|
||||
private readonly ICipherService _cipherService;
|
||||
|
||||
private List<FolderView> _decryptedFolders;
|
||||
private List<CipherView> _decryptedCiphers;
|
||||
|
||||
public ExportService(
|
||||
IFolderService folderService,
|
||||
ICipherService cipherService)
|
||||
{
|
||||
_folderService = folderService;
|
||||
_cipherService = cipherService;
|
||||
}
|
||||
|
||||
public async Task<string> GetExport(string format = "csv")
|
||||
{
|
||||
_decryptedFolders = await _folderService.GetAllDecryptedAsync();
|
||||
_decryptedCiphers = await _cipherService.GetAllDecryptedAsync();
|
||||
|
||||
if(format == "csv")
|
||||
{
|
||||
var foldersMap = _decryptedFolders.Where(f => f.Id != null).ToDictionary(f => f.Id);
|
||||
|
||||
var exportCiphers = new List<ExportCipher>();
|
||||
foreach(var c in _decryptedCiphers)
|
||||
{
|
||||
// only export logins and secure notes
|
||||
if(c.Type != CipherType.Login && c.Type != CipherType.SecureNote)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c.OrganizationId != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cipher = new ExportCipher();
|
||||
cipher.Folder = c.FolderId != null && foldersMap.ContainsKey(c.FolderId)
|
||||
? foldersMap[c.FolderId].Name : null;
|
||||
cipher.Favorite = c.Favorite ? "1" : null;
|
||||
BuildCommonCipher(cipher, c);
|
||||
exportCiphers.Add(cipher);
|
||||
}
|
||||
|
||||
using (var writer = new StringWriter())
|
||||
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
|
||||
{
|
||||
csv.WriteRecords(exportCiphers);
|
||||
csv.Flush();
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var jsonDoc = new
|
||||
{
|
||||
Folders = _decryptedFolders.Where(f => f.Id != null).Select(f => new FolderWithId(f)),
|
||||
Items = _decryptedCiphers.Where(c => c.OrganizationId == null)
|
||||
.Select(c => new CipherWithId(c) {CollectionIds = null})
|
||||
};
|
||||
|
||||
return CoreHelpers.SerializeJson(jsonDoc,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Task<string> GetOrganizationExport(string organizationId, string format = "csv")
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetFileName(string prefix = null, string extension = "csv")
|
||||
{
|
||||
var dateString = DateTime.Now.ToString("yyyyMMddHHmmss");
|
||||
|
||||
return string.Format("bitwarden{0}_export_{1}.{2}",
|
||||
!string.IsNullOrEmpty(prefix) ? ("_" + prefix) : string.Empty, dateString, extension);
|
||||
}
|
||||
|
||||
private void BuildCommonCipher(ExportCipher cipher, CipherView c)
|
||||
{
|
||||
cipher.Type = null;
|
||||
cipher.Name = c.Name;
|
||||
cipher.Notes = c.Notes;
|
||||
cipher.Fields = null;
|
||||
// Login props
|
||||
cipher.LoginUris = null;
|
||||
cipher.LoginUsername = null;
|
||||
cipher.LoginPassword = null;
|
||||
cipher.LoginTotp = null;
|
||||
|
||||
if(c.Fields != null)
|
||||
{
|
||||
foreach(var f in c.Fields)
|
||||
{
|
||||
if(cipher.Fields == null)
|
||||
{
|
||||
cipher.Fields = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
cipher.Fields += "\n";
|
||||
}
|
||||
|
||||
cipher.Fields += (f.Name ?? "") + ": " + f.Value;
|
||||
}
|
||||
}
|
||||
|
||||
switch(c.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
cipher.Type = "login";
|
||||
cipher.LoginUsername = c.Login.Username;
|
||||
cipher.LoginPassword = c.Login.Password;
|
||||
cipher.LoginTotp = c.Login.Totp;
|
||||
|
||||
if(c.Login.Uris != null)
|
||||
{
|
||||
foreach(var u in c.Login.Uris)
|
||||
{
|
||||
if(cipher.LoginUris == null)
|
||||
{
|
||||
cipher.LoginUris = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
cipher.LoginUris += ",";
|
||||
}
|
||||
|
||||
cipher.LoginUris += u.Uri;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
cipher.Type = "note";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private class ExportCipher
|
||||
{
|
||||
[Name("folder")]
|
||||
public string Folder { get; set; }
|
||||
[Name("favorite")]
|
||||
public string Favorite { get; set; }
|
||||
[Name("type")]
|
||||
public string Type { get; set; }
|
||||
[Name("name")]
|
||||
public string Name { get; set; }
|
||||
[Name("notes")]
|
||||
public string Notes { get; set; }
|
||||
[Name("fields")]
|
||||
public string Fields { get; set; }
|
||||
[Name("login_uri")]
|
||||
public string LoginUris { get; set; }
|
||||
[Name("login_username")]
|
||||
public string LoginUsername { get; set; }
|
||||
[Name("login_password")]
|
||||
public string LoginPassword { get; set; }
|
||||
[Name("login_totp")]
|
||||
public string LoginTotp { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,6 +190,11 @@ namespace Bit.Core.Utilities
|
||||
}
|
||||
return JsonConvert.SerializeObject(obj, jsonSerializationSettings);
|
||||
}
|
||||
|
||||
public static string SerializeJson(object obj, JsonSerializerSettings jsonSerializationSettings)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, jsonSerializationSettings);
|
||||
}
|
||||
|
||||
public static T DeserializeJson<T>(string json, bool ignoreNulls = false)
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Bit.Core.Utilities
|
||||
var totpService = new TotpService(storageService, cryptoFunctionService);
|
||||
var authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
||||
i18nService, platformUtilsService, messagingService, lockService);
|
||||
// TODO: export service
|
||||
var exportService = new ExportService(folderService, cipherService);
|
||||
var auditService = new AuditService(cryptoFunctionService, apiService);
|
||||
var environmentService = new EnvironmentService(apiService, storageService);
|
||||
var eventService = new EventService(storageService, apiService, userService, cipherService);
|
||||
@@ -80,6 +80,7 @@ namespace Bit.Core.Utilities
|
||||
Register<IPasswordGenerationService>("passwordGenerationService", passwordGenerationService);
|
||||
Register<ITotpService>("totpService", totpService);
|
||||
Register<IAuthService>("authService", authService);
|
||||
Register<IExportService>("exportService", exportService);
|
||||
Register<IAuditService>("auditService", auditService);
|
||||
Register<IEnvironmentService>("environmentService", environmentService);
|
||||
Register<IEventService>("eventService", eventService);
|
||||
|
||||
Reference in New Issue
Block a user