1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00

Compare commits

...

62 Commits

Author SHA1 Message Date
Kyle Spearrin
8fc8d03cc4 version bump 2017-11-01 14:41:16 -04:00
Kyle Spearrin
df77f42145 remove FilterTouchesWhenObscured for now 2017-11-01 11:19:57 -04:00
Kyle Spearrin
0dea5bdbea remove amazon store assets 2017-10-30 16:51:23 -04:00
Kyle Spearrin
5c7f939440 Update README.md 2017-10-30 16:48:45 -04:00
Kyle Spearrin
09bef28362 remove .png from selected icon 2017-10-30 15:18:24 -04:00
Kyle Spearrin
1f0f94746b only show icons in nav 2017-10-30 14:13:09 -04:00
Kyle Spearrin
c057be17d0 bump bundle version for ios 2017-10-30 12:51:36 -04:00
Kyle Spearrin
301aaf9c68 version bump on iOS and new lang codes 2017-10-30 11:23:19 -04:00
Kyle Spearrin
ab7093f962 New Crowdin translations (#154)
* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (French)
2017-10-30 11:18:25 -04:00
Kyle Spearrin
29b2d67fb6 null checks 2017-10-30 11:12:14 -04:00
Kyle Spearrin
d4cd2b8be8 perform sync on update 2017-10-28 21:36:27 -04:00
Kyle Spearrin
fea94f956d version bump for beta 2017-10-27 11:32:38 -04:00
Kyle Spearrin
a656aa21f8 more icons resized on android 2017-10-27 11:23:29 -04:00
Kyle Spearrin
3b235f2ca2 Update README.md 2017-10-26 11:54:09 -04:00
Kyle Spearrin
376841f619 New Crowdin translations (#152)
* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Indonesian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (German)

* New translations copy.resx (German)

* New translations copy.resx (German)

* New translations AppResources.resx (German)

* New translations AppResources.resx (French)
2017-10-26 09:40:34 -04:00
Kyle Spearrin
746a7c404b set custom icons server url 2017-10-23 23:20:35 -04:00
Kyle Spearrin
2d126300d8 set placeholder first 2017-10-23 13:08:46 -04:00
Kyle Spearrin
ed7e43ed6e downgrade cachedimage lib 2017-10-21 00:05:59 -04:00
Kyle Spearrin
7c56f1a773 bind to image with OnBindingContextChanged 2017-10-20 23:08:39 -04:00
Kyle Spearrin
6ba396440f cipher renames 2017-10-20 16:57:48 -04:00
Kyle Spearrin
8970525861 Fix cipher changes in extension model 2017-10-20 16:56:10 -04:00
Kyle Spearrin
5a88a66709 next return if nextelement set later 2017-10-20 16:51:30 -04:00
Kyle Spearrin
3ae6e3ee53 icons for uwp 2017-10-20 16:33:12 -04:00
Kyle Spearrin
5c0d4700f9 new icons for ios 2017-10-20 16:32:08 -04:00
Kyle Spearrin
7b354f5b8c update folder size to 20 2017-10-20 16:28:55 -04:00
Kyle Spearrin
a197c0219e hostnameUri fix 2017-10-20 16:18:30 -04:00
Kyle Spearrin
05f4036309 disable website icons option 2017-10-20 16:10:22 -04:00
Kyle Spearrin
37974c7ec8 icons in vault listing 2017-10-20 15:24:40 -04:00
Kyle Spearrin
5cb3e15201 update more icon for android styling 2017-10-20 13:03:04 -04:00
Kyle Spearrin
54b4766680 optimizations for secure notes 2017-10-20 12:51:41 -04:00
Kyle Spearrin
cc0bb65096 subtitles for each type 2017-10-20 12:47:05 -04:00
Kyle Spearrin
296c9dc055 cipher edit for various types 2017-10-20 12:35:31 -04:00
Kyle Spearrin
70aa2309b7 added support for cards and identity to view page 2017-10-20 11:25:34 -04:00
Kyle Spearrin
d2468d144e more renames 2017-10-19 16:08:29 -04:00
Kyle Spearrin
ebbe704672 replace launch and clipboard buttons with icons 2017-10-19 14:56:11 -04:00
Kyle Spearrin
d146870a74 rename pages and props for login => cipher 2017-10-19 14:30:12 -04:00
Kyle Spearrin
58ebabf74c fix add class refs 2017-10-19 13:49:15 -04:00
Kyle Spearrin
8f8a3b6387 rename page to addcipher 2017-10-19 13:46:12 -04:00
Kyle Spearrin
df616cfe3e add ciphers: card, identity, and sec note 2017-10-19 13:44:05 -04:00
Kyle Spearrin
dd96608bb1 splash is exportable 2017-10-19 11:19:24 -04:00
Kyle Spearrin
264f2ab316 restore api endpoints 2017-10-19 11:19:10 -04:00
Kyle Spearrin
773f156785 change home settings to extendedbutton 2017-10-19 08:55:18 -04:00
Kyle Spearrin
7cd3e2a5b9 do not export bitwarden activities 2017-10-19 08:53:30 -04:00
Kyle Spearrin
0ec22a4639 update resource strings for Logins => Items 2017-10-18 21:53:44 -04:00
Kyle Spearrin
74ac9cbbbe add other cipher type support to vault listings 2017-10-18 21:35:33 -04:00
Kyle Spearrin
0020bd0fb7 some remaining login => renames 2017-10-18 21:07:30 -04:00
Kyle Spearrin
1d6ec0f953 refactoring code for login => cipher support 2017-10-18 20:55:33 -04:00
Kyle Spearrin
37f05f0a12 Changed "Cancel" to "Close" 2017-10-13 09:11:37 -04:00
Kyle Spearrin
9a22a1dbf4 add autofill support for edge browser 2017-10-12 22:53:41 -04:00
Kyle Spearrin
b768c8b28a proper push service 2017-10-10 11:49:56 -04:00
Kyle Spearrin
bcbdbb4932 cleanup push 2017-10-10 10:55:54 -04:00
Kyle Spearrin
04e42c4a75 UNUserNotificationCenterDelegate 2017-10-10 09:13:09 -04:00
Kyle Spearrin
6040c7768f rename to pushnotificationservice 2017-10-10 08:26:17 -04:00
Kyle Spearrin
6da0d3e88d push for uwp 2017-10-09 23:53:06 -04:00
Kyle Spearrin
7c6cc7b246 local push notification implementation from lib 2017-10-09 23:45:23 -04:00
Kyle Spearrin
d5da1d6f3f all architectures 2017-10-08 21:36:27 -04:00
Kyle Spearrin
de5ee90e21 C2D_MESSAGE protectionLevel signature 2017-10-07 12:57:52 -04:00
Kyle Spearrin
8a0c9ab3db add back slash prefix to api routes 2017-10-03 23:56:10 -04:00
Kyle Spearrin
e901a1f231 UWP tabbed page with icons 2017-10-03 12:11:09 -04:00
Kyle Spearrin
e4c47aca9e shorthand 2017-10-02 22:38:56 -04:00
Kyle Spearrin
a43a3db098 formatting updates 2017-10-02 22:38:10 -04:00
Hicham Boushaba
d651606800 Add UWP support (#139)
* Add UWP project, and generate services boilerplate

* SqliteService implementation and sqlite-net-pcl update (#bug https://stackoverflow.com/questions/45418669/xamarin-forms-pcl-assemly-issue)

* Important services implementation

* Create a shared project to host images for UWP (to keep code project clean)

* Add extensions to image names referenced by the pcl project

* Add DismissModalToolBarItem to modal pages

* moving UWP folders inside src folder

* Add DeviceInfoService implementation

* Remove dependency on BouncyCastle, and calculate key derivation using native support

* changes requested by project maintener

* Fix HasCamera property

* DeviceActionService implementation
2017-10-02 22:15:13 -04:00
338 changed files with 13738 additions and 8032 deletions

View File

@@ -4,7 +4,7 @@
# bitwarden mobile
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a> <a href="https://www.amazon.com/dp/B06XMYGPMV" target="_blank"><img src="https://imgur.com/f75uYeM.png" width="132" height="45"></a>
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
The bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
@@ -17,8 +17,8 @@ The bitwarden mobile application is written in C# with Xamarin Android, Xamarin
- [Visual Studio w/ Xamarin -or- Xamarin Studio](https://store.xamarin.com/)
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 API. Open `src/App/Utilities/ApiHttpClient.cs` and set `BaseAddress` to your local
API instance (ex. `new Uri("http://localhost:4000")`).
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).
After restoring the nuget packages, you can now build and run the app.

View File

@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.13
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{04B18ED2-B76D-4947-8474-191F8FD2B5E0}"
EndProject
@@ -29,7 +29,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E3996
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{428CACAB-CC26-4F41-9062-1E4A9BC82640}"
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
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
@@ -94,8 +102,6 @@ Global
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.ActiveCfg = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.Build.0 = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x64.Deploy.0 = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.ActiveCfg = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.Build.0 = Debug|Any CPU
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|x86.Deploy.0 = Debug|Any CPU
@@ -136,7 +142,6 @@ Global
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x64.ActiveCfg = Debug|iPhone
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x64.Build.0 = Debug|iPhone
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x86.ActiveCfg = Debug|iPhone
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|x86.Build.0 = Debug|iPhone
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|Any CPU.ActiveCfg = Release|iPhone
@@ -222,7 +227,6 @@ Global
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x64.ActiveCfg = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x64.Build.0 = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x86.ActiveCfg = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|x86.Build.0 = Debug|Any CPU
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -258,7 +262,6 @@ Global
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x64.ActiveCfg = Debug|iPhone
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x64.Build.0 = Debug|iPhone
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x86.ActiveCfg = Debug|iPhone
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Debug|x86.Build.0 = Debug|iPhone
{32F5A2D6-F54D-4DA1-AE26-0A980D48F422}.Release|Any CPU.ActiveCfg = Release|iPhone
@@ -300,7 +303,6 @@ Global
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x64.ActiveCfg = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x64.Build.0 = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x86.ActiveCfg = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Debug|x86.Build.0 = Debug|Any CPU
{B2538ADA-B605-4D6F-ACD2-62A409680F84}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -394,8 +396,6 @@ Global
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.ActiveCfg = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.Build.0 = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x64.Deploy.0 = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.ActiveCfg = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.Build.0 = Debug|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Debug|x86.Deploy.0 = Debug|Any CPU
@@ -450,7 +450,6 @@ Global
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.ActiveCfg = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.Build.0 = Debug|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -465,6 +464,66 @@ Global
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x64.Build.0 = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x86.ActiveCfg = Release|Any CPU
{428CACAB-CC26-4F41-9062-1E4A9BC82640}.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}.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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -480,5 +539,10 @@ Global
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
{428CACAB-CC26-4F41-9062-1E4A9BC82640} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
{3A2D5669-ED71-4F2B-BA85-2D36BAA05141} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{0BE54BBB-7772-4289-BD51-1FDBB0CC2446} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {318CB2DF-0118-43A3-AC83-56BADCF71CCD}
EndGlobalSection
EndGlobal

View File

@@ -70,6 +70,7 @@
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidLinkSkip>PushNotification.Plugin;PushNotification.Plugin.Abstractions;Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;SQLite-net;Xamarin.Android.Net</AndroidLinkSkip>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidSupportedAbis>armeabi;armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
</PropertyGroup>
<ItemGroup>
<Reference Include="Acr.Support.Android, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@@ -163,14 +164,6 @@
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
</Reference>
@@ -178,8 +171,8 @@
<HintPath>..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite-net, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.4.118\lib\netstandard1.1\SQLite-net.dll</HintPath>
<Reference Include="SQLite-net, Version=1.5.166.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.5.166-beta\lib\netstandard1.1\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\MonoAndroid\SQLitePCLRaw.batteries_green.dll</HintPath>
@@ -324,6 +317,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\LogService.cs" />
<Compile Include="Services\MemoryService.cs" />
<Compile Include="Services\AndroidPushNotificationService.cs" />
<Compile Include="Services\ReflectionService.cs" />
<Compile Include="Services\SqlService.cs" />
<Compile Include="SplashActivity.cs" />
@@ -948,6 +942,126 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable\shield.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\clipboard.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\launch.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\clipboard.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\launch.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\clipboard.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\launch.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\clipboard.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\launch.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\clipboard.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\launch.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\card.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\id.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\login.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\note.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\card.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\id.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\note.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\login.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\card.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\id.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\note.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\login.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\card.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\id.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\login.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\note.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\card.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\id.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\note.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\login.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\apple.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\apple.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\apple.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\apple.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\android.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\apple.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@@ -55,7 +55,8 @@ namespace Bit.Android
new Browser("com.linkbubble.playstore", "url_text"),
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
new Browser("acr.browser.lightning", "search"),
new Browser("acr.browser.barebones", "search")
new Browser("acr.browser.barebones", "search"),
new Browser("com.microsoft.emmx", "url_bar")
}.ToDictionary(n => n.PackageName);
private readonly IAppSettingsService _appSettings;

View File

@@ -16,6 +16,10 @@ namespace Bit.Android.Controls
{
Control.TextSize = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Button));
}
// This will prevent all screen overlay apps from being able to interact with buttons.
// Ex: apps that change the screen color for "night mode"
// Control.FilterTouchesWhenObscured = true;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)

View File

@@ -62,7 +62,8 @@ namespace Bit.Android.Controls
if(selected)
{
var selectedResource = IdFromTitle(string.Format("{0}_selected", icon), ResourceManager.DrawableClass);
var selectedIcon = string.Format("{0}_selected", icon.Replace(".png", string.Empty));
var selectedResource = IdFromTitle(selectedIcon, ResourceManager.DrawableClass);
if(selectedResource != 0)
{
tab.SetIcon(selectedResource);

View File

@@ -24,7 +24,8 @@ namespace Bit.Android
{
[Activity(Label = "bitwarden",
Icon = "@drawable/icon",
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
Exported = false)]
public class MainActivity : FormsAppCompatActivity
{
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
@@ -104,7 +105,7 @@ namespace Bit.Android
OpenAccessibilitySettings();
});
MessagingCenter.Subscribe<Xamarin.Forms.Application, VaultListPageModel.Login>(
MessagingCenter.Subscribe<Xamarin.Forms.Application, VaultListPageModel.Cipher>(
Xamarin.Forms.Application.Current, "Autofill", (sender, args) =>
{
ReturnCredentials(args);
@@ -128,10 +129,10 @@ namespace Bit.Android
});
}
private void ReturnCredentials(VaultListPageModel.Login login)
private void ReturnCredentials(VaultListPageModel.Cipher cipher)
{
Intent data = new Intent();
if(login == null)
if(cipher == null)
{
data.PutExtra("canceled", "true");
}
@@ -139,14 +140,14 @@ namespace Bit.Android
{
var isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false;
var autoCopyEnabled = !_settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false);
if(isPremium && autoCopyEnabled && _deviceActionService != null && login.Totp.Value != null)
if(isPremium && autoCopyEnabled && _deviceActionService != null && cipher.LoginTotp?.Value != null)
{
_deviceActionService.CopyToClipboard(App.Utilities.Crypto.Totp(login.Totp.Value));
_deviceActionService.CopyToClipboard(App.Utilities.Crypto.Totp(cipher.LoginTotp.Value));
}
data.PutExtra("uri", login.Uri.Value);
data.PutExtra("username", login.Username);
data.PutExtra("password", login.Password.Value);
data.PutExtra("uri", cipher.LoginUri);
data.PutExtra("username", cipher.LoginUsername);
data.PutExtra("password", cipher.LoginPassword?.Value ?? null);
}
if(Parent == null)

View File

@@ -12,8 +12,6 @@ using Plugin.Connectivity;
using Plugin.CurrentActivity;
using Plugin.Fingerprint;
using Plugin.Settings;
using PushNotification.Plugin;
using PushNotification.Plugin.Abstractions;
using XLabs.Ioc;
using System.Threading.Tasks;
using Plugin.Settings.Abstractions;
@@ -69,7 +67,7 @@ namespace Bit.Android
private void HandlePushReregistration()
{
var pushNotification = Resolver.Resolve<IPushNotification>();
var pushNotification = Resolver.Resolve<IPushNotificationService>();
var settings = Resolver.Resolve<ISettings>();
// Reregister for push token based on certain conditions
@@ -153,11 +151,11 @@ namespace Bit.Android
public static void StartPushService()
{
AppContext.StartService(new Intent(AppContext, typeof(PushNotificationService)));
AppContext.StartService(new Intent(AppContext, typeof(AndroidPushService)));
if(Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext,
typeof(PushNotificationService)), 0);
typeof(AndroidPushService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(AlarmService);
alarm.Cancel(pintent);
}
@@ -165,11 +163,11 @@ namespace Bit.Android
public static void StopPushService()
{
AppContext.StopService(new Intent(AppContext, typeof(PushNotificationService)));
AppContext.StopService(new Intent(AppContext, typeof(AndroidPushService)));
if(Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext,
typeof(PushNotificationService)), 0);
typeof(AndroidPushService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(AlarmService);
alarm.Cancel(pintent);
}
@@ -197,7 +195,7 @@ namespace Bit.Android
container.RegisterSingleton<IKeyDerivationService, BouncyCastleKeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ILoginService, LoginService>();
container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
container.RegisterSingleton<IAppIdService, AppIdService>();
@@ -218,7 +216,7 @@ namespace Bit.Android
// Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>();
container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();

View File

@@ -15,8 +15,9 @@ namespace Bit.Android
public override void OnReceive(Context context, Intent intent)
{
Debug.WriteLine("App updated!");
Helpers.PerformUpdateTasks(Resolver.Resolve<ISettings>(), Resolver.Resolve<IAppInfoService>(),
Resolver.Resolve<IDatabaseService>());
Helpers.PerformUpdateTasks(Resolver.Resolve<ISettings>(),
Resolver.Resolve<IAppInfoService>(),Resolver.Resolve<IDatabaseService>(),
Resolver.Resolve<ISyncService>());
}
}
}

View File

@@ -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.11.0" 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.12.1" 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,6 +12,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" />
<permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

View File

@@ -2311,520 +2311,544 @@ namespace Bit.Android
public const int accessibility_step2 = 2130837582;
// aapt resource value: 0x7f02004f
public const int camera = 2130837583;
public const int android = 2130837583;
// aapt resource value: 0x7f020050
public const int cloudup = 2130837584;
public const int apple = 2130837584;
// aapt resource value: 0x7f020051
public const int cog = 2130837585;
public const int camera = 2130837585;
// aapt resource value: 0x7f020052
public const int cogs = 2130837586;
public const int card = 2130837586;
// aapt resource value: 0x7f020053
public const int cogs_selected = 2130837587;
public const int clipboard = 2130837587;
// aapt resource value: 0x7f020054
public const int common_full_open_on_phone = 2130837588;
public const int cloudup = 2130837588;
// aapt resource value: 0x7f020055
public const int common_google_signin_btn_icon_dark = 2130837589;
public const int cog = 2130837589;
// aapt resource value: 0x7f020056
public const int common_google_signin_btn_icon_dark_disabled = 2130837590;
public const int cogs = 2130837590;
// aapt resource value: 0x7f020057
public const int common_google_signin_btn_icon_dark_focused = 2130837591;
public const int cogs_selected = 2130837591;
// aapt resource value: 0x7f020058
public const int common_google_signin_btn_icon_dark_normal = 2130837592;
public const int common_full_open_on_phone = 2130837592;
// aapt resource value: 0x7f020059
public const int common_google_signin_btn_icon_dark_pressed = 2130837593;
public const int common_google_signin_btn_icon_dark = 2130837593;
// aapt resource value: 0x7f02005a
public const int common_google_signin_btn_icon_light = 2130837594;
public const int common_google_signin_btn_icon_dark_disabled = 2130837594;
// aapt resource value: 0x7f02005b
public const int common_google_signin_btn_icon_light_disabled = 2130837595;
public const int common_google_signin_btn_icon_dark_focused = 2130837595;
// aapt resource value: 0x7f02005c
public const int common_google_signin_btn_icon_light_focused = 2130837596;
public const int common_google_signin_btn_icon_dark_normal = 2130837596;
// aapt resource value: 0x7f02005d
public const int common_google_signin_btn_icon_light_normal = 2130837597;
public const int common_google_signin_btn_icon_dark_pressed = 2130837597;
// aapt resource value: 0x7f02005e
public const int common_google_signin_btn_icon_light_pressed = 2130837598;
public const int common_google_signin_btn_icon_light = 2130837598;
// aapt resource value: 0x7f02005f
public const int common_google_signin_btn_text_dark = 2130837599;
public const int common_google_signin_btn_icon_light_disabled = 2130837599;
// aapt resource value: 0x7f020060
public const int common_google_signin_btn_text_dark_disabled = 2130837600;
public const int common_google_signin_btn_icon_light_focused = 2130837600;
// aapt resource value: 0x7f020061
public const int common_google_signin_btn_text_dark_focused = 2130837601;
public const int common_google_signin_btn_icon_light_normal = 2130837601;
// aapt resource value: 0x7f020062
public const int common_google_signin_btn_text_dark_normal = 2130837602;
public const int common_google_signin_btn_icon_light_pressed = 2130837602;
// aapt resource value: 0x7f020063
public const int common_google_signin_btn_text_dark_pressed = 2130837603;
public const int common_google_signin_btn_text_dark = 2130837603;
// aapt resource value: 0x7f020064
public const int common_google_signin_btn_text_light = 2130837604;
public const int common_google_signin_btn_text_dark_disabled = 2130837604;
// aapt resource value: 0x7f020065
public const int common_google_signin_btn_text_light_disabled = 2130837605;
public const int common_google_signin_btn_text_dark_focused = 2130837605;
// aapt resource value: 0x7f020066
public const int common_google_signin_btn_text_light_focused = 2130837606;
public const int common_google_signin_btn_text_dark_normal = 2130837606;
// aapt resource value: 0x7f020067
public const int common_google_signin_btn_text_light_normal = 2130837607;
public const int common_google_signin_btn_text_dark_pressed = 2130837607;
// aapt resource value: 0x7f020068
public const int common_google_signin_btn_text_light_pressed = 2130837608;
public const int common_google_signin_btn_text_light = 2130837608;
// aapt resource value: 0x7f020069
public const int common_ic_googleplayservices = 2130837609;
public const int common_google_signin_btn_text_light_disabled = 2130837609;
// aapt resource value: 0x7f02006a
public const int common_plus_signin_btn_icon_dark = 2130837610;
public const int common_google_signin_btn_text_light_focused = 2130837610;
// aapt resource value: 0x7f02006b
public const int common_plus_signin_btn_icon_dark_disabled = 2130837611;
public const int common_google_signin_btn_text_light_normal = 2130837611;
// aapt resource value: 0x7f02006c
public const int common_plus_signin_btn_icon_dark_focused = 2130837612;
public const int common_google_signin_btn_text_light_pressed = 2130837612;
// aapt resource value: 0x7f02006d
public const int common_plus_signin_btn_icon_dark_normal = 2130837613;
public const int common_ic_googleplayservices = 2130837613;
// aapt resource value: 0x7f02006e
public const int common_plus_signin_btn_icon_dark_pressed = 2130837614;
public const int common_plus_signin_btn_icon_dark = 2130837614;
// aapt resource value: 0x7f02006f
public const int common_plus_signin_btn_icon_light = 2130837615;
public const int common_plus_signin_btn_icon_dark_disabled = 2130837615;
// aapt resource value: 0x7f020070
public const int common_plus_signin_btn_icon_light_disabled = 2130837616;
public const int common_plus_signin_btn_icon_dark_focused = 2130837616;
// aapt resource value: 0x7f020071
public const int common_plus_signin_btn_icon_light_focused = 2130837617;
public const int common_plus_signin_btn_icon_dark_normal = 2130837617;
// aapt resource value: 0x7f020072
public const int common_plus_signin_btn_icon_light_normal = 2130837618;
public const int common_plus_signin_btn_icon_dark_pressed = 2130837618;
// aapt resource value: 0x7f020073
public const int common_plus_signin_btn_icon_light_pressed = 2130837619;
public const int common_plus_signin_btn_icon_light = 2130837619;
// aapt resource value: 0x7f020074
public const int common_plus_signin_btn_text_dark = 2130837620;
public const int common_plus_signin_btn_icon_light_disabled = 2130837620;
// aapt resource value: 0x7f020075
public const int common_plus_signin_btn_text_dark_disabled = 2130837621;
public const int common_plus_signin_btn_icon_light_focused = 2130837621;
// aapt resource value: 0x7f020076
public const int common_plus_signin_btn_text_dark_focused = 2130837622;
public const int common_plus_signin_btn_icon_light_normal = 2130837622;
// aapt resource value: 0x7f020077
public const int common_plus_signin_btn_text_dark_normal = 2130837623;
public const int common_plus_signin_btn_icon_light_pressed = 2130837623;
// aapt resource value: 0x7f020078
public const int common_plus_signin_btn_text_dark_pressed = 2130837624;
public const int common_plus_signin_btn_text_dark = 2130837624;
// aapt resource value: 0x7f020079
public const int common_plus_signin_btn_text_light = 2130837625;
public const int common_plus_signin_btn_text_dark_disabled = 2130837625;
// aapt resource value: 0x7f02007a
public const int common_plus_signin_btn_text_light_disabled = 2130837626;
public const int common_plus_signin_btn_text_dark_focused = 2130837626;
// aapt resource value: 0x7f02007b
public const int common_plus_signin_btn_text_light_focused = 2130837627;
public const int common_plus_signin_btn_text_dark_normal = 2130837627;
// aapt resource value: 0x7f02007c
public const int common_plus_signin_btn_text_light_normal = 2130837628;
public const int common_plus_signin_btn_text_dark_pressed = 2130837628;
// aapt resource value: 0x7f02007d
public const int common_plus_signin_btn_text_light_pressed = 2130837629;
public const int common_plus_signin_btn_text_light = 2130837629;
// aapt resource value: 0x7f02007e
public const int design_fab_background = 2130837630;
public const int common_plus_signin_btn_text_light_disabled = 2130837630;
// aapt resource value: 0x7f02007f
public const int design_snackbar_background = 2130837631;
public const int common_plus_signin_btn_text_light_focused = 2130837631;
// aapt resource value: 0x7f020080
public const int download = 2130837632;
public const int common_plus_signin_btn_text_light_normal = 2130837632;
// aapt resource value: 0x7f020081
public const int envelope = 2130837633;
public const int common_plus_signin_btn_text_light_pressed = 2130837633;
// aapt resource value: 0x7f020082
public const int eye = 2130837634;
public const int design_fab_background = 2130837634;
// aapt resource value: 0x7f020083
public const int eye_slash = 2130837635;
public const int design_snackbar_background = 2130837635;
// aapt resource value: 0x7f020084
public const int fa_lock = 2130837636;
public const int download = 2130837636;
// aapt resource value: 0x7f020085
public const int fa_lock_selected = 2130837637;
public const int envelope = 2130837637;
// aapt resource value: 0x7f020086
public const int fingerprint = 2130837638;
public const int eye = 2130837638;
// aapt resource value: 0x7f020087
public const int fingerprint_white = 2130837639;
public const int eye_slash = 2130837639;
// aapt resource value: 0x7f020088
public const int folder = 2130837640;
public const int fa_lock = 2130837640;
// aapt resource value: 0x7f020089
public const int globe = 2130837641;
public const int fa_lock_selected = 2130837641;
// aapt resource value: 0x7f02008a
public const int hockeyapp_btn_background = 2130837642;
public const int fingerprint = 2130837642;
// aapt resource value: 0x7f02008b
public const int ic_audiotrack = 2130837643;
public const int fingerprint_white = 2130837643;
// aapt resource value: 0x7f02008c
public const int ic_audiotrack_light = 2130837644;
public const int folder = 2130837644;
// aapt resource value: 0x7f02008d
public const int ic_bluetooth_grey = 2130837645;
public const int globe = 2130837645;
// aapt resource value: 0x7f02008e
public const int ic_bluetooth_white = 2130837646;
public const int hockeyapp_btn_background = 2130837646;
// aapt resource value: 0x7f02008f
public const int ic_cast_dark = 2130837647;
public const int ic_audiotrack = 2130837647;
// aapt resource value: 0x7f020090
public const int ic_cast_disabled_light = 2130837648;
public const int ic_audiotrack_light = 2130837648;
// aapt resource value: 0x7f020091
public const int ic_cast_grey = 2130837649;
public const int ic_bluetooth_grey = 2130837649;
// aapt resource value: 0x7f020092
public const int ic_cast_light = 2130837650;
public const int ic_bluetooth_white = 2130837650;
// aapt resource value: 0x7f020093
public const int ic_cast_off_light = 2130837651;
public const int ic_cast_dark = 2130837651;
// aapt resource value: 0x7f020094
public const int ic_cast_on_0_light = 2130837652;
public const int ic_cast_disabled_light = 2130837652;
// aapt resource value: 0x7f020095
public const int ic_cast_on_1_light = 2130837653;
public const int ic_cast_grey = 2130837653;
// aapt resource value: 0x7f020096
public const int ic_cast_on_2_light = 2130837654;
public const int ic_cast_light = 2130837654;
// aapt resource value: 0x7f020097
public const int ic_cast_on_light = 2130837655;
public const int ic_cast_off_light = 2130837655;
// aapt resource value: 0x7f020098
public const int ic_cast_white = 2130837656;
public const int ic_cast_on_0_light = 2130837656;
// aapt resource value: 0x7f020099
public const int ic_close_dark = 2130837657;
public const int ic_cast_on_1_light = 2130837657;
// aapt resource value: 0x7f02009a
public const int ic_close_light = 2130837658;
public const int ic_cast_on_2_light = 2130837658;
// aapt resource value: 0x7f02009b
public const int ic_collapse = 2130837659;
public const int ic_cast_on_light = 2130837659;
// aapt resource value: 0x7f02009c
public const int ic_collapse_00000 = 2130837660;
public const int ic_cast_white = 2130837660;
// aapt resource value: 0x7f02009d
public const int ic_collapse_00001 = 2130837661;
public const int ic_close_dark = 2130837661;
// aapt resource value: 0x7f02009e
public const int ic_collapse_00002 = 2130837662;
public const int ic_close_light = 2130837662;
// aapt resource value: 0x7f02009f
public const int ic_collapse_00003 = 2130837663;
public const int ic_collapse = 2130837663;
// aapt resource value: 0x7f0200a0
public const int ic_collapse_00004 = 2130837664;
public const int ic_collapse_00000 = 2130837664;
// aapt resource value: 0x7f0200a1
public const int ic_collapse_00005 = 2130837665;
public const int ic_collapse_00001 = 2130837665;
// aapt resource value: 0x7f0200a2
public const int ic_collapse_00006 = 2130837666;
public const int ic_collapse_00002 = 2130837666;
// aapt resource value: 0x7f0200a3
public const int ic_collapse_00007 = 2130837667;
public const int ic_collapse_00003 = 2130837667;
// aapt resource value: 0x7f0200a4
public const int ic_collapse_00008 = 2130837668;
public const int ic_collapse_00004 = 2130837668;
// aapt resource value: 0x7f0200a5
public const int ic_collapse_00009 = 2130837669;
public const int ic_collapse_00005 = 2130837669;
// aapt resource value: 0x7f0200a6
public const int ic_collapse_00010 = 2130837670;
public const int ic_collapse_00006 = 2130837670;
// aapt resource value: 0x7f0200a7
public const int ic_collapse_00011 = 2130837671;
public const int ic_collapse_00007 = 2130837671;
// aapt resource value: 0x7f0200a8
public const int ic_collapse_00012 = 2130837672;
public const int ic_collapse_00008 = 2130837672;
// aapt resource value: 0x7f0200a9
public const int ic_collapse_00013 = 2130837673;
public const int ic_collapse_00009 = 2130837673;
// aapt resource value: 0x7f0200aa
public const int ic_collapse_00014 = 2130837674;
public const int ic_collapse_00010 = 2130837674;
// aapt resource value: 0x7f0200ab
public const int ic_collapse_00015 = 2130837675;
public const int ic_collapse_00011 = 2130837675;
// aapt resource value: 0x7f0200ac
public const int ic_errorstatus = 2130837676;
public const int ic_collapse_00012 = 2130837676;
// aapt resource value: 0x7f0200ad
public const int ic_expand = 2130837677;
public const int ic_collapse_00013 = 2130837677;
// aapt resource value: 0x7f0200ae
public const int ic_expand_00000 = 2130837678;
public const int ic_collapse_00014 = 2130837678;
// aapt resource value: 0x7f0200af
public const int ic_expand_00001 = 2130837679;
public const int ic_collapse_00015 = 2130837679;
// aapt resource value: 0x7f0200b0
public const int ic_expand_00002 = 2130837680;
public const int ic_errorstatus = 2130837680;
// aapt resource value: 0x7f0200b1
public const int ic_expand_00003 = 2130837681;
public const int ic_expand = 2130837681;
// aapt resource value: 0x7f0200b2
public const int ic_expand_00004 = 2130837682;
public const int ic_expand_00000 = 2130837682;
// aapt resource value: 0x7f0200b3
public const int ic_expand_00005 = 2130837683;
public const int ic_expand_00001 = 2130837683;
// aapt resource value: 0x7f0200b4
public const int ic_expand_00006 = 2130837684;
public const int ic_expand_00002 = 2130837684;
// aapt resource value: 0x7f0200b5
public const int ic_expand_00007 = 2130837685;
public const int ic_expand_00003 = 2130837685;
// aapt resource value: 0x7f0200b6
public const int ic_expand_00008 = 2130837686;
public const int ic_expand_00004 = 2130837686;
// aapt resource value: 0x7f0200b7
public const int ic_expand_00009 = 2130837687;
public const int ic_expand_00005 = 2130837687;
// aapt resource value: 0x7f0200b8
public const int ic_expand_00010 = 2130837688;
public const int ic_expand_00006 = 2130837688;
// aapt resource value: 0x7f0200b9
public const int ic_expand_00011 = 2130837689;
public const int ic_expand_00007 = 2130837689;
// aapt resource value: 0x7f0200ba
public const int ic_expand_00012 = 2130837690;
public const int ic_expand_00008 = 2130837690;
// aapt resource value: 0x7f0200bb
public const int ic_expand_00013 = 2130837691;
public const int ic_expand_00009 = 2130837691;
// aapt resource value: 0x7f0200bc
public const int ic_expand_00014 = 2130837692;
public const int ic_expand_00010 = 2130837692;
// aapt resource value: 0x7f0200bd
public const int ic_expand_00015 = 2130837693;
public const int ic_expand_00011 = 2130837693;
// aapt resource value: 0x7f0200be
public const int ic_media_pause = 2130837694;
public const int ic_expand_00012 = 2130837694;
// aapt resource value: 0x7f0200bf
public const int ic_media_play = 2130837695;
public const int ic_expand_00013 = 2130837695;
// aapt resource value: 0x7f0200c0
public const int ic_media_route_disabled_mono_dark = 2130837696;
public const int ic_expand_00014 = 2130837696;
// aapt resource value: 0x7f0200c1
public const int ic_media_route_off_mono_dark = 2130837697;
public const int ic_expand_00015 = 2130837697;
// aapt resource value: 0x7f0200c2
public const int ic_media_route_on_0_mono_dark = 2130837698;
public const int ic_media_pause = 2130837698;
// aapt resource value: 0x7f0200c3
public const int ic_media_route_on_1_mono_dark = 2130837699;
public const int ic_media_play = 2130837699;
// aapt resource value: 0x7f0200c4
public const int ic_media_route_on_2_mono_dark = 2130837700;
public const int ic_media_route_disabled_mono_dark = 2130837700;
// aapt resource value: 0x7f0200c5
public const int ic_media_route_on_mono_dark = 2130837701;
public const int ic_media_route_off_mono_dark = 2130837701;
// aapt resource value: 0x7f0200c6
public const int ic_pause_dark = 2130837702;
public const int ic_media_route_on_0_mono_dark = 2130837702;
// aapt resource value: 0x7f0200c7
public const int ic_pause_light = 2130837703;
public const int ic_media_route_on_1_mono_dark = 2130837703;
// aapt resource value: 0x7f0200c8
public const int ic_play_dark = 2130837704;
public const int ic_media_route_on_2_mono_dark = 2130837704;
// aapt resource value: 0x7f0200c9
public const int ic_play_light = 2130837705;
public const int ic_media_route_on_mono_dark = 2130837705;
// aapt resource value: 0x7f0200ca
public const int ic_speaker_dark = 2130837706;
public const int ic_pause_dark = 2130837706;
// aapt resource value: 0x7f0200cb
public const int ic_speaker_group_dark = 2130837707;
public const int ic_pause_light = 2130837707;
// aapt resource value: 0x7f0200cc
public const int ic_speaker_group_light = 2130837708;
public const int ic_play_dark = 2130837708;
// aapt resource value: 0x7f0200cd
public const int ic_speaker_light = 2130837709;
public const int ic_play_light = 2130837709;
// aapt resource value: 0x7f0200ce
public const int ic_successstatus = 2130837710;
public const int ic_speaker_dark = 2130837710;
// aapt resource value: 0x7f0200cf
public const int ic_tv_dark = 2130837711;
public const int ic_speaker_group_dark = 2130837711;
// aapt resource value: 0x7f0200d0
public const int ic_tv_light = 2130837712;
public const int ic_speaker_group_light = 2130837712;
// aapt resource value: 0x7f0200d1
public const int icon = 2130837713;
public const int ic_speaker_light = 2130837713;
// aapt resource value: 0x7f0200d2
public const int ion_chevron_right = 2130837714;
public const int ic_successstatus = 2130837714;
// aapt resource value: 0x7f0200d3
public const int lightbulb = 2130837715;
public const int ic_tv_dark = 2130837715;
// aapt resource value: 0x7f0200d4
public const int list_selector = 2130837716;
public const int ic_tv_light = 2130837716;
// aapt resource value: 0x7f0200d5
public const int @lock = 2130837717;
public const int icon = 2130837717;
// aapt resource value: 0x7f0200d6
public const int logo = 2130837718;
public const int id = 2130837718;
// aapt resource value: 0x7f0200d7
public const int more = 2130837719;
public const int ion_chevron_right = 2130837719;
// aapt resource value: 0x7f0200d8
public const int mr_dialog_material_background_dark = 2130837720;
public const int launch = 2130837720;
// aapt resource value: 0x7f0200d9
public const int mr_dialog_material_background_light = 2130837721;
public const int lightbulb = 2130837721;
// aapt resource value: 0x7f0200da
public const int mr_ic_audiotrack_light = 2130837722;
public const int list_selector = 2130837722;
// aapt resource value: 0x7f0200db
public const int mr_ic_cast_dark = 2130837723;
public const int @lock = 2130837723;
// aapt resource value: 0x7f0200dc
public const int mr_ic_cast_light = 2130837724;
public const int login = 2130837724;
// aapt resource value: 0x7f0200dd
public const int mr_ic_close_dark = 2130837725;
public const int logo = 2130837725;
// aapt resource value: 0x7f0200de
public const int mr_ic_close_light = 2130837726;
public const int more = 2130837726;
// aapt resource value: 0x7f0200df
public const int mr_ic_media_route_connecting_mono_dark = 2130837727;
public const int mr_dialog_material_background_dark = 2130837727;
// aapt resource value: 0x7f0200e0
public const int mr_ic_media_route_connecting_mono_light = 2130837728;
public const int mr_dialog_material_background_light = 2130837728;
// aapt resource value: 0x7f0200e1
public const int mr_ic_media_route_mono_dark = 2130837729;
public const int mr_ic_audiotrack_light = 2130837729;
// aapt resource value: 0x7f0200e2
public const int mr_ic_media_route_mono_light = 2130837730;
public const int mr_ic_cast_dark = 2130837730;
// aapt resource value: 0x7f0200e3
public const int mr_ic_pause_dark = 2130837731;
public const int mr_ic_cast_light = 2130837731;
// aapt resource value: 0x7f0200e4
public const int mr_ic_pause_light = 2130837732;
public const int mr_ic_close_dark = 2130837732;
// aapt resource value: 0x7f0200e5
public const int mr_ic_play_dark = 2130837733;
public const int mr_ic_close_light = 2130837733;
// aapt resource value: 0x7f0200e6
public const int mr_ic_play_light = 2130837734;
public const int mr_ic_media_route_connecting_mono_dark = 2130837734;
// aapt resource value: 0x7f0200e7
public const int notification_sm = 2130837735;
// aapt resource value: 0x7f0200fa
public const int notification_template_icon_bg = 2130837754;
public const int mr_ic_media_route_connecting_mono_light = 2130837735;
// aapt resource value: 0x7f0200e8
public const int paperclip = 2130837736;
public const int mr_ic_media_route_mono_dark = 2130837736;
// aapt resource value: 0x7f0200e9
public const int plus = 2130837737;
public const int mr_ic_media_route_mono_light = 2130837737;
// aapt resource value: 0x7f0200ea
public const int refresh = 2130837738;
public const int mr_ic_pause_dark = 2130837738;
// aapt resource value: 0x7f0200eb
public const int roundedbg = 2130837739;
public const int mr_ic_pause_light = 2130837739;
// aapt resource value: 0x7f0200ec
public const int roundedbgdark = 2130837740;
public const int mr_ic_play_dark = 2130837740;
// aapt resource value: 0x7f0200ed
public const int search = 2130837741;
public const int mr_ic_play_light = 2130837741;
// aapt resource value: 0x7f0200ee
public const int share = 2130837742;
public const int note = 2130837742;
// aapt resource value: 0x7f0200ef
public const int share_tools = 2130837743;
public const int notification_sm = 2130837743;
// aapt resource value: 0x7f020102
public const int notification_template_icon_bg = 2130837762;
// aapt resource value: 0x7f0200f0
public const int shield = 2130837744;
public const int paperclip = 2130837744;
// aapt resource value: 0x7f0200f1
public const int splash_screen = 2130837745;
public const int plus = 2130837745;
// aapt resource value: 0x7f0200f2
public const int star = 2130837746;
public const int refresh = 2130837746;
// aapt resource value: 0x7f0200f3
public const int star_selected = 2130837747;
public const int roundedbg = 2130837747;
// aapt resource value: 0x7f0200f4
public const int tools = 2130837748;
public const int roundedbgdark = 2130837748;
// aapt resource value: 0x7f0200f5
public const int tools_selected = 2130837749;
public const int search = 2130837749;
// aapt resource value: 0x7f0200f6
public const int trash = 2130837750;
public const int share = 2130837750;
// aapt resource value: 0x7f0200f7
public const int upload = 2130837751;
public const int share_tools = 2130837751;
// aapt resource value: 0x7f0200f8
public const int user = 2130837752;
public const int shield = 2130837752;
// aapt resource value: 0x7f0200f9
public const int yubikey = 2130837753;
public const int splash_screen = 2130837753;
// aapt resource value: 0x7f0200fa
public const int star = 2130837754;
// aapt resource value: 0x7f0200fb
public const int star_selected = 2130837755;
// aapt resource value: 0x7f0200fc
public const int tools = 2130837756;
// aapt resource value: 0x7f0200fd
public const int tools_selected = 2130837757;
// aapt resource value: 0x7f0200fe
public const int trash = 2130837758;
// aapt resource value: 0x7f0200ff
public const int upload = 2130837759;
// aapt resource value: 0x7f020100
public const int user = 2130837760;
// aapt resource value: 0x7f020101
public const int yubikey = 2130837761;
static Drawable()
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 1009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

View File

@@ -0,0 +1,560 @@
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.OS;
using Bit.App.Abstractions;
using Bit.App.Utilities;
using System.Threading;
using Xamarin.Forms;
using Android.Gms.Gcm.Iid;
using Android.Gms.Gcm;
using Java.IO;
using Newtonsoft.Json.Linq;
using Android.Support.V4.App;
using Android.Media;
using Newtonsoft.Json;
namespace Bit.Android.Services
{
public class AndroidPushNotificationService : IPushNotificationService
{
private const string GcmPreferencesKey = "GCMPreferences";
private const string Tag = "PushNotification";
internal static IPushNotificationListener Listener { get; set; }
public string Token => GetRegistrationId();
public void Register()
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - Register - Registering push notifications");
if(string.IsNullOrEmpty(CrossPushNotification.SenderId))
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - Register - SenderId is missing.");
CrossPushNotification.PushNotificationListener.OnError(
$"{PushNotificationContants.DomainName} - Register - Sender Id is missing.", Device.Android);
}
else
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - Register - Registering for Push Notifications");
ThreadPool.QueueUserWorkItem(state =>
{
try
{
Intent intent = new Intent(global::Android.App.Application.Context,
typeof(PushNotificationRegistrationIntentService));
global::Android.App.Application.Context.StartService(intent);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine($"{Tag} - Error : {ex.Message}");
CrossPushNotification.PushNotificationListener.OnError($"{Tag} - Register - {ex.Message}",
Device.Android);
}
});
}
}
public void Unregister()
{
ThreadPool.QueueUserWorkItem(state =>
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - Unregister - Unregistering push notifications");
try
{
var instanceID = InstanceID.GetInstance(global::Android.App.Application.Context);
instanceID.DeleteToken(CrossPushNotification.SenderId, GoogleCloudMessaging.InstanceIdScope);
CrossPushNotification.PushNotificationListener.OnUnregistered(Device.Android);
StoreRegistrationId(global::Android.App.Application.Context, string.Empty);
}
catch(IOException ex)
{
System.Diagnostics.Debug.WriteLine($"{Tag} - Error : {ex.Message}");
CrossPushNotification.PushNotificationListener.OnError(
$"{Tag} - Unregister - {ex.Message}", Device.Android);
}
});
}
private string GetRegistrationId()
{
var context = global::Android.App.Application.Context;
var prefs = GetGCMPreferences(context);
var registrationId = prefs.GetString(PushNotificationContants.Token, string.Empty);
if(string.IsNullOrEmpty(registrationId))
{
System.Diagnostics.Debug.WriteLine($"{PushNotificationContants.DomainName} - Registration not found.");
return string.Empty;
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing registration ID is not guaranteed to work with
// the new app version.
var registeredVersion = prefs.GetInt(PushNotificationContants.AppVersion, Java.Lang.Integer.MinValue);
var currentVersion = GetAppVersion(context);
if(registeredVersion != currentVersion)
{
System.Diagnostics.Debug.WriteLine($"{PushNotificationContants.DomainName} - App version changed.");
return string.Empty;
}
return registrationId;
}
internal static ISharedPreferences GetGCMPreferences(Context context)
{
return context.GetSharedPreferences(GcmPreferencesKey, FileCreationMode.Private);
}
internal static int GetAppVersion(Context context)
{
try
{
var packageInfo = context.PackageManager.GetPackageInfo(context.PackageName, 0);
return packageInfo.VersionCode;
}
catch(global::Android.Content.PM.PackageManager.NameNotFoundException e)
{
// should never happen
throw new Java.Lang.RuntimeException("Could not get package name: " + e);
}
}
internal static void StoreRegistrationId(Context context, string regId)
{
var prefs = GetGCMPreferences(context);
var appVersion = GetAppVersion(context);
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - Saving token on app version {appVersion}");
var editor = prefs.Edit();
editor.PutString(PushNotificationContants.Token, regId);
editor.PutInt(PushNotificationContants.AppVersion, appVersion);
editor.Commit();
}
}
[Service(Exported = false)]
public class PushNotificationRegistrationIntentService : IntentService
{
private const string Tag = "PushNotificationRegistationIntentService";
private string[] _topics = new string[] { "global" };
private readonly object _syncLock = new object();
protected override void OnHandleIntent(Intent intent)
{
try
{
var extras = intent.Extras;
lock(_syncLock)
{
var instanceID = InstanceID.GetInstance(global::Android.App.Application.Context);
var token = instanceID.GetToken(CrossPushNotification.SenderId,
GoogleCloudMessaging.InstanceIdScope, null);
CrossPushNotification.PushNotificationListener.OnRegistered(token, Device.Android);
AndroidPushNotificationService.StoreRegistrationId(global::Android.App.Application.Context, token);
SubscribeTopics(token);
System.Diagnostics.Debug.WriteLine($"{token} - Device registered, registration ID={Tag}");
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine($"{ex.Message} - Error : {Tag}");
CrossPushNotification.PushNotificationListener.OnError(
$"{ex.ToString()} - Register - {Tag}", Device.Android);
}
}
private void SubscribeTopics(string token)
{
var pubSub = GcmPubSub.GetInstance(this);
foreach(var topic in _topics)
{
pubSub.Subscribe(token, "/topics/" + topic, null);
}
}
}
[Service(Exported = false)]
[IntentFilter(new string[] { "com.google.android.gms.iid.InstanceID" })]
public class PushNotificationInstanceIDListenerService : InstanceIDListenerService
{
private const string Tag = "PushNotificationInstanceIDLS";
public override void OnTokenRefresh()
{
base.OnTokenRefresh();
ThreadPool.QueueUserWorkItem(state =>
{
try
{
var intent = new Intent(global::Android.App.Application.Context,
typeof(PushNotificationRegistrationIntentService));
global::Android.App.Application.Context.StartService(intent);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine($"{ex.Message} - Error : {Tag}");
CrossPushNotification.PushNotificationListener.OnError(
$"{ex.ToString()} - Register - {Tag}", Device.Android);
}
});
}
}
[Service(Exported = false, Name = "pushnotification.plugin.PushNotificationGcmListener")]
[IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" },
Categories = new string[] { "com.x8bit.bitwarden" })]
public class PushNotificationGcmListener : GcmListenerService
{
public override void OnMessageReceived(string from, Bundle extras)
{
if(extras != null && !extras.IsEmpty)
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - GCM Listener - Push Received");
var parameters = new Dictionary<string, object>();
var values = new JObject();
foreach(var key in extras.KeySet())
{
var value = extras.Get(key).ToString();
if(ValidateJSON(value))
{
values.Add(key, JObject.Parse(value));
}
else
{
values.Add(key, value);
}
parameters.Add(key, extras.Get(key));
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - GCM Listener - Push Params {key} : {extras.Get(key)}");
}
var context = global::Android.App.Application.Context;
CrossPushNotification.PushNotificationListener.OnMessage(values, Device.Android);
try
{
var notifyId = 0;
var title = context.ApplicationInfo.LoadLabel(context.PackageManager);
var message = string.Empty;
var tag = string.Empty;
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTextKey) &&
parameters.ContainsKey(CrossPushNotification.NotificationContentTextKey))
{
message = parameters[CrossPushNotification.NotificationContentTextKey].ToString();
}
else if(parameters.ContainsKey(PushNotificationContants.Alert))
{
message = parameters[PushNotificationContants.Alert].ToString();
}
else if(parameters.ContainsKey(PushNotificationContants.Message))
{
message = parameters[PushNotificationContants.Message].ToString();
}
else if(parameters.ContainsKey(PushNotificationContants.Subtitle))
{
message = parameters[PushNotificationContants.Subtitle].ToString();
}
else if(parameters.ContainsKey(PushNotificationContants.Text))
{
message = parameters[PushNotificationContants.Text].ToString();
}
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTitleKey) &&
parameters.ContainsKey(CrossPushNotification.NotificationContentTitleKey))
{
title = parameters[CrossPushNotification.NotificationContentTitleKey].ToString();
}
else if(parameters.ContainsKey(PushNotificationContants.Title))
{
if(!string.IsNullOrEmpty(message))
{
title = parameters[PushNotificationContants.Title].ToString();
}
else
{
message = parameters[PushNotificationContants.Title].ToString();
}
}
if(string.IsNullOrEmpty(message))
{
var data = (
!string.IsNullOrEmpty(CrossPushNotification.NotificationContentDataKey) &&
values[CrossPushNotification.NotificationContentDataKey] != null) ?
values[CrossPushNotification.NotificationContentDataKey] :
values[PushNotificationContants.Data];
if(data != null)
{
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTextKey) &&
data[CrossPushNotification.NotificationContentTextKey] != null)
{
message = data[CrossPushNotification.NotificationContentTextKey].ToString();
}
else if(data[PushNotificationContants.Alert] != null)
{
message = data[PushNotificationContants.Alert].ToString();
}
else if(data[PushNotificationContants.Message] != null)
{
message = data[PushNotificationContants.Message].ToString();
}
else if(data[PushNotificationContants.Subtitle] != null)
{
message = data[PushNotificationContants.Subtitle].ToString();
}
else if(data[PushNotificationContants.Text] != null)
{
message = data[PushNotificationContants.Text].ToString();
}
if(!string.IsNullOrEmpty(CrossPushNotification.NotificationContentTitleKey) &&
data[CrossPushNotification.NotificationContentTitleKey] != null)
{
title = data[CrossPushNotification.NotificationContentTitleKey].ToString();
}
else if(data[PushNotificationContants.Title] != null)
{
if(!string.IsNullOrEmpty(message))
{
title = data[PushNotificationContants.Title].ToString();
}
else
{
message = data[PushNotificationContants.Title].ToString();
}
}
}
}
if(parameters.ContainsKey(PushNotificationContants.Id))
{
var str = parameters[PushNotificationContants.Id].ToString();
try
{
notifyId = Convert.ToInt32(str);
}
catch(Exception)
{
// Keep the default value of zero for the notify_id, but log the conversion problem.
System.Diagnostics.Debug.WriteLine("Failed to convert {0} to an integer", str);
}
}
if(parameters.ContainsKey(PushNotificationContants.Tag))
{
tag = parameters[PushNotificationContants.Tag].ToString();
}
if(!parameters.ContainsKey(PushNotificationContants.Silent) ||
!System.Boolean.Parse(parameters[PushNotificationContants.Silent].ToString()))
{
if(CrossPushNotification.PushNotificationListener.ShouldShowNotification())
{
CreateNotification(title, message, notifyId, tag, extras);
}
}
}
catch(Java.Lang.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
catch(Exception ex1)
{
System.Diagnostics.Debug.WriteLine(ex1.ToString());
}
}
}
private void CreateNotification(string title, string message, int notifyId, string tag, Bundle extras)
{
System.Diagnostics.Debug.WriteLine(
$"{PushNotificationContants.DomainName} - PushNotification - Message {title} : {message}");
NotificationCompat.Builder builder = null;
var context = global::Android.App.Application.Context;
if(CrossPushNotification.SoundUri == null)
{
CrossPushNotification.SoundUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);
}
try
{
if(CrossPushNotification.IconResource == 0)
{
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
}
else
{
var name = context.Resources.GetResourceName(CrossPushNotification.IconResource);
if(name == null)
{
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
}
}
}
catch(global::Android.Content.Res.Resources.NotFoundException ex)
{
CrossPushNotification.IconResource = context.ApplicationInfo.Icon;
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
var resultIntent = context.PackageManager.GetLaunchIntentForPackage(context.PackageName);
if(extras != null)
{
resultIntent.PutExtras(extras);
}
// Create a PendingIntent; we're only using one PendingIntent (ID = 0):
const int pendingIntentId = 0;
var resultPendingIntent = PendingIntent.GetActivity(context, pendingIntentId,
resultIntent, PendingIntentFlags.OneShot);
// Build the notification
builder = new NotificationCompat.Builder(context)
.SetAutoCancel(true) // dismiss the notification from the notification area when the user clicks on it
.SetContentIntent(resultPendingIntent) // start up this activity when the user clicks the intent.
.SetContentTitle(title) // Set the title
.SetSound(CrossPushNotification.SoundUri)
.SetSmallIcon(CrossPushNotification.IconResource) // This is the icon to display
.SetContentText(message); // the message to display.
if(Build.VERSION.SdkInt >= BuildVersionCodes.JellyBean)
{
// Using BigText notification style to support long message
var style = new NotificationCompat.BigTextStyle();
style.BigText(message);
builder.SetStyle(style);
}
var notificationManager = (NotificationManager)context.GetSystemService(NotificationService);
notificationManager.Notify(tag, notifyId, builder.Build());
}
private static bool ValidateJSON(string s)
{
try
{
JObject.Parse(s);
return true;
}
catch(JsonReaderException ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
return false;
}
}
}
[BroadcastReceiver(Exported = true, Permission = "com.google.android.c2dm.permission.SEND")]
[IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" },
Categories = new string[] { "com.x8bit.bitwarden" })]
public class PushNotificationsReceiver : GcmReceiver
{ }
[Service]
public class AndroidPushService : Service
{
public override void OnCreate()
{
base.OnCreate();
System.Diagnostics.Debug.WriteLine("Push Notification Service - Created");
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
System.Diagnostics.Debug.WriteLine("Push Notification Service - Started");
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
System.Diagnostics.Debug.WriteLine("Push Notification Service - Binded");
return null;
}
public override void OnDestroy()
{
System.Diagnostics.Debug.WriteLine("Push Notification Service - Destroyed");
base.OnDestroy();
}
}
internal class CrossPushNotification
{
private static Lazy<IPushNotificationService> Implementation = new Lazy<IPushNotificationService>(
() => new AndroidPushNotificationService(),
LazyThreadSafetyMode.PublicationOnly);
public static bool IsInitialized => PushNotificationListener != null;
public static IPushNotificationListener PushNotificationListener { get; private set; }
public static string SenderId { get; set; }
public static string NotificationContentTitleKey { get; set; }
public static string NotificationContentTextKey { get; set; }
public static string NotificationContentDataKey { get; set; }
public static int IconResource { get; set; }
public static global::Android.Net.Uri SoundUri { get; set; }
public static void Initialize<T>(T listener, string senderId) where T : IPushNotificationListener
{
SenderId = senderId;
if(PushNotificationListener == null)
{
PushNotificationListener = listener;
System.Diagnostics.Debug.WriteLine("PushNotification plugin initialized.");
}
else
{
System.Diagnostics.Debug.WriteLine("PushNotification plugin already initialized.");
}
}
public static void Initialize<T>(string senderId) where T : IPushNotificationListener, new()
{
Initialize(new T(), senderId);
}
public static IPushNotificationService Current
{
get
{
if(!IsInitialized)
{
throw new Exception("Not initialized.");
}
var ret = Implementation.Value;
if(ret == null)
{
throw new Exception("Not in PCL");
}
return ret;
}
}
}
}

View File

@@ -19,7 +19,7 @@
<package id="Plugin.Fingerprint" version="1.4.5" targetFramework="monoandroid71" />
<package id="SimpleInjector" version="4.0.8" targetFramework="monoandroid71" />
<package id="Splat" version="1.6.2" targetFramework="monoandroid60" />
<package id="sqlite-net-pcl" version="1.4.118" targetFramework="monoandroid71" />
<package id="sqlite-net-pcl" version="1.5.166-beta" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.lib.e_sqlite3.android" version="1.1.8" targetFramework="monoandroid71" />
@@ -69,7 +69,6 @@
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="monoandroid71" />
<package id="Validation" version="2.3.7" targetFramework="monoandroid60" />
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="monoandroid71" />
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="monoandroid60" developmentDependency="true" />
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />

View File

@@ -7,7 +7,7 @@ namespace Bit.App.Abstractions
{
public interface IAttachmentRepository : IRepository<AttachmentData, string>
{
Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId);
Task<IEnumerable<AttachmentData>> GetAllByCipherIdAsync(string cipherId);
Task<IEnumerable<AttachmentData>> GetAllByUserIdAsync(string userId);
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Data;
namespace Bit.App.Abstractions
{
public interface ICipherRepository : IRepository<CipherData, string>
{
Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View File

@@ -8,6 +8,6 @@ namespace Bit.App.Abstractions
public interface IFolderRepository : IRepository<FolderData, string>
{
Task<IEnumerable<FolderData>> GetAllByUserIdAsync(string userId);
Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate);
Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate);
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Data;
namespace Bit.App.Abstractions
{
public interface ILoginRepository : IRepository<LoginData, string>
{
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View File

@@ -9,10 +9,12 @@ namespace Bit.App.Abstractions
DateTime LastCacheClear { get; set; }
bool AutofillPersistNotification { get; set; }
bool AutofillPasswordField { get; set; }
bool DisableWebsiteIcons { get; set; }
string SecurityStamp { get; set; }
string BaseUrl { get; set; }
string WebVaultUrl { get; set; }
string ApiUrl { get; set; }
string IdentityUrl { get; set; }
string IconsUrl { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Models.Api;
using System;
namespace Bit.App.Abstractions
{
public interface ICipherService
{
Task<Cipher> GetByIdAsync(string id);
Task<IEnumerable<Cipher>> GetAllAsync();
Task<IEnumerable<Cipher>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString);
Task<ApiResult<CipherResponse>> SaveAsync(Cipher cipher);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Cipher cipher, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(Cipher cipher, string attachmentId);
}
}

View File

@@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Models.Api;
using System;
namespace Bit.App.Abstractions
{
public interface ILoginService
{
Task<Login> GetByIdAsync(string id);
Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString);
Task<ApiResult<CipherResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(Login login, string attachmentId);
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.App.Abstractions
{
public interface IPushNotificationService
{
string Token { get; }
void Register();
void Unregister();
}
}

View File

@@ -0,0 +1,13 @@
using Newtonsoft.Json.Linq;
namespace Bit.App.Abstractions
{
public interface IPushNotificationListener
{
void OnMessage(JObject values, string device);
void OnRegistered(string token, string device);
void OnUnregistered(string device);
void OnError(string message, string device);
bool ShouldShowNotification();
}
}

View File

@@ -9,7 +9,7 @@ namespace Bit.App.Abstractions
Task<bool> SyncCipherAsync(string id);
Task<bool> SyncFolderAsync(string id);
Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate);
Task<bool> SyncDeleteLoginAsync(string id);
Task<bool> SyncDeleteCipherAsync(string id);
Task<bool> SyncSettingsAsync();
Task<bool> SyncProfileAsync();
Task<bool> FullSyncAsync(bool forceSync = false);

View File

@@ -68,7 +68,7 @@ namespace Bit.App
if(authService.IsAuthenticated && _uri != null)
{
MainPage = new ExtendedNavigationPage(new VaultAutofillListLoginsPage(_uri));
MainPage = new ExtendedNavigationPage(new VaultAutofillListCiphersPage(_uri));
}
else if(authService.IsAuthenticated)
{
@@ -103,7 +103,7 @@ namespace Bit.App
if(string.IsNullOrWhiteSpace(_uri))
{
Helpers.PerformUpdateTasks(_settings, _appInfoService, _databaseService);
Helpers.PerformUpdateTasks(_settings, _appInfoService, _databaseService, _syncService);
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
}

View File

@@ -44,6 +44,8 @@
<Compile Include="Abstractions\Repositories\ISettingsRepository.cs" />
<Compile Include="Abstractions\Services\IAppSettingsService.cs" />
<Compile Include="Abstractions\Services\IMemoryService.cs" />
<Compile Include="Abstractions\Services\IPushNotificationListener.cs" />
<Compile Include="Abstractions\Services\IPushNotification.cs" />
<Compile Include="Abstractions\Services\ISettingsService.cs" />
<Compile Include="Abstractions\Services\ITokenService.cs" />
<Compile Include="Abstractions\Services\IHttpService.cs" />
@@ -56,7 +58,7 @@
<Compile Include="Abstractions\Services\IKeyDerivationService.cs" />
<Compile Include="Abstractions\Services\ILogService.cs" />
<Compile Include="Abstractions\Services\IReflectionService.cs" />
<Compile Include="Abstractions\Services\ILoginService.cs" />
<Compile Include="Abstractions\Services\ICipherService.cs" />
<Compile Include="Abstractions\Services\IFolderService.cs" />
<Compile Include="App.cs" />
<Compile Include="Abstractions\Services\ISecureStorageService.cs" />
@@ -87,7 +89,9 @@
<Compile Include="Controls\PinControl.cs" />
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
<Compile Include="Controls\VaultListViewCell.cs" />
<Compile Include="Enums\DeviceType.cs" />
<Compile Include="Enums\FieldType.cs" />
<Compile Include="Enums\SecureNoteType.cs" />
<Compile Include="Enums\TwoFactorProviderType.cs" />
<Compile Include="Enums\EncryptionType.cs" />
<Compile Include="Enums\OrganizationUserType.cs" />
@@ -101,6 +105,9 @@
<Compile Include="Models\Api\ApiResult.cs" />
<Compile Include="Models\Api\CipherDataModel.cs" />
<Compile Include="Models\Api\FieldDataModel.cs" />
<Compile Include="Models\Api\CardDataModel.cs" />
<Compile Include="Models\Api\IdentityDataModel.cs" />
<Compile Include="Models\Api\SecureNoteDataModel.cs" />
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
<Compile Include="Models\Api\Request\FolderRequest.cs" />
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
@@ -122,16 +129,20 @@
<Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" />
<Compile Include="Models\Card.cs" />
<Compile Include="Models\CipherString.cs" />
<Compile Include="Models\Data\AttachmentData.cs" />
<Compile Include="Models\Attachment.cs" />
<Compile Include="Models\Field.cs" />
<Compile Include="Models\Identity.cs" />
<Compile Include="Models\Login.cs" />
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
<Compile Include="Models\SecureNote.cs" />
<Compile Include="Models\SymmetricCryptoKey.cs" />
<Compile Include="Models\Data\SettingsData.cs" />
<Compile Include="Models\Data\FolderData.cs" />
<Compile Include="Abstractions\IDataObject.cs" />
<Compile Include="Models\Data\LoginData.cs" />
<Compile Include="Models\Data\CipherData.cs" />
<Compile Include="Models\DomainName.cs" />
<Compile Include="Models\Folder.cs" />
<Compile Include="Models\LoginResult.cs" />
@@ -141,8 +152,8 @@
<Compile Include="Models\Page\PasswordGeneratorPageModel.cs" />
<Compile Include="Models\PlatformCulture.cs" />
<Compile Include="Models\PushNotification.cs" />
<Compile Include="Models\Login.cs" />
<Compile Include="Models\Page\VaultViewLoginPageModel.cs" />
<Compile Include="Models\Cipher.cs" />
<Compile Include="Models\Page\VaultViewCipherPageModel.cs" />
<Compile Include="Pages\HomePage.cs" />
<Compile Include="Pages\Lock\BaseLockPage.cs" />
<Compile Include="Pages\Lock\LockPasswordPage.cs" />
@@ -169,10 +180,10 @@
<Compile Include="Pages\Settings\SettingsPage.cs" />
<Compile Include="Pages\Settings\SettingsListFoldersPage.cs" />
<Compile Include="Pages\Vault\VaultCustomFieldsPage.cs" />
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
<Compile Include="Pages\Vault\VaultAutofillListCiphersPage.cs" />
<Compile Include="Pages\Vault\VaultAttachmentsPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Abstractions\Repositories\ICipherRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" />
<Compile Include="Repositories\SyncApiRepository.cs" />
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
@@ -189,7 +200,7 @@
<Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" />
<Compile Include="Repositories\SettingsRepository.cs" />
<Compile Include="Repositories\FolderApiRepository.cs" />
<Compile Include="Repositories\LoginRepository.cs" />
<Compile Include="Repositories\CipherRepository.cs" />
<Compile Include="Repositories\FolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IRepository.cs" />
@@ -203,6 +214,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.da.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.de.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.de.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -337,16 +353,16 @@
<Compile Include="Abstractions\Services\ISyncService.cs" />
<Compile Include="Abstractions\Services\IPasswordGenerationService.cs" />
<Compile Include="Services\SyncService.cs" />
<Compile Include="Services\LoginService.cs" />
<Compile Include="Services\CipherService.cs" />
<Compile Include="Services\AuthService.cs" />
<Compile Include="Services\CryptoService.cs" />
<Compile Include="Models\Page\VaultListPageModel.cs" />
<Compile Include="Pages\LoginPage.cs" />
<Compile Include="Pages\Settings\SettingsAddFolderPage.cs" />
<Compile Include="Pages\Vault\VaultAddLoginPage.cs" />
<Compile Include="Pages\Vault\VaultViewLoginPage.cs" />
<Compile Include="Pages\Vault\VaultEditLoginPage.cs" />
<Compile Include="Pages\Vault\VaultListLoginsPage.cs" />
<Compile Include="Pages\Vault\VaultAddCipherPage.cs" />
<Compile Include="Pages\Vault\VaultViewCipherPage.cs" />
<Compile Include="Pages\Vault\VaultEditCipherPage.cs" />
<Compile Include="Pages\Vault\VaultListCiphersPage.cs" />
<Compile Include="Services\PasswordGenerationService.cs" />
<Compile Include="Utilities\Base32.cs" />
<Compile Include="Utilities\Crypto.cs" />
@@ -355,6 +371,7 @@
<Compile Include="Utilities\Extentions.cs" />
<Compile Include="Utilities\ExtendedObservableCollection.cs" />
<Compile Include="Utilities\ApiHttpClient.cs" />
<Compile Include="Utilities\PushNotificationContants.cs" />
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
</ItemGroup>
<ItemGroup>
@@ -370,6 +387,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.de.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.de.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.es.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
@@ -528,20 +549,12 @@
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\netstandard1.0\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PushNotification.Plugin.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite-net, Version=1.4.118.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.4.118\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
<Reference Include="SQLite-net, Version=1.5.166.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.5.166-beta\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_green.dll</HintPath>

View File

@@ -9,6 +9,7 @@
public const string SettingPinUnlockOn = "setting:pinUnlockOn";
public const string SettingLockSeconds = "setting:lockSeconds";
public const string SettingGaOptOut = "setting:googleAnalyticsOptOut";
public const string SettingDisableWebsiteIcons = "setting:disableWebsiteIcons";
public const string SettingDisableTotpCopy = "setting:disableAutoCopyTotp";
public const string AutofillPersistNotification = "setting:persistNotification";
public const string AutofillPasswordField = "setting:autofillPasswordField";
@@ -39,6 +40,7 @@
public const string WebVaultUrl = "other:webVaultUrl";
public const string ApiUrl = "other:apiUrl";
public const string IdentityUrl = "other:identityUrl";
public const string IconsUrl = "other:iconsUrl";
public const int SelectFileRequestCode = 42;
public const int SelectFilePermissionRequestCode = 43;

View File

@@ -43,7 +43,7 @@ namespace Bit.App.Controls
protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{
if(!VerticalOptions.Expands)
if(!VerticalOptions.Expands && Device.RuntimePlatform != Device.Windows)
{
var reflectionService = Resolver.Resolve<IReflectionService>();
var baseBaseOnSizeRequest = reflectionService.GetVisualElementOnSizeRequest(this);

View File

@@ -21,8 +21,6 @@ namespace Bit.App.Controls
Thickness? containerPadding = null,
bool useButton = false)
{
_nextElement = nextElement;
if(!useLabelAsPlaceholder)
{
Label = new Label
@@ -50,10 +48,7 @@ namespace Bit.App.Controls
Entry.Placeholder = labelText;
}
if(nextElement != null)
{
Entry.ReturnType = Enums.ReturnType.Next;
}
NextElement = nextElement;
var imageStackLayout = new StackLayout
{
@@ -129,6 +124,7 @@ namespace Bit.App.Controls
{
Button.Padding = new Thickness(0);
Button.BackgroundColor = Color.Transparent;
Button.WidthRequest = 40;
}
}
@@ -138,6 +134,22 @@ namespace Bit.App.Controls
public Label Label { get; private set; }
public ExtendedEntry Entry { get; private set; }
public ExtendedButton Button { get; private set; }
public VisualElement NextElement
{
get => _nextElement;
set
{
_nextElement = value;
if(_nextElement != null && Entry != null)
{
Entry.ReturnType = Enums.ReturnType.Next;
}
else if(Entry != null)
{
Entry.ReturnType = null;
}
}
}
public void InitEvents()
{
@@ -150,7 +162,7 @@ namespace Bit.App.Controls
{
_tgr.Tapped += Tgr_Tapped;
}
Tapped += FormEntryCell_Tapped;
}

View File

@@ -1,4 +1,5 @@
using FFImageLoading.Forms;
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
@@ -7,6 +8,17 @@ namespace Bit.App.Controls
{
public LabeledDetailCell()
{
Icon = new CachedImage
{
WidthRequest = 20,
HeightRequest = 20,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
ErrorPlaceholder = "login.png",
CacheDuration = TimeSpan.FromDays(30),
BitmapOptimizations = true
};
Label = new Label
{
LineBreakMode = LineBreakMode.TailTruncation,
@@ -45,21 +57,24 @@ namespace Bit.App.Controls
{
ColumnSpacing = 0,
RowSpacing = 0,
Padding = new Thickness(15, 3, 0, 3)
Padding = new Thickness(3, 3, 0, 3)
};
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(40, GridUnitType.Absolute) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(60, GridUnitType.Absolute) });
grid.Children.Add(Label, 0, 0);
grid.Children.Add(Detail, 0, 1);
grid.Children.Add(LabelIcon, 1, 0);
grid.Children.Add(LabelIcon2, 2, 0);
grid.Children.Add(Button, 3, 0);
Grid.SetColumnSpan(Detail, 3);
grid.Children.Add(Icon, 0, 0);
grid.Children.Add(Label, 1, 0);
grid.Children.Add(Detail, 1, 1);
grid.Children.Add(LabelIcon, 2, 0);
grid.Children.Add(LabelIcon2, 3, 0);
grid.Children.Add(Button, 4, 0);
Grid.SetRowSpan(Icon, 2);
Grid.SetRowSpan(Button, 2);
Grid.SetColumnSpan(Detail, 3);
if(Device.RuntimePlatform == Device.Android)
{
@@ -69,6 +84,7 @@ namespace Bit.App.Controls
View = grid;
}
public CachedImage Icon { get; private set; }
public Label Label { get; private set; }
public Label Detail { get; private set; }
public CachedImage LabelIcon { get; private set; }

View File

@@ -7,8 +7,8 @@ namespace Bit.App.Controls
public LabeledValueCell(
string labelText = null,
string valueText = null,
string button1Text = null,
string button2Text = null,
string button1Image = null,
string button2Image = null,
string subText = null)
{
var containerStackLayout = new StackLayout
@@ -69,11 +69,11 @@ namespace Bit.App.Controls
buttonStackLayout.Children.Add(Sub);
}
if(button1Text != null)
if(button1Image != null)
{
Button1 = new ExtendedButton
{
Text = button1Text,
Image = button1Image,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center,
Margin = new Thickness(0)
@@ -82,11 +82,11 @@ namespace Bit.App.Controls
buttonStackLayout.Children.Add(Button1);
}
if(button2Text != null)
if(button2Image != null)
{
Button2 = new ExtendedButton
{
Text = button2Text,
Image = button2Image,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center,
Margin = new Thickness(0)
@@ -103,11 +103,13 @@ namespace Bit.App.Controls
{
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();

View File

@@ -1,4 +1,5 @@
using Bit.App.Models.Page;
using FFImageLoading.Forms;
using System;
using Xamarin.Forms;
@@ -6,31 +7,46 @@ namespace Bit.App.Controls
{
public class VaultListViewCell : LabeledDetailCell
{
public static readonly BindableProperty LoginParameterProperty = BindableProperty.Create(nameof(LoginParameter),
typeof(VaultListPageModel.Login), typeof(VaultListViewCell), null);
public static readonly BindableProperty CipherParameterProperty = BindableProperty.Create(nameof(CipherParameter),
typeof(VaultListPageModel.Cipher), typeof(VaultListViewCell), null);
public VaultListViewCell(Action<VaultListPageModel.Login> moreClickedAction)
public VaultListViewCell(Action<VaultListPageModel.Cipher> moreClickedAction)
{
SetBinding(LoginParameterProperty, new Binding("."));
Label.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Login.Name));
Detail.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Login.Username));
LabelIcon.SetBinding(VisualElement.IsVisibleProperty, nameof(VaultListPageModel.Login.Shared));
LabelIcon2.SetBinding(VisualElement.IsVisibleProperty, nameof(VaultListPageModel.Login.HasAttachments));
SetBinding(CipherParameterProperty, new Binding("."));
Label.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Cipher.Name));
Detail.SetBinding(Label.TextProperty, nameof(VaultListPageModel.Cipher.Subtitle));
LabelIcon.SetBinding(VisualElement.IsVisibleProperty, nameof(VaultListPageModel.Cipher.Shared));
LabelIcon2.SetBinding(VisualElement.IsVisibleProperty, nameof(VaultListPageModel.Cipher.HasAttachments));
Button.Image = "more";
Button.Command = new Command(() => moreClickedAction?.Invoke(LoginParameter));
Button.Image = "more.png";
Button.Command = new Command(() => moreClickedAction?.Invoke(CipherParameter));
Button.BackgroundColor = Color.Transparent;
LabelIcon.Source = "share";
LabelIcon2.Source = "paperclip";
LabelIcon.Source = "share.png";
LabelIcon2.Source = "paperclip.png";
BackgroundColor = Color.White;
}
public VaultListPageModel.Login LoginParameter
public VaultListPageModel.Cipher CipherParameter
{
get { return GetValue(LoginParameterProperty) as VaultListPageModel.Login; }
set { SetValue(LoginParameterProperty, value); }
get { return GetValue(CipherParameterProperty) as VaultListPageModel.Cipher; }
set { SetValue(CipherParameterProperty, value); }
}
protected override void OnBindingContextChanged()
{
Icon.Source = null;
if(BindingContext is VaultListPageModel.Cipher item)
{
if(item.Type == Enums.CipherType.Login)
{
Icon.LoadingPlaceholder = "login.png";
}
Icon.Source = item.Icon;
}
base.OnBindingContextChanged();
}
}
}

View File

@@ -6,6 +6,7 @@
//Folder = 0,
Login = 1,
SecureNote = 2,
Card = 3
Card = 3,
Identity = 4
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.App.Enums
{
public enum DeviceType
{
Android = 0,
iOS = 1,
UWP = 16
}
}

View File

@@ -0,0 +1,7 @@
namespace Bit.App.Enums
{
public enum SecureNoteType : byte
{
Generic = 0
}
}

View File

@@ -0,0 +1,12 @@
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; }
}
}

View File

@@ -0,0 +1,24 @@
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; }
}
}

