Initial commit of new TOTP page

This commit is contained in:
Carlos J. Muentes 2022-02-11 15:22:51 -05:00
parent b55a450f44
commit b02c58e362
10 changed files with 339 additions and 56 deletions

View File

@ -1,57 +1,48 @@
<?xml version='1.0' encoding='UTF-8'?>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2.15.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.NFC"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<application android:label="Bitwarden" android:theme="@style/LaunchTheme" android:allowBackup="false" tools:replace="android:allowBackup" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:networkSecurityConfig="@xml/network_security_config">
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.x8bit.bitwarden.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/>
</provider>
<meta-data android:name="android.max_aspect" android:value="2.1"/>
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions"/>
<!-- Support for Samsung "Multi Window" mode (for Android < 7.0 users) -->
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true"/>
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true"/>
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true"/>
<!-- Declare MainActivity manually so we can set LaunchMode using API dependant resource -->
<activity android:name="com.x8bit.bitwarden.MainActivity" android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|uiMode" android:exported="true" android:icon="@mipmap/ic_launcher" android:label="Bitwarden" android:launchMode="@integer/launchModeAPIlevel" android:theme="@style/LaunchTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/*"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
<data android:mimeType="text/*"/>
</intent-filter>
</activity>
</application>
<!-- Package visibility (for Android 11+) -->
<queries>
<intent>
<action android:name="*"/>
</intent>
</queries>
</manifest>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<application android:label="Bitwarden" android:theme="@style/LaunchTheme" android:allowBackup="false" tools:replace="android:allowBackup" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:networkSecurityConfig="@xml/network_security_config">
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.x8bit.bitwarden.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
</provider>
<meta-data android:name="android.max_aspect" android:value="2.1" />
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions" />
<!-- Support for Samsung "Multi Window" mode (for Android < 7.0 users) -->
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true" />
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true" />
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true" />
<!-- Declare MainActivity manually so we can set LaunchMode using API dependant resource -->
<activity android:name="com.x8bit.bitwarden.MainActivity" android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|uiMode" android:exported="true" android:icon="@mipmap/ic_launcher" android:label="Bitwarden" android:launchMode="@integer/launchModeAPIlevel" android:theme="@style/LaunchTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/*" />
<data android:mimeType="image/*" />
<data android:mimeType="video/*" />
<data android:mimeType="text/*" />
</intent-filter>
</activity>
</application>
<!-- Package visibility (for Android 11+) -->
<queries>
<intent>
<action android:name="*" />
</intent>
</queries>
</manifest>

View File

@ -120,11 +120,19 @@
<DependentUpon>SendGroupingsPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Condition=" '$(EnableDefaultCompileItems)' == 'true' " Update="Pages\Authenticator\GeneratorPage.xaml.cs">
<DependentUpon>GeneratorPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Condition=" '$(EnableDefaultCompileItems)' == 'true' " Update="Pages\Authenticator\AuthenticatorPage.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Behaviors\" />
<Folder Include="Pages\Authenticator\" />
</ItemGroup>
<ItemGroup>
@ -414,5 +422,6 @@
<ItemGroup>
<None Remove="Behaviors\" />
<None Remove="Pages\Authenticator\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.Authenticator.AuthenticatorPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:pages1="clr-namespace:Bit.App.Pages.Authenticator"
x:DataType="pages:GeneratorPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages1:AuthenticatorPageViewModel />
</ContentPage.BindingContext>
<StackLayout>
<RefreshView
IsVisible="{Binding ShowList}"
IsRefreshing="{Binding Refreshing}"
Command="{Binding RefreshCommand}">
<controls:ExtendedCollectionView
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
</controls:ExtendedCollectionView>
</RefreshView>
<StackLayout
IsVisible="{Binding !ShowList}">
</StackLayout>
</StackLayout>
</pages:BaseContentPage>

View File

@ -0,0 +1,143 @@
using Bit.App.Resources;
using System;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Bit.App.Pages.Authenticator
{
public partial class AuthenticatorPage : BaseContentPage
{
#region Members
private readonly IBroadcasterService _broadcasterService;
private AuthenticatorPageViewModel _vm;
private readonly bool _fromTabPage;
private readonly Action<string> _selectAction;
private readonly TabsPage _tabsPage;
#endregion
public AuthenticatorPage(bool fromTabPage, Action<string> selectAction = null, TabsPage tabsPage = null)
{
_tabsPage = tabsPage;
InitializeComponent();
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_vm = BindingContext as AuthenticatorPageViewModel;
_vm.Page = this;
_fromTabPage = fromTabPage;
_selectAction = selectAction;
var isIos = Device.RuntimePlatform == Device.iOS;
if (selectAction != null)
{
if (isIos)
{
ToolbarItems.Add(_closeItem);
}
ToolbarItems.Add(_selectItem);
}
else
{
if (isIos)
{
ToolbarItems.Add(_moreItem);
}
else
{
ToolbarItems.Add(_historyItem);
}
}
if (isIos)
{
_typePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
}
}
public async Task InitAsync()
{
await _vm.InitAsync();
}
protected async override void OnAppearing()
{
base.OnAppearing();
if (!_fromTabPage)
{
await InitAsync();
}
_broadcasterService.Subscribe(nameof(GeneratorPage), async (message) =>
{
if (message.Command == "updatedTheme")
{
Device.BeginInvokeOnMainThread(() =>
{
//_vm.RedrawPassword();
});
}
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_broadcasterService.Unsubscribe(nameof(GeneratorPage));
}
protected override bool OnBackButtonPressed()
{
if (Device.RuntimePlatform == Device.Android && _tabsPage != null)
{
_tabsPage.ResetToVaultPage();
return true;
}
return base.OnBackButtonPressed();
}
private async void Copy_Clicked(object sender, EventArgs e)
{
//await _vm.CopyAsync();
}
private async void More_Clicked(object sender, EventArgs e)
{
if (!DoOnce())
{
return;
}
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
null, AppResources.PasswordHistory);
if (selection == AppResources.PasswordHistory)
{
var page = new GeneratorHistoryPage();
await Navigation.PushModalAsync(new Xamarin.Forms.NavigationPage(page));
}
}
private void Select_Clicked(object sender, EventArgs e)
{
_selectAction?.Invoke(_vm.Password);
}
private async void History_Clicked(object sender, EventArgs e)
{
var page = new GeneratorHistoryPage();
await Navigation.PushModalAsync(new Xamarin.Forms.NavigationPage(page));
}
private async void LengthSlider_DragCompleted(object sender, EventArgs e)
{
await _vm.SliderChangedAsync();
}
private async void Close_Clicked(object sender, EventArgs e)
{
if (DoOnce())
{
await Navigation.PopModalAsync();
}
}
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
namespace Bit.App.Pages.Authenticator
{
public class AuthenticatorPageViewModel : BaseViewModel
{
#region Members
private readonly IClipboardService _clipboardService;
private bool _showList;
private bool _refreshing;
private readonly IUserService _userService;
private readonly IVaultTimeoutService _vaultTimeoutService;
#endregion
#region Ctor
public AuthenticatorPageViewModel()
{
_userService = ServiceContainer.Resolve<IUserService>("userService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
}
#endregion
#region Methods
public async Task InitAsync() { }
public async Task CopyAsync()
{
//await _clipboardService.CopyTextAsync(Password);
//_platformUtilsService.ShowToast("success", null,
// string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
}
public async Task LoadAsync()
{
var authed = await _userService.IsAuthenticatedAsync();
if (!authed)
{
return;
}
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
this.ShowList = true;
this.Refreshing = false;
}
#endregion
#region Properties
public bool ShowList
{
get => _showList;
set => SetProperty(ref _showList, value);
}
public bool Refreshing
{
get => _refreshing;
set => SetProperty(ref _refreshing, value);
}
#endregion
}
}

View File

@ -13,6 +13,7 @@ namespace Bit.App.Pages
private readonly IKeyConnectorService _keyConnectorService;
private NavigationPage _groupingsPage;
private NavigationPage _authenticatorPage;
private NavigationPage _sendGroupingsPage;
private NavigationPage _generatorPage;
@ -26,8 +27,15 @@ namespace Bit.App.Pages
Title = AppResources.MyVault,
IconImageSource = "lock.png"
};
Children.Add(_groupingsPage);
_authenticatorPage = new NavigationPage(new Authenticator.AuthenticatorPage(true, null, this))
{
Title = AppResources.Authenticator,
IconImageSource = "info.png"
};
_sendGroupingsPage = new NavigationPage(new SendGroupingsPage(true, null, null, appOptions))
{
Title = AppResources.Send,

View File

@ -329,6 +329,12 @@ namespace Bit.App.Resources {
}
}
public static string Authenticator {
get {
return ResourceManager.GetString("Authenticator", resourceCulture);
}
}
public static string Name {
get {
return ResourceManager.GetString("Name", resourceCulture);

View File

@ -287,6 +287,10 @@
<value>My Vault</value>
<comment>The title for the vault page.</comment>
</data>
<data name="Authenticator" xml:space="preserve">
<value>Authenticator</value>
<comment>Authenticator TOTP feature</comment>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
<comment>Label for an entity name.</comment>

5
src/iOS.Core/Info.plist Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

View File

@ -208,5 +208,8 @@
<Version>2.0.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
</Project>