From 56935a7210dd3d459e3e6f56915286c6b17c3a24 Mon Sep 17 00:00:00 2001 From: Matt Portune <59324545+mportune-bw@users.noreply.github.com> Date: Fri, 15 Jan 2021 14:04:07 -0500 Subject: [PATCH] restore vault timeout timer for Android (#1220) --- src/Android/MainActivity.cs | 19 ++++++++++++++++++- src/Android/Services/DeviceActionService.cs | 2 +- src/App/App.xaml.cs | 9 +++++++-- src/App/Pages/BaseContentPage.cs | 2 +- src/App/Services/MobileStorageService.cs | 2 +- src/Core/Constants.cs | 2 +- src/Core/Services/VaultTimeoutService.cs | 17 +++++++++-------- src/iOS.Core/Services/DeviceActionService.cs | 6 +++--- src/iOS.Core/Utilities/iOSHelpers.cs | 4 ++-- src/iOS/AppDelegate.cs | 2 +- 10 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs index 8987e9e1a..e2e9bb407 100644 --- a/src/Android/MainActivity.cs +++ b/src/Android/MainActivity.cs @@ -38,6 +38,7 @@ namespace Bit.Droid private IAppIdService _appIdService; private IStorageService _storageService; private IEventService _eventService; + private PendingIntent _vaultTimeoutAlarmPendingIntent; private PendingIntent _clearClipboardPendingIntent; private PendingIntent _eventUploadPendingIntent; private AppOptions _appOptions; @@ -50,6 +51,9 @@ namespace Bit.Droid var eventUploadIntent = new Intent(this, typeof(EventUploadReceiver)); _eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent, PendingIntentFlags.UpdateCurrent); + var alarmIntent = new Intent(this, typeof(LockAlarmReceiver)); + _vaultTimeoutAlarmPendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, + PendingIntentFlags.UpdateCurrent); var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver)); _clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent, PendingIntentFlags.UpdateCurrent); @@ -87,7 +91,20 @@ namespace Bit.Droid _broadcasterService.Subscribe(_activityKey, (message) => { - if (message.Command == "startEventTimer") + if (message.Command == "scheduleVaultTimeoutTimer") + { + var alarmManager = GetSystemService(AlarmService) as AlarmManager; + var vaultTimeoutMinutes = (int)message.Data; + var vaultTimeoutMs = vaultTimeoutMinutes * 60000; + var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + vaultTimeoutMs + 10; + alarmManager.Set(AlarmType.RtcWakeup, triggerMs, _vaultTimeoutAlarmPendingIntent); + } + else if (message.Command == "cancelVaultTimeoutTimer") + { + var alarmManager = GetSystemService(AlarmService) as AlarmManager; + alarmManager.Cancel(_vaultTimeoutAlarmPendingIntent); + } + else if (message.Command == "startEventTimer") { StartEventAlarm(); } diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs index 2c106e454..7585bf2e1 100644 --- a/src/Android/Services/DeviceActionService.cs +++ b/src/Android/Services/DeviceActionService.cs @@ -758,7 +758,7 @@ namespace Bit.Droid.Services // be monotonic, and continues to tick even when the CPU is in power saving modes, so is the recommend // basis for general purpose interval timing. // ref: https://developer.android.com/reference/android/os/SystemClock#elapsedRealtime() - return SystemClock.ElapsedRealtime() / 1000; + return SystemClock.ElapsedRealtime(); } private bool DeleteDir(Java.IO.File dir) diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 531dbf9dc..15563b45f 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -185,7 +185,7 @@ namespace Bit.App var isLocked = await _vaultTimeoutService.IsLockedAsync(); if (!isLocked) { - await _storageService.SaveAsync(Constants.LastActiveKey, _deviceActionService.GetActiveTime()); + await _storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime()); } SetTabsPageFromAutofill(isLocked); await SleptAsync(); @@ -211,6 +211,7 @@ namespace Bit.App private async void ResumedAsync() { await _vaultTimeoutService.CheckVaultTimeoutAsync(); + _messagingService.Send("cancelVaultTimeoutTimer"); _messagingService.Send("startEventTimer"); await ClearCacheIfNeededAsync(); Prime(); @@ -302,7 +303,11 @@ namespace Bit.App vaultTimeout = await _storageService.GetAsync(Constants.VaultTimeoutKey); } vaultTimeout = vaultTimeout.GetValueOrDefault(-1); - if (vaultTimeout == 0) + if (vaultTimeout > 0) + { + _messagingService.Send("scheduleVaultTimeoutTimer", vaultTimeout.Value); + } + else if (vaultTimeout == 0) { var action = await _storageService.GetAsync(Constants.VaultTimeoutActionKey); if (action == "logOut") diff --git a/src/App/Pages/BaseContentPage.cs b/src/App/Pages/BaseContentPage.cs index 1dcce333e..8919f8e1d 100644 --- a/src/App/Pages/BaseContentPage.cs +++ b/src/App/Pages/BaseContentPage.cs @@ -118,7 +118,7 @@ namespace Bit.App.Pages private void SaveActivity() { SetServices(); - _storageService.SaveAsync(Constants.LastActiveKey, _deviceActionService.GetActiveTime()); + _storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime()); } } } diff --git a/src/App/Services/MobileStorageService.cs b/src/App/Services/MobileStorageService.cs index 610d340e0..b43550a8e 100644 --- a/src/App/Services/MobileStorageService.cs +++ b/src/App/Services/MobileStorageService.cs @@ -21,7 +21,7 @@ namespace Bit.App.Services Constants.DisableFaviconKey, Constants.ClearClipboardKey, Constants.AutofillDisableSavePromptKey, - Constants.LastActiveKey, + Constants.LastActiveTimeKey, Constants.PushInitialPromptShownKey, Constants.LastFileCacheClearKey, Constants.PushLastRegistrationDateKey, diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index a96dd2364..3ef3529f6 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -7,7 +7,7 @@ public static string SyncOnRefreshKey = "syncOnRefresh"; public static string VaultTimeoutKey = "lockOption"; public static string VaultTimeoutActionKey = "vaultTimeoutAction"; - public static string LastActiveKey = "lastActive"; + public static string LastActiveTimeKey = "lastActiveTime"; public static string BiometricUnlockKey = "fingerprintUnlock"; public static string ProtectedPin = "protectedPin"; public static string PinProtectedKey = "pinProtectedKey"; diff --git a/src/Core/Services/VaultTimeoutService.cs b/src/Core/Services/VaultTimeoutService.cs index 1e1847897..9a44581ee 100644 --- a/src/Core/Services/VaultTimeoutService.cs +++ b/src/Core/Services/VaultTimeoutService.cs @@ -81,22 +81,23 @@ namespace Bit.Core.Services return; } // This only returns null - var vaultTimeout = _platformUtilsService.LockTimeout(); - if (vaultTimeout == null) + var vaultTimeoutMinutes = _platformUtilsService.LockTimeout(); + if (vaultTimeoutMinutes == null) { - vaultTimeout = await _storageService.GetAsync(Constants.VaultTimeoutKey); + vaultTimeoutMinutes = await _storageService.GetAsync(Constants.VaultTimeoutKey); } - if (vaultTimeout.GetValueOrDefault(-1) < 0) + if (vaultTimeoutMinutes.GetValueOrDefault(-1) < 0) { return; } - var lastActive = await _storageService.GetAsync(Constants.LastActiveKey); - if (lastActive == null) + var lastActiveTime = await _storageService.GetAsync(Constants.LastActiveTimeKey); + if (lastActiveTime == null) { return; } - var diff = _platformUtilsService.GetActiveTime() - lastActive; - if (diff >= vaultTimeout * 60) + var diffMs = _platformUtilsService.GetActiveTime() - lastActiveTime; + var vaultTimeoutMs = vaultTimeoutMinutes * 60000; + if (diffMs >= vaultTimeoutMs) { // Pivot based on saved action var action = await _storageService.GetAsync(Constants.VaultTimeoutActionKey); diff --git a/src/iOS.Core/Services/DeviceActionService.cs b/src/iOS.Core/Services/DeviceActionService.cs index fa06cf2d5..d528e138a 100644 --- a/src/iOS.Core/Services/DeviceActionService.cs +++ b/src/iOS.Core/Services/DeviceActionService.cs @@ -432,9 +432,9 @@ namespace Bit.iOS.Core.Services public long GetActiveTime() { - // Fall back to UnixTimeSeconds in case this approach stops working. We'll lose clock-change protection but - // the lock functionality will continue to work. - return iOSHelpers.GetSystemUpTimeSeconds() ?? DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + // Fall back to UnixTimeMilliseconds in case this approach stops working. We'll lose clock-change + // protection but the lock functionality will continue to work. + return iOSHelpers.GetSystemUpTimeMilliseconds() ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); } private void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e) diff --git a/src/iOS.Core/Utilities/iOSHelpers.cs b/src/iOS.Core/Utilities/iOSHelpers.cs index ab6a8c36d..7bb32057e 100644 --- a/src/iOS.Core/Utilities/iOSHelpers.cs +++ b/src/iOS.Core/Utilities/iOSHelpers.cs @@ -18,7 +18,7 @@ namespace Bit.iOS.Core.Utilities // includes sleep time. // ref: https://forums.xamarin.com/discussion/20006/access-to-sysctl-h // ref: https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/src/Platform/XLabs.Platform.iOS/Device/AppleDevice.cs - public static long? GetSystemUpTimeSeconds() + public static long? GetSystemUpTimeMilliseconds() { long? uptime = null; IntPtr pLen = default, pStr = default; @@ -34,7 +34,7 @@ namespace Bit.iOS.Core.Utilities var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); if (timeVal.sec > 0 && now > 0) { - uptime = now - timeVal.sec; + uptime = (now - timeVal.sec) * 1000; } } catch (Exception e) diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 66464ae53..e56e02cf9 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -201,7 +201,7 @@ namespace Bit.iOS UIApplication.SharedApplication.KeyWindow.BringSubviewToFront(view); UIApplication.SharedApplication.KeyWindow.EndEditing(true); UIApplication.SharedApplication.SetStatusBarHidden(true, false); - _storageService.SaveAsync(Constants.LastActiveKey, _deviceActionService.GetActiveTime()); + _storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime()); _messagingService.Send("slept"); base.DidEnterBackground(uiApplication); }