diff --git a/AfRApay.MateCard/include/Adafruit_PN532.h b/AfRApay.MateCard/include/Adafruit_PN532.h index c777ce0..c6c2eea 100644 --- a/AfRApay.MateCard/include/Adafruit_PN532.h +++ b/AfRApay.MateCard/include/Adafruit_PN532.h @@ -186,6 +186,7 @@ public: uint16_t timeout = 0); // timeout 0 means no timeout - will block forever. bool startPassiveTargetIDDetection(uint8_t cardbaudrate); bool readDetectedPassiveTargetID(uint8_t* uid, uint8_t* uidLength); + bool readDetectedPassiveTargetID(uint8_t* uid, uint8_t* uidLength, uint16_t* atqa, uint8_t* sak); bool readDetectedPassiveTargetIDFeliCa(uint8_t* IDm, uint8_t* IDmLength); bool inDataExchange(uint8_t* send, uint8_t sendLength, uint8_t* response, uint8_t* responseLength); diff --git a/AfRApay.MateCard/src/Adafruit_PN532.cpp b/AfRApay.MateCard/src/Adafruit_PN532.cpp index e54d8cd..dd22bb3 100644 --- a/AfRApay.MateCard/src/Adafruit_PN532.cpp +++ b/AfRApay.MateCard/src/Adafruit_PN532.cpp @@ -631,6 +631,66 @@ bool Adafruit_PN532::startPassiveTargetIDDetection(uint8_t cardbaudrate) { @returns 1 if everything executed properly, 0 for an error */ /**************************************************************************/ +bool Adafruit_PN532::readDetectedPassiveTargetID(uint8_t* uid, + uint8_t* uidLength, + uint16_t* atqa, + uint8_t* sak) { + // read data packet + readdata(pn532_packetbuffer, 20); + // check some basic stuff + + /* ISO14443A card response should be in the following format: + + byte Description + ------------- ------------------------------------------ + b0..6 Frame header and preamble + b7 Tags Found + b8 Tag Number (only one used in this example) + b9..10 SENS_RES + b11 SEL_RES + b12 NFCID Length + b13..NFCIDLen NFCID */ + +#ifdef PN532CARDDEBUG + PN532DEBUGPRINT.print(F("Found ")); + PN532DEBUGPRINT.print(pn532_packetbuffer[7], DEC); + PN532DEBUGPRINT.println(F(" tags")); +#endif + if (pn532_packetbuffer[7] != 1) + return 0; + + uint16_t sens_res = pn532_packetbuffer[9]; + sens_res <<= 8; + sens_res |= pn532_packetbuffer[10]; +#ifdef PN532CARDDEBUG + PN532DEBUGPRINT.print(F("ATQA: 0x")); + PN532DEBUGPRINT.println(sens_res, HEX); + PN532DEBUGPRINT.print(F("SAK: 0x")); + PN532DEBUGPRINT.println(pn532_packetbuffer[11], HEX); +#endif + + *atqa = sens_res; + *sak = pn532_packetbuffer[11]; + + /* Card appears to be Mifare Classic */ + *uidLength = pn532_packetbuffer[12]; +#ifdef PN532CARDDEBUG + PN532DEBUGPRINT.print(F("UID:")); +#endif + for (uint8_t i = 0; i < pn532_packetbuffer[12]; i++) { + uid[i] = pn532_packetbuffer[13 + i]; +#ifdef PN532CARDDEBUG + PN532DEBUGPRINT.print(F(" 0x")); + PN532DEBUGPRINT.print(uid[i], HEX); +#endif + } +#ifdef PN532CARDDEBUG + PN532DEBUGPRINT.println(); +#endif + + return 1; +} + bool Adafruit_PN532::readDetectedPassiveTargetID(uint8_t* uid, uint8_t* uidLength) { // read data packet diff --git a/AfRApay.MateCard/src/readers/pn532.cpp b/AfRApay.MateCard/src/readers/pn532.cpp index 47cbc29..8e0619f 100644 --- a/AfRApay.MateCard/src/readers/pn532.cpp +++ b/AfRApay.MateCard/src/readers/pn532.cpp @@ -65,7 +65,19 @@ bool PN532Reader::isNewCardPresent() { String PN532Reader::getCardUid() { if (mode == PN532_MIFARE_ISO14443A) { Serial.println("Reading NFC-A UID"); - pn532->readDetectedPassiveTargetID(uid, &uidLength); + + uint16_t atqa; + uint8_t sak; + + pn532->readDetectedPassiveTargetID(uid, &uidLength, &atqa, &sak); + if (uidLength == 4) { + if (atqa == 0x2 && sak == 0x18) { + Serial.println("4 byte uid with ATQA 0x2 and SAK 0x18, assuming ov-chipkaart"); + uidLength = 6; + uid[4] = 0x02; + uid[5] = 0x18; + } + } } else { Serial.println("Reading FeliCa IDm"); diff --git a/AfRApay.Web/Backend/Database/Tables/Card.cs b/AfRApay.Web/Backend/Database/Tables/Card.cs index 5e6f54c..81d7f2b 100644 --- a/AfRApay.Web/Backend/Database/Tables/Card.cs +++ b/AfRApay.Web/Backend/Database/Tables/Card.cs @@ -17,8 +17,10 @@ public class Card { NfcTflOyster = 22, NfcOvChipkaart = 23, NfcItso = 24, - FeliCaGeneric = 30, - FeliCaSuica = 31, - FeliCaPasmo = 32, + NfcContactless = 25, + FeliCaGeneric = 30, + FeliCaSuica = 31, + FeliCaPasmo = 32, + FeliCaApplePay = 33, } } diff --git a/AfRApay.Web/Controllers/CardController.cs b/AfRApay.Web/Controllers/CardController.cs index 7579e22..a369dd2 100644 --- a/AfRApay.Web/Controllers/CardController.cs +++ b/AfRApay.Web/Controllers/CardController.cs @@ -121,7 +121,7 @@ public class CardController : Controller { var db = new DatabaseContext(); if (db.Cards.Any(p => p.Id == card)) { var user = db.Cards.Include(p => p.User).First(p => p.Id == card).User; - + var dbCard = db.Cards.First(p => p.Id == card); var newType = GetCardType(reader, card); @@ -152,14 +152,18 @@ public class CardController : Controller { public ErrorResponse GetExamples() => new("No active link process"); } - private Card.CardType GetCardType(string? reader, string cardNumber) { - //TODO match more specific type based on card number format - - return reader switch { - "rdm6300" => Card.CardType.Rfid125KhzGeneric, - "pn532-iso14443a" => Card.CardType.NfcGeneric, - "pn532-felica" => Card.CardType.FeliCaGeneric, - _ => Card.CardType.Unknown - }; - } + private Card.CardType GetCardType(string? reader, string cardNumber) => reader switch { + "rdm6300" => Card.CardType.Rfid125KhzGeneric, + "pn532-iso14443a" when cardNumber.Length == 8 => Card.CardType.NfcMifareClassic, + "pn532-iso14443a" when cardNumber.Length == 12 && cardNumber.EndsWith("0218") => Card.CardType.NfcOvChipkaart, + "pn532-iso14443a" when cardNumber.Length == 14 && cardNumber.EndsWith("5e80") => Card.CardType.NfcTflOyster, + "pn532-iso14443a" when cardNumber.Length == 14 && cardNumber.StartsWith("04") && cardNumber.EndsWith("80") => Card.CardType.NfcItso, + "pn532-iso14443a" => Card.CardType.NfcGeneric, + "pn532-felica" when cardNumber.Length == 16 && cardNumber.StartsWith("0112") => Card.CardType.FeliCaSuica, + "pn532-felica" when cardNumber.Length == 16 && cardNumber.StartsWith("0101") => Card.CardType.FeliCaPasmo, + "pn532-felica" when cardNumber.Length == 16 && cardNumber.StartsWith("0139") => Card.CardType.FeliCaApplePay, + "pn532-felica" => Card.CardType.FeliCaGeneric, + _ => Card.CardType.Unknown + //"pn532-iso14443a" when [???] => Card.CardType.NfcContactless, + }; } diff --git a/AfRApay.Web/Pages/EditUser.cshtml b/AfRApay.Web/Pages/EditUser.cshtml index e70fa9a..5666f88 100644 --- a/AfRApay.Web/Pages/EditUser.cshtml +++ b/AfRApay.Web/Pages/EditUser.cshtml @@ -42,9 +42,9 @@
- - -
+ + + @@ -108,12 +108,13 @@ - @if(cardNumber.Length < 12) { + @if (cardNumber.Length < 12) { if (cardType == Card.CardType.Rfid125KhzGeneric) { -

0000000@cardNumber[^3..]

+

+ 0000000@cardNumber[^3..] +

} - else - { + else {

@cardNumber

} } @@ -126,10 +127,69 @@ @expDate -
- -
-
+ @switch (cardType) { + case Card.CardType.Rfid125KhzGeneric: +
+ +
+ break; + case Card.CardType.NfcGeneric: +
+ +
+ break; + case Card.CardType.FeliCaGeneric: +
+ +
+ break; + case Card.CardType.NfcMifareClassic: +
+ +
+ break; + case Card.CardType.NfcTflOyster: +
+ +
+ break; + case Card.CardType.NfcOvChipkaart: +
+ +
+ break; + case Card.CardType.NfcItso: +
+ +
+ break; + case Card.CardType.NfcContactless: +
+ +
+ break; + case Card.CardType.FeliCaSuica: +
+ +
+ break; + case Card.CardType.FeliCaPasmo: +
+ +
+ break; + case Card.CardType.FeliCaApplePay: +
+ + +
+ break; + case Card.CardType.Unknown: + break; + default: + throw new ArgumentOutOfRangeException(nameof(cardType), cardType, null); + } +
@@ -168,6 +228,7 @@ await RenderCard(user.Nickname, card.Id, cardType: card.Type); await RenderCardModal(user.Nickname, card.Id, cardType: card.Type); } + await RenderCard(user.Nickname, displayType: EditUserModel.CardDisplayType.LinkPlaceholder); } diff --git a/AfRApay.Web/wwwroot/css/site.css b/AfRApay.Web/wwwroot/css/site.css index 61fa075..2923f52 100644 --- a/AfRApay.Web/wwwroot/css/site.css +++ b/AfRApay.Web/wwwroot/css/site.css @@ -224,7 +224,7 @@ button.accept-policy { line-height: 9px; margin-right: 5px; } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom-matecard { position: absolute; bottom: 33px; right: 20px; @@ -234,30 +234,253 @@ button.accept-policy { align-items: center; justify-content: center; } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom-matecard img { + width: 55px; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom-matecard img.fake-card-logo-inner { + margin-top: 18px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-rfid { position: absolute; top: 25px; right: 20px; width: 70px; height: 65px; border-radius: 10px; - background-color: white; display: flex; align-items: center; - justify-content: center; overflow: hidden; + justify-content: center; + overflow: hidden; } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top img { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-rfid img { width: 55px; + filter: invert(100%); } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top img.fake-card-logo-inner { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-rfid img.fake-card-logo-inner { margin-top: 1px; margin-bottom: 2px; } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom img { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-ovc { + position: absolute; + top: 25px; + right: 20px; + width: 70px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-ovc img { + width: 55px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-ovc img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-mifare { + position: absolute; + top: 25px; + right: 20px; + width: 100px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-mifare img { + width: 100px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-mifare img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-itso { + position: absolute; + top: 25px; + right: 20px; + width: 70px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-itso img { + width: 55px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-itso img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-pasmo { + position: absolute; + top: 25px; + right: 20px; + width: 90px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-pasmo img { + width: 75px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-pasmo img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-contactless { + position: absolute; + top: 25px; + right: 20px; + width: 60px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-contactless img { + width: 25px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-contactless img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-suica { + position: absolute; + top: 25px; + right: 20px; + width: 120px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-suica img { + width: 110px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-suica img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-oyster { + position: absolute; + top: 25px; + right: 20px; + width: 120px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-oyster img { + width: 120px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-oyster img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-felica { + position: absolute; + top: 25px; + right: 20px; + width: 70px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-felica img { + width: 55px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-felica img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-apay { + position: absolute; + top: 25px; + right: 20px; + width: 130px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-apay img:nth-of-type(1) { + width: 55px; + margin-right: 15px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-apay img:nth-of-type(2) { + width: 50px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-apay img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-nfc { + position: absolute; + top: 25px; + right: 20px; + width: 70px; + height: 65px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-nfc img { + width: 55px; + filter: invert(100%); +} +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-top-nfc img.fake-card-logo-inner { + margin-top: 1px; + margin-bottom: 2px; +} + +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom-matecard img { width: 55px; } -.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom img.fake-card-logo-inner { +.fake-card-wrapper .fake-card .face-card.front .fake-card-logo-bottom-matecard img.fake-card-logo-inner { margin-top: 18px; } diff --git a/AfRApay.Web/wwwroot/img/apay.svg b/AfRApay.Web/wwwroot/img/apay.svg new file mode 100644 index 0000000..d0fb0c7 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/apay.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/AfRApay.Web/wwwroot/img/contactless.svg b/AfRApay.Web/wwwroot/img/contactless.svg new file mode 100644 index 0000000..fa42cf4 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/contactless.svg @@ -0,0 +1,7 @@ + + +ContactlessIndicator 000 + + \ No newline at end of file diff --git a/AfRApay.Web/wwwroot/img/felica.png b/AfRApay.Web/wwwroot/img/felica.png new file mode 100644 index 0000000..fc48ff1 Binary files /dev/null and b/AfRApay.Web/wwwroot/img/felica.png differ diff --git a/AfRApay.Web/wwwroot/img/itso.svg b/AfRApay.Web/wwwroot/img/itso.svg new file mode 100644 index 0000000..2755337 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/itso.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + diff --git a/AfRApay.Web/wwwroot/img/mifare.svg b/AfRApay.Web/wwwroot/img/mifare.svg new file mode 100644 index 0000000..95db33c --- /dev/null +++ b/AfRApay.Web/wwwroot/img/mifare.svg @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AfRApay.Web/wwwroot/img/nfc.png b/AfRApay.Web/wwwroot/img/nfc.png new file mode 100644 index 0000000..33a9ddf Binary files /dev/null and b/AfRApay.Web/wwwroot/img/nfc.png differ diff --git a/AfRApay.Web/wwwroot/img/ovc.png b/AfRApay.Web/wwwroot/img/ovc.png new file mode 100644 index 0000000..fe64100 Binary files /dev/null and b/AfRApay.Web/wwwroot/img/ovc.png differ diff --git a/AfRApay.Web/wwwroot/img/ovc.svg b/AfRApay.Web/wwwroot/img/ovc.svg new file mode 100644 index 0000000..25eec6f --- /dev/null +++ b/AfRApay.Web/wwwroot/img/ovc.svg @@ -0,0 +1,46 @@ + + + + diff --git a/AfRApay.Web/wwwroot/img/oyster.svg b/AfRApay.Web/wwwroot/img/oyster.svg new file mode 100644 index 0000000..7075703 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/oyster.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + diff --git a/AfRApay.Web/wwwroot/img/pasmo.svg b/AfRApay.Web/wwwroot/img/pasmo.svg new file mode 100644 index 0000000..6a22aa6 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/pasmo.svg @@ -0,0 +1,43 @@ + + + + diff --git a/AfRApay.Web/wwwroot/img/rfid.png b/AfRApay.Web/wwwroot/img/rfid.png new file mode 100644 index 0000000..d9f8b29 Binary files /dev/null and b/AfRApay.Web/wwwroot/img/rfid.png differ diff --git a/AfRApay.Web/wwwroot/img/suica.svg b/AfRApay.Web/wwwroot/img/suica.svg new file mode 100644 index 0000000..9af18d3 --- /dev/null +++ b/AfRApay.Web/wwwroot/img/suica.svg @@ -0,0 +1,68 @@ + + + + + + + image/svg+xml + + + + + + + + + + +