summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2021-08-23 19:05:09 -0400
committerGlenn Smith <glenn@vector35.com>2021-11-18 21:37:52 -0500
commit994a42659dc500f602e83f91501ec4a959481fa5 (patch)
treeca783900c9a6d41dbdd98a1cd66a083d3e886578
parent60f2ecd9d1961f7cd700e01f802bcf640c9d50e0 (diff)
Enterprise apis and support
Also secrets provider + openUrl
-rw-r--r--binaryninjaapi.h77
-rw-r--r--binaryninjacore.h42
-rw-r--r--downloadprovider.cpp20
-rw-r--r--http.cpp59
-rw-r--r--http.h125
-rw-r--r--interaction.cpp14
-rw-r--r--python/CMakeLists.txt19
-rw-r--r--python/__init__.py11
-rw-r--r--python/enterprise.py189
-rw-r--r--python/generator.cpp5
-rw-r--r--python/interaction.py24
-rw-r--r--secretsprovider.cpp141
-rw-r--r--ui/uitypes.h1
13 files changed, 637 insertions, 90 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index dd443c80..629b8b31 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -37,6 +37,7 @@
#include <cstdint>
#include <type_traits>
#include <variant>
+#include <optional>
#include "binaryninjacore.h"
#include "json/json.h"
@@ -730,6 +731,8 @@ __attribute__ ((format (printf, 1, 2)))
BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text,
BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon);
+ bool OpenUrl(const std::string& url);
+
/*!
Split a single progress function into equally sized subparts.
This function takes the original progress function and returns a new function whose signature
@@ -5722,6 +5725,7 @@ __attribute__ ((format (printf, 1, 2)))
virtual BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text,
BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon) = 0;
+ virtual bool OpenUrl(const std::string& url) = 0;
};
typedef BNPluginOrigin PluginOrigin;
@@ -6218,5 +6222,78 @@ __attribute__ ((format (printf, 1, 2)))
virtual bool IsValid(Ref<BinaryView>) = 0;
virtual void ParseInfo(Ref<DebugInfo>, Ref<BinaryView>) = 0;
};
+
+ /*!
+ Class for storing secrets (e.g. tokens) in a system-specific manner
+ */
+ class SecretsProvider: public StaticCoreRefCountObject<BNSecretsProvider>
+ {
+ std::string m_nameForRegister;
+
+ protected:
+ SecretsProvider(const std::string& name);
+ SecretsProvider(BNSecretsProvider* provider);
+
+ static bool HasDataCallback(void* ctxt, const char* key);
+ static char* GetDataCallback(void* ctxt, const char* key);
+ static bool StoreDataCallback(void* ctxt, const char* key, const char* data);
+ static bool DeleteDataCallback(void* ctxt, const char* key);
+
+ public:
+ /*!
+ Check if data for a specific key exists, but do not retrieve it
+ \param key Key for data
+ \return True if data exists
+ */
+ virtual bool HasData(const std::string& key) = 0;
+ /*!
+ Retrieve data for the given key, if it exists
+ \param key Key for data
+ \return Optional with data, if it exists, or empty optional if it does not exist
+ or otherwise could not be retrieved.
+ */
+ virtual std::optional<std::string> GetData(const std::string& key) = 0;
+ /*!
+ Store data with the given key
+ \param key Key for data
+ \param data Data to store
+ \return True if the data was stored
+ */
+ virtual bool StoreData(const std::string& key, const std::string& data) = 0;
+ /*!
+ Delete stored data with the given key
+ \param key Key for data
+ \return True if it was deleted
+ */
+ virtual bool DeleteData(const std::string& key) = 0;
+
+ /*!
+ Retrieve the list of providers
+ \return A list of registered providers
+ */
+ static std::vector<Ref<SecretsProvider>> GetList();
+ /*!
+ Retrieve a provider by name
+ \param name Name of provider
+ \return Provider object, if one with the given name is regestered, or nullptr if not
+ */
+ static Ref<SecretsProvider> GetByName(const std::string& name);
+ /*!
+ Register a new provider
+ \param provider New provider to register
+ */
+ static void Register(SecretsProvider* provider);
+ };
+
+ class CoreSecretsProvider: public SecretsProvider
+ {
+ public:
+ CoreSecretsProvider(BNSecretsProvider* provider);
+
+ virtual bool HasData(const std::string& key) override;
+ virtual std::optional<std::string> GetData(const std::string& key) override;
+ virtual bool StoreData(const std::string& key, const std::string& data) override;
+ virtual bool DeleteData(const std::string& key) override;
+ };
}
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 6b95c459..1e424ccb 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -222,6 +222,7 @@ extern "C"
struct BNLinearViewCursor;
struct BNDebugInfo;
struct BNDebugInfoParser;
+ struct BNSecretsProvider;
//! Console log levels
@@ -2439,6 +2440,7 @@ extern "C"
bool (*getFormInput)(void* ctxt, BNFormInputField* fields, size_t count, const char* title);
BNMessageBoxButtonResult (*showMessageBox)(void* ctxt, const char* title, const char* text,
BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon);
+ bool (*openUrl)(void* ctxt, const char* url);
};
struct BNObjectDestructionCallbacks
@@ -2651,6 +2653,15 @@ extern "C"
BNPlatform* platform;
};
+ struct BNSecretsProviderCallbacks
+ {
+ void* context;
+ bool (*hasData)(void* ctxt, const char* key);
+ char* (*getData)(void* ctxt, const char* key);
+ bool (*storeData)(void* ctxt, const char* key, const char* data);
+ bool (*deleteData)(void* ctxt, const char* key);
+ };
+
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI void BNFreeString(char* str);
BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size);
@@ -2674,6 +2685,23 @@ extern "C"
BINARYNINJACOREAPI bool BNIsUIEnabled(void);
BINARYNINJACOREAPI void BNSetLicense(const char* licenseData);
+ BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithCredentials(const char* username, const char* password);
+ BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithMethod(const char* method);
+ BINARYNINJACOREAPI size_t BNGetEnterpriseServerAuthenticationMethods(char*** methods, char*** names);
+ BINARYNINJACOREAPI bool BNDeauthenticateEnterpriseServer(void);
+ BINARYNINJACOREAPI void BNCancelEnterpriseServerAuthentication(void);
+ BINARYNINJACOREAPI bool BNConnectEnterpriseServer(void);
+ BINARYNINJACOREAPI bool BNAcquireEnterpriseServerLicense(uint64_t timeout, bool cached);
+ BINARYNINJACOREAPI bool BNReleaseEnterpriseServerLicense(void);
+ BINARYNINJACOREAPI bool BNIsEnterpriseServerConnected(void);
+ BINARYNINJACOREAPI bool BNIsEnterpriseServerAuthenticated(void);
+ BINARYNINJACOREAPI char* BNGetEnterpriseServerUsername(void);
+ BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerLicenseExpirationTime(void);
+ BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerLicenseDuration(void);
+ BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerReservationTimeLimit(void);
+ BINARYNINJACOREAPI bool BNIsEnterpriseServerLicenseStillActivated(void);
+ BINARYNINJACOREAPI char* BNGetEnterpriseServerLastError(void);
+
BINARYNINJACOREAPI void BNRegisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks);
BINARYNINJACOREAPI void BNUnregisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks);
@@ -5245,6 +5273,7 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI void BNFreeFormInputResults(BNFormInputField* fields, size_t count);
BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text,
BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon);
+ BINARYNINJACOREAPI bool BNOpenUrl(const char* url);
BINARYNINJACOREAPI BNReportCollection* BNCreateReportCollection(void);
BINARYNINJACOREAPI BNReportCollection* BNNewReportCollectionReference(BNReportCollection* reports);
@@ -5573,6 +5602,19 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI bool BNAddDebugDataVariable(BNDebugInfo* const debugInfo, uint64_t address, const BNType* const type, const char* name);
BINARYNINJACOREAPI BNDataVariableAndName* BNGetDebugDataVariables(BNDebugInfo* const debugInfo, const char* const name, size_t* count);
+ // Secrets providers
+ BINARYNINJACOREAPI BNSecretsProvider* BNRegisterSecretsProvider(const char* name, BNSecretsProviderCallbacks* callbacks);
+ BINARYNINJACOREAPI BNSecretsProvider** BNGetSecretsProviderList(size_t* count);
+ BINARYNINJACOREAPI void BNFreeSecretsProviderList(BNSecretsProvider** providers);
+ BINARYNINJACOREAPI BNSecretsProvider* BNGetSecretsProviderByName(const char* name);
+
+ BINARYNINJACOREAPI char* BNGetSecretsProviderName(BNSecretsProvider* provider);
+
+ BINARYNINJACOREAPI bool BNSecretsProviderHasData(BNSecretsProvider* provider, const char* key);
+ BINARYNINJACOREAPI char* BNGetSecretsProviderData(BNSecretsProvider* provider, const char* key);
+ BINARYNINJACOREAPI bool BNStoreSecretsProviderData(BNSecretsProvider* provider, const char* key, const char* data);
+ BINARYNINJACOREAPI bool BNDeleteSecretsProviderData(BNSecretsProvider* provider, const char* key);
+
#ifdef __cplusplus
}
#endif
diff --git a/downloadprovider.cpp b/downloadprovider.cpp
index d54a85e3..99c6c7c2 100644
--- a/downloadprovider.cpp
+++ b/downloadprovider.cpp
@@ -1,3 +1,23 @@
+// Copyright (c) 2015-2021 Vector 35 Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
#include "binaryninjaapi.h"
using namespace BinaryNinja;
diff --git a/http.cpp b/http.cpp
index a7753f0f..669d742a 100644
--- a/http.cpp
+++ b/http.cpp
@@ -24,10 +24,22 @@
#include <math.h>
#include "http.h"
+#ifdef BINARYNINJACORE_LIBRARY
+#include "log.h"
+#endif
+
+#ifdef BINARYNINJACORE_LIBRARY
+using namespace BinaryNinjaCore;
+#else
using namespace BinaryNinja;
using namespace std;
+#endif
+#ifdef BINARYNINJACORE_LIBRARY
+namespace BinaryNinjaCore::Http
+#else
namespace BinaryNinja::Http
+#endif
{
#define HTTP_MAX_RETRIES 3
#define HTTP_BACKOFF_FACTOR 1
@@ -167,7 +179,7 @@ namespace BinaryNinja::Http
vector<uint8_t> MultipartEncode(const vector<MultipartField>& fields, string& boundary)
{
- boundary = string(4, '-') + "MultipartFormBoundary" + GetUniqueIdentifierString();
+ boundary = string(4, '-') + "MultipartFormBoundary" + (string)BNGetUniqueIdentifierString();
vector<uint8_t> boundaryVec;
boundaryVec.reserve(boundary.size());
@@ -223,8 +235,8 @@ namespace BinaryNinja::Http
Request::Request(string method, string url,
unordered_map<string, string> headers,
vector<pair<string, string>> params,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress):
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress):
m_method(method), m_url(url), m_headers(headers),
m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress)
{
@@ -249,8 +261,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<uint8_t> body,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress):
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress):
m_method(method), m_url(url), m_headers(headers), m_body(body),
m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress)
{
@@ -275,8 +287,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<pair<string, string>> formFields,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress):
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress):
m_method(method), m_url(url), m_headers(headers),
m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress)
{
@@ -305,8 +317,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<MultipartField> formFields,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress):
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress):
m_method(method), m_url(url), m_headers(headers),
m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress)
{
@@ -335,8 +347,8 @@ namespace BinaryNinja::Http
Request Request::Get(string url,
unordered_map<string, string> headers,
vector<pair<string, string>> params,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress)
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress)
{
return Request("GET", url, headers, params, downloadProgress, uploadProgress);
}
@@ -346,8 +358,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<uint8_t> body,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress)
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress)
{
return Request("POST", url, headers, params, body, downloadProgress, uploadProgress);
}
@@ -357,8 +369,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<pair<string, string>> formFields,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress)
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress)
{
return Request("POST", url, headers, params, formFields, downloadProgress, uploadProgress);
}
@@ -368,8 +380,8 @@ namespace BinaryNinja::Http
unordered_map<string, string> headers,
vector<pair<string, string>> params,
vector<MultipartField> formFields,
- function<bool(size_t, size_t)> downloadProgress,
- function<bool(size_t, size_t)> uploadProgress)
+ std::function<bool(size_t, size_t)> downloadProgress,
+ std::function<bool(size_t, size_t)> uploadProgress)
{
return Request("POST", url, headers, params, formFields, downloadProgress, uploadProgress);
}
@@ -381,6 +393,11 @@ namespace BinaryNinja::Http
int retry = 0;
while (true)
{
+ response.response.statusCode = 0;
+ response.response.headers.clear();
+ response.body.clear();
+ response.error.clear();
+
RequestContext context{request, response};
BNDownloadInstanceInputOutputCallbacks callbacks{};
memset(&callbacks, 0, sizeof(BNDownloadInstanceInputOutputCallbacks));
@@ -399,7 +416,7 @@ namespace BinaryNinja::Http
size_t backoff = 1000 * HTTP_BACKOFF_FACTOR * (2 * pow(2, retry - 1));
retry += 1;
LogWarn("Attempt %d to %s %s failed, trying again in %zums\n", retry, request.m_method.data(), request.m_url.data(), backoff);
- this_thread::sleep_for(chrono::milliseconds(backoff));
+ std::this_thread::sleep_for(std::chrono::milliseconds(backoff));
}
return result;
}
@@ -422,12 +439,12 @@ namespace BinaryNinja::Http
{
string str = GetString();
- unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
+ std::unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
string errors;
Json::Value value;
if (!reader->parse(str.data(), str.data() + str.size(), &value, &errors))
{
- throw runtime_error(std::string("Could not parse JSON: ") + errors);
+ throw std::runtime_error(std::string("Could not parse JSON: ") + errors.c_str());
}
return value;
}
@@ -437,7 +454,7 @@ namespace BinaryNinja::Http
{
string str = GetString();
- unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
+ std::unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
string errors;
return reader->parse(str.data(), str.data() + str.size(), &value, &errors);
}
diff --git a/http.h b/http.h
index c3f0b5a9..37d6a836 100644
--- a/http.h
+++ b/http.h
@@ -27,12 +27,32 @@
#include <functional>
#include <utility>
#include <stdint.h>
+
+#ifdef BINARYNINJACORE_LIBRARY
+#include "downloadprovider.h"
+#include "json/json.h"
+#else
#include "binaryninjaapi.h"
+#endif
+#ifdef BINARYNINJACORE_LIBRARY
+namespace BinaryNinjaCore::Http
+#else
namespace BinaryNinja::Http
+#endif
{
+#ifdef BINARYNINJACORE_LIBRARY
+#define _STD_STRING string
+#define _STD_VECTOR vector
+#define _STD_UNORDERED_MAP unordered_map
+#else
+#define _STD_STRING std::string
+#define _STD_VECTOR std::vector
+#define _STD_UNORDERED_MAP std::unordered_map
+#endif
+
enum ResponseCode
{
Continue = 100,
@@ -84,20 +104,20 @@ namespace BinaryNinja::Http
*/
struct Response
{
- BinaryNinja::DownloadInstance::Response response;
- std::vector<uint8_t> body;
- std::string error;
+ DownloadInstance::Response response;
+ _STD_VECTOR<uint8_t> body;
+ _STD_STRING error;
/*!
Get response body as uint8_t vector
\return Response body bytes
*/
- std::vector<uint8_t> GetRaw() const noexcept;
+ _STD_VECTOR<uint8_t> GetRaw() const noexcept;
/*!
Get response body as text string
\return Response body string
*/
- std::string GetString() const noexcept;
+ _STD_STRING GetString() const noexcept;
/*!
Get response body as a json value
\return Response body json
@@ -118,16 +138,16 @@ namespace BinaryNinja::Http
*/
struct MultipartField
{
- std::string name;
- std::vector<uint8_t> content;
- std::optional<std::string> filename;
+ _STD_STRING name;
+ _STD_VECTOR<uint8_t> content;
+ std::optional<_STD_STRING> filename;
/*!
Construct a Multipart Field structure with a UTF-8 string encoded body
\param name Name of the field to be sent in a POST request
\param content Contents of the field
*/
- MultipartField(std::string name, const std::string& content):
+ MultipartField(_STD_STRING name, const _STD_STRING& content):
name(std::move(name)), content({}), filename({})
{
std::copy(content.begin(), content.end(), std::back_inserter(this->content));
@@ -139,7 +159,7 @@ namespace BinaryNinja::Http
\param content Contents of the field
\param filename Filename associated with the contents
*/
- MultipartField(std::string name, const std::string& content, std::string filename):
+ MultipartField(_STD_STRING name, const _STD_STRING& content, _STD_STRING filename):
name(std::move(name)), content({}), filename(std::move(filename))
{
std::copy(content.begin(), content.end(), std::back_inserter(this->content));
@@ -150,7 +170,7 @@ namespace BinaryNinja::Http
\param name Name of the field to be sent in a POST request
\param content Contents of the field
*/
- MultipartField(std::string name, std::vector<uint8_t> content):
+ MultipartField(_STD_STRING name, _STD_VECTOR<uint8_t> content):
name(std::move(name)), content(std::move(content)), filename({})
{
@@ -162,7 +182,7 @@ namespace BinaryNinja::Http
\param content Contents of the field
\param filename Filename associated with the contents
*/
- MultipartField(std::string name, std::vector<uint8_t> content, std::string filename):
+ MultipartField(_STD_STRING name, _STD_VECTOR<uint8_t> content, _STD_STRING filename):
name(std::move(name)), content(std::move(content)), filename(std::move(filename))
{
@@ -175,10 +195,10 @@ namespace BinaryNinja::Http
*/
struct Request
{
- std::string m_method;
- std::string m_url;
- std::unordered_map<std::string, std::string> m_headers;
- std::vector<uint8_t> m_body;
+ _STD_STRING m_method;
+ _STD_STRING m_url;
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> m_headers;
+ _STD_VECTOR<uint8_t> m_body;
std::function<bool(size_t, size_t)> m_downloadProgress;
std::function<bool(size_t, size_t)> m_uploadProgress;
@@ -192,9 +212,9 @@ namespace BinaryNinja::Http
\param downloadProgress Function to call for download progress updates
\param uploadProgress Function to call for upload progress updates
*/
- Request(std::string method, std::string url,
- std::unordered_map<std::string, std::string> headers = {},
- std::vector<std::pair<std::string, std::string>> params = {},
+ Request(_STD_STRING method, _STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {},
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {},
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -209,10 +229,10 @@ namespace BinaryNinja::Http
\param downloadProgress Function to call for download progress updates
\param uploadProgress Function to call for upload progress updates
*/
- Request(std::string method, std::string url,
- std::unordered_map<std::string, std::string> headers,
- std::vector<std::pair<std::string, std::string>> params,
- std::vector<uint8_t> body,
+ Request(_STD_STRING method, _STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params,
+ _STD_VECTOR<uint8_t> body,
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -227,10 +247,10 @@ namespace BinaryNinja::Http
\param downloadProgress Function to call for download progress updates
\param uploadProgress Function to call for upload progress updates
*/
- Request(std::string method, std::string url,
- std::unordered_map<std::string, std::string> headers,
- std::vector<std::pair<std::string, std::string>> params,
- std::vector<std::pair<std::string, std::string>> formFields,
+ Request(_STD_STRING method, _STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> formFields,
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -245,10 +265,10 @@ namespace BinaryNinja::Http
\param downloadProgress Function to call for download progress updates
\param uploadProgress Function to call for upload progress updates
*/
- Request(std::string method, std::string url,
- std::unordered_map<std::string, std::string> headers,
- std::vector<std::pair<std::string, std::string>> params,
- std::vector<MultipartField> formFields,
+ Request(_STD_STRING method, _STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params,
+ _STD_VECTOR<MultipartField> formFields,
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -262,9 +282,9 @@ namespace BinaryNinja::Http
\param uploadProgress Function to call for upload progress updates
\return Request structure with specified fields
*/
- static Request Get(std::string url,
- std::unordered_map<std::string, std::string> headers = {},
- std::vector<std::pair<std::string, std::string>> params = {},
+ static Request Get(_STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {},
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {},
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -279,10 +299,10 @@ namespace BinaryNinja::Http
\param uploadProgress Function to call for upload progress updates
\return Request structure with specified fields
*/
- static Request Post(std::string url,
- std::unordered_map<std::string, std::string> headers = {},
- std::vector<std::pair<std::string, std::string>> params = {},
- std::vector<uint8_t> body = {},
+ static Request Post(_STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {},
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {},
+ _STD_VECTOR<uint8_t> body = {},
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -297,10 +317,10 @@ namespace BinaryNinja::Http
\param uploadProgress Function to call for upload progress updates
\return Request structure with specified fields
*/
- static Request Post(std::string url,
- std::unordered_map<std::string, std::string> headers,
- std::vector<std::pair<std::string, std::string>> params,
- std::vector<std::pair<std::string, std::string>> formFields,
+ static Request Post(_STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> formFields,
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
@@ -315,10 +335,10 @@ namespace BinaryNinja::Http
\param uploadProgress Function to call for upload progress updates
\return Request structure with specified fields
*/
- static Request Post(std::string url,
- std::unordered_map<std::string, std::string> headers,
- std::vector<std::pair<std::string, std::string>> params,
- std::vector<MultipartField> formFields,
+ static Request Post(_STD_STRING url,
+ _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers,
+ _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params,
+ _STD_VECTOR<MultipartField> formFields,
std::function<bool(size_t, size_t)> downloadProgress = {},
std::function<bool(size_t, size_t)> uploadProgress = {});
};
@@ -329,7 +349,7 @@ namespace BinaryNinja::Http
\param str Input string
\return URLEncoded string
*/
- std::string UrlEncode(const std::string& str);
+ _STD_STRING UrlEncode(const _STD_STRING& str);
/*!
@@ -337,7 +357,7 @@ namespace BinaryNinja::Http
\param fields Input key/value pairs
\return URLEncoded form body
*/
- std::string UrlEncode(const std::vector<std::pair<std::string, std::string>>& fields);
+ _STD_STRING UrlEncode(const _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>>& fields);
/*!
@@ -347,7 +367,7 @@ namespace BinaryNinja::Http
\param boundary Output boundary between fields in the body (for Content-Type header)
\return Multipart encoded form body
*/
- std::vector<uint8_t> MultipartEncode(const std::vector<MultipartField>& fields, std::string& boundary);
+ _STD_VECTOR<uint8_t> MultipartEncode(const _STD_VECTOR<MultipartField>& fields, _STD_STRING& boundary);
/*!
@@ -357,5 +377,10 @@ namespace BinaryNinja::Http
\param response Output Response structure with body
\return Zero or greater on success
*/
- int Perform(const BinaryNinja::Ref<BinaryNinja::DownloadInstance>& instance, const Request& request, Response& response);
+ int Perform(const Ref<DownloadInstance>& instance, const Request& request, Response& response);
+
+#undef _STD_VECTOR
+#undef _STD_SET
+#undef _STD_UNORDERED_MAP
+#undef _STD_MAP
} \ No newline at end of file
diff --git a/interaction.cpp b/interaction.cpp
index 05420f17..2f808067 100644
--- a/interaction.cpp
+++ b/interaction.cpp
@@ -415,6 +415,13 @@ static BNMessageBoxButtonResult ShowMessageBoxCallback(void* ctxt, const char* t
}
+static bool OpenUrlCallback(void* ctxt, const char* url)
+{
+ InteractionHandler* handler = (InteractionHandler*)ctxt;
+ return handler->OpenUrl(url);
+}
+
+
void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler)
{
BNInteractionHandlerCallbacks cb;
@@ -433,6 +440,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler)
cb.getDirectoryNameInput = GetDirectoryNameInputCallback;
cb.getFormInput = GetFormInputCallback;
cb.showMessageBox = ShowMessageBoxCallback;
+ cb.openUrl = OpenUrlCallback;
BNRegisterInteractionHandler(&cb);
}
@@ -660,6 +668,12 @@ BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const
}
+bool BinaryNinja::OpenUrl(const std::string& url)
+{
+ return BNOpenUrl(url.c_str());
+}
+
+
ReportCollection::ReportCollection()
{
m_object = BNCreateReportCollection();
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 483cbad3..9fd8c6b2 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -6,6 +6,10 @@ file(GLOB PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/*.py)
list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/_binaryninjacore.py)
list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enums.py)
+if(NOT ENTERPRISE)
+ list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enterprise.py)
+endif()
+
add_executable(generator
${PROJECT_SOURCE_DIR}/generator.cpp)
target_link_libraries(generator binaryninjaapi)
@@ -22,25 +26,12 @@ if(BN_INTERNAL_BUILD)
COMMAND ${CMAKE_COMMAND} -E copy ${BN_CORE_OUTPUT_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/)
endif()
- option(LICENSE_FILE "Path to license file, for compiling")
- set(LICENSE "")
- if(LICENSE_FILE)
- file(READ ${LICENSE_FILE} LICENSE_CONTS)
- message(STATUS "Using licence for build: ${LICENSE_FILE}")
- # Encode for passing through the command-line
- string(REPLACE "\n" "" LICENSE_CONTS "${LICENSE_CONTS}")
- string(REPLACE "\"" "\\\"" LICENSE_CONTS "${LICENSE_CONTS}")
- string(REPLACE "{" "\\{" LICENSE_CONTS "${LICENSE_CONTS}")
- string(REPLACE "}" "\\}" LICENSE_CONTS "${LICENSE_CONTS}")
- set(LICENSE "BN_LICENSE=${LICENSE_CONTS}")
- endif()
-
add_custom_target(generator_copy ALL
BYPRODUCTS ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py
DEPENDS ${PYTHON_SOURCES} ${PROJECT_SOURCE_DIR}/../binaryninjacore.h $<TARGET_FILE:generator>
COMMAND ${CMAKE_COMMAND} -E echo "Copying Python Sources"
COMMAND ${CMAKE_COMMAND} -E make_directory ${BN_RESOURCE_DIR}/python/binaryninja/
- COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 ${LICENSE} $<TARGET_FILE:generator> ${PROJECT_SOURCE_DIR}/../binaryninjacore.h ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py
+ COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 $<TARGET_FILE:generator> ${PROJECT_SOURCE_DIR}/../binaryninjacore.h ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py
COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_SOURCES} ${BN_RESOURCE_DIR}/python/binaryninja/
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${BN_RESOURCE_DIR}/python/binaryninja/
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/enums.py ${BN_RESOURCE_DIR}/python/binaryninja/
diff --git a/python/__init__.py b/python/__init__.py
index 711ed550..1cf00773 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -72,6 +72,9 @@ from .log import (redirect_output_to_log, is_output_redirected_to_log,
log_debug, log_info, log_warn, log_error, log_alert,
log_to_stdout, log_to_stderr, log_to_file, close_logs)
from .log import log as log_at_level
+# Only load Enterprise Client support on Enterprise builds
+if core.BNGetProduct() == "Binary Ninja Enterprise Client":
+ from .enterprise import *
def shutdown():
@@ -123,6 +126,14 @@ _plugin_init = False
def _init_plugins():
global _enable_default_log
global _plugin_init
+
+ if not core_ui_enabled() and core.BNGetProduct() == "Binary Ninja Enterprise Client":
+ # Enterprise client needs to checkout a license reservation or else BNInitPlugins will fail
+ if not core.BNAuthenticateEnterpriseServerWithMethod("Keychain") and (not core.BNIsLicenseValidated() or not enterprise.is_license_still_activated()):
+ raise RuntimeError(
+ "To use Binary Ninja Enterprise from a headless python script, you must check out a license first.\n"
+ "You can either check out a license for an extended time with the UI, or use the binaryninja.enterprise module.")
+
if not _plugin_init:
# The first call to BNInitCorePlugins returns True for successful initialization and True in this context indicates headless operation.
# The result is pulled from BNInitPlugins as that now wraps BNInitCorePlugins.
diff --git a/python/enterprise.py b/python/enterprise.py
new file mode 100644
index 00000000..8eadb06c
--- /dev/null
+++ b/python/enterprise.py
@@ -0,0 +1,189 @@
+import ctypes
+from typing import Tuple, List, Optional
+
+import binaryninja._binaryninjacore as core
+import binaryninja
+
+if core.BNGetProduct() != "Binary Ninja Enterprise Client":
+ # None of these functions exist on other builds, so just raise here to notify anyone who tries to use this
+ raise RuntimeError("Cannot use Binary Ninja Enterprise client functionality with a non-Enterprise client.")
+
+
+def connect():
+ """
+ Connect to the Enterprise Server.
+ """
+ if not core.BNConnectEnterpriseServer():
+ raise RuntimeError(last_error())
+
+def is_connected() -> bool:
+ """
+ Determine if the Enterprise Server is currently connected.
+ :return: True if connected
+ """
+ return core.BNIsEnterpriseServerConnected()
+
+def authenticate_with_credentials(username: str, password: str):
+ """
+ Authenticate to the Enterprise Server with username/password credentials.
+ :param str username: Username to use.
+ :param str password: Password to use.
+ """
+ if not core.BNAuthenticateEnterpriseServerWithCredentials(username, password):
+ raise RuntimeError(last_error())
+
+def authenticate_with_method(method: str):
+ """
+ Authenticate to the Enterprise Server with a non-password method. Note that many of these will
+ open a URL for a browser-based login prompt, which may not be usable on headless installations.
+ See :func:`authentication_methods` for a list of accepted methods.
+ :param str method: Name of method to use.
+ """
+ if not core.BNAuthenticateEnterpriseServerWithMethod(method):
+ raise RuntimeError(last_error())
+
+def authentication_methods() -> List[Tuple[str, str]]:
+ """
+ Get a list of authentication methods accepted by the Enterprise Server.
+ :return: List of (<method name>, <method display name>) tuples
+ """
+ methods = ctypes.POINTER(ctypes.c_char_p)()
+ names = ctypes.POINTER(ctypes.c_char_p)()
+ count = core.BNGetEnterpriseServerAuthenticationMethods(methods, names)
+ results = []
+ for i in range(count):
+ results.append((core.pyNativeStr(methods[i]), core.pyNativeStr(names[i])))
+ core.BNFreeStringList(methods, count)
+ core.BNFreeStringList(names, count)
+ return results
+
+def deauthenticate():
+ """
+ Deauthenticate from the Enterprise server, clearing any cached credentials.
+ """
+ if not core.BNDeauthenticateEnterpriseServer():
+ raise RuntimeError(last_error())
+
+def cancel_authentication():
+ """
+ Cancel a call to :func:`authenticate_with_credentials` or :func:`authenticate_with_method`.
+ Note those functions are blocking, so this must be called on a separate thread.
+ """
+ core.BNCancelEnterpriseServerAuthentication()
+
+def is_authenticated() -> bool:
+ """
+ Determine if you have authenticated to the Enterprise Server.
+ :return: True if you are authenticated
+ """
+ return core.BNIsEnterpriseServerAuthenticated()
+
+def username() -> Optional[None]:
+ """
+ Get the username of the currently authenticated user to the Enterprise Server.
+ :return: Username, if authenticated. None, otherwise.
+ """
+ return core.BNGetEnterpriseServerUsername()
+
+def reservation_time_limit() -> int:
+ """
+ Get the maximum checkout duration allowed by the Enterprise Server.
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ :return: Duration, in seconds, of the maximum time you are allowed to checkout a license.
+ """
+ return core.BNGetEnterpriseServerReservationTimeLimit()
+
+def acquire_license(duration, cache=False):
+ """
+ Check out and activate a license from the Enterprise Server.
+ If ``cache`` is True, the checkout will be saved to a local secrets storage. This is platform-dependent:
+ - macOS: Saved to the user's keychain
+ - Windows: Saved to the credential store
+ - Linux: Saved with dbus's Secret Service API
+
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ .. warning:: If ``cache`` is False, you must remember to call :func:`release_license` before the process
+ exits to release the uncached license back to the server. If you forget to do so, you will
+ have to either wait for the checkout to expire or have an administrator revoke the checkout.
+
+ :param int duration: Desired length of license checkout, in seconds.
+ :param bool cache: If true, the license will be saved to a local secrets storage.
+ """
+ if not core.BNAcquireEnterpriseServerLicense(duration, cache):
+ raise RuntimeError(last_error())
+
+def release_license():
+ """
+ Release the currently checked out license back to the Enterprise Server.
+
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ .. note:: This will deactivate the Binary Ninja Enterprise client. You must call :func:`acquire_license`
+ again to continue using Binary Ninja Enterprise in the current process.
+ """
+ if not core.BNReleaseEnterpriseServerLicense():
+ raise RuntimeError(last_error())
+
+def license_expiration_time() -> int:
+ """
+ Get the expiry time of the current license checkout.
+ :return: Expiry time as a Unix epoch, or 0 if no license is checked out.
+ """
+ return core.BNGetEnterpriseServerLicenseExpirationTime()
+
+def license_duration() -> int:
+ """
+ Get the duration of the current license checkout.
+ :return: Duration, in seconds, of the total time of the current checkout.
+ """
+ return core.BNGetEnterpriseServerLicenseDuration()
+
+def is_license_still_activated() -> bool:
+ """
+ Determine if your current license checkout is still valid.
+ :return: True if your current checkout is still valid.
+ """
+ return core.BNIsEnterpriseServerLicenseStillActivated()
+
+def last_error() -> str:
+ """
+ Get a text representation the last error encountered by the Enterprise Client
+ :return: Last error message, or empty string if there is none.
+ """
+ return core.BNGetEnterpriseServerLastError()
+
+class LicenseCheckout:
+ """
+ Helper class for scripts to make use of a license checkout in a scope.
+
+ :Example:
+ enterprise.connect()
+ enterprise.authenticate_with_credentials("username", "password")
+ with enterprise.LicenseCheckout():
+ # Do some operation
+ bv = open_view("/bin/ls") # e.g
+ # License is released at end of scope
+
+ """
+
+ def __init__(self, duration=900, cache=False):
+ self.desired_duration = duration
+ self.desired_cache = cache
+
+ def __enter__(self):
+ # UI builds have their own license manager
+ if binaryninja.core_ui_enabled():
+ return
+ if not is_connected():
+ connect()
+ if not is_authenticated():
+ raise RuntimeError("Could not checkout a license: Not authenticated. Please use binaryninja.enterprise.authenticate_with_credentials or authenticate_with_method first!")
+ acquire_license(self.desired_duration, self.desired_cache)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ # UI builds have their own license manager
+ if binaryninja.core_ui_enabled():
+ return
+ release_license()
diff --git a/python/generator.cpp b/python/generator.cpp
index e0695b66..2e42fa6f 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -160,11 +160,6 @@ int main(int argc, char* argv[])
return 1;
}
- if (getenv("BN_LICENSE"))
- {
- BNSetLicense(getenv("BN_LICENSE"));
- }
-
Architecture::Register(new GeneratorArchitecture());
// Parse API header to get type and function information
diff --git a/python/interaction.py b/python/interaction.py
index 3bbf5fa6..581a87f6 100644
--- a/python/interaction.py
+++ b/python/interaction.py
@@ -20,6 +20,7 @@
import ctypes
import traceback
+import webbrowser
from typing import Optional
# Binary Ninja components
@@ -491,6 +492,7 @@ class InteractionHandler:
self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input)
self._cb.getFormInput = self._cb.getFormInput.__class__(self._get_form_input)
self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box)
+ self._cb.openUrl = self._cb.openUrl.__class__(self._open_url)
def register(self):
self.__class__._interaction_handler = self
@@ -665,6 +667,13 @@ class InteractionHandler:
except:
log_error(traceback.format_exc())
+ def _open_url(self, ctxt, url):
+ try:
+ return self.open_url(url)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
def show_plain_text_report(self, view, title, contents):
pass
@@ -715,6 +724,10 @@ class InteractionHandler:
def show_message_box(self, title, text, buttons, icon):
return MessageBoxButtonResult.CancelButton
+ def open_url(self, url):
+ webbrowser.open(url)
+ return True
+
class PlainTextReport:
def __init__(self, title, contents, view = None):
@@ -1302,3 +1315,14 @@ def show_message_box(title, text, buttons=MessageBoxButtonSet.OKButtonSet, icon=
:rtype: MessageBoxButtonResult
"""
return core.BNShowMessageBox(title, text, buttons, icon)
+
+
+def open_url(url):
+ """
+ ``open_url`` Opens a given url in the user's web browser, if available.
+
+ :param str url: Url to open
+ :return: True if successful
+ :rtype: bool
+ """
+ return core.BNOpenUrl(url)
diff --git a/secretsprovider.cpp b/secretsprovider.cpp
new file mode 100644
index 00000000..62a51fff
--- /dev/null
+++ b/secretsprovider.cpp
@@ -0,0 +1,141 @@
+// Copyright (c) 2015-2021 Vector 35 Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "binaryninjaapi.h"
+#include <string.h>
+
+using namespace BinaryNinja;
+
+SecretsProvider::SecretsProvider(const std::string& name): m_nameForRegister(name)
+{
+
+}
+
+
+SecretsProvider::SecretsProvider(BNSecretsProvider* provider)
+{
+ m_object = provider;
+}
+
+
+bool SecretsProvider::HasDataCallback(void* ctxt, const char* key)
+{
+ SecretsProvider* provider = (SecretsProvider*)ctxt;
+ return provider->HasData(key);
+}
+
+
+char* SecretsProvider::GetDataCallback(void* ctxt, const char* key)
+{
+ SecretsProvider* provider = (SecretsProvider*)ctxt;
+ std::optional<std::string> data = provider->GetData(key);
+ if (!data.has_value())
+ return nullptr;
+ char* value = BNAllocString(data->c_str());
+ memset(data->data(), 0, data->size());
+ return value;
+}
+
+
+bool SecretsProvider::StoreDataCallback(void* ctxt, const char* key, const char* data)
+{
+ SecretsProvider* provider = (SecretsProvider*)ctxt;
+ std::string value = data;
+ bool result = provider->StoreData(key, value);
+ memset(value.data(), 0, value.size());
+ return result;
+}
+
+
+bool SecretsProvider::DeleteDataCallback(void* ctxt, const char* key)
+{
+ SecretsProvider* provider = (SecretsProvider*)ctxt;
+ return provider->DeleteData(key);
+}
+
+
+std::vector<Ref<SecretsProvider>> SecretsProvider::GetList()
+{
+ size_t count;
+ BNSecretsProvider** list = BNGetSecretsProviderList(&count);
+ std::vector<Ref<SecretsProvider>> result;
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new CoreSecretsProvider(list[i]));
+ BNFreeSecretsProviderList(list);
+ return result;
+}
+
+
+Ref<SecretsProvider> SecretsProvider::GetByName(const std::string& name)
+{
+ BNSecretsProvider* result = BNGetSecretsProviderByName(name.c_str());
+ if (!result)
+ return nullptr;
+ return new CoreSecretsProvider(result);
+}
+
+
+void SecretsProvider::Register(SecretsProvider* provider)
+{
+ BNSecretsProviderCallbacks cb;
+ cb.context = provider;
+ cb.hasData = HasDataCallback;
+ cb.getData = GetDataCallback;
+ cb.storeData = StoreDataCallback;
+ cb.deleteData = DeleteDataCallback;
+ provider->m_object = BNRegisterSecretsProvider(provider->m_nameForRegister.c_str(), &cb);
+}
+
+
+CoreSecretsProvider::CoreSecretsProvider(BNSecretsProvider* provider): SecretsProvider(provider)
+{
+
+}
+
+
+bool CoreSecretsProvider::HasData(const std::string& key)
+{
+ return BNSecretsProviderHasData(m_object, key.c_str());
+}
+
+
+std::optional<std::string> CoreSecretsProvider::GetData(const std::string& key)
+{
+ char* data = BNGetSecretsProviderData(m_object, key.c_str());
+ if (data == nullptr)
+ return std::optional<std::string>();
+
+ std::string value = data;
+ memset(data, 0, strlen(data));
+ BNFreeString(data);
+ return value;
+}
+
+
+bool CoreSecretsProvider::StoreData(const std::string& key, const std::string& data)
+{
+ return BNStoreSecretsProviderData(m_object, key.c_str(), data.c_str());
+}
+
+
+bool CoreSecretsProvider::DeleteData(const std::string& key)
+{
+ return BNDeleteSecretsProviderData(m_object, key.c_str());
+}
diff --git a/ui/uitypes.h b/ui/uitypes.h
index 7bcaa560..3ed27da8 100644
--- a/ui/uitypes.h
+++ b/ui/uitypes.h
@@ -85,6 +85,7 @@ typedef BinaryNinja::Ref<BinaryNinja::ReportCollection> ReportCollectionRef;
typedef BinaryNinja::Ref<BinaryNinja::SaveSettings> SaveSettingsRef;
typedef BinaryNinja::Ref<BinaryNinja::ScriptingInstance> ScriptingInstanceRef;
typedef BinaryNinja::Ref<BinaryNinja::ScriptingProvider> ScriptingProviderRef;
+typedef BinaryNinja::Ref<BinaryNinja::SecretsProvider> SecretsProviderRef;
typedef BinaryNinja::Ref<BinaryNinja::Section> SectionRef;
typedef BinaryNinja::Ref<BinaryNinja::Segment> SegmentRef;
typedef BinaryNinja::Ref<BinaryNinja::Settings> SettingsRef;