AfRApay.FTM: We can link cards :D
This commit is contained in:
parent
e73725cdbf
commit
450af83856
|
@ -2,13 +2,18 @@
|
|||
using PCSC;
|
||||
using PCSC.Monitoring;
|
||||
using PCSC.Iso7816;
|
||||
using System.Net.Http;
|
||||
|
||||
var rootCommand = new RootCommand("Fancy Test Machine for AfRApay");
|
||||
|
||||
var listReadersOption = new Option<bool>("--list-readers", "List card readers and exit");
|
||||
rootCommand.Add(listReadersOption);
|
||||
|
||||
rootCommand.SetHandler((listReaders) => {
|
||||
var webAddrOption = new Option<Uri>("--web-addr", "Base URL for AfRApay.Web");
|
||||
webAddrOption.SetDefaultValue(new Uri("http://127.0.0.1:5296"));
|
||||
rootCommand.Add(webAddrOption);
|
||||
|
||||
rootCommand.SetHandler((listReaders, webAddr) => {
|
||||
using (var context = ContextFactory.Instance.Establish(SCardScope.System)) {
|
||||
// We need at least one card reader or this won't work!
|
||||
var readerNames = context.GetReaders();
|
||||
|
@ -27,16 +32,22 @@ rootCommand.SetHandler((listReaders) => {
|
|||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
using HttpClient httpClient = new();
|
||||
httpClient.BaseAddress = webAddr;
|
||||
|
||||
Console.Error.WriteLine("----------------------------------------");
|
||||
Console.Error.WriteLine("--- AfRApay FTM - Fancy Test Machine ---");
|
||||
Console.Error.WriteLine("----------------------------------------");
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("AfRApay.Web: {0}", httpClient.BaseAddress);
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("Hotkeys (case insensitive):");
|
||||
Console.Error.WriteLine(" [L] Link Card, instead of debiting it");
|
||||
Console.Error.WriteLine(" [Esc] Cancel, return to default state");
|
||||
Console.Error.WriteLine();
|
||||
Console.Error.WriteLine("----------------------------------------");
|
||||
|
||||
|
||||
// Listen for events on all connected readers.
|
||||
using (var monitor = MonitorFactory.Instance.Create(SCardScope.System)) {
|
||||
var state = TerminalState.Default;
|
||||
|
@ -50,7 +61,7 @@ rootCommand.SetHandler((listReaders) => {
|
|||
monitor.CardInserted += (_, args) => {
|
||||
Console.WriteLine("> TAP: {0}", Convert.ToHexString(args.Atr));
|
||||
var reader = new IsoReader(context, args.ReaderName, SCardShareMode.Shared, SCardProtocol.Any);
|
||||
HandleTap(reader, state);
|
||||
HandleTap(reader, httpClient, state);
|
||||
};
|
||||
monitor.CardRemoved += (_, args) => {
|
||||
Console.WriteLine("< OFF");
|
||||
|
@ -68,7 +79,7 @@ rootCommand.SetHandler((listReaders) => {
|
|||
break;
|
||||
case ConsoleKey.Escape:
|
||||
state = TerminalState.Default;
|
||||
Console.Error.WriteLine("\\ => Mode: Default"); // Hack: the \\ eats the escape character.
|
||||
Console.Error.WriteLine("\b => Mode: Default"); // Hack: the \b eats the escape character.
|
||||
break;
|
||||
default:
|
||||
Console.Error.WriteLine(" => UNRECOGNISED KEY");
|
||||
|
@ -77,25 +88,37 @@ rootCommand.SetHandler((listReaders) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, listReadersOption);
|
||||
}, listReadersOption, webAddrOption);
|
||||
|
||||
return await rootCommand.InvokeAsync(args);
|
||||
|
||||
// Queries a card for data when one is tapped.
|
||||
static void HandleTap(IsoReader reader, TerminalState state) {
|
||||
static async void HandleTap(IsoReader reader, HttpClient httpClient, TerminalState state) {
|
||||
// Send a PCSC pseudo-APDU to query the ISO 14443 UID.
|
||||
var rsp = reader.Transmit(new CommandApdu(IsoCase.Case2Short, SCardProtocol.Any) {
|
||||
var uidRsp = reader.Transmit(new CommandApdu(IsoCase.Case2Short, SCardProtocol.Any) {
|
||||
CLA = 0xFF,
|
||||
Instruction = InstructionCode.GetData,
|
||||
P1 = 0x00,
|
||||
P2 = 0x00,
|
||||
});
|
||||
if (!IsSucc(rsp)) {
|
||||
Console.Error.WriteLine("--> Card Error: SW1={0} SW2={1}", (SW1Code)rsp.SW1, rsp.SW2);
|
||||
if (!IsSucc(uidRsp)) {
|
||||
Console.Error.WriteLine("--> Card Error: SW1={0} SW2={1}", (SW1Code)uidRsp.SW1, uidRsp.SW2);
|
||||
return;
|
||||
}
|
||||
var uid = rsp.GetData();
|
||||
var uid = uidRsp.GetData();
|
||||
Console.WriteLine(" UID: {0}", Convert.ToHexString(uid));
|
||||
|
||||
// Query the backend, which endpoint depending on terminal state.
|
||||
switch (state) {
|
||||
case TerminalState.Default:
|
||||
break;
|
||||
case TerminalState.Link:
|
||||
await CallGet(httpClient, String.Format("/api/card/link?card={0}", Convert.ToHexString(uid)));
|
||||
break;
|
||||
default:
|
||||
Console.Error.WriteLine("UNKNOWN TERMINAL STATE: {0}", state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Was the command successful?
|
||||
|
@ -103,6 +126,13 @@ static bool IsSucc(Response rsp) {
|
|||
return rsp.SW1 == (byte)SW1Code.Normal && rsp.SW2 == 0x00;
|
||||
}
|
||||
|
||||
static async Task<string> CallGet(HttpClient client, string path) {
|
||||
Console.WriteLine(" -> GET {0}", path);
|
||||
var rsp = await client.GetStringAsync(path);
|
||||
Console.WriteLine(" <- {0}", rsp);
|
||||
return rsp;
|
||||
}
|
||||
|
||||
// Terminal State.
|
||||
enum TerminalState {
|
||||
Default,
|
||||
|
|
Loading…
Reference in a new issue