public void EncryptedDataWithPasswordBytes()
 {
     var encryptedData = new EncryptedDataWithPassword(Encoding.UTF8.GetBytes(TestString), TestPassword);
     var encryptedDataString = encryptedData.ToString();
     var decryptedTestBytes = EncryptedDataWithPassword.DecryptDataAsBytes(encryptedDataString, TestPassword);
     Assert.AreEqual(TestString, Encoding.UTF8.GetString(decryptedTestBytes));
 }
 public void EncryptedDataWithPasswordString()
 {
     var encryptedData = new EncryptedDataWithPassword(TestString, TestPassword);
     var encryptedDataString = encryptedData.ToString();
     
     var decryptedTestString = EncryptedDataWithPassword.DecryptData(TestPassword, encryptedDataString);
     Assert.AreEqual(TestString, decryptedTestString);
 }
        private void BackupEntrySecrets()
        {
            var accountSettings = _model.ServerAccountSettings.Query().First();

            if (!accountSettings.BackupRecoveryPasswordHashSet)
                return;

            var secrets = _model.EntriesSharedSecrets.Query().ToList();
            foreach (var secret in secrets)
            {
                var entry = _model.Entries.Query().First(r => r.Id == secret.EntryId);
                var database = _model.Links.Query().First(r => r.Id == entry.LinkId);

                if (secret.ToBeDeleted)
                {
                    var deleteRequest = new DeleteDatabaseEntryDeviceSecret
                    {
                        LinkIdentifier = database.Identifier,
                        SecretIdentifier = secret.SecretIdentifier
                    };

                    try
                    {
                        deleteRequest.GetResponse(GetApiClient());
                    }
                    catch (RequestException)
                    {
                        // Try again next time.
                        continue;
                    }

                    _model.EntriesSharedSecretsData.Delete(secret.EntrySecretDataId);
                    _model.EntriesSharedSecrets.Delete(secret.Id);

                    continue;
                }

                // Is there an update request for this entry?
                var updateRequests = _model.EntriesSharedSecretsSync.Query()
                    .Where(r => r.EntrySecretId == secret.Id).ToList();

                if (updateRequests.Count == 0)
                    continue;

                var updateRequestsSorted = updateRequests.OrderByDescending(update => update.CreatedAt);
                var latestUpdateRequest = updateRequestsSorted.First();
                
                // Remove duplicate update requests
                foreach (var updateRequest in updateRequestsSorted)
                {
                    if (updateRequest.Id == latestUpdateRequest.Id)
                        continue;

                    _model.EntriesSharedSecretsSync.Delete(updateRequest.Id);
                }
                
                var secretData = _model.EntriesSharedSecretsData.Query().First(r => r.Id == secret.EntrySecretDataId);
                var serializedEntry = JsonConvert.SerializeObject(secretData);
                var encryptedData = new EncryptedDataWithPassword(
                    Compression.Compress(serializedEntry), accountSettings.BackupRecoveryPasswordHash).ToString();
                
                var request = new SetDatabaseEntryDeviceSecret
                {
                    LinkIdentifier = database.Identifier,
                    EntryIdentifier = entry.Identifier,
                    SecretIdentifier = secret.SecretIdentifier,
                    DataType = "ModelJsonGz",
                    Data = encryptedData
                };

                try
                {
                    request.GetResponse(GetApiClient());
                }
                catch (RequestException)
                {
                    // Try again later
                    continue;
                }
                
                // Sync completed
                _model.EntriesSharedSecretsSync.Delete(latestUpdateRequest.Id);
            }
        }
Beispiel #4
0
        private void SyncDatabaseUploadEntries(int databaseId)
        {
            if (_databaseEntriesUploadRunning)
                return;

            if (_requestErrors > 0)
                return;

            var serverAccount = GetServerAccount();
            var linkedClientCryptoKey = Model.CryptoKeys.Get(serverAccount.LinkedDeviceCryptoKeyId);
            var database = Model.Databases.Get(databaseId);

            var entriesToBeDeleted = Model.DatabasesEntries.Find(new DatabaseEntry {ToBeDeleted = true}).ToList();
            foreach (var entryToBeDeleted in entriesToBeDeleted)
            {
                if (_stopSyncLoop || _processMessagesOnly)
                    return;

                var deleteRequest = new DeleteDatabaseEntry
                {
                    LinkIdentifier = database.Identifier,
                    EntryIdentifier = entryToBeDeleted.Identifier
                };

                var deleteOnDeviceMessageContent = new DeviceToDeviceMessages.DeleteEntry
                {
                    LinkIdentifier = database.Identifier,
                    EntryIdentifier = entryToBeDeleted.Identifier
                };
                var deleteOnDeviceMessageRequest = new SendLinkedDeviceMessage();
                deleteOnDeviceMessageRequest.SetMessage(deleteOnDeviceMessageContent, linkedClientCryptoKey.PublicKeyPem);

                try
                {
                    deleteRequest.GetResponse(GetApiClient());
                    deleteOnDeviceMessageRequest.GetResponse(GetApiClient());

                    _requestErrors = 0;
                }
                catch (NetworkErrorException)
                {
                    _requestErrors++;
                    return;
                }
                catch (RequestException)
                {
                    // Try again next time.
                    continue;
                }

                var versions = Model.DatabasesEntriesDataVersions.Find(new DatabaseEntryDataVersion
                {
                    DatabaseEntryId = entryToBeDeleted.Id
                });
                foreach (var version in versions)
                {
                    Model.DatabasesEntriesData.Delete(version.DatabaseEntryDataId);
                    Model.DatabasesEntriesDataVersions.Delete(version.Id);
                }

                Model.DatabasesEntries.Delete(entryToBeDeleted.Id);
            }

            _databaseEntriesUploadRunning = true;
            Task.Run(() =>
            {
                var databaseEntries = Model.DatabasesEntries.Find(new DatabaseEntry { DatabaseId = databaseId });

                var entriesToSend = new List<DatabaseEntry>();
                var entriesDataToSend = new List<DatabaseEntryData>();
                var entriesDataSerialized = new List<string>();
                var entriesSyncRequest = new List<DatabaseEntryDataSync>();
                var entriesUploadItems = new List<SetDatabaseEntries.EntryItem>();

                foreach (var entry in databaseEntries)
                {
                    if (_stopSyncLoop || _processMessagesOnly)
                    {
                        _databaseEntriesUploadRunning = false;
                        return;
                    }

                    var entryData = Model.DatabasesEntriesData.Get(entry.DatabaseEntryDataId);
                    if (!entryData.PasswordShared)
                        continue;

                    // Is there an update request for this entry?
                    var updateRequests = Model.DatabasesEntriesDataSync.Find(new DatabaseEntryDataSync
                    {
                        DatabaseEntryId = entry.Id
                    });
                    var updateRequestsSorted = updateRequests?.OrderByDescending(update => update.CreatedAt);
                    var latestUpdateRequest = updateRequestsSorted?.FirstOrDefault();
                    if (latestUpdateRequest == null)
                        continue;

                    // Remove duplicate update requests
                    foreach (var updateRequest in updateRequestsSorted)
                    {
                        if (updateRequest.Id == latestUpdateRequest.Id)
                            continue;

                        Model.DatabasesEntriesDataSync.Delete(updateRequest.Id);
                    }

                    var newVersion = entry.Version + 1;
                    var serializedEntry = JsonConvert.SerializeObject(entryData);
                    var encryptedData = new EncryptedDataWithPassword(
                        Util.CompressData(serializedEntry), serverAccount.BackupEncryptionPassword).ToString();

                    var group = Model.DatabasesGroups.Get(entry.DatabaseGroupId);
                    entriesUploadItems.Add(new SetDatabaseEntries.EntryItem
                    {
                        Version = newVersion,
                        GroupIdentifier = group.Identifier,
                        EntryIdentifier = entry.Identifier,
                        DataType = "ModelJsonGz",
                        Data = encryptedData
                    });

                    entriesToSend.Add(entry);
                    entriesDataToSend.Add(entryData);
                    entriesDataSerialized.Add(serializedEntry);
                    entriesSyncRequest.Add(latestUpdateRequest);
                }

                if (entriesToSend.Count == 0)
                {
                    _databaseEntriesUploadRunning = false;
                    return;
                }

                _controller.SetDatabaseSyncStatus(databaseId, Statuses.Syncing);

                var request = new SetDatabaseEntries
                {
                    LinkIdentifier = database.Identifier,
                    Entries = entriesUploadItems
                };

                try
                {
                    request.GetResponse(GetApiClient());
                    _requestErrors = 0;
                }
                catch (ConflictException)
                {
                    if (Program.AppEnvDebug)
                        throw new NotImplementedException("TODO: Download update to group");
                    _databaseEntriesUploadRunning = false;
                    return;
                }
                catch (NetworkErrorException)
                {
                    _requestErrors++;
                    _databaseEntriesUploadRunning = false;
                    return;
                }
                catch (RequestException)
                {
                    _databaseEntriesUploadRunning = false;
                    return;
                }

                for (var i = 0; i < entriesToSend.Count; i++)
                {
                    var entry = entriesToSend[i];
                    var entryUploadItem = entriesUploadItems[i];
                    var serializedEntry = entriesDataSerialized[i];
                    var latestUpdateRequest = entriesSyncRequest[i];
                    var newVersion = entryUploadItem.Version;

                    // Create archive version
                    var archiveData = JsonConvert.DeserializeObject<DatabaseEntryData>(serializedEntry);
                    archiveData.RemoveId();
                    var archiveDataId = Model.DatabasesEntriesData.Create(archiveData);
                    Model.DatabasesEntriesDataVersions.Create(new DatabaseEntryDataVersion
                    {
                        DatabaseEntryId = entry.Id,
                        Version = newVersion,
                        DatabaseEntryDataId = archiveDataId
                    });

                    // Update current record
                    Model.DatabasesEntries.Update(entry.Id, new DatabaseEntry
                    {
                        Version = newVersion
                    });

                    // Sync completed
                    Model.DatabasesEntriesDataSync.Delete(latestUpdateRequest.Id);
                }
                
                _controller.SetDatabaseSyncStatus(databaseId, Statuses.UpToDate);
                _databaseEntriesUploadRunning = false;
            });
        }
