1use std::fmt;
2use std::borrow::Cow;
3use url::Url;
4use super::ndef::NDEF;
5
6#[derive(Debug)]
7pub struct CardResponse {
8 pub status: [u8; 2],
9 pub data: Vec<u8>,
10}
11
12pub enum Error {
14 PCSC(pcsc::Error),
15 Response([u8; 2]),
16 Message(&'static str),
17}
18impl fmt::Debug for Error {
19 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20 match *self {
21 Error::PCSC(pcsc_error) => write!(f, "{:?}", pcsc_error),
22 Error::Response(bytes) => write!(f, "{:x?}", bytes),
23 Error::Message(s) => write!(f, "{}", s),
24 }
25 }
26}
27impl From<pcsc::Error> for Error {
28 fn from(err: pcsc::Error) -> Error {
29 Error::PCSC(err)
30 }
31}
32impl From<[u8; 2]> for Error {
33 fn from(err: [u8; 2]) -> Error {
34 Error::Response(err)
35 }
36}
37impl From<&'static str> for Error {
38 fn from(err: &'static str) -> Error {
39 Error::Message(err)
40 }
41}
42
43pub struct NFCBadge<'a> {
44 card: &'a pcsc::Card,
45}
46
47impl NFCBadge<'_> {
48 pub fn new(card: &pcsc::Card) -> NFCBadge {
49 NFCBadge {
50 card,
51 }
52 }
53
54 pub fn get_user_id(&self) -> Result<String, Error> {
55 const START_PAGE: u8 = 0x04; const END_PAGE: u8 = 0x27; let apdu = [0xFF, 0x00, 0x00, 0x00, 0x05, 0xD4, 0x42, 0x3A, START_PAGE, END_PAGE];
81 let response = self.send_data(&apdu)?;
82
83 if &response.data[0..3] != [0xD5, 0x43, 0x00] {
84 return Err(Error::Message("Invalid PN532 response"));
85 }
86 let data = &response.data[3..];
87 let message = NDEF::parse(data)?;
88 let url = message.get_content().ok_or("NDEF message not URL")?;
89 let url = Url::parse(&url).ok().ok_or("Invalid URL")?;
90
91 for keyvalue in url.query_pairs() {
92 match keyvalue.0 {
93 Cow::Borrowed("user") => return Ok(keyvalue.1.to_string()),
94 _ => {},
95 }
96 }
97 Err(Error::Message("URL did not contain user ID"))
98 }
99
100 pub fn set_buzzer(&self, enabled: bool) -> Result<bool, Error> {
101 let value = if enabled { 0xFF } else { 0x00 };
102 let apdu = [0xFF, 0x00, 0x52, value, 0x00];
103 self.send_data(&apdu)?;
104 Ok(enabled)
105 }
106
107 pub(crate) fn send_data(&self, apdu: &[u8]) -> Result<CardResponse, Error> {
108 let mut rapdu_buf = [0u8; pcsc::MAX_BUFFER_SIZE];
109 let mut rapdu = self.card.transmit(apdu, &mut rapdu_buf)?.to_vec();
110
111 if rapdu.len() < 2 {
112 return Err(pcsc::Error::InvalidValue.into());
113 }
114
115 let status = [rapdu[rapdu.len() - 2], rapdu[rapdu.len() - 1]];
116 rapdu.truncate(rapdu.len() - 2);
117 if status[0] == 0x90 && status[1] == 0x00 {
119 Ok(CardResponse {
120 status,
121 data: rapdu,
122 })
123 }
124 else {
125 Err(status.into())
126 }
127 }
128}