mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
[EC-770] Implement MessagePack on Watch sync (#2264)
* EC-770 Started implementing MessagePack for the iPhone -> Watch communication * EC-770 Removed Pods and installed MessagePack through SPM * EC-770 Implemented MessagePack + Lzfse compression when syncing iPhone -> Watch * EC-770 Added MessagePack as submodule and updated the build to checkout the submodule as well. Also added MessagePack files as reference in the watch project * EC-770 Updated build Updated build.yml to checkout submodules on iOS
This commit is contained in:
parent
a18f74a72a
commit
9f8307a4ff
21 changed files with 228 additions and 45 deletions
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
@ -37,6 +37,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Check if special branches exist
|
- name: Check if special branches exist
|
||||||
id: branch-check
|
id: branch-check
|
||||||
|
@ -514,6 +516,8 @@ jobs:
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Login to Azure - Prod Subscription
|
- name: Login to Azure - Prod Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "lib/MessagePack"]
|
||||||
|
path = lib/MessagePack
|
||||||
|
url = https://github.com/bitwarden/MessagePack.git
|
1
lib/MessagePack
Submodule
1
lib/MessagePack
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 1ecb15e31176023f6aa0b4948859b197b771d357
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Services;
|
using Bit.App.Services;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models;
|
|
||||||
|
|
||||||
namespace Bit.Droid.Services
|
namespace Bit.Droid.Services
|
||||||
{
|
{
|
||||||
|
@ -22,7 +21,7 @@ namespace Bit.Droid.Services
|
||||||
|
|
||||||
protected override bool CanSendData => false;
|
protected override bool CanSendData => false;
|
||||||
|
|
||||||
protected override Task SendDataToWatchAsync(WatchDTO watchDto) => throw new NotImplementedException();
|
protected override Task SendDataToWatchAsync(byte[] rawData) => throw new NotImplementedException();
|
||||||
|
|
||||||
protected override void ConnectToWatch() => throw new NotImplementedException();
|
protected override void ConnectToWatch() => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2515" />
|
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2515" />
|
||||||
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
||||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
||||||
|
<PackageReference Include="MessagePack" Version="2.4.59" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -436,6 +437,8 @@
|
||||||
<None Remove="Utilities\AccountManagement\" />
|
<None Remove="Utilities\AccountManagement\" />
|
||||||
<None Remove="Controls\DateTime\" />
|
<None Remove="Controls\DateTime\" />
|
||||||
<None Remove="Controls\IconLabelButton\" />
|
<None Remove="Controls\IconLabelButton\" />
|
||||||
|
<None Remove="MessagePack" />
|
||||||
|
<None Remove="MessagePack.MSBuild.Tasks" />
|
||||||
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
using Xamarin.Forms;
|
using MessagePack;
|
||||||
|
using MessagePack.Resolvers;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
|
@ -124,7 +124,18 @@ namespace Bit.App.Services
|
||||||
await SyncDataToWatchAsync();
|
await SyncDataToWatchAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Task SendDataToWatchAsync(WatchDTO watchDto);
|
protected async Task SendDataToWatchAsync(WatchDTO watchDto)
|
||||||
|
{
|
||||||
|
var options = MessagePackSerializerOptions.Standard
|
||||||
|
.WithResolver(CompositeResolver.Create(
|
||||||
|
GeneratedResolver.Instance,
|
||||||
|
StandardResolver.Instance
|
||||||
|
));
|
||||||
|
|
||||||
|
await SendDataToWatchAsync(MessagePackSerializer.Serialize(watchDto, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task SendDataToWatchAsync(byte[] rawData);
|
||||||
|
|
||||||
protected abstract void ConnectToWatch();
|
protected abstract void ConnectToWatch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
<None Remove="Microsoft.AppCenter.Crashes" />
|
<None Remove="Microsoft.AppCenter.Crashes" />
|
||||||
<None Remove="Services\Logging\" />
|
<None Remove="Services\Logging\" />
|
||||||
<None Remove="Attributes\" />
|
<None Remove="Attributes\" />
|
||||||
|
<None Remove="MessagePack" />
|
||||||
|
<None Remove="MessagePack.MSBuild.Tasks" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -32,6 +34,11 @@
|
||||||
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
||||||
<PackageReference Include="zxcvbn-core" Version="7.0.92" />
|
<PackageReference Include="zxcvbn-core" Version="7.0.92" />
|
||||||
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.3" />
|
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.3" />
|
||||||
|
<PackageReference Include="MessagePack" Version="2.4.59" />
|
||||||
|
<PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.4.59">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
namespace Bit.Core.Models.View
|
namespace Bit.Core.Models.View
|
||||||
{
|
{
|
||||||
|
[MessagePackObject]
|
||||||
public class SimpleCipherView
|
public class SimpleCipherView
|
||||||
{
|
{
|
||||||
|
public SimpleCipherView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public SimpleCipherView(CipherView c)
|
public SimpleCipherView(CipherView c)
|
||||||
{
|
{
|
||||||
Id = c.Id;
|
Id = c.Id;
|
||||||
|
@ -22,26 +28,40 @@ namespace Bit.Core.Models.View
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Key(0)]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
[Key(1)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public CipherType Type { get; set; }
|
[IgnoreMember]
|
||||||
|
public CipherType Type { get; set; } // ignoring on serialization for now, given that all are going to be of type Login
|
||||||
|
[Key(2)]
|
||||||
public SimpleLoginView Login { get; set; }
|
public SimpleLoginView Login { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
public class SimpleLoginView
|
public class SimpleLoginView
|
||||||
{
|
{
|
||||||
|
[Key(0)]
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
[Key(1)]
|
||||||
public string Totp { get; set; }
|
public string Totp { get; set; }
|
||||||
|
[Key(2)]
|
||||||
public List<SimpleLoginUriView> Uris { get; set; }
|
public List<SimpleLoginUriView> Uris { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
public class SimpleLoginUriView
|
public class SimpleLoginUriView
|
||||||
{
|
{
|
||||||
|
public SimpleLoginUriView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public SimpleLoginUriView(string uri)
|
public SimpleLoginUriView(string uri)
|
||||||
{
|
{
|
||||||
Uri = uri;
|
Uri = uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Key(0)]
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,56 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
namespace Bit.Core.Models
|
namespace Bit.Core.Models
|
||||||
{
|
{
|
||||||
|
[MessagePackObject]
|
||||||
public class WatchDTO
|
public class WatchDTO
|
||||||
{
|
{
|
||||||
|
public WatchDTO()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public WatchDTO(WatchState state)
|
public WatchDTO(WatchState state)
|
||||||
{
|
{
|
||||||
State = state;
|
State = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Key(0)]
|
||||||
public WatchState State { get; private set; }
|
public WatchState State { get; private set; }
|
||||||
|
|
||||||
|
[Key(1)]
|
||||||
public List<SimpleCipherView> Ciphers { get; set; }
|
public List<SimpleCipherView> Ciphers { get; set; }
|
||||||
|
|
||||||
|
[Key(2)]
|
||||||
public UserDataDto UserData { get; set; }
|
public UserDataDto UserData { get; set; }
|
||||||
|
|
||||||
|
[Key(3)]
|
||||||
public EnvironmentUrlDataDto EnvironmentData { get; set; }
|
public EnvironmentUrlDataDto EnvironmentData { get; set; }
|
||||||
|
|
||||||
//public SettingsDataDto SettingsData { get; set; }
|
//public SettingsDataDto SettingsData { get; set; }
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
public class UserDataDto
|
public class UserDataDto
|
||||||
{
|
{
|
||||||
|
[Key(0)]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[Key(1)]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Key(2)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
public class EnvironmentUrlDataDto
|
public class EnvironmentUrlDataDto
|
||||||
{
|
{
|
||||||
|
[Key(0)]
|
||||||
public string Base { get; set; }
|
public string Base { get; set; }
|
||||||
|
|
||||||
|
[Key(1)]
|
||||||
public string Icons { get; set; }
|
public string Icons { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Services;
|
using Bit.App.Services;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models;
|
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Newtonsoft.Json;
|
using Foundation;
|
||||||
using WatchConnectivity;
|
using WatchConnectivity;
|
||||||
|
|
||||||
namespace Bit.iOS.Core.Services
|
namespace Bit.iOS.Core.Services
|
||||||
|
@ -15,12 +14,17 @@ namespace Bit.iOS.Core.Services
|
||||||
const string ACTION_MESSAGE_KEY = "actionMessage";
|
const string ACTION_MESSAGE_KEY = "actionMessage";
|
||||||
const string TRIGGER_SYNC_ACTION_KEY = "triggerSync";
|
const string TRIGGER_SYNC_ACTION_KEY = "triggerSync";
|
||||||
|
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public WatchDeviceService(ICipherService cipherService,
|
public WatchDeviceService(ICipherService cipherService,
|
||||||
IEnvironmentService environmentService,
|
IEnvironmentService environmentService,
|
||||||
IStateService stateService,
|
IStateService stateService,
|
||||||
IVaultTimeoutService vaultTimeoutService)
|
IVaultTimeoutService vaultTimeoutService,
|
||||||
|
ILogger logger)
|
||||||
: base(cipherService, environmentService, stateService, vaultTimeoutService)
|
: base(cipherService, environmentService, stateService, vaultTimeoutService)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
WCSessionManager.SharedManager.OnMessagedReceived += OnMessagedReceived;
|
WCSessionManager.SharedManager.OnMessagedReceived += OnMessagedReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,17 +34,24 @@ namespace Bit.iOS.Core.Services
|
||||||
|
|
||||||
protected override bool IsSupported => WCSession.IsSupported;
|
protected override bool IsSupported => WCSession.IsSupported;
|
||||||
|
|
||||||
protected override Task SendDataToWatchAsync(WatchDTO watchDto)
|
protected override Task SendDataToWatchAsync(byte[] rawData)
|
||||||
{
|
{
|
||||||
var serializedData = JsonConvert.SerializeObject(watchDto);
|
NSError error = null;
|
||||||
|
// Lzfse is available on iOS 13+ but we're already constraining that by the constraint of watchOS version
|
||||||
|
// so there's no way this will be executed on lower than iOS 13. So no condition is needed here.
|
||||||
|
var data = NSData.FromArray(rawData).Compress(NSDataCompressionAlgorithm.Lzfse, out error);
|
||||||
|
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
_logger.Error("Can't compress Lzfse. Error: " + error.LocalizedDescription);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
// Add time to the key to make it change on every message sent so it's delivered faster.
|
// Add time to the key to make it change on every message sent so it's delivered faster.
|
||||||
// If we use the same key then the OS may defer the delivery of the message because of
|
// If we use the same key then the OS may defer the delivery of the message because of
|
||||||
// resources, reachability and other stuff
|
// resources, reachability and other stuff
|
||||||
WCSessionManager.SharedManager.SendBackgroundHighPriorityMessage(new Dictionary<string, object>
|
var dict = new NSDictionary<NSString, NSObject>(new NSString($"watchDto-{DateTime.UtcNow.ToLongTimeString()}"), data);
|
||||||
{
|
WCSessionManager.SharedManager.SendBackgroundHighPriorityMessage(dict);
|
||||||
[$"watchDto-{DateTime.UtcNow.ToLongTimeString()}"] = serializedData
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace WatchConnectivity
|
||||||
Debug.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')}");
|
Debug.WriteLine($"Watch connectivity Reachable:{(session.Reachable ? '✓' : '✗')}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendBackgroundHighPriorityMessage(Dictionary<string, object> applicationContext)
|
public void SendBackgroundHighPriorityMessage(NSDictionary<NSString, NSObject> applicationContext)
|
||||||
{
|
{
|
||||||
// Application context doesnt need the watch to be reachable, it will be received when opened
|
// Application context doesnt need the watch to be reachable, it will be received when opened
|
||||||
if (validSession is null || validSession.ActivationState != WCSessionActivationState.Activated)
|
if (validSession is null || validSession.ActivationState != WCSessionActivationState.Activated)
|
||||||
|
@ -84,10 +84,10 @@ namespace WatchConnectivity
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sendSuccessfully = validSession.UpdateApplicationContext(applicationContext.ToNSDictionary(), out var error);
|
var sendSuccessfully = validSession.UpdateApplicationContext(applicationContext, out var error);
|
||||||
if (sendSuccessfully)
|
if (sendSuccessfully)
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Sent App Context \nPayLoad: {applicationContext.ToNSDictionary().ToString()} \n");
|
Debug.WriteLine($"Sent App Context \nPayLoad: {applicationContext.ToString()} \n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,7 +144,8 @@ namespace Bit.iOS.Core.Utilities
|
||||||
ServiceContainer.Register<IWatchDeviceService>(new WatchDeviceService(ServiceContainer.Resolve<ICipherService>(),
|
ServiceContainer.Register<IWatchDeviceService>(new WatchDeviceService(ServiceContainer.Resolve<ICipherService>(),
|
||||||
ServiceContainer.Resolve<IEnvironmentService>(),
|
ServiceContainer.Resolve<IEnvironmentService>(),
|
||||||
ServiceContainer.Resolve<IStateService>(),
|
ServiceContainer.Resolve<IStateService>(),
|
||||||
ServiceContainer.Resolve<IVaultTimeoutService>()));
|
ServiceContainer.Resolve<IVaultTimeoutService>(),
|
||||||
|
ServiceContainer.Resolve<ILogger>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bootstrap(Func<Task> postBootstrapFunc = null)
|
public static void Bootstrap(Func<Task> postBootstrapFunc = null)
|
||||||
|
|
|
@ -2,6 +2,12 @@ import Foundation
|
||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
struct Cipher:Identifiable,Codable{
|
struct Cipher:Identifiable,Codable{
|
||||||
|
enum CodingKeys : CodingKey {
|
||||||
|
case id
|
||||||
|
case name
|
||||||
|
case login
|
||||||
|
}
|
||||||
|
|
||||||
var id:String
|
var id:String
|
||||||
var name:String?
|
var name:String?
|
||||||
var userId:String?
|
var userId:String?
|
||||||
|
|
|
@ -9,6 +9,7 @@ enum BWState : Int, Codable {
|
||||||
case syncing = 5
|
case syncing = 5
|
||||||
// case needUnlock = 6
|
// case needUnlock = 6
|
||||||
case needDeviceOwnerAuth = 7
|
case needDeviceOwnerAuth = 7
|
||||||
|
case debug = 255
|
||||||
|
|
||||||
var isDestructive: Bool {
|
var isDestructive: Bool {
|
||||||
return self == .needSetup || self == .needLogin || self == .needPremium || self == .need2FAItem
|
return self == .needSetup || self == .needLogin || self == .needPremium || self == .need2FAItem
|
||||||
|
|
|
@ -3,9 +3,9 @@ import Foundation
|
||||||
extension JSONDecoder.KeyDecodingStrategy {
|
extension JSONDecoder.KeyDecodingStrategy {
|
||||||
static var upperToLowerCamelCase: JSONDecoder.KeyDecodingStrategy {
|
static var upperToLowerCamelCase: JSONDecoder.KeyDecodingStrategy {
|
||||||
return .custom { codingKeys in
|
return .custom { codingKeys in
|
||||||
|
|
||||||
var key = AnyCodingKey(codingKeys.last!)
|
var key = JSONAnyCodingKey(codingKeys.last!)
|
||||||
|
|
||||||
if let firstChar = key.stringValue.first {
|
if let firstChar = key.stringValue.first {
|
||||||
key.stringValue.replaceSubrange(
|
key.stringValue.replaceSubrange(
|
||||||
...key.stringValue.startIndex, with: String(firstChar).lowercased()
|
...key.stringValue.startIndex, with: String(firstChar).lowercased()
|
||||||
|
@ -16,10 +16,10 @@ extension JSONDecoder.KeyDecodingStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnyCodingKey : CodingKey {
|
struct JSONAnyCodingKey : CodingKey {
|
||||||
var stringValue: String
|
var stringValue: String
|
||||||
var intValue: Int?
|
var intValue: Int?
|
||||||
|
|
||||||
init(_ base: CodingKey) {
|
init(_ base: CodingKey) {
|
||||||
self.init(stringValue: base.stringValue, intValue: base.intValue)
|
self.init(stringValue: base.stringValue, intValue: base.intValue)
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,12 @@ struct AnyCodingKey : CodingKey {
|
||||||
init(stringValue: String) {
|
init(stringValue: String) {
|
||||||
self.stringValue = stringValue
|
self.stringValue = stringValue
|
||||||
}
|
}
|
||||||
|
|
||||||
init(intValue: Int) {
|
init(intValue: Int) {
|
||||||
self.stringValue = "\(intValue)"
|
self.stringValue = "\(intValue)"
|
||||||
self.intValue = intValue
|
self.intValue = intValue
|
||||||
}
|
}
|
||||||
|
|
||||||
init(stringValue: String, intValue: Int?) {
|
init(stringValue: String, intValue: Int?) {
|
||||||
self.stringValue = stringValue
|
self.stringValue = stringValue
|
||||||
self.intValue = intValue
|
self.intValue = intValue
|
||||||
|
|
|
@ -4,7 +4,7 @@ class BWStateViewModel : ObservableObject{
|
||||||
@Published var text:String
|
@Published var text:String
|
||||||
@Published var isLoading:Bool = false
|
@Published var isLoading:Bool = false
|
||||||
|
|
||||||
init(_ state: BWState){
|
init(_ state: BWState, _ defaultText: String?){
|
||||||
switch state {
|
switch state {
|
||||||
case .needLogin:
|
case .needLogin:
|
||||||
text = "LogInToBitwardenOnYourIPhoneToViewVerificationCodes"
|
text = "LogInToBitwardenOnYourIPhoneToViewVerificationCodes"
|
||||||
|
@ -22,7 +22,7 @@ class BWStateViewModel : ObservableObject{
|
||||||
case .needDeviceOwnerAuth:
|
case .needDeviceOwnerAuth:
|
||||||
text = "SetUpAppleWatchPasscodeInOrderToUseBitwarden"
|
text = "SetUpAppleWatchPasscodeInOrderToUseBitwarden"
|
||||||
default:
|
default:
|
||||||
text = ""
|
text = defaultText ?? ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ class CipherListViewModel : ObservableObject {
|
||||||
|
|
||||||
@Published var searchTerm: String = ""
|
@Published var searchTerm: String = ""
|
||||||
|
|
||||||
|
var debugText: String? = nil
|
||||||
|
|
||||||
private var subscriber: AnyCancellable?
|
private var subscriber: AnyCancellable?
|
||||||
|
|
||||||
init(_ cipherService: CipherServiceProtocol){
|
init(_ cipherService: CipherServiceProtocol){
|
||||||
|
@ -23,6 +25,7 @@ class CipherListViewModel : ObservableObject {
|
||||||
subscriber = watchConnectivityManager.watchConnectivitySubject.sink { completion in
|
subscriber = watchConnectivityManager.watchConnectivitySubject.sink { completion in
|
||||||
print("WCM subject: \(completion)")
|
print("WCM subject: \(completion)")
|
||||||
} receiveValue: { value in
|
} receiveValue: { value in
|
||||||
|
self.debugText = value.debugText
|
||||||
self.checkStateAndFetch(value.state)
|
self.checkStateAndFetch(value.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ import SwiftUI
|
||||||
struct BWStateView: View {
|
struct BWStateView: View {
|
||||||
@ObservedObject var viewModel:BWStateViewModel
|
@ObservedObject var viewModel:BWStateViewModel
|
||||||
|
|
||||||
init(_ state: BWState) {
|
init(_ state: BWState, _ defaultText: String?) {
|
||||||
viewModel = BWStateViewModel(state)
|
viewModel = BWStateViewModel(state, defaultText)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -32,6 +32,6 @@ struct BWStateView: View {
|
||||||
|
|
||||||
struct BWStateView_Previews: PreviewProvider {
|
struct BWStateView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
BWStateView(.needSetup)
|
BWStateView(.needSetup, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct CipherListView: View {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $viewModel.showingSheet) {
|
.fullScreenCover(isPresented: $viewModel.showingSheet) {
|
||||||
BWStateView(viewModel.currentState)
|
BWStateView(viewModel.currentState, viewModel.debugText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import WatchConnectivity
|
||||||
|
|
||||||
struct WatchConnectivityMessage {
|
struct WatchConnectivityMessage {
|
||||||
var state: BWState?
|
var state: BWState?
|
||||||
|
var debugText: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WatchConnectivityManager: NSObject, ObservableObject {
|
final class WatchConnectivityManager: NSObject, ObservableObject {
|
||||||
|
@ -76,22 +77,41 @@ extension WatchConnectivityManager: WCSessionDelegate {
|
||||||
k.starts(with: WATCH_DTO_APP_CONTEXT_KEY)
|
k.starts(with: WATCH_DTO_APP_CONTEXT_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let dtoKey = watchDtoKey, let serializedDto = applicationContext[dtoKey] as? String else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard KeychainHelper.standard.hasDeviceOwnerAuth() else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
guard let json = try! JSONSerialization.jsonObject(with: serializedDto.data(using: .utf8)!, options: [.fragmentsAllowed]) as? String else {
|
guard let dtoKey = watchDtoKey,
|
||||||
|
let nsRawData = applicationContext[dtoKey] as? NSData,
|
||||||
|
KeychainHelper.standard.hasDeviceOwnerAuth() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoder = JSONDecoder()
|
let decoder = MessagePackDecoder()
|
||||||
decoder.keyDecodingStrategy = .upperToLowerCamelCase
|
decoder.userInfo[MessagePackDecoder.dataSpecKey] = DataSpecBuilder()
|
||||||
let watchDTO = try decoder.decode(WatchDTO.self, from: json.data(using: .utf8)!)
|
.append("state")
|
||||||
|
.appendArray("ciphers", DataSpecBuilder()
|
||||||
|
.append("id")
|
||||||
|
.append("name")
|
||||||
|
.appendObj("login", DataSpecBuilder()
|
||||||
|
.append("username")
|
||||||
|
.append("totp")
|
||||||
|
.appendArray("uris", DataSpecBuilder()
|
||||||
|
.append("uri")
|
||||||
|
.build())
|
||||||
|
.build())
|
||||||
|
.build())
|
||||||
|
.appendObj("userData", DataSpecBuilder()
|
||||||
|
.append("id")
|
||||||
|
.append("email")
|
||||||
|
.append("name")
|
||||||
|
.build())
|
||||||
|
.appendObj("environmentData", DataSpecBuilder()
|
||||||
|
.append("base")
|
||||||
|
.append("icons")
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
let rawData = try nsRawData.decompressed(using: .lzfse)
|
||||||
|
|
||||||
|
let watchDTO = try decoder.decode(WatchDTO.self, from: Data(referencing: rawData))
|
||||||
|
|
||||||
let previousUserId = StateService.shared.getUser()?.id
|
let previousUserId = StateService.shared.getUser()?.id
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,18 @@
|
||||||
1B15615B28B7F3D900610B9B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1B15615A28B7F3D900610B9B /* Preview Assets.xcassets */; };
|
1B15615B28B7F3D900610B9B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1B15615A28B7F3D900610B9B /* Preview Assets.xcassets */; };
|
||||||
1B15616C28B81A2200610B9B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B15616B28B81A2200610B9B /* Cipher.swift */; };
|
1B15616C28B81A2200610B9B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B15616B28B81A2200610B9B /* Cipher.swift */; };
|
||||||
1B15616E28B81A4300610B9B /* WatchConnectivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B15616D28B81A4300610B9B /* WatchConnectivityManager.swift */; };
|
1B15616E28B81A4300610B9B /* WatchConnectivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B15616D28B81A4300610B9B /* WatchConnectivityManager.swift */; };
|
||||||
|
1B2A484029A90D9B00621E13 /* FixedWidthInteger+Bytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483229A90D9B00621E13 /* FixedWidthInteger+Bytes.swift */; };
|
||||||
|
1B2A484129A90D9B00621E13 /* UnkeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483429A90D9B00621E13 /* UnkeyedEncodingContainer.swift */; };
|
||||||
|
1B2A484229A90D9B00621E13 /* SingleValueEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483529A90D9B00621E13 /* SingleValueEncodingContainer.swift */; };
|
||||||
|
1B2A484329A90D9B00621E13 /* KeyedEncodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483629A90D9B00621E13 /* KeyedEncodingContainer.swift */; };
|
||||||
|
1B2A484429A90D9B00621E13 /* MessagePackEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483729A90D9B00621E13 /* MessagePackEncoder.swift */; };
|
||||||
|
1B2A484529A90D9B00621E13 /* KeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483929A90D9B00621E13 /* KeyedDecodingContainer.swift */; };
|
||||||
|
1B2A484629A90D9B00621E13 /* SingleValueDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483A29A90D9B00621E13 /* SingleValueDecodingContainer.swift */; };
|
||||||
|
1B2A484729A90D9B00621E13 /* MessagePackDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483B29A90D9B00621E13 /* MessagePackDecoder.swift */; };
|
||||||
|
1B2A484829A90D9B00621E13 /* UnkeyedDecodingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483C29A90D9B00621E13 /* UnkeyedDecodingContainer.swift */; };
|
||||||
|
1B2A484929A90D9B00621E13 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483D29A90D9B00621E13 /* Box.swift */; };
|
||||||
|
1B2A484A29A90D9B00621E13 /* DataSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483E29A90D9B00621E13 /* DataSpec.swift */; };
|
||||||
|
1B2A484B29A90D9B00621E13 /* AnyCodingKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2A483F29A90D9B00621E13 /* AnyCodingKey.swift */; };
|
||||||
1B5849A7294D1C020055286B /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B5849A6294D1C020055286B /* Queue.swift */; };
|
1B5849A7294D1C020055286B /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B5849A6294D1C020055286B /* Queue.swift */; };
|
||||||
1B59EC5729007DEE00A8718D /* BitwardenDB.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1B59EC5529007DEE00A8718D /* BitwardenDB.xcdatamodeld */; };
|
1B59EC5729007DEE00A8718D /* BitwardenDB.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1B59EC5529007DEE00A8718D /* BitwardenDB.xcdatamodeld */; };
|
||||||
1B59EC592900801500A8718D /* StringEncryptionTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B59EC582900801500A8718D /* StringEncryptionTransformer.swift */; };
|
1B59EC592900801500A8718D /* StringEncryptionTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B59EC582900801500A8718D /* StringEncryptionTransformer.swift */; };
|
||||||
|
@ -140,6 +152,18 @@
|
||||||
1B15615D28B7F3D900610B9B /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
|
1B15615D28B7F3D900610B9B /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
|
||||||
1B15616B28B81A2200610B9B /* Cipher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = "<group>"; };
|
1B15616B28B81A2200610B9B /* Cipher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = "<group>"; };
|
||||||
1B15616D28B81A4300610B9B /* WatchConnectivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConnectivityManager.swift; sourceTree = "<group>"; };
|
1B15616D28B81A4300610B9B /* WatchConnectivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConnectivityManager.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483229A90D9B00621E13 /* FixedWidthInteger+Bytes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FixedWidthInteger+Bytes.swift"; sourceTree = "<group>"; };
|
||||||
|
1B2A483429A90D9B00621E13 /* UnkeyedEncodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnkeyedEncodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483529A90D9B00621E13 /* SingleValueEncodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleValueEncodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483629A90D9B00621E13 /* KeyedEncodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedEncodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483729A90D9B00621E13 /* MessagePackEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePackEncoder.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483929A90D9B00621E13 /* KeyedDecodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyedDecodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483A29A90D9B00621E13 /* SingleValueDecodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleValueDecodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483B29A90D9B00621E13 /* MessagePackDecoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePackDecoder.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483C29A90D9B00621E13 /* UnkeyedDecodingContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnkeyedDecodingContainer.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483D29A90D9B00621E13 /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483E29A90D9B00621E13 /* DataSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataSpec.swift; sourceTree = "<group>"; };
|
||||||
|
1B2A483F29A90D9B00621E13 /* AnyCodingKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodingKey.swift; sourceTree = "<group>"; };
|
||||||
1B5849A6294D1C020055286B /* Queue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = "<group>"; };
|
1B5849A6294D1C020055286B /* Queue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = "<group>"; };
|
||||||
1B5849A92950BC860055286B /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS9.1.sdk/System/Library/Frameworks/LocalAuthentication.framework; sourceTree = DEVELOPER_DIR; };
|
1B5849A92950BC860055286B /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS9.1.sdk/System/Library/Frameworks/LocalAuthentication.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
1B59EC5629007DEE00A8718D /* BitwardenDB.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = BitwardenDB.xcdatamodel; sourceTree = "<group>"; };
|
1B59EC5629007DEE00A8718D /* BitwardenDB.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = BitwardenDB.xcdatamodel; sourceTree = "<group>"; };
|
||||||
|
@ -288,6 +312,7 @@
|
||||||
1B15614C28B7F3D800610B9B /* bitwarden WatchKit Extension */ = {
|
1B15614C28B7F3D800610B9B /* bitwarden WatchKit Extension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1B2A483129A90D9B00621E13 /* MessagePack */,
|
||||||
1B8BF9072919A2BC006F069E /* Controls */,
|
1B8BF9072919A2BC006F069E /* Controls */,
|
||||||
1B5AFF0629197809004478F9 /* Localization */,
|
1B5AFF0629197809004478F9 /* Localization */,
|
||||||
1B59EC5F2900C48300A8718D /* Helpers */,
|
1B59EC5F2900C48300A8718D /* Helpers */,
|
||||||
|
@ -320,6 +345,42 @@
|
||||||
path = "Preview Content";
|
path = "Preview Content";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
1B2A483129A90D9B00621E13 /* MessagePack */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1B2A483229A90D9B00621E13 /* FixedWidthInteger+Bytes.swift */,
|
||||||
|
1B2A483329A90D9B00621E13 /* Encoder */,
|
||||||
|
1B2A483829A90D9B00621E13 /* Decoder */,
|
||||||
|
1B2A483D29A90D9B00621E13 /* Box.swift */,
|
||||||
|
1B2A483E29A90D9B00621E13 /* DataSpec.swift */,
|
||||||
|
1B2A483F29A90D9B00621E13 /* AnyCodingKey.swift */,
|
||||||
|
);
|
||||||
|
name = MessagePack;
|
||||||
|
path = ../../../../lib/MessagePack/Sources/MessagePack;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1B2A483329A90D9B00621E13 /* Encoder */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1B2A483429A90D9B00621E13 /* UnkeyedEncodingContainer.swift */,
|
||||||
|
1B2A483529A90D9B00621E13 /* SingleValueEncodingContainer.swift */,
|
||||||
|
1B2A483629A90D9B00621E13 /* KeyedEncodingContainer.swift */,
|
||||||
|
1B2A483729A90D9B00621E13 /* MessagePackEncoder.swift */,
|
||||||
|
);
|
||||||
|
path = Encoder;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1B2A483829A90D9B00621E13 /* Decoder */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1B2A483929A90D9B00621E13 /* KeyedDecodingContainer.swift */,
|
||||||
|
1B2A483A29A90D9B00621E13 /* SingleValueDecodingContainer.swift */,
|
||||||
|
1B2A483B29A90D9B00621E13 /* MessagePackDecoder.swift */,
|
||||||
|
1B2A483C29A90D9B00621E13 /* UnkeyedDecodingContainer.swift */,
|
||||||
|
);
|
||||||
|
path = Decoder;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
1B5849A82950BC860055286B /* Frameworks */ = {
|
1B5849A82950BC860055286B /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -584,8 +645,12 @@
|
||||||
1BDBFEAC290B4215009C78C7 /* CipherListViewModel.swift in Sources */,
|
1BDBFEAC290B4215009C78C7 /* CipherListViewModel.swift in Sources */,
|
||||||
1BF5F6DB29103066002DDC0C /* CipherService.swift in Sources */,
|
1BF5F6DB29103066002DDC0C /* CipherService.swift in Sources */,
|
||||||
1B5F5E3E293FBB17009B5FCC /* CipherItemView.swift in Sources */,
|
1B5F5E3E293FBB17009B5FCC /* CipherItemView.swift in Sources */,
|
||||||
|
1B2A484629A90D9B00621E13 /* SingleValueDecodingContainer.swift in Sources */,
|
||||||
1B15616C28B81A2200610B9B /* Cipher.swift in Sources */,
|
1B15616C28B81A2200610B9B /* Cipher.swift in Sources */,
|
||||||
|
1B2A484A29A90D9B00621E13 /* DataSpec.swift in Sources */,
|
||||||
1B8BF90429199BBB006F069E /* CipherDetailsView.swift in Sources */,
|
1B8BF90429199BBB006F069E /* CipherDetailsView.swift in Sources */,
|
||||||
|
1B2A484229A90D9B00621E13 /* SingleValueEncodingContainer.swift in Sources */,
|
||||||
|
1B2A484929A90D9B00621E13 /* Box.swift in Sources */,
|
||||||
1B8BF9112919CDBB006F069E /* DateExtensions.swift in Sources */,
|
1B8BF9112919CDBB006F069E /* DateExtensions.swift in Sources */,
|
||||||
1BD291BB2927E9B50004F33F /* WatchDTO.swift in Sources */,
|
1BD291BB2927E9B50004F33F /* WatchDTO.swift in Sources */,
|
||||||
1B11C899291BFAB500CE58D8 /* CryptoFunctionService.swift in Sources */,
|
1B11C899291BFAB500CE58D8 /* CryptoFunctionService.swift in Sources */,
|
||||||
|
@ -595,32 +660,40 @@
|
||||||
1BD291BD292807240004F33F /* User.swift in Sources */,
|
1BD291BD292807240004F33F /* User.swift in Sources */,
|
||||||
1BDBFEB3290B5D07009C78C7 /* CoreDataHelper.swift in Sources */,
|
1BDBFEB3290B5D07009C78C7 /* CoreDataHelper.swift in Sources */,
|
||||||
1B15615028B7F3D800610B9B /* CipherListView.swift in Sources */,
|
1B15615028B7F3D800610B9B /* CipherListView.swift in Sources */,
|
||||||
|
1B2A484529A90D9B00621E13 /* KeyedDecodingContainer.swift in Sources */,
|
||||||
|
1B2A484329A90D9B00621E13 /* KeyedEncodingContainer.swift in Sources */,
|
||||||
1BD291BF292D0E6F0004F33F /* JsonDecoderExtensions.swift in Sources */,
|
1BD291BF292D0E6F0004F33F /* JsonDecoderExtensions.swift in Sources */,
|
||||||
1B59EC632901B1C100A8718D /* LoggerHelper.swift in Sources */,
|
1B59EC632901B1C100A8718D /* LoggerHelper.swift in Sources */,
|
||||||
1BD291C329311E1C0004F33F /* VaultTimeoutAction.swift in Sources */,
|
1BD291C329311E1C0004F33F /* VaultTimeoutAction.swift in Sources */,
|
||||||
1B15615628B7F3D800610B9B /* ComplicationController.swift in Sources */,
|
1B15615628B7F3D800610B9B /* ComplicationController.swift in Sources */,
|
||||||
|
1B2A484129A90D9B00621E13 /* UnkeyedEncodingContainer.swift in Sources */,
|
||||||
1BD291B9292438830004F33F /* StateService.swift in Sources */,
|
1BD291B9292438830004F33F /* StateService.swift in Sources */,
|
||||||
1BC1CD6329227D3C006540DA /* EnvironmentService.swift in Sources */,
|
1BC1CD6329227D3C006540DA /* EnvironmentService.swift in Sources */,
|
||||||
1B8BF9092919A2CC006F069E /* CircularProgressView.swift in Sources */,
|
1B8BF9092919A2CC006F069E /* CircularProgressView.swift in Sources */,
|
||||||
|
1B2A484B29A90D9B00621E13 /* AnyCodingKey.swift in Sources */,
|
||||||
1BD291B7292409410004F33F /* BWState.swift in Sources */,
|
1BD291B7292409410004F33F /* BWState.swift in Sources */,
|
||||||
1B15614E28B7F3D800610B9B /* bitwardenApp.swift in Sources */,
|
1B15614E28B7F3D800610B9B /* bitwardenApp.swift in Sources */,
|
||||||
1BC1CD6929228CEB006540DA /* StringExtensions.swift in Sources */,
|
1BC1CD6929228CEB006540DA /* StringExtensions.swift in Sources */,
|
||||||
1BDBFEB1290B5BD3009C78C7 /* DBHelperProtocol.swift in Sources */,
|
1BDBFEB1290B5BD3009C78C7 /* DBHelperProtocol.swift in Sources */,
|
||||||
|
1B2A484429A90D9B00621E13 /* MessagePackEncoder.swift in Sources */,
|
||||||
1B8BF90629199EC5006F069E /* CipherDetailsViewModel.swift in Sources */,
|
1B8BF90629199EC5006F069E /* CipherDetailsViewModel.swift in Sources */,
|
||||||
1BF5F6DE29103B86002DDC0C /* CipherServiceMock.swift in Sources */,
|
1BF5F6DE29103B86002DDC0C /* CipherServiceMock.swift in Sources */,
|
||||||
1BC1CD672922871A006540DA /* URLExtensions.swift in Sources */,
|
1BC1CD672922871A006540DA /* URLExtensions.swift in Sources */,
|
||||||
1B11C89B291C587600CE58D8 /* UInt64Extensions.swift in Sources */,
|
1B11C89B291C587600CE58D8 /* UInt64Extensions.swift in Sources */,
|
||||||
1B8453ED290C672E00F921E1 /* CipherEntity+CoreDataProperties.swift in Sources */,
|
1B8453ED290C672E00F921E1 /* CipherEntity+CoreDataProperties.swift in Sources */,
|
||||||
|
1B2A484029A90D9B00621E13 /* FixedWidthInteger+Bytes.swift in Sources */,
|
||||||
1BC1CD6E2922B92B006540DA /* ImageView.swift in Sources */,
|
1BC1CD6E2922B92B006540DA /* ImageView.swift in Sources */,
|
||||||
1BD291C1292E7E690004F33F /* ErrorExtensions.swift in Sources */,
|
1BD291C1292E7E690004F33F /* ErrorExtensions.swift in Sources */,
|
||||||
1B14DF37291186D900EA43F1 /* EmptyStateViewModifier.swift in Sources */,
|
1B14DF37291186D900EA43F1 /* EmptyStateViewModifier.swift in Sources */,
|
||||||
1BD291B52924047C0004F33F /* BWStateViewModel.swift in Sources */,
|
1BD291B52924047C0004F33F /* BWStateViewModel.swift in Sources */,
|
||||||
1B5849A7294D1C020055286B /* Queue.swift in Sources */,
|
1B5849A7294D1C020055286B /* Queue.swift in Sources */,
|
||||||
1B15616E28B81A4300610B9B /* WatchConnectivityManager.swift in Sources */,
|
1B15616E28B81A4300610B9B /* WatchConnectivityManager.swift in Sources */,
|
||||||
|
1B2A484829A90D9B00621E13 /* UnkeyedDecodingContainer.swift in Sources */,
|
||||||
1B5AFF0329196C81004478F9 /* ColorUtils.swift in Sources */,
|
1B5AFF0329196C81004478F9 /* ColorUtils.swift in Sources */,
|
||||||
1B59EC612900C48E00A8718D /* KeychainHelper.swift in Sources */,
|
1B59EC612900C48E00A8718D /* KeychainHelper.swift in Sources */,
|
||||||
1B5BE453295A08C600E0C323 /* ExtensionDelegate.swift in Sources */,
|
1B5BE453295A08C600E0C323 /* ExtensionDelegate.swift in Sources */,
|
||||||
1B59EC5729007DEE00A8718D /* BitwardenDB.xcdatamodeld in Sources */,
|
1B59EC5729007DEE00A8718D /* BitwardenDB.xcdatamodeld in Sources */,
|
||||||
|
1B2A484729A90D9B00621E13 /* MessagePackDecoder.swift in Sources */,
|
||||||
1B8BF90D2919BED9006F069E /* Base32.swift in Sources */,
|
1B8BF90D2919BED9006F069E /* Base32.swift in Sources */,
|
||||||
1B8453EC290C672E00F921E1 /* CipherEntity+CoreDataClass.swift in Sources */,
|
1B8453EC290C672E00F921E1 /* CipherEntity+CoreDataClass.swift in Sources */,
|
||||||
1BC1CD6529227F3C006540DA /* IconImageHelper.swift in Sources */,
|
1BC1CD6529227F3C006540DA /* IconImageHelper.swift in Sources */,
|
||||||
|
|
Loading…
Reference in a new issue