From db887e63d708925ad759e3504a6bc9ceef4aeb8f Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sat, 14 May 2022 15:07:08 -0700 Subject: Enhancement and fixes of "Secure" feature (#16958) --- tests/secure/test_secure.cpp | 278 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 tests/secure/test_secure.cpp (limited to 'tests/secure/test_secure.cpp') diff --git a/tests/secure/test_secure.cpp b/tests/secure/test_secure.cpp new file mode 100644 index 0000000000..87055ebb7f --- /dev/null +++ b/tests/secure/test_secure.cpp @@ -0,0 +1,278 @@ +/* Copyright 2021 Stefan Kerkmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gtest/gtest.h" +#include "keyboard_report_util.hpp" +#include "test_common.hpp" + +using testing::_; +using testing::AnyNumber; +using testing::InSequence; + +class Secure : public TestFixture { + public: + void SetUp() override { + secure_lock(); + } + // Convenience function to tap `key`. + void TapKey(KeymapKey key) { + key.press(); + run_one_scan_loop(); + key.release(); + run_one_scan_loop(); + } + + // Taps in order each key in `keys`. + template + void TapKeys(Ts... keys) { + for (KeymapKey key : {keys...}) { + TapKey(key); + } + } +}; + +TEST_F(Secure, test_lock) { + TestDriver driver; + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + + EXPECT_FALSE(secure_is_unlocked()); + secure_unlock(); + EXPECT_TRUE(secure_is_unlocked()); + run_one_scan_loop(); + EXPECT_TRUE(secure_is_unlocked()); + secure_lock(); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_timeout) { + TestDriver driver; + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + + EXPECT_FALSE(secure_is_unlocked()); + secure_unlock(); + EXPECT_TRUE(secure_is_unlocked()); + idle_for(SECURE_IDLE_TIMEOUT+1); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request) { + TestDriver driver; + auto key_mo = KeymapKey(0, 0, 0, MO(1)); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_mo, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + + EXPECT_TRUE(secure_is_locked()); + secure_request_unlock(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_b, key_c, key_d); + EXPECT_TRUE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_fail) { + TestDriver driver; + auto key_e = KeymapKey(0, 0, 0, KC_E); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_e, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber()); + { // Expect the following reports in this order. + InSequence s; + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_A))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_D))); + } + EXPECT_TRUE(secure_is_locked()); + secure_request_unlock(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_e, key_a, key_b, key_c, key_d); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_timeout) { + TestDriver driver; + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + + EXPECT_FALSE(secure_is_unlocked()); + secure_request_unlock(); + EXPECT_TRUE(secure_is_unlocking()); + idle_for(SECURE_UNLOCK_TIMEOUT+1); + EXPECT_FALSE(secure_is_unlocking()); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + + +TEST_F(Secure, test_unlock_request_fail_mid) { + TestDriver driver; + auto key_e = KeymapKey(0, 0, 0, KC_E); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_e, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber()); + { // Expect the following reports in this order. + InSequence s; + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_D))); + } + EXPECT_FALSE(secure_is_unlocked()); + secure_request_unlock(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_b, key_e, key_c, key_d); + EXPECT_FALSE(secure_is_unlocking()); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_fail_out_of_order) { + TestDriver driver; + auto key_e = KeymapKey(0, 0, 0, KC_E); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_e, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(AnyNumber()); + { // Expect the following reports in this order. + InSequence s; + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_B))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_C))); + } + EXPECT_FALSE(secure_is_unlocked()); + secure_request_unlock(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_d, key_b, key_c); + EXPECT_TRUE(secure_is_locked()); + EXPECT_FALSE(secure_is_unlocking()); + EXPECT_FALSE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_on_layer) { + TestDriver driver; + auto key_mo = KeymapKey(0, 0, 0, MO(1)); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_mo, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())).Times(0); + + EXPECT_TRUE(secure_is_locked()); + key_mo.press(); + run_one_scan_loop(); + secure_request_unlock(); + key_mo.release(); + run_one_scan_loop(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_b, key_c, key_d); + EXPECT_TRUE(secure_is_unlocked()); + EXPECT_FALSE(layer_state_is(1)); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_mid_stroke) { + TestDriver driver; + auto key_e = KeymapKey(0, 0, 0, KC_E); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_e, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_E))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())); + EXPECT_TRUE(secure_is_locked()); + key_e.press(); + run_one_scan_loop(); + secure_request_unlock(); + key_e.release(); + run_one_scan_loop(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_b, key_c, key_d); + EXPECT_TRUE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} + +TEST_F(Secure, test_unlock_request_mods) { + TestDriver driver; + auto key_lsft = KeymapKey(0, 0, 0, KC_LSFT); + auto key_a = KeymapKey(0, 1, 0, KC_A); + auto key_b = KeymapKey(0, 2, 0, KC_B); + auto key_c = KeymapKey(0, 3, 0, KC_C); + auto key_d = KeymapKey(0, 4, 0, KC_D); + + set_keymap({key_lsft, key_a, key_b, key_c, key_d}); + + // Allow any number of empty reports. + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(key_lsft.report_code))); + EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport())); + EXPECT_TRUE(secure_is_locked()); + key_lsft.press(); + run_one_scan_loop(); + secure_request_unlock(); + key_lsft.release(); + run_one_scan_loop(); + EXPECT_TRUE(secure_is_unlocking()); + TapKeys(key_a, key_b, key_c, key_d); + EXPECT_TRUE(secure_is_unlocked()); + + testing::Mock::VerifyAndClearExpectations(&driver); +} -- cgit v1.2.3