1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! A wrapper around the asynchronous NBGL [nbgl_useCaseKeypad](https://github.com/LedgerHQ/ledger-secure-sdk/blob/master/lib_nbgl/src/nbgl_use_case.c#L4565) C API binding.
//!
//! Draws a keypad for user input, allowing for PIN entry and other numeric input.
use super::*;
/// A builder to create and show a keypad for user input.
pub struct NbglKeypad {
title: CString,
min_digits: u8,
max_digits: u8,
shuffled: bool,
hide: bool,
}
impl SyncNBGL for NbglKeypad {}
static mut PIN_BUFFER: [u8; 16] = [0x00; 16];
unsafe extern "C" fn pin_callback(pin: *const u8, pin_len: u8) {
for i in 0..pin_len {
PIN_BUFFER[i as usize] = *pin.add(i.into());
}
G_ENDED = true;
}
unsafe extern "C" fn action_callback() {
G_RET = SyncNbgl::UxSyncRetPinRejected.into();
G_ENDED = true;
}
impl NbglKeypad {
/// Creates a new keypad builder with default settings.
/// By default, the title is "Enter PIN", minimum and maximum digits are set to 4,
/// the keypad is shuffled, and input is hidden.
/// # Returns
/// Returns a new instance of `NbglKeypad`.
pub fn new() -> NbglKeypad {
NbglKeypad {
title: CString::new("Enter PIN").unwrap(),
min_digits: 4,
max_digits: 4,
shuffled: true,
hide: true,
}
}
/// Sets the title to display at the top of the keypad.
/// # Arguments
/// * `title` - The title to display at the top of the keypad.
/// # Returns
/// Returns the builder itself to allow method chaining.
pub fn title(self, title: &str) -> NbglKeypad {
NbglKeypad {
title: CString::new(title).unwrap(),
..self
}
}
/// Sets the minimum number of digits required for input.
/// # Arguments
/// * `min` - The minimum number of digits required for input.
/// # Returns
/// Returns the builder itself to allow method chaining.
pub fn min_digits(self, min: u8) -> NbglKeypad {
NbglKeypad {
min_digits: min,
..self
}
}
/// Sets the maximum number of digits allowed for input.
/// # Arguments
/// * `max` - The maximum number of digits allowed for input.
/// # Returns
/// Returns the builder itself to allow method chaining.
pub fn max_digits(self, max: u8) -> NbglKeypad {
NbglKeypad {
max_digits: max,
..self
}
}
/// Sets whether the keypad should be shuffled.
/// # Arguments
/// * `shuffle` - If `true`, the keypad will be shuffled; otherwise, it will be in a fixed order.
/// # Returns
/// Returns the builder itself to allow method chaining.
pub fn shuffled(self, shuffle: bool) -> NbglKeypad {
NbglKeypad {
shuffled: shuffle,
..self
}
}
/// Sets whether the input should be hidden (e.g., for PIN entry).
/// # Arguments
/// * `hide` - If `true`, the input will be hidden; otherwise, it will be visible.
/// # Returns
/// Returns the builder itself to allow method chaining.
pub fn hide(self, hide: bool) -> NbglKeypad {
NbglKeypad { hide, ..self }
}
/// Shows the keypad and waits for user input.
/// # Arguments
/// * `pin` - A slice containing the expected PIN for validation.
/// # Returns
/// Returns `SyncNbgl::UxSyncRetPinValidated` if the entered PIN matches the expected PIN,
/// otherwise returns `SyncNbgl::UxSyncRetPinRejected`.
pub fn ask(self, pin: &[u8]) -> SyncNbgl {
unsafe {
self.ux_sync_init();
nbgl_useCaseKeypad(
self.title.as_ptr() as *const c_char,
self.min_digits,
self.max_digits,
self.shuffled,
self.hide,
Some(pin_callback),
Some(action_callback),
);
self.ux_sync_wait(false);
// Compare with set pin code
if pin == &PIN_BUFFER[..pin.len()] {
return SyncNbgl::UxSyncRetPinValidated;
} else {
return SyncNbgl::UxSyncRetPinRejected;
}
}
}
}