diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj index 2200ce290..681d232d3 100644 --- a/src/Android/Android.csproj +++ b/src/Android/Android.csproj @@ -123,6 +123,14 @@ ..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll True + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.dll + True + + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.Abstractions.dll + True + ..\..\packages\Plugin.Fingerprint.1.1.1-beta\lib\MonoAndroid\Plugin.Fingerprint.dll True diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index 49d34b55f..42b7bfae2 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -11,6 +11,7 @@ using Bit.App.Services; using Microsoft.Practices.Unity; using Plugin.Connectivity; using Plugin.CurrentActivity; +using Plugin.DeviceInfo; using Plugin.Fingerprint; using Plugin.Settings; using PushNotification.Plugin; @@ -119,6 +120,7 @@ namespace Bit.Android .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) + .RegisterType(new ContainerControlledLifetimeManager()) // Repositories .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) @@ -127,12 +129,13 @@ namespace Bit.Android .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) // Other + .RegisterInstance(CrossDeviceInfo.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(CrossConnectivity.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(UserDialogs.Instance, new ContainerControlledLifetimeManager()) .RegisterInstance(CrossFingerprint.Current, new ContainerControlledLifetimeManager()); - CrossPushNotification.Initialize(container.Resolve(), "SENDERID"); + CrossPushNotification.Initialize(container.Resolve(), "SECRET_SENDER_ID"); container.RegisterInstance(CrossPushNotification.Current, new ContainerControlledLifetimeManager()); Resolver.SetResolver(new UnityResolver(container)); diff --git a/src/Android/packages.config b/src/Android/packages.config index 55fc40f36..bbc0a2ce0 100644 --- a/src/Android/packages.config +++ b/src/Android/packages.config @@ -11,6 +11,7 @@ + diff --git a/src/App/Abstractions/Repositories/IDeviceApiRepository.cs b/src/App/Abstractions/Repositories/IDeviceApiRepository.cs index 962362c3e..8f0874d5a 100644 --- a/src/App/Abstractions/Repositories/IDeviceApiRepository.cs +++ b/src/App/Abstractions/Repositories/IDeviceApiRepository.cs @@ -2,9 +2,12 @@ using System.Collections.Generic; using System.Threading.Tasks; using Bit.App.Models.Api; +using Bit.App.Repositories; namespace Bit.App.Abstractions { public interface IDeviceApiRepository : IApiRepository - { } + { + Task> PutTokenAsync(string identifier, DeviceTokenRequest request); + } } \ No newline at end of file diff --git a/src/App/Abstractions/Services/IAppIdService.cs b/src/App/Abstractions/Services/IAppIdService.cs new file mode 100644 index 000000000..1ea728037 --- /dev/null +++ b/src/App/Abstractions/Services/IAppIdService.cs @@ -0,0 +1,7 @@ +namespace Bit.App.Abstractions +{ + public interface IAppIdService + { + string AppId { get; } + } +} diff --git a/src/App/App.csproj b/src/App/App.csproj index 5e6f37d38..d6b55ac64 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -36,6 +36,8 @@ + + @@ -65,6 +67,7 @@ + @@ -117,10 +120,10 @@ True AppResources.resx + - @@ -140,7 +143,9 @@ - + + Designer + @@ -179,6 +184,14 @@ ..\..\packages\Xam.Plugin.Connectivity.2.1.2\lib\portable-net45+wp80+wp81+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+Xamarin.Mac20+UAP10\Plugin.Connectivity.Abstractions.dll True + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\Plugin.DeviceInfo.dll + True + + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\Plugin.DeviceInfo.Abstractions.dll + True + ..\..\packages\Plugin.Fingerprint.1.1.1-beta\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.dll True diff --git a/src/App/Models/Api/Request/DeviceRequest.cs b/src/App/Models/Api/Request/DeviceRequest.cs index 2797d274f..929ac37ea 100644 --- a/src/App/Models/Api/Request/DeviceRequest.cs +++ b/src/App/Models/Api/Request/DeviceRequest.cs @@ -1,11 +1,23 @@ -using PushNotification.Plugin.Abstractions; +using Bit.App.Abstractions; +using Plugin.DeviceInfo.Abstractions; +using PushNotification.Plugin.Abstractions; namespace Bit.App.Models.Api { public class DeviceRequest { + public DeviceRequest() { } + + public DeviceRequest(IAppIdService appIdService, IDeviceInfo deviceInfo) + { + Identifier = appIdService.AppId; + Name = deviceInfo.Model; + Type = deviceInfo.Platform == Platform.Android ? DeviceType.Android : DeviceType.iOS; + } + public DeviceType Type { get; set; } public string Name { get; set; } + public string Identifier { get; set; } public string PushToken { get; set; } } } diff --git a/src/App/Models/Api/Request/DeviceTokenRequest.cs b/src/App/Models/Api/Request/DeviceTokenRequest.cs new file mode 100644 index 000000000..e9b584341 --- /dev/null +++ b/src/App/Models/Api/Request/DeviceTokenRequest.cs @@ -0,0 +1,12 @@ +namespace Bit.App.Models.Api +{ + public class DeviceTokenRequest + { + public DeviceTokenRequest(string token) + { + PushToken = token; + } + + public string PushToken { get; set; } + } +} diff --git a/src/App/Models/Api/Request/TokenRequest.cs b/src/App/Models/Api/Request/TokenRequest.cs index 5cfba970d..260835e17 100644 --- a/src/App/Models/Api/Request/TokenRequest.cs +++ b/src/App/Models/Api/Request/TokenRequest.cs @@ -4,5 +4,6 @@ { public string Email { get; set; } public string MasterPasswordHash { get; set; } + public DeviceRequest Device { get; set; } } } diff --git a/src/App/Models/Api/Response/DeviceResponse.cs b/src/App/Models/Api/Response/DeviceResponse.cs index 10fc40802..9cb1483a3 100644 --- a/src/App/Models/Api/Response/DeviceResponse.cs +++ b/src/App/Models/Api/Response/DeviceResponse.cs @@ -7,6 +7,7 @@ namespace Bit.App.Models.Api { public string Id { get; set; } public string Name { get; set; } + public string Identifier { get; set; } public DeviceType Type { get; set; } public DateTime CreationDate { get; set; } } diff --git a/src/App/Pages/LoginPage.cs b/src/App/Pages/LoginPage.cs index 62534de0c..110ae7b89 100644 --- a/src/App/Pages/LoginPage.cs +++ b/src/App/Pages/LoginPage.cs @@ -7,6 +7,7 @@ using Bit.App.Abstractions; using Bit.App.Behaviors; using Bit.App.Models.Api; using Bit.App.Resources; +using Plugin.DeviceInfo.Abstractions; using Xamarin.Forms; using XLabs.Ioc; @@ -18,6 +19,8 @@ namespace Bit.App.Pages { var cryptoService = Resolver.Resolve(); var authService = Resolver.Resolve(); + var deviceInfo = Resolver.Resolve(); + var appIdService = Resolver.Resolve(); var emailEntry = new Entry { @@ -58,13 +61,14 @@ namespace Bit.App.Pages var request = new TokenRequest { Email = emailEntry.Text, - MasterPasswordHash = cryptoService.HashPasswordBase64(key, masterPasswordEntry.Text) + MasterPasswordHash = cryptoService.HashPasswordBase64(key, masterPasswordEntry.Text), + Device = new DeviceRequest(appIdService, deviceInfo) }; var response = await authService.TokenPostAsync(request); if(!response.Succeeded) { - await DisplayAlert(AppResources.AnErrorHasOccurred, response.Errors.First().Message, AppResources.Ok); + await DisplayAlert(AppResources.AnErrorHasOccurred, response.Errors.FirstOrDefault()?.Message, AppResources.Ok); return; } diff --git a/src/App/Repositories/DeviceApiRepository.cs b/src/App/Repositories/DeviceApiRepository.cs index 1a0a0a78a..c08c7b54f 100644 --- a/src/App/Repositories/DeviceApiRepository.cs +++ b/src/App/Repositories/DeviceApiRepository.cs @@ -1,11 +1,33 @@ using System; +using System.Net.Http; +using System.Threading.Tasks; using Bit.App.Abstractions; using Bit.App.Models.Api; +using Newtonsoft.Json; namespace Bit.App.Repositories { public class DeviceApiRepository : ApiRepository, IDeviceApiRepository { protected override string ApiRoute => "devices"; + + public virtual async Task> PutTokenAsync(string identifier, DeviceTokenRequest request) + { + var requestMessage = new TokenHttpRequestMessage(request) + { + Method = HttpMethod.Put, + RequestUri = new Uri(Client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")), + }; + + var response = await Client.SendAsync(requestMessage); + if(!response.IsSuccessStatusCode) + { + return await HandleErrorAsync(response); + } + + var responseContent = await response.Content.ReadAsStringAsync(); + var responseObj = JsonConvert.DeserializeObject(responseContent); + return ApiResult.Success(responseObj, response.StatusCode); + } } } diff --git a/src/App/Services/AppIdService.cs b/src/App/Services/AppIdService.cs new file mode 100644 index 000000000..16f589a62 --- /dev/null +++ b/src/App/Services/AppIdService.cs @@ -0,0 +1,39 @@ +using System; +using Bit.App.Abstractions; +using Plugin.Settings.Abstractions; + +namespace Bit.App.Services +{ + public class AppIdService : IAppIdService + { + private const string AppIdKey = "appId"; + private readonly ISettings _settings; + private string _appId; + + public AppIdService(ISettings settings) + { + _settings = settings; + } + + public string AppId + { + get + { + if(!string.IsNullOrWhiteSpace(_appId)) + { + return _appId; + } + + _appId = _settings.GetValueOrDefault(AppIdKey); + if(!string.IsNullOrWhiteSpace(_appId)) + { + return _appId; + } + + _appId = Guid.NewGuid().ToString(); + _settings.AddOrUpdateValue(AppIdKey, _appId); + return _appId; + } + } + } +} diff --git a/src/App/Services/PushNotificationListener.cs b/src/App/Services/PushNotificationListener.cs index d0a2b74f2..89df5402e 100644 --- a/src/App/Services/PushNotificationListener.cs +++ b/src/App/Services/PushNotificationListener.cs @@ -9,6 +9,8 @@ using PushNotification.Plugin; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Bit.App.Abstractions; +using Xamarin.Forms; +using Plugin.DeviceInfo.Abstractions; namespace Bit.App.Services { @@ -18,15 +20,18 @@ namespace Bit.App.Services private readonly ISyncService _syncService; private readonly IDeviceApiRepository _deviceApiRepository; private readonly IAuthService _authService; + private readonly IAppIdService _appIdService; public PushNotificationListener( ISyncService syncService, IDeviceApiRepository deviceApiRepository, - IAuthService authService) + IAuthService authService, + IAppIdService appIdService) { _syncService = syncService; _deviceApiRepository = deviceApiRepository; _authService = authService; + _appIdService = appIdService; } public void OnMessage(JObject values, DeviceType deviceType) @@ -44,13 +49,8 @@ namespace Bit.App.Services return; } - var response = _deviceApiRepository.PostAsync(new Models.Api.DeviceRequest - { - Name = deviceType.ToString(), - Type = deviceType, - PushToken = token - }).GetAwaiter().GetResult(); - + var response = _deviceApiRepository.PutTokenAsync(_appIdService.AppId, new Models.Api.DeviceTokenRequest(token)) + .GetAwaiter().GetResult(); if(response.Succeeded) { Debug.WriteLine("Registered device with server."); diff --git a/src/App/packages.config b/src/App/packages.config index 8081ede0a..4df604a0b 100644 --- a/src/App/packages.config +++ b/src/App/packages.config @@ -11,6 +11,7 @@ + diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 25a157db2..10e70d00f 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -22,6 +22,7 @@ using Xamarin.Forms; using Bit.App; using Bit.iOS.Core.Services; using PushNotification.Plugin; +using Plugin.DeviceInfo; namespace Bit.iOS { @@ -187,6 +188,7 @@ namespace Bit.iOS .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) + .RegisterType(new ContainerControlledLifetimeManager()) // Repositories .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) @@ -195,6 +197,7 @@ namespace Bit.iOS .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) // Other + .RegisterInstance(CrossDeviceInfo.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(CrossConnectivity.Current, new ContainerControlledLifetimeManager()) .RegisterInstance(UserDialogs.Instance, new ContainerControlledLifetimeManager()) diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index b71aaa1b4..90107f2c6 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -180,6 +180,14 @@ ..\..\packages\Xam.Plugin.Connectivity.2.1.2\lib\Xamarin.iOS10\Plugin.Connectivity.Abstractions.dll True + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\Xamarin.iOS10\Plugin.DeviceInfo.dll + True + + + ..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\Xamarin.iOS10\Plugin.DeviceInfo.Abstractions.dll + True + ..\..\packages\Plugin.Fingerprint.1.1.1-beta\lib\Xamarin.iOS10\Plugin.Fingerprint.dll True diff --git a/src/iOS/packages.config b/src/iOS/packages.config index f2ab43c98..0f8f94da6 100644 --- a/src/iOS/packages.config +++ b/src/iOS/packages.config @@ -11,6 +11,7 @@ +