1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-04 01:23:15 +00:00

push notification services

This commit is contained in:
Kyle Spearrin
2019-05-28 12:01:55 -04:00
parent faccb61a6b
commit 3f11fdaa82
24 changed files with 1982 additions and 1256 deletions

View File

@@ -0,0 +1,14 @@
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{
public interface IPushNotificationListenerService
{
Task OnMessageAsync(JObject values, string device);
Task OnRegisteredAsync(string token, string device);
void OnUnregistered(string device);
void OnError(string message, string device);
bool ShouldShowNotification();
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{
public interface IPushNotificationService
{
Task<string> GetTokenAsync();
Task RegisterAsync();
Task UnregisterAsync();
}
}

View File

@@ -1,4 +1,6 @@
using Bit.App.Resources;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
@@ -12,6 +14,8 @@ namespace Bit.App.Pages
{
private readonly IBroadcasterService _broadcasterService;
private readonly ISyncService _syncService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IStorageService _storageService;
private readonly GroupingsPageViewModel _vm;
private readonly string _pageName;
@@ -23,6 +27,8 @@ namespace Bit.App.Pages
SetActivityIndicator(_mainContent);
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_vm = BindingContext as GroupingsPageViewModel;
_vm.Page = this;
_vm.MainPage = mainPage;
@@ -71,6 +77,30 @@ namespace Bit.App.Pages
}
}
}, _mainContent);
// Push registration
var lastPushRegistration = await _storageService.GetAsync<DateTime?>(Constants.PushLastRegistrationDateKey);
lastPushRegistration = lastPushRegistration.GetValueOrDefault(DateTime.MinValue);
if(Device.RuntimePlatform == Device.iOS)
{
var pushPromptShow = await _storageService.GetAsync<bool?>(Constants.PushInitialPromptShownKey);
if(!pushPromptShow.GetValueOrDefault(false))
{
await _storageService.SaveAsync(Constants.PushInitialPromptShownKey, true);
await DisplayAlert(AppResources.EnableAutomaticSyncing, AppResources.PushNotificationAlert,
AppResources.OkGotIt);
}
if(!pushPromptShow.GetValueOrDefault(false) ||
DateTime.UtcNow - lastPushRegistration > TimeSpan.FromDays(1))
{
await _pushNotificationService.RegisterAsync();
}
}
else if(Device.RuntimePlatform == Device.Android &&
DateTime.UtcNow - lastPushRegistration > TimeSpan.FromDays(1))
{
await _pushNotificationService.RegisterAsync();
}
}
protected override void OnDisappearing()

View File

@@ -0,0 +1,32 @@
using Newtonsoft.Json.Linq;
using Bit.App.Abstractions;
using System.Threading.Tasks;
namespace Bit.App.Services
{
public class NoopPushNotificationListenerService : IPushNotificationListenerService
{
public Task OnMessageAsync(JObject value, string deviceType)
{
return Task.FromResult(0);
}
public Task OnRegisteredAsync(string token, string deviceType)
{
return Task.FromResult(0);
}
public void OnUnregistered(string deviceType)
{
}
public void OnError(string message, string deviceType)
{
}
public bool ShouldShowNotification()
{
return false;
}
}
}

View File

@@ -0,0 +1,23 @@
using System.Threading.Tasks;
using Bit.App.Abstractions;
namespace Bit.App.Services
{
public class NoopPushNotificationService : IPushNotificationService
{
public Task<string> GetTokenAsync()
{
return Task.FromResult(null as string);
}
public Task RegisterAsync()
{
return Task.FromResult(0);
}
public Task UnregisterAsync()
{
return Task.FromResult(0);
}
}
}

View File

@@ -0,0 +1,187 @@
#if !FDROID
using System.Diagnostics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Bit.App.Abstractions;
using System;
using Xamarin.Forms;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core;
using Bit.Core.Models.Response;
using Bit.Core.Exceptions;
namespace Bit.App.Services
{
public class PushNotificationListenerService : IPushNotificationListenerService
{
private bool _showNotification;
private bool _resolved;
private IStorageService _storageService;
private ISyncService _syncService;
private IUserService _userService;
private IAppIdService _appIdService;
private IApiService _apiService;
private IMessagingService _messagingService;
public async Task OnMessageAsync(JObject value, string deviceType)
{
Resolve();
if(value == null)
{
return;
}
_showNotification = false;
Debug.WriteLine("Message Arrived: {0}", JsonConvert.SerializeObject(value));
NotificationResponse notification = null;
if(deviceType == Device.Android)
{
notification = value.ToObject<NotificationResponse>();
}
else
{
if(!value.TryGetValue("data", StringComparison.OrdinalIgnoreCase, out JToken dataToken) ||
dataToken == null)
{
return;
}
notification = dataToken.ToObject<NotificationResponse>();
}
var appId = await _appIdService.GetAppIdAsync();
if(notification?.Payload == null || notification.ContextId == appId)
{
return;
}
var myUserId = await _userService.GetUserIdAsync();
var isAuthenticated = await _userService.IsAuthenticatedAsync();
switch(notification.Type)
{
case NotificationType.SyncCipherUpdate:
case NotificationType.SyncCipherCreate:
var cipherCreateUpdateMessage = JsonConvert.DeserializeObject<SyncCipherNotification>(
notification.Payload);
if(isAuthenticated && cipherCreateUpdateMessage.UserId == myUserId)
{
await _syncService.SyncUpsertCipherAsync(cipherCreateUpdateMessage,
notification.Type == NotificationType.SyncCipherUpdate);
}
break;
case NotificationType.SyncFolderUpdate:
case NotificationType.SyncFolderCreate:
var folderCreateUpdateMessage = JsonConvert.DeserializeObject<SyncFolderNotification>(
notification.Payload);
if(isAuthenticated && folderCreateUpdateMessage.UserId == myUserId)
{
await _syncService.SyncUpsertFolderAsync(folderCreateUpdateMessage,
notification.Type == NotificationType.SyncFolderUpdate);
}
break;
case NotificationType.SyncLoginDelete:
case NotificationType.SyncCipherDelete:
var loginDeleteMessage = JsonConvert.DeserializeObject<SyncCipherNotification>(
notification.Payload);
if(isAuthenticated && loginDeleteMessage.UserId == myUserId)
{
await _syncService.SyncDeleteCipherAsync(loginDeleteMessage);
}
break;
case NotificationType.SyncFolderDelete:
var folderDeleteMessage = JsonConvert.DeserializeObject<SyncFolderNotification>(
notification.Payload);
if(isAuthenticated && folderDeleteMessage.UserId == myUserId)
{
await _syncService.SyncDeleteFolderAsync(folderDeleteMessage);
}
break;
case NotificationType.SyncCiphers:
case NotificationType.SyncVault:
case NotificationType.SyncSettings:
if(isAuthenticated)
{
await _syncService.FullSyncAsync(false);
}
break;
case NotificationType.SyncOrgKeys:
if(isAuthenticated)
{
await _apiService.RefreshIdentityTokenAsync();
await _syncService.FullSyncAsync(true);
}
break;
case NotificationType.LogOut:
if(isAuthenticated)
{
_messagingService.Send("logout");
}
break;
default:
break;
}
}
public async Task OnRegisteredAsync(string token, string deviceType)
{
Resolve();
Debug.WriteLine(string.Format("Push Notification - Device Registered - Token : {0}", token));
var isAuthenticated = await _userService.IsAuthenticatedAsync();
if(!isAuthenticated)
{
return;
}
var appId = await _appIdService.GetAppIdAsync();
try
{
await _apiService.PutDeviceTokenAsync(appId,
new Core.Models.Request.DeviceTokenRequest { PushToken = token });
Debug.WriteLine("Registered device with server.");
await _storageService.SaveAsync(Constants.PushLastRegistrationDateKey, DateTime.UtcNow);
if(deviceType == Device.Android)
{
await _storageService.SaveAsync(Constants.PushCurrentTokenKey, token);
}
}
catch(ApiException)
{
Debug.WriteLine("Failed to register device.");
}
}
public void OnUnregistered(string deviceType)
{
Debug.WriteLine("Push Notification - Device Unnregistered");
}
public void OnError(string message, string deviceType)
{
Debug.WriteLine(string.Format("Push notification error - {0}", message));
}
public bool ShouldShowNotification()
{
return _showNotification;
}
private void Resolve()
{
if(_resolved)
{
return;
}
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_userService = ServiceContainer.Resolve<IUserService>("userService");
_appIdService = ServiceContainer.Resolve<IAppIdService>("appIdService");
_apiService = ServiceContainer.Resolve<IApiService>("apiService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_resolved = true;
}
}
}
#endif