mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 23:31:52 +03:00
updates
This commit is contained in:
parent
bc3d9c4465
commit
e05ed4c1f2
33 changed files with 298 additions and 77 deletions
|
@ -94,6 +94,14 @@
|
||||||
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll</HintPath>
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings.Abstractions, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
|
|
@ -12,6 +12,7 @@ using Bit.App.Services;
|
||||||
using XLabs.Ioc.Unity;
|
using XLabs.Ioc.Unity;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
using Bit.Android.Services;
|
using Bit.Android.Services;
|
||||||
|
using Plugin.Settings;
|
||||||
|
|
||||||
namespace Bit.Android
|
namespace Bit.Android
|
||||||
{
|
{
|
||||||
|
@ -40,6 +41,7 @@ namespace Bit.Android
|
||||||
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<ISecureStorageService, KeyStoreStorageService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ISecureStorageService, KeyStoreStorageService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="monoandroid60" />
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="monoandroid60" />
|
||||||
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="monoandroid60" />
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="monoandroid60" />
|
||||||
<package id="Unity" version="3.5.1405-prerelease" targetFramework="monoandroid60" />
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xam.Plugins.Settings" version="2.1.0" targetFramework="monoandroid60" />
|
||||||
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
|
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
|
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
|
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
|
|
@ -7,7 +7,9 @@ namespace Bit.App.Abstractions
|
||||||
{
|
{
|
||||||
bool IsAuthenticated { get; }
|
bool IsAuthenticated { get; }
|
||||||
string Token { get; set; }
|
string Token { get; set; }
|
||||||
|
string UserId { get; set; }
|
||||||
|
|
||||||
|
void LogOut();
|
||||||
Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request);
|
Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Views;
|
using Bit.App.Pages;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App
|
namespace Bit.App
|
||||||
|
@ -11,26 +11,20 @@ namespace Bit.App
|
||||||
public class App : Application
|
public class App : Application
|
||||||
{
|
{
|
||||||
private readonly IDatabaseService _databaseService;
|
private readonly IDatabaseService _databaseService;
|
||||||
|
private readonly IAuthService _authService;
|
||||||
|
|
||||||
public App(IAuthService authService, IDatabaseService databaseService)
|
public App(IAuthService authService, IDatabaseService databaseService)
|
||||||
{
|
{
|
||||||
_databaseService = databaseService;
|
_databaseService = databaseService;
|
||||||
|
_authService = authService;
|
||||||
|
|
||||||
if(authService.IsAuthenticated)
|
if(authService.IsAuthenticated)
|
||||||
{
|
{
|
||||||
var nav = new NavigationPage(new VaultListPage());
|
MainPage = new MainPage();
|
||||||
nav.BarBackgroundColor = Color.FromHex("3c8dbc");
|
|
||||||
nav.BarTextColor = Color.FromHex("ffffff");
|
|
||||||
|
|
||||||
MainPage = nav;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var nav = new NavigationPage(new LoginPage());
|
MainPage = new LoginNavigationPage();
|
||||||
nav.BarBackgroundColor = Color.FromHex("3c8dbc");
|
|
||||||
nav.BarTextColor = Color.FromHex("ffffff");
|
|
||||||
|
|
||||||
MainPage = nav;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainPage.BackgroundColor = Color.FromHex("ecf0f5");
|
MainPage.BackgroundColor = Color.FromHex("ecf0f5");
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
<Compile Include="Models\Data\SiteData.cs" />
|
<Compile Include="Models\Data\SiteData.cs" />
|
||||||
<Compile Include="Models\Folder.cs" />
|
<Compile Include="Models\Folder.cs" />
|
||||||
<Compile Include="Models\Site.cs" />
|
<Compile Include="Models\Site.cs" />
|
||||||
|
<Compile Include="Pages\LoginNavigationPage.cs" />
|
||||||
|
<Compile Include="Pages\MainPage.cs" />
|
||||||
|
<Compile Include="Pages\SyncPage.cs" />
|
||||||
|
<Compile Include="Pages\SettingsPage.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\DatabaseService.cs" />
|
<Compile Include="Services\DatabaseService.cs" />
|
||||||
<Compile Include="Services\FolderService.cs" />
|
<Compile Include="Services\FolderService.cs" />
|
||||||
|
@ -105,6 +109,14 @@
|
||||||
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\Plugin.Settings.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings.Abstractions, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
|
|
@ -5,6 +5,5 @@ namespace Bit.App.Models.Api
|
||||||
public class ApiError
|
public class ApiError
|
||||||
{
|
{
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
public HttpStatusCode StatusCode { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Bit.App.Models.Api
|
namespace Bit.App.Models.Api
|
||||||
{
|
{
|
||||||
|
@ -9,19 +10,26 @@ namespace Bit.App.Models.Api
|
||||||
public bool Succeeded { get; private set; }
|
public bool Succeeded { get; private set; }
|
||||||
public T Result { get; set; }
|
public T Result { get; set; }
|
||||||
public IEnumerable<ApiError> Errors => m_errors;
|
public IEnumerable<ApiError> Errors => m_errors;
|
||||||
|
public HttpStatusCode StatusCode { get; private set; }
|
||||||
|
|
||||||
public static ApiResult<T> Success(T result)
|
public static ApiResult<T> Success(T result, HttpStatusCode statusCode)
|
||||||
{
|
{
|
||||||
return new ApiResult<T>
|
return new ApiResult<T>
|
||||||
{
|
{
|
||||||
Succeeded = true,
|
Succeeded = true,
|
||||||
Result = result
|
Result = result,
|
||||||
|
StatusCode = statusCode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ApiResult<T> Failed(params ApiError[] errors)
|
public static ApiResult<T> Failed(HttpStatusCode statusCode, params ApiError[] errors)
|
||||||
{
|
{
|
||||||
var result = new ApiResult<T> { Succeeded = false };
|
var result = new ApiResult<T>
|
||||||
|
{
|
||||||
|
Succeeded = false,
|
||||||
|
StatusCode = statusCode
|
||||||
|
};
|
||||||
|
|
||||||
if(errors != null)
|
if(errors != null)
|
||||||
{
|
{
|
||||||
result.m_errors.AddRange(errors);
|
result.m_errors.AddRange(errors);
|
||||||
|
|
|
@ -10,10 +10,11 @@ namespace Bit.App.Models.Data
|
||||||
public FolderData()
|
public FolderData()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public FolderData(Folder folder)
|
public FolderData(Folder folder, string userId)
|
||||||
{
|
{
|
||||||
Id = folder.Id;
|
Id = folder.Id;
|
||||||
ServerId = folder.ServerId;
|
ServerId = folder.ServerId;
|
||||||
|
UserId = userId;
|
||||||
Name = folder.Name?.EncryptedString;
|
Name = folder.Name?.EncryptedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ namespace Bit.App.Models.Data
|
||||||
[AutoIncrement]
|
[AutoIncrement]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string ServerId { get; set; }
|
public string ServerId { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,13 @@ namespace Bit.App.Models.Data
|
||||||
public SiteData()
|
public SiteData()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public SiteData(Site site)
|
public SiteData(Site site, string userId)
|
||||||
{
|
{
|
||||||
Id = site.Id;
|
Id = site.Id;
|
||||||
ServerId = site.ServerId;
|
ServerId = site.ServerId;
|
||||||
FolderId = site.FolderId;
|
FolderId = site.FolderId;
|
||||||
ServerFolderId = site.ServerFolderId;
|
ServerFolderId = site.ServerFolderId;
|
||||||
|
UserId = userId;
|
||||||
Name = site.Name?.EncryptedString;
|
Name = site.Name?.EncryptedString;
|
||||||
Uri = site.Uri?.EncryptedString;
|
Uri = site.Uri?.EncryptedString;
|
||||||
Username = site.Username?.EncryptedString;
|
Username = site.Username?.EncryptedString;
|
||||||
|
@ -29,6 +30,7 @@ namespace Bit.App.Models.Data
|
||||||
public string ServerId { get; set; }
|
public string ServerId { get; set; }
|
||||||
public int? FolderId { get; set; }
|
public int? FolderId { get; set; }
|
||||||
public string ServerFolderId { get; set; }
|
public string ServerFolderId { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
|
@ -21,9 +21,9 @@ namespace Bit.App.Models
|
||||||
Name = response.Name != null ? new CipherString(response.Name) : null;
|
Name = response.Name != null ? new CipherString(response.Name) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FolderData ToFolderData()
|
public FolderData ToFolderData(string userId)
|
||||||
{
|
{
|
||||||
return new FolderData(this);
|
return new FolderData(this, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ namespace Bit.App.Models
|
||||||
public CipherString Password { get; set; }
|
public CipherString Password { get; set; }
|
||||||
public CipherString Notes { get; set; }
|
public CipherString Notes { get; set; }
|
||||||
|
|
||||||
public SiteData ToSiteData()
|
public SiteData ToSiteData(string userId)
|
||||||
{
|
{
|
||||||
return new SiteData(this);
|
return new SiteData(this, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/App/Pages/LoginNavigationPage.cs
Normal file
15
src/App/Pages/LoginNavigationPage.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public class LoginNavigationPage : NavigationPage
|
||||||
|
{
|
||||||
|
public LoginNavigationPage()
|
||||||
|
: base(new LoginPage())
|
||||||
|
{
|
||||||
|
BarBackgroundColor = Color.FromHex("3c8dbc");
|
||||||
|
BarTextColor = Color.FromHex("ffffff");
|
||||||
|
Title = "Login";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ using Bit.App.Models.Api;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class LoginPage : ContentPage
|
public class LoginPage : ContentPage
|
||||||
{
|
{
|
||||||
|
@ -63,12 +63,15 @@ namespace Bit.App.Views
|
||||||
var response = await authService.TokenPostAsync(request);
|
var response = await authService.TokenPostAsync(request);
|
||||||
if(!response.Succeeded)
|
if(!response.Succeeded)
|
||||||
{
|
{
|
||||||
throw new Exception();
|
await DisplayAlert("An error occurred", response.Errors.First().Message, "Ok");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cryptoService.Key = key;
|
cryptoService.Key = key;
|
||||||
authService.Token = response.Result.Token;
|
authService.Token = response.Result.Token;
|
||||||
await Navigation.PushAsync(new VaultListPage());
|
authService.UserId = response.Result.Profile.Id;
|
||||||
|
|
||||||
|
Application.Current.MainPage = new MainPage();
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
26
src/App/Pages/MainPage.cs
Normal file
26
src/App/Pages/MainPage.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public class MainPage : TabbedPage
|
||||||
|
{
|
||||||
|
public MainPage()
|
||||||
|
{
|
||||||
|
var vaultNavigation = new NavigationPage(new VaultListPage());
|
||||||
|
vaultNavigation.BarBackgroundColor = Color.FromHex("3c8dbc");
|
||||||
|
vaultNavigation.BarTextColor = Color.FromHex("ffffff");
|
||||||
|
vaultNavigation.Title = "My Vault";
|
||||||
|
|
||||||
|
var settingsNavigation = new NavigationPage(new SettingsPage());
|
||||||
|
settingsNavigation.BarBackgroundColor = Color.FromHex("3c8dbc");
|
||||||
|
settingsNavigation.BarTextColor = Color.FromHex("ffffff");
|
||||||
|
settingsNavigation.Title = "Settings";
|
||||||
|
|
||||||
|
Children.Add(vaultNavigation);
|
||||||
|
Children.Add(new SyncPage());
|
||||||
|
Children.Add(settingsNavigation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/App/Pages/SettingsPage.cs
Normal file
34
src/App/Pages/SettingsPage.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public class SettingsPage : ContentPage
|
||||||
|
{
|
||||||
|
private ListView _listView = new ListView();
|
||||||
|
|
||||||
|
public SettingsPage()
|
||||||
|
{
|
||||||
|
var authService = Resolver.Resolve<IAuthService>();
|
||||||
|
|
||||||
|
var logoutButton = new Button
|
||||||
|
{
|
||||||
|
Text = "Log Out",
|
||||||
|
Command = new Command(() =>
|
||||||
|
{
|
||||||
|
authService.LogOut();
|
||||||
|
Application.Current.MainPage = new LoginNavigationPage();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
var stackLayout = new StackLayout { };
|
||||||
|
stackLayout.Children.Add(logoutButton);
|
||||||
|
|
||||||
|
Title = "Settings";
|
||||||
|
Content = stackLayout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/App/Pages/SyncPage.cs
Normal file
14
src/App/Pages/SyncPage.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public class SyncPage : ContentPage
|
||||||
|
{
|
||||||
|
public SyncPage()
|
||||||
|
{
|
||||||
|
Title = "Sync";
|
||||||
|
Content = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ using Bit.App.Models;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultAddFolderPage : ContentPage
|
public class VaultAddFolderPage : ContentPage
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ using Bit.App.Models;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultAddSitePage : ContentPage
|
public class VaultAddSitePage : ContentPage
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultEditFolderPage : ContentPage
|
public class VaultEditFolderPage : ContentPage
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultEditSitePage : ContentPage
|
public class VaultEditSitePage : ContentPage
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,13 +7,13 @@ using Bit.App.Models.View;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultListPage : ContentPage
|
public class VaultListPage : ContentPage
|
||||||
{
|
{
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly ISiteService _siteService;
|
private readonly ISiteService _siteService;
|
||||||
private ListView _listView;
|
private ListView _listView = new ListView();
|
||||||
|
|
||||||
public VaultListPage()
|
public VaultListPage()
|
||||||
{
|
{
|
||||||
|
@ -28,12 +28,8 @@ namespace Bit.App.Views
|
||||||
|
|
||||||
ToolbarItems.Add(addSiteToolBarItem);
|
ToolbarItems.Add(addSiteToolBarItem);
|
||||||
|
|
||||||
_listView = new ListView
|
_listView.IsGroupingEnabled = true;
|
||||||
{
|
_listView.GroupDisplayBinding = new Binding("Name");
|
||||||
IsGroupingEnabled = true,
|
|
||||||
GroupDisplayBinding = new Binding("Name")
|
|
||||||
};
|
|
||||||
|
|
||||||
_listView.ItemSelected += FolderSelected;
|
_listView.ItemSelected += FolderSelected;
|
||||||
_listView.ItemTemplate = new DataTemplate(() =>
|
_listView.ItemTemplate = new DataTemplate(() =>
|
||||||
{
|
{
|
||||||
|
@ -45,7 +41,6 @@ namespace Bit.App.Views
|
||||||
|
|
||||||
Title = "My Vault";
|
Title = "My Vault";
|
||||||
Content = _listView;
|
Content = _listView;
|
||||||
NavigationPage.SetHasBackButton(this, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Views
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultViewSitePage : ContentPage
|
public class VaultViewSitePage : ContentPage
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
@ -20,21 +21,26 @@ namespace Bit.App.Services
|
||||||
|
|
||||||
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
var error = new ApiError
|
|
||||||
{
|
|
||||||
Message = "An unknown error has occured.",
|
|
||||||
StatusCode = response.StatusCode
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent);
|
var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent);
|
||||||
error.Message = errorResponseModel.Message;
|
|
||||||
}
|
|
||||||
catch(JsonReaderException) { }
|
|
||||||
|
|
||||||
return ApiResult<T>.Failed(error);
|
var errors = new List<ApiError>();
|
||||||
|
foreach(var valError in errorResponseModel.ValidationErrors)
|
||||||
|
{
|
||||||
|
foreach(var errorMessage in valError.Value)
|
||||||
|
{
|
||||||
|
errors.Add(new ApiError { Message = errorMessage });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ApiResult<T>.Failed(response.StatusCode, errors.ToArray());
|
||||||
|
}
|
||||||
|
catch(JsonReaderException)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
return ApiResult<T>.Failed(response.StatusCode, new ApiError { Message = "An unknown error has occured." });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,31 @@ using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.Api;
|
using Bit.App.Models.Api;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Plugin.Settings.Abstractions;
|
||||||
|
|
||||||
namespace Bit.App.Services
|
namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
public class AuthService : IAuthService
|
public class AuthService : IAuthService
|
||||||
{
|
{
|
||||||
private const string TokenKey = "token";
|
private const string TokenKey = "token";
|
||||||
|
private const string UserIdKey = "userId";
|
||||||
|
|
||||||
private readonly ISecureStorageService _secureStorage;
|
private readonly ISecureStorageService _secureStorage;
|
||||||
|
private readonly ISettings _settings;
|
||||||
private readonly ICryptoService _cryptoService;
|
private readonly ICryptoService _cryptoService;
|
||||||
private readonly IApiService _apiService;
|
private readonly IApiService _apiService;
|
||||||
|
|
||||||
|
private string _token;
|
||||||
|
private string _userId;
|
||||||
|
|
||||||
public AuthService(
|
public AuthService(
|
||||||
ISecureStorageService secureStorage,
|
ISecureStorageService secureStorage,
|
||||||
|
ISettings settings,
|
||||||
ICryptoService cryptoService,
|
ICryptoService cryptoService,
|
||||||
IApiService apiService)
|
IApiService apiService)
|
||||||
{
|
{
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = secureStorage;
|
||||||
|
_settings = settings;
|
||||||
_cryptoService = cryptoService;
|
_cryptoService = cryptoService;
|
||||||
_apiService = apiService;
|
_apiService = apiService;
|
||||||
}
|
}
|
||||||
|
@ -30,8 +38,19 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if(_token != null)
|
||||||
|
{
|
||||||
|
return _token;
|
||||||
|
}
|
||||||
|
|
||||||
var tokenBytes = _secureStorage.Retrieve(TokenKey);
|
var tokenBytes = _secureStorage.Retrieve(TokenKey);
|
||||||
return Encoding.UTF8.GetString(tokenBytes, 0, tokenBytes.Length);
|
if(tokenBytes == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_token = Encoding.UTF8.GetString(tokenBytes, 0, tokenBytes.Length);
|
||||||
|
return _token;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -43,6 +62,33 @@ namespace Bit.App.Services
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_secureStorage.Delete(TokenKey);
|
_secureStorage.Delete(TokenKey);
|
||||||
|
_token = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_userId != null)
|
||||||
|
{
|
||||||
|
return _userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
_userId = _settings.GetValueOrDefault<string>(UserIdKey);
|
||||||
|
return _userId;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
_settings.AddOrUpdateValue(UserIdKey, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_settings.Remove(UserIdKey);
|
||||||
|
_userId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,10 +97,17 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _cryptoService.Key != null && Token != null;
|
return _cryptoService.Key != null && Token != null && UserId != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LogOut()
|
||||||
|
{
|
||||||
|
Token = null;
|
||||||
|
UserId = null;
|
||||||
|
_cryptoService.Key = null;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request)
|
public async Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request)
|
||||||
{
|
{
|
||||||
var requestContent = JsonConvert.SerializeObject(request);
|
var requestContent = JsonConvert.SerializeObject(request);
|
||||||
|
@ -66,7 +119,7 @@ namespace Bit.App.Services
|
||||||
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||||
return ApiResult<TokenResponse>.Success(responseObj);
|
return ApiResult<TokenResponse>.Success(responseObj, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,30 @@ namespace Bit.App.Services
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_secureStorage.Store(KeyKey, value);
|
if(value != null)
|
||||||
_keyParameter = new KeyParameter(value);
|
{
|
||||||
|
_secureStorage.Store(KeyKey, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_secureStorage.Delete(KeyKey);
|
||||||
|
_keyParameter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Base64Key
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(Key == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ToBase64String(Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string Base64Key { get { return Convert.ToBase64String(Key); } }
|
|
||||||
|
|
||||||
public CipherString Encrypt(string plaintextValue)
|
public CipherString Encrypt(string plaintextValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,18 +10,25 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
public class FolderService : Repository<FolderData, int>, IFolderService
|
public class FolderService : Repository<FolderData, int>, IFolderService
|
||||||
{
|
{
|
||||||
public FolderService(ISqlService sqlite)
|
private readonly IAuthService _authService;
|
||||||
: base(sqlite) { }
|
|
||||||
|
|
||||||
public new async Task<IEnumerable<Folder>> GetAllAsync()
|
public FolderService(
|
||||||
|
ISqlService sqlService,
|
||||||
|
IAuthService authService)
|
||||||
|
: base(sqlService)
|
||||||
{
|
{
|
||||||
var data = await base.GetAllAsync();
|
_authService = authService;
|
||||||
return data.Select(f => new Folder(f));
|
}
|
||||||
|
|
||||||
|
public new Task<IEnumerable<Folder>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var data = Connection.Table<FolderData>().Where(f => f.UserId == _authService.UserId).Cast<FolderData>();
|
||||||
|
return Task.FromResult(data.Select(f => new Folder(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveAsync(Folder folder)
|
public async Task SaveAsync(Folder folder)
|
||||||
{
|
{
|
||||||
var data = new FolderData(folder);
|
var data = new FolderData(folder, _authService.UserId);
|
||||||
data.RevisionDateTime = DateTime.UtcNow;
|
data.RevisionDateTime = DateTime.UtcNow;
|
||||||
|
|
||||||
if(folder.Id == 0)
|
if(folder.Id == 0)
|
||||||
|
|
|
@ -11,38 +11,38 @@ namespace Bit.App.Services
|
||||||
where TId : IEquatable<TId>
|
where TId : IEquatable<TId>
|
||||||
where T : class, IDataObject<TId>, new()
|
where T : class, IDataObject<TId>, new()
|
||||||
{
|
{
|
||||||
protected readonly SQLiteConnection _connection;
|
public Repository(ISqlService sqlService)
|
||||||
|
|
||||||
public Repository(ISqlService sqlite)
|
|
||||||
{
|
{
|
||||||
_connection = sqlite.GetConnection();
|
Connection = sqlService.GetConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SQLiteConnection Connection { get; private set; }
|
||||||
|
|
||||||
protected virtual Task<T> GetByIdAsync(TId id)
|
protected virtual Task<T> GetByIdAsync(TId id)
|
||||||
{
|
{
|
||||||
return Task.FromResult(_connection.Get<T>(id));
|
return Task.FromResult(Connection.Get<T>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task<IEnumerable<T>> GetAllAsync()
|
protected virtual Task<IEnumerable<T>> GetAllAsync()
|
||||||
{
|
{
|
||||||
return Task.FromResult(_connection.Table<T>().Cast<T>());
|
return Task.FromResult(Connection.Table<T>().Cast<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task CreateAsync(T obj)
|
protected virtual Task CreateAsync(T obj)
|
||||||
{
|
{
|
||||||
_connection.Insert(obj);
|
Connection.Insert(obj);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task ReplaceAsync(T obj)
|
protected virtual Task ReplaceAsync(T obj)
|
||||||
{
|
{
|
||||||
_connection.Update(obj);
|
Connection.Update(obj);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task DeleteAsync(T obj)
|
protected virtual Task DeleteAsync(T obj)
|
||||||
{
|
{
|
||||||
_connection.Delete<T>(obj.Id);
|
Connection.Delete<T>(obj.Id);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,25 @@ namespace Bit.App.Services
|
||||||
{
|
{
|
||||||
public class SiteService : Repository<SiteData, int>, ISiteService
|
public class SiteService : Repository<SiteData, int>, ISiteService
|
||||||
{
|
{
|
||||||
public SiteService(ISqlService sqlite)
|
private readonly IAuthService _authService;
|
||||||
: base(sqlite) { }
|
|
||||||
|
|
||||||
public new async Task<IEnumerable<Site>> GetAllAsync()
|
public SiteService(
|
||||||
|
ISqlService sqlService,
|
||||||
|
IAuthService authService)
|
||||||
|
: base(sqlService)
|
||||||
{
|
{
|
||||||
var data = await base.GetAllAsync();
|
_authService = authService;
|
||||||
return data.Select(s => new Site(s));
|
}
|
||||||
|
|
||||||
|
public new Task<IEnumerable<Site>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var data = Connection.Table<SiteData>().Where(f => f.UserId == _authService.UserId).Cast<SiteData>();
|
||||||
|
return Task.FromResult(data.Select(s => new Site(s)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveAsync(Site site)
|
public async Task SaveAsync(Site site)
|
||||||
{
|
{
|
||||||
var data = new SiteData(site);
|
var data = new SiteData(site, _authService.UserId);
|
||||||
data.RevisionDateTime = DateTime.UtcNow;
|
data.RevisionDateTime = DateTime.UtcNow;
|
||||||
|
|
||||||
if(site.Id == 0)
|
if(site.Id == 0)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Unity" version="3.5.1405-prerelease" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="Xam.Plugins.Settings" version="2.1.0" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
<package id="XLabs.IoC" version="2.0.5782" targetFramework="portable45-net45+win8+wpa81" />
|
<package id="XLabs.IoC" version="2.0.5782" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
</packages>
|
</packages>
|
|
@ -10,6 +10,7 @@ using Bit.App.Abstractions;
|
||||||
using Bit.App.Services;
|
using Bit.App.Services;
|
||||||
using Microsoft.Practices.Unity;
|
using Microsoft.Practices.Unity;
|
||||||
using Bit.iOS.Services;
|
using Bit.iOS.Services;
|
||||||
|
using Plugin.Settings;
|
||||||
|
|
||||||
namespace Bit.iOS
|
namespace Bit.iOS
|
||||||
{
|
{
|
||||||
|
@ -48,6 +49,7 @@ namespace Bit.iOS
|
||||||
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<ISecureStorageService, KeyChainStorageService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ISecureStorageService, KeyChainStorageService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterInstance(CrossSettings.Current, new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
||||||
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
||||||
|
|
|
@ -130,6 +130,14 @@
|
||||||
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll</HintPath>
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\Xamarin.iOS10\Plugin.Settings.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Plugin.Settings.Abstractions, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xam.Plugins.Settings.2.1.0\lib\Xamarin.iOS10\Plugin.Settings.Abstractions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="xamarinios10" />
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="xamarinios10" />
|
||||||
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="xamarinios10" />
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="xamarinios10" />
|
||||||
<package id="Unity" version="3.5.1405-prerelease" targetFramework="xamarinios10" />
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="xamarinios10" />
|
||||||
|
<package id="Xam.Plugins.Settings" version="2.1.0" targetFramework="xamarinios10" />
|
||||||
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="xamarinios10" />
|
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="xamarinios10" />
|
||||||
<package id="XLabs.IoC" version="2.0.5782" targetFramework="xamarinios10" />
|
<package id="XLabs.IoC" version="2.0.5782" targetFramework="xamarinios10" />
|
||||||
<package id="XLabs.IoC.Unity" version="2.0.5782" targetFramework="xamarinios10" />
|
<package id="XLabs.IoC.Unity" version="2.0.5782" targetFramework="xamarinios10" />
|
||||||
|
|
Loading…
Reference in a new issue