summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2018-03-02 11:41:13 +0100
committerSzczepan Zalega <szczepan@nitrokey.com>2018-03-02 11:41:13 +0100
commit379daf936caa7fc8d7311a5dda101edb40d35ca5 (patch)
tree2d186dec6976b12a9f7b37e589c02703275a30ef
parentd5486ba77235a874245fbee07a75cea89fa59ea2 (diff)
parentc3d615b659b608f3a1d624f6fc78c303efbe1f8e (diff)
downloadlibnitrokey-379daf936caa7fc8d7311a5dda101edb40d35ca5.tar.gz
libnitrokey-379daf936caa7fc8d7311a5dda101edb40d35ca5.tar.bz2
Merge branch 'wip-multiple_devices'
Allow to use multiple devices, iteratively. Storage only.
-rw-r--r--.idea/vcs.xml3
-rw-r--r--CMakeLists.txt3
-rw-r--r--NK_C_API.cc21
-rw-r--r--NK_C_API.h31
-rw-r--r--NitrokeyManager.cc139
-rw-r--r--device.cc35
-rw-r--r--include/NitrokeyManager.h22
-rw-r--r--include/device.h10
-rw-r--r--include/log.h8
-rw-r--r--log.cc19
-rw-r--r--unittest/misc.py7
-rw-r--r--unittest/test_C_API.cpp28
-rw-r--r--unittest/test_multiple.py60
-rw-r--r--unittest/test_multiple_devices.cc152
-rw-r--r--unittest/test_pro.py6
15 files changed, 521 insertions, 23 deletions
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 486a99a..94a25f7 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,8 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
- <mapping directory="$PROJECT_DIR$/hidapi" vcs="Git" />
- <mapping directory="$PROJECT_DIR$/python_bindings/pybind11" vcs="Git" />
- <mapping directory="$PROJECT_DIR$/unittest/Catch" vcs="Git" />
</component>
</project> \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a4ebb0..6037393 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -191,6 +191,9 @@ IF (COMPILE_TESTS)
add_executable (test_issues unittest/test_issues.cc)
target_link_libraries (test_issues ${EXTRA_LIBS} nitrokey catch)
+ add_executable (test_multiple_devices unittest/test_multiple_devices.cc)
+ target_link_libraries (test_multiple_devices ${EXTRA_LIBS} nitrokey catch)
+
ENDIF()
diff --git a/NK_C_API.cc b/NK_C_API.cc
index f881caf..66bbcf9 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 delimiter char
+ return strndup(res.c_str(), 8192); //this buffer size sets limit to over 200 devices ID's
+ });
+ }
+
+ 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..3778ad0 100644
--- a/NK_C_API.h
+++ b/NK_C_API.h
@@ -269,6 +269,7 @@ extern "C" {
NK_C_API int NK_totp_set_time(uint64_t time);
NK_C_API int NK_totp_get_time();
+
//passwords
/**
* Change administrator PIN
@@ -568,6 +569,36 @@ extern "C" {
*/
NK_C_API int NK_get_progress_bar_value();
+/**
+ * Returns a list of connected devices' id's, delimited by ';' character. Empty string is returned on no device found.
+ * Each ID could consist of:
+ * 1. SC_id:SD_id_p_path (about 40 bytes)
+ * 2. path (about 10 bytes)
+ * where 'path' is USB path (bus:num), 'SC_id' is smartcard ID, 'SD_id' is storage card ID and
+ * '_p_' and ':' are field delimiters.
+ * Case 2 (USB path only) is used, when the device cannot be asked about its status data (e.g. during a long operation,
+ * like clearing SD card.
+ * Internally connects to all available devices and creates a map between ids and connection objects.
+ * Side effects: changes active device to last detected Storage device.
+ * Storage only
+ * @example Example of returned data: '00005d19:dacc2cb4_p_0001:0010:02;000037c7:4cf12445_p_0001:000f:02;0001:000c:02'
+ * @return string delimited id's of connected devices
+ */
+ NK_C_API const char* NK_list_devices_by_cpuID();
+
+
+/**
+ * Connects to the device with given ID. ID's list could be created with NK_list_devices_by_cpuID.
+ * Requires calling to NK_list_devices_by_cpuID first. Connecting to arbitrary ID/USB path is not handled.
+ * On connection requests status from device and disconnects it / removes from map on connection failure.
+ * Storage only
+ * @param id Target device ID (example: '00005d19:dacc2cb4_p_0001:0010:02')
+ * @return 1 on successful connection, 0 otherwise
+ */
+ NK_C_API int NK_connect_with_ID(const char* id);
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc
index d563b26..e5f10df 100644
--- a/NitrokeyManager.cc
+++ b/NitrokeyManager.cc
@@ -81,6 +81,13 @@ 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();
+ connected_devices[d.first] = nullptr;
+ }
}
bool NitrokeyManager::set_current_device_speed(int retry_delay, int send_receive_delay){
@@ -98,6 +105,132 @@ using nitrokey::misc::strcpyT;
return true;
}
+ 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
+ }
+
+ std::vector<std::string> NitrokeyManager::list_devices_by_cpuID(){
+ using misc::toHex;
+ //disconnect default device
+ disconnect();
+
+ std::lock_guard<std::mutex> lock(mex_dev_com_manager);
+ LOGD1("Disconnecting registered devices");
+ for (auto & kv : connected_devices_byID){
+ if (kv.second != nullptr)
+ kv.second->disconnect();
+ }
+ connected_devices_byID.clear();
+
+ LOGD1("Enumerating devices");
+ std::vector<std::string> res;
+ auto d = make_shared<Stick20>();
+ const auto v = d->enumerate();
+ LOGD1("Discovering IDs");
+ for (auto & p: v){
+ d = make_shared<Stick20>();
+ LOGD1( std::string("Found: ") + p );
+ d->set_path(p);
+ try{
+ if (d->connect()){
+ device = d;
+ std::string id;
+ try {
+ const auto status = get_status_storage();
+ const auto sc_id = toHex(status.ActiveSmartCardID_u32);
+ const auto sd_id = toHex(status.ActiveSD_CardID_u32);
+ id += sc_id + ":" + sd_id;
+ id += "_p_" + p;
+ }
+ catch (const LongOperationInProgressException &e) {
+ LOGD1(std::string("Long operation in progress, setting ID to: ") + p);
+ id = p;
+ }
+
+ connected_devices_byID[id] = d;
+ res.push_back(id);
+ LOGD1( std::string("Found: ") + p + " => " + id);
+ } else{
+ LOGD1( std::string("Could not connect to: ") + p);
+ }
+ }
+ catch (const DeviceCommunicationException &e){
+ LOGD1( std::string("Exception encountered: ") + p);
+ }
+ }
+ return res;
+ }
+
+ 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()) {
+ LOGD1(std::string("Could not find device ")+id + ". Refresh devices list with list_devices_by_cpuID().");
+ return false;
+ }
+
+ auto d = connected_devices_byID[id];
+ device = d;
+ current_device_id = id;
+
+ //validate connection
+ try{
+ get_status();
+ }
+ catch (const LongOperationInProgressException &){
+ //ignore
+ }
+ catch (const DeviceCommunicationException &){
+ d->disconnect();
+ current_device_id = "";
+ connected_devices_byID[id] = nullptr;
+ connected_devices_byID.erase(position);
+ return false;
+ }
+ nitrokey::log::Log::setPrefix(id);
+ LOGD1("Device successfully changed");
+ 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;
+
+ if(cache_connections){
+ connected_devices [path] = p;
+ }
+
+ device = p; //previous device will be disconnected automatically
+ current_device_id = path;
+ nitrokey::log::Log::setPrefix(path);
+ LOGD1("Device successfully changed");
+ return true;
+ }
+
bool NitrokeyManager::connect() {
std::lock_guard<std::mutex> lock(mex_dev_com_manager);
vector< shared_ptr<Device> > devices = { make_shared<Stick10>(), make_shared<Stick20>() };
@@ -233,7 +366,7 @@ using nitrokey::misc::strcpyT;
return response.data();
}
catch (DeviceSendingFailure &e){
- disconnect();
+// disconnect();
throw;
}
}
@@ -979,5 +1112,9 @@ using nitrokey::misc::strcpyT;
return data.data().SD_Card_Size_u8;
}
+ const string NitrokeyManager::get_current_device_id() const {
+ return current_device_id;
+ }
+
}
diff --git a/device.cc b/device.cc
index ac31b1d..da5345b 100644
--- a/device.cc
+++ b/device.cc
@@ -20,6 +20,7 @@
*/
#include <chrono>
+#include <iostream>
#include <thread>
#include <cstddef>
#include <stdexcept>
@@ -68,7 +69,7 @@ bool Device::_disconnect() {
LOG(std::string(__FUNCTION__) + std::string(m_model == DeviceModel::PRO ? "PRO" : "STORAGE"), Loglevel::DEBUG_L2);
LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2);
- LOG(std::string("Disconnection success: ") + std::to_string(mp_devhandle == nullptr), Loglevel::DEBUG_L2);
+ LOG(std::string("Disconnection: handle already freed: ") + std::to_string(mp_devhandle == nullptr) + " ("+m_path+")", Loglevel::DEBUG_L1);
if(mp_devhandle == nullptr) return false;
hid_close(mp_devhandle);
@@ -92,12 +93,20 @@ bool Device::_connect() {
LOG(std::string(__FUNCTION__) + std::string(" *IN* "), Loglevel::DEBUG_L2);
// hid_init(); // done automatically on hid_open
- mp_devhandle = hid_open(m_vid, m_pid, nullptr);
+ if (m_path.empty()){
+ mp_devhandle = hid_open(m_vid, m_pid, nullptr);
+ } else {
+ mp_devhandle = hid_open_path(m_path.c_str());
+ }
const bool success = mp_devhandle != nullptr;
- LOG(std::string("Connection success: ") + std::to_string(success), Loglevel::DEBUG_L2);
+ LOG(std::string("Connection success: ") + std::to_string(success) + " ("+m_path+")", Loglevel::DEBUG_L1);
return success;
}
+void Device::set_path(const std::string path){
+ m_path = path;
+}
+
int Device::send(const void *packet) {
LOG(__FUNCTION__, Loglevel::DEBUG_L2);
std::lock_guard<std::mutex> lock(mex_dev_com);
@@ -160,6 +169,24 @@ int Device::recv(void *packet) {
return status;
}
+std::vector<std::string> Device::enumerate(){
+ //TODO make static
+ auto pInfo = hid_enumerate(m_vid, m_pid);
+ auto pInfo_ = pInfo;
+ std::vector<std::string> res;
+ while (pInfo != nullptr){
+ std::string a (pInfo->path);
+ res.push_back(a);
+ pInfo = pInfo->next;
+ }
+
+ if (pInfo_ != nullptr){
+ hid_free_enumeration(pInfo_);
+ }
+
+ return res;
+}
+
bool Device::could_be_enumerated() {
LOG(__FUNCTION__, Loglevel::DEBUG_L2);
std::lock_guard<std::mutex> lock(mex_dev_com);
@@ -221,7 +248,7 @@ Stick10::Stick10():
Stick20::Stick20():
- Device(0x20a0, 0x4109, DeviceModel::STORAGE, 40ms, 25, 40ms)
+ Device(0x20a0, 0x4109, DeviceModel::STORAGE, 40ms, 55, 40ms)
{
setDefaultDelay();
}
diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h
index 0db0856..ca58d24 100644
--- a/include/NitrokeyManager.h
+++ b/include/NitrokeyManager.h
@@ -30,6 +30,7 @@
#include "stick20_commands.h"
#include <vector>
#include <memory>
+#include <unordered_map>
namespace nitrokey {
using namespace nitrokey::device;
@@ -67,6 +68,17 @@ char * strndup(const char* str, size_t maxlen);
bool get_time(uint64_t time = 0);
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();
+
+ /**
+ * Connect to the device using unique smartcard:datacard id.
+ * Needs list_device_by_cpuID() run first
+ * @param id Current ID of the target device
+ * @return true on success, false on failure
+ */
+ bool connect_with_ID(const std::string id);
+ bool connect_with_path (std::string path);
bool connect(const char *device_model);
bool connect();
bool disconnect();
@@ -198,8 +210,16 @@ char * strndup(const char* str, size_t maxlen);
static shared_ptr <NitrokeyManager> _instance;
std::shared_ptr<Device> device;
+ std::string current_device_id;
+ public:
+ const string get_current_device_id() const;
+
+ private:
+ 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);
+ stick10::ReadSlot::ResponsePayload get_OTP_slot_data(const uint8_t slot_number);
bool is_valid_hotp_slot_number(uint8_t slot_number) const;
bool is_valid_totp_slot_number(uint8_t slot_number) const;
bool is_valid_password_safe_slot_number(uint8_t slot_number) const;
diff --git a/include/device.h b/include/device.h
index 1bd4773..f6d2380 100644
--- a/include/device.h
+++ b/include/device.h
@@ -25,6 +25,7 @@
#include "hidapi/hidapi.h"
#include <cstdint>
#include <string>
+#include <vector>
#define HID_REPORT_SIZE 65
@@ -105,8 +106,10 @@ public:
* @return true if visible by OS
*/
bool could_be_enumerated();
+ std::vector<std::string> enumerate();
- void show_stats();
+
+ void show_stats();
// ErrorCounters get_stats(){ return m_counters; }
int get_retry_receiving_count() const { return m_retry_receiving_count; };
int get_retry_sending_count() const { return m_retry_sending_count; };
@@ -121,8 +124,10 @@ public:
void set_retry_delay(std::chrono::milliseconds delay);
static void set_default_device_speed(int delay);
void setDefaultDelay();
+ void set_path(const std::string path);
+
-private:
+ private:
std::atomic<uint8_t> last_command_status;
void _reconnect();
bool _connect();
@@ -143,6 +148,7 @@ protected:
std::chrono::milliseconds m_retry_timeout;
std::chrono::milliseconds m_send_receive_delay;
std::atomic<hid_device *>mp_devhandle;
+ std::string m_path;
static std::atomic_int instances_count;
static std::chrono::milliseconds default_delay ;
diff --git a/include/log.h b/include/log.h
index 52a6e16..2a64bef 100644
--- a/include/log.h
+++ b/include/log.h
@@ -23,8 +23,6 @@
#define LOG_H
#include <string>
-#include <cstddef>
-
#include <functional>
namespace nitrokey {
@@ -86,6 +84,11 @@ namespace nitrokey {
private:
LogHandler *mp_loghandler;
Loglevel m_loglevel;
+ static std::string prefix;
+ public:
+ static void setPrefix(std::string prefix = std::string());
+
+ private:
static Log *mp_instance;
};
@@ -98,6 +101,7 @@ namespace nitrokey {
#define LOGD(string) while(false){}
#else
#define LOG(string, level) nitrokey::log::Log::instance()((string), (level))
+#define LOGD1(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L1))
#define LOGD(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L2))
#endif
diff --git a/log.cc b/log.cc
index 263ddd7..06acee7 100644
--- a/log.cc
+++ b/log.cc
@@ -19,11 +19,10 @@
* SPDX-License-Identifier: LGPL-3.0
*/
+#include "log.h"
#include <iostream>
-#include <string>
#include <ctime>
#include <iomanip>
-#include "log.h"
#include <sstream>
@@ -33,6 +32,9 @@ namespace nitrokey {
Log *Log::mp_instance = nullptr;
StdlogHandler stdlog_handler;
+ std::string Log::prefix = "";
+
+
std::string LogHandler::loglevel_to_str(Loglevel lvl) {
switch (lvl) {
case Loglevel::DEBUG_L1:
@@ -52,8 +54,17 @@ namespace nitrokey {
}
void Log::operator()(const std::string &logstr, Loglevel lvl) {
- if (mp_loghandler != nullptr)
- if ((int) lvl <= (int) m_loglevel) mp_loghandler->print(logstr, lvl);
+ if (mp_loghandler != nullptr){
+ if ((int) lvl <= (int) m_loglevel) mp_loghandler->print(prefix+logstr, lvl);
+ }
+ }
+
+ void Log::setPrefix(const std::string prefix) {
+ if (!prefix.empty()){
+ Log::prefix = "["+prefix+"]";
+ } else {
+ Log::prefix = "";
+ }
}
void StdlogHandler::print(const std::string &str, Loglevel lvl) {
diff --git a/unittest/misc.py b/unittest/misc.py
index a41f2b2..8be915d 100644
--- a/unittest/misc.py
+++ b/unittest/misc.py
@@ -43,7 +43,7 @@ def cast_pointer_to_tuple(obj, typen, len):
def get_devices_firmware_version(C):
- firmware = C.NK_get_major_firmware_version()
+ firmware = C.NK_get_minor_firmware_version()
return firmware
@@ -54,7 +54,7 @@ def is_pro_rtm_07(C):
def is_pro_rtm_08(C):
firmware = get_devices_firmware_version(C)
- return firmware == 8
+ return firmware in [8,9]
def is_storage(C):
@@ -62,7 +62,8 @@ def is_storage(C):
exact firmware storage is sent by other function
"""
# TODO identify connected device directly
- return not is_pro_rtm_08(C) and not is_pro_rtm_07(C)
+ firmware = get_devices_firmware_version(C)
+ return firmware >= 45
def is_long_OTP_secret_handled(C):
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.py b/unittest/test_multiple.py
new file mode 100644
index 0000000..7ea195e
--- /dev/null
+++ b/unittest/test_multiple.py
@@ -0,0 +1,60 @@
+import pprint
+from time import sleep
+
+import pytest
+from collections import defaultdict
+
+from tqdm import tqdm
+
+from conftest import skip_if_device_version_lower_than
+from constants import DefaultPasswords, DeviceErrorCode, bb
+from misc import gs, wait
+
+pprint = pprint.PrettyPrinter(indent=4).pprint
+
+
+@pytest.mark.other
+@pytest.mark.info
+def test_get_status_storage_multiple(C):
+ ids = gs(C.NK_list_devices_by_cpuID())
+ print(ids)
+ devices_list = ids.split(b';')
+ #
+ # for s in devices_list:
+ # res = C.NK_connect_with_ID(s)
+ # assert res == 1
+ # # st = gs(C.NK_get_status_storage_as_string())
+ # # print(len(st))
+ # C.NK_lock_device()
+ #
+ for s in devices_list:
+ res = C.NK_connect_with_ID(s)
+ assert res == 1
+ v = C.NK_fill_SD_card_with_random_data(b'12345678')
+ # print(v)
+
+ devices_count = len(devices_list)
+ assert devices_count != 0
+ b = 0
+
+ last_b = 0
+ with tqdm(total=devices_count*100) as pbar:
+ while b/devices_count < 100:
+ pbar.update(b - last_b)
+
+ b = defaultdict (lambda: 0)
+
+ ids = gs(C.NK_list_devices_by_cpuID())
+ devices_list = ids.split(b';')
+ devices_count = len(devices_list)
+
+ for s in devices_list:
+ res = C.NK_connect_with_ID(s)
+ if res != 1: continue
+ b[s] += C.NK_get_progress_bar_value()
+ print(b)
+ b = sum(b.values())
+ print('{}: {}'.format(b, int(b/devices_count) * '='))
+ sleep(5)
+
+
diff --git a/unittest/test_multiple_devices.cc b/unittest/test_multiple_devices.cc
new file mode 100644
index 0000000..f497908
--- /dev/null
+++ b/unittest/test_multiple_devices.cc
@@ -0,0 +1,152 @@
+
+static const char *const default_admin_pin = "12345678";
+static const char *const default_user_pin = "123456";
+const char * temporary_password = "123456789012345678901234";
+const char * RFC_SECRET = "12345678901234567890";
+
+#include "catch.hpp"
+
+#include <iostream>
+#include <NitrokeyManager.h>
+#include <stick20_commands.h>
+
+using namespace nitrokey;
+
+
+TEST_CASE("List devices", "[BASIC]") {
+ shared_ptr<Stick20> d = make_shared<Stick20>();
+ auto v = d->enumerate();
+ REQUIRE(v.size() > 0);
+ for (auto a : v){
+ std::cout << a;
+ d->set_path(a);
+ d->connect();
+ auto res = GetStatus::CommandTransaction::run(d);
+ auto res2 = GetDeviceStatus::CommandTransaction::run(d);
+ std::cout << " " << res.data().card_serial_u32 << " "
+ << res.data().get_card_serial_hex()
+ << " " << std::to_string(res2.data().versionInfo.minor)
+ << std::endl;
+ d->disconnect();
+ }
+}
+
+TEST_CASE("Regenerate AES keys", "[BASIC]") {
+ shared_ptr<Stick20> d = make_shared<Stick20>();
+ auto v = d->enumerate();
+ REQUIRE(v.size() > 0);
+
+ std::vector<shared_ptr<Stick20>> devices;
+ for (auto a : v){
+ std::cout << a << endl;
+ d = make_shared<Stick20>();
+ d->set_path(a);
+ d->connect();
+ devices.push_back(d);
+ }
+
+ for (auto d : devices){
+ auto res2 = GetDeviceStatus::CommandTransaction::run(d);
+ std::cout << std::to_string(res2.data().versionInfo.minor) << std::endl;
+// nitrokey::proto::stick20::CreateNewKeys::CommandPayload p;
+// p.set_defaults();
+// memcpy(p.password, "12345678", 8);
+// auto res3 = nitrokey::proto::stick20::CreateNewKeys::CommandTransaction::run(d, p);
+ }
+
+ for (auto d : devices){
+ //TODO watch out for multiple hid_exit calls
+ d->disconnect();
+ }
+}
+
+
+TEST_CASE("Use API", "[BASIC]") {
+ auto nm = NitrokeyManager::instance();
+ nm->set_loglevel(2);
+ auto v = nm->list_devices();
+ REQUIRE(v.size() > 0);
+
+ for (int i=0; i<10; i++){
+ for (auto a : v) {
+ std::cout <<"Connect with: " << a <<
+ " " << std::boolalpha << nm->connect_with_path(a) << " ";
+ try{
+ auto status_storage = nm->get_status_storage();
+ std::cout << status_storage.ActiveSmartCardID_u32
+ << " " << status_storage.ActiveSD_CardID_u32
+ << std::endl;
+
+// 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);
+ }
+ }
+ 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);
+
+ //no refresh - should not reconnect to new devices
+ // Scenario:
+ // 1. Run test
+ // 2. Remove one of the devices and reinsert it after a while
+ // 3. Device should not be reconnected and test should not crash
+ // 4. Remove all devices - test should continue
+
+ for (int j = 0; j < 100; j++) {
+ for (auto i : v) {
+ if (!nm->connect_with_ID(i)) continue;
+ int retry_count = 99;
+ try {
+ retry_count = nm->get_admin_retry_count();
+ std::cout << j << " " << i << " " << to_string(retry_count) << std::endl;
+ }
+ catch (...) {
+ retry_count = 99;
+ //pass
+ }
+ }
+ }
+ std::cout << "finished" << std::endl;
+}
+
+TEST_CASE("Use API ID refresh", "[BASIC]") {
+ auto nm = NitrokeyManager::instance();
+ nm->set_loglevel(2);
+
+ //refresh in each iteration - should reconnect to new devices
+ // Scenario:
+ // 1. Run test
+ // 2. Remove one of the devices and reinsert it after a while
+ // 3. Device should be reconnected
+
+ for(int j=0; j<100; j++) {
+ auto v = nm->list_devices_by_cpuID();
+ REQUIRE(v.size() > 0);
+ for (auto i : v) {
+ nm->connect_with_ID(i);
+ int retry_count = 99;
+ try {
+ retry_count = nm->get_admin_retry_count();
+ std::cout << j <<" " << i << " " << to_string(retry_count) << std::endl;
+ }
+ catch (...){
+ retry_count = 99;
+ //pass
+ }
+ }
+ }
+ std::cout << "finished" << std::endl;
+} \ No newline at end of file
diff --git a/unittest/test_pro.py b/unittest/test_pro.py
index 12a34e9..53588f6 100644
--- a/unittest/test_pro.py
+++ b/unittest/test_pro.py
@@ -164,9 +164,9 @@ def test_password_safe_slot_status(C):
@pytest.mark.aes
def test_issue_device_locks_on_second_key_generation_in_sequence(C):
- if is_pro_rtm_07(C) or is_pro_rtm_08(C):
- pytest.skip("issue to register: device locks up "
- "after below commands sequence (reinsertion fixes), skipping for now")
+# if is_pro_rtm_07(C) or is_pro_rtm_08(C):
+ pytest.skip("issue to register: device locks up "
+ "after below commands sequence (reinsertion fixes), skipping for now")
assert C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK
assert C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK