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
use std::fmt;
use std::borrow::Cow;
use url::Url;
use super::ndef::NDEF;
#[derive(Debug)]
pub struct CardResponse {
pub status: [u8; 2],
pub data: Vec<u8>,
}
pub enum Error {
PCSC(pcsc::Error),
Response([u8; 2]),
Message(&'static str),
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::PCSC(pcsc_error) => write!(f, "{:?}", pcsc_error),
Error::Response(bytes) => write!(f, "{:x?}", bytes),
Error::Message(s) => write!(f, "{}", s),
}
}
}
impl From<pcsc::Error> for Error {
fn from(err: pcsc::Error) -> Error {
Error::PCSC(err)
}
}
impl From<[u8; 2]> for Error {
fn from(err: [u8; 2]) -> Error {
Error::Response(err)
}
}
impl From<&'static str> for Error {
fn from(err: &'static str) -> Error {
Error::Message(err)
}
}
pub struct NFCBadge<'a> {
card: &'a pcsc::Card,
}
impl NFCBadge<'_> {
pub fn new(card: &pcsc::Card) -> NFCBadge {
NFCBadge {
card,
}
}
pub fn get_user_id(&self) -> Result<String, Error> {
const START_PAGE: u8 = 0x04;
const END_PAGE: u8 = 0x27;
let apdu = [0xFF, 0x00, 0x00, 0x00, 0x05, 0xD4, 0x42, 0x3A, START_PAGE, END_PAGE];
let response = self.send_data(&apdu)?;
if &response.data[0..3] != [0xD5, 0x43, 0x00] {
return Err(Error::Message("Invalid PN532 response"));
}
let data = &response.data[3..];
let message = NDEF::parse(data)?;
let url = message.get_content().ok_or("NDEF message not URL")?;
let url = Url::parse(&url).ok().ok_or("Invalid URL")?;
for keyvalue in url.query_pairs() {
match keyvalue.0 {
Cow::Borrowed("user") => return Ok(keyvalue.1.to_string()),
_ => {},
}
}
Err(Error::Message("URL did not contain user ID"))
}
pub fn set_buzzer(&self, enabled: bool) -> Result<bool, Error> {
let value = if enabled { 0xFF } else { 0x00 };
let apdu = [0xFF, 0x00, 0x52, value, 0x00];
self.send_data(&apdu)?;
Ok(enabled)
}
pub(crate) fn send_data(&self, apdu: &[u8]) -> Result<CardResponse, Error> {
let mut rapdu_buf = [0u8; pcsc::MAX_BUFFER_SIZE];
let mut rapdu = self.card.transmit(apdu, &mut rapdu_buf)?.to_vec();
if rapdu.len() < 2 {
return Err(pcsc::Error::InvalidValue.into());
}
let status = [rapdu[rapdu.len() - 2], rapdu[rapdu.len() - 1]];
rapdu.truncate(rapdu.len() - 2);
if status[0] == 0x90 && status[1] == 0x00 {
Ok(CardResponse {
status,
data: rapdu,
})
}
else {
Err(status.into())
}
}
}