Skip to content
API Documentation
BastionGuard™
PasswordVault.hpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *
17 * BastionGuard™ is a trademark of Calogero Scarnà.
18 * The BastionGuard™ name and branding are not licensed under the GPL.
19 */
20
21#pragma once
22
23#include <string>
24#include <vector>
25#include <functional>
26#include <utility>
27#include <unordered_map>
28#include <mutex>
29#include <atomic>
30#include "PasswordEntry.hpp"
31
33public:
35
36 bool initialize();
37 bool isUnlocked() const;
38
39 bool isFirstRun() const;
40 bool createMasterPassword(const std::string& masterPassword);
41 bool unlock(const std::string& masterPassword);
42 void lock();
43
44 std::vector<PasswordEntry> loadIndex() const;
45 bool saveIndex(const std::vector<PasswordEntry>& entries) const;
46
47 bool addEntry(const PasswordEntry& entry, const std::string& secret);
48 bool updateEntry(const PasswordEntry& entry, const std::string& secret);
49 bool deleteEntry(const std::string& id);
50 void deleteAllEntries(std::function<void(bool)> onDone);
51 void addEntriesBulk(
52 const std::vector<std::pair<PasswordEntry, std::string>>& items,
53 std::function<void(int ok, int fail)> onDone);
54 void exportToCSV(
55 std::function<void(std::string csv, std::string err)> onDone) const;
56 void getSecretAsync(const std::string& id,
57 std::function<void(std::string)> callback) const;
58
59 bool setSecret(const std::string& id, const std::string& secret);
60
61 bool isCacheReady() const { return cacheReady_.load(); }
62
63 std::string generateId() const;
64 std::string nowIso() const;
65 std::string getIndexPath() const;
66
67private:
68 // atomic: letto/scritto sia dal main thread (lock/unlock) sia dal
69 // thread di caricamento cache lanciato in unlock() → senza atomic
70 // sarebbe una data race (UB).
71 std::atomic<bool> unlocked_{ false };
72 std::string masterPassword_;
73 mutable std::unordered_map<std::string, std::string> secretCache_;
74 mutable std::mutex cacheMutex_;
75 mutable std::atomic<bool> cacheReady_{ false };
76
77 // Percorsi
78 std::string getHashPath() const;
79 std::string getSecretsPath() const;
80
81 // Crypto
82 std::string pbkdf2Hex(const std::string& password,
83 const std::string& saltHex,
84 int iterations = 200000) const;
85 std::string generateSaltHex() const;
86 std::string generateNonceHex() const;
87 bool saveSecretsFile(const std::unordered_map<std::string,std::string>& secrets) const;
88 bool loadSecretsFile(std::unordered_map<std::string,std::string>& secrets) const;
89 bool aesEncrypt(const std::string& key32,
90 const std::string& nonce12,
91 const std::string& plaintext,
92 std::string& ciphertext,
93 std::string& tag16) const;
94
95 bool aesDecrypt(const std::string& key32,
96 const std::string& nonce12,
97 const std::string& ciphertext,
98 const std::string& tag16,
99 std::string& plaintext) const;
100 std::string deriveKey(const std::string& saltHex) const;
101 static bool atomicWriteFile(const std::string& path, const std::string& content);
102 void flushAsync(std::unordered_map<std::string,std::string> snapshot) const;
103
104 std::string makeSecretKey(const std::string& id) const;
105};
std::string masterPassword_
std::unordered_map< std::string, std::string > secretCache_
bool setSecret(const std::string &id, const std::string &secret)
bool createMasterPassword(const std::string &masterPassword)
std::string generateId() const
std::mutex cacheMutex_
bool isUnlocked() const
std::atomic< bool > cacheReady_
bool addEntry(const PasswordEntry &entry, const std::string &secret)
std::string pbkdf2Hex(const std::string &password, const std::string &saltHex, int iterations=200000) const
std::string getSecretsPath() const
std::atomic< bool > unlocked_
std::string generateNonceHex() const
std::string getHashPath() const
void flushAsync(std::unordered_map< std::string, std::string > snapshot) const
bool isCacheReady() const
std::string generateSaltHex() const
bool isFirstRun() const
bool loadSecretsFile(std::unordered_map< std::string, std::string > &secrets) const
bool aesEncrypt(const std::string &key32, const std::string &nonce12, const std::string &plaintext, std::string &ciphertext, std::string &tag16) const
std::string nowIso() const
std::string makeSecretKey(const std::string &id) const
void getSecretAsync(const std::string &id, std::function< void(std::string)> callback) const
bool aesDecrypt(const std::string &key32, const std::string &nonce12, const std::string &ciphertext, const std::string &tag16, std::string &plaintext) const
bool unlock(const std::string &masterPassword)
std::string deriveKey(const std::string &saltHex) const
bool updateEntry(const PasswordEntry &entry, const std::string &secret)
static bool atomicWriteFile(const std::string &path, const std::string &content)
bool saveSecretsFile(const std::unordered_map< std::string, std::string > &secrets) const
std::string getIndexPath() const
void deleteAllEntries(std::function< void(bool)> onDone)
std::vector< PasswordEntry > loadIndex() const
void exportToCSV(std::function< void(std::string csv, std::string err)> onDone) const
bool deleteEntry(const std::string &id)
void addEntriesBulk(const std::vector< std::pair< PasswordEntry, std::string > > &items, std::function< void(int ok, int fail)> onDone)
bool saveIndex(const std::vector< PasswordEntry > &entries) const