-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Type of change <!-- (mark with an `X`) --> ``` - [ ] Bug fix - [x ] New feature development - [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc) - [ ] Build/deploy pipeline (DevOps) - [ ] Other ``` ## Objective Implemented C++ library that wraps native C library and exposed its commands through BitwardenClient class. ## Code changes - Implemented BitwardenLibrary for connection with `bitwarden_c` library and its three functions: `init`, `run_command`, and `free_mem` - Implemented CRUD operations for the Projects and Secrets for Bitwarden Secrets Manager using the API - Developed building mechanism that is building C++ dynamic library using `Cmake` - Added example in the `examples` directory - Added documentation in .md files for CRUD operations use, building the dynamic library, and for the client use --------- Co-authored-by: Todosijevic-Slobodan <[email protected]> Co-authored-by: Daniel García <[email protected]>
- Loading branch information
1 parent
9f77596
commit 0f5f11b
Showing
18 changed files
with
1,075 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# CMAKE build | ||
|
||
## INTRODUCTION | ||
|
||
Cmake is used to build the c++ Bitwarden client library. Output should be placed in the build directory. The output contains two dynamic libraries: one that we are building `BitwardenClient` and another that the building library uses `bitwarden_c`. | ||
|
||
## PREREQUISITES | ||
|
||
- Cmake installed, minimum version 3.15 | ||
- `schemas.hpp` generated into `include` directory | ||
- installed `nlohmann-json` library | ||
- installed `boost` library | ||
|
||
## BUILD commands | ||
|
||
One should be in the root directory of the c++ wrapper (the same level where is CMakeLists.txt placed). Paths of the three libraries should be placed inside the cmake build command: | ||
|
||
$ mkdir build | ||
$ cd build | ||
$ cmake .. -DNLOHMANN=/path/to/include/nlohmann -DBOOST=/path/to/include/boost -DTARGET=relative/path/to/libbitwarden_c | ||
$ cmake --build . | ||
|
||
|
||
|
||
## Example | ||
|
||
macOS: | ||
|
||
$ mkdir build | ||
$ cd build | ||
$ cmake .. -DNLOHMANN=/opt/hombrew/include -DBOOST=/opt/homebrew/include -DTARGET=../../target/release/libbitwarden_c.dylib | ||
$ cmake --build . | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
cmake_minimum_required(VERSION 3.15) | ||
project(BitwardenClient) | ||
|
||
set(CMAKE_CXX_STANDARD 20) | ||
|
||
# Set placeholders to be passed from command line | ||
set(NLOHMANN_JSON_INCLUDE_DIR_PLACEHOLDER ${NLOHMANN}) | ||
set(BOOST_INCLUDE_DIR_PLACEHOLDER ${BOOST}) | ||
set(TARGET_INCLUDE_DIR_PLACEHOLDER ${TARGET}) | ||
|
||
# Specify the locations of nlohmann.json and Boost libraries | ||
find_path(NLOHMANN_JSON_INCLUDE_DIR nlohmann/json.hpp HINTS ${NLOHMANN_JSON_INCLUDE_DIR_PLACEHOLDER}) | ||
find_path(BOOST_INCLUDE_DIR boost/optional.hpp HINTS ${BOOST_INCLUDE_DIR_PLACEHOLDER}) | ||
|
||
# Include directories for library | ||
include_directories(include ${NLOHMANN_JSON_INCLUDE_DIR} ${BOOST_INCLUDE_DIR}) | ||
|
||
# Add library source files | ||
file(GLOB SOURCES "src/*.cpp") | ||
|
||
# Add library source files along with the schemas.cpp file | ||
add_library(BitwardenClient SHARED ${SOURCES} ${SCHEMAS_SOURCE}) | ||
|
||
# Set path for native library loading | ||
set(LIB_BITWARDEN_C "${CMAKE_SOURCE_DIR}/${TARGET}") | ||
|
||
# Copy the library to the build directory before building | ||
add_custom_command( | ||
TARGET BitwardenClient PRE_BUILD | ||
COMMAND ${CMAKE_COMMAND} -E copy | ||
${LIB_BITWARDEN_C} | ||
$<TARGET_FILE_DIR:BitwardenClient> | ||
) | ||
|
||
# Link libraries | ||
target_link_libraries(BitwardenClient PRIVATE ${LIB_BITWARDEN_C}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# EXAMPLES | ||
|
||
|
||
## PREREQUISITES | ||
|
||
### BITWARDEN Libraries | ||
One should have two libraries at the same path: | ||
- `BitwardeClient` | ||
- `bitwarden_c` | ||
|
||
It should look like `libBitwardeClient.dylib` and `libbitwarden_c.dylib` for the macOS. | ||
|
||
For Linux: `libBitwardeClient.so` and `libbitwarden_c.so` | ||
For Windows: `BitwardeClient.dll` and `bitwarden_c.dll` | ||
|
||
### INCLUDE directory | ||
|
||
`include` directory contains: | ||
- `BitwardenLibrary.h` | ||
- `BitwardenClient.h` | ||
- `BitwardenSettings.h` | ||
- `CommandRunner.h` | ||
- `Projects.h` | ||
- `Secrets.h` | ||
- `schemas.hpp` | ||
|
||
### Other libraries | ||
- `nlohmann-json` (https://github.com/nlohmann/json) | ||
- `boost` (https://www.boost.org/) | ||
|
||
|
||
### COMPILING | ||
|
||
One could use g++/clang++ for compiling. | ||
Example of the folder structure (macOS): | ||
|
||
--root | ||
--build | ||
`libBitwardenClient.dylib` | ||
`libbitwarden_c.dylib` | ||
--include | ||
--`BitwardenLibrary.h` | ||
--`BitwardenClient.h` | ||
--`BitwardenSettings.h` | ||
--`CommandRunner.h` | ||
--`Projects.h` | ||
--`Secrets.h` | ||
--`schemas.hpp` | ||
--examples | ||
--`Wrapper.cpp` | ||
|
||
|
||
1. $ export ACCESS_TOKEN=<"access-token"> | ||
2. $ export ORGANIZATION_ID=<"organization-id"> | ||
3. $ export DYLD_LIBRARY_PATH=/path/to/your/library:$DYLD_LIBRARY_PATH | ||
|
||
The last step is neccessary to add the path for the dynamic library (macOS). | ||
For the Linux one should use: | ||
$ export LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH | ||
For the Windows: | ||
$ set PATH=%PATH%;C:\path\to\your\library | ||
|
||
4. $ cd examples | ||
5. $ clang++ -std=c++20 -I../include -I/path/to/include/nlohmann -I/path/to/include/boost -L../build/ -o MyBitwardenApp Wrapper.cpp -lBitwardenClient -ldl | ||
|
||
for Windows `-ldl` should be excluded, | ||
|
||
The result is `MyBitwardenApp` in the `examples` directory, and one can run it from the `examples` directory: | ||
|
||
6. $ ./MyBitwardenApp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Bitwarden Secrets Manager SDK | ||
|
||
C++ bindings for interacting with the [Bitwarden Secrets Manager]. This is a beta release and might be missing some functionality. | ||
|
||
## Create access token | ||
|
||
Review the help documentation on [Access Tokens] | ||
|
||
## Usage code snippets | ||
|
||
### Client settings | ||
|
||
```c++ | ||
// Optional - if not stressed, then default values are used | ||
BitwardenSettings bitwardenSettings; | ||
bitwardenSettings.set_api_url("<bitwarden-url>"); | ||
bitwardenSettings.set_identity_url("<bitwarden-identity>"); | ||
``` | ||
|
||
|
||
### Create new Bitwarden client | ||
|
||
```c++ | ||
std::string accessToken = "<access-token>"; | ||
// Optional - argument in BitwardenClient | ||
BitwardenClient bitwardenClient = BitwardenClient(bitwardenSettings); | ||
bitwardenClient.accessTokenLogin(accessToken); | ||
``` | ||
|
||
### Create new project | ||
|
||
```c++ | ||
boost::uuids::uuid organizationUuid = boost::uuids::string_generator()("<organization-id>"); | ||
ProjectResponse projectResponseCreate = bitwardenClient.createProject(organizationUuid, "TestProject"); | ||
``` | ||
|
||
### List all projects | ||
|
||
```c++ | ||
ProjectsResponse projectResponseList = bitwardenClient.listProjects(organizationUuid); | ||
``` | ||
|
||
### Get project details | ||
|
||
```c++ | ||
boost::uuids::uuid projectId = boost::uuids::string_generator()(projectResponseCreate.get_id()); | ||
ProjectResponse projectResponseGet = bitwardenClient.getProject(projectId); | ||
``` | ||
|
||
### Update project | ||
|
||
```c++ | ||
boost::uuids::uuid projectId = boost::uuids::string_generator()(projectResponseCreate.get_id()); | ||
ProjectResponse projectResponseUpdate = bitwardenClient.updateProject(projectId, organizationUuid, "TestProjectUpdated"); | ||
``` | ||
|
||
### Delete projects | ||
|
||
```c++ | ||
SecretsDeleteResponse secretsDeleteResponse = bitwardenClient.deleteSecrets({secretId}); | ||
``` | ||
### Add new secret | ||
```c++ | ||
std::string key = "key"; | ||
std::string value = "value"; | ||
std::string note = "note"; | ||
SecretResponse secretResponseCreate = bitwardenClient.createSecret(key, value, note, organizationUuid, {projectId}); | ||
``` | ||
|
||
### List secrets | ||
|
||
```c++ | ||
SecretIdentifiersResponse secretIdentifiersResponse = bitwardenClient.listSecrets(organizationUuid); | ||
``` | ||
|
||
### Get secret details | ||
|
||
``` | ||
boost::uuids::uuid secretId = boost::uuids::string_generator()(secretResponseCreate.get_id()); | ||
SecretResponse secretResponseGet = bitwardenClient.getSecret(secretId); | ||
``` | ||
|
||
### Update secret | ||
```c++ | ||
SecretResponse secretResponseUpdate = bitwardenClient.updateSecret(secretId, "key2", "value2", "note2", organizationUuid, {projectId}); | ||
``` | ||
# Delete secrets | ||
```c++ | ||
SecretsDeleteResponse secretsDeleteResponse = bitwardenClient.deleteSecrets({secretId}); | ||
``` | ||
|
||
[Access Tokens]: https://bitwarden.com/help/access-tokens/ | ||
[Bitwarden Secrets Manager]: https://bitwarden.com/products/secrets-manager/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "BitwardenClient.h" | ||
#include <boost/uuid/string_generator.hpp> | ||
#include <cstdlib> | ||
|
||
int main() { | ||
// Retrieve access token and organization ID from environment variables | ||
const char* accessTokenEnv = std::getenv("ACCESS_TOKEN"); | ||
const char* organizationIdEnv = std::getenv("ORGANIZATION_ID"); | ||
|
||
if (!accessTokenEnv || !organizationIdEnv) { | ||
std::cerr << "Error: Environment variables ACCESS_TOKEN or ORGANIZATION_ID not set." << std::endl; | ||
return 1; | ||
} | ||
|
||
std::string accessToken = accessTokenEnv; | ||
std::string organizationId = organizationIdEnv; | ||
|
||
|
||
|
||
// Optional - commented to use default values | ||
// BitwardenSettings bitwardenSettings; | ||
// bitwardenSettings.set_api_url("<bitwarden-url>"); | ||
// bitwardenSettings.set_identity_url("<bitwarden-identity>"); | ||
|
||
// Create a Bitwarden client instance | ||
BitwardenClient bitwardenClient = BitwardenClient(); | ||
// // Access token login | ||
bitwardenClient.accessTokenLogin(accessToken); | ||
// Organization ID | ||
boost::uuids::uuid organizationUuid = boost::uuids::string_generator()(organizationId); | ||
|
||
// // Create a new project | ||
ProjectResponse projectResponseCreate = bitwardenClient.createProject(organizationUuid, "NewTestProject"); | ||
boost::uuids::uuid projectId = boost::uuids::string_generator()(projectResponseCreate.get_id()); | ||
|
||
// List projects | ||
ProjectsResponse projectResponseList = bitwardenClient.listProjects(organizationUuid); | ||
|
||
// Get project details | ||
ProjectResponse projectResponseGet = bitwardenClient.getProject(projectId); | ||
|
||
// Update project | ||
ProjectResponse ProjectResponseUpdate = bitwardenClient.updateProject(projectId, organizationUuid, "NewTestProject2"); | ||
|
||
// Secrets | ||
std::string key = "key"; | ||
std::string value = "value"; | ||
std::string note = "note"; | ||
|
||
// Create a new secret | ||
SecretResponse secretResponseCreate = bitwardenClient.createSecret(key, value, note, organizationUuid, {projectId}); | ||
boost::uuids::uuid secretId = boost::uuids::string_generator()(secretResponseCreate.get_id()); | ||
|
||
// List secrets | ||
SecretIdentifiersResponse secretIdentifiersResponse = bitwardenClient.listSecrets(organizationUuid); | ||
|
||
// Get secret details | ||
SecretResponse secretResponseGet = bitwardenClient.getSecret(secretId); | ||
|
||
// Update secret | ||
key = "key2"; | ||
value = "value2"; | ||
note = "note2"; | ||
SecretResponse responseForSecretResponseUpdate = bitwardenClient.updateSecret(secretId, key, value, note, organizationUuid, {projectId}); | ||
|
||
// Delete secrets | ||
SecretsDeleteResponse secretsDeleteResponse = bitwardenClient.deleteSecrets({secretId}); | ||
|
||
// Delete projects | ||
ProjectsDeleteResponse projectsDeleteResponse = bitwardenClient.deleteProjects({projectId}); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#pragma once | ||
|
||
#include "CommandRunner.h" | ||
#include "BitwardenSettings.h" | ||
#include "Projects.h" | ||
#include "Secrets.h" | ||
#include <functional> | ||
#include <string> | ||
|
||
class BitwardenClient { | ||
public: | ||
BitwardenClient(const BitwardenSettings& bitwardenSettings = BitwardenSettings()); | ||
~BitwardenClient(); | ||
|
||
void accessTokenLogin(const std::string& accessToken); | ||
ProjectResponse getProject(const boost::uuids::uuid& id); | ||
ProjectResponse createProject(const boost::uuids::uuid& organizationId, const std::string& name); | ||
ProjectResponse updateProject(const boost::uuids::uuid& id, const boost::uuids::uuid& organizationId, const std::string& name); | ||
ProjectsDeleteResponse deleteProjects(const std::vector<boost::uuids::uuid>& ids); | ||
ProjectsResponse listProjects(const boost::uuids::uuid &organizationId); | ||
SecretResponse getSecret(const boost::uuids::uuid& id); | ||
SecretResponse createSecret(const std::string& key, const std::string& value, const std::string& note, const boost::uuids::uuid& organizationId, const std::vector<boost::uuids::uuid>& projectIds); | ||
SecretResponse updateSecret(const boost::uuids::uuid& id, const std::string& key, const std::string& value, const std::string& note, const boost::uuids::uuid& organizationId, const std::vector<boost::uuids::uuid>& projectIds); | ||
SecretsDeleteResponse deleteSecrets(const std::vector<boost::uuids::uuid>& ids); | ||
SecretIdentifiersResponse listSecrets(const boost::uuids::uuid& organizationId); | ||
|
||
private: | ||
BitwardenLibrary* library; | ||
void* client; | ||
CommandRunner* commandRunner; | ||
Projects projects; | ||
Secrets secrets; | ||
bool isClientOpen; | ||
ClientSettings clientSettings; | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
|
||
#ifdef _WIN32 | ||
#include <windows.h> | ||
#else | ||
#include <dlfcn.h> | ||
#endif | ||
|
||
class BitwardenLibrary { | ||
public: | ||
BitwardenLibrary(const std::string& providedLibraryPath); | ||
~BitwardenLibrary(); | ||
|
||
void* init(const char* clientSettingsJson); | ||
void free_mem(void* client); | ||
const char* run_command(const char* commandJson, void* client); | ||
|
||
private: | ||
#ifdef _WIN32 | ||
HMODULE libraryHandle; | ||
#else | ||
void* libraryHandle; | ||
#endif | ||
}; | ||
|
Oops, something went wrong.