View File

@@ -6,18 +6,18 @@ namespace Bit.App.Models.Api
{
public class CipherRequest
{
public CipherRequest(Login login)
public CipherRequest(Cipher cipher)
{
Type = CipherType.Login;
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Favorite = login.Favorite;
Type = cipher.Type;
OrganizationId = cipher.OrganizationId;
FolderId = cipher.FolderId;
Name = cipher.Name?.EncryptedString;
Notes = cipher.Notes?.EncryptedString;
Favorite = cipher.Favorite;
if(login.Fields != null)
if(cipher.Fields != null)
{
Fields = login.Fields.Select(f => new FieldDataModel
Fields = cipher.Fields.Select(f => new FieldDataModel
{
Name = f.Name?.EncryptedString,
Value = f.Value?.EncryptedString,
@@ -28,7 +28,16 @@ namespace Bit.App.Models.Api
switch(Type)
{
case CipherType.Login:
Login = new LoginType(login);
Login = new LoginType(cipher);
break;
case CipherType.Card:
Card = new CardType(cipher);
break;
case CipherType.Identity:
Identity = new IdentityType(cipher);
break;
case CipherType.SecureNote:
SecureNote = new SecureNoteType(cipher);
break;
default:
break;
@@ -42,16 +51,20 @@ namespace Bit.App.Models.Api
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { 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(Login login)
public LoginType(Cipher cipher)
{
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Totp = login.Totp?.EncryptedString;
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; }
@@ -59,5 +72,79 @@ namespace Bit.App.Models.Api
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; }
}
}
}

View File

@@ -1,5 +1,5 @@
using Bit.App.Abstractions;
using PushNotification.Plugin.Abstractions;
using Bit.App.Enums;
using Xamarin.Forms;
namespace Bit.App.Models.Api

View File

@@ -1,5 +1,5 @@
using System;
using PushNotification.Plugin.Abstractions;
using Bit.App.Enums;
using System;
namespace Bit.App.Models.Api
{

View File

@@ -0,0 +1,9 @@
using Bit.App.Enums;
namespace Bit.App.Models.Api
{
public class SecureNoteDataModel : CipherDataModel
{
public SecureNoteType Type { get; set; }
}
}

View File

@@ -32,11 +32,6 @@ namespace Bit.App.Models
public long Size { get; set; }
public string SizeName { get; set; }
public AttachmentData ToAttachmentData(string loginId)
{
return new AttachmentData(this, loginId);
}
private void SetSize(string sizeString)
{
long size;

31
src/App/Models/Card.cs Normal file
View File

@@ -0,0 +1,31 @@
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
namespace Bit.App.Models
{
public class Card
{
public Card() { }
public Card(CipherData data)
{
var deserializedData = JsonConvert.DeserializeObject<CardDataModel>(data.Data);
CardholderName = deserializedData.CardholderName != null ?
new CipherString(deserializedData.CardholderName) : null;
Brand = deserializedData.Brand != null ? new CipherString(deserializedData.Brand) : null;
Number = deserializedData.Number != null ? new CipherString(deserializedData.Number) : null;
ExpMonth = deserializedData.ExpMonth != null ? new CipherString(deserializedData.ExpMonth) : null;
ExpYear = deserializedData.ExpYear != null ? new CipherString(deserializedData.ExpYear) : null;
Code = deserializedData.Code != null ? new CipherString(deserializedData.Code) : null;
}
public CipherString CardholderName { get; set; }
public CipherString Brand { get; set; }
public CipherString Number { get; set; }
public CipherString ExpMonth { get; set; }
public CipherString ExpYear { get; set; }
public CipherString Code { get; set; }
}
}

76
src/App/Models/Cipher.cs Normal file
View File

@@ -0,0 +1,76 @@
using Bit.App.Enums;
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace Bit.App.Models
{
public class Cipher
{
public Cipher()
{ }
public Cipher(CipherData data, IEnumerable<AttachmentData> attachments = null)
{
Id = data.Id;
UserId = data.UserId;
OrganizationId = data.OrganizationId;
FolderId = data.FolderId;
Type = data.Type;
Name = data.Name != null ? new CipherString(data.Name) : null;
Notes = data.Notes != null ? new CipherString(data.Notes) : null;
Favorite = data.Favorite;
Edit = data.Edit;
OrganizationUseTotp = data.OrganizationUseTotp;
Attachments = attachments?.Select(a => new Attachment(a));
switch(Type)
{
case CipherType.Login:
Login = new Login(data);
break;
case CipherType.SecureNote:
SecureNote = new SecureNote(data);
break;
case CipherType.Card:
Card = new Card(data);
break;
case CipherType.Identity:
Identity = new Identity(data);
break;
default:
break;
}
if(!string.IsNullOrWhiteSpace(data.Fields))
{
try
{
var fieldModels = JsonConvert.DeserializeObject<IEnumerable<FieldDataModel>>(data.Fields);
Fields = fieldModels?.Select(f => new Field(f));
}
catch(JsonSerializationException) { }
}
}
public string Id { get; set; }
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public CipherType Type { get; set; }
public CipherString Name { get; set; }
public CipherString Notes { get; set; }
public IEnumerable<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
public Login Login { get; set; }
public Identity Identity { get; set; }
public Card Card { get; set; }
public SecureNote SecureNote { get; set; }
}
}

View File

@@ -10,20 +10,20 @@ namespace Bit.App.Models.Data
public AttachmentData()
{ }
public AttachmentData(Attachment attachment, string loginId)
public AttachmentData(Attachment attachment, string cipherId)
{
Id = attachment.Id;
LoginId = loginId;
LoginId = cipherId;
Url = attachment.Url;
FileName = attachment.FileName?.EncryptedString;
Size = attachment.Size.ToString();
SizeName = attachment.SizeName;
}
public AttachmentData(AttachmentResponse response, string loginId)
public AttachmentData(AttachmentResponse response, string cipherId)
{
Id = response.Id;
LoginId = loginId;
LoginId = cipherId;
Url = response.Url;
FileName = response.FileName;
Size = response.Size;
@@ -32,6 +32,7 @@ namespace Bit.App.Models.Data
[PrimaryKey]
public string Id { get; set; }
// Really should be called CipherId
[Indexed]
public string LoginId { get; set; }
public string Url { get; set; }

View File

@@ -0,0 +1,100 @@
using System;
using SQLite;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using System.Linq;
using Bit.App.Enums;
namespace Bit.App.Models.Data
{
// Old table that has just carried over for backward compat. sake. Should really be "Cipher"
[Table("Site")]
public class CipherData : IDataObject<string>
{
public CipherData()
{ }
public CipherData(CipherResponse cipher, string userId)
{
Id = cipher.Id;
FolderId = cipher.FolderId;
UserId = userId;
OrganizationId = cipher.OrganizationId;
Favorite = cipher.Favorite;
Edit = cipher.Edit;
OrganizationUseTotp = cipher.OrganizationUseTotp;
RevisionDateTime = cipher.RevisionDate;
Type = cipher.Type;
Data = JsonConvert.SerializeObject(cipher.Data);
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;
break;
case CipherType.SecureNote:
var noteData = cipher.Data.ToObject<SecureNoteDataModel>();
cipherData = noteData;
SecureNoteType = noteData.Type;
break;
case CipherType.Card:
var cardData = cipher.Data.ToObject<CardDataModel>();
cipherData = cardData;
break;
case CipherType.Identity:
var idData = cipher.Data.ToObject<IdentityDataModel>();
cipherData = idData;
break;
default:
throw new ArgumentException(nameof(cipher.Type));
}
Name = cipherData.Name;
Notes = cipherData.Notes;
if(cipherData.Fields != null && cipherData.Fields.Any())
{
try
{
Fields = JsonConvert.SerializeObject(cipherData.Fields);
}
catch(JsonSerializationException) { }
}
}
[PrimaryKey]
public string Id { get; set; }
public string FolderId { get; set; }
[Indexed]
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public string Fields { 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;
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; }
}
}

View File

@@ -1,73 +0,0 @@
using System;
using SQLite;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using System.Linq;
namespace Bit.App.Models.Data
{
[Table("Site")]
public class LoginData : IDataObject<string>
{
public LoginData()
{ }
public LoginData(CipherResponse cipher, string userId)
{
if(cipher.Type != Enums.CipherType.Login)
{
throw new ArgumentException(nameof(cipher.Type));
}
var data = cipher.Data.ToObject<LoginDataModel>();
Id = cipher.Id;
FolderId = cipher.FolderId;
UserId = userId;
OrganizationId = cipher.OrganizationId;
Name = data.Name;
Uri = data.Uri;
Username = data.Username;
Password = data.Password;
Notes = data.Notes;
Totp = data.Totp;
Favorite = cipher.Favorite;
Edit = cipher.Edit;
OrganizationUseTotp = cipher.OrganizationUseTotp;
RevisionDateTime = cipher.RevisionDate;
if(data.Fields != null && data.Fields.Any())
{
try
{
Fields = JsonConvert.SerializeObject(data.Fields);
}
catch(JsonSerializationException) { }
}
}
[PrimaryKey]
public string Id { get; set; }
public string FolderId { get; set; }
[Indexed]
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public string Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
public Login ToLogin()
{
return new Login(this);
}
}
}

View File

@@ -0,0 +1,56 @@
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
namespace Bit.App.Models
{
public class Identity
{
public Identity() { }
public Identity(CipherData data)
{
var deserializedData = JsonConvert.DeserializeObject<IdentityDataModel>(data.Data);
Title = deserializedData.Title != null ? new CipherString(deserializedData.Title) : null;
FirstName = deserializedData.FirstName != null ? new CipherString(deserializedData.FirstName) : null;
MiddleName = deserializedData.MiddleName != null ? new CipherString(deserializedData.MiddleName) : null;
LastName = deserializedData.LastName != null ? new CipherString(deserializedData.LastName) : null;
Address1 = deserializedData.Address1 != null ? new CipherString(deserializedData.Address1) : null;
Address2 = deserializedData.Address2 != null ? new CipherString(deserializedData.Address2) : null;
Address3 = deserializedData.Address3 != null ? new CipherString(deserializedData.Address3) : null;
City = deserializedData.City != null ? new CipherString(deserializedData.City) : null;
State = deserializedData.State != null ? new CipherString(deserializedData.State) : null;
PostalCode = deserializedData.PostalCode != null ? new CipherString(deserializedData.PostalCode) : null;
Country = deserializedData.Country != null ? new CipherString(deserializedData.Country) : null;
Company = deserializedData.Company != null ? new CipherString(deserializedData.Company) : null;
Email = deserializedData.Email != null ? new CipherString(deserializedData.Email) : null;
Phone = deserializedData.Phone != null ? new CipherString(deserializedData.Phone) : null;
SSN = deserializedData.SSN != null ? new CipherString(deserializedData.SSN) : null;
Username = deserializedData.Username != null ? new CipherString(deserializedData.Username) : null;
PassportNumber = deserializedData.PassportNumber != null ?
new CipherString(deserializedData.PassportNumber) : null;
LicenseNumber = deserializedData.LicenseNumber != null ?
new CipherString(deserializedData.LicenseNumber) : null;
}
public CipherString Title { get; set; }
public CipherString FirstName { get; set; }
public CipherString MiddleName { get; set; }
public CipherString LastName { get; set; }
public CipherString Address1 { get; set; }
public CipherString Address2 { get; set; }
public CipherString Address3 { get; set; }
public CipherString City { get; set; }
public CipherString State { get; set; }
public CipherString PostalCode { get; set; }
public CipherString Country { get; set; }
public CipherString Company { get; set; }
public CipherString Email { get; set; }
public CipherString Phone { get; set; }
public CipherString SSN { get; set; }
public CipherString Username { get; set; }
public CipherString PassportNumber { get; set; }
public CipherString LicenseNumber { get; set; }
}
}

View File

@@ -1,58 +1,22 @@
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using Bit.App.Models.Data;
namespace Bit.App.Models
{
public class Login
{
public Login()
{ }
public Login() { }
public Login(LoginData data, IEnumerable<AttachmentData> attachments = null)
public Login(CipherData data)
{
Id = data.Id;
UserId = data.UserId;
OrganizationId = data.OrganizationId;
FolderId = data.FolderId;
Name = data.Name != null ? new CipherString(data.Name) : null;
Uri = data.Uri != null ? new CipherString(data.Uri) : null;
Username = data.Username != null ? new CipherString(data.Username) : null;
Password = data.Password != null ? new CipherString(data.Password) : null;
Notes = data.Notes != null ? new CipherString(data.Notes) : null;
Totp = data.Totp != null ? new CipherString(data.Totp) : null;
Favorite = data.Favorite;
Edit = data.Edit;
OrganizationUseTotp = data.OrganizationUseTotp;
Attachments = attachments?.Select(a => new Attachment(a));
if(!string.IsNullOrWhiteSpace(data.Fields))
{
try
{
var fieldModels = JsonConvert.DeserializeObject<IEnumerable<FieldDataModel>>(data.Fields);
Fields = fieldModels?.Select(f => new Field(f));
}
catch(JsonSerializationException) { }
}
}
public string Id { get; set; }
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public CipherString Name { get; set; }
public CipherString Uri { get; set; }
public CipherString Username { get; set; }
public CipherString Password { get; set; }
public CipherString Notes { get; set; }
public CipherString Totp { get; set; }
public IEnumerable<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
}
}

View File

@@ -2,24 +2,116 @@
using System.Collections.Generic;
using Bit.App.Resources;
using System.Linq;
using Bit.App.Enums;
using Bit.App.Abstractions;
namespace Bit.App.Models.Page
{
public class VaultListPageModel
{
public class Login
public class Cipher
{
public Login(Models.Login login)
public Cipher(Models.Cipher cipher, IAppSettingsService appSettings)
{
Id = login.Id;
Shared = !string.IsNullOrWhiteSpace(login.OrganizationId);
HasAttachments = login.Attachments?.Any() ?? false;
FolderId = login.FolderId;
Name = login.Name?.Decrypt(login.OrganizationId);
Username = login.Username?.Decrypt(login.OrganizationId) ?? " ";
Password = new Lazy<string>(() => login.Password?.Decrypt(login.OrganizationId));
Uri = new Lazy<string>(() => login.Uri?.Decrypt(login.OrganizationId));
Totp = new Lazy<string>(() => login.Totp?.Decrypt(login.OrganizationId));
Id = cipher.Id;
Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId);
HasAttachments = cipher.Attachments?.Any() ?? false;
FolderId = cipher.FolderId;
Name = cipher.Name?.Decrypt(cipher.OrganizationId);
Type = cipher.Type;
switch(cipher.Type)
{
case CipherType.Login:
LoginUsername = cipher.Login?.Username?.Decrypt(cipher.OrganizationId) ?? " ";
LoginUri = cipher.Login?.Uri?.Decrypt(cipher.OrganizationId) ?? " ";
LoginPassword = new Lazy<string>(() => cipher.Login?.Password?.Decrypt(cipher.OrganizationId));
LoginTotp = new Lazy<string>(() => cipher.Login?.Totp?.Decrypt(cipher.OrganizationId));
Icon = "login.png";
var hostnameUri = LoginUri;
var isWebsite = false;
var imageEnabled = !appSettings.DisableWebsiteIcons;
if(hostnameUri.StartsWith("androidapp://"))
{
Icon = "android.png";
}
else if(hostnameUri.StartsWith("iosapp://"))
{
Icon = "apple.png";
}
else if(imageEnabled && !hostnameUri.Contains("://") && hostnameUri.Contains("."))
{
hostnameUri = $"http://{hostnameUri}";
isWebsite = true;
}
else if(imageEnabled)
{
isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains(".");
}
if(imageEnabled && isWebsite && Uri.TryCreate(hostnameUri, UriKind.Absolute, out Uri u))
{
var iconsUrl = appSettings.IconsUrl;
if(string.IsNullOrWhiteSpace(iconsUrl))
{
if(!string.IsNullOrWhiteSpace(appSettings.BaseUrl))
{
iconsUrl = $"{appSettings.BaseUrl}/icons";
}
else
{
iconsUrl = "https://icons.bitwarden.com";
}
}
Icon = $"{iconsUrl}/{u.Host}/icon.png";
}
Subtitle = LoginUsername;
break;
case CipherType.SecureNote:
Icon = "note.png";
Subtitle = " ";
break;
case CipherType.Card:
CardNumber = cipher.Card?.Number?.Decrypt(cipher.OrganizationId) ?? " ";
var cardBrand = cipher.Card?.Brand?.Decrypt(cipher.OrganizationId) ?? " ";
CardCode = new Lazy<string>(() => cipher.Card?.Code?.Decrypt(cipher.OrganizationId));
Icon = "card.png";
Subtitle = cardBrand;
if(!string.IsNullOrWhiteSpace(CardNumber) && CardNumber.Length >= 4)
{
if(!string.IsNullOrWhiteSpace(CardNumber))
{
Subtitle += ", ";
}
Subtitle += ("*" + CardNumber.Substring(CardNumber.Length - 4));
}
break;
case CipherType.Identity:
var firstName = cipher.Identity?.FirstName?.Decrypt(cipher.OrganizationId) ?? " ";
var lastName = cipher.Identity?.LastName?.Decrypt(cipher.OrganizationId) ?? " ";
Icon = "id.png";
Subtitle = " ";
if(!string.IsNullOrWhiteSpace(firstName))
{
Subtitle = firstName;
}
if(!string.IsNullOrWhiteSpace(lastName))
{
if(!string.IsNullOrWhiteSpace(Subtitle))
{
Subtitle += " ";
}
Subtitle += lastName;
}
break;
default:
break;
}
}
public string Id { get; set; }
@@ -27,16 +119,26 @@ namespace Bit.App.Models.Page
public bool HasAttachments { get; set; }
public string FolderId { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public Lazy<string> Password { get; set; }
public Lazy<string> Uri { get; set; }
public Lazy<string> Totp { get; set; }
public string Subtitle { get; set; }
public CipherType Type { get; set; }
public string Icon { get; set; }
public string Image { get; set; }
// Login metadata
public string LoginUsername { get; set; }
public Lazy<string> LoginPassword { get; set; }
public string LoginUri { get; set; }
public Lazy<string> LoginTotp { get; set; }
// Login metadata
public string CardNumber { get; set; }
public Lazy<string> CardCode { get; set; }
}
public class AutofillLogin : Login
public class AutofillCipher : Cipher
{
public AutofillLogin(Models.Login login, bool fuzzy = false)
: base(login)
public AutofillCipher(Models.Cipher cipher, IAppSettingsService appSettings, bool fuzzy = false)
: base(cipher, appSettings)
{
Fuzzy = fuzzy;
}
@@ -44,7 +146,7 @@ namespace Bit.App.Models.Page
public bool Fuzzy { get; set; }
}
public class Folder : List<Login>
public class Folder : List<Cipher>
{
public Folder(Models.Folder folder)
{
@@ -52,18 +154,18 @@ namespace Bit.App.Models.Page
Name = folder.Name?.Decrypt();
}
public Folder(List<Login> logins)
public Folder(List<Cipher> ciphers)
{
AddRange(logins);
AddRange(ciphers);
}
public string Id { get; set; }
public string Name { get; set; } = AppResources.FolderNone;
}
public class AutofillGrouping : List<AutofillLogin>
public class AutofillGrouping : List<AutofillCipher>
{
public AutofillGrouping(List<AutofillLogin> logins, string name)
public AutofillGrouping(List<AutofillCipher> logins, string name)
{
AddRange(logins);
Name = name;

View File

@@ -0,0 +1,669 @@
using System;
using System.ComponentModel;
using Xamarin.Forms;
using System.Collections.Generic;
using Bit.App.Enums;
namespace Bit.App.Models.Page
{
public class VaultViewCipherPageModel : INotifyPropertyChanged
{
private string _name, _notes;
private List<Attachment> _attachments;
private List<Field> _fields;
// Login
private string _loginUsername, _loginPassword, _loginUri, _loginTotpCode;
private int _loginTotpSec = 30;
private bool _loginRevealPassword;
// Card
private string _cardName, _cardNumber, _cardBrand, _cardExpMonth, _cardExpYear, _cardCode;
// Identity
private string _idFirstName, _idLastName, _idMiddleName, _idCompany, _idEmail, _idPhone, _idUsername,
_idPassportNumber, _idLicenseNumber, _idSsn, _idAddress1, _idAddress2, _idAddress3, _idCity,
_idState, _idCountry, _idPostalCode, _idTitle;
public VaultViewCipherPageModel() { }
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get => _name;
set
{
_name = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public string Notes
{
get => _notes;
set
{
_notes = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Notes)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowNotes)));
}
}
public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes);
public List<Attachment> Attachments
{
get => _attachments;
set
{
_attachments = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Attachments)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowAttachments)));
}
}
public bool ShowAttachments => (Attachments?.Count ?? 0) > 0;
public List<Field> Fields
{
get => _fields;
set
{
_fields = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Fields)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowFields)));
}
}
public bool ShowFields => (Fields?.Count ?? 0) > 0;
// Login
public string LoginUsername
{
get => _loginUsername;
set
{
_loginUsername = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUsername)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginUsername)));
}
}
public bool ShowLoginUsername => !string.IsNullOrWhiteSpace(LoginUsername);
public string LoginPassword
{
get => _loginPassword;
set
{
_loginPassword = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedLoginPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginPassword)));
}
}
public bool ShowLoginPassword => !string.IsNullOrWhiteSpace(LoginPassword);
public bool RevealLoginPassword
{
get => _loginRevealPassword;
set
{
_loginRevealPassword = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealLoginPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedLoginPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginShowHideImage)));
}
}
public string MaskedLoginPassword => RevealLoginPassword ?
LoginPassword : LoginPassword == null ? null : new string('●', LoginPassword.Length);
public ImageSource LoginShowHideImage => RevealLoginPassword ?
ImageSource.FromFile("eye_slash.png") : ImageSource.FromFile("eye.png");
public string LoginUri
{
get => _loginUri;
set
{
_loginUri = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUri)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginUriHost)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginUri)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowLoginLaunch)));
}
}
public bool ShowLoginUri => !string.IsNullOrWhiteSpace(LoginUri);
public bool ShowLoginLaunch
{
get
{
if(!ShowLoginUri)
{
return false;
}
if(Device.RuntimePlatform == Device.Android && !LoginUri.StartsWith("http") &&
!LoginUri.StartsWith("androidapp://"))
{
return false;
}
if(Device.RuntimePlatform != Device.Android && !LoginUri.StartsWith("http"))
{
return false;
}
if(!Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri uri))
{
return false;
}
return true;
}
}
public string LoginUriHost
{
get
{
if(!ShowLoginUri)
{
return null;
}
if(!Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri uri))
{
return LoginUri;
}
if(DomainName.TryParseBaseDomain(uri.Host, out string domain))
{
return domain;
}
return uri.Host;
}
}
public string LoginTotpCode
{
get => _loginTotpCode;
set
{
_loginTotpCode = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpCode)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpCodeFormatted)));
}
}
public int LoginTotpSecond
{
get => _loginTotpSec;
set
{
_loginTotpSec = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpSecond)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(LoginTotpColor)));
}
}
public bool LoginTotpLow => LoginTotpSecond <= 7;
public Color LoginTotpColor => !string.IsNullOrWhiteSpace(LoginTotpCode) && LoginTotpLow ?
Color.Red : Color.Black;
public string LoginTotpCodeFormatted => !string.IsNullOrWhiteSpace(LoginTotpCode) ?
string.Format("{0} {1}", LoginTotpCode.Substring(0, 3), LoginTotpCode.Substring(3)) : null;
// Card
public string CardName
{
get => _cardName;
set
{
_cardName = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardName)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardName)));
}
}
public bool ShowCardName => !string.IsNullOrWhiteSpace(CardName);
public string CardNumber
{
get => _cardNumber;
set
{
_cardNumber = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardNumber)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardNumber)));
}
}
public bool ShowCardNumber => !string.IsNullOrWhiteSpace(CardNumber);
public string CardBrand
{
get => _cardBrand;
set
{
_cardBrand = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardBrand)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardBrand)));
}
}
public bool ShowCardBrand => !string.IsNullOrWhiteSpace(CardBrand);
public string CardExpMonth
{
private get => _cardExpMonth;
set
{
_cardExpMonth = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExpMonth)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExp)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardExp)));
}
}
public string CardExpYear
{
private get => _cardExpYear;
set
{
_cardExpYear = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExpYear)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardExp)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardExp)));
}
}
public string CardExp
{
get
{
var expMonth = !string.IsNullOrWhiteSpace(CardExpMonth) ? CardExpMonth.PadLeft(2, '0') : "__";
var expYear = "____";
if(!string.IsNullOrWhiteSpace(CardExpYear))
{
expYear = CardExpYear;
}
if(expYear.Length == 2)
{
expYear = "20" + expYear;
}
return $"{expMonth} / {expYear}";
}
}
public bool ShowCardExp => !string.IsNullOrWhiteSpace(CardExpMonth) && !string.IsNullOrWhiteSpace(CardExpYear);
public string CardCode
{
get => _cardCode;
set
{
_cardCode = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(CardCode)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowCardCode)));
}
}
public bool ShowCardCode => !string.IsNullOrWhiteSpace(CardCode);
// Identity
public string IdTitle
{
get => _idTitle;
set
{
_idTitle = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdTitle)));
}
}
public string IdFirstName
{
private get => _idFirstName;
set
{
_idFirstName = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdFirstName)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdName)));
}
}
public string IdMiddleName
{
private get => _idMiddleName;
set
{
_idMiddleName = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdMiddleName)));
}
}
public string IdLastName
{
private get => _idLastName;
set
{
_idLastName = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdLastName)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdName)));
}
}
public string IdName
{
get
{
var name = IdTitle;
if(!string.IsNullOrWhiteSpace(IdFirstName))
{
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdFirstName);
}
if(!string.IsNullOrWhiteSpace(IdMiddleName))
{
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdMiddleName);
}
if(!string.IsNullOrWhiteSpace(IdLastName))
{
name += ((!string.IsNullOrWhiteSpace(name) ? " " : string.Empty) + IdLastName);
}
return name;
}
}
public bool ShowIdName => !string.IsNullOrWhiteSpace(IdFirstName) || !string.IsNullOrWhiteSpace(IdLastName);
public string IdUsername
{
get => _idUsername;
set
{
_idUsername = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdUsername)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdUsername)));
}
}
public bool ShowIdUsername => !string.IsNullOrWhiteSpace(IdUsername);
public string IdCompany
{
get => _idCompany;
set
{
_idCompany = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCompany)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdCompany)));
}
}
public bool ShowIdCompany => !string.IsNullOrWhiteSpace(IdCompany);
public string IdSsn
{
get => _idSsn;
set
{
_idSsn = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdSsn)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdSsn)));
}
}
public bool ShowIdSsn => !string.IsNullOrWhiteSpace(IdSsn);
public string IdPassportNumber
{
get => _idPassportNumber;
set
{
_idPassportNumber = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPassportNumber)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdPassportNumber)));
}
}
public bool ShowIdPassportNumber => !string.IsNullOrWhiteSpace(IdPassportNumber);
public string IdLicenseNumber
{
get => _idLicenseNumber;
set
{
_idLicenseNumber = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdLicenseNumber)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdLicenseNumber)));
}
}
public bool ShowIdLicenseNumber => !string.IsNullOrWhiteSpace(IdLicenseNumber);
public string IdEmail
{
get => _idEmail;
set
{
_idEmail = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdEmail)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdEmail)));
}
}
public bool ShowIdEmail => !string.IsNullOrWhiteSpace(IdEmail);
public string IdPhone
{
get => _idPhone;
set
{
_idPhone = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPhone)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdPhone)));
}
}
public bool ShowIdPhone => !string.IsNullOrWhiteSpace(IdPhone);
public string IdAddress1
{
get => _idAddress1;
set
{
_idAddress1 = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress1)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
}
}
public string IdAddress2
{
get => _idAddress2;
set
{
_idAddress2 = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress2)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
}
}
public string IdAddress3
{
get => _idAddress3;
set
{
_idAddress3 = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress3)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
}
}
public string IdCity
{
get => _idCity;
set
{
_idCity = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCity)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
}
}
public string IdState
{
get => _idState;
set
{
_idState = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdState)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
}
}
public string IdPostalCode
{
get => _idPostalCode;
set
{
_idPostalCode = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdPostalCode)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
}
}
public string IdCountry
{
get => _idCountry;
set
{
_idCountry = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdCountry)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(IdAddress)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowIdAddress)));
}
}
public string IdAddress
{
get
{
var address = IdAddress1;
if(!string.IsNullOrWhiteSpace(IdAddress2))
{
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdAddress2);
}
if(!string.IsNullOrWhiteSpace(IdAddress3))
{
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdAddress3);
}
if(!string.IsNullOrWhiteSpace(IdCity) || !string.IsNullOrWhiteSpace(IdState) ||
!string.IsNullOrWhiteSpace(IdPostalCode))
{
var cityLine = IdCity + ", ";
cityLine += !string.IsNullOrWhiteSpace(IdState) ? IdState : "-";
cityLine += " ";
cityLine += !string.IsNullOrWhiteSpace(IdPostalCode) ? IdPostalCode : "-";
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + cityLine);
}
if(!string.IsNullOrWhiteSpace(IdCountry))
{
address += ((!string.IsNullOrWhiteSpace(address) ? "\n" : string.Empty) + IdCountry);
}
return address;
}
}
public bool ShowIdAddress => !string.IsNullOrWhiteSpace(IdAddress1) || !string.IsNullOrWhiteSpace(IdCity) ||
!string.IsNullOrWhiteSpace(IdCountry);
public void Update(Cipher cipher)
{
Name = cipher.Name?.Decrypt(cipher.OrganizationId);
Notes = cipher.Notes?.Decrypt(cipher.OrganizationId);
if(cipher.Attachments != null)
{
var attachments = new List<Attachment>();
foreach(var attachment in cipher.Attachments)
{
attachments.Add(new Attachment
{
Id = attachment.Id,
Name = attachment.FileName?.Decrypt(cipher.OrganizationId),
SizeName = attachment.SizeName,
Size = attachment.Size,
Url = attachment.Url
});
}
Attachments = attachments;
}
else
{
cipher.Attachments = null;
}
if(cipher.Fields != null)
{
var fields = new List<Field>();
foreach(var field in cipher.Fields)
{
fields.Add(new Field
{
Name = field.Name?.Decrypt(cipher.OrganizationId),
Value = field.Value?.Decrypt(cipher.OrganizationId),
Type = field.Type
});
}
Fields = fields;
}
else
{
cipher.Fields = null;
}
switch(cipher.Type)
{
case CipherType.Login:
LoginUsername = cipher.Login.Username?.Decrypt(cipher.OrganizationId);
LoginPassword = cipher.Login.Password?.Decrypt(cipher.OrganizationId);
LoginUri = cipher.Login.Uri?.Decrypt(cipher.OrganizationId);
break;
case CipherType.Card:
CardName = cipher.Card.CardholderName?.Decrypt(cipher.OrganizationId);
CardNumber = cipher.Card.Number?.Decrypt(cipher.OrganizationId);
CardBrand = cipher.Card.Brand?.Decrypt(cipher.OrganizationId);
CardExpMonth = cipher.Card.ExpMonth?.Decrypt(cipher.OrganizationId);
CardExpYear = cipher.Card.ExpYear?.Decrypt(cipher.OrganizationId);
CardCode = cipher.Card.Code?.Decrypt(cipher.OrganizationId);
break;
case CipherType.Identity:
IdTitle = cipher.Identity.Title?.Decrypt(cipher.OrganizationId);
IdFirstName = cipher.Identity.FirstName?.Decrypt(cipher.OrganizationId);
IdMiddleName = cipher.Identity.MiddleName?.Decrypt(cipher.OrganizationId);
IdLastName = cipher.Identity.LastName?.Decrypt(cipher.OrganizationId);
IdCompany = cipher.Identity.Company?.Decrypt(cipher.OrganizationId);
IdUsername = cipher.Identity.Username?.Decrypt(cipher.OrganizationId);
IdSsn = cipher.Identity.SSN?.Decrypt(cipher.OrganizationId);
IdPassportNumber = cipher.Identity.PassportNumber?.Decrypt(cipher.OrganizationId);
IdLicenseNumber = cipher.Identity.LicenseNumber?.Decrypt(cipher.OrganizationId);
IdEmail = cipher.Identity.Email?.Decrypt(cipher.OrganizationId);
IdPhone = cipher.Identity.Phone?.Decrypt(cipher.OrganizationId);
IdAddress1 = cipher.Identity.Address1?.Decrypt(cipher.OrganizationId);
IdAddress2 = cipher.Identity.Address2?.Decrypt(cipher.OrganizationId);
IdAddress3 = cipher.Identity.Address3?.Decrypt(cipher.OrganizationId);
IdCity = cipher.Identity.City?.Decrypt(cipher.OrganizationId);
IdState = cipher.Identity.State?.Decrypt(cipher.OrganizationId);
IdPostalCode = cipher.Identity.PostalCode?.Decrypt(cipher.OrganizationId);
IdCountry = cipher.Identity.Country?.Decrypt(cipher.OrganizationId);
break;
default:
break;
}
}
public class Attachment
{
public string Id { get; set; }
public string Name { get; set; }
public string SizeName { get; set; }
public long Size { get; set; }
public string Url { get; set; }
}
public class Field
{
private string _maskedValue;
public string Name { get; set; }
public string Value { get; set; }
public string MaskedValue
{
get
{
if(_maskedValue == null && Value != null)
{
_maskedValue = new string('●', Value.Length);
}
return _maskedValue;
}
}
public FieldType Type { get; set; }
public bool Revealed { get; set; }
}
}
}

Some files were not shown because too many files have changed in this diff Show More