Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
375f23ac9e | ||
|
|
8e5a01d82c | ||
|
|
910658aa93 | ||
|
|
d766ffa040 | ||
|
|
b960640e03 | ||
|
|
c984617b1c | ||
|
|
a12a7127c0 | ||
|
|
98a6a5c93d | ||
|
|
27202fd740 |
@@ -3,7 +3,7 @@
|
||||
|
||||
# bitwarden mobile
|
||||
|
||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
|
||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a> <a href="https://www.amazon.com/dp/B06XMYGPMV" target="_blank"><img src="https://imgur.com/f75uYeM.png" width="132" height="45"></a>
|
||||
|
||||
The bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
|
||||
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
|
||||
<AndroidStoreUncompressedFileExtensions />
|
||||
<MandroidI18n />
|
||||
|
||||
@@ -53,77 +53,76 @@ namespace Bit.Android
|
||||
|
||||
public override void OnAccessibilityEvent(AccessibilityEvent e)
|
||||
{
|
||||
var root = RootInActiveWindow;
|
||||
if(string.IsNullOrWhiteSpace(e.PackageName) || e.PackageName == SystemUiPackage ||
|
||||
root?.PackageName != e.PackageName)
|
||||
try
|
||||
{
|
||||
return;
|
||||
}
|
||||
var root = RootInActiveWindow;
|
||||
if(e == null || root == null || string.IsNullOrWhiteSpace(e.PackageName) ||
|
||||
e.PackageName == SystemUiPackage || root.PackageName != e.PackageName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
|
||||
var testNodesData = testNodes.Select(n => new { id = n.ViewIdResourceName, text = n.Text });
|
||||
testNodes.Dispose();
|
||||
testNodes = null;
|
||||
*/
|
||||
/*
|
||||
var testNodes = GetWindowNodes(root, e, n => n.ViewIdResourceName != null && n.Text != null, false);
|
||||
var testNodesData = testNodes.Select(n => new { id = n.ViewIdResourceName, text = n.Text });
|
||||
testNodes.Dispose();
|
||||
*/
|
||||
|
||||
var notificationManager = ((NotificationManager)GetSystemService(NotificationService));
|
||||
switch(e.EventType)
|
||||
{
|
||||
case EventTypes.WindowContentChanged:
|
||||
case EventTypes.WindowStateChanged:
|
||||
var cancelNotification = true;
|
||||
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
|
||||
switch(e.EventType)
|
||||
{
|
||||
case EventTypes.WindowContentChanged:
|
||||
case EventTypes.WindowStateChanged:
|
||||
var cancelNotification = true;
|
||||
|
||||
if(e.PackageName == BitwardenPackage)
|
||||
{
|
||||
notificationManager.Cancel(AutoFillNotificationId);
|
||||
break;
|
||||
}
|
||||
|
||||
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
|
||||
if(passwordNodes.Count > 0)
|
||||
{
|
||||
var uri = GetUri(root);
|
||||
if(uri != null && !uri.Contains(BitwardenWebsite))
|
||||
if(e.PackageName == BitwardenPackage)
|
||||
{
|
||||
if(NeedToAutofill(AutofillActivity.LastCredentials, uri))
|
||||
{
|
||||
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
|
||||
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
|
||||
FillCredentials(usernameEditText, passwordNodes);
|
||||
|
||||
allEditTexts.Dispose();
|
||||
allEditTexts = null;
|
||||
usernameEditText.Dispose();
|
||||
usernameEditText = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyToAutofill(uri, notificationManager);
|
||||
cancelNotification = false;
|
||||
}
|
||||
notificationManager?.Cancel(AutoFillNotificationId);
|
||||
break;
|
||||
}
|
||||
|
||||
AutofillActivity.LastCredentials = null;
|
||||
}
|
||||
var passwordNodes = GetWindowNodes(root, e, n => n.Password, false);
|
||||
if(passwordNodes.Count > 0)
|
||||
{
|
||||
var uri = GetUri(root);
|
||||
if(uri != null && !uri.Contains(BitwardenWebsite))
|
||||
{
|
||||
if(NeedToAutofill(AutofillActivity.LastCredentials, uri))
|
||||
{
|
||||
var allEditTexts = GetWindowNodes(root, e, n => EditText(n), false);
|
||||
var usernameEditText = allEditTexts.TakeWhile(n => !n.Password).LastOrDefault();
|
||||
FillCredentials(usernameEditText, passwordNodes);
|
||||
|
||||
passwordNodes.Dispose();
|
||||
passwordNodes = null;
|
||||
allEditTexts.Dispose();
|
||||
usernameEditText.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyToAutofill(uri, notificationManager);
|
||||
cancelNotification = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(cancelNotification)
|
||||
{
|
||||
notificationManager.Cancel(AutoFillNotificationId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
AutofillActivity.LastCredentials = null;
|
||||
}
|
||||
|
||||
passwordNodes.Dispose();
|
||||
|
||||
if(cancelNotification)
|
||||
{
|
||||
notificationManager?.Cancel(AutoFillNotificationId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
notificationManager?.Dispose();
|
||||
root.Dispose();
|
||||
e.Dispose();
|
||||
}
|
||||
|
||||
notificationManager.Dispose();
|
||||
notificationManager = null;
|
||||
root.Dispose();
|
||||
root = null;
|
||||
e.Dispose();
|
||||
// Some unknown condition is causing NullReferenceException's in production. Suppress it for now.
|
||||
catch(NullReferenceException) { }
|
||||
}
|
||||
|
||||
public override void OnInterrupt()
|
||||
@@ -142,7 +141,6 @@ namespace Bit.Android
|
||||
{
|
||||
uri = ExtractUri(uri, addressNode, SupportedBrowsers[root.PackageName]);
|
||||
addressNode.Dispose();
|
||||
addressNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,11 +199,16 @@ namespace Bit.Android
|
||||
|
||||
private static bool EditText(AccessibilityNodeInfo n)
|
||||
{
|
||||
return n.ClassName != null && n.ClassName.Contains("EditText");
|
||||
return n?.ClassName?.Contains("EditText") ?? false;
|
||||
}
|
||||
|
||||
private void NotifyToAutofill(string uri, NotificationManager notificationManager)
|
||||
{
|
||||
if(notificationManager == null || string.IsNullOrWhiteSpace(uri))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var intent = new Intent(this, typeof(AutofillActivity));
|
||||
intent.PutExtra("uri", uri);
|
||||
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
|
||||
@@ -229,15 +232,14 @@ namespace Bit.Android
|
||||
notificationManager.Notify(AutoFillNotificationId, builder.Build());
|
||||
|
||||
builder.Dispose();
|
||||
builder = null;
|
||||
}
|
||||
|
||||
private void FillCredentials(AccessibilityNodeInfo usernameNode, IEnumerable<AccessibilityNodeInfo> passwordNodes)
|
||||
{
|
||||
FillEditText(usernameNode, AutofillActivity.LastCredentials.Username);
|
||||
FillEditText(usernameNode, AutofillActivity.LastCredentials?.Username);
|
||||
foreach(var n in passwordNodes)
|
||||
{
|
||||
FillEditText(n, AutofillActivity.LastCredentials.Password);
|
||||
FillEditText(n, AutofillActivity.LastCredentials?.Password);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.4.0" android:installLocation="auto" android:versionCode="101">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.4.3" android:installLocation="auto" android:versionCode="502">
|
||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
|
||||
@@ -126,26 +126,19 @@ namespace Bit.App.Models.Page
|
||||
return _uriHost;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var host = new Uri(Uri).Host;
|
||||
|
||||
DomainName domain;
|
||||
if(DomainName.TryParse(host, out domain))
|
||||
{
|
||||
_uriHost = domain.BaseDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
_uriHost = host;
|
||||
}
|
||||
|
||||
return _uriHost;
|
||||
}
|
||||
catch
|
||||
Uri uri;
|
||||
if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out uri))
|
||||
{
|
||||
return Uri;
|
||||
}
|
||||
|
||||
DomainName domain;
|
||||
if(DomainName.TryParse(uri.Host, out domain))
|
||||
{
|
||||
return domain.BaseDomain;
|
||||
}
|
||||
|
||||
return uri.Host;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -213,29 +213,49 @@ namespace Bit.App.Pages
|
||||
AlertNoConnection();
|
||||
}
|
||||
|
||||
PasswordCell.InitEvents();
|
||||
UsernameCell.InitEvents();
|
||||
UriCell.InitEvents();
|
||||
NameCell.InitEvents();
|
||||
NotesCell.InitEvents();
|
||||
FolderCell.InitEvents();
|
||||
PasswordCell.Button.Clicked += PasswordButton_Clicked;
|
||||
GenerateCell.Tapped += GenerateCell_Tapped;
|
||||
DeleteCell.Tapped += DeleteCell_Tapped;
|
||||
PasswordCell?.InitEvents();
|
||||
UsernameCell?.InitEvents();
|
||||
UriCell?.InitEvents();
|
||||
NameCell?.InitEvents();
|
||||
NotesCell?.InitEvents();
|
||||
FolderCell?.InitEvents();
|
||||
|
||||
if(PasswordCell?.Button != null)
|
||||
{
|
||||
PasswordCell.Button.Clicked += PasswordButton_Clicked;
|
||||
}
|
||||
if(GenerateCell != null)
|
||||
{
|
||||
GenerateCell.Tapped += GenerateCell_Tapped;
|
||||
}
|
||||
if(DeleteCell != null)
|
||||
{
|
||||
DeleteCell.Tapped += DeleteCell_Tapped;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisappearing()
|
||||
{
|
||||
base.OnDisappearing();
|
||||
PasswordCell.Dispose();
|
||||
UsernameCell.Dispose();
|
||||
UriCell.Dispose();
|
||||
NameCell.Dispose();
|
||||
NotesCell.Dispose();
|
||||
FolderCell.Dispose();
|
||||
PasswordCell.Button.Clicked -= PasswordButton_Clicked;
|
||||
GenerateCell.Tapped -= GenerateCell_Tapped;
|
||||
DeleteCell.Tapped -= DeleteCell_Tapped;
|
||||
PasswordCell?.Dispose();
|
||||
UsernameCell?.Dispose();
|
||||
UriCell?.Dispose();
|
||||
NameCell?.Dispose();
|
||||
NotesCell?.Dispose();
|
||||
FolderCell?.Dispose();
|
||||
|
||||
if(PasswordCell?.Button != null)
|
||||
{
|
||||
PasswordCell.Button.Clicked -= PasswordButton_Clicked;
|
||||
}
|
||||
if(GenerateCell != null)
|
||||
{
|
||||
GenerateCell.Tapped -= GenerateCell_Tapped;
|
||||
}
|
||||
if(DeleteCell != null)
|
||||
{
|
||||
DeleteCell.Tapped -= DeleteCell_Tapped;
|
||||
}
|
||||
}
|
||||
|
||||
private void PasswordButton_Clicked(object sender, EventArgs e)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.4.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.4.1</string>
|
||||
<key>UIMainStoryboardFile~ipad</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
|
||||
28
store/amazon/en/CAPTIONS.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Feature Graphic
|
||||
|
||||
A secure and free password manager for all of your devices
|
||||
|
||||
# Screenshot 1
|
||||
|
||||
Manage all your logins and passwords from a secure vault
|
||||
|
||||
# Screenshot 2
|
||||
|
||||
Automatically generate strong, random, and secure passwords
|
||||
|
||||
# Screenshot 3
|
||||
|
||||
Protect your vault with fingerprint, PIN code, or master password
|
||||
|
||||
# Screenshot 4
|
||||
|
||||
Quickly auto-fill logins from within your web browser and other apps
|
||||
|
||||
# Screenshot 5
|
||||
|
||||
Sync and access your vault from multiple devices
|
||||
|
||||
- Phone
|
||||
- Tablet
|
||||
- Desktop
|
||||
- Web
|
||||
19
store/amazon/en/COPY.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Title
|
||||
|
||||
bitwarden Free Password Manager
|
||||
|
||||
# Description
|
||||
|
||||
bitwarden is the easiest and safest way to store all of your logins and passwords while conveniently keeping them synced between all of your devices.
|
||||
|
||||
Password theft is a serious problem. The websites and apps that you use are under attack every day. Security breaches occur and your passwords are stolen. When you reuse the same passwords across apps and websites hackers can easily access your email, bank, and other important accounts.
|
||||
|
||||
Security experts recommend that you use a different, randomly generated password for every account that you create. But how do you manage all those passwords? bitwarden makes it easy for you to create, store, and access your passwords.
|
||||
|
||||
bitwarden stores all of your logins in an encrypted vault that syncs across all of your devices. Since it's fully encrypted before it ever leaves your device, only you have access to your data. Not even the team at bitwarden can read your data, even if we wanted to. Your data is sealed with AES-256 bit encryption, salted hashing, and PBKDF2 SHA-256.
|
||||
|
||||
# Product Feature Bullets
|
||||
|
||||
- Sync your logins and passwords across all your browsers and devices
|
||||
- Fill in logins on the web and in other apps automatically
|
||||
- Automatically generate strong, secure passwords for your logins
|
||||
BIN
store/amazon/en/assets/feature-graphic.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
store/amazon/en/assets/large-icon.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
store/amazon/en/assets/small-icon.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
store/amazon/en/screenshots/Nexus 5x - Screenshot 1.png
Normal file
|
After Width: | Height: | Size: 441 KiB |
BIN
store/amazon/en/screenshots/Nexus 5x - Screenshot 2.png
Normal file
|
After Width: | Height: | Size: 374 KiB |
BIN
store/amazon/en/screenshots/Nexus 5x - Screenshot 3.png
Normal file
|
After Width: | Height: | Size: 325 KiB |
BIN
store/amazon/en/screenshots/Nexus 5x - Screenshot 4.png
Normal file
|
After Width: | Height: | Size: 443 KiB |
BIN
store/amazon/en/screenshots/Nexus 5x - Screenshot 5.png
Normal file
|
After Width: | Height: | Size: 402 KiB |
@@ -16,7 +16,7 @@
|
||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
|
||||