summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2017-12-04 19:21:09 +0100
committerSzczepan Zalega <szczepan@nitrokey.com>2018-02-28 19:23:05 +0100
commit388cf5fcb33f24bc04f79cd1fbea980214518d54 (patch)
tree1b57874287d02a1fe339f035ba84a54d3bf1f408
parent2faa8f6782a2e6294ed8849048a281d12d60da1c (diff)
downloadlibnitrokey-388cf5fcb33f24bc04f79cd1fbea980214518d54.tar.gz
libnitrokey-388cf5fcb33f24bc04f79cd1fbea980214518d54.tar.bz2
List devices by unique SC:SD id
Add C API and tests Add mutexes Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
-rw-r--r--NK_C_API.cc21
-rw-r--r--NK_C_API.h6
-rw-r--r--NitrokeyManager.cc87
-rw-r--r--include/NitrokeyManager.h3
-rw-r--r--unittest/test_C_API.cpp28
-rw-r--r--unittest/test_multiple_devices.cc24
6 files changed, 160 insertions, 9 deletions
diff --git a/NK_C_API.cc b/NK_C_API.cc
index f881caf..59247ba 100644
--- a/NK_C_API.cc
+++ b/NK_C_API.cc
@@ -608,6 +608,27 @@ extern "C" {
});
}
+ NK_C_API const char* NK_list_devices_by_cpuID() {
+ auto nm = NitrokeyManager::instance();
+ return get_with_string_result([&]() {
+ auto v = nm->list_devices_by_cpuID();
+ std::string res;
+ for (const auto a : v){
+ res += a+";";
+ }
+ if (res.size()>0) res.pop_back(); // remove last delimeter char
+ return strndup(res.c_str(), 4096);
+ });
+ }
+
+ NK_C_API int NK_connect_with_ID(const char* id) {
+ auto m = NitrokeyManager::instance();
+ return get_with_result([&]() {
+ return m->connect_with_ID(id) ? 1 : 0;
+ });
+ }
+
+
#ifdef __cplusplus
}
diff --git a/NK_C_API.h b/NK_C_API.h
index 73022b2..5933c67 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -568,6 +568,12 @@ extern "C" {
*/
NK_C_API int NK_get_progress_bar_value();
+
+ NK_C_API const char* NK_list_devices_by_cpuID();
+ NK_C_API int NK_connect_with_ID(const char* id);
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc
index da5f61a..4935076 100644
--- a/NitrokeyManager.cc
+++ b/NitrokeyManager.cc
@@ -81,6 +81,8 @@ using nitrokey::misc::strcpyT;
set_debug(true);
}
NitrokeyManager::~NitrokeyManager() {
+ std::lock_guard<std::mutex> lock(mex_dev_com_manager);
+
for (auto d : connected_devices){
if (d.second == nullptr) continue;
d.second->disconnect();
@@ -104,27 +106,98 @@ using nitrokey::misc::strcpyT;
}
std::vector<std::string> NitrokeyManager::list_devices(){
+ std::lock_guard<std::mutex> lock(mex_dev_com_manager);
+
auto p = make_shared<Stick20>();
return p->enumerate(); // make static
}
- bool NitrokeyManager::connect_with_path(std::string path) {
+ std::vector<std::string> NitrokeyManager::list_devices_by_cpuID(){
std::lock_guard<std::mutex> lock(mex_dev_com_manager);
- if(connected_devices.find(path) != connected_devices.end()
- && connected_devices[path] != nullptr) {
- device = connected_devices[path];
- return true;
+ std::vector<std::string> res;
+ auto d = make_shared<Stick20>();
+ const auto v = d->enumerate();
+ for (auto & p: v){
+ d = make_shared<Stick20>();
+ d->set_path(p);
+ try{
+ if (d->connect()){
+ device = d;
+ const auto status = get_status_storage();
+ const auto sc_id = status.ActiveSmartCardID_u32;
+ const auto sd_id = status.ActiveSD_CardID_u32;
+
+ auto id = std::to_string(sc_id) + ":" + std::to_string(sd_id);
+ connected_devices_byID[id] = d;
+ res.push_back(id);
+ } else{
+ std::cout << "Could not connect to: " + p << std::endl;
+ }
+ }
+ catch (const DeviceCommunicationException &e){
+ //ignore
+ std::cout << p << ": " << " Exception encountered" << std::endl;
+ }
}
+ return res;
+ }
+/**
+ * Connect to the device using unique smartcard:datacard id.
+ * Needs list_device_by_cpuID run first
+ * @param id
+ * @return
+ */
+ bool NitrokeyManager::connect_with_ID(const std::string id) {
+ std::lock_guard<std::mutex> lock(mex_dev_com_manager);
+ auto position = connected_devices_byID.find(id);
+ if (position == connected_devices_byID.end()) return false;
+
+ auto d = connected_devices_byID[id];
+ device = d;
+
+ try{
+ get_status();
+ }
+ catch (const DeviceCommunicationException &){
+ d->disconnect();
+ connected_devices_byID[id] = nullptr;
+ connected_devices_byID.erase(position);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Connects device to path.
+ * Assumes devices are not being disconnected and caches connections (param cache_connections).
+ * @param path os-dependent device path
+ * @return false, when could not connect, true otherwise
+ */
+ bool NitrokeyManager::connect_with_path(std::string path) {
+ const bool cache_connections = false;
+
+ std::lock_guard<std::mutex> lock(mex_dev_com_manager);
+
+ if (cache_connections){
+ if(connected_devices.find(path) != connected_devices.end()
+ && connected_devices[path] != nullptr) {
+ device = connected_devices[path];
+ return true;
+ }
+ }
auto p = make_shared<Stick20>();
p->set_path(path);
if(!p->connect()) return false;
- connected_devices [path] = p;
- device = p;
+ if(cache_connections){
+ connected_devices [path] = p;
+ }
+
+ device = p; //previous device will be disconnected automatically
return true;
}
diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h
index 2a79922..7ce432f 100644
--- a/include/NitrokeyManager.h
+++ b/include/NitrokeyManager.h
@@ -69,6 +69,8 @@ char * strndup(const char* str, size_t maxlen);
bool erase_totp_slot(uint8_t slot_number, const char *temporary_password);
bool erase_hotp_slot(uint8_t slot_number, const char *temporary_password);
std::vector<std::string> list_devices();
+ std::vector<std::string> list_devices_by_cpuID();
+ bool connect_with_ID(const std::string id);
bool connect_with_path (std::string path);
bool connect(const char *device_model);
bool connect();
@@ -202,6 +204,7 @@ char * strndup(const char* str, size_t maxlen);
static shared_ptr <NitrokeyManager> _instance;
std::shared_ptr<Device> device;
std::unordered_map<std::string, shared_ptr<Device> > connected_devices;
+ std::unordered_map<std::string, shared_ptr<Device> > connected_devices_byID;
stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number);
diff --git a/unittest/test_C_API.cpp b/unittest/test_C_API.cpp
index be47f08..2d83ef4 100644
--- a/unittest/test_C_API.cpp
+++ b/unittest/test_C_API.cpp
@@ -43,6 +43,7 @@ TEST_CASE("C API connect", "[BASIC]") {
TEST_CASE("Check retry count", "[BASIC]") {
REQUIRE(login != 0);
+ NK_set_debug_level(3);
REQUIRE(NK_get_admin_retry_count() == 3);
REQUIRE(NK_get_user_retry_count() == 3);
}
@@ -56,4 +57,31 @@ TEST_CASE("Check long strings", "[STANDARD]") {
result = NK_change_user_PIN(pin, longPin);
REQUIRE(result == TOO_LONG_STRING);
CAPTURE(result);
+}
+
+#include <string.h>
+
+TEST_CASE("multiple devices with ID", "[BASIC]") {
+ NK_logout();
+ NK_set_debug_level(3);
+ auto s = NK_list_devices_by_cpuID();
+ REQUIRE(s!=nullptr);
+ REQUIRE(strnlen(s, 4096) < 4096);
+ REQUIRE(strnlen(s, 4096) > 2*4);
+ std::cout << s << std::endl;
+
+ char *string, *token;
+ int t;
+
+ string = strndup(s, 4096);
+ free ( (void*) s);
+
+ while ((token = strsep(&string, ";")) != nullptr){
+ if (strnlen(token, 4096) < 3) continue;
+ std::cout << token << " connecting: ";
+ std::cout << (t=NK_connect_with_ID(token)) << std::endl;
+ REQUIRE(t == 1);
+ }
+
+ free (string);
} \ No newline at end of file
diff --git a/unittest/test_multiple_devices.cc b/unittest/test_multiple_devices.cc
index f5b4d6e..235a24d 100644
--- a/unittest/test_multiple_devices.cc
+++ b/unittest/test_multiple_devices.cc
@@ -78,15 +78,35 @@ TEST_CASE("Use API", "[BASIC]") {
<< " " << status_storage.ActiveSD_CardID_u32
<< std::endl;
- nm->fill_SD_card_with_random_data("12345678");
+// nm->fill_SD_card_with_random_data("12345678");
}
catch (const LongOperationInProgressException &e){
std::cout << "long operation in progress on " << a
<< " " << std::to_string(e.progress_bar_value) << std::endl;
- this_thread::sleep_for(1000ms);
+// this_thread::sleep_for(1000ms);
}
}
std::cout <<"Iteration: " << i << std::endl;
}
+}
+
+
+TEST_CASE("Use API ID", "[BASIC]") {
+ auto nm = NitrokeyManager::instance();
+ nm->set_loglevel(2);
+
+ auto v = nm->list_devices_by_cpuID();
+ REQUIRE(v.size() > 0);
+
+ for(int i=0; i<1000; i++) {
+ auto v = nm->list_devices_by_cpuID();
+ REQUIRE(v.size() > 0);
+ for (auto i : v) {
+ nm->connect_with_ID(i);
+ auto retry_count = nm->get_admin_retry_count();
+ std::cout << i << " " << to_string(retry_count) << std::endl;
+ }
+ }
+ std::cout << "finished" << std::endl;
} \ No newline at end of file