Skip to content
Snippets Groups Projects
Verified Commit efad7a87 authored by Daniel Lyubomirov's avatar Daniel Lyubomirov
Browse files

[17] docs

parent 503ae787
No related branches found
No related tags found
1 merge request!97Crypto Storage and LoginWithNewDevice and LoginWithPreviouslyAddedDevice APIs
#include "vereign/crypto/rand.hh"
#include <vereign/bytes/view.hh>
#include <vereign/bytes/buffer.hh>
#include <vereign/bytes/view_dump.hh>
#include <vereign/fs/path.hh>
#include <vereign/fs/util.hh>
#include <iostream>
auto main(int argc, char** argv) -> int {
argc = 0;
argv = nullptr;
auto path = vereign::fs::TempFilePath(vereign::fs::path::Join("tmp", "foo"), "test_db_");
std::cout << path << std::endl;
return 0;
}
......@@ -9,7 +9,64 @@
namespace vereign::bytes {
namespace detail {
class ViewDump;
}
/**
* Returns a view dump object that can write the view dump into std::ostream.
*
* The dump is the good old hexadecimal format.
*
* Example:
* @code
* std::string input{"foo bar"};
* std::cout << bytes::dump(bytes::View(input)) << std::endl;
*
* // Output:
* // 0x0000: 666f 6f20 6261 72 foo bar
*
* auto buf = crypto::Rand(32);
* std::cout << bytes::dump(buf.View()) << std::endl;
*
* // Output:
* // 0x0000: 1666 855a 650a 7549 ed0f ec01 4d87 09bf .f.Ze.uI....M...
* // 0x0010: e644 dbc8 7943 37b4 185c dbab 4977 ff3f .D..yC7..\..Iw.?
*
* @endcode
*/
auto dump(View buf) -> detail::ViewDump;
/**
* Returns a dump object that can write the buffer dump into std::ostream.
*
* The dump is the good old hexadecimal format.
*
* Example:
* @code
auto buf = bytes::Buffer{bytes::View("foo bar")};
std::cout << bytes::dump(buf) << std::endl;
*
* // Output:
* // 0x0000: 666f 6f20 6261 72 foo bar
*
* auto buf = crypto::Rand(32);
* std::cout << bytes::dump(buf) << std::endl;
*
* // Output:
* // 0x0000: 1666 855a 650a 7549 ed0f ec01 4d87 09bf .f.Ze.uI....M...
* // 0x0010: e644 dbc8 7943 37b4 185c dbab 4977 ff3f .D..yC7..\..Iw.?
*
* @endcode
*/
auto dump(const Buffer& buf) -> detail::ViewDump;
namespace detail {
/**
* Helper for dumping a view to a std::ostream.
*
* Users typically will use the bytes::dump functions.
*/
class ViewDump {
public:
auto operator=(const ViewDump&) -> ViewDump& = delete;
......@@ -27,11 +84,8 @@ private:
private:
View buf_;
};
} // namespace detail
auto dump(View buf) -> detail::ViewDump;
auto dump(const Buffer& buf) -> detail::ViewDump;
} // namespace detail
} // namespace vereign::bytes
......
......@@ -28,6 +28,9 @@ private:
std::string path_;
};
/**
* A RAII guard that deletes all files and directories recursively.
*/
class RemoveAllGuard {
public:
RemoveAllGuard(std::string path);
......@@ -39,13 +42,70 @@ private:
std::string path_;
};
auto BoostPath(std::string_view path) -> boost::filesystem::path;
/**
* Generates a file path usable as temporary file.
*
* For a temp file path under the system tmp dir use the other TempFilePath overload.
*
* @code
* auto path = fs::TempFilePath("/tmp/foo", "test_db_");
* std::cout << path << std::endl;
*
* // Output:
* // /tmp/foo/test_db_bh0vcr0jbz
* @endcode
*
* @param dir The directory of the temp file path.
* @param prefix A prefix to prepend to the temp file name.
* @returns a file path usable as temporary file.
*/
auto TempFilePath(std::string_view dir, std::string_view prefix) -> std::string;
/**
* Generates a file path usable as temporary file under the system temporary directory.
*
* It tries to detect the correct temp dir under different operation systems.
* For Linux this is `/tmp` and for Windows this is `C:\Users\<username>\AppData\Local\Temp`.
*
* @code
* auto path = fs::TempFilePath("test_db_");
* std::cout << path << std::endl;
*
* // Output:
* // /tmp/test_db_bh0vcr0jbz
* @endcode
*
* @param prefix A prefix to prepend to the temp file name.
* @returns a file path usable as temporary file.
*/
auto TempFilePath(std::string_view prefix) -> std::string;
/**
* Creates a temporary sub directory under the system temporary directory.
*
* It tries to detect the correct temp dir under different operation systems.
* For Linux this is `/tmp` and for Windows this is `C:\Users\<username>\AppData\Local\Temp`.
*
* @code
* auto path = fs::TempDir("test_db_");
* std::cout << path << std::endl;
*
* // Output:
* // /tmp/test_db_bh0vcr0jbz
* @endcode
*
* @param prefix A prefix to prepend to the temp dir name.
* @returns a the path of the created temporary directory.
*/
auto TempDir(std::string_view prefix) -> std::string;
/**
* Returns current user home directory.
*
* On Windows this is `C:\Users\<username>\AppData\Local`.
*
* @returns the user's home directory full path.
*/
auto HomePath() -> std::string;
} // namespace vereign::fs
......
......@@ -8,6 +8,13 @@ namespace vereign::grpc {
static constexpr const char* ClientErrorStatus = "Vereign Client Library Error";
/**
* Error codes returned into the gRPC API response `code` field on various failures.
*
* These are errors that happen inside the Vereign Client Library.
* The errors that happen inside the Vereign Restful API are in the standard HTTP status code range
* below 600.
*/
enum class ErrorCode : uint64_t {
ClientError = 1000,
UnexpectedError = 1001,
......@@ -16,6 +23,12 @@ enum class ErrorCode : uint64_t {
InvalidIdentity = 1004
};
/**
* Convert the error code to string.
*
* @param ec The error code.
* @returns the error code integer as string.
*/
inline auto ErrorCodeAsString(ErrorCode ec) -> std::string {
return std::to_string(uint64_t(ec));
}
......
......@@ -11,21 +11,53 @@
namespace vereign::grpc {
/**
* Implementation of the gRPC `vereign::client_library::IdentityAPI::Service` service.
*
* Inherits all the API implementations from the generated gen::IdentityAPI and adds some
* additional implementations.
*
* IdentityAPI is a thin layer on top of the service::IdentityService.
*/
template <class VereignService>
class IdentityAPI final : public gen::IdentityAPI<VereignService> {
public:
// API service name.
static constexpr const char* Name = gen::IdentityAPI<VereignService>::Name;
using VereignServiceType = VereignService;
using VereignServicePtr = std::unique_ptr<VereignService>;
/**
* Constructs IdentityAPI instance.
*
* @param service The client library Identity service.
*/
IdentityAPI(VereignServicePtr&& service)
: gen::IdentityAPI<VereignService>{std::move(service)}
{}
// disable copying
IdentityAPI(const IdentityAPI&) = delete;
auto operator=(const IdentityAPI&) -> IdentityAPI& = delete;
/**
* Registers a new device.
*
* req.pin is required only under Linux.
*
* Under windows the system cypto storage is used.
* When the device is registered a master key is created and the user will be asked for his
* consent by showing a dialog window.
*
* Unexpected error codes:
* - ErrorCode::ClientError Error that happen inside the Vereign Client Library
* - ErrorCode::UnexpectedError Should never happen.
*
* Error codes of interest:
* - ErrorCode::InvalidPinCode The pin code is invalid, currently during the registration an empty
* pin code is considered invalid.
*/
auto LoginWithNewDevice(
::grpc::ServerContext* ctx,
const client_library::LoginFormNewDevice* req,
......@@ -55,6 +87,24 @@ public:
return ::grpc::Status::OK;
}
/**
* Login with already registered device.
*
* req.pin is required only under Linux.
*
* Under windows the system cypto storage is used.
* When the device is registered a master key is created and the user will be asked for his
* consent by showing a dialog window.
*
* Unexpected error codes:
* - ErrorCode::ClientError Error that happen inside the Vereign Client Library
* - ErrorCode::UnexpectedError Should never happen.
*
* Error codes of interest:
* - ErrorCode::DeviceNotRegistered The device is not registered.
* - ErrorCode::InvalidPinCode The pin code is invalid and the crypto storage cannot be unlocked.
* - ErrorCode::InvalidIdentity Under windows if for some reason the RSA master key has been changed.
*/
auto LoginWithPreviouslyAddedDevice(
::grpc::ServerContext* ctx,
const client_library::LoginFormPreviousAddedDevice* req,
......
#include "vereign/crypto/digest.hh"
#include <vereign/identity/provider.hh>
#include <vereign/crypto/digest.hh>
#include <vereign/crypto/bio.hh>
#include <vereign/crypto/rsa.hh>
#include <vereign/encoding/base64.hh>
......
......@@ -7,20 +7,62 @@
namespace vereign::identity {
/**
* Identity provider that manages the locally stored user identity.
*
* All public methods are thread safe.
*/
class Provider {
public:
/**
* Creates Provider instance.
*
* @param storage The crypto storage used for read/write identity properties.
*/
Provider(kvstore::CryptoStorage& storage);
/**
* Default constructor.
*
* Does nothing.
*/
~Provider();
// disable copying
Provider(const kvstore::Storage&) = delete;
auto operator=(const kvstore::Storage&) -> Provider& = delete;
/**
* Replaces the current identity.
*
* @param pin Required only under Linux. The pin code used for derivation of the crypto storage
* master key.
*
* @returns The base64 encoded PEM encoded identity public key.
*/
auto ResetIdentity(const std::string& pin) -> std::string;
/**
* Loads the local identity.
*
* @param pin Required only under Linux. The pin code used for derivation of the crypto storage
* master key.
*
* @returns The base64 encoded PEM encoded identity public key.
*/
auto LoadIdentity(const std::string& pin) -> std::string;
/**
* Retrieve identity public key.
*
* @returns The base64 encoded PEM encoded identity public key.
*/
auto GetIdentityPublicKeyBase64() -> std::string;
auto GetDeviceHash() -> std::string;
~Provider();
/**
* @returns base64 encoded SHA1 hash of the identity public key.
*/
auto GetDeviceHash() -> std::string;
private:
std::mutex mu_;
......
......@@ -6,12 +6,40 @@
namespace vereign::kvstore {
/**
* Lock guard used for lock/unlock Storage within a scope.
*
* When the Lock is constructed it locks the Storage, and when it is destroyed it unlock it.
*/
class Lock {
public:
/**
* Creates a Lock and locks the Storage.
*
* @param storage The storage to lock.
* @throws LockError when the lock is held by another process.
*/
explicit Lock(Storage& storage);
/**
* Creates a Lock and locks the Storage.
*
* If the lock is not possible it retries `retry_count` and sleeps between retries `sleep_interval`.
*
* @param storage The storage to lock.
* @param retry_count How many times to retry if the lock is held by another process.
* @param sleep_interval How many time to sleep between retries.
*
* @throws LockError If the lock could not be held after `retry_count` retries.
*/
Lock(Storage& storage, int retry_count, std::chrono::milliseconds sleep_interval);
/**
* Unlocks the storage.
*/
~Lock() noexcept;
// copying is disabled.
Lock(const Lock&) = delete;
auto operator=(const Lock&) -> Lock& = delete;
......
......@@ -6,23 +6,96 @@
namespace vereign::kvstore {
/**
* Sqlite implementation of the kvstore::Storage interface.
*/
class SqliteStorage : public Storage {
public:
/**
* Creates SqliteStorage instance.
*
* @param db_path Full path to the sqlite database file.
*/
SqliteStorage(const std::string& db_path);
/**
* Closes the connection with the database.
*/
~SqliteStorage() override;
// disable copying
SqliteStorage(const SqliteStorage&) = delete;
auto operator=(const SqliteStorage&) -> SqliteStorage& = delete;
/**
* Locks the storage.
*
* The lock must be recursive, meaning that may be called multiple times.
* Storage::Unlock must be called the same number of times the Storage::Lock was called.
*
* Use kvstore::Lock for lock guard and lock with retrials.
*
* @throws LockError when the lock is held by another process.
*/
void Lock() override;
/**
* Locks the storage.
*
* The lock must be recursive, meaning that may be called multiple times.
* Storage::Unlock must be called the same number of times the Storage::Lock was called.
*
* Use kvstore::Lock for lock guard and lock with retrials.
*/
void Unlock() override;
/**
* Deletes all the values in the storage.
*
* @throws sqlite::Error on failure.
*/
void DeleteAll() override;
/**
* Store bytes value into the storage.
*
* @param key The key under which the value will be stored.
* @param value The bytes that will be stored.
*
* @throws sqlite::Error on failure.
*/
void PutBytes(const std::string& key, bytes::View value) override;
/**
* Retrieve bytes value from the storage.
*
* @param key The key of the value that will be retrieved.
* @param value Buffer where the value will be returned.
*
* @throws ValueNotFoundError when the key does not exist.
* @throws sqlite::Error on failure.
*/
void GetBytes(const std::string& key, bytes::Buffer& value) override;
/**
* Store int64_t value into the storage.
*
* @param key The key under which the value will be stored.
* @param value The value that will be stored.
*
* @throws sqlite::Error on failure.
*/
void PutInt64(const std::string& key, int64_t value) override;
/**
* Retrieve int64_t value from the storage.
*
* @param key The key of the value that will be retrieved.
* @param value Buffer where the value will be returned.
*
* @throws ValueNotFoundError when the key does not exist.
* @throws sqlite::Error on failure.
*/
auto GetInt64(const std::string& key) -> int64_t override;
private:
......
......@@ -5,21 +5,80 @@
namespace vereign::kvstore {
// The vereign RSA master key name.
constexpr const auto VereignKeyName = std::string_view{"vereign_key"};
/**
* Key/value storage interface.
*/
class Storage {
public:
/**
* Locks the storage.
*
* The lock must be recursive, meaning that may be called multiple times.
* Storage::Unlock must be called the same number of times the Storage::Lock was called.
*
* Use kvstore::Lock for lock guard and lock with retrials.
*
* @throws LockError when the lock is held by another process.
*/
virtual void Lock() = 0;
/**
* Locks the storage.
*
* The lock must be recursive, meaning that may be called multiple times.
* Storage::Unlock must be called the same number of times the Storage::Lock was called.
*
* Use kvstore::Lock for lock guard and lock with retrials.
*/
virtual void Unlock() = 0;
/**
* Deletes all the values in the storage.
*/
virtual void DeleteAll() = 0;
/**
* Store bytes value into the storage.
*
* @param key The key under which the value will be stored.
* @param value The bytes that will be stored.
*/
virtual void PutBytes(const std::string& key, bytes::View value) = 0;
/**
* Retrieve bytes value from the storage.
*
* @param key The key of the value that will be retrieved.
* @param value Buffer where the value will be returned.
*
* @throws ValueNotFoundError when the key does not exist.
*/
virtual void GetBytes(const std::string& key, bytes::Buffer& value) = 0;
/**
* Store int64_t value into the storage.
*
* @param key The key under which the value will be stored.
* @param value The value that will be stored.
*/
virtual void PutInt64(const std::string& key, int64_t value) = 0;
/**
* Retrieve int64_t value from the storage.
*
* @param key The key of the value that will be retrieved.
* @param value Buffer where the value will be returned.
*
* @throws ValueNotFoundError when the key does not exist.
*/
virtual auto GetInt64(const std::string& key) -> int64_t = 0;
/**
* Destroy and cleanup.
*/
virtual ~Storage() = default;
};
......
......@@ -23,24 +23,73 @@ using Result = restapi::PostResult<Request, Response>;
class IdentityService : public gen::IdentityService {
public:
/**
* Creates IdentityService instance.
*
* @param client_session HTTP client used for communicating with the Vereign Restful API.
* @param identity_provider Local identity provider (manager).
*/
IdentityService(
restapi::ClientSession& client_session,
identity::Provider& identity_provider
);
// disable copying
IdentityService(const IdentityService&) = delete;
auto operator=(const IdentityService&) -> IdentityService& = delete;
/**
* Login with existing identity public key.
*
* This API is for test purposes only. It is not exposed under the gRPC API, and thus is not
* accessible by the integrators.
*
* **WARN: do not use this in production code**
*/
void LoginWithExistingPubKey(
const client_library::LoginWithExistingPubKeyForm* req,
client_library::EmptyResponse* resp
);
/**
* Registers a new device.
*
* req.pin is required only under Linux.
*
* Under windows the system cypto storage is used.
* When the device is registered a master key is created and the user will be asked for his
* consent by showing a dialog window.
*
* @param req Login request.
* @param resp Operation response.
*
* @throws kvstore::InvalidPinCodeError Only under Linux. Thrown when the provided pin is invalid,
* currently that is when the pin is empty.
*/
void LoginWithNewDevice(
const client_library::LoginFormNewDevice* req,
client_library::LoginFormNewDeviceResponse* resp
);
/**
* Login with already registered device.
*
* req.pin is required only under Linux.
*
* Under windows the system cypto storage is used.
* When the device is registered a master key is created and the user will be asked for his
* consent by showing a dialog window.
*
* @param req Login request.
* @param resp Operation response.
*
* @throws kvstore::StorageNotInitializedError when the crypto storage is empty, meaning that
* the device is not registered.
* @throws kvstore::InvalidPinCodeError under Linux, when the provided pin is invalid, meaning
* that the pin does not match the pin used during the registration.
* @throws kvstore::InvalidIdentityError under windows, when for some reason the RSA master key
* has been changed.
*/
void LoginWithPreviouslyAddedDevice(
const client_library::LoginFormPreviousAddedDevice* req,
client_library::EmptyResponse* resp
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment