From 32ba9027841bf011c5084abdd1bbb97cfa3bd1d6 Mon Sep 17 00:00:00 2001 From: embr Date: Wed, 8 Feb 2023 15:03:16 +0100 Subject: [PATCH] AfRApay.FTM: We can link cards :D --- AfRApay.FTM/Program.cs | 48 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/AfRApay.FTM/Program.cs b/AfRApay.FTM/Program.cs index c3b3d43..df9fa32 100644 --- a/AfRApay.FTM/Program.cs +++ b/AfRApay.FTM/Program.cs @@ -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("--list-readers", "List card readers and exit"); rootCommand.Add(listReadersOption); -rootCommand.SetHandler((listReaders) => { +var webAddrOption = new Option("--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 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,