Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad55e8a8c | ||
|
|
a8a1750d5c | ||
|
|
5407e20150 | ||
|
|
58aa37bf8e | ||
|
|
7c781b60c5 | ||
|
|
acdfce7e88 | ||
|
|
4e4b56d7fe | ||
|
|
a3174d7015 | ||
|
|
b595c8aeac | ||
|
|
a9a33ad71e | ||
|
|
4d08ce90cc | ||
|
|
01d9ccc110 | ||
|
|
029f069ad5 | ||
|
|
13b9e01604 | ||
|
|
19c46a472a | ||
|
|
37edfffb97 | ||
|
|
67fa653d06 | ||
|
|
366b9ddc4a | ||
|
|
c9354f79b8 | ||
|
|
d5b3bd5905 | ||
|
|
45dd240415 | ||
|
|
bf99cea004 | ||
|
|
f680b1e856 | ||
|
|
b2f40c7af0 | ||
|
|
82b17677b9 | ||
|
|
b7df2d5441 | ||
|
|
dd511ba365 | ||
|
|
d705e3c1fb | ||
|
|
4bd1322904 | ||
|
|
ac027ee3a0 | ||
|
|
e5e3ebdbba | ||
|
|
993fc2e6f4 | ||
|
|
61c480618c | ||
|
|
db7f2622c8 | ||
|
|
a39e78a989 | ||
|
|
5a461d68a7 | ||
|
|
899816673c | ||
|
|
84a10139c1 | ||
|
|
da3aa56d86 | ||
|
|
a6dcd512ea | ||
|
|
572d32c1de | ||
|
|
e8b67ead1e | ||
|
|
377029226e | ||
|
|
72d1421f1d | ||
|
|
d359547dab | ||
|
|
9523c7ab33 | ||
|
|
7cac07c185 | ||
|
|
a607a7f3ef | ||
|
|
b5277e89d5 | ||
|
|
99713f8ed7 | ||
|
|
145dac500c | ||
|
|
eefd9bf31c | ||
|
|
3f47ca645b | ||
|
|
c906f037b5 | ||
|
|
ffc4e32119 | ||
|
|
51eb46241b | ||
|
|
541416f64b | ||
|
|
14d1d132a3 | ||
|
|
22a0045796 | ||
|
|
2e5ba0335d | ||
|
|
3315704c14 | ||
|
|
f90c407fb6 | ||
|
|
d3646e10a5 | ||
|
|
d3003efe72 | ||
|
|
235ca947be | ||
|
|
e7bc9ed5ba | ||
|
|
740a18dbc0 | ||
|
|
add5189bb1 | ||
|
|
62002b8bb3 | ||
|
|
41b4ee33fe | ||
|
|
85c67ac676 | ||
|
|
4637b7d93f | ||
|
|
8b9a178c87 | ||
|
|
c595c381a9 | ||
|
|
c308d7a610 | ||
|
|
f7570122c6 | ||
|
|
1e5f186b58 | ||
|
|
b732b2ffa7 | ||
|
|
617a7be4f3 | ||
|
|
5c5e368d6b | ||
|
|
ff9f49416a | ||
|
|
93cae0e9cc | ||
|
|
61e75ce747 | ||
|
|
50affe26c5 | ||
|
|
8566362607 | ||
|
|
36925770d0 | ||
|
|
d17ca1686e | ||
|
|
2ad709dae4 | ||
|
|
5a3d86a12a | ||
|
|
1a4ba36820 | ||
|
|
ddeae3b5ba | ||
|
|
10df9e7cd5 | ||
|
|
be11933c60 | ||
|
|
d2db68b781 | ||
|
|
da6e271584 | ||
|
|
5103c80e1e | ||
|
|
b5c80ea267 | ||
|
|
b5747fbb44 | ||
|
|
215ded8a77 | ||
|
|
e7ab6da068 | ||
|
|
ee881f67ee | ||
|
|
f33248aa4f | ||
|
|
c6a40bac03 | ||
|
|
aa38e79d08 | ||
|
|
9cac10e559 | ||
|
|
efbd418f56 | ||
|
|
4ff3464abd | ||
|
|
907ddbf903 | ||
|
|
7041991d5a | ||
|
|
b26067e5da | ||
|
|
e519b13533 | ||
|
|
30bc3867bf | ||
|
|
5326c3aecc | ||
|
|
c95251c903 | ||
|
|
e08a0a0938 | ||
|
|
fcb072c37d | ||
|
|
262c19b194 | ||
|
|
1031ddcd83 | ||
|
|
aaee0212f0 | ||
|
|
8fc95759ba | ||
|
|
b6a3a0a54f | ||
|
|
e3091be314 | ||
|
|
045d0678b3 | ||
|
|
e3eeaddb3e | ||
|
|
f2b202c714 | ||
|
|
e6f3ad60ef | ||
|
|
fb6e0c9eb8 | ||
|
|
fb6e488339 | ||
|
|
0bccc8f0d5 | ||
|
|
560d831e92 | ||
|
|
7c8f6a1cc7 | ||
|
|
deb1ead4ea | ||
|
|
005b2a4fb6 | ||
|
|
4c8204f29a | ||
|
|
83fd19784a | ||
|
|
1f21a2ecc7 | ||
|
|
c3f4d56d1e | ||
|
|
7e4f79bacb | ||
|
|
b8267d4329 | ||
|
|
205ca693b3 | ||
|
|
23159c2201 | ||
|
|
884521ced0 |
@@ -6,8 +6,8 @@ Code contributions are welcome! Please commit any pull requests against the `mas
|
||||
|
||||
We use a translation tool called [Crowdin](https://crowdin.com) to help manage our localization efforts across many different languages.
|
||||
|
||||
If you are interested in helping translate the bitwarden mobile app into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-mobile
|
||||
If you are interested in helping translate the Bitwarden mobile app into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-mobile
|
||||
|
||||
If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/mail/compose/kspearrin).
|
||||
If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/kspearrin).
|
||||
|
||||
You can read Crowdin's getting started guide for translators here: https://support.crowdin.com/crowdin-intro/
|
||||
|
||||
5
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,5 @@
|
||||
<!--
|
||||
Please do not submit feature requests. The [Community Forums][1] has a
|
||||
section for submitting, voting for, and discussing product feature requests.
|
||||
[1]: https://community.bitwarden.com
|
||||
-->
|
||||
10
README.md
@@ -2,13 +2,13 @@
|
||||
[](https://crowdin.com/project/bitwarden-mobile)
|
||||
[](https://gitter.im/bitwarden/Lobby)
|
||||
|
||||
# bitwarden mobile
|
||||
# Bitwarden Mobile Application
|
||||
|
||||
<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>
|
||||
|
||||
The bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, UWP, and Xamarin Forms.
|
||||
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, UWP, and Xamarin Forms.
|
||||
|
||||
<img src="https://i.imgur.com/R7H2tkQ.png" alt="" width="300" height="533" /> <img src="https://i.imgur.com/3BO1Wcg.png" alt="" width="300" height="533" />
|
||||
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android.png" alt="" width="300" height="533" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios.png" alt="" width="300" height="533" />
|
||||
|
||||
# Build/Run
|
||||
|
||||
@@ -16,10 +16,14 @@ The bitwarden mobile application is written in C# with Xamarin Android, Xamarin
|
||||
|
||||
- [Visual Studio](https://store.xamarin.com/)
|
||||
|
||||
**API endpoint**
|
||||
|
||||
By default the app is targeting the production API. If you are running the [Core](https://github.com/bitwarden/core) API locally,
|
||||
you'll need to switch the app to target your local instance. Open `src/App/Utilities/ApiHttpClient.cs` and `src/App/Utilities/IdentityHttpClient.cs` and set the `BaseAddress` to your local
|
||||
API endpoints (ex. `new Uri("http://localhost:5000")`). Alternatively, you can also adjust the environment endpoints from the environment settings page on the home screen of the app (log out).
|
||||
|
||||
**Run the app**
|
||||
|
||||
After restoring the nuget packages, you can now build and run the app.
|
||||
|
||||
# Contribute
|
||||
|
||||
16
SECURITY.md
@@ -1,4 +1,4 @@
|
||||
bitwarden believes that working with security researchers across the globe is crucial to keeping our
|
||||
Bitwarden believes that working with security researchers across the globe is crucial to keeping our
|
||||
users safe. If you believe you've found a security issue in our product or service, we encourage you to
|
||||
notify us. We welcome working with you to resolve the issue promptly. Thanks in advance!
|
||||
|
||||
@@ -16,7 +16,7 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
|
||||
|
||||
# In-scope
|
||||
|
||||
- Security issues in any current release of bitwarden. This includes the web vault, browser extension,
|
||||
- Security issues in any current release of Bitwarden. This includes the web vault, browser extension,
|
||||
and mobile apps (iOS and Android). Product downloads are available at https://bitwarden.com. Source
|
||||
code is available at https://github.com/bitwarden.
|
||||
|
||||
@@ -24,14 +24,14 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
|
||||
|
||||
The following bug classes are out-of scope:
|
||||
|
||||
- Bugs that are already reported on any of bitwarden's issue trackers (https://github.com/bitwarden),
|
||||
- Bugs that are already reported on any of Bitwarden's issue trackers (https://github.com/bitwarden),
|
||||
or that we already know of. Note that some of our issue tracking is private.
|
||||
- Issues in an upstream software dependency (ex: Xamarin, ASP.NET) which are already reported to the
|
||||
upstream maintainer.
|
||||
- Attacks requiring physical access to a user's device.
|
||||
- Self-XSS
|
||||
- Issues related to software or protocols not under bitwarden's control
|
||||
- Vulnerabilities in outdated versions of bitwarden
|
||||
- Issues related to software or protocols not under Bitwarden's control
|
||||
- Vulnerabilities in outdated versions of Bitwarden
|
||||
- Missing security best practices that do not directly lead to a vulnerability
|
||||
- Issues that do not have any impact on the general public
|
||||
|
||||
@@ -39,7 +39,7 @@ While researching, we'd like to ask you to refrain from:
|
||||
|
||||
- Denial of service
|
||||
- Spamming
|
||||
- Social engineering (including phishing) of bitwarden staff or contractors
|
||||
- Any physical attempts against bitwarden property or data centers
|
||||
- Social engineering (including phishing) of Bitwarden staff or contractors
|
||||
- Any physical attempts against Bitwarden property or data centers
|
||||
|
||||
Thank you for helping keep bitwarden and our users safe!
|
||||
Thank you for helping keep Bitwarden and our users safe!
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
install:
|
||||
- appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
|
||||
- appveyor DownloadFile https://aka.ms/vs/15/release/vs_community.exe
|
||||
- vs_community.exe update --wait --quiet --norestart --installPath "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community"
|
||||
- choco install cloc --no-progress
|
||||
- "cloc --vcs git --exclude-dir Resources,store,test,UWP,Properties --include-lang C#,JavaScript,TypeScript,PowerShell"
|
||||
# - appveyor DownloadFile https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
|
||||
# - appveyor DownloadFile https://aka.ms/vs/15/release/vs_community.exe
|
||||
# - vs_community.exe update --wait --quiet --norestart --installPath "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community"
|
||||
before_build:
|
||||
- nuget restore
|
||||
- IF DEFINED keystore_dec_secret nuget install secure-file -ExcludeVersion
|
||||
|
||||
@@ -21,10 +21,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UWP", "src\UWP\UWP.csproj", "{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}"
|
||||
EndProject
|
||||
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "UWP.Images", "src\UWP.Images\UWP.Images.shproj", "{0BE54BBB-7772-4289-BD51-1FDBB0CC2446}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{8A279EE4-4537-4656-9C93-44945E594556}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{D5D91152-CB01-4F24-A503-304D3A94408B}"
|
||||
@@ -39,10 +35,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
src\UWP.Images\UWP.Images.projitems*{0be54bbb-7772-4289-bd51-1fdbb0cc2446}*SharedItemsImports = 13
|
||||
src\UWP.Images\UWP.Images.projitems*{3a2d5669-ed71-4f2b-ba85-2d36baa05141}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
Ad-Hoc|ARM = Ad-Hoc|ARM
|
||||
@@ -344,84 +336,6 @@ Global
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|Any CPU.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.ActiveCfg = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.Build.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|ARM.Deploy.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhone.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x64.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.Build.0 = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Ad-Hoc|x86.Deploy.0 = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|Any CPU.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.ActiveCfg = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.Build.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|ARM.Deploy.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhone.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|iPhoneSimulator.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x64.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.Build.0 = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.AppStore|x86.Deploy.0 = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|iPhone.ActiveCfg = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|iPhoneSimulator.ActiveCfg = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.Build.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.Build.0 = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|Any CPU.ActiveCfg = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|Any CPU.Build.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|Any CPU.Deploy.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|ARM.ActiveCfg = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|ARM.Build.0 = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|ARM.Deploy.0 = Debug|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhone.ActiveCfg = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhone.Build.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhone.Deploy.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhoneSimulator.ActiveCfg = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhoneSimulator.Build.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|iPhoneSimulator.Deploy.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x64.ActiveCfg = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x64.Build.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x64.Deploy.0 = Debug|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x86.ActiveCfg = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x86.Build.0 = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.FDroid|x86.Deploy.0 = Debug|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.Build.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|iPhone.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|iPhoneSimulator.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.ActiveCfg = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.Build.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x64.Deploy.0 = Release|x64
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.ActiveCfg = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.Build.0 = Release|x86
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141}.Release|x86.Deploy.0 = Release|x86
|
||||
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A279EE4-4537-4656-9C93-44945E594556}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
@@ -553,8 +467,6 @@ Global
|
||||
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{B2538ADA-B605-4D6F-ACD2-62A409680F84} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
|
||||
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{0BE54BBB-7772-4289-BD51-1FDBB0CC2446} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{8A279EE4-4537-4656-9C93-44945E594556} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||
{D5D91152-CB01-4F24-A503-304D3A94408B} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
|
||||
EndGlobalSection
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
files:
|
||||
- source: /src/App/Resources/AppResources.resx
|
||||
translation: /src/App/Resources/AppResources.%two_letters_code%.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
@@ -9,6 +10,7 @@ files:
|
||||
pt-BR: pt-BR
|
||||
- source: /store/apple/en/copy.resx
|
||||
translation: /store/apple/%two_letters_code%/copy.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
@@ -17,6 +19,7 @@ files:
|
||||
pt-BR: pt-BR
|
||||
- source: /store/google/en/copy.resx
|
||||
translation: /store/google/%two_letters_code%/copy.resx
|
||||
update_option: update_as_unapproved
|
||||
languages_mapping:
|
||||
two_letters_code:
|
||||
zh-CN: zh-Hans
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
|
||||
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<AndroidStoreUncompressedFileExtensions />
|
||||
@@ -472,21 +472,6 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\list_selector.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\notification_sm.png" />
|
||||
</ItemGroup>
|
||||
@@ -873,20 +858,35 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
||||
<Version>42.1021.1</Version>
|
||||
<Version>60.1142.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.Analytics">
|
||||
<Version>42.1021.1</Version>
|
||||
<Version>60.1142.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SimpleInjector">
|
||||
<Version>4.0.12</Version>
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.Design">
|
||||
<Version>27.0.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v4">
|
||||
<Version>27.0.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
|
||||
<Version>25.4.0.2</Version>
|
||||
<Version>27.0.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.CardView">
|
||||
<Version>27.0.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter">
|
||||
<Version>27.0.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||
<Version>60.1142.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="XLabs.IoC.SimpleInjector" Version="2.0.5782" />
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.3" />
|
||||
<PackageReference Include="Plugin.CurrentActivity" Version="1.0.1" />
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
|
||||
<PackageReference Include="Plugin.CurrentActivity" Version="2.1.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\bottom_nav_bg.xml" />
|
||||
@@ -906,5 +906,119 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\pencil.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\refresh_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\refresh_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\refresh_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\refresh_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\refresh_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\cog_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\cog_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\cog_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\cog_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\cog_alt.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\upload2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-hdpi\upload2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\upload2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\upload2.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxxhdpi\upload2.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -14,7 +14,7 @@ using XLabs.Ioc;
|
||||
|
||||
namespace Bit.Android.Autofill
|
||||
{
|
||||
[Service(Permission = Manifest.Permission.BindAutofillService, Label = "bitwarden")]
|
||||
[Service(Permission = Manifest.Permission.BindAutofillService, Label = "Bitwarden")]
|
||||
[IntentFilter(new string[] { "android.service.autofill.AutofillService" })]
|
||||
[MetaData("android.autofill", Resource = "@xml/autofillservice")]
|
||||
[Register("com.x8bit.bitwarden.Autofill.AutofillService")]
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Bit.Android.Autofill
|
||||
public Field(ViewNode node)
|
||||
{
|
||||
Id = node.Id;
|
||||
TrackingId = $"{node.Id}_{node.GetHashCode()}";
|
||||
IdEntry = node.IdEntry;
|
||||
AutofillId = node.AutofillId;
|
||||
AutofillType = node.AutofillType;
|
||||
@@ -68,6 +69,7 @@ namespace Bit.Android.Autofill
|
||||
}
|
||||
public string Hint { get; set; }
|
||||
public int Id { get; private set; }
|
||||
public string TrackingId { get; private set; }
|
||||
public string IdEntry { get; set; }
|
||||
public AutofillId AutofillId { get; private set; }
|
||||
public AutofillType AutofillType { get; private set; }
|
||||
|
||||
@@ -11,8 +11,9 @@ namespace Bit.Android.Autofill
|
||||
{
|
||||
private List<Field> _passwordFields = null;
|
||||
private List<Field> _usernameFields = null;
|
||||
private HashSet<string> _ignoreSearchTerms = new HashSet<string> { "search", "find", "recipient", "edit" };
|
||||
private HashSet<string> _passwordTerms = new HashSet<string> { "password", "pswd" };
|
||||
|
||||
public HashSet<int> Ids { get; private set; } = new HashSet<int>();
|
||||
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
|
||||
public SaveDataType SaveType
|
||||
{
|
||||
@@ -32,9 +33,8 @@ namespace Bit.Android.Autofill
|
||||
}
|
||||
public HashSet<string> Hints { get; private set; } = new HashSet<string>();
|
||||
public HashSet<string> FocusedHints { get; private set; } = new HashSet<string>();
|
||||
public HashSet<string> FieldTrackingIds { get; private set; } = new HashSet<string>();
|
||||
public List<Field> Fields { get; private set; } = new List<Field>();
|
||||
public IDictionary<int, Field> IdToFieldMap { get; private set; } =
|
||||
new Dictionary<int, Field>();
|
||||
public IDictionary<string, List<Field>> HintToFieldsMap { get; private set; } =
|
||||
new Dictionary<string, List<Field>>();
|
||||
public List<AutofillId> IgnoreAutofillIds { get; private set; } = new List<AutofillId>();
|
||||
@@ -58,21 +58,10 @@ namespace Bit.Android.Autofill
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordFields = Fields
|
||||
.Where(f =>
|
||||
(!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||
(!f.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
|
||||
(
|
||||
f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationWebPassword)
|
||||
)
|
||||
).ToList();
|
||||
_passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
|
||||
if(!_passwordFields.Any())
|
||||
{
|
||||
_passwordFields = Fields.Where(f =>
|
||||
(f.IdEntry?.ToLowerInvariant().Contains("password") ?? false)
|
||||
|| (f.Hint?.ToLowerInvariant().Contains("password") ?? false)).ToList();
|
||||
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +94,8 @@ namespace Bit.Android.Autofill
|
||||
{
|
||||
foreach(var passwordField in PasswordFields)
|
||||
{
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault();
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
|
||||
.LastOrDefault();
|
||||
if(usernameField != null)
|
||||
{
|
||||
_usernameFields.Add(usernameField);
|
||||
@@ -131,19 +121,14 @@ namespace Bit.Android.Autofill
|
||||
|
||||
public void Add(Field field)
|
||||
{
|
||||
if(Ids.Contains(field.Id))
|
||||
if(field == null || FieldTrackingIds.Contains(field.TrackingId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_passwordFields = _usernameFields = null;
|
||||
|
||||
if(field.Id > -1)
|
||||
{
|
||||
Ids.Add(field.Id);
|
||||
IdToFieldMap.Add(field.Id, field);
|
||||
}
|
||||
|
||||
FieldTrackingIds.Add(field.TrackingId);
|
||||
Fields.Add(field);
|
||||
AutofillIds.Add(field.AutofillId);
|
||||
|
||||
@@ -312,5 +297,45 @@ namespace Bit.Android.Autofill
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool FieldIsPassword(Field f)
|
||||
{
|
||||
var inputTypePassword = f.InputType.HasFlag(InputTypes.TextVariationPassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationVisiblePassword) ||
|
||||
f.InputType.HasFlag(InputTypes.TextVariationWebPassword);
|
||||
|
||||
if(!inputTypePassword && f.HtmlInfo != null && f.HtmlInfo.Tag == "input" &&
|
||||
(f.HtmlInfo.Attributes?.Any() ?? false))
|
||||
{
|
||||
foreach(var a in f.HtmlInfo.Attributes)
|
||||
{
|
||||
var key = a.First as Java.Lang.String;
|
||||
var val = a.Second as Java.Lang.String;
|
||||
if(key != null && val != null && key.ToString() == "type" && val.ToString() == "password")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputTypePassword && !ValueContainsAnyTerms(f.IdEntry, _ignoreSearchTerms) &&
|
||||
!ValueContainsAnyTerms(f.Hint, _ignoreSearchTerms);
|
||||
}
|
||||
|
||||
private bool FieldHasPasswordTerms(Field f)
|
||||
{
|
||||
return ValueContainsAnyTerms(f.IdEntry, _passwordTerms) || ValueContainsAnyTerms(f.Hint, _passwordTerms);
|
||||
}
|
||||
|
||||
private bool ValueContainsAnyTerms(string value, HashSet<string> terms)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var lowerValue = value.ToLowerInvariant();
|
||||
return terms.Any(t => lowerValue.Contains(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ namespace Bit.Android.Autofill
|
||||
"com.opera.browser.beta","com.opera.mini.native","com.chrome.dev","com.chrome.canary",
|
||||
"com.google.android.apps.chrome","com.google.android.apps.chrome_dev","com.yandex.browser",
|
||||
"com.sec.android.app.sbrowser","com.sec.android.app.sbrowser.beta","org.codeaurora.swe.browser",
|
||||
"com.amazon.cloud9","org.mozilla.klar", "com.duckduckgo.mobile.android"
|
||||
"com.amazon.cloud9","org.mozilla.klar","com.duckduckgo.mobile.android","mark.via.gp","org.bromite.bromite",
|
||||
"org.chromium.chrome", "com.kiwibrowser.browser", "com.ecosia.android"
|
||||
};
|
||||
|
||||
public static HashSet<string> ExcludedPackageIds = new HashSet<string>
|
||||
|
||||
@@ -3,15 +3,14 @@ using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using System;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
[Activity(Theme = "@style/BitwardenTheme.Splash",
|
||||
Label = "bitwarden",
|
||||
Icon = "@drawable/icon",
|
||||
WindowSoftInputMode = SoftInput.StateHidden)]
|
||||
[Activity(Theme = "@style/BitwardenTheme.Splash", WindowSoftInputMode = SoftInput.StateHidden)]
|
||||
public class AutofillActivity : Activity
|
||||
{
|
||||
private DateTime? _lastLaunch = null;
|
||||
private string _lastQueriedUri;
|
||||
|
||||
public static AutofillCredentials LastCredentials { get; set; }
|
||||
@@ -93,6 +92,13 @@ namespace Bit.Android
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
if(_lastLaunch.HasValue && (now - _lastLaunch.Value <= TimeSpan.FromSeconds(2)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastLaunch = now;
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
if(!callingIntent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ using Bit.App.Resources;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
[Service(Permission = global::Android.Manifest.Permission.BindAccessibilityService, Label = "bitwarden")]
|
||||
[Service(Permission = global::Android.Manifest.Permission.BindAccessibilityService, Label = "Bitwarden")]
|
||||
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
|
||||
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
|
||||
public class AutofillService : AccessibilityService
|
||||
@@ -23,12 +23,13 @@ namespace Bit.Android
|
||||
private const int AutoFillNotificationId = 34573;
|
||||
private const string SystemUiPackage = "com.android.systemui";
|
||||
private const string BitwardenPackage = "com.x8bit.bitwarden";
|
||||
private const string BitwardenWebsite = "bitwarden.com";
|
||||
private const string BitwardenWebsite = "vault.bitwarden.com";
|
||||
|
||||
private static Dictionary<string, Browser> SupportedBrowsers => new List<Browser>
|
||||
{
|
||||
new Browser("com.android.chrome", "url_bar"),
|
||||
new Browser("com.chrome.beta", "url_bar"),
|
||||
new Browser("org.chromium.chrome", "url_bar"),
|
||||
new Browser("com.android.browser", "url"),
|
||||
new Browser("com.brave.browser", "url_bar"),
|
||||
new Browser("com.opera.browser", "url_field"),
|
||||
@@ -62,7 +63,11 @@ namespace Bit.Android
|
||||
new Browser("acr.browser.lightning", "search"),
|
||||
new Browser("acr.browser.barebones", "search"),
|
||||
new Browser("com.microsoft.emmx", "url_bar"),
|
||||
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput")
|
||||
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
|
||||
new Browser("mark.via.gp", "aw"),
|
||||
new Browser("org.bromite.bromite", "url_bar"),
|
||||
new Browser("com.kiwibrowser.browser", "url_bar"),
|
||||
new Browser("com.ecosia.android", "url_bar"),
|
||||
}.ToDictionary(n => n.PackageName);
|
||||
|
||||
// Known packages to skip
|
||||
@@ -124,7 +129,6 @@ namespace Bit.Android
|
||||
|
||||
//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);
|
||||
var cancelNotification = true;
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Bit.Android.Controls
|
||||
|
||||
private void Control_EditorAction(object sender, TextView.EditorActionEventArgs e)
|
||||
{
|
||||
if(_view.ReturnType != ReturnType.Next)
|
||||
if(_view.TargetReturnType != Bit.App.Enums.ReturnType.Next)
|
||||
{
|
||||
_view.Unfocus();
|
||||
}
|
||||
@@ -165,23 +165,23 @@ namespace Bit.Android.Controls
|
||||
|
||||
private void SetReturnType(ExtendedEntry view)
|
||||
{
|
||||
if(view.ReturnType.HasValue)
|
||||
if(view.TargetReturnType.HasValue)
|
||||
{
|
||||
switch(view.ReturnType.Value)
|
||||
switch(view.TargetReturnType.Value)
|
||||
{
|
||||
case ReturnType.Go:
|
||||
case App.Enums.ReturnType.Go:
|
||||
Control.ImeOptions = ImeAction.Go;
|
||||
Control.SetImeActionLabel("Go", ImeAction.Go);
|
||||
break;
|
||||
case ReturnType.Next:
|
||||
case App.Enums.ReturnType.Next:
|
||||
Control.ImeOptions = ImeAction.Next;
|
||||
Control.SetImeActionLabel("Next", ImeAction.Next);
|
||||
break;
|
||||
case ReturnType.Search:
|
||||
case App.Enums.ReturnType.Search:
|
||||
Control.ImeOptions = ImeAction.Search;
|
||||
Control.SetImeActionLabel("Search", ImeAction.Search);
|
||||
break;
|
||||
case ReturnType.Send:
|
||||
case App.Enums.ReturnType.Send:
|
||||
Control.ImeOptions = ImeAction.Send;
|
||||
Control.SetImeActionLabel("Send", ImeAction.Send);
|
||||
break;
|
||||
@@ -206,7 +206,7 @@ namespace Bit.Android.Controls
|
||||
|
||||
private void SetMaxLength(ExtendedEntry view)
|
||||
{
|
||||
Control.SetFilters(new IInputFilter[] { new InputFilterLengthFilter(view.MaxLength) });
|
||||
Control.SetFilters(new IInputFilter[] { new InputFilterLengthFilter(view.TargetMaxLength) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,14 @@ using Bit.App.Enums;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
[Activity(Label = "bitwarden",
|
||||
Icon = "@drawable/icon",
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
|
||||
Exported = false)]
|
||||
[Activity(ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, Exported = false)]
|
||||
public class MainActivity : FormsAppCompatActivity
|
||||
{
|
||||
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
|
||||
private Java.Util.Regex.Pattern _otpPattern = Java.Util.Regex.Pattern.Compile("^.*?([cbdefghijklnrtuv]{32,64})$");
|
||||
private IDeviceActionService _deviceActionService;
|
||||
private IDeviceInfoService _deviceInfoService;
|
||||
private IAppSettingsService _appSettingsService;
|
||||
private ISettings _settings;
|
||||
private AppOptions _appOptions;
|
||||
|
||||
@@ -72,6 +71,8 @@ namespace Bit.Android
|
||||
.SetValue(null, Color.FromHex("d2d6de"));
|
||||
|
||||
_deviceActionService = Resolver.Resolve<IDeviceActionService>();
|
||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||
_appSettingsService = Resolver.Resolve<IAppSettingsService>();
|
||||
_settings = Resolver.Resolve<ISettings>();
|
||||
_appOptions = GetOptions();
|
||||
LoadApplication(new App.App(
|
||||
@@ -84,7 +85,7 @@ namespace Bit.Android
|
||||
Resolver.Resolve<ILockService>(),
|
||||
Resolver.Resolve<ILocalizeService>(),
|
||||
Resolver.Resolve<IAppInfoService>(),
|
||||
Resolver.Resolve<IAppSettingsService>(),
|
||||
_appSettingsService,
|
||||
_deviceActionService));
|
||||
|
||||
if(_appOptions?.Uri == null)
|
||||
@@ -137,7 +138,7 @@ namespace Bit.Android
|
||||
// ref https://bugzilla.xamarin.com/show_bug.cgi?id=36907
|
||||
Task.Delay(10).Wait();
|
||||
|
||||
if(Utilities.NfcEnabled())
|
||||
if(_deviceInfoService.NfcEnabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -148,6 +149,11 @@ namespace Bit.Android
|
||||
System.Diagnostics.Debug.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(_appSettingsService.Locked)
|
||||
{
|
||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "Resumed", false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
@@ -209,7 +215,7 @@ namespace Bit.Android
|
||||
|
||||
private void ListenYubiKey(bool listen)
|
||||
{
|
||||
if(!Utilities.NfcEnabled())
|
||||
if(!_deviceInfoService.NfcEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -227,8 +233,12 @@ namespace Bit.Android
|
||||
ndef.AddDataScheme("https");
|
||||
var filters = new IntentFilter[] { ndef };
|
||||
|
||||
// register for foreground dispatch so we'll receive tags according to our intent filters
|
||||
adapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
|
||||
try
|
||||
{
|
||||
// register for foreground dispatch so we'll receive tags according to our intent filters
|
||||
adapter.EnableForegroundDispatch(this, pendingIntent, filters, null);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -13,9 +13,9 @@ using Plugin.Fingerprint;
|
||||
using Plugin.Settings;
|
||||
using XLabs.Ioc;
|
||||
using System.Threading.Tasks;
|
||||
using FFImageLoading.Forms.Droid;
|
||||
using XLabs.Ioc.SimpleInjectorContainer;
|
||||
using SimpleInjector;
|
||||
using Android.Gms.Security;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
@@ -24,13 +24,11 @@ namespace Bit.Android
|
||||
#else
|
||||
[Application(Debuggable = false)]
|
||||
#endif
|
||||
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
|
||||
public class MainApplication : Application, ProviderInstaller.IProviderInstallListener
|
||||
{
|
||||
private const string FirstLaunchKey = "firstLaunch";
|
||||
private const string LastVersionCodeKey = "lastVersionCode";
|
||||
|
||||
public static Context AppContext;
|
||||
|
||||
public MainApplication(IntPtr handle, JniHandleOwnership transer)
|
||||
: base(handle, transer)
|
||||
{
|
||||
@@ -40,6 +38,11 @@ namespace Bit.Android
|
||||
{
|
||||
SetIoc(this);
|
||||
}
|
||||
|
||||
if(Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)
|
||||
{
|
||||
ProviderInstaller.InstallIfNeededAsync(ApplicationContext, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
|
||||
@@ -56,52 +59,13 @@ namespace Bit.Android
|
||||
// workaround for app compat bug
|
||||
// ref https://forums.xamarin.com/discussion/62414/app-resuming-results-in-crash-with-formsappcompatactivity
|
||||
Task.Delay(10).Wait();
|
||||
|
||||
RegisterActivityLifecycleCallbacks(this);
|
||||
AppContext = ApplicationContext;
|
||||
}
|
||||
|
||||
public override void OnTerminate()
|
||||
{
|
||||
base.OnTerminate();
|
||||
UnregisterActivityLifecycleCallbacks(this);
|
||||
}
|
||||
|
||||
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivityDestroyed(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityPaused(Activity activity)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityResumed(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActivityStarted(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Activity = activity;
|
||||
}
|
||||
|
||||
public void OnActivityStopped(Activity activity)
|
||||
{
|
||||
CrossCurrentActivity.Current.Init(this);
|
||||
}
|
||||
|
||||
public static void SetIoc(Application application)
|
||||
{
|
||||
Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init();
|
||||
CachedImageRenderer.Init(true);
|
||||
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
|
||||
ZXing.Net.Mobile.Forms.Android.Platform.Init();
|
||||
CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
|
||||
|
||||
@@ -109,8 +73,8 @@ namespace Bit.Android
|
||||
var container = new Container();
|
||||
|
||||
// Android Stuff
|
||||
container.RegisterSingleton(application.ApplicationContext);
|
||||
container.RegisterSingleton<Application>(application);
|
||||
container.RegisterInstance(application.ApplicationContext);
|
||||
container.RegisterInstance<Application>(application);
|
||||
|
||||
// Services
|
||||
container.RegisterSingleton<IDatabaseService, DatabaseService>();
|
||||
@@ -158,9 +122,9 @@ namespace Bit.Android
|
||||
container.RegisterSingleton<ICipherCollectionRepository, CipherCollectionRepository>();
|
||||
|
||||
// Other
|
||||
container.RegisterSingleton(CrossSettings.Current);
|
||||
container.RegisterSingleton(CrossConnectivity.Current);
|
||||
container.RegisterSingleton(CrossFingerprint.Current);
|
||||
container.RegisterInstance(CrossSettings.Current);
|
||||
container.RegisterInstance(CrossConnectivity.Current);
|
||||
container.RegisterInstance(CrossFingerprint.Current);
|
||||
|
||||
// Push
|
||||
#if FDROID
|
||||
@@ -174,5 +138,13 @@ namespace Bit.Android
|
||||
container.Verify();
|
||||
Resolver.SetResolver(new SimpleInjectorResolver(container));
|
||||
}
|
||||
|
||||
public void OnProviderInstallFailed(int errorCode, Intent recoveryIntent)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnProviderInstalled()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.14.4" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.18.0" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@@ -12,7 +12,8 @@
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
|
||||
<application android:label="bitwarden" android:theme="@style/BitwardenTheme" android:allowBackup="false">
|
||||
<application android:label="Bitwarden" android:theme="@style/BitwardenTheme" android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round">
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="com.x8bit.bitwarden.fileprovider"
|
||||
@@ -30,10 +31,11 @@
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
|
||||
<category android:name="${applicationId}" />
|
||||
<category android:name="com.x8bit.bitwarden" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="net.hockeyapp.android.UpdateActivity" android:exported="false" android:icon="@drawable/icon" />
|
||||
<activity android:name="net.hockeyapp.android.UpdateActivity" android:exported="false" />
|
||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -10,7 +10,7 @@ using Android.App;
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("8bit Solutions LLC")]
|
||||
[assembly: AssemblyProduct("bitwarden")]
|
||||
[assembly: AssemblyProduct("Bitwarden")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
8373
src/Android/Resources/Resource.Designer.cs
generated
BIN
src/Android/Resources/drawable-hdpi/cog_alt.png
Normal file
|
After Width: | Height: | Size: 738 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
src/Android/Resources/drawable-hdpi/refresh_alt.png
Normal file
|
After Width: | Height: | Size: 804 B |
BIN
src/Android/Resources/drawable-hdpi/upload2.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/Android/Resources/drawable-xhdpi/cog_alt.png
Normal file
|
After Width: | Height: | Size: 1005 B |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
src/Android/Resources/drawable-xhdpi/refresh_alt.png
Normal file
|
After Width: | Height: | Size: 1017 B |
BIN
src/Android/Resources/drawable-xhdpi/upload2.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/Android/Resources/drawable-xxhdpi/cog_alt.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
src/Android/Resources/drawable-xxhdpi/refresh_alt.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/Android/Resources/drawable-xxhdpi/upload2.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/Android/Resources/drawable-xxxhdpi/cog_alt.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.6 KiB |
BIN
src/Android/Resources/drawable-xxxhdpi/refresh_alt.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/Android/Resources/drawable-xxxhdpi/upload2.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/Android/Resources/drawable/cog_alt.png
Normal file
|
After Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 941 B |
BIN
src/Android/Resources/drawable/refresh_alt.png
Normal file
|
After Width: | Height: | Size: 583 B |
BIN
src/Android/Resources/drawable/upload2.png
Normal file
|
After Width: | Height: | Size: 689 B |
5
src/Android/Resources/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
src/Android/Resources/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/Android/Resources/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 941 B |
BIN
src/Android/Resources/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/Android/Resources/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 896 B |
BIN
src/Android/Resources/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 608 B |
BIN
src/Android/Resources/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/Android/Resources/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/Android/Resources/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/Android/Resources/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/Android/Resources/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/Android/Resources/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/Android/Resources/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
src/Android/Resources/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
src/Android/Resources/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/Android/Resources/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
4
src/Android/Resources/values/ic_launcher_background.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#3C8DBC</color>
|
||||
</resources>
|
||||
@@ -5,9 +5,9 @@
|
||||
</string>
|
||||
<string name="AutoFillServiceDescription">
|
||||
It can be difficult and insecure for users to switch between apps to copy/paste username and password information
|
||||
from their bitwarden vault.\n\nUsing this accessibility service allows bitwarden to detect and read input fields on
|
||||
your device\'s screen. Whenever bitwarden detects a password field on the screen a notification will appear that allows
|
||||
you to quickly access your bitwarden vault and automatically fill (auto-fill) the correct login information into the
|
||||
from their Bitwarden vault.\n\nUsing this accessibility service allows Bitwarden to detect and read input fields on
|
||||
your device\'s screen. Whenever Bitwarden detects a password field on the screen a notification will appear that allows
|
||||
you to quickly access your Bitwarden vault and automatically fill (auto-fill) the correct login information into the
|
||||
necessary fields.
|
||||
</string>
|
||||
<string name="MyVault">
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
<item name="android:windowBackground">@color/lightgray</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="android:navigationBarColor">@color/darkaccent</item>
|
||||
<item name="android:actionModeBackground">@color/darkaccent</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -44,7 +44,15 @@ namespace Bit.Android.Services
|
||||
_keyStore = KeyStore.GetInstance(AndroidKeyStore);
|
||||
_keyStore.Load(null);
|
||||
|
||||
GenerateStoreKey();
|
||||
try
|
||||
{
|
||||
GenerateStoreKey(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
GenerateStoreKey(false);
|
||||
}
|
||||
|
||||
GenerateAesKey();
|
||||
}
|
||||
|
||||
@@ -128,7 +136,7 @@ namespace Bit.Android.Services
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateStoreKey()
|
||||
private void GenerateStoreKey(bool withDate)
|
||||
{
|
||||
if(_keyStore.ContainsAlias(KeyAlias))
|
||||
{
|
||||
@@ -144,27 +152,33 @@ namespace Bit.Android.Services
|
||||
{
|
||||
var subject = new X500Principal($"CN={KeyAlias}");
|
||||
|
||||
var spec = new KeyPairGeneratorSpec.Builder(Application.Context)
|
||||
var builder = new KeyPairGeneratorSpec.Builder(Application.Context)
|
||||
.SetAlias(KeyAlias)
|
||||
.SetSubject(subject)
|
||||
.SetSerialNumber(BigInteger.Ten)
|
||||
.SetStartDate(new Date(0))
|
||||
.SetEndDate(end.Time)
|
||||
.Build();
|
||||
.SetSerialNumber(BigInteger.Ten);
|
||||
|
||||
if(withDate)
|
||||
{
|
||||
builder.SetStartDate(new Date(0)).SetEndDate(end.Time);
|
||||
}
|
||||
|
||||
var spec = builder.Build();
|
||||
var gen = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, AndroidKeyStore);
|
||||
gen.Initialize(spec);
|
||||
gen.GenerateKeyPair();
|
||||
}
|
||||
else
|
||||
{
|
||||
var spec = new KeyGenParameterSpec.Builder(KeyAlias, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
|
||||
var builder = new KeyGenParameterSpec.Builder(KeyAlias, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt)
|
||||
.SetBlockModes(KeyProperties.BlockModeGcm)
|
||||
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone)
|
||||
.SetKeyValidityStart(new Date(0))
|
||||
.SetKeyValidityEnd(end.Time)
|
||||
.Build();
|
||||
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone);
|
||||
|
||||
if(withDate)
|
||||
{
|
||||
builder.SetKeyValidityStart(new Date(0)).SetKeyValidityEnd(end.Time);
|
||||
}
|
||||
|
||||
var spec = builder.Build();
|
||||
var gen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, AndroidKeyStore);
|
||||
gen.Init(spec);
|
||||
gen.GenerateKey();
|
||||
|
||||
@@ -24,6 +24,7 @@ using Bit.Android.Autofill;
|
||||
using System.Linq;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Android.Views.InputMethods;
|
||||
using Android.Widget;
|
||||
|
||||
namespace Bit.Android.Services
|
||||
{
|
||||
@@ -424,36 +425,167 @@ namespace Bit.Android.Services
|
||||
|
||||
public void OpenAutofillSettings()
|
||||
{
|
||||
var activity = (MainActivity)CurrentContext;
|
||||
var intent = new Intent(Settings.ActionRequestSetAutofillService);
|
||||
intent.SetData(global::Android.Net.Uri.Parse("package:com.x8bit.bitwarden"));
|
||||
activity.StartActivity(intent);
|
||||
try
|
||||
{
|
||||
var activity = (MainActivity)CurrentContext;
|
||||
var intent = new Intent(Settings.ActionRequestSetAutofillService);
|
||||
intent.SetData(global::Android.Net.Uri.Parse("package:com.x8bit.bitwarden"));
|
||||
activity.StartActivity(intent);
|
||||
}
|
||||
catch(ActivityNotFoundException)
|
||||
{
|
||||
var alertBuilder = new AlertDialog.Builder((MainActivity)CurrentContext);
|
||||
alertBuilder.SetMessage(AppResources.BitwardenAutofillGoToSettings);
|
||||
alertBuilder.SetCancelable(true);
|
||||
alertBuilder.SetPositiveButton(AppResources.Ok, (sender, args) =>
|
||||
{
|
||||
(sender as AlertDialog)?.Cancel();
|
||||
});
|
||||
alertBuilder.Create().Show();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowLoading(string text)
|
||||
public async Task ShowLoadingAsync(string text)
|
||||
{
|
||||
if(_progressDialog != null)
|
||||
{
|
||||
HideLoading();
|
||||
await HideLoadingAsync();
|
||||
}
|
||||
|
||||
var activity = (MainActivity)CurrentContext;
|
||||
_progressDialog = new ProgressDialog(activity);
|
||||
_progressDialog.SetMessage(text);
|
||||
_progressDialog.SetCancelable(true);
|
||||
_progressDialog.SetCancelable(false);
|
||||
_progressDialog.Show();
|
||||
}
|
||||
|
||||
public void HideLoading()
|
||||
public Task HideLoadingAsync()
|
||||
{
|
||||
if(_progressDialog == null)
|
||||
if(_progressDialog != null)
|
||||
{
|
||||
return;
|
||||
_progressDialog.Dismiss();
|
||||
_progressDialog.Dispose();
|
||||
_progressDialog = null;
|
||||
}
|
||||
|
||||
_progressDialog.Dismiss();
|
||||
_progressDialog.Dispose();
|
||||
_progressDialog = null;
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task<string> DisplayPromptAync(string title = null, string description = null, string text = null)
|
||||
{
|
||||
var activity = (MainActivity)CurrentContext;
|
||||
if(activity == null)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
var alertBuilder = new AlertDialog.Builder(activity);
|
||||
alertBuilder.SetTitle(title);
|
||||
alertBuilder.SetMessage(description);
|
||||
|
||||
var input = new EditText(activity)
|
||||
{
|
||||
InputType = global::Android.Text.InputTypes.ClassText
|
||||
};
|
||||
|
||||
if(text == null)
|
||||
{
|
||||
text = string.Empty;
|
||||
}
|
||||
|
||||
input.Text = text;
|
||||
input.SetSelection(text.Length);
|
||||
|
||||
alertBuilder.SetView(input);
|
||||
|
||||
var result = new TaskCompletionSource<string>();
|
||||
alertBuilder.SetPositiveButton(AppResources.Ok, (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(input.Text ?? string.Empty);
|
||||
});
|
||||
|
||||
alertBuilder.SetNegativeButton(AppResources.Cancel, (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(null);
|
||||
});
|
||||
|
||||
var alert = alertBuilder.Create();
|
||||
alert.Window.SetSoftInputMode(global::Android.Views.SoftInput.StateVisible);
|
||||
alert.Show();
|
||||
return result.Task;
|
||||
}
|
||||
|
||||
public Task<string> DisplayAlertAsync(string title, string message, string cancel, params string[] buttons)
|
||||
{
|
||||
var activity = (MainActivity)CurrentContext;
|
||||
if(activity == null)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
var result = new TaskCompletionSource<string>();
|
||||
var alertBuilder = new AlertDialog.Builder(activity);
|
||||
alertBuilder.SetTitle(title);
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
if(buttons != null && buttons.Length > 2)
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(title))
|
||||
{
|
||||
alertBuilder.SetTitle($"{title}: {message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
alertBuilder.SetTitle(message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
alertBuilder.SetMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
if(buttons != null)
|
||||
{
|
||||
if(buttons.Length > 2)
|
||||
{
|
||||
alertBuilder.SetItems(buttons, (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(buttons[args.Which]);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if(buttons.Length > 0)
|
||||
{
|
||||
alertBuilder.SetPositiveButton(buttons[0], (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(buttons[0]);
|
||||
});
|
||||
}
|
||||
if(buttons.Length > 1)
|
||||
{
|
||||
alertBuilder.SetNeutralButton(buttons[1], (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(buttons[1]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(cancel))
|
||||
{
|
||||
alertBuilder.SetNegativeButton(cancel, (sender, args) =>
|
||||
{
|
||||
result.TrySetResult(cancel);
|
||||
});
|
||||
}
|
||||
|
||||
var alert = alertBuilder.Create();
|
||||
alert.CancelEvent += (o, args) => { result.TrySetResult(null); };
|
||||
alert.Show();
|
||||
return result.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Nfc;
|
||||
using Android.OS;
|
||||
using Android.Views.Autofill;
|
||||
using Bit.App.Abstractions;
|
||||
@@ -45,7 +47,7 @@ namespace Bit.Android.Services
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
public bool NfcEnabled => Utilities.NfcEnabled();
|
||||
public bool NfcEnabled => NfcIsEnabled();
|
||||
public bool HasCamera => CrossCurrentActivity.Current.Activity.PackageManager.HasSystemFeature(
|
||||
PackageManager.FeatureCamera);
|
||||
public bool AutofillServiceSupported => AutofillSupported();
|
||||
@@ -56,10 +58,17 @@ namespace Bit.Android.Services
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var afm = (AutofillManager)CrossCurrentActivity.Current.Activity.GetSystemService(
|
||||
Java.Lang.Class.FromType(typeof(AutofillManager)));
|
||||
return afm.IsAutofillSupported;
|
||||
}
|
||||
public bool NfcIsEnabled()
|
||||
{
|
||||
var activity = CrossCurrentActivity.Current.Activity;
|
||||
var manager = (NfcManager)activity.GetSystemService(Context.NfcService);
|
||||
var adapter = manager.DefaultAdapter;
|
||||
return adapter != null && adapter.IsEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,12 @@ using Android.App;
|
||||
using Android.Content;
|
||||
using Java.Security;
|
||||
using System.IO;
|
||||
using Android.Nfc;
|
||||
using Android.Provider;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
public static class Utilities
|
||||
{
|
||||
public static bool NfcEnabled()
|
||||
{
|
||||
var manager = (NfcManager)Application.Context.GetSystemService("nfc");
|
||||
var adapter = manager.DefaultAdapter;
|
||||
return adapter != null && adapter.IsEnabled;
|
||||
}
|
||||
|
||||
public static void SendCrashEmail(Exception e, bool includeSecurityProviders = true)
|
||||
{
|
||||
SendCrashEmail(e.Message + "\n\n" + e.StackTrace, includeSecurityProviders);
|
||||
@@ -38,7 +30,7 @@ namespace Bit.Android
|
||||
|
||||
emailIntent.SetType("plain/text");
|
||||
emailIntent.PutExtra(Intent.ExtraEmail, new String[] { "hello@bitwarden.com" });
|
||||
emailIntent.PutExtra(Intent.ExtraSubject, "bitwarden Crash Report");
|
||||
emailIntent.PutExtra(Intent.ExtraSubject, "Bitwarden Crash Report");
|
||||
emailIntent.PutExtra(Intent.ExtraText, FormatText(text, includeSecurityProviders));
|
||||
|
||||
Application.Context.StartActivity(Intent.CreateChooser(emailIntent, "Send mail..."));
|
||||
@@ -50,7 +42,7 @@ namespace Bit.Android
|
||||
|
||||
emailIntent.SetType("plain/text");
|
||||
emailIntent.PutExtra(Intent.ExtraEmail, new String[] { "hello@bitwarden.com" });
|
||||
emailIntent.PutExtra(Intent.ExtraSubject, "bitwarden Crash Report");
|
||||
emailIntent.PutExtra(Intent.ExtraSubject, "Bitwarden Crash Report");
|
||||
emailIntent.PutExtra(Intent.ExtraText, FormatText(text, includeSecurityProviders));
|
||||
|
||||
act.StartActivity(Intent.CreateChooser(emailIntent, "Send mail..."));
|
||||
@@ -68,7 +60,7 @@ namespace Bit.Android
|
||||
|
||||
private static string FormatText(string text, bool includeSecurityProviders = true)
|
||||
{
|
||||
var crashMessage = "bitwarden has crashed. Please send this email to our support team so that we can help " +
|
||||
var crashMessage = "Bitwarden has crashed. Please send this email to our support team so that we can help " +
|
||||
"resolve the problem for you. Thank you.";
|
||||
|
||||
text = crashMessage + "\n\n =============================================== \n\n" + text;
|
||||
|
||||
@@ -17,5 +17,6 @@ namespace Bit.App.Abstractions
|
||||
string ApiUrl { get; set; }
|
||||
string IdentityUrl { get; set; }
|
||||
string IconsUrl { get; set; }
|
||||
bool ClearCiphersCache { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ namespace Bit.App.Abstractions
|
||||
{
|
||||
public interface IDeviceActionService
|
||||
{
|
||||
void ShowLoading(string text);
|
||||
void HideLoading();
|
||||
Task ShowLoadingAsync(string text);
|
||||
Task HideLoadingAsync();
|
||||
void Toast(string text, bool longDuration = false);
|
||||
void CopyToClipboard(string text);
|
||||
bool OpenFile(byte[] fileData, string id, string fileName);
|
||||
@@ -22,5 +22,7 @@ namespace Bit.App.Abstractions
|
||||
void OpenAccessibilitySettings();
|
||||
void OpenAutofillSettings();
|
||||
Task LaunchAppAsync(string appName, Page page);
|
||||
Task<string> DisplayPromptAync(string title = null, string description = null, string text = null);
|
||||
Task<string> DisplayAlertAsync(string title, string message, string cancel, params string[] buttons);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace Bit.App.Abstractions
|
||||
public interface ILockService
|
||||
{
|
||||
void UpdateLastActivity();
|
||||
Task<LockType> GetLockTypeAsync(bool forceLock);
|
||||
Task CheckLockAsync(bool forceLock);
|
||||
Task<LockType> GetLockTypeAsync(bool forceLock, bool onlyIfAlreadyLocked = false);
|
||||
Task CheckLockAsync(bool forceLock, bool onlyIfAlreadyLocked = false);
|
||||
bool TopPageIsLock();
|
||||
}
|
||||
}
|
||||
@@ -78,14 +78,14 @@ namespace Bit.App
|
||||
MainPage = new ExtendedNavigationPage(new HomePage());
|
||||
}
|
||||
|
||||
if(Device.RuntimePlatform == Device.iOS)
|
||||
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, forceLock) =>
|
||||
{
|
||||
MessagingCenter.Subscribe<Application, bool>(Current, "Resumed", async (sender, forceLock) =>
|
||||
Device.BeginInvokeOnMainThread(async () => await _lockService.CheckLockAsync(forceLock));
|
||||
if(Device.RuntimePlatform == Device.iOS)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(async () => await _lockService.CheckLockAsync(forceLock));
|
||||
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected async override void OnStart()
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HockeySDK.Xamarin" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="HockeySDK.Xamarin" Version="5.1.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="PCLCrypto" Version="2.0.147" />
|
||||
<PackageReference Include="Plugin.Fingerprint" Version="1.4.6-beta4" />
|
||||
<PackageReference Include="Plugin.Fingerprint" Version="1.4.7" />
|
||||
<PackageReference Include="Refractored.FloatingActionButtonForms" Version="2.1.0" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.5.166-beta" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.3" />
|
||||
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.0.3" />
|
||||
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
|
||||
<PackageReference Include="Xam.Plugins.Settings" Version="3.1.1" />
|
||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.3.4" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="2.5.0.122203" />
|
||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.3.840" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="3.1.0.697729" />
|
||||
<PackageReference Include="XLabs.IoC" Version="2.0.5782" />
|
||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.1.47" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
public const string IdentityUrl = "other:identityUrl";
|
||||
public const string IconsUrl = "other:iconsUrl";
|
||||
public const string FailedPinAttempts = "other:failedPinAttempts";
|
||||
public const string ClearCiphersCache = "other:clearCiphersCache";
|
||||
|
||||
public const int SelectFileRequestCode = 42;
|
||||
public const int SelectFilePermissionRequestCode = 43;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Bit.App.Controls
|
||||
BackgroundColor = Color.FromHex("efeff4");
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
protected async override void OnAppearing()
|
||||
{
|
||||
if(_requireAuth && !_authService.IsAuthenticated)
|
||||
{
|
||||
@@ -52,6 +52,7 @@ namespace Bit.App.Controls
|
||||
}
|
||||
|
||||
_googleAnalyticsService.TrackPage(GetType().Name);
|
||||
await _lockService.CheckLockAsync(false, true);
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Bit.App.Controls
|
||||
public static readonly BindableProperty BottomBorderColorProperty =
|
||||
BindableProperty.Create(nameof(BottomBorderColor), typeof(Color), typeof(ExtendedEntry), Color.Default);
|
||||
|
||||
public static readonly BindableProperty MaxLengthProperty =
|
||||
BindableProperty.Create(nameof(MaxLength), typeof(int), typeof(ExtendedEntry), int.MaxValue);
|
||||
public static readonly BindableProperty TargetMaxLengthProperty =
|
||||
BindableProperty.Create(nameof(TargetMaxLength), typeof(int), typeof(ExtendedEntry), int.MaxValue);
|
||||
|
||||
public bool HasBorder
|
||||
{
|
||||
@@ -46,13 +46,13 @@ namespace Bit.App.Controls
|
||||
set { SetValue(BottomBorderColorProperty, value); }
|
||||
}
|
||||
|
||||
public int MaxLength
|
||||
public int TargetMaxLength
|
||||
{
|
||||
get { return (int)GetValue(MaxLengthProperty); }
|
||||
set { SetValue(MaxLengthProperty, value); }
|
||||
get { return (int)GetValue(TargetMaxLengthProperty); }
|
||||
set { SetValue(TargetMaxLengthProperty, value); }
|
||||
}
|
||||
|
||||
public ReturnType? ReturnType { get; set; }
|
||||
public Enums.ReturnType? TargetReturnType { get; set; }
|
||||
public bool? Autocorrect { get; set; }
|
||||
public bool DisableAutocapitalize { get; set; }
|
||||
public bool AllowClear { get; set; }
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Bit.App.Controls
|
||||
public class ExtendedViewCell : ViewCell
|
||||
{
|
||||
public static readonly BindableProperty BackgroundColorProperty =
|
||||
BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(ExtendedTextCell), Color.White);
|
||||
BindableProperty.Create(nameof(BackgroundColor), typeof(Color), typeof(ExtendedViewCell), Color.White);
|
||||
|
||||
public static readonly BindableProperty ShowDisclousureProperty =
|
||||
BindableProperty.Create(nameof(ShowDisclousure), typeof(bool), typeof(ExtendedTextCell), false);
|
||||
BindableProperty.Create(nameof(ShowDisclousure), typeof(bool), typeof(ExtendedViewCell), false);
|
||||
|
||||
public Color BackgroundColor
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Bit.App.Abstractions;
|
||||
using FFImageLoading.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xamarin.Forms;
|
||||
using XLabs.Ioc;
|
||||
|
||||
@@ -10,6 +11,7 @@ namespace Bit.App.Controls
|
||||
{
|
||||
private VisualElement _nextElement;
|
||||
private TapGestureRecognizer _tgr;
|
||||
private StackLayout _buttonStackLayout = null;
|
||||
|
||||
public FormEntryCell(
|
||||
string labelText,
|
||||
@@ -19,7 +21,8 @@ namespace Bit.App.Controls
|
||||
bool useLabelAsPlaceholder = false,
|
||||
string imageSource = null,
|
||||
Thickness? containerPadding = null,
|
||||
bool useButton = false)
|
||||
string button1 = null,
|
||||
string button2 = null)
|
||||
{
|
||||
if(!useLabelAsPlaceholder)
|
||||
{
|
||||
@@ -82,6 +85,45 @@ namespace Bit.App.Controls
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand
|
||||
};
|
||||
|
||||
if(!useLabelAsPlaceholder)
|
||||
{
|
||||
formStackLayout.Children.Add(Label);
|
||||
}
|
||||
|
||||
formStackLayout.Children.Add(Entry);
|
||||
imageStackLayout.Children.Add(formStackLayout);
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(button1) || !string.IsNullOrWhiteSpace(button2))
|
||||
{
|
||||
_buttonStackLayout = new StackLayout
|
||||
{
|
||||
Orientation = StackOrientation.Horizontal,
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
Spacing = 5
|
||||
};
|
||||
imageStackLayout.Children.Add(_buttonStackLayout);
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(button1))
|
||||
{
|
||||
Button1 = new ExtendedButton { Image = button1 };
|
||||
_buttonStackLayout.Children.Add(Button1);
|
||||
Button1.Padding = new Thickness(0);
|
||||
Button1.BackgroundColor = Color.Transparent;
|
||||
Button1.WidthRequest = 40;
|
||||
Button1.VerticalOptions = LayoutOptions.FillAndExpand;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(button2))
|
||||
{
|
||||
Button2 = new ExtendedButton { Image = button2 };
|
||||
_buttonStackLayout.Children.Add(Button2);
|
||||
Button2.Padding = new Thickness(0);
|
||||
Button2.BackgroundColor = Color.Transparent;
|
||||
Button2.WidthRequest = 40;
|
||||
Button2.VerticalOptions = LayoutOptions.FillAndExpand;
|
||||
}
|
||||
}
|
||||
|
||||
if(Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
var deviceInfo = Resolver.Resolve<IDeviceInfoService>();
|
||||
@@ -106,25 +148,11 @@ namespace Bit.App.Controls
|
||||
imageStackLayout.AdjustPaddingForDevice();
|
||||
}
|
||||
}
|
||||
|
||||
if(!useLabelAsPlaceholder)
|
||||
else if(Device.RuntimePlatform == Device.UWP)
|
||||
{
|
||||
formStackLayout.Children.Add(Label);
|
||||
}
|
||||
|
||||
formStackLayout.Children.Add(Entry);
|
||||
imageStackLayout.Children.Add(formStackLayout);
|
||||
|
||||
if(useButton)
|
||||
{
|
||||
Button = new ExtendedButton();
|
||||
imageStackLayout.Children.Add(Button);
|
||||
|
||||
if(Device.RuntimePlatform == Device.Android)
|
||||
if(_buttonStackLayout != null)
|
||||
{
|
||||
Button.Padding = new Thickness(0);
|
||||
Button.BackgroundColor = Color.Transparent;
|
||||
Button.WidthRequest = 40;
|
||||
_buttonStackLayout.Spacing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +161,8 @@ namespace Bit.App.Controls
|
||||
|
||||
public Label Label { get; private set; }
|
||||
public ExtendedEntry Entry { get; private set; }
|
||||
public ExtendedButton Button { get; private set; }
|
||||
public ExtendedButton Button1 { get; private set; }
|
||||
public ExtendedButton Button2 { get; private set; }
|
||||
public VisualElement NextElement
|
||||
{
|
||||
get => _nextElement;
|
||||
@@ -142,14 +171,15 @@ namespace Bit.App.Controls
|
||||
_nextElement = value;
|
||||
if(_nextElement != null && Entry != null)
|
||||
{
|
||||
Entry.ReturnType = Enums.ReturnType.Next;
|
||||
Entry.TargetReturnType = Enums.ReturnType.Next;
|
||||
}
|
||||
else if(Entry != null)
|
||||
{
|
||||
Entry.ReturnType = null;
|
||||
Entry.TargetReturnType = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Dictionary<string, object> MetaData { get; set; }
|
||||
|
||||
public void InitEvents()
|
||||
{
|
||||
|
||||
47
src/App/Controls/FormSwitchCell.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class FormSwitchCell : ExtendedViewCell
|
||||
{
|
||||
public FormSwitchCell(string labelText, string button1 = null)
|
||||
{
|
||||
Label = new Label
|
||||
{
|
||||
Text = labelText,
|
||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||
VerticalTextAlignment = TextAlignment.Center,
|
||||
TextColor = Color.Black,
|
||||
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
|
||||
};
|
||||
Switch = new Switch
|
||||
{
|
||||
VerticalOptions = LayoutOptions.Center
|
||||
};
|
||||
|
||||
var stackLayout = new StackLayout
|
||||
{
|
||||
Padding = new Thickness(15, 5),
|
||||
Orientation = StackOrientation.Horizontal,
|
||||
Children = { Label, Switch }
|
||||
};
|
||||
stackLayout.AdjustPaddingForDevice();
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(button1))
|
||||
{
|
||||
Button1 = new ExtendedButton { Image = button1 };
|
||||
stackLayout.Children.Add(Button1);
|
||||
Button1.BackgroundColor = Color.Transparent;
|
||||
Button1.Padding = new Thickness(0);
|
||||
Button1.WidthRequest = 40;
|
||||
Button1.VerticalOptions = LayoutOptions.FillAndExpand;
|
||||
}
|
||||
|
||||
View = stackLayout;
|
||||
}
|
||||
|
||||
public Switch Switch { get; private set; }
|
||||
public Label Label { get; set; }
|
||||
public ExtendedButton Button1 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,8 @@ namespace Bit.App.Controls
|
||||
var buttonStackLayout = new StackLayout
|
||||
{
|
||||
Orientation = StackOrientation.Horizontal,
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
Spacing = 5
|
||||
};
|
||||
|
||||
if(subText != null)
|
||||
@@ -75,8 +76,11 @@ namespace Bit.App.Controls
|
||||
{
|
||||
Image = button1Image,
|
||||
HorizontalOptions = LayoutOptions.End,
|
||||
VerticalOptions = LayoutOptions.Center,
|
||||
Margin = new Thickness(0)
|
||||
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||
Margin = new Thickness(0),
|
||||
Padding = new Thickness(0),
|
||||
BackgroundColor = Color.Transparent,
|
||||
WidthRequest = 40
|
||||
};
|
||||
|
||||
buttonStackLayout.Children.Add(Button1);
|
||||
@@ -88,8 +92,11 @@ namespace Bit.App.Controls
|
||||
{
|
||||
Image = button2Image,
|
||||
HorizontalOptions = LayoutOptions.End,
|
||||
VerticalOptions = LayoutOptions.Center,
|
||||
Margin = new Thickness(0)
|
||||
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||
Margin = new Thickness(0),
|
||||
Padding = new Thickness(0),
|
||||
BackgroundColor = Color.Transparent,
|
||||
WidthRequest = 40
|
||||
};
|
||||
|
||||
buttonStackLayout.Children.Add(Button2);
|
||||
@@ -97,21 +104,6 @@ namespace Bit.App.Controls
|
||||
|
||||
if(Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
buttonStackLayout.Spacing = 5;
|
||||
|
||||
if(Button1 != null)
|
||||
{
|
||||
Button1.Padding = new Thickness(0);
|
||||
Button1.BackgroundColor = Color.Transparent;
|
||||
Button1.WidthRequest = 40;
|
||||
}
|
||||
if(Button2 != null)
|
||||
{
|
||||
Button2.Padding = new Thickness(0);
|
||||
Button2.BackgroundColor = Color.Transparent;
|
||||
Button2.WidthRequest = 40;
|
||||
}
|
||||
|
||||
containerStackLayout.AdjustPaddingForDevice();
|
||||
}
|
||||
else if(Device.RuntimePlatform == Device.UWP)
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Bit.App.Controls
|
||||
Entry = new ExtendedEntry
|
||||
{
|
||||
Keyboard = Keyboard.Numeric,
|
||||
MaxLength = 4,
|
||||
TargetMaxLength = 4,
|
||||
HideCursor = true
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
Duo = 2,
|
||||
YubiKey = 3,
|
||||
U2f = 4,
|
||||
Remember = 5
|
||||
Remember = 5,
|
||||
OrganizationDuo = 6
|
||||
}
|
||||
}
|
||||
|
||||
12
src/App/Enums/UriMatchType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Bit.App.Enums
|
||||
{
|
||||
public enum UriMatchType : byte
|
||||
{
|
||||
Domain = 0,
|
||||
Host = 1,
|
||||
StartsWith = 2,
|
||||
Exact = 3,
|
||||
RegularExpression = 4,
|
||||
Never = 5
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class CardDataModel : CipherDataModel
|
||||
{
|
||||
public string CardholderName { get; set; }
|
||||
public string Brand { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
24
src/App/Models/Api/CardType.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class CardType
|
||||
{
|
||||
public CardType() { }
|
||||
|
||||
public CardType(Cipher cipher)
|
||||
{
|
||||
CardholderName = cipher.Card.CardholderName?.EncryptedString;
|
||||
Brand = cipher.Card.Brand?.EncryptedString;
|
||||
Number = cipher.Card.Number?.EncryptedString;
|
||||
ExpMonth = cipher.Card.ExpMonth?.EncryptedString;
|
||||
ExpYear = cipher.Card.ExpYear?.EncryptedString;
|
||||
Code = cipher.Card.Code?.EncryptedString;
|
||||
}
|
||||
|
||||
public string CardholderName { get; set; }
|
||||
public string Brand { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public abstract class CipherDataModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public IEnumerable<FieldDataModel> Fields { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using Bit.App.Enums;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class FieldDataModel
|
||||
{
|
||||
public FieldType Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
18
src/App/Models/Api/FieldType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class FieldType
|
||||
{
|
||||
public FieldType() { }
|
||||
|
||||
public FieldType(Field field)
|
||||
{
|
||||
Type = field.Type;
|
||||
Name = field.Name?.EncryptedString;
|
||||
Value = field.Value?.EncryptedString;
|
||||
}
|
||||
|
||||
public Enums.FieldType Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class IdentityDataModel : CipherDataModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string MiddleName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Address1 { get; set; }
|
||||
public string Address2 { get; set; }
|
||||
public string Address3 { get; set; }
|
||||
public string City { get; set; }
|
||||
public string State { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string Company { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string SSN { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string PassportNumber { get; set; }
|
||||
public string LicenseNumber { get; set; }
|
||||
}
|
||||
}
|
||||
48
src/App/Models/Api/IdentityType.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class IdentityType
|
||||
{
|
||||
public IdentityType() { }
|
||||
|
||||
public IdentityType(Cipher cipher)
|
||||
{
|
||||
Title = cipher.Identity.Title?.EncryptedString;
|
||||
FirstName = cipher.Identity.FirstName?.EncryptedString;
|
||||
MiddleName = cipher.Identity.MiddleName?.EncryptedString;
|
||||
LastName = cipher.Identity.LastName?.EncryptedString;
|
||||
Address1 = cipher.Identity.Address1?.EncryptedString;
|
||||
Address2 = cipher.Identity.Address2?.EncryptedString;
|
||||
Address3 = cipher.Identity.Address3?.EncryptedString;
|
||||
City = cipher.Identity.City?.EncryptedString;
|
||||
State = cipher.Identity.State?.EncryptedString;
|
||||
PostalCode = cipher.Identity.PostalCode?.EncryptedString;
|
||||
Country = cipher.Identity.Country?.EncryptedString;
|
||||
Company = cipher.Identity.Company?.EncryptedString;
|
||||
Email = cipher.Identity.Email?.EncryptedString;
|
||||
Phone = cipher.Identity.Phone?.EncryptedString;
|
||||
SSN = cipher.Identity.SSN?.EncryptedString;
|
||||
Username = cipher.Identity.Username?.EncryptedString;
|
||||
PassportNumber = cipher.Identity.PassportNumber?.EncryptedString;
|
||||
LicenseNumber = cipher.Identity.LicenseNumber?.EncryptedString;
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string MiddleName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Address1 { get; set; }
|
||||
public string Address2 { get; set; }
|
||||
public string Address3 { get; set; }
|
||||
public string City { get; set; }
|
||||
public string State { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string Company { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string SSN { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string PassportNumber { get; set; }
|
||||
public string LicenseNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class LoginDataModel : CipherDataModel
|
||||
{
|
||||
public string Uri { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Totp { get; set; }
|
||||
}
|
||||
}
|
||||
26
src/App/Models/Api/LoginType.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class LoginType
|
||||
{
|
||||
public LoginType() { }
|
||||
|
||||
public LoginType(Cipher cipher)
|
||||
{
|
||||
Uris = cipher.Login.Uris?.Select(u => new LoginUriType(u));
|
||||
Username = cipher.Login.Username?.EncryptedString;
|
||||
Password = cipher.Login.Password?.EncryptedString;
|
||||
PasswordRevisionDate = cipher.Login.PasswordRevisionDate;
|
||||
Totp = cipher.Login.Totp?.EncryptedString;
|
||||
}
|
||||
|
||||
public IEnumerable<LoginUriType> Uris { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public System.DateTime? PasswordRevisionDate { get; set; }
|
||||
public string Totp { get; set; }
|
||||
}
|
||||
}
|
||||
18
src/App/Models/Api/LoginUriType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Bit.App.Enums;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class LoginUriType
|
||||
{
|
||||
public LoginUriType() { }
|
||||
|
||||
public LoginUriType(LoginUri u)
|
||||
{
|
||||
Uri = u.Uri?.EncryptedString;
|
||||
Match = u.Match;
|
||||
}
|
||||
|
||||
public string Uri { get; set; }
|
||||
public UriMatchType? Match { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,12 @@ namespace Bit.App.Models.Api
|
||||
|
||||
if(cipher.Fields != null)
|
||||
{
|
||||
Fields = cipher.Fields.Select(f => new FieldDataModel
|
||||
{
|
||||
Name = f.Name?.EncryptedString,
|
||||
Value = f.Value?.EncryptedString,
|
||||
Type = f.Type
|
||||
});
|
||||
Fields = cipher.Fields.Select(f => new FieldType(f));
|
||||
}
|
||||
|
||||
if(cipher.PasswordHistory != null)
|
||||
{
|
||||
PasswordHistory = cipher.PasswordHistory.Select(h => new PasswordHistoryRequest(h));
|
||||
}
|
||||
|
||||
switch(Type)
|
||||
@@ -50,101 +50,12 @@ namespace Bit.App.Models.Api
|
||||
public bool Favorite { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public IEnumerable<FieldDataModel> Fields { get; set; }
|
||||
public IEnumerable<FieldType> Fields { get; set; }
|
||||
public IEnumerable<PasswordHistoryRequest> PasswordHistory { get; set; }
|
||||
|
||||
public LoginType Login { get; set; }
|
||||
public CardType Card { get; set; }
|
||||
public IdentityType Identity { get; set; }
|
||||
public SecureNoteType SecureNote { get; set; }
|
||||
|
||||
public class LoginType
|
||||
{
|
||||
public LoginType(Cipher cipher)
|
||||
{
|
||||
Uri = cipher.Login.Uri?.EncryptedString;
|
||||
Username = cipher.Login.Username?.EncryptedString;
|
||||
Password = cipher.Login.Password?.EncryptedString;
|
||||
Totp = cipher.Login.Totp?.EncryptedString;
|
||||
}
|
||||
|
||||
public string Uri { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Totp { get; set; }
|
||||
}
|
||||
|
||||
public class CardType
|
||||
{
|
||||
public CardType(Cipher cipher)
|
||||
{
|
||||
CardholderName = cipher.Card.CardholderName?.EncryptedString;
|
||||
Brand = cipher.Card.Brand?.EncryptedString;
|
||||
Number = cipher.Card.Number?.EncryptedString;
|
||||
ExpMonth = cipher.Card.ExpMonth?.EncryptedString;
|
||||
ExpYear = cipher.Card.ExpYear?.EncryptedString;
|
||||
Code = cipher.Card.Code?.EncryptedString;
|
||||
}
|
||||
|
||||
public string CardholderName { get; set; }
|
||||
public string Brand { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class IdentityType
|
||||
{
|
||||
public IdentityType(Cipher cipher)
|
||||
{
|
||||
Title = cipher.Identity.Title?.EncryptedString;
|
||||
FirstName = cipher.Identity.FirstName?.EncryptedString;
|
||||
MiddleName = cipher.Identity.MiddleName?.EncryptedString;
|
||||
LastName = cipher.Identity.LastName?.EncryptedString;
|
||||
Address1 = cipher.Identity.Address1?.EncryptedString;
|
||||
Address2 = cipher.Identity.Address2?.EncryptedString;
|
||||
Address3 = cipher.Identity.Address3?.EncryptedString;
|
||||
City = cipher.Identity.City?.EncryptedString;
|
||||
State = cipher.Identity.State?.EncryptedString;
|
||||
PostalCode = cipher.Identity.PostalCode?.EncryptedString;
|
||||
Country = cipher.Identity.Country?.EncryptedString;
|
||||
Company = cipher.Identity.Company?.EncryptedString;
|
||||
Email = cipher.Identity.Email?.EncryptedString;
|
||||
Phone = cipher.Identity.Phone?.EncryptedString;
|
||||
SSN = cipher.Identity.SSN?.EncryptedString;
|
||||
Username = cipher.Identity.Username?.EncryptedString;
|
||||
PassportNumber = cipher.Identity.PassportNumber?.EncryptedString;
|
||||
LicenseNumber = cipher.Identity.LicenseNumber?.EncryptedString;
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string MiddleName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Address1 { get; set; }
|
||||
public string Address2 { get; set; }
|
||||
public string Address3 { get; set; }
|
||||
public string City { get; set; }
|
||||
public string State { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string Company { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string SSN { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string PassportNumber { get; set; }
|
||||
public string LicenseNumber { get; set; }
|
||||
}
|
||||
|
||||
public class SecureNoteType
|
||||
{
|
||||
public SecureNoteType(Cipher cipher)
|
||||
{
|
||||
Type = cipher.SecureNote.Type;
|
||||
}
|
||||
|
||||
public Enums.SecureNoteType Type { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
14
src/App/Models/Api/Request/PasswordHistoryRequest.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class PasswordHistoryRequest
|
||||
{
|
||||
public PasswordHistoryRequest(PasswordHistory ph)
|
||||
{
|
||||
Password = ph.Password?.EncryptedString;
|
||||
LastUsedDate = ph.LastUsedDate;
|
||||
}
|
||||
|
||||
public string Password { get; set; }
|
||||
public System.DateTime LastUsedDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Bit.App.Enums;
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
@@ -15,8 +14,15 @@ namespace Bit.App.Models.Api
|
||||
public bool Favorite { get; set; }
|
||||
public bool Edit { get; set; }
|
||||
public bool OrganizationUseTotp { get; set; }
|
||||
public JObject Data { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public LoginType Login { get; set; }
|
||||
public CardType Card { get; set; }
|
||||
public IdentityType Identity { get; set; }
|
||||
public SecureNoteType SecureNote { get; set; }
|
||||
public IEnumerable<FieldType> Fields { get; set; }
|
||||
public IEnumerable<AttachmentResponse> Attachments { get; set; }
|
||||
public IEnumerable<PasswordHistoryResponse> PasswordHistory { get; set; }
|
||||
public IEnumerable<string> CollectionIds { get; set; }
|
||||
public DateTime RevisionDate { get; set; }
|
||||
}
|
||||
|
||||
8
src/App/Models/Api/Response/PasswordHistoryResponse.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class PasswordHistoryResponse
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public System.DateTime LastUsedDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using Bit.App.Enums;
|
||||
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class SecureNoteDataModel : CipherDataModel
|
||||
{
|
||||
public SecureNoteType Type { get; set; }
|
||||
}
|
||||
}
|
||||
14
src/App/Models/Api/SecureNoteType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Bit.App.Models.Api
|
||||
{
|
||||
public class SecureNoteType
|
||||
{
|
||||
public SecureNoteType() { }
|
||||
|
||||
public SecureNoteType(Cipher cipher)
|
||||
{
|
||||
Type = cipher.SecureNote.Type;
|
||||
}
|
||||
|
||||
public Enums.SecureNoteType Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.App.Models.Api;
|
||||
using Bit.App.Models.Data;
|
||||
using Bit.App.Models.Data;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Bit.App.Models
|
||||
{
|
||||
@@ -10,7 +10,19 @@ namespace Bit.App.Models
|
||||
|
||||
public Card(CipherData data)
|
||||
{
|
||||
var deserializedData = JsonConvert.DeserializeObject<CardDataModel>(data.Data);
|
||||
CardDataModel deserializedData;
|
||||
if(data.Card != null)
|
||||
{
|
||||
deserializedData = JsonConvert.DeserializeObject<CardDataModel>(data.Card);
|
||||
}
|
||||
else if(data.Data != null)
|
||||
{
|
||||
deserializedData = JsonConvert.DeserializeObject<CardDataModel>(data.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data.Card));
|
||||
}
|
||||
|
||||
CardholderName = deserializedData.CardholderName != null ?
|
||||
new CipherString(deserializedData.CardholderName) : null;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Bit.App.Enums;
|
||||
using Bit.App.Models.Api;
|
||||
using Bit.App.Models.Data;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
@@ -25,6 +24,7 @@ namespace Bit.App.Models
|
||||
Edit = data.Edit;
|
||||
OrganizationUseTotp = data.OrganizationUseTotp;
|
||||
Attachments = attachments?.Select(a => new Attachment(a));
|
||||
RevisionDate = data.RevisionDateTime;
|
||||
|
||||
switch(Type)
|
||||
{
|
||||
@@ -53,6 +53,17 @@ namespace Bit.App.Models
|
||||
}
|
||||
catch(JsonSerializationException) { }
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(data.PasswordHistory))
|
||||
{
|
||||
try
|
||||
{
|
||||
var phModels = JsonConvert.DeserializeObject<IEnumerable<PasswordHistoryDataModel>>(
|
||||
data.PasswordHistory);
|
||||
PasswordHistory = phModels?.Select(f => new PasswordHistory(f));
|
||||
}
|
||||
catch(JsonSerializationException) { }
|
||||
}
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
@@ -63,14 +74,19 @@ namespace Bit.App.Models
|
||||
public CipherString Name { get; set; }
|
||||
public CipherString Notes { get; set; }
|
||||
public IEnumerable<Field> Fields { get; set; }
|
||||
public IEnumerable<PasswordHistory> PasswordHistory { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Edit { get; set; }
|
||||
public bool OrganizationUseTotp { get; set; }
|
||||
public IEnumerable<Attachment> Attachments { get; set; }
|
||||
public System.DateTime RevisionDate { get; set; }
|
||||
|
||||
public Login Login { get; set; }
|
||||
public Identity Identity { get; set; }
|
||||
public Card Card { get; set; }
|
||||
public SecureNote SecureNote { get; set; }
|
||||
|
||||
public System.DateTime? PasswordRevisionDisplayDate =>
|
||||
Login?.Password == null ? null : Login.PasswordRevisionDate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using SQLite;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using Bit.App.Enums;
|
||||
using Bit.App.Models.Api;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Bit.App.Models.Data
|
||||
{
|
||||
@@ -26,46 +27,50 @@ namespace Bit.App.Models.Data
|
||||
OrganizationUseTotp = cipher.OrganizationUseTotp;
|
||||
RevisionDateTime = cipher.RevisionDate;
|
||||
Type = cipher.Type;
|
||||
Data = JsonConvert.SerializeObject(cipher.Data);
|
||||
Data = null;
|
||||
|
||||
CipherDataModel cipherData = null;
|
||||
switch(cipher.Type)
|
||||
{
|
||||
case CipherType.Login:
|
||||
var loginData = cipher.Data.ToObject<LoginDataModel>();
|
||||
cipherData = loginData;
|
||||
|
||||
Uri = loginData.Uri;
|
||||
Username = loginData.Username;
|
||||
Password = loginData.Password;
|
||||
Totp = loginData.Totp;
|
||||
var loginObj = JObject.FromObject(new LoginDataModel(cipher),
|
||||
new JsonSerializer { NullValueHandling = NullValueHandling.Ignore });
|
||||
loginObj[nameof(LoginDataModel.Uri)]?.Parent?.Remove();
|
||||
Login = loginObj.ToString(Formatting.None);
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
var noteData = cipher.Data.ToObject<SecureNoteDataModel>();
|
||||
cipherData = noteData;
|
||||
|
||||
SecureNoteType = noteData.Type;
|
||||
var noteData = new SecureNoteDataModel(cipher);
|
||||
SecureNote = JsonConvert.SerializeObject(noteData);
|
||||
break;
|
||||
case CipherType.Card:
|
||||
var cardData = cipher.Data.ToObject<CardDataModel>();
|
||||
cipherData = cardData;
|
||||
var cardData = new CardDataModel(cipher);
|
||||
Card = JsonConvert.SerializeObject(cardData);
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
var idData = cipher.Data.ToObject<IdentityDataModel>();
|
||||
cipherData = idData;
|
||||
var idData = new IdentityDataModel(cipher);
|
||||
Identity = JsonConvert.SerializeObject(idData);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException(nameof(cipher.Type));
|
||||
}
|
||||
|
||||
Name = cipherData.Name;
|
||||
Notes = cipherData.Notes;
|
||||
Name = cipher.Name;
|
||||
Notes = cipher.Notes;
|
||||
|
||||
if(cipherData.Fields != null && cipherData.Fields.Any())
|
||||
if(cipher.Fields != null && cipher.Fields.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
Fields = JsonConvert.SerializeObject(cipherData.Fields);
|
||||
Fields = JsonConvert.SerializeObject(cipher.Fields.Select(f => new FieldDataModel(f)));
|
||||
}
|
||||
catch(JsonSerializationException) { }
|
||||
}
|
||||
|
||||
if(cipher.PasswordHistory != null && cipher.PasswordHistory.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
PasswordHistory = JsonConvert.SerializeObject(
|
||||
cipher.PasswordHistory.Select(h => new PasswordHistoryDataModel(h)));
|
||||
}
|
||||
catch(JsonSerializationException) { }
|
||||
}
|
||||
@@ -80,21 +85,18 @@ namespace Bit.App.Models.Data
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public string Fields { get; set; }
|
||||
public string PasswordHistory { get; set; }
|
||||
public string Login { get; set; }
|
||||
public string Card { get; set; }
|
||||
public string Identity { get; set; }
|
||||
public string SecureNote { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Edit { get; set; }
|
||||
public bool OrganizationUseTotp { get; set; }
|
||||
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||
[Indexed]
|
||||
public CipherType Type { get; set; } = CipherType.Login;
|
||||
[Obsolete]
|
||||
public string Data { get; set; }
|
||||
|
||||
// Login metadata
|
||||
public string Uri { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Totp { get; set; }
|
||||
|
||||
// Secure Note metadata
|
||||
public SecureNoteType? SecureNoteType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
33
src/App/Models/Data/CipherData/CardDataModel.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Bit.App.Models.Api;
|
||||
using System;
|
||||
|
||||
namespace Bit.App.Models.Data
|
||||
{
|
||||
public class CardDataModel : CipherDataModel
|
||||
{
|
||||
public CardDataModel() { }
|
||||
|
||||
public CardDataModel(CipherResponse response)
|
||||
: base(response)
|
||||
{
|
||||
if(response?.Card == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(response.Card));
|
||||
}
|
||||
|
||||
CardholderName = response.Card.CardholderName;
|
||||
Brand = response.Card.Brand;
|
||||
Number = response.Card.Number;
|
||||
ExpMonth = response.Card.ExpMonth;
|
||||
ExpYear = response.Card.ExpYear;
|
||||
Code = response.Card.Code;
|
||||
}
|
||||
|
||||
public string CardholderName { get; set; }
|
||||
public string Brand { get; set; }
|
||||
public string Number { get; set; }
|
||||
public string ExpMonth { get; set; }
|
||||
public string ExpYear { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
}
|
||||
24
src/App/Models/Data/CipherData/CipherDataModel.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Bit.App.Models.Api;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bit.App.Models.Data
|
||||
{
|
||||
public abstract class CipherDataModel
|
||||
{
|
||||
public CipherDataModel() { }
|
||||
|
||||
public CipherDataModel(CipherResponse cipher)
|
||||
{
|
||||
Name = cipher.Name;
|
||||
Notes = cipher.Notes;
|
||||
Fields = cipher.Fields?.Select(f => new FieldDataModel(f));
|
||||
PasswordHistory = cipher.PasswordHistory?.Select(h => new PasswordHistoryDataModel(h));
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public IEnumerable<FieldDataModel> Fields { get; set; }
|
||||
public IEnumerable<PasswordHistoryDataModel> PasswordHistory { get; set; }
|
||||
}
|
||||
}
|
||||