diff options
| -rw-r--r-- | .idea/vcs.xml | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | NK_C_API.cc | 21 | ||||
| -rw-r--r-- | NK_C_API.h | 31 | ||||
| -rw-r--r-- | NitrokeyManager.cc | 139 | ||||
| -rw-r--r-- | device.cc | 35 | ||||
| -rw-r--r-- | include/NitrokeyManager.h | 22 | ||||
| -rw-r--r-- | include/device.h | 10 | ||||
| -rw-r--r-- | include/log.h | 8 | ||||
| -rw-r--r-- | log.cc | 19 | ||||
| -rw-r--r-- | unittest/misc.py | 7 | ||||
| -rw-r--r-- | unittest/test_C_API.cpp | 28 | ||||
| -rw-r--r-- | unittest/test_multiple.py | 60 | ||||
| -rw-r--r-- | unittest/test_multiple_devices.cc | 152 | ||||
| -rw-r--r-- | unittest/test_pro.py | 6 | 
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  } @@ -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; +    } +  } @@ -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 @@ -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 | 
