internal static PasswordRecord Load(this IPasswordRecord r, byte[] key) { var record = new PasswordRecord() { RecordKey = key, Uid = r.RecordUid, Shared = r.Shared, Owner = r.Owner, ClientModified = r.ClientModifiedTime != 0 ? DateTimeOffsetExtensions.FromUnixTimeMilliseconds(r.ClientModifiedTime) : DateTimeOffset.Now, }; var data = r.Data.Base64UrlDecode(); data = CryptoUtils.DecryptAesV1(data, key); using (var ms = new MemoryStream(data)) { var parsedData = (RecordData)DataSerializer.ReadObject(ms); record.Title = parsedData.title; record.Login = parsedData.secret1; record.Password = parsedData.secret2; record.Link = parsedData.link; record.Notes = parsedData.notes; if (parsedData.custom != null) { foreach (var cr in parsedData.custom) { record.Custom.Add(new CustomField { Name = cr.name, Value = cr.value, Type = cr.type }); } } } if (!string.IsNullOrEmpty(r.Extra)) { var extra = CryptoUtils.DecryptAesV1(r.Extra.Base64UrlDecode(), key); using (var ms = new MemoryStream(extra)) { var parsedExtra = (RecordExtra)ExtraSerializer.ReadObject(ms); if (parsedExtra.files != null && parsedExtra.files.Length > 0) { foreach (var file in parsedExtra.files) { var atta = new AttachmentFile { Id = file.id, Key = file.key, Name = file.name, Title = file.title ?? "", Type = file.type ?? "", Size = file.size ?? 0, LastModified = file.lastModified != null ? DateTimeOffsetExtensions.FromUnixTimeMilliseconds(file.lastModified.Value) : DateTimeOffset.Now }; if (file.thumbs != null) { atta.Thumbnails = file.thumbs .Select(t => new AttachmentFileThumb { Id = t.id, Type = t.type, Size = t.size ?? 0 }) .ToArray(); } record.Attachments.Add(atta); } } if (parsedExtra.fields != null) { foreach (var field in parsedExtra.fields) { var fld = new ExtraField(); foreach (var pair in field) { switch (pair.Key) { case "id": fld.Id = pair.Value.ToString(); break; case "field_type": fld.FieldType = pair.Value.ToString(); break; case "field_title": fld.FieldTitle = pair.Value.ToString(); break; default: fld.Custom[pair.Key] = pair.Value; break; } } record.ExtraFields.Add(fld); } } } } return(record); }
public static async Task <PasswordRecord> PutRecord(this VaultOnline vault, PasswordRecord record, bool skipData = false, bool skipExtra = true) { IPasswordRecord existingRecord = null; if (!string.IsNullOrEmpty(record.Uid)) { existingRecord = vault.Storage.Records.GetEntity(record.Uid); } if (existingRecord == null) { return(await vault.AddRecordToFolder(record)); } var updateRecord = new RecordUpdateRecord { RecordUid = existingRecord.RecordUid }; var rmd = vault.ResolveRecordAccessPath(updateRecord, true); if (rmd != null) { if (rmd.RecordKeyType == (int)KeyType.NoKey || rmd.RecordKeyType == (int)KeyType.PrivateKey) { updateRecord.RecordKey = CryptoUtils.EncryptAesV1(record.RecordKey, vault.Auth.AuthContext.DataKey) .Base64UrlEncode(); } } updateRecord.Revision = existingRecord.Revision; if (!skipData) { var dataSerializer = new DataContractJsonSerializer(typeof(RecordData), JsonUtils.JsonSettings); RecordData existingData = null; try { var unencryptedData = CryptoUtils.DecryptAesV1(existingRecord.Data.Base64UrlDecode(), record.RecordKey); using (var ms = new MemoryStream(unencryptedData)) { existingData = (RecordData)dataSerializer.ReadObject(ms); } } catch (Exception e) { Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.RecordUid, e.GetType().Name, e.Message); } var data = record.ExtractRecordData(existingData); using (var ms = new MemoryStream()) { dataSerializer.WriteObject(ms, data); updateRecord.Data = CryptoUtils.EncryptAesV1(ms.ToArray(), record.RecordKey).Base64UrlEncode(); } } if (!skipExtra) { var extraSerializer = new DataContractJsonSerializer(typeof(RecordExtra), JsonUtils.JsonSettings); RecordExtra existingExtra = null; try { var unencryptedExtra = CryptoUtils.DecryptAesV1(existingRecord.Extra.Base64UrlDecode(), record.RecordKey); using (var ms = new MemoryStream(unencryptedExtra)) { existingExtra = (RecordExtra)extraSerializer.ReadObject(ms); } } catch (Exception e) { Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.RecordUid, e.GetType().Name, e.Message); } var extra = record.ExtractRecordExtra(existingExtra); using (var ms = new MemoryStream()) { extraSerializer.WriteObject(ms, extra); updateRecord.Extra = CryptoUtils.EncryptAesV1(ms.ToArray(), record.RecordKey).Base64UrlEncode(); } var udata = new RecordUpdateUData(); var ids = new HashSet <string>(); if (record.Attachments != null) { foreach (var atta in record.Attachments) { ids.Add(atta.Id); if (atta.Thumbnails != null) { foreach (var thumb in atta.Thumbnails) { ids.Add(thumb.Id); } } } } udata.FileIds = ids.ToArray(); updateRecord.Udata = udata; } var command = new RecordUpdateCommand { deviceId = vault.Auth.Endpoint.DeviceName, UpdateRecords = new[] { updateRecord } }; await vault.Auth.ExecuteAuthCommand <RecordUpdateCommand, RecordUpdateResponse>(command); await vault.ScheduleSyncDown(TimeSpan.FromSeconds(0)); return(vault.TryGetRecord(record.Uid, out var r) ? r : record); }