• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

canokeys / canokey-core / 6641952240

25 Oct 2023 02:32PM UTC coverage: 79.064% (+0.2%) from 78.862%
6641952240

push

github

web-flow
Merge pull request #60 from canokeys/feature/fido2.1

Feature/fido2.1

55 of 55 new or added lines in 6 files covered. (100.0%)

6186 of 7824 relevant lines covered (79.06%)

571.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/src/device.c
1
// SPDX-License-Identifier: Apache-2.0
2
#include "common.h"
3
#include <admin.h>
4
#include <ccid.h>
5
#include <ctaphid.h>
6
#include <device.h>
7
#include <kbdhid.h>
8
#include <webusb.h>
9

10
volatile static uint8_t touch_result;
11
static uint8_t has_rf;
12
static uint32_t last_blink = UINT32_MAX, blink_timeout, blink_interval;
13
static enum { ON, OFF } led_status;
14
typedef enum { WAIT_NONE = 1, WAIT_CCID, WAIT_CTAPHID, WAIT_DEEP, WAIT_DEEP_TOUCHED, WAIT_DEEP_CANCEL } wait_status_t;
15
volatile static wait_status_t wait_status = WAIT_NONE; // WAIT_NONE is not 0, hence inited
16

17
uint8_t device_is_blinking(void) { return last_blink != UINT32_MAX; }
861✔
18

19
void device_loop(uint8_t has_touch) {
20
  CCID_Loop();
×
21
  CTAPHID_Loop(0);
×
22
  WebUSB_Loop();
×
23
  if (has_touch &&                  // hardware features the touch pad
×
24
      !device_is_blinking() &&      // applets are not waiting for touch
×
25
      cfg_is_kbd_interface_enable() // keyboard emulation enabled
×
26
  )
27
    KBDHID_Loop();
×
28
}
×
29

30
uint8_t get_touch_result(void) {
31
#ifdef TEST // emulate user interaction in test mode
32
  testmode_emulate_user_presence();
416✔
33
#endif
34
  return touch_result;
416✔
35
}
36

37
void set_touch_result(uint8_t result) { touch_result = result; }
832✔
38

39
uint8_t wait_for_user_presence(uint8_t entry) {
40
  start_blinking(0);
380✔
41
  uint32_t start = device_get_tick();
380✔
42
  uint32_t last = start;
380✔
43
  DBG_MSG("start %u\n", start);
380✔
44

45
  wait_status_t shallow = wait_status;
380✔
46
  if (wait_status == WAIT_NONE) {
380✔
47
    switch (entry) {
380✔
48
    case WAIT_ENTRY_CCID:
4✔
49
      wait_status = WAIT_CCID;
4✔
50
      break;
4✔
51
    case WAIT_ENTRY_CTAPHID:
376✔
52
      wait_status = WAIT_CTAPHID;
376✔
53
      break;
376✔
54
    }
55
  } else
56
    wait_status = WAIT_DEEP;
×
57
  while (get_touch_result() == TOUCH_NO) {
380✔
58
    if (wait_status == WAIT_DEEP_TOUCHED || wait_status == WAIT_DEEP_CANCEL) break;
×
59
    if (wait_status == WAIT_CTAPHID) CCID_Loop();
×
60
    if (CTAPHID_Loop(wait_status != WAIT_CCID) == LOOP_CANCEL) {
×
61
      DBG_MSG("Cancelled by host\n");
×
62
      if (wait_status != WAIT_DEEP) {
×
63
        stop_blinking();
×
64
        wait_status = WAIT_NONE; // namely shallow
×
65
      } else
66
        wait_status = WAIT_DEEP_CANCEL;
×
67
      return USER_PRESENCE_CANCEL;
×
68
    }
69
    uint32_t now = device_get_tick();
×
70
    if (now - start >= 30000) {
×
71
      DBG_MSG("timeout at %u\n", now);
×
72
      if (wait_status != WAIT_DEEP) stop_blinking();
×
73
      wait_status = shallow;
×
74
      return USER_PRESENCE_TIMEOUT;
×
75
    }
76
    if (now - last >= 100) {
×
77
      last = now;
×
78
      if (wait_status != WAIT_CCID) CTAPHID_SendKeepAlive(KEEPALIVE_STATUS_UPNEEDED);
×
79
    }
80
  }
81
  set_touch_result(TOUCH_NO);
380✔
82
  if (wait_status != WAIT_DEEP) stop_blinking();
380✔
83
  if (wait_status == WAIT_DEEP)
380✔
84
    wait_status = WAIT_DEEP_TOUCHED;
×
85
  else if (wait_status == WAIT_DEEP_CANCEL) {
380✔
86
    wait_status = WAIT_NONE;
×
87
    return USER_PRESENCE_TIMEOUT;
×
88
  } else
89
    wait_status = WAIT_NONE;
380✔
90
  return USER_PRESENCE_OK;
380✔
91
}
92

93
int send_keepalive_during_processing(uint8_t entry) {
94
  if (entry == WAIT_ENTRY_CTAPHID) CTAPHID_SendKeepAlive(KEEPALIVE_STATUS_PROCESSING);
544✔
95
  DBG_MSG("KEEPALIVE\n");
544✔
96
  return 0;
544✔
97
}
98

99
__attribute__((weak)) int strong_user_presence_test(void) {
100
  for (int i = 0; i < 5; i++) {
×
101
    const uint8_t wait_sec = 2;
×
102
    start_blinking_interval(wait_sec, (i & 1) ? 200 : 50);
×
103
    uint32_t now, begin = device_get_tick();
×
104
    bool user_presence = false;
×
105
    do {
106
      if (get_touch_result() == TOUCH_SHORT) {
×
107
        user_presence = true;
×
108
        set_touch_result(TOUCH_NO);
×
109
        stop_blinking();
×
110
        // wait for some time before next user-precense test
111
        begin = device_get_tick();
×
112
      }
113
      now = device_get_tick();
×
114
    } while (now - begin < 1000 * wait_sec);
×
115
    if (!user_presence) {
×
116
      return -1;
×
117
    }
118
  }
119
  return 0;
×
120
}
121

122
void set_nfc_state(uint8_t val) { has_rf = val; }
1,602✔
123

124
uint8_t is_nfc(void) {
125
#ifdef TEST // read NFC emulation config from a file
126
  testmode_get_is_nfc_mode();
1,605✔
127
#endif
128
  return has_rf;
1,605✔
129
}
130

131
static void toggle_led(void) {
445✔
132
  if (led_status == ON) {
445✔
133
    led_off();
443✔
134
    led_status = OFF;
443✔
135
  } else {
136
    led_on();
2✔
137
    led_status = ON;
2✔
138
  }
139
}
445✔
140

141
void device_update_led(void) {
142
  uint32_t now = device_get_tick();
×
143
  if (now > blink_timeout) stop_blinking();
×
144
  if (now >= last_blink && now - last_blink >= blink_interval) {
×
145
    last_blink = now;
×
146
    toggle_led();
×
147
  }
148
}
×
149

150
void start_blinking_interval(uint8_t sec, uint32_t interval) {
151
  if (device_is_blinking()) return;
445✔
152
  last_blink = device_get_tick();
445✔
153
  blink_interval = interval;
445✔
154
  if (sec == 0) {
445✔
155
    blink_timeout = UINT32_MAX;
409✔
156
  } else {
157
    blink_timeout = last_blink + sec * 1000;
36✔
158
  }
159
  toggle_led();
445✔
160
}
161

162
void stop_blinking(void) {
163
  last_blink = UINT32_MAX;
2,042✔
164
  if (cfg_is_led_normally_on()) {
2,042✔
165
    led_on();
2,030✔
166
    led_status = ON;
2,030✔
167
  } else {
168
    led_off();
12✔
169
    led_status = OFF;
12✔
170
  }
171
}
2,042✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc