Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- void Main()
- {
- var outputPath = $@"./bitwarden_import/bitwarden_importdata{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.json";
- var teamsidPersonalCsv = @"./teamsid_export/indivisual_records_2019-01-12 20_08_36.csv";
- var teamsidOrganizationCsv = @"./teamsid_export/Organization_records_2019-01-12 21_20_10.csv";
- var teamsidCsvs = new[] { teamsidPersonalCsv, teamsidOrganizationCsv };
- var bitwardenFolderDefinitionJson = @"./bitwarden_export/bitwarden_export_folder_definition.json";
- // deserialize folder definitions
- BitwardenFolderDefinition DeserializeFolderJson(string path)
- {
- using (var stream = File.OpenRead(path))
- {
- var folders = Utf8Json.JsonSerializer.Deserialize<BitwardenFolderDefinition>(stream);
- return folders;
- }
- }
- var folderDefinition = DeserializeFolderJson(bitwardenFolderDefinitionJson);
- // convert teamsid to bitwarden
- var combinedResult = teamsidCsvs.SelectMany(json =>
- {
- var parser = new CsvParser(json);
- var teamsIdDatas = parser.Parse<TeamsId>();
- var bitwardenItems = new BitwardenConverter().Convert(teamsIdDatas, folderDefinition, "Socials");
- return bitwardenItems;
- })
- .ToArray();
- combinedResult.Dump();
- // serialize bitwarden import data
- var importData = new BitwardenDefinition
- {
- folders = folderDefinition.folders,
- items = combinedResult,
- };
- var jsonBytes = Utf8Json.JsonSerializer.Serialize<BitwardenDefinition>(importData);
- // output json
- File.WriteAllBytes(outputPath, jsonBytes);
- }
- public class BitwardenConverter
- {
- private class FieldRecord
- {
- public string Url { get; set; }
- public string Email { get; set; }
- public string UserName { get; set; }
- public string Password { get; set; }
- public (string key, string value)[] SecureFields { get; set; }
- public (string key, string value)[] Fields { get; set; }
- public string Group { get; set; }
- }
- public BitwardenItem[] Convert(TeamsId[] from, BitwardenFolderDefinition folderDefinition, string defaultGroup = null)
- {
- var records = from
- .Select(record =>
- {
- // reflection to check fieldXX and get valueXX
- var t = record.GetType();
- var props = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
- var description = GetPropertyValue(record, t, "description");
- var note = GetPropertyValue(record, t, "note");
- var fieldRecord = ParseFieldRecord(props, t, record, defaultGroup);
- // generate typed item
- var bitwarden = new BitwardenItem
- {
- id = Guid.NewGuid().ToString(),
- organizationId = null,
- collectionIds = null,
- type = 1,
- name = description,
- login = new BitwardenLogin
- {
- username = fieldRecord.UserName,
- password = fieldRecord.Password,
- uris = new[] {
- new BitwardenUri
- {
- uri = fieldRecord.Url,
- match = null,
- }
- }
- },
- favorite = false,
- notes = note,
- folderId = folderDefinition.GetId(fieldRecord.Group),
- };
- // initialize fields
- var customField = fieldRecord.Fields == null
- ? Array.Empty<BitwardenField>()
- : fieldRecord.Fields.Select(x => new BitwardenField { name = x.key, value = x.value, type = 0 });
- var customSecretField = fieldRecord.SecureFields == null
- ? Array.Empty<BitwardenField>()
- : fieldRecord.SecureFields.Select(x => new BitwardenField { name = x.key, value = x.value, type = 1 });
- var fields = customField.Concat(customSecretField).ToArray();
- if (fields.Any())
- {
- bitwarden.fields = fields;
- }
- return bitwarden;
- })
- .ToArray();
- return records;
- }
- private FieldRecord ParseFieldRecord(PropertyInfo[] props, Type t, TeamsId source, string defaultGroup = null)
- {
- var fieldRecord = new FieldRecord();
- // get FieldXX properties via reflection
- var fieldRecords = props
- .Where(x => Match(x.Name, @"Field\d+"))
- .Where(x => GetPropertyValue(source, t, x.Name) != "")
- .Select(x => (key: GetPropertyValue(source, t, x.Name), value: GetPropertyValue(source, t, x.Name.Replace("Field", "Value"))))
- .ToArray();
- // get field's value and categolize each via field name regex pattern
- var secureMemoList = new List<(string, string)>();
- var memoList = new List<(string, string)>();
- foreach (var record in fieldRecords)
- {
- switch (record.key)
- {
- case var _ when Match(record.key, "url") && fieldRecord.Url == null:
- fieldRecord.Url = record.value;
- break;
- case var _ when Match(record.key, "email|e-mail") && fieldRecord.Email == null:
- fieldRecord.Email = record.value;
- break;
- case var _ when Match(record.key, "username") && fieldRecord.UserName == null:
- fieldRecord.UserName = record.value;
- break;
- case var _ when Match(record.key, "password") && fieldRecord.Password == null:
- fieldRecord.Password = record.value;
- break;
- case var _ when Match(record.key, "pass|access|secret|pin|token|enctypt"):
- secureMemoList.Add((record.key, record.value));
- break;
- case var _ when Match(record.key, "group"):
- fieldRecord.Group = record.value;
- break;
- default:
- memoList.Add((record.key, record.value));
- break;
- }
- }
- // group fallback
- if (defaultGroup != null && string.IsNullOrWhiteSpace(fieldRecord.Group))
- {
- fieldRecord.Group = defaultGroup;
- }
- fieldRecord.Fields = memoList.ToArray();
- fieldRecord.SecureFields = secureMemoList.ToArray();
- return fieldRecord;
- }
- private bool Match(string text, string pattern)
- {
- return Regex.IsMatch(text, pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
- }
- private string GetPropertyValue(TeamsId record, Type t, string propertyField)
- {
- return (string)t.GetProperty(propertyField).GetValue(record);
- }
- }
- public class CsvParser
- {
- private readonly string path;
- public CsvParser(string path)
- {
- this.path = path;
- }
- public T[] Parse<T>() where T : class
- {
- using (var reader = new StreamReader(path))
- using (var csv = new CsvReader(reader))
- {
- csv.Configuration.MissingFieldFound = null;
- var records = csv.GetRecords<T>();
- return records.ToArray();
- }
- }
- }
- public class BitwardenDefinition
- {
- public BitwardenFolder[] folders { get; set; }
- public BitwardenItem[] items {get;set;}
- }
- public class BitwardenItem
- {
- public string id { get; set; }
- public string organizationId { get; set; }
- public string collectionIds { get; set; }
- public bool favorite { get; set; }
- public string folderId { get; set; }
- // login = 1, card = 3
- public int type { get; set; }
- public string name { get; set; }
- public string notes { get; set; }
- public BitwardenField[] fields { get; set; }
- public BitwardenLogin login { get; set; }
- }
- public class BitwardenLogin
- {
- public BitwardenUri[] uris { get; set; }
- public string username { get; set; }
- public string password { get; set; }
- // authenticator = null (premium only)
- public string totp { get; set; }
- }
- public class BitwardenUri
- {
- // default = null
- public object match { get; set; }
- public string uri { get; set; }
- }
- public class BitwardenField
- {
- public string name { get; set; }
- public string value { get; set; }
- // custom = 0, hidden = 1, boolean = 2
- public int type { get; set; }
- }
- public class BitwardenFolderDefinition
- {
- public BitwardenFolder[] folders { get; set; }
- private static readonly string defaultIdName = "Social";
- public string GetId(string name)
- {
- if (folders == null || !folders.Any()) return defaultIdName;
- return folders.FirstOrDefault(x => x.name == name)?.id ?? defaultIdName;
- }
- }
- public class BitwardenFolder
- {
- public string id { get; set; }
- public string name { get; set; }
- }
- public class TeamsId
- {
- public string description { get; set; }
- public string note { get; set; }
- public string Field0 { get; set; }
- public string Type0 { get; set; }
- public string Value0 { get; set; }
- public string Field1 { get; set; }
- public string Type1 { get; set; }
- public string Value1 { get; set; }
- public string Field2 { get; set; }
- public string Type2 { get; set; }
- public string Value2 { get; set; }
- public string Field3 { get; set; }
- public string Type3 { get; set; }
- public string Value3 { get; set; }
- public string Field4 { get; set; }
- public string Type4 { get; set; }
- public string Value4 { get; set; }
- public string Field5 { get; set; }
- public string Type5 { get; set; }
- public string Value5 { get; set; }
- public string Field6 { get; set; }
- public string Type6 { get; set; }
- public string Value6 { get; set; }
- public string Field7 { get; set; }
- public string Type7 { get; set; }
- public string Value7 { get; set; }
- public string Field8 { get; set; }
- public string Type8 { get; set; }
- public string Value8 { get; set; }
- public string Field9 { get; set; }
- public string Type9 { get; set; }
- public string Value9 { get; set; }
- public string Field10 { get; set; }
- public string Type10 { get; set; }
- public string Value10 { get; set; }
- public string Field11 { get; set; }
- public string Type11 { get; set; }
- public string Value11 { get; set; }
- public string Field12 { get; set; }
- public string Type12 { get; set; }
- public string Value12 { get; set; }
- }
Add Comment
Please, Sign In to add comment