mirror of
https://github.com/bitwarden/mobile
synced 2025-12-18 09:13:15 +00:00
Merge branch 'master' into EC-295-swipe-to-copy-logins
# Conflicts: # src/Android/Properties/AndroidManifest.xml # src/App/Utilities/AppHelpers.cs
This commit is contained in:
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@@ -54,17 +54,26 @@ jobs:
|
|||||||
echo "::set-output name=branch-name::$BRANCH_NAME"
|
echo "::set-output name=branch-name::$BRANCH_NAME"
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
branch: ${{ steps.branch.outputs.branch-name }}
|
branch: ${{ steps.branch.outputs.branch-name }}
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||||
|
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||||
|
with:
|
||||||
|
workflow: build.yml
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
|
||||||
- name: Prep Bitwarden iOS release asset
|
- name: Prep Bitwarden iOS release asset
|
||||||
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
|
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
if: github.event.inputs.release_type != 'Dry Run'
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01 # v1.9.0
|
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01 # v1.9.0
|
||||||
with:
|
with:
|
||||||
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
|
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
|
||||||
@@ -89,6 +98,7 @@ jobs:
|
|||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
||||||
|
|
||||||
- name: Download F-Droid .apk artifact
|
- name: Download F-Droid .apk artifact
|
||||||
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
@@ -96,6 +106,15 @@ jobs:
|
|||||||
branch: ${{ needs.release.outputs.branch-name }}
|
branch: ${{ needs.release.outputs.branch-name }}
|
||||||
name: com.x8bit.bitwarden-fdroid.apk
|
name: com.x8bit.bitwarden-fdroid.apk
|
||||||
|
|
||||||
|
- name: Download F-Droid .apk artifact
|
||||||
|
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||||
|
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||||
|
with:
|
||||||
|
workflow: build.yml
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
name: com.x8bit.bitwarden-fdroid.apk
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
|
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
|
||||||
with:
|
with:
|
||||||
@@ -161,5 +180,5 @@ jobs:
|
|||||||
cd $GITHUB_WORKSPACE
|
cd $GITHUB_WORKSPACE
|
||||||
|
|
||||||
- name: Deploy to gh-pages
|
- name: Deploy to gh-pages
|
||||||
if: github.event.inputs.release_type != 'Dry Run'
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
run: npm run deploy
|
run: npm run deploy
|
||||||
|
|||||||
15
.github/workflows/version-auto-bump.yml
vendored
Normal file
15
.github/workflows/version-auto-bump.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: Version Auto Bump
|
||||||
|
|
||||||
|
on:
|
||||||
|
# For testing only
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
setup:
|
||||||
|
name: "Setup"
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: Stub for testing
|
||||||
|
run: echo "this is a stub"
|
||||||
@@ -1,58 +1,49 @@
|
|||||||
<?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="2022.6.2" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2022.6.3" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||||
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
|
||||||
<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.INTERNET"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.NFC"/>
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||||
<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-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
<uses-feature android:name="android.hardware.camera.autofocus" 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">
|
||||||
<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">
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
|
||||||
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.x8bit.bitwarden.fileprovider" android:exported="false" android:grantUriPermissions="true">
|
</provider>
|
||||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/>
|
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||||
</provider>
|
<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="android.max_aspect" android:value="2.1"/>
|
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true" />
|
||||||
<meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions"/>
|
<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) -->
|
||||||
<!-- Support for Samsung "Multi Window" mode (for Android < 7.0 users) -->
|
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true" />
|
||||||
<meta-data android:name="com.samsung.android.sdk.multiwindow.enable" android:value="true"/>
|
<!-- Declare MainActivity manually so we can set LaunchMode using API dependant resource -->
|
||||||
<meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable" android:value="true"/>
|
<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>
|
||||||
<!-- Support for LG "Dual Window" mode (for Android < 7.0 users) -->
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<meta-data android:name="com.lge.support.SPLIT_WINDOW" android:value="true"/>
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
<!-- Declare MainActivity manually so we can set LaunchMode using API dependant resource -->
|
</intent-filter>
|
||||||
<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>
|
||||||
<intent-filter>
|
<action android:name="android.intent.action.SEND" />
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<data android:mimeType="application/*" />
|
||||||
</intent-filter>
|
<data android:mimeType="image/*" />
|
||||||
<intent-filter>
|
<data android:mimeType="video/*" />
|
||||||
<action android:name="android.intent.action.SEND"/>
|
<data android:mimeType="text/*" />
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
</intent-filter>
|
||||||
<data android:mimeType="application/*"/>
|
</activity>
|
||||||
<data android:mimeType="image/*"/>
|
</application>
|
||||||
<data android:mimeType="video/*"/>
|
<!-- Package visibility (for Android 11+) -->
|
||||||
<data android:mimeType="text/*"/>
|
<queries>
|
||||||
</intent-filter>
|
<intent>
|
||||||
</activity>
|
<action android:name="*" />
|
||||||
</application>
|
</intent>
|
||||||
|
</queries>
|
||||||
<!-- Package visibility (for Android 11+) -->
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="*"/>
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -97,11 +97,11 @@
|
|||||||
<Compile Update="Pages\Vault\PasswordHistoryPage.xaml.cs">
|
<Compile Update="Pages\Vault\PasswordHistoryPage.xaml.cs">
|
||||||
<DependentUpon>PasswordHistoryPage.xaml</DependentUpon>
|
<DependentUpon>PasswordHistoryPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Update="Pages\Vault\AddEditPage.xaml.cs">
|
<Compile Update="Pages\Vault\CipherDetailsPage.xaml.cs">
|
||||||
<DependentUpon>AddEditPage.xaml</DependentUpon>
|
<DependentUpon>CipherDetailsPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Update="Pages\Vault\ViewPage.xaml.cs">
|
<Compile Update="Pages\Vault\CipherAddEditPage.xaml.cs">
|
||||||
<DependentUpon>ViewPage.xaml</DependentUpon>
|
<DependentUpon>CipherAddEditPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Update="Pages\Settings\SettingsPage\SettingsPage.xaml.cs">
|
<Compile Update="Pages\Settings\SettingsPage\SettingsPage.xaml.cs">
|
||||||
<DependentUpon>SettingsPage.xaml</DependentUpon>
|
<DependentUpon>SettingsPage.xaml</DependentUpon>
|
||||||
|
|||||||
@@ -330,20 +330,20 @@ namespace Bit.App
|
|||||||
var topPage = tabbedPage.Navigation.ModalStack[tabbedPage.Navigation.ModalStack.Count - 1];
|
var topPage = tabbedPage.Navigation.ModalStack[tabbedPage.Navigation.ModalStack.Count - 1];
|
||||||
if (topPage is NavigationPage navPage)
|
if (topPage is NavigationPage navPage)
|
||||||
{
|
{
|
||||||
if (navPage.CurrentPage is ViewPage viewPage)
|
if (navPage.CurrentPage is CipherDetailsPage cipherDetailsPage)
|
||||||
{
|
{
|
||||||
lastPageBeforeLock = new PreviousPageInfo
|
lastPageBeforeLock = new PreviousPageInfo
|
||||||
{
|
{
|
||||||
Page = "view",
|
Page = "view",
|
||||||
CipherId = viewPage.ViewModel.CipherId
|
CipherId = cipherDetailsPage.ViewModel.CipherId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (navPage.CurrentPage is AddEditPage addEditPage && addEditPage.ViewModel.EditMode)
|
else if (navPage.CurrentPage is CipherAddEditPage cipherAddEditPage && cipherAddEditPage.ViewModel.EditMode)
|
||||||
{
|
{
|
||||||
lastPageBeforeLock = new PreviousPageInfo
|
lastPageBeforeLock = new PreviousPageInfo
|
||||||
{
|
{
|
||||||
Page = "edit",
|
Page = "edit",
|
||||||
CipherId = addEditPage.ViewModel.CipherId
|
CipherId = cipherAddEditPage.ViewModel.CipherId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,7 +378,7 @@ namespace Bit.App
|
|||||||
Current.MainPage = new TabsPage(Options);
|
Current.MainPage = new TabsPage(Options);
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.AddEditCipher:
|
case NavigationTarget.AddEditCipher:
|
||||||
Current.MainPage = new NavigationPage(new AddEditPage(appOptions: Options));
|
Current.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: Options));
|
||||||
break;
|
break;
|
||||||
case NavigationTarget.AutofillCiphers:
|
case NavigationTarget.AutofillCiphers:
|
||||||
Current.MainPage = new NavigationPage(new AutofillCiphersPage(Options));
|
Current.MainPage = new NavigationPage(new AutofillCiphersPage(Options));
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
bool IsUrlValid(string url)
|
bool IsUrlValid(string url)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(url) || Uri.IsWellFormedUriString(url, UriKind.Absolute);
|
return string.IsNullOrEmpty(url) || Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsUrlValid(BaseUrl)
|
return IsUrlValid(BaseUrl)
|
||||||
|
|||||||
@@ -132,20 +132,20 @@
|
|||||||
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
|
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
|
||||||
<StackLayout StyleClass="box-row, box-row-input">
|
<StackLayout StyleClass="box-row, box-row-input">
|
||||||
<Label
|
<Label
|
||||||
Text="{u:I18n BlacklistedUris}"
|
Text="{u:I18n AutofillBlockedUris}"
|
||||||
StyleClass="box-label" />
|
StyleClass="box-label" />
|
||||||
<Editor
|
<Editor
|
||||||
x:Name="_blacklistedUrisEditor"
|
x:Name="_autofillBlockedUrisEditor"
|
||||||
Text="{Binding AutofillBlacklistedUris}"
|
Text="{Binding AutofillBlockedUris}"
|
||||||
StyleClass="box-value"
|
StyleClass="box-value"
|
||||||
AutoSize="TextChanges"
|
AutoSize="TextChanges"
|
||||||
IsSpellCheckEnabled="False"
|
IsSpellCheckEnabled="False"
|
||||||
IsTextPredictionEnabled="False"
|
IsTextPredictionEnabled="False"
|
||||||
Keyboard="Url"
|
Keyboard="Url"
|
||||||
Unfocused="BlacklistedUrisEditor_Unfocused" />
|
Unfocused="AutofillBlockedUrisEditor_Unfocused" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
<Label
|
<Label
|
||||||
Text="{u:I18n BlacklistedUrisDescription}"
|
Text="{u:I18n AutofillBlockedUrisDescription}"
|
||||||
StyleClass="box-footer-label" />
|
StyleClass="box-footer-label" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ namespace Bit.App.Pages
|
|||||||
protected async override void OnDisappearing()
|
protected async override void OnDisappearing()
|
||||||
{
|
{
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
await _vm.UpdateAutofillBlacklistedUris();
|
await _vm.UpdateAutofillBlockedUris();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void BlacklistedUrisEditor_Unfocused(object sender, FocusEventArgs e)
|
private async void AutofillBlockedUrisEditor_Unfocused(object sender, FocusEventArgs e)
|
||||||
{
|
{
|
||||||
await _vm.UpdateAutofillBlacklistedUris();
|
await _vm.UpdateAutofillBlockedUris();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Close_Clicked(object sender, System.EventArgs e)
|
private async void Close_Clicked(object sender, System.EventArgs e)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
|
|
||||||
private bool _autofillSavePrompt;
|
private bool _autofillSavePrompt;
|
||||||
private string _autofillBlacklistedUris;
|
private string _autofillBlockedUris;
|
||||||
private bool _favicon;
|
private bool _favicon;
|
||||||
private bool _autoTotpCopy;
|
private bool _autoTotpCopy;
|
||||||
private int _clearClipboardSelectedIndex;
|
private int _clearClipboardSelectedIndex;
|
||||||
@@ -167,10 +167,10 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string AutofillBlacklistedUris
|
public string AutofillBlockedUris
|
||||||
{
|
{
|
||||||
get => _autofillBlacklistedUris;
|
get => _autofillBlockedUris;
|
||||||
set => SetProperty(ref _autofillBlacklistedUris, value);
|
set => SetProperty(ref _autofillBlockedUris, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowAndroidAutofillSettings
|
public bool ShowAndroidAutofillSettings
|
||||||
@@ -182,8 +182,8 @@ namespace Bit.App.Pages
|
|||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
AutofillSavePrompt = !(await _stateService.GetAutofillDisableSavePromptAsync()).GetValueOrDefault();
|
AutofillSavePrompt = !(await _stateService.GetAutofillDisableSavePromptAsync()).GetValueOrDefault();
|
||||||
var blacklistedUrisList = await _stateService.GetAutofillBlacklistedUrisAsync();
|
var blockedUrisList = await _stateService.GetAutofillBlacklistedUrisAsync();
|
||||||
AutofillBlacklistedUris = blacklistedUrisList != null ? string.Join(", ", blacklistedUrisList) : null;
|
AutofillBlockedUris = blockedUrisList != null ? string.Join(", ", blockedUrisList) : null;
|
||||||
AutoTotpCopy = !(await _stateService.GetDisableAutoTotpCopyAsync() ?? false);
|
AutoTotpCopy = !(await _stateService.GetDisableAutoTotpCopyAsync() ?? false);
|
||||||
Favicon = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
|
Favicon = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
|
||||||
var theme = await _stateService.GetThemeAsync();
|
var theme = await _stateService.GetThemeAsync();
|
||||||
@@ -252,19 +252,19 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateAutofillBlacklistedUris()
|
public async Task UpdateAutofillBlockedUris()
|
||||||
{
|
{
|
||||||
if (_inited)
|
if (_inited)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(AutofillBlacklistedUris))
|
if (string.IsNullOrWhiteSpace(AutofillBlockedUris))
|
||||||
{
|
{
|
||||||
await _stateService.SetAutofillBlacklistedUrisAsync(null);
|
await _stateService.SetAutofillBlacklistedUrisAsync(null);
|
||||||
AutofillBlacklistedUris = null;
|
AutofillBlockedUris = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var csv = AutofillBlacklistedUris;
|
var csv = AutofillBlockedUris;
|
||||||
var urisList = new List<string>();
|
var urisList = new List<string>();
|
||||||
foreach (var uri in csv.Split(','))
|
foreach (var uri in csv.Split(','))
|
||||||
{
|
{
|
||||||
@@ -281,7 +281,7 @@ namespace Bit.App.Pages
|
|||||||
urisList.Add(cleanedUri);
|
urisList.Add(cleanedUri);
|
||||||
}
|
}
|
||||||
await _stateService.SetAutofillBlacklistedUrisAsync(urisList);
|
await _stateService.SetAutofillBlacklistedUrisAsync(urisList);
|
||||||
AutofillBlacklistedUris = string.Join(", ", urisList);
|
AutofillBlockedUris = string.Join(", ", urisList);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Bit.App.Pages
|
|||||||
public bool UseFrame { get; set; }
|
public bool UseFrame { get; set; }
|
||||||
public Func<Task> ExecuteAsync { get; set; }
|
public Func<Task> ExecuteAsync { get; set; }
|
||||||
|
|
||||||
public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled;
|
public bool SubLabelTextEnabled => SubLabel == AppResources.On;
|
||||||
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
||||||
public bool ShowSubLabel => SubLabel.Length != 0;
|
public bool ShowSubLabel => SubLabel.Length != 0;
|
||||||
public bool ShowTimeInput => Time != null;
|
public bool ShowTimeInput => Time != null;
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ namespace Bit.App.Pages
|
|||||||
autofillItems.Add(new SettingsPageListItem
|
autofillItems.Add(new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.AutofillServices,
|
Name = AppResources.AutofillServices,
|
||||||
SubLabel = _deviceActionService.AutofillServicesEnabled() ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _deviceActionService.AutofillServicesEnabled() ? AppResources.On : AppResources.Off,
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage)))
|
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ namespace Bit.App.Pages
|
|||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.UnlockWithPIN,
|
Name = AppResources.UnlockWithPIN,
|
||||||
SubLabel = _pin ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _pin ? AppResources.On : AppResources.Off,
|
||||||
ExecuteAsync = () => UpdatePinAsync()
|
ExecuteAsync = () => UpdatePinAsync()
|
||||||
},
|
},
|
||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
@@ -525,7 +525,7 @@ namespace Bit.App.Pages
|
|||||||
var item = new SettingsPageListItem
|
var item = new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = string.Format(AppResources.UnlockWith, biometricName),
|
Name = string.Format(AppResources.UnlockWith, biometricName),
|
||||||
SubLabel = _biometric ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _biometric ? AppResources.On : AppResources.Off,
|
||||||
ExecuteAsync = () => UpdateBiometricAsync()
|
ExecuteAsync = () => UpdateBiometricAsync()
|
||||||
};
|
};
|
||||||
securityItems.Insert(2, item);
|
securityItems.Insert(2, item);
|
||||||
@@ -554,7 +554,7 @@ namespace Bit.App.Pages
|
|||||||
securityItems.Add(new SettingsPageListItem
|
securityItems.Add(new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.AllowScreenCapture,
|
Name = AppResources.AllowScreenCapture,
|
||||||
SubLabel = _screenCaptureAllowed ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _screenCaptureAllowed ? AppResources.On : AppResources.Off,
|
||||||
ExecuteAsync = () => SetScreenCaptureAllowedAsync()
|
ExecuteAsync = () => SetScreenCaptureAllowedAsync()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -627,7 +627,7 @@ namespace Bit.App.Pages
|
|||||||
new SettingsPageListItem
|
new SettingsPageListItem
|
||||||
{
|
{
|
||||||
Name = AppResources.SubmitCrashLogs,
|
Name = AppResources.SubmitCrashLogs,
|
||||||
SubLabel = _reportLoggingEnabled ? AppResources.Enabled : AppResources.Disabled,
|
SubLabel = _reportLoggingEnabled ? AppResources.On : AppResources.Off,
|
||||||
ExecuteAsync = () => LoggerReportingAsync()
|
ExecuteAsync = () => LoggerReportingAsync()
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (_appOptions.FillType.HasValue && _appOptions.FillType != CipherType.Login)
|
if (_appOptions.FillType.HasValue && _appOptions.FillType != CipherType.Login)
|
||||||
{
|
{
|
||||||
var pageForOther = new AddEditPage(type: _appOptions.FillType, fromAutofill: true);
|
var pageForOther = new CipherAddEditPage(type: _appOptions.FillType, fromAutofill: true);
|
||||||
await Navigation.PushModalAsync(new NavigationPage(pageForOther));
|
await Navigation.PushModalAsync(new NavigationPage(pageForOther));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var pageForLogin = new AddEditPage(null, CipherType.Login, uri: _vm.Uri, name: _vm.Name,
|
var pageForLogin = new CipherAddEditPage(null, CipherType.Login, uri: _vm.Uri, name: _vm.Name,
|
||||||
fromAutofill: true);
|
fromAutofill: true);
|
||||||
await Navigation.PushModalAsync(new NavigationPage(pageForLogin));
|
await Navigation.PushModalAsync(new NavigationPage(pageForLogin));
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/App/Pages/Vault/BaseCipherViewModel.cs
Normal file
76
src/App/Pages/Vault/BaseCipherViewModel.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Exceptions;
|
||||||
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Xamarin.CommunityToolkit.ObjectModel;
|
||||||
|
|
||||||
|
namespace Bit.App.Pages
|
||||||
|
{
|
||||||
|
public abstract class BaseCipherViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
private readonly IAuditService _auditService;
|
||||||
|
protected readonly IDeviceActionService _deviceActionService;
|
||||||
|
protected readonly ILogger _logger;
|
||||||
|
protected readonly IPlatformUtilsService _platformUtilsService;
|
||||||
|
private CipherView _cipher;
|
||||||
|
protected abstract string[] AdditionalPropertiesToRaiseOnCipherChanged { get; }
|
||||||
|
|
||||||
|
public BaseCipherViewModel()
|
||||||
|
{
|
||||||
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
||||||
|
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||||
|
|
||||||
|
CheckPasswordCommand = new AsyncCommand(CheckPasswordAsync, allowsMultipleExecutions: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CipherView Cipher
|
||||||
|
{
|
||||||
|
get => _cipher;
|
||||||
|
set => SetProperty(ref _cipher, value, additionalPropertyNames: AdditionalPropertiesToRaiseOnCipherChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncCommand CheckPasswordCommand { get; }
|
||||||
|
|
||||||
|
protected async Task CheckPasswordAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Cipher?.Login?.Password))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _deviceActionService.ShowLoadingAsync(AppResources.CheckingPassword);
|
||||||
|
var matches = await _auditService.PasswordLeakedAsync(Cipher.Login.Password);
|
||||||
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
|
||||||
|
await _platformUtilsService.ShowDialogAsync(matches > 0
|
||||||
|
? string.Format(AppResources.PasswordExposed, matches.ToString("N0"))
|
||||||
|
: AppResources.PasswordSafe);
|
||||||
|
}
|
||||||
|
catch (ApiException apiException)
|
||||||
|
{
|
||||||
|
_logger.Exception(apiException);
|
||||||
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
if (apiException?.Error != null)
|
||||||
|
{
|
||||||
|
await _platformUtilsService.ShowDialogAsync(apiException.Error.GetSingleMessage(),
|
||||||
|
AppResources.AnErrorHasOccurred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<pages:BaseContentPage
|
<pages:BaseContentPage
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
x:Class="Bit.App.Pages.AddEditPage"
|
x:Class="Bit.App.Pages.CipherAddEditPage"
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||||
@@ -10,11 +10,11 @@
|
|||||||
xmlns:behaviors="clr-namespace:Bit.App.Behaviors"
|
xmlns:behaviors="clr-namespace:Bit.App.Behaviors"
|
||||||
xmlns:effects="clr-namespace:Bit.App.Effects"
|
xmlns:effects="clr-namespace:Bit.App.Effects"
|
||||||
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
||||||
x:DataType="pages:AddEditPageViewModel"
|
x:DataType="pages:CipherAddEditPageViewModel"
|
||||||
x:Name="_page"
|
x:Name="_page"
|
||||||
Title="{Binding PageTitle}">
|
Title="{Binding PageTitle}">
|
||||||
<ContentPage.BindingContext>
|
<ContentPage.BindingContext>
|
||||||
<pages:AddEditPageViewModel />
|
<pages:CipherAddEditPageViewModel />
|
||||||
</ContentPage.BindingContext>
|
</ContentPage.BindingContext>
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
<ContentPage.ToolbarItems>
|
||||||
@@ -608,7 +608,7 @@
|
|||||||
</StackLayout>
|
</StackLayout>
|
||||||
<controls:RepeaterView ItemsSource="{Binding Fields}">
|
<controls:RepeaterView ItemsSource="{Binding Fields}">
|
||||||
<controls:RepeaterView.ItemTemplate>
|
<controls:RepeaterView.ItemTemplate>
|
||||||
<DataTemplate x:DataType="pages:AddEditPageFieldViewModel">
|
<DataTemplate x:DataType="pages:CipherAddEditPageFieldViewModel">
|
||||||
<StackLayout Spacing="0" Padding="0">
|
<StackLayout Spacing="0" Padding="0">
|
||||||
<Grid StyleClass="box-row, box-row-input">
|
<Grid StyleClass="box-row, box-row-input">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -14,7 +14,7 @@ using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
|||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class AddEditPage : BaseContentPage
|
public partial class CipherAddEditPage : BaseContentPage
|
||||||
{
|
{
|
||||||
private readonly AppOptions _appOptions;
|
private readonly AppOptions _appOptions;
|
||||||
private readonly IStateService _stateService;
|
private readonly IStateService _stateService;
|
||||||
@@ -22,10 +22,10 @@ namespace Bit.App.Pages
|
|||||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
private readonly IVaultTimeoutService _vaultTimeoutService;
|
||||||
private readonly IKeyConnectorService _keyConnectorService;
|
private readonly IKeyConnectorService _keyConnectorService;
|
||||||
|
|
||||||
private AddEditPageViewModel _vm;
|
private CipherAddEditPageViewModel _vm;
|
||||||
private bool _fromAutofill;
|
private bool _fromAutofill;
|
||||||
|
|
||||||
public AddEditPage(
|
public CipherAddEditPage(
|
||||||
string cipherId = null,
|
string cipherId = null,
|
||||||
CipherType? type = null,
|
CipherType? type = null,
|
||||||
string folderId = null,
|
string folderId = null,
|
||||||
@@ -36,7 +36,7 @@ namespace Bit.App.Pages
|
|||||||
bool fromAutofill = false,
|
bool fromAutofill = false,
|
||||||
AppOptions appOptions = null,
|
AppOptions appOptions = null,
|
||||||
bool cloneMode = false,
|
bool cloneMode = false,
|
||||||
ViewPage viewPage = null)
|
CipherDetailsPage cipherDetailsPage = null)
|
||||||
{
|
{
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
@@ -47,7 +47,7 @@ namespace Bit.App.Pages
|
|||||||
_fromAutofill = fromAutofill;
|
_fromAutofill = fromAutofill;
|
||||||
FromAutofillFramework = _appOptions?.FromAutofillFramework ?? false;
|
FromAutofillFramework = _appOptions?.FromAutofillFramework ?? false;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_vm = BindingContext as AddEditPageViewModel;
|
_vm = BindingContext as CipherAddEditPageViewModel;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_vm.CipherId = cipherId;
|
_vm.CipherId = cipherId;
|
||||||
_vm.FolderId = folderId == "none" ? null : folderId;
|
_vm.FolderId = folderId == "none" ? null : folderId;
|
||||||
@@ -57,7 +57,7 @@ namespace Bit.App.Pages
|
|||||||
_vm.DefaultName = name ?? appOptions?.SaveName;
|
_vm.DefaultName = name ?? appOptions?.SaveName;
|
||||||
_vm.DefaultUri = uri ?? appOptions?.Uri;
|
_vm.DefaultUri = uri ?? appOptions?.Uri;
|
||||||
_vm.CloneMode = cloneMode;
|
_vm.CloneMode = cloneMode;
|
||||||
_vm.ViewPage = viewPage;
|
_vm.CipherDetailsPage = cipherDetailsPage;
|
||||||
_vm.Init();
|
_vm.Init();
|
||||||
SetActivityIndicator();
|
SetActivityIndicator();
|
||||||
if (_vm.EditMode && !_vm.CloneMode && Device.RuntimePlatform == Device.Android)
|
if (_vm.EditMode && !_vm.CloneMode && Device.RuntimePlatform == Device.Android)
|
||||||
@@ -145,7 +145,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool FromAutofillFramework { get; set; }
|
public bool FromAutofillFramework { get; set; }
|
||||||
public AddEditPageViewModel ViewModel => _vm;
|
public CipherAddEditPageViewModel ViewModel => _vm;
|
||||||
|
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
@@ -15,22 +14,17 @@ using Xamarin.Forms;
|
|||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class AddEditPageViewModel : BaseViewModel
|
public class CipherAddEditPageViewModel : BaseCipherViewModel
|
||||||
{
|
{
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly ICollectionService _collectionService;
|
private readonly ICollectionService _collectionService;
|
||||||
private readonly IStateService _stateService;
|
private readonly IStateService _stateService;
|
||||||
private readonly IOrganizationService _organizationService;
|
private readonly IOrganizationService _organizationService;
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IAuditService _auditService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
private readonly IMessagingService _messagingService;
|
||||||
private readonly IEventService _eventService;
|
private readonly IEventService _eventService;
|
||||||
private readonly IPolicyService _policyService;
|
private readonly IPolicyService _policyService;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private CipherView _cipher;
|
|
||||||
private bool _showNotesSeparator;
|
private bool _showNotesSeparator;
|
||||||
private bool _showPassword;
|
private bool _showPassword;
|
||||||
private bool _showCardNumber;
|
private bool _showCardNumber;
|
||||||
@@ -44,7 +38,7 @@ namespace Bit.App.Pages
|
|||||||
private bool _hasCollections;
|
private bool _hasCollections;
|
||||||
private string _previousCipherId;
|
private string _previousCipherId;
|
||||||
private List<Core.Models.View.CollectionView> _writeableCollections;
|
private List<Core.Models.View.CollectionView> _writeableCollections;
|
||||||
private string[] _additionalCipherProperties = new string[]
|
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
|
||||||
{
|
{
|
||||||
nameof(IsLogin),
|
nameof(IsLogin),
|
||||||
nameof(IsIdentity),
|
nameof(IsIdentity),
|
||||||
@@ -54,6 +48,7 @@ namespace Bit.App.Pages
|
|||||||
nameof(ShowAttachments),
|
nameof(ShowAttachments),
|
||||||
nameof(ShowCollections),
|
nameof(ShowCollections),
|
||||||
};
|
};
|
||||||
|
|
||||||
private List<KeyValuePair<UriMatchType?, string>> _matchDetectionOptions =
|
private List<KeyValuePair<UriMatchType?, string>> _matchDetectionOptions =
|
||||||
new List<KeyValuePair<UriMatchType?, string>>
|
new List<KeyValuePair<UriMatchType?, string>>
|
||||||
{
|
{
|
||||||
@@ -66,31 +61,26 @@ namespace Bit.App.Pages
|
|||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.Never, AppResources.Never)
|
new KeyValuePair<UriMatchType?, string>(UriMatchType.Never, AppResources.Never)
|
||||||
};
|
};
|
||||||
|
|
||||||
public AddEditPageViewModel()
|
public CipherAddEditPageViewModel()
|
||||||
{
|
{
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||||
_folderService = ServiceContainer.Resolve<IFolderService>("folderService");
|
_folderService = ServiceContainer.Resolve<IFolderService>("folderService");
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
||||||
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
|
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||||
_collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
|
_collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
|
||||||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||||
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
|
||||||
|
|
||||||
GeneratePasswordCommand = new Command(GeneratePassword);
|
GeneratePasswordCommand = new Command(GeneratePassword);
|
||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
||||||
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
||||||
CheckPasswordCommand = new Command(CheckPasswordAsync);
|
|
||||||
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
|
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
|
||||||
FieldOptionsCommand = new Command<AddEditPageFieldViewModel>(FieldOptions);
|
FieldOptionsCommand = new Command<CipherAddEditPageFieldViewModel>(FieldOptions);
|
||||||
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
|
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
|
||||||
Uris = new ExtendedObservableCollection<LoginUriView>();
|
Uris = new ExtendedObservableCollection<LoginUriView>();
|
||||||
Fields = new ExtendedObservableCollection<AddEditPageFieldViewModel>();
|
Fields = new ExtendedObservableCollection<CipherAddEditPageFieldViewModel>();
|
||||||
Collections = new ExtendedObservableCollection<CollectionViewModel>();
|
Collections = new ExtendedObservableCollection<CollectionViewModel>();
|
||||||
AllowPersonal = true;
|
AllowPersonal = true;
|
||||||
|
|
||||||
@@ -146,7 +136,6 @@ namespace Bit.App.Pages
|
|||||||
public Command TogglePasswordCommand { get; set; }
|
public Command TogglePasswordCommand { get; set; }
|
||||||
public Command ToggleCardNumberCommand { get; set; }
|
public Command ToggleCardNumberCommand { get; set; }
|
||||||
public Command ToggleCardCodeCommand { get; set; }
|
public Command ToggleCardCodeCommand { get; set; }
|
||||||
public Command CheckPasswordCommand { get; set; }
|
|
||||||
public Command UriOptionsCommand { get; set; }
|
public Command UriOptionsCommand { get; set; }
|
||||||
public Command FieldOptionsCommand { get; set; }
|
public Command FieldOptionsCommand { get; set; }
|
||||||
public Command PasswordPromptHelpCommand { get; set; }
|
public Command PasswordPromptHelpCommand { get; set; }
|
||||||
@@ -164,7 +153,7 @@ namespace Bit.App.Pages
|
|||||||
public List<KeyValuePair<string, string>> FolderOptions { get; set; }
|
public List<KeyValuePair<string, string>> FolderOptions { get; set; }
|
||||||
public List<KeyValuePair<string, string>> OwnershipOptions { get; set; }
|
public List<KeyValuePair<string, string>> OwnershipOptions { get; set; }
|
||||||
public ExtendedObservableCollection<LoginUriView> Uris { get; set; }
|
public ExtendedObservableCollection<LoginUriView> Uris { get; set; }
|
||||||
public ExtendedObservableCollection<AddEditPageFieldViewModel> Fields { get; set; }
|
public ExtendedObservableCollection<CipherAddEditPageFieldViewModel> Fields { get; set; }
|
||||||
public ExtendedObservableCollection<CollectionViewModel> Collections { get; set; }
|
public ExtendedObservableCollection<CollectionViewModel> Collections { get; set; }
|
||||||
|
|
||||||
public int TypeSelectedIndex
|
public int TypeSelectedIndex
|
||||||
@@ -233,11 +222,6 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => _cipher;
|
|
||||||
set => SetProperty(ref _cipher, value, additionalPropertyNames: _additionalCipherProperties);
|
|
||||||
}
|
|
||||||
public bool ShowNotesSeparator
|
public bool ShowNotesSeparator
|
||||||
{
|
{
|
||||||
get => _showNotesSeparator;
|
get => _showNotesSeparator;
|
||||||
@@ -285,7 +269,7 @@ namespace Bit.App.Pages
|
|||||||
public bool ShowOwnershipOptions => !EditMode || CloneMode;
|
public bool ShowOwnershipOptions => !EditMode || CloneMode;
|
||||||
public bool OwnershipPolicyInEffect => ShowOwnershipOptions && !AllowPersonal;
|
public bool OwnershipPolicyInEffect => ShowOwnershipOptions && !AllowPersonal;
|
||||||
public bool CloneMode { get; set; }
|
public bool CloneMode { get; set; }
|
||||||
public ViewPage ViewPage { get; set; }
|
public CipherDetailsPage CipherDetailsPage { get; set; }
|
||||||
public bool IsLogin => Cipher?.Type == CipherType.Login;
|
public bool IsLogin => Cipher?.Type == CipherType.Login;
|
||||||
public bool IsIdentity => Cipher?.Type == CipherType.Identity;
|
public bool IsIdentity => Cipher?.Type == CipherType.Identity;
|
||||||
public bool IsCard => Cipher?.Type == CipherType.Card;
|
public bool IsCard => Cipher?.Type == CipherType.Card;
|
||||||
@@ -421,7 +405,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (Cipher.Fields != null)
|
if (Cipher.Fields != null)
|
||||||
{
|
{
|
||||||
Fields.ResetWithRange(Cipher.Fields?.Select(f => new AddEditPageFieldViewModel(Cipher, f)));
|
Fields.ResetWithRange(Cipher.Fields?.Select(f => new CipherAddEditPageFieldViewModel(Cipher, f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +493,7 @@ namespace Bit.App.Pages
|
|||||||
EditMode && !CloneMode ? AppResources.ItemUpdated : AppResources.NewItemCreated);
|
EditMode && !CloneMode ? AppResources.ItemUpdated : AppResources.NewItemCreated);
|
||||||
_messagingService.Send(EditMode && !CloneMode ? "editedCipher" : "addedCipher", Cipher.Id);
|
_messagingService.Send(EditMode && !CloneMode ? "editedCipher" : "addedCipher", Cipher.Id);
|
||||||
|
|
||||||
if (Page is AddEditPage page && page.FromAutofillFramework)
|
if (Page is CipherAddEditPage page && page.FromAutofillFramework)
|
||||||
{
|
{
|
||||||
// Close and go back to app
|
// Close and go back to app
|
||||||
_deviceActionService.CloseAutofill();
|
_deviceActionService.CloseAutofill();
|
||||||
@@ -518,7 +502,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (CloneMode)
|
if (CloneMode)
|
||||||
{
|
{
|
||||||
ViewPage?.UpdateCipherId(this.Cipher.Id);
|
CipherDetailsPage?.UpdateCipherId(this.Cipher.Id);
|
||||||
}
|
}
|
||||||
// if the app is tombstoned then PopModalAsync would throw index out of bounds
|
// if the app is tombstoned then PopModalAsync would throw index out of bounds
|
||||||
if (Page.Navigation?.ModalStack?.Count > 0)
|
if (Page.Navigation?.ModalStack?.Count > 0)
|
||||||
@@ -603,7 +587,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public async void UriOptions(LoginUriView uri)
|
public async void UriOptions(LoginUriView uri)
|
||||||
{
|
{
|
||||||
if (!(Page as AddEditPage).DoOnce())
|
if (!(Page as CipherAddEditPage).DoOnce())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -639,9 +623,9 @@ namespace Bit.App.Pages
|
|||||||
Uris.Add(new LoginUriView());
|
Uris.Add(new LoginUriView());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void FieldOptions(AddEditPageFieldViewModel field)
|
public async void FieldOptions(CipherAddEditPageFieldViewModel field)
|
||||||
{
|
{
|
||||||
if (!(Page as AddEditPage).DoOnce())
|
if (!(Page as CipherAddEditPage).DoOnce())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -701,10 +685,10 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (Fields == null)
|
if (Fields == null)
|
||||||
{
|
{
|
||||||
Fields = new ExtendedObservableCollection<AddEditPageFieldViewModel>();
|
Fields = new ExtendedObservableCollection<CipherAddEditPageFieldViewModel>();
|
||||||
}
|
}
|
||||||
var type = fieldTypeOptions.FirstOrDefault(f => f.Value == typeSelection).Key;
|
var type = fieldTypeOptions.FirstOrDefault(f => f.Value == typeSelection).Key;
|
||||||
Fields.Add(new AddEditPageFieldViewModel(Cipher, new FieldView
|
Fields.Add(new CipherAddEditPageFieldViewModel(Cipher, new FieldView
|
||||||
{
|
{
|
||||||
Type = type,
|
Type = type,
|
||||||
Name = string.IsNullOrWhiteSpace(name) ? null : name,
|
Name = string.IsNullOrWhiteSpace(name) ? null : name,
|
||||||
@@ -832,35 +816,11 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
private void TriggerCipherChanged()
|
private void TriggerCipherChanged()
|
||||||
{
|
{
|
||||||
TriggerPropertyChanged(nameof(Cipher), _additionalCipherProperties);
|
TriggerPropertyChanged(nameof(Cipher), AdditionalPropertiesToRaiseOnCipherChanged);
|
||||||
}
|
|
||||||
|
|
||||||
private async void CheckPasswordAsync()
|
|
||||||
{
|
|
||||||
if (!(Page as BaseContentPage).DoOnce())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(Cipher.Login?.Password))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.CheckingPassword);
|
|
||||||
var matches = await _auditService.PasswordLeakedAsync(Cipher.Login.Password);
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
if (matches > 0)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(string.Format(AppResources.PasswordExposed,
|
|
||||||
matches.ToString("N0")));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.PasswordSafe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AddEditPageFieldViewModel : ExtendedViewModel
|
public class CipherAddEditPageFieldViewModel : ExtendedViewModel
|
||||||
{
|
{
|
||||||
private II18nService _i18nService;
|
private II18nService _i18nService;
|
||||||
private FieldView _field;
|
private FieldView _field;
|
||||||
@@ -876,7 +836,7 @@ namespace Bit.App.Pages
|
|||||||
nameof(IsLinkedType),
|
nameof(IsLinkedType),
|
||||||
};
|
};
|
||||||
|
|
||||||
public AddEditPageFieldViewModel(CipherView cipher, FieldView field)
|
public CipherAddEditPageFieldViewModel(CipherView cipher, FieldView field)
|
||||||
{
|
{
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
||||||
_cipher = cipher;
|
_cipher = cipher;
|
||||||
@@ -2,18 +2,18 @@
|
|||||||
<pages:BaseContentPage
|
<pages:BaseContentPage
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
x:Class="Bit.App.Pages.ViewPage"
|
x:Class="Bit.App.Pages.CipherDetailsPage"
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
xmlns:controls="clr-namespace:Bit.App.Controls"
|
||||||
xmlns:effects="clr-namespace:Bit.App.Effects"
|
xmlns:effects="clr-namespace:Bit.App.Effects"
|
||||||
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
|
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
|
||||||
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
||||||
x:DataType="pages:ViewPageViewModel"
|
x:DataType="pages:CipherDetailsPageViewModel"
|
||||||
x:Name="_page"
|
x:Name="_page"
|
||||||
Title="{Binding PageTitle}">
|
Title="{Binding PageTitle}">
|
||||||
<ContentPage.BindingContext>
|
<ContentPage.BindingContext>
|
||||||
<pages:ViewPageViewModel />
|
<pages:CipherDetailsPageViewModel />
|
||||||
</ContentPage.BindingContext>
|
</ContentPage.BindingContext>
|
||||||
|
|
||||||
<ContentPage.Resources>
|
<ContentPage.Resources>
|
||||||
@@ -540,7 +540,7 @@
|
|||||||
</StackLayout>
|
</StackLayout>
|
||||||
<controls:RepeaterView ItemsSource="{Binding Fields}">
|
<controls:RepeaterView ItemsSource="{Binding Fields}">
|
||||||
<controls:RepeaterView.ItemTemplate>
|
<controls:RepeaterView.ItemTemplate>
|
||||||
<DataTemplate x:DataType="pages:ViewPageFieldViewModel">
|
<DataTemplate x:DataType="pages:CipherDetailsPageFieldViewModel">
|
||||||
<StackLayout Spacing="0" Padding="0">
|
<StackLayout Spacing="0" Padding="0">
|
||||||
<Grid StyleClass="box-row">
|
<Grid StyleClass="box-row">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -571,6 +571,8 @@
|
|||||||
IsVisible="{Binding IsLinkedType}" />
|
IsVisible="{Binding IsLinkedType}" />
|
||||||
<controls:IconLabel
|
<controls:IconLabel
|
||||||
Text="{Binding ValueText, Mode=OneWay}"
|
Text="{Binding ValueText, Mode=OneWay}"
|
||||||
|
AutomationProperties.IsInAccessibleTree="true"
|
||||||
|
AutomationProperties.Name="{Binding ValueAccessibilityText, Mode=OneWay}"
|
||||||
StyleClass="box-value"
|
StyleClass="box-value"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@@ -9,18 +9,18 @@ using Xamarin.Forms;
|
|||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class ViewPage : BaseContentPage
|
public partial class CipherDetailsPage : BaseContentPage
|
||||||
{
|
{
|
||||||
private readonly IBroadcasterService _broadcasterService;
|
private readonly IBroadcasterService _broadcasterService;
|
||||||
private readonly ISyncService _syncService;
|
private readonly ISyncService _syncService;
|
||||||
private ViewPageViewModel _vm;
|
private CipherDetailsPageViewModel _vm;
|
||||||
|
|
||||||
public ViewPage(string cipherId)
|
public CipherDetailsPage(string cipherId)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
||||||
_vm = BindingContext as ViewPageViewModel;
|
_vm = BindingContext as CipherDetailsPageViewModel;
|
||||||
_vm.Page = this;
|
_vm.Page = this;
|
||||||
_vm.CipherId = cipherId;
|
_vm.CipherId = cipherId;
|
||||||
SetActivityIndicator(_mainContent);
|
SetActivityIndicator(_mainContent);
|
||||||
@@ -40,7 +40,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewPageViewModel ViewModel => _vm;
|
public CipherDetailsPageViewModel ViewModel => _vm;
|
||||||
|
|
||||||
public void UpdateCipherId(string cipherId)
|
public void UpdateCipherId(string cipherId)
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ namespace Bit.App.Pages
|
|||||||
IsBusy = true;
|
IsBusy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcasterService.Subscribe(nameof(ViewPage), async (message) =>
|
_broadcasterService.Subscribe(nameof(CipherDetailsPage), async (message) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
_broadcasterService.Unsubscribe(nameof(ViewPage));
|
_broadcasterService.Unsubscribe(nameof(CipherDetailsPage));
|
||||||
_vm.CleanUp();
|
_vm.CleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Navigation.PushModalAsync(new NavigationPage(new AddEditPage(_vm.CipherId)));
|
await Navigation.PushModalAsync(new NavigationPage(new CipherAddEditPage(_vm.CipherId)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var page = new AddEditPage(_vm.CipherId, cloneMode: true, viewPage: this);
|
var page = new CipherAddEditPage(_vm.CipherId, cloneMode: true, cipherDetailsPage: this);
|
||||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
else if (selection == AppResources.Clone)
|
else if (selection == AppResources.Clone)
|
||||||
{
|
{
|
||||||
var page = new AddEditPage(_vm.CipherId, cloneMode: true, viewPage: this);
|
var page = new CipherAddEditPage(_vm.CipherId, cloneMode: true, cipherDetailsPage: this);
|
||||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,23 +17,18 @@ using Xamarin.Forms;
|
|||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class ViewPageViewModel : BaseViewModel
|
public class CipherDetailsPageViewModel : BaseCipherViewModel
|
||||||
{
|
{
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly ICipherService _cipherService;
|
private readonly ICipherService _cipherService;
|
||||||
private readonly IStateService _stateService;
|
private readonly IStateService _stateService;
|
||||||
private readonly ITotpService _totpService;
|
private readonly ITotpService _totpService;
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IAuditService _auditService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
private readonly IMessagingService _messagingService;
|
||||||
private readonly IEventService _eventService;
|
private readonly IEventService _eventService;
|
||||||
private readonly IPasswordRepromptService _passwordRepromptService;
|
private readonly IPasswordRepromptService _passwordRepromptService;
|
||||||
private readonly ILocalizeService _localizeService;
|
private readonly ILocalizeService _localizeService;
|
||||||
private readonly IClipboardService _clipboardService;
|
private readonly IClipboardService _clipboardService;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private CipherView _cipher;
|
private List<CipherDetailsPageFieldViewModel> _fields;
|
||||||
private List<ViewPageFieldViewModel> _fields;
|
|
||||||
private bool _canAccessPremium;
|
private bool _canAccessPremium;
|
||||||
private bool _showPassword;
|
private bool _showPassword;
|
||||||
private bool _showCardNumber;
|
private bool _showCardNumber;
|
||||||
@@ -48,20 +43,16 @@ namespace Bit.App.Pages
|
|||||||
private string _attachmentFilename;
|
private string _attachmentFilename;
|
||||||
private bool _passwordReprompted;
|
private bool _passwordReprompted;
|
||||||
|
|
||||||
public ViewPageViewModel()
|
public CipherDetailsPageViewModel()
|
||||||
{
|
{
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
||||||
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||||
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
||||||
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
|
||||||
|
|
||||||
CopyCommand = new AsyncCommand<string>((id) => CopyAsync(id, null), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyCommand = new AsyncCommand<string>((id) => CopyAsync(id, null), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
CopyUriCommand = new AsyncCommand<LoginUriView>(uriView => CopyAsync("LoginUri", uriView.Uri), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
CopyUriCommand = new AsyncCommand<LoginUriView>(uriView => CopyAsync("LoginUri", uriView.Uri), onException: ex => _logger.Exception(ex), allowsMultipleExecutions: false);
|
||||||
@@ -70,8 +61,7 @@ namespace Bit.App.Pages
|
|||||||
TogglePasswordCommand = new Command(TogglePassword);
|
TogglePasswordCommand = new Command(TogglePassword);
|
||||||
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
ToggleCardNumberCommand = new Command(ToggleCardNumber);
|
||||||
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
ToggleCardCodeCommand = new Command(ToggleCardCode);
|
||||||
CheckPasswordCommand = new Command(CheckPasswordAsync);
|
DownloadAttachmentCommand = new AsyncCommand<AttachmentView>(DownloadAttachmentAsync, allowsMultipleExecutions: false);
|
||||||
DownloadAttachmentCommand = new Command<AttachmentView>(DownloadAttachmentAsync);
|
|
||||||
|
|
||||||
PageTitle = AppResources.ViewItem;
|
PageTitle = AppResources.ViewItem;
|
||||||
}
|
}
|
||||||
@@ -83,32 +73,26 @@ namespace Bit.App.Pages
|
|||||||
public Command TogglePasswordCommand { get; set; }
|
public Command TogglePasswordCommand { get; set; }
|
||||||
public Command ToggleCardNumberCommand { get; set; }
|
public Command ToggleCardNumberCommand { get; set; }
|
||||||
public Command ToggleCardCodeCommand { get; set; }
|
public Command ToggleCardCodeCommand { get; set; }
|
||||||
public Command CheckPasswordCommand { get; set; }
|
public AsyncCommand<AttachmentView> DownloadAttachmentCommand { get; set; }
|
||||||
public Command DownloadAttachmentCommand { get; set; }
|
|
||||||
public string CipherId { get; set; }
|
public string CipherId { get; set; }
|
||||||
public CipherView Cipher
|
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
|
||||||
{
|
{
|
||||||
get => _cipher;
|
nameof(IsLogin),
|
||||||
set => SetProperty(ref _cipher, value,
|
nameof(IsIdentity),
|
||||||
additionalPropertyNames: new string[]
|
nameof(IsCard),
|
||||||
{
|
nameof(IsSecureNote),
|
||||||
nameof(IsLogin),
|
nameof(ShowUris),
|
||||||
nameof(IsIdentity),
|
nameof(ShowAttachments),
|
||||||
nameof(IsCard),
|
nameof(ShowTotp),
|
||||||
nameof(IsSecureNote),
|
nameof(ColoredPassword),
|
||||||
nameof(ShowUris),
|
nameof(UpdatedText),
|
||||||
nameof(ShowAttachments),
|
nameof(PasswordUpdatedText),
|
||||||
nameof(ShowTotp),
|
nameof(PasswordHistoryText),
|
||||||
nameof(ColoredPassword),
|
nameof(ShowIdentityAddress),
|
||||||
nameof(UpdatedText),
|
nameof(IsDeleted),
|
||||||
nameof(PasswordUpdatedText),
|
nameof(CanEdit),
|
||||||
nameof(PasswordHistoryText),
|
};
|
||||||
nameof(ShowIdentityAddress),
|
public List<CipherDetailsPageFieldViewModel> Fields
|
||||||
nameof(IsDeleted),
|
|
||||||
nameof(CanEdit),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public List<ViewPageFieldViewModel> Fields
|
|
||||||
{
|
{
|
||||||
get => _fields;
|
get => _fields;
|
||||||
set => SetProperty(ref _fields, value);
|
set => SetProperty(ref _fields, value);
|
||||||
@@ -256,7 +240,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
Cipher = await cipher.DecryptAsync();
|
Cipher = await cipher.DecryptAsync();
|
||||||
CanAccessPremium = await _stateService.CanAccessPremiumAsync();
|
CanAccessPremium = await _stateService.CanAccessPremiumAsync();
|
||||||
Fields = Cipher.Fields?.Select(f => new ViewPageFieldViewModel(this, Cipher, f)).ToList();
|
Fields = Cipher.Fields?.Select(f => new CipherDetailsPageFieldViewModel(this, Cipher, f)).ToList();
|
||||||
|
|
||||||
if (Cipher.Type == Core.Enums.CipherType.Login && !string.IsNullOrWhiteSpace(Cipher.Login.Totp) &&
|
if (Cipher.Type == Core.Enums.CipherType.Login && !string.IsNullOrWhiteSpace(Cipher.Login.Totp) &&
|
||||||
(Cipher.OrganizationUseTotp || CanAccessPremium))
|
(Cipher.OrganizationUseTotp || CanAccessPremium))
|
||||||
@@ -455,86 +439,52 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void CheckPasswordAsync()
|
private async Task DownloadAttachmentAsync(AttachmentView attachment)
|
||||||
{
|
{
|
||||||
if (!(Page as BaseContentPage).DoOnce())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(Cipher.Login?.Password))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
|
|
||||||
AppResources.InternetConnectionRequiredTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.CheckingPassword);
|
|
||||||
var matches = await _auditService.PasswordLeakedAsync(Cipher.Login.Password);
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
if (matches > 0)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(string.Format(AppResources.PasswordExposed,
|
|
||||||
matches.ToString("N0")));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.PasswordSafe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void DownloadAttachmentAsync(AttachmentView attachment)
|
|
||||||
{
|
|
||||||
if (!(Page as BaseContentPage).DoOnce())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
|
|
||||||
AppResources.InternetConnectionRequiredTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Cipher.OrganizationId == null && !CanAccessPremium)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.PremiumRequired);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (attachment.FileSize >= 10485760) // 10 MB
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(
|
|
||||||
string.Format(AppResources.AttachmentLargeWarning, attachment.SizeName), null,
|
|
||||||
AppResources.Yes, AppResources.No);
|
|
||||||
if (!confirmed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var canOpenFile = true;
|
|
||||||
if (!_deviceActionService.CanOpenFile(attachment.FileName))
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
// iOS is currently hardcoded to always return CanOpenFile == true, but should it ever return false
|
|
||||||
// for any reason we want to be sure to catch it here.
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.UnableToOpenFile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
canOpenFile = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await PromptPasswordAsync())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.Downloading);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
|
||||||
|
{
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
|
||||||
|
AppResources.InternetConnectionRequiredTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Cipher.OrganizationId == null && !CanAccessPremium)
|
||||||
|
{
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.PremiumRequired);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attachment.FileSize >= 10485760) // 10 MB
|
||||||
|
{
|
||||||
|
var confirmed = await _platformUtilsService.ShowDialogAsync(
|
||||||
|
string.Format(AppResources.AttachmentLargeWarning, attachment.SizeName), null,
|
||||||
|
AppResources.Yes, AppResources.No);
|
||||||
|
if (!confirmed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var canOpenFile = true;
|
||||||
|
if (!_deviceActionService.CanOpenFile(attachment.FileName))
|
||||||
|
{
|
||||||
|
if (Device.RuntimePlatform == Device.iOS)
|
||||||
|
{
|
||||||
|
// iOS is currently hardcoded to always return CanOpenFile == true, but should it ever return false
|
||||||
|
// for any reason we want to be sure to catch it here.
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.UnableToOpenFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
canOpenFile = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await PromptPasswordAsync())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _deviceActionService.ShowLoadingAsync(AppResources.Downloading);
|
||||||
var data = await _cipherService.DownloadAndDecryptAttachmentAsync(Cipher.Id, attachment, Cipher.OrganizationId);
|
var data = await _cipherService.DownloadAndDecryptAttachmentAsync(Cipher.Id, attachment, Cipher.OrganizationId);
|
||||||
await _deviceActionService.HideLoadingAsync();
|
await _deviceActionService.HideLoadingAsync();
|
||||||
if (data == null)
|
if (data == null)
|
||||||
@@ -561,9 +511,11 @@ namespace Bit.App.Pages
|
|||||||
OpenAttachment(data, attachment);
|
OpenAttachment(data, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
await _deviceActionService.HideLoadingAsync();
|
await _deviceActionService.HideLoadingAsync();
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,15 +655,15 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ViewPageFieldViewModel : ExtendedViewModel
|
public class CipherDetailsPageFieldViewModel : ExtendedViewModel
|
||||||
{
|
{
|
||||||
private II18nService _i18nService;
|
private II18nService _i18nService;
|
||||||
private ViewPageViewModel _vm;
|
private CipherDetailsPageViewModel _vm;
|
||||||
private FieldView _field;
|
private FieldView _field;
|
||||||
private CipherView _cipher;
|
private CipherView _cipher;
|
||||||
private bool _showHiddenValue;
|
private bool _showHiddenValue;
|
||||||
|
|
||||||
public ViewPageFieldViewModel(ViewPageViewModel vm, CipherView cipher, FieldView field)
|
public CipherDetailsPageFieldViewModel(CipherDetailsPageViewModel vm, CipherView cipher, FieldView field)
|
||||||
{
|
{
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
||||||
_vm = vm;
|
_vm = vm;
|
||||||
@@ -727,6 +679,7 @@ namespace Bit.App.Pages
|
|||||||
additionalPropertyNames: new string[]
|
additionalPropertyNames: new string[]
|
||||||
{
|
{
|
||||||
nameof(ValueText),
|
nameof(ValueText),
|
||||||
|
nameof(ValueAccessibilityText),
|
||||||
nameof(IsBooleanType),
|
nameof(IsBooleanType),
|
||||||
nameof(IsHiddenType),
|
nameof(IsHiddenType),
|
||||||
nameof(IsTextType),
|
nameof(IsTextType),
|
||||||
@@ -750,7 +703,7 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
if (IsBooleanType)
|
if (IsBooleanType)
|
||||||
{
|
{
|
||||||
return _field.Value == "true" ? BitwardenIcons.CheckSquare : BitwardenIcons.Square;
|
return _field.BoolValue ? BitwardenIcons.CheckSquare : BitwardenIcons.Square;
|
||||||
}
|
}
|
||||||
else if (IsLinkedType)
|
else if (IsLinkedType)
|
||||||
{
|
{
|
||||||
@@ -764,6 +717,19 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ValueAccessibilityText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsBooleanType)
|
||||||
|
{
|
||||||
|
return _field.BoolValue ? AppResources.Enabled : AppResources.Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValueText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public FormattedString ColoredHiddenValue => PasswordFormatter.FormatPassword(_field.Value);
|
public FormattedString ColoredHiddenValue => PasswordFormatter.FormatPassword(_field.Value);
|
||||||
|
|
||||||
public Command ToggleHiddenValueCommand { get; set; }
|
public Command ToggleHiddenValueCommand { get; set; }
|
||||||
@@ -159,7 +159,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (selection == AppResources.View || string.IsNullOrWhiteSpace(AutofillUrl))
|
if (selection == AppResources.View || string.IsNullOrWhiteSpace(AutofillUrl))
|
||||||
{
|
{
|
||||||
var page = new ViewPage(cipher.Id);
|
var page = new CipherDetailsPage(cipher.Id);
|
||||||
await Page.Navigation.PushModalAsync(new NavigationPage(page));
|
await Page.Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
else if (selection == AppResources.Autofill || selection == AppResources.AutofillAndSave)
|
else if (selection == AppResources.Autofill || selection == AppResources.AutofillAndSave)
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ namespace Bit.App.Pages
|
|||||||
}
|
}
|
||||||
if (!_vm.Deleted && DoOnce())
|
if (!_vm.Deleted && DoOnce())
|
||||||
{
|
{
|
||||||
var page = new AddEditPage(null, _vm.Type, _vm.FolderId, _vm.CollectionId, _vm.GetVaultFilterOrgId());
|
var page = new CipherAddEditPage(null, _vm.Type, _vm.FolderId, _vm.CollectionId, _vm.GetVaultFilterOrgId());
|
||||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,11 +298,11 @@ namespace Bit.App.Pages
|
|||||||
await _accountListOverlay.HideAsync();
|
await _accountListOverlay.HideAsync();
|
||||||
if (_previousPage.Page == "view" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
|
if (_previousPage.Page == "view" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
|
||||||
{
|
{
|
||||||
await Navigation.PushModalAsync(new NavigationPage(new ViewPage(_previousPage.CipherId)));
|
await Navigation.PushModalAsync(new NavigationPage(new CipherDetailsPage(_previousPage.CipherId)));
|
||||||
}
|
}
|
||||||
else if (_previousPage.Page == "edit" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
|
else if (_previousPage.Page == "edit" && !string.IsNullOrWhiteSpace(_previousPage.CipherId))
|
||||||
{
|
{
|
||||||
await Navigation.PushModalAsync(new NavigationPage(new AddEditPage(_previousPage.CipherId)));
|
await Navigation.PushModalAsync(new NavigationPage(new CipherAddEditPage(_previousPage.CipherId)));
|
||||||
}
|
}
|
||||||
_previousPage = null;
|
_previousPage = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ namespace Bit.App.Pages
|
|||||||
|
|
||||||
public async Task SelectCipherAsync(CipherView cipher)
|
public async Task SelectCipherAsync(CipherView cipher)
|
||||||
{
|
{
|
||||||
var page = new ViewPage(cipher.Id);
|
var page = new CipherDetailsPage(cipher.Id);
|
||||||
await Page.Navigation.PushModalAsync(new NavigationPage(page));
|
await Page.Navigation.PushModalAsync(new NavigationPage(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9267
src/App/Resources/AppResources.Designer.cs
generated
9267
src/App/Resources/AppResources.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -418,7 +418,7 @@
|
|||||||
<value>Use the Bitwarden accessibility service to auto-fill your logins across apps and the web.</value>
|
<value>Use the Bitwarden accessibility service to auto-fill your logins across apps and the web.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AutofillService" xml:space="preserve">
|
<data name="AutofillService" xml:space="preserve">
|
||||||
<value>Auto-fill Service</value>
|
<value>Auto-fill service</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||||
<value>Avoid Ambiguous Characters</value>
|
<value>Avoid Ambiguous Characters</value>
|
||||||
@@ -445,7 +445,7 @@
|
|||||||
<value>You can change your email address on the bitwarden.com web vault. Do you want to visit the website now?</value>
|
<value>You can change your email address on the bitwarden.com web vault. Do you want to visit the website now?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ChangeMasterPassword" xml:space="preserve">
|
<data name="ChangeMasterPassword" xml:space="preserve">
|
||||||
<value>Change Master Password</value>
|
<value>Change master password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ChangePasswordConfirmation" xml:space="preserve">
|
<data name="ChangePasswordConfirmation" xml:space="preserve">
|
||||||
<value>You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?</value>
|
<value>You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?</value>
|
||||||
@@ -473,13 +473,13 @@
|
|||||||
<value>Enter your account email address to receive your master password hint.</value>
|
<value>Enter your account email address to receive your master password hint.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ExntesionReenable" xml:space="preserve">
|
<data name="ExntesionReenable" xml:space="preserve">
|
||||||
<value>Re-enable App Extension</value>
|
<value>Re-enable app extension</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ExtensionAlmostDone" xml:space="preserve">
|
<data name="ExtensionAlmostDone" xml:space="preserve">
|
||||||
<value>Almost done!</value>
|
<value>Almost done!</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ExtensionEnable" xml:space="preserve">
|
<data name="ExtensionEnable" xml:space="preserve">
|
||||||
<value>Enable App Extension</value>
|
<value>Enable app extension</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ExtensionInSafari" xml:space="preserve">
|
<data name="ExtensionInSafari" xml:space="preserve">
|
||||||
<value>In Safari, find Bitwarden using the share icon (hint: scroll to the right on the bottom row of the menu).</value>
|
<value>In Safari, find Bitwarden using the share icon (hint: scroll to the right on the bottom row of the menu).</value>
|
||||||
@@ -694,7 +694,7 @@
|
|||||||
<value>Syncing failed.</value>
|
<value>Syncing failed.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SyncVaultNow" xml:space="preserve">
|
<data name="SyncVaultNow" xml:space="preserve">
|
||||||
<value>Sync Vault Now</value>
|
<value>Sync vault now</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TouchID" xml:space="preserve">
|
<data name="TouchID" xml:space="preserve">
|
||||||
<value>Touch ID</value>
|
<value>Touch ID</value>
|
||||||
@@ -723,7 +723,7 @@
|
|||||||
<value>View Item</value>
|
<value>View Item</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="WebVault" xml:space="preserve">
|
<data name="WebVault" xml:space="preserve">
|
||||||
<value>Bitwarden Web Vault</value>
|
<value>Bitwarden web vault</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Lost2FAApp" xml:space="preserve">
|
<data name="Lost2FAApp" xml:space="preserve">
|
||||||
<value>Lost authenticator app?</value>
|
<value>Lost authenticator app?</value>
|
||||||
@@ -733,7 +733,7 @@
|
|||||||
<comment>Screen title</comment>
|
<comment>Screen title</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="ExtensionActivated" xml:space="preserve">
|
<data name="ExtensionActivated" xml:space="preserve">
|
||||||
<value>Extension Activated!</value>
|
<value>Extension activated!</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Icons" xml:space="preserve">
|
<data name="Icons" xml:space="preserve">
|
||||||
<value>Icons</value>
|
<value>Icons</value>
|
||||||
@@ -770,6 +770,12 @@
|
|||||||
<data name="Enabled" xml:space="preserve">
|
<data name="Enabled" xml:space="preserve">
|
||||||
<value>Enabled</value>
|
<value>Enabled</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Off" xml:space="preserve">
|
||||||
|
<value>Off</value>
|
||||||
|
</data>
|
||||||
|
<data name="On" xml:space="preserve">
|
||||||
|
<value>On</value>
|
||||||
|
</data>
|
||||||
<data name="Status" xml:space="preserve">
|
<data name="Status" xml:space="preserve">
|
||||||
<value>Status</value>
|
<value>Status</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -798,7 +804,7 @@
|
|||||||
<value>You are searching for an auto-fill item for "{0}".</value>
|
<value>You are searching for an auto-fill item for "{0}".</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LearnOrg" xml:space="preserve">
|
<data name="LearnOrg" xml:space="preserve">
|
||||||
<value>Learn About Organizations</value>
|
<value>Learn about organizations</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CannotOpenApp" xml:space="preserve">
|
<data name="CannotOpenApp" xml:space="preserve">
|
||||||
<value>Cannot open the app "{0}".</value>
|
<value>Cannot open the app "{0}".</value>
|
||||||
@@ -1542,10 +1548,10 @@
|
|||||||
<value>Default (System)</value>
|
<value>Default (System)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultDarkTheme" xml:space="preserve">
|
<data name="DefaultDarkTheme" xml:space="preserve">
|
||||||
<value>Default Dark Theme</value>
|
<value>Default dark theme</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultDarkThemeDescription" xml:space="preserve">
|
<data name="DefaultDarkThemeDescription" xml:space="preserve">
|
||||||
<value>Choose the dark theme to use when using Default (System) theme while your device's dark mode is enabled</value>
|
<value>Choose the dark theme to use when using Default (System) theme while your device's dark mode is enabled.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CopyNotes" xml:space="preserve">
|
<data name="CopyNotes" xml:space="preserve">
|
||||||
<value>Copy Note</value>
|
<value>Copy Note</value>
|
||||||
@@ -1567,11 +1573,11 @@
|
|||||||
<value>Nord</value>
|
<value>Nord</value>
|
||||||
<comment>'Nord' is the name of a specific color scheme. It should not be translated.</comment>
|
<comment>'Nord' is the name of a specific color scheme. It should not be translated.</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="BlacklistedUris" xml:space="preserve">
|
<data name="AutofillBlockedUris" xml:space="preserve">
|
||||||
<value>Blacklisted URIs</value>
|
<value>Auto-fill blocked URIs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="BlacklistedUrisDescription" xml:space="preserve">
|
<data name="AutofillBlockedUrisDescription" xml:space="preserve">
|
||||||
<value>URIs that are blacklisted will not offer auto-fill. The list should be comma separated. Ex: "https://twitter.com, androidapp://com.twitter.android".</value>
|
<value>Auto-fill will not be offered for blocked URIs. Separate multiple URIs with a comma. For example: "https://twitter.com, androidapp://com.twitter.android".</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AskToAddLogin" xml:space="preserve">
|
<data name="AskToAddLogin" xml:space="preserve">
|
||||||
<value>Ask to add login</value>
|
<value>Ask to add login</value>
|
||||||
@@ -1814,16 +1820,16 @@
|
|||||||
<value>Bitwarden needs attention - Enable "Draw-Over" in "Auto-fill Services" from Bitwarden Settings</value>
|
<value>Bitwarden needs attention - Enable "Draw-Over" in "Auto-fill Services" from Bitwarden Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AutofillServices" xml:space="preserve">
|
<data name="AutofillServices" xml:space="preserve">
|
||||||
<value>Auto-fill Services</value>
|
<value>Auto-fill services</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InlineAutofill" xml:space="preserve">
|
<data name="InlineAutofill" xml:space="preserve">
|
||||||
<value>Use Inline Autofill</value>
|
<value>Use inline autofill</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="InlineAutofillDescription" xml:space="preserve">
|
<data name="InlineAutofillDescription" xml:space="preserve">
|
||||||
<value>Use inline autofill if your selected IME (keyboard) supports it. If your configuration is not supported (or this option is disabled), the default Autofill overlay will be used.</value>
|
<value>Use inline autofill if your selected IME (keyboard) supports it. If your configuration is not supported (or this option is disabled), the default Autofill overlay will be used.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Accessibility" xml:space="preserve">
|
<data name="Accessibility" xml:space="preserve">
|
||||||
<value>Use Accessibility</value>
|
<value>Use accessibility</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AccessibilityDescription" xml:space="preserve">
|
<data name="AccessibilityDescription" xml:space="preserve">
|
||||||
<value>Use the Bitwarden Accessibility Service to auto-fill your logins across apps and the web. When enabled, we'll display a popup when login fields are selected.</value>
|
<value>Use the Bitwarden Accessibility Service to auto-fill your logins across apps and the web. When enabled, we'll display a popup when login fields are selected.</value>
|
||||||
@@ -1838,7 +1844,7 @@
|
|||||||
<value>Required to use the Autofill Quick-Action Tile, or to augment the Autofill Service by using Draw-Over (if enabled).</value>
|
<value>Required to use the Autofill Quick-Action Tile, or to augment the Autofill Service by using Draw-Over (if enabled).</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DrawOver" xml:space="preserve">
|
<data name="DrawOver" xml:space="preserve">
|
||||||
<value>Use Draw-Over</value>
|
<value>Use draw-over</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DrawOverDescription" xml:space="preserve">
|
<data name="DrawOverDescription" xml:space="preserve">
|
||||||
<value>When enabled, allows the Bitwarden Accessibility Service to display a popup when login fields are selected.</value>
|
<value>When enabled, allows the Bitwarden Accessibility Service to display a popup when login fields are selected.</value>
|
||||||
@@ -2264,7 +2270,7 @@
|
|||||||
<value>We were unable to process your request. Please try again or contact us.</value>
|
<value>We were unable to process your request. Please try again or contact us.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllowScreenCapture" xml:space="preserve">
|
<data name="AllowScreenCapture" xml:space="preserve">
|
||||||
<value>Allow Screen Capture</value>
|
<value>Allow screen capture</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AreYouSureYouWantToEnableScreenCapture" xml:space="preserve">
|
<data name="AreYouSureYouWantToEnableScreenCapture" xml:space="preserve">
|
||||||
<value>Are you sure you want to enable Screen Capture?</value>
|
<value>Are you sure you want to enable Screen Capture?</value>
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ namespace Bit.App.Utilities
|
|||||||
{
|
{
|
||||||
if (appOptions.FromAutofillFramework && appOptions.SaveType.HasValue)
|
if (appOptions.FromAutofillFramework && appOptions.SaveType.HasValue)
|
||||||
{
|
{
|
||||||
Application.Current.MainPage = new NavigationPage(new AddEditPage(appOptions: appOptions));
|
Application.Current.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: appOptions));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (appOptions.Uri != null)
|
if (appOptions.Uri != null)
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ namespace Bit.App.Utilities.Helpers
|
|||||||
}
|
}
|
||||||
else if (selection == AppResources.View)
|
else if (selection == AppResources.View)
|
||||||
{
|
{
|
||||||
await page.Navigation.PushModalAsync(new NavigationPage(new ViewPage(cipher.Id)));
|
await page.Navigation.PushModalAsync(new NavigationPage(new CipherDetailsPage(cipher.Id)));
|
||||||
}
|
}
|
||||||
else if (selection == AppResources.Edit)
|
else if (selection == AppResources.Edit)
|
||||||
{
|
{
|
||||||
if (await RepromptPasswordIfNeededAsync(cipher))
|
if (await RepromptPasswordIfNeededAsync(cipher))
|
||||||
{
|
{
|
||||||
await page.Navigation.PushModalAsync(new NavigationPage(new AddEditPage(cipher.Id)));
|
await page.Navigation.PushModalAsync(new NavigationPage(new CipherAddEditPage(cipher.Id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (selection == AppResources.CopyUsername)
|
else if (selection == AppResources.CopyUsername)
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ namespace Bit.Core.Models.View
|
|||||||
public string MaskedValue => Value != null ? "••••••••" : null;
|
public string MaskedValue => Value != null ? "••••••••" : null;
|
||||||
public bool NewField { get; set; }
|
public bool NewField { get; set; }
|
||||||
public LinkedIdType? LinkedId { get; set; }
|
public LinkedIdType? LinkedId { get; set; }
|
||||||
|
public bool BoolValue => bool.TryParse(Value, out var b) && b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden.autofill</string>
|
<string>com.8bit.bitwarden.autofill</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2022.6.2</string>
|
<string>2022.6.3</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>CFBundleLocalizations</key>
|
<key>CFBundleLocalizations</key>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden.find-login-action-extension</string>
|
<string>com.8bit.bitwarden.find-login-action-extension</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2022.6.2</string>
|
<string>2022.6.3</string>
|
||||||
<key>CFBundleLocalizations</key>
|
<key>CFBundleLocalizations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>XPC!</string>
|
<string>XPC!</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2022.6.2</string>
|
<string>2022.6.3</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.8bit.bitwarden</string>
|
<string>com.8bit.bitwarden</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2022.6.2</string>
|
<string>2022.6.3</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>CFBundleIconName</key>
|
<key>CFBundleIconName</key>
|
||||||
|
|||||||
Reference in New Issue
Block a user