Beispiel #5
0
        private void SyncDatabaseUploadGroups(int databaseId)
        {
            var serverAccount = GetServerAccount();
            var database = Model.Databases.Get(databaseId);
            var databaseGroups = Model.DatabasesGroups.Find(new DatabaseGroup {DatabaseId = databaseId});
            foreach (var group in databaseGroups)
            {
                if (_stopSyncLoop)
                    return;

                if (_processMessagesOnly)
                    return;

                var updateRequests = Model.DatabasesGroupsMetaSync.Find(new DatabaseGroupMetaSync
                {
                    DatabaseGroupId = group.Id
                });
                var updateRequestsSorted = updateRequests?.OrderByDescending(update => update.CreatedAt);
                var latestUpdateRequest =updateRequestsSorted?.FirstOrDefault();
                
                if (latestUpdateRequest == null)
                    continue;
                
                _controller.SetDatabaseSyncStatus(databaseId, Statuses.Syncing);

                // Remove duplicate update requests
                foreach (var updateRequest in updateRequestsSorted)
                {
                    if (updateRequest.Id == latestUpdateRequest.Id)
                        continue;

                    Model.DatabasesGroupsMetaSync.Delete(updateRequest.Id);
                }

                var newVersion = group.Version + 1;
                var groupMeta = Model.DatabasesGroupsMeta.Get(group.DatabaseGroupMetaId);
                var serializedEntry = JsonConvert.SerializeObject(groupMeta);
                var encryptedData = new EncryptedDataWithPassword(
                    Util.CompressData(serializedEntry), serverAccount.BackupEncryptionPassword).ToString();
                
                var request = new SetDatabaseGroup
                {
                    Version = newVersion,
                    DatabaseIdentifier = database.Identifier,
                    GroupIdentifier = group.Identifier,
                    DataType = "ModelJsonGz",
                    Data = encryptedData
                };

                try
                {
                    request.GetResponse(GetApiClient());
                    _requestErrors = 0;
                }
                catch (ConflictException)
                {
                    if (Program.AppEnvDebug)
                        throw new NotImplementedException("TODO: Download update to group");
                    continue;
                }
                catch (NetworkErrorException)
                {
                    _requestErrors++;
                    return;
                }
                catch (RequestException)
                {
                    continue;
                }

                // Create archive version
                var archiveMetaData = JsonConvert.DeserializeObject<DatabaseGroupMeta>(serializedEntry);
                archiveMetaData.RemoveId();
                var archiveMetaDataId = Model.DatabasesGroupsMeta.Create(archiveMetaData);
                Model.DatabasesGroupsMetaVersions.Create(new DatabaseGroupMetaVersion
                {
                    DatabaseGroupId = group.Id,
                    Version = newVersion,
                    DatabaseGroupMetaId = archiveMetaDataId
                });

                // Update current record
                Model.DatabasesGroups.Update(group.Id, new DatabaseGroup
                {
                    Version = newVersion
                });

                // Sync completed
                Model.DatabasesGroupsMetaSync.Delete(latestUpdateRequest.Id);

                _controller.SetDatabaseSyncStatus(databaseId, Statuses.UpToDate);
            }
        }