mirror of
https://github.com/bitwarden/android.git
synced 2025-03-07 15:06:02 +03:00
sync org keys and refactors
This commit is contained in:
parent
439370e25a
commit
b26c3d050c
5 changed files with 96 additions and 87 deletions
|
@ -11,6 +11,7 @@ namespace Bit.App.Abstractions
|
|||
Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate);
|
||||
Task<bool> SyncDeleteLoginAsync(string id);
|
||||
Task<bool> SyncSettingsAsync();
|
||||
Task<bool> SyncProfileAsync();
|
||||
Task<bool> FullSyncAsync(bool forceSync = false);
|
||||
Task<bool> FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false);
|
||||
}
|
||||
|
|
|
@ -60,11 +60,13 @@ namespace Bit.App.Services
|
|||
case Enums.PushType.SyncCipherUpdate:
|
||||
case Enums.PushType.SyncCipherCreate:
|
||||
var cipherCreateUpdateMessage = values.ToObject<SyncCipherPushNotification>();
|
||||
if(cipherCreateUpdateMessage.UserId != null && cipherCreateUpdateMessage.UserId != _authService.UserId)
|
||||
if(cipherCreateUpdateMessage.OrganizationId == null &&
|
||||
cipherCreateUpdateMessage.UserId != _authService.UserId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(!_authService.BelongsToOrganization(cipherCreateUpdateMessage.OrganizationId))
|
||||
else if(cipherCreateUpdateMessage.OrganizationId != null &&
|
||||
!_authService.BelongsToOrganization(cipherCreateUpdateMessage.OrganizationId))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -89,11 +91,13 @@ namespace Bit.App.Services
|
|||
break;
|
||||
case Enums.PushType.SyncLoginDelete:
|
||||
var loginDeleteMessage = values.ToObject<SyncCipherPushNotification>();
|
||||
if(loginDeleteMessage.UserId != null && loginDeleteMessage.UserId != _authService.UserId)
|
||||
if(loginDeleteMessage.OrganizationId == null &&
|
||||
loginDeleteMessage.UserId != _authService.UserId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(!_authService.BelongsToOrganization(loginDeleteMessage.OrganizationId))
|
||||
else if(loginDeleteMessage.OrganizationId != null &&
|
||||
!_authService.BelongsToOrganization(loginDeleteMessage.OrganizationId))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -116,6 +120,14 @@ namespace Bit.App.Services
|
|||
}
|
||||
_syncService.SyncSettingsAsync();
|
||||
break;
|
||||
case Enums.PushType.SyncOrgKeys:
|
||||
var orgKeysMessage = values.ToObject<SyncUserPushNotification>();
|
||||
if(orgKeysMessage.UserId != _authService.UserId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
_syncService.SyncProfileAsync();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ using Bit.App.Models.Api;
|
|||
using System.Collections.Generic;
|
||||
using Xamarin.Forms;
|
||||
using Newtonsoft.Json;
|
||||
using Bit.App.Models;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Bit.App.Services
|
||||
{
|
||||
|
@ -22,6 +24,7 @@ namespace Bit.App.Services
|
|||
private readonly ILoginRepository _loginRepository;
|
||||
private readonly ISettingsRepository _settingsRepository;
|
||||
private readonly IAuthService _authService;
|
||||
private readonly ICryptoService _cryptoService;
|
||||
private readonly ISettings _settings;
|
||||
|
||||
public SyncService(
|
||||
|
@ -34,6 +37,7 @@ namespace Bit.App.Services
|
|||
ILoginRepository loginRepository,
|
||||
ISettingsRepository settingsRepository,
|
||||
IAuthService authService,
|
||||
ICryptoService cryptoService,
|
||||
ISettings settings)
|
||||
{
|
||||
_cipherApiRepository = cipherApiRepository;
|
||||
|
@ -45,6 +49,7 @@ namespace Bit.App.Services
|
|||
_loginRepository = loginRepository;
|
||||
_settingsRepository = settingsRepository;
|
||||
_authService = authService;
|
||||
_cryptoService = cryptoService;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
|
@ -60,16 +65,8 @@ namespace Bit.App.Services
|
|||
SyncStarted();
|
||||
|
||||
var cipher = await _cipherApiRepository.GetByIdAsync(id).ConfigureAwait(false);
|
||||
if(!cipher.Succeeded)
|
||||
if(!CheckSuccess(cipher))
|
||||
{
|
||||
SyncCompleted(false);
|
||||
|
||||
if(Application.Current != null && (cipher.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||
|| cipher.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||
{
|
||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -106,16 +103,8 @@ namespace Bit.App.Services
|
|||
SyncStarted();
|
||||
|
||||
var folder = await _folderApiRepository.GetByIdAsync(id).ConfigureAwait(false);
|
||||
if(!folder.Succeeded)
|
||||
if(!CheckSuccess(folder))
|
||||
{
|
||||
SyncCompleted(false);
|
||||
|
||||
if(Application.Current != null && (folder.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||
|| folder.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||
{
|
||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -188,16 +177,8 @@ namespace Bit.App.Services
|
|||
SyncStarted();
|
||||
|
||||
var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false);
|
||||
if(!domains.Succeeded)
|
||||
if(!CheckSuccess(domains))
|
||||
{
|
||||
SyncCompleted(false);
|
||||
|
||||
if(Application.Current != null && (domains.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||
|| domains.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||
{
|
||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -206,6 +187,26 @@ namespace Bit.App.Services
|
|||
SyncCompleted(true);
|
||||
return true;
|
||||
}
|
||||
public async Task<bool> SyncProfileAsync()
|
||||
{
|
||||
if(!_authService.IsAuthenticated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SyncStarted();
|
||||
|
||||
var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false);
|
||||
if(!CheckSuccess(profile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SyncOrgKeys(profile.Result);
|
||||
|
||||
SyncCompleted(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> FullSyncAsync(TimeSpan syncThreshold, bool forceSync = false)
|
||||
{
|
||||
|
@ -234,26 +235,19 @@ namespace Bit.App.Services
|
|||
SyncStarted();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
// Just check profile first to make sure we'll have a success with the API
|
||||
var profile = await _accountsApiRepository.GetProfileAsync().ConfigureAwait(false);
|
||||
if(!CheckSuccess(profile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ciphers = await _cipherApiRepository.GetAsync().ConfigureAwait(false);
|
||||
var folders = await _folderApiRepository.GetAsync().ConfigureAwait(false);
|
||||
var domains = await _settingsApiRepository.GetDomains(false).ConfigureAwait(false);
|
||||
|
||||
if(!ciphers.Succeeded || !domains.Succeeded)
|
||||
if(!CheckSuccess(ciphers) || !CheckSuccess(folders) || !CheckSuccess(domains))
|
||||
{
|
||||
SyncCompleted(false);
|
||||
if(Application.Current == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ciphers.StatusCode == System.Net.HttpStatusCode.Forbidden ||
|
||||
ciphers.StatusCode == System.Net.HttpStatusCode.Unauthorized ||
|
||||
domains.StatusCode == System.Net.HttpStatusCode.Forbidden ||
|
||||
domains.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||
{
|
||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,6 +257,7 @@ namespace Bit.App.Services
|
|||
var loginTask = SyncLoginsAsync(loginsDict);
|
||||
var folderTask = SyncFoldersAsync(foldersDict);
|
||||
var domainsTask = SyncDomainsAsync(domains.Result);
|
||||
SyncOrgKeys(profile.Result);
|
||||
await Task.WhenAll(loginTask, folderTask, domainsTask).ConfigureAwait(false);
|
||||
|
||||
if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null)
|
||||
|
@ -394,6 +389,29 @@ namespace Bit.App.Services
|
|||
catch(SQLite.SQLiteException) { }
|
||||
}
|
||||
|
||||
private void SyncOrgKeys(ProfileResponse profile)
|
||||
{
|
||||
var orgKeysDict = new Dictionary<string, CryptoKey>();
|
||||
|
||||
if(profile.Organizations != null)
|
||||
{
|
||||
foreach(var org in profile.Organizations)
|
||||
{
|
||||
try
|
||||
{
|
||||
var decBytes = _cryptoService.RsaDecryptToBytes(new CipherString(org.Key), null);
|
||||
orgKeysDict.Add(org.Id, new CryptoKey(decBytes));
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.WriteLine($"Cannot set org key {org.Id}. Decryption failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_cryptoService.OrgKeys = orgKeysDict;
|
||||
}
|
||||
|
||||
private void SyncStarted()
|
||||
{
|
||||
if(Application.Current == null)
|
||||
|
@ -415,5 +433,23 @@ namespace Bit.App.Services
|
|||
SyncInProgress = false;
|
||||
MessagingCenter.Send(Application.Current, "SyncCompleted", successfully);
|
||||
}
|
||||
|
||||
private bool CheckSuccess<T>(ApiResult<T> result)
|
||||
{
|
||||
if(!result.Succeeded)
|
||||
{
|
||||
SyncCompleted(false);
|
||||
|
||||
if(Application.Current != null && (result.StatusCode == System.Net.HttpStatusCode.Forbidden
|
||||
|| result.StatusCode == System.Net.HttpStatusCode.Unauthorized))
|
||||
{
|
||||
MessagingCenter.Send(Application.Current, "Logout", (string)null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="X5k-f2-b5h">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="gAE-YM-kbH">
|
||||
<objects>
|
||||
<viewController id="X5k-f2-b5h" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Y8P-hJ-Z43"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="9ZL-r4-8FZ"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="yd7-JS-zBw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="Icon-60.png" translatesAutoresizingMaskIntoConstraints="NO" id="23">
|
||||
<rect key="frame" x="270" y="270" width="60" height="60"/>
|
||||
<rect key="contentStretch" x="0.0" y="0.0" width="0.0" height="0.0"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.59607843137254901" blue="0.85882352941176465" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="23" firstAttribute="centerY" secondItem="yd7-JS-zBw" secondAttribute="centerY" priority="1" id="39"/>
|
||||
<constraint firstItem="23" firstAttribute="centerX" secondItem="yd7-JS-zBw" secondAttribute="centerX" priority="1" id="41"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="XAI-xm-WK6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="349" y="339"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Icon-60.png" width="180" height="180"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -253,7 +253,6 @@
|
|||
<BundleResource Include="Resources\Icon-Small.png" />
|
||||
<BundleResource Include="Resources\Icon-Small%402x.png" />
|
||||
<BundleResource Include="Resources\Icon-Small%403x.png" />
|
||||
<InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Acr.Support.iOS, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
|
|
Loading…
Add table
Reference in a new issue