less flushing

This commit is contained in:
2026-04-27 11:30:30 +02:00
parent 32641f97de
commit 0f95cb9aba
5 changed files with 36 additions and 26 deletions

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@
/build /build
*.py *.py
*.dull *.dull
/TODO
/.clangd

View File

@@ -1,11 +1,10 @@
#pragma once #pragma once
#include "common.h" #include "common.h"
#include <algorithm>
#include <botan/aead.h> #include <botan/aead.h>
#include <botan/auto_rng.h> #include <botan/auto_rng.h>
#include <botan/pwdhash.h> #include <botan/pwdhash.h>
#include <algorithm>
namespace Crypto { namespace Crypto {
inline Botan::secure_vector<u8> encrypt(const Botan::secure_vector<u8> &key, inline Botan::secure_vector<u8> encrypt(const Botan::secure_vector<u8> &key,
@@ -16,15 +15,16 @@ inline Botan::secure_vector<u8> encrypt(const Botan::secure_vector<u8> &key,
// XChaCha20 is selected automatically based on the nonce size // XChaCha20 is selected automatically based on the nonce size
// https://github.com/randombit/botan/blob/master/src/lib/stream/chacha/chacha.cpp#L375 // https://github.com/randombit/botan/blob/master/src/lib/stream/chacha/chacha.cpp#L375
static auto cipher = Botan::AEAD_Mode::create_or_throw( static thread_local auto cipher = Botan::AEAD_Mode::create_or_throw(
"ChaCha20Poly1305", Botan::Cipher_Dir::Encryption); "ChaCha20Poly1305", Botan::Cipher_Dir::Encryption);
cipher->clear();
auto nonce = rng.random_array<24>(); auto nonce = rng.random_array<24>();
cipher->set_key(key); cipher->set_key(key);
cipher->start(nonce); cipher->start(nonce);
Botan::secure_vector<u8> res; Botan::secure_vector<u8> res;
res.resize(24 + plaintext.size() + 16); res.resize(24 + plaintext.size());
std::ranges::copy(nonce, res.begin()); std::ranges::copy(nonce, res.begin());
std::ranges::copy(plaintext, res.begin() + 24); std::ranges::copy(plaintext, res.begin() + 24);
cipher->finish(res, 24); cipher->finish(res, 24);
@@ -40,8 +40,9 @@ decrypt(const Botan::secure_vector<u8> &key,
std::array<u8, 24> nonce{}; std::array<u8, 24> nonce{};
std::copy_n(ciphertext_with_nonce.begin(), 24, nonce.begin()); std::copy_n(ciphertext_with_nonce.begin(), 24, nonce.begin());
static auto cipher = Botan::AEAD_Mode::create_or_throw( static thread_local auto cipher = Botan::AEAD_Mode::create_or_throw(
"ChaCha20Poly1305", Botan::Cipher_Dir::Decryption); "ChaCha20Poly1305", Botan::Cipher_Dir::Decryption);
cipher->clear();
cipher->set_key(key); cipher->set_key(key);
cipher->start(nonce); cipher->start(nonce);

View File

@@ -70,10 +70,9 @@ MainWindow::MainWindow(QWidget *parent)
ui->statusbar->showMessage("Creating the vault..."); ui->statusbar->showMessage("Creating the vault...");
QCoreApplication::processEvents(); QCoreApplication::processEvents();
Vault::create(path.toStdString(), password.toStdString());
m_vault = m_vault =
std::make_unique<Vault>(path.toStdString(), password.toStdString()); Vault::create_and_open(path.toStdString(), password.toStdString());
ui->statusbar->showMessage("Opened " + path); ui->statusbar->showMessage("Opened " + path);
reload_fs_tree(); reload_fs_tree();
@@ -134,6 +133,7 @@ MainWindow::MainWindow(QWidget *parent)
file.read(content.data(), size); file.read(content.data(), size);
m_vault->create_file(basename(path.toStdString()), content); m_vault->create_file(basename(path.toStdString()), content);
} }
m_vault->flush();
reload_fs_tree(); reload_fs_tree();
ui->statusbar->showMessage("Added " + QString::number(paths.size()) + ui->statusbar->showMessage("Added " + QString::number(paths.size()) +
@@ -304,6 +304,7 @@ void MainWindow::file_context_menu(const QPoint &pos) {
style()->standardIcon(QStyle::SP_DialogCancelButton), "Delete"); style()->standardIcon(QStyle::SP_DialogCancelButton), "Delete");
connect(delete_action, &QAction::triggered, this, [this, item]() { connect(delete_action, &QAction::triggered, this, [this, item]() {
m_vault->delete_file(item->text(0).toStdString()); m_vault->delete_file(item->text(0).toStdString());
m_vault->flush();
reload_fs_tree(); reload_fs_tree();
}); });
@@ -346,6 +347,7 @@ void MainWindow::dropEvent(QDropEvent *event) {
file.read(content.data(), size); file.read(content.data(), size);
m_vault->create_file(basename(u.toLocalFile().toStdString()), content); m_vault->create_file(basename(u.toLocalFile().toStdString()), content);
} }
m_vault->flush();
ui->statusbar->showMessage( ui->statusbar->showMessage(
"Added " + QString::number(event->mimeData()->urls().size()) + " files"); "Added " + QString::number(event->mimeData()->urls().size()) + " files");
reload_fs_tree(); reload_fs_tree();

View File

@@ -49,7 +49,8 @@ Vault::Vault(std::string path, const std::string &password)
build_file_map(); build_file_map();
} }
void Vault::create(const std::string &path, const std::string &password) { std::unique_ptr<Vault> Vault::create_and_open(const std::string &path,
const std::string &password) {
static Botan::AutoSeeded_RNG rng; static Botan::AutoSeeded_RNG rng;
auto salt = rng.random_array<16>(); auto salt = rng.random_array<16>();
@@ -64,6 +65,8 @@ void Vault::create(const std::string &path, const std::string &password) {
WRITE(file, to_char_ptr(salt.data()), 16); WRITE(file, to_char_ptr(salt.data()), 16);
WRITE(file, to_char_ptr(check_ciphertext.data()), 46); WRITE(file, to_char_ptr(check_ciphertext.data()), 46);
file.close(); file.close();
return std::make_unique<Vault>(path, password);
} }
void Vault::build_file_map() { void Vault::build_file_map() {
@@ -86,8 +89,8 @@ void Vault::build_file_map() {
} }
} }
std::string Vault::read_file(const std::string &filename) { std::string Vault::read_file(const std::string &name) {
auto header = m_file_map.at(filename); auto header = m_file_map.at(name);
ASSERT(!header.deleted); ASSERT(!header.deleted);
m_file.clear(); m_file.clear();
@@ -102,14 +105,15 @@ std::string Vault::read_file(const std::string &filename) {
return {to_char_ptr(plaintext.data()), plaintext.size()}; return {to_char_ptr(plaintext.data()), plaintext.size()};
} }
void Vault::create_file(const std::string &filename, void Vault::create_file(const std::string &name, const std::string &content) {
const std::string &content) { ASSERT(!m_file_map.contains(name));
m_file.clear(); m_file.clear();
m_file.seekp(0, std::ios::end); m_file.seekp(0, std::ios::end);
auto offset = m_file.tellp(); auto offset = m_file.tellp();
auto name_ciphertext = Crypto::encrypt(m_key, to_span(filename)); auto name_ciphertext = Crypto::encrypt(m_key, to_span(name));
u64 name_ciphertext_size = name_ciphertext.size(); u64 name_ciphertext_size = name_ciphertext.size();
auto ciphertext = Crypto::encrypt(m_key, to_span(content)); auto ciphertext = Crypto::encrypt(m_key, to_span(content));
@@ -122,20 +126,19 @@ void Vault::create_file(const std::string &filename,
WRITE(m_file, &ciphertext_size, sizeof(u64)); WRITE(m_file, &ciphertext_size, sizeof(u64));
auto content_offset = m_file.tellp(); auto content_offset = m_file.tellp();
WRITE(m_file, ciphertext.data(), ciphertext_size); WRITE(m_file, ciphertext.data(), ciphertext_size);
m_file.flush();
m_file_map[filename] = FileHeader{ m_file_map[name] = FileHeader{
.offset = static_cast<u64>(offset), .offset = static_cast<u64>(offset),
.deleted = false, .deleted = false,
.name_ciphertext_size = name_ciphertext_size, .name_ciphertext_size = name_ciphertext_size,
.name = filename, .name = name,
.content_ciphertext_size = ciphertext_size, .content_ciphertext_size = ciphertext_size,
.content_offset = static_cast<u64>(content_offset), .content_offset = static_cast<u64>(content_offset),
}; };
} }
void Vault::delete_file(const std::string &filename) { void Vault::delete_file(const std::string &name) {
auto header = m_file_map.at(filename); auto header = m_file_map.at(name);
// zero the ciphertext and mark as deleted // zero the ciphertext and mark as deleted
m_file.clear(); m_file.clear();
@@ -152,15 +155,14 @@ void Vault::delete_file(const std::string &filename) {
m_file.seekp(static_cast<i64>(header.offset), std::ios::beg); m_file.seekp(static_cast<i64>(header.offset), std::ios::beg);
bool deleted = true; bool deleted = true;
WRITE(m_file, &deleted, sizeof(bool)); WRITE(m_file, &deleted, sizeof(bool));
m_file.flush();
m_file_map.erase(filename); m_file_map.erase(name);
} }
void Vault::update_file(const std::string &filename, void Vault::update_file(const std::string &name, const std::string &content) {
const std::string &content) { delete_file(name);
delete_file(filename); create_file(name, content);
create_file(filename, content); flush();
} }
std::optional<FileHeader> Vault::read_file_header() { std::optional<FileHeader> Vault::read_file_header() {

View File

@@ -3,6 +3,7 @@
#include "common.h" #include "common.h"
#include <botan/secmem.h> #include <botan/secmem.h>
#include <fstream> #include <fstream>
#include <memory>
#include <optional> #include <optional>
#include <unordered_map> #include <unordered_map>
@@ -22,12 +23,14 @@ class Vault {
public: public:
explicit Vault(std::string path, const std::string &password); explicit Vault(std::string path, const std::string &password);
static void create(const std::string &path, const std::string &password); static std::unique_ptr<Vault> create_and_open(const std::string &path,
const std::string &password);
std::string read_file(const std::string &name); std::string read_file(const std::string &name);
void create_file(const std::string &name, const std::string &content); void create_file(const std::string &name, const std::string &content);
void delete_file(const std::string &name); void delete_file(const std::string &name);
void update_file(const std::string &name, const std::string &content); void update_file(const std::string &name, const std::string &content);
void flush() { m_file.flush(); }
const std::string &path() const { return m_path; } const std::string &path() const { return m_path; }
const std::unordered_map<std::string, FileHeader> &file_map() const { const std::unordered_map<std::string, FileHeader> &file_map() const {