From 740a18dbc04aa3d611fafc85917f63909a3f6477 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 24 May 2018 11:41:57 -0400 Subject: [PATCH] stub out yubico nfc support for ios --- src/Android/MainActivity.cs | 6 ++- src/Android/Resources/Resource.Designer.cs | 33 ++++++++++--- src/Android/Services/DeviceInfoService.cs | 13 +++++- src/Android/Utilities.cs | 8 ---- src/iOS.Core/Services/DeviceInfoService.cs | 2 +- src/iOS/AppDelegate.cs | 23 +++++++++ src/iOS/NFCReaderDelegate.cs | 54 ++++++++++++++++++++++ src/iOS/iOS.csproj | 1 + 8 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 src/iOS/NFCReaderDelegate.cs diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs index bd2beaa4f..a5f87f2bb 100644 --- a/src/Android/MainActivity.cs +++ b/src/Android/MainActivity.cs @@ -27,6 +27,7 @@ namespace Bit.Android private const string HockeyAppId = "d3834185b4a643479047b86c65293d42"; private Java.Util.Regex.Pattern _otpPattern = Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$"); private IDeviceActionService _deviceActionService; + private IDeviceInfoService _deviceInfoService; private ISettings _settings; private AppOptions _appOptions; @@ -69,6 +70,7 @@ namespace Bit.Android .SetValue(null, Color.FromHex("d2d6de")); _deviceActionService = Resolver.Resolve(); + _deviceInfoService = Resolver.Resolve(); _settings = Resolver.Resolve(); _appOptions = GetOptions(); LoadApplication(new App.App( @@ -134,7 +136,7 @@ namespace Bit.Android // ref https://bugzilla.xamarin.com/show_bug.cgi?id=36907 Task.Delay(10).Wait(); - if(Utilities.NfcEnabled()) + if(_deviceInfoService.NfcEnabled) { try { @@ -206,7 +208,7 @@ namespace Bit.Android private void ListenYubiKey(bool listen) { - if(!Utilities.NfcEnabled()) + if(!_deviceInfoService.NfcEnabled) { return; } diff --git a/src/Android/Resources/Resource.Designer.cs b/src/Android/Resources/Resource.Designer.cs index 0b96097c2..81cb43c92 100644 --- a/src/Android/Resources/Resource.Designer.cs +++ b/src/Android/Resources/Resource.Designer.cs @@ -6506,17 +6506,17 @@ namespace Bit.Android // aapt resource value: 0x7f0a0051 public const int ApplicationName = 2131361873; - // aapt resource value: 0x7f0a00ab - public const int AutoFillServiceDescription = 2131361963; + // aapt resource value: 0x7f0a00b2 + public const int AutoFillServiceDescription = 2131361970; - // aapt resource value: 0x7f0a00aa - public const int AutoFillServiceSummary = 2131361962; + // aapt resource value: 0x7f0a00b1 + public const int AutoFillServiceSummary = 2131361969; // aapt resource value: 0x7f0a0050 public const int Hello = 2131361872; - // aapt resource value: 0x7f0a00ac - public const int MyVault = 2131361964; + // aapt resource value: 0x7f0a00b3 + public const int MyVault = 2131361971; // aapt resource value: 0x7f0a0027 public const int abc_action_bar_home_description = 2131361831; @@ -6671,6 +6671,27 @@ namespace Bit.Android // aapt resource value: 0x7f0a000f public const int common_signin_button_text_long = 2131361807; + // aapt resource value: 0x7f0a00ac + public const int default_web_client_id = 2131361964; + + // aapt resource value: 0x7f0a00ad + public const int firebase_database_url = 2131361965; + + // aapt resource value: 0x7f0a00aa + public const int gcm_defaultSenderId = 2131361962; + + // aapt resource value: 0x7f0a00ae + public const int google_api_key = 2131361966; + + // aapt resource value: 0x7f0a00ab + public const int google_app_id = 2131361963; + + // aapt resource value: 0x7f0a00af + public const int google_crash_reporting_api_key = 2131361967; + + // aapt resource value: 0x7f0a00b0 + public const int google_storage_bucket = 2131361968; + // aapt resource value: 0x7f0a0052 public const int hockeyapp_crash_dialog_app_name_fallback = 2131361874; diff --git a/src/Android/Services/DeviceInfoService.cs b/src/Android/Services/DeviceInfoService.cs index 12fef2085..3f56fb4a5 100644 --- a/src/Android/Services/DeviceInfoService.cs +++ b/src/Android/Services/DeviceInfoService.cs @@ -1,5 +1,7 @@ using Android.App; +using Android.Content; using Android.Content.PM; +using Android.Nfc; using Android.OS; using Android.Views.Autofill; using Bit.App.Abstractions; @@ -45,7 +47,7 @@ namespace Bit.Android.Services return 1f; } } - public bool NfcEnabled => Utilities.NfcEnabled(); + public bool NfcEnabled => NfcIsEnabled(); public bool HasCamera => CrossCurrentActivity.Current.Activity.PackageManager.HasSystemFeature( PackageManager.FeatureCamera); public bool AutofillServiceSupported => AutofillSupported(); @@ -56,10 +58,17 @@ namespace Bit.Android.Services { return false; } - + var afm = (AutofillManager)CrossCurrentActivity.Current.Activity.GetSystemService( Java.Lang.Class.FromType(typeof(AutofillManager))); return afm.IsAutofillSupported; } + public bool NfcIsEnabled() + { + var activity = CrossCurrentActivity.Current.Activity; + var manager = (NfcManager)activity.GetSystemService(Context.NfcService); + var adapter = manager.DefaultAdapter; + return adapter != null && adapter.IsEnabled; + } } } diff --git a/src/Android/Utilities.cs b/src/Android/Utilities.cs index 955561ca5..6e2fedb08 100644 --- a/src/Android/Utilities.cs +++ b/src/Android/Utilities.cs @@ -3,20 +3,12 @@ using Android.App; using Android.Content; using Java.Security; using System.IO; -using Android.Nfc; using Android.Provider; namespace Bit.Android { public static class Utilities { - public static bool NfcEnabled() - { - var manager = (NfcManager)Application.Context.GetSystemService("nfc"); - var adapter = manager.DefaultAdapter; - return adapter != null && adapter.IsEnabled; - } - public static void SendCrashEmail(Exception e, bool includeSecurityProviders = true) { SendCrashEmail(e.Message + "\n\n" + e.StackTrace, includeSecurityProviders); diff --git a/src/iOS.Core/Services/DeviceInfoService.cs b/src/iOS.Core/Services/DeviceInfoService.cs index 41daf9f78..b194da9d3 100644 --- a/src/iOS.Core/Services/DeviceInfoService.cs +++ b/src/iOS.Core/Services/DeviceInfoService.cs @@ -24,7 +24,7 @@ namespace Bit.iOS.Core.Services } } public float Scale => (float)UIScreen.MainScreen.Scale; - public bool NfcEnabled => false; + public bool NfcEnabled => CoreNFC.NFCNdefReaderSession.ReadingAvailable; public bool HasCamera => true; public bool AutofillServiceSupported => false; public bool HasFaceIdSupport diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 29cf40e07..5dc4427b7 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -20,6 +20,7 @@ using Google.Analytics; using FFImageLoading.Forms.Touch; using SimpleInjector; using XLabs.Ioc.SimpleInjectorContainer; +using CoreNFC; namespace Bit.iOS { @@ -28,6 +29,7 @@ namespace Bit.iOS { private GaiCompletionHandler _dispatchHandler = null; private ILockService _lockService; + private IDeviceInfoService _deviceInfoService; private iOSPushNotificationHandler _pushHandler = null; public ISettings Settings { get; set; } @@ -42,6 +44,7 @@ namespace Bit.iOS } _lockService = Resolver.Resolve(); + _deviceInfoService = Resolver.Resolve(); _pushHandler = new iOSPushNotificationHandler(Resolver.Resolve()); var appIdService = Resolver.Resolve(); @@ -106,6 +109,26 @@ namespace Bit.iOS modal.PresentViewController(activityViewController, true, null); }); + MessagingCenter.Subscribe(Xamarin.Forms.Application.Current, + "ListenYubiKeyOTP", (sender, listen) => + { + if(!_deviceInfoService.NfcEnabled) + { + return; + } + + var del = new NFCReaderDelegate((success, message) => + { + Debug.WriteLine((success ? "SUCCESS! " : "ERROR! ") + message); + if(success) + { + MessagingCenter.Send(Xamarin.Forms.Application.Current, "GotYubiKeyOTP", message); + } + }); + var session = new NFCNdefReaderSession(del, null, true); + session.BeginSession(); + }); + UIApplication.SharedApplication.StatusBarHidden = false; UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent; diff --git a/src/iOS/NFCReaderDelegate.cs b/src/iOS/NFCReaderDelegate.cs new file mode 100644 index 000000000..bdd076d4d --- /dev/null +++ b/src/iOS/NFCReaderDelegate.cs @@ -0,0 +1,54 @@ +using CoreNFC; +using Foundation; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace Bit.iOS +{ + public class NFCReaderDelegate : NFCNdefReaderSessionDelegate + { + private Regex _otpPattern = new Regex("^.*?([cbdefghijklnrtuv]{32,64})$"); + private Action _callback; + + public NFCReaderDelegate(Action callback) + { + _callback = callback; + } + + public override void DidDetect(NFCNdefReaderSession session, NFCNdefMessage[] messages) + { + var results = new List(); + foreach(var message in messages) + { + foreach(var record in message.Records) + { + try + { + results.Add(new NSString(record.Payload, NSStringEncoding.UTF8)); + } + catch { } + } + } + + foreach(var result in results) + { + Debug.WriteLine("READ TAG: " + result); + if(_otpPattern.IsMatch(result)) + { + Debug.WriteLine("TAG IS MATCH: " + result); + _callback.Invoke(true, result); + return; + } + } + + _callback.Invoke(false, "No tags were read."); + } + + public override void DidInvalidate(NFCNdefReaderSession session, NSError error) + { + _callback.Invoke(false, error?.LocalizedDescription); + } + } +} diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index 97b780fe8..84b72a8ad 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -233,6 +233,7 @@ +