initial commit
|
@ -0,0 +1,199 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Visual Studo 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding addin-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
*.[Cc]ache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Other
|
||||||
|
project.lock.json
|
|
@ -0,0 +1,256 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 14
|
||||||
|
VisualStudioVersion = 14.0.25123.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{04B18ED2-B76D-4947-8474-191F8FD2B5E0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{1F78403F-9A28-405B-9289-B9DBEB55F074}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{B490C5DA-639E-4994-ABD2-54222B8A348E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EC730FD9-F623-4B6C-B503-95CDCFBCF277}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App.Test", "test\App.Test\App.Test.csproj", "{A300DCE1-8D10-4267-B96A-CB01AEB7C220}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||||
|
Ad-Hoc|ARM = Ad-Hoc|ARM
|
||||||
|
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||||
|
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||||
|
Ad-Hoc|x64 = Ad-Hoc|x64
|
||||||
|
Ad-Hoc|x86 = Ad-Hoc|x86
|
||||||
|
AppStore|Any CPU = AppStore|Any CPU
|
||||||
|
AppStore|ARM = AppStore|ARM
|
||||||
|
AppStore|iPhone = AppStore|iPhone
|
||||||
|
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||||
|
AppStore|x64 = AppStore|x64
|
||||||
|
AppStore|x86 = AppStore|x86
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|ARM = Debug|ARM
|
||||||
|
Debug|iPhone = Debug|iPhone
|
||||||
|
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|ARM = Release|ARM
|
||||||
|
Release|iPhone = Release|iPhone
|
||||||
|
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|ARM.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x64.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Ad-Hoc|x86.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|ARM.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x64.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.AppStore|x86.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Debug|iPhoneSimulator.Deploy.0 = 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
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x64.Deploy.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0}.Release|x86.Deploy.0 = Release|Any CPU
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|x64.ActiveCfg = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|ARM.ActiveCfg = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|x64.ActiveCfg = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.AppStore|x86.ActiveCfg = AppStore|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|ARM.ActiveCfg = Debug|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||||
|
{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|x86.ActiveCfg = Debug|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|Any CPU.ActiveCfg = Release|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|ARM.ActiveCfg = Release|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhone.Build.0 = Release|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|x64.ActiveCfg = Release|iPhone
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074}.Release|x86.ActiveCfg = Release|iPhone
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x64.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.AppStore|x86.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x64.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Ad-Hoc|x86.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|ARM.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x64.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.AppStore|x86.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Debug|iPhoneSimulator.Build.0 = 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
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{04B18ED2-B76D-4947-8474-191F8FD2B5E0} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||||
|
{1F78403F-9A28-405B-9289-B9DBEB55F074} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||||
|
{B490C5DA-639E-4994-ABD2-54222B8A348E} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
|
||||||
|
{A300DCE1-8D10-4267-B96A-CB01AEB7C220} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,208 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{04B18ED2-B76D-4947-8474-191F8FD2B5E0}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Bit.Android</RootNamespace>
|
||||||
|
<AssemblyName>Bit.Android</AssemblyName>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AndroidApplication>true</AndroidApplication>
|
||||||
|
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
||||||
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
|
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||||
|
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
||||||
|
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
|
||||||
|
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
|
||||||
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
|
<MandroidI18n />
|
||||||
|
<JavaMaximumHeapSize />
|
||||||
|
<JavaOptions />
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>True</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
|
||||||
|
<AndroidLinkMode>None</AndroidLinkMode>
|
||||||
|
<AndroidLinkSkip />
|
||||||
|
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||||
|
<BundleAssemblies>False</BundleAssemblies>
|
||||||
|
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidSupportedAbis>
|
||||||
|
</AndroidSupportedAbis>
|
||||||
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
|
<MandroidI18n />
|
||||||
|
<Debugger>Xamarin</Debugger>
|
||||||
|
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||||
|
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
||||||
|
<AndroidLinkSkip />
|
||||||
|
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||||
|
<BundleAssemblies>False</BundleAssemblies>
|
||||||
|
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
|
||||||
|
<AndroidSupportedAbis>
|
||||||
|
</AndroidSupportedAbis>
|
||||||
|
<AndroidStoreUncompressedFileExtensions />
|
||||||
|
<MandroidI18n />
|
||||||
|
<Debugger>Xamarin</Debugger>
|
||||||
|
<AotAssemblies>False</AotAssemblies>
|
||||||
|
<EnableLLVM>False</EnableLLVM>
|
||||||
|
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
|
||||||
|
<EnableProguard>False</EnableProguard>
|
||||||
|
<DebugSymbols>False</DebugSymbols>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Practices.Unity, Version=3.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Unity.3.5.1405-prerelease\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ModernHttpClient, Version=2.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\ModernHttpClient.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Mono.Android" />
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="OkHttp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\MonoAndroid\OkHttp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.Design, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.v4, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.v7.AppCompat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.v7.CardView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.v7.MediaRouter, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Android.Support.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Platform.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="XLabs.Ioc.Unity, Version=2.0.5782.12230, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\XLabs.IoC.Unity.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.Unity.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Resources\Resource.Designer.cs" />
|
||||||
|
<Compile Include="Services\KeyStoreStorageService.cs" />
|
||||||
|
<Compile Include="MainActivity.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Services\SqlService.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="Resources\AboutResources.txt" />
|
||||||
|
<None Include="Assets\AboutAssets.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidResource Include="Resources\drawable\icon.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-hdpi\icon.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xhdpi\icon.png" />
|
||||||
|
<AndroidResource Include="Resources\drawable-xxhdpi\icon.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Properties\AndroidManifest.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\App\App.csproj">
|
||||||
|
<Project>{b490c5da-639e-4994-abd2-54222b8a348e}</Project>
|
||||||
|
<Name>App</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</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">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\..\packages\SQLitePCL.raw.0.8.6\build\MonoAndroid\SQLitePCL.raw.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCL.raw.0.8.6\build\MonoAndroid\SQLitePCL.raw.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<Import Project="..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||||
|
<Import Project="..\..\packages\SQLitePCL.raw.0.8.6\build\MonoAndroid\SQLitePCL.raw.targets" Condition="Exists('..\..\packages\SQLitePCL.raw.0.8.6\build\MonoAndroid\SQLitePCL.raw.targets')" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,19 @@
|
||||||
|
Any raw assets you want to be deployed with your application can be placed in
|
||||||
|
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||||
|
|
||||||
|
These files will be deployed with you package and will be accessible using Android's
|
||||||
|
AssetManager, like this:
|
||||||
|
|
||||||
|
public class ReadAsset : Activity
|
||||||
|
{
|
||||||
|
protected override void OnCreate (Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate (bundle);
|
||||||
|
|
||||||
|
InputStream input = Assets.Open ("my_asset.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Additionally, some Android functions will automatically load asset files:
|
||||||
|
|
||||||
|
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content.PM;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Widget;
|
||||||
|
using Android.OS;
|
||||||
|
using Microsoft.Practices.Unity;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Services;
|
||||||
|
using XLabs.Ioc.Unity;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
using Bit.Android.Services;
|
||||||
|
|
||||||
|
namespace Bit.Android
|
||||||
|
{
|
||||||
|
[Activity(Label = "bitwarden", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
|
||||||
|
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
|
||||||
|
{
|
||||||
|
protected override void OnCreate(Bundle bundle)
|
||||||
|
{
|
||||||
|
base.OnCreate(bundle);
|
||||||
|
|
||||||
|
global::Xamarin.Forms.Forms.Init(this, bundle);
|
||||||
|
|
||||||
|
if(!Resolver.IsSet)
|
||||||
|
{
|
||||||
|
SetIoc();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadApplication(new App.App(Resolver.Resolve<IAuthService>(), Resolver.Resolve<IDatabaseService>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetIoc()
|
||||||
|
{
|
||||||
|
var container = new UnityContainer();
|
||||||
|
|
||||||
|
container
|
||||||
|
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ISecureStorageService, KeyStoreStorageService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IFolderService, FolderService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ISiteService, SiteService>(new ContainerControlledLifetimeManager());
|
||||||
|
|
||||||
|
Resolver.SetResolver(new UnityResolver(container));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="Bit.Android" android:versionCode="1" android:versionName="0.0.1" android:installLocation="auto">
|
||||||
|
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="23" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<application android:label="bitwarden"></application>
|
||||||
|
</manifest>
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Android.App;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Bit.Android")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("bitwarden")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
|
||||||
|
// Add some common permissions, these can be removed if not needed
|
||||||
|
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||||
|
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
|
@ -0,0 +1,50 @@
|
||||||
|
Images, layout descriptions, binary blobs and string dictionaries can be included
|
||||||
|
in your application as resource files. Various Android APIs are designed to
|
||||||
|
operate on the resource IDs instead of dealing with images, strings or binary blobs
|
||||||
|
directly.
|
||||||
|
|
||||||
|
For example, a sample Android app that contains a user interface layout (main.xml),
|
||||||
|
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
|
||||||
|
would keep its resources in the "Resources" directory of the application:
|
||||||
|
|
||||||
|
Resources/
|
||||||
|
drawable-hdpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
drawable-ldpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
drawable-mdpi/
|
||||||
|
icon.png
|
||||||
|
|
||||||
|
layout/
|
||||||
|
main.xml
|
||||||
|
|
||||||
|
values/
|
||||||
|
strings.xml
|
||||||
|
|
||||||
|
In order to get the build system to recognize Android resources, set the build action to
|
||||||
|
"AndroidResource". The native Android APIs do not operate directly with filenames, but
|
||||||
|
instead operate on resource IDs. When you compile an Android application that uses resources,
|
||||||
|
the build system will package the resources for distribution and generate a class called
|
||||||
|
"Resource" that contains the tokens for each one of the resources included. For example,
|
||||||
|
for the above Resources layout, this is what the Resource class would expose:
|
||||||
|
|
||||||
|
public class Resource {
|
||||||
|
public class drawable {
|
||||||
|
public const int icon = 0x123;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class layout {
|
||||||
|
public const int main = 0x456;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class strings {
|
||||||
|
public const int first_string = 0xabc;
|
||||||
|
public const int second_string = 0xbcd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
|
||||||
|
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
|
||||||
|
string in the dictionary file values/strings.xml.
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,112 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.IsolatedStorage;
|
||||||
|
using Java.Lang;
|
||||||
|
using Java.Security;
|
||||||
|
using Javax.Crypto;
|
||||||
|
using Android.OS;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.Android.Services
|
||||||
|
{
|
||||||
|
public class KeyStoreStorageService : ISecureStorageService
|
||||||
|
{
|
||||||
|
private const string StorageFile = "Bit.Android.KeyStoreStorageService";
|
||||||
|
|
||||||
|
private static readonly object SaveLock = new object();
|
||||||
|
|
||||||
|
private readonly KeyStore _keyStore;
|
||||||
|
private readonly KeyStore.PasswordProtection _protection;
|
||||||
|
|
||||||
|
public KeyStoreStorageService()
|
||||||
|
: this(Build.Serial.ToCharArray()) { }
|
||||||
|
|
||||||
|
public KeyStoreStorageService(char[] password)
|
||||||
|
{
|
||||||
|
_keyStore = KeyStore.GetInstance(KeyStore.DefaultType);
|
||||||
|
_protection = new KeyStore.PasswordProtection(password);
|
||||||
|
|
||||||
|
if(File.FileExists(StorageFile))
|
||||||
|
{
|
||||||
|
using(var stream = new IsolatedStorageFileStream(StorageFile, FileMode.Open, FileAccess.Read, File))
|
||||||
|
{
|
||||||
|
_keyStore.Load(stream, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_keyStore.Load(null, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IsolatedStorageFile File
|
||||||
|
{
|
||||||
|
get { return IsolatedStorageFile.GetUserStoreForApplication(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Store(string key, byte[] dataBytes)
|
||||||
|
{
|
||||||
|
_keyStore.SetEntry(key, new KeyStore.SecretKeyEntry(new SecureData(dataBytes)), _protection);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Retrieve(string key)
|
||||||
|
{
|
||||||
|
var entry = _keyStore.GetEntry(key, _protection) as KeyStore.SecretKeyEntry;
|
||||||
|
if(entry == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry.SecretKey.GetEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(string key)
|
||||||
|
{
|
||||||
|
_keyStore.DeleteEntry(key);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string key)
|
||||||
|
{
|
||||||
|
return _keyStore.ContainsAlias(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
lock(SaveLock)
|
||||||
|
{
|
||||||
|
using(var stream = new IsolatedStorageFileStream(StorageFile, FileMode.OpenOrCreate, FileAccess.Write, File))
|
||||||
|
{
|
||||||
|
_keyStore.Store(stream, _protection.GetPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SecureData : Object, ISecretKey
|
||||||
|
{
|
||||||
|
private const string Raw = "RAW";
|
||||||
|
|
||||||
|
private readonly byte[] _data;
|
||||||
|
|
||||||
|
public SecureData(byte[] dataBytes)
|
||||||
|
{
|
||||||
|
_data = dataBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Algorithm
|
||||||
|
{
|
||||||
|
get { return Raw; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Format
|
||||||
|
{
|
||||||
|
get { return Raw; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetEncoded()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.Android.Services
|
||||||
|
{
|
||||||
|
public class SqlService : ISqlService
|
||||||
|
{
|
||||||
|
public SQLite.SQLiteConnection GetConnection()
|
||||||
|
{
|
||||||
|
var sqliteFilename = "bitwarden.db3";
|
||||||
|
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
|
||||||
|
var path = Path.Combine(documentsPath, sqliteFilename);
|
||||||
|
|
||||||
|
Console.WriteLine(path);
|
||||||
|
var conn = new SQLite.SQLiteConnection(path);
|
||||||
|
|
||||||
|
// Return the database connection
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="CommonServiceLocator" version="1.3" targetFramework="monoandroid60" />
|
||||||
|
<package id="modernhttpclient" version="2.4.2" targetFramework="monoandroid50" />
|
||||||
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="monoandroid60" />
|
||||||
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="monoandroid60" />
|
||||||
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="monoandroid60" />
|
||||||
|
<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" />
|
||||||
|
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Android.Support.v7.AppCompat" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Android.Support.v7.CardView" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Android.Support.v7.MediaRouter" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Android.Support.v7.RecyclerView" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
|
||||||
|
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="monoandroid60" />
|
||||||
|
<package id="XLabs.IoC" version="2.0.5782" targetFramework="monoandroid60" />
|
||||||
|
<package id="XLabs.IoC.Unity" version="2.0.5782" targetFramework="monoandroid60" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IDataObject<T> where T : IEquatable<T>
|
||||||
|
{
|
||||||
|
T Id { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IApiService
|
||||||
|
{
|
||||||
|
HttpClient Client { get; set; }
|
||||||
|
|
||||||
|
Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IAuthService
|
||||||
|
{
|
||||||
|
bool IsAuthenticated { get; }
|
||||||
|
string Token { get; set; }
|
||||||
|
|
||||||
|
Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using Bit.App.Models;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ICryptoService
|
||||||
|
{
|
||||||
|
string Base64Key { get; }
|
||||||
|
byte[] Key { get; set; }
|
||||||
|
|
||||||
|
string Decrypt(CipherString encyptedValue);
|
||||||
|
CipherString Encrypt(string plaintextValue);
|
||||||
|
byte[] MakeKeyFromPassword(string password, string salt);
|
||||||
|
string MakeKeyFromPasswordBase64(string password, string salt);
|
||||||
|
byte[] HashPassword(byte[] key, string password);
|
||||||
|
string HashPasswordBase64(byte[] key, string password);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IDatabaseService
|
||||||
|
{
|
||||||
|
void CreateTables();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface IFolderService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Folder>> GetAllAsync();
|
||||||
|
Task SaveAsync(Folder folder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ISecureStorageService
|
||||||
|
{
|
||||||
|
void Store(string key, byte[] dataBytes);
|
||||||
|
byte[] Retrieve(string key);
|
||||||
|
void Delete(string key);
|
||||||
|
bool Contains(string key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Models;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ISiteService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Site>> GetAllAsync();
|
||||||
|
Task SaveAsync(Site site);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ISqlService
|
||||||
|
{
|
||||||
|
SQLiteConnection GetConnection();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Views;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public class App : Application
|
||||||
|
{
|
||||||
|
private readonly IDatabaseService _databaseService;
|
||||||
|
|
||||||
|
public App(IAuthService authService, IDatabaseService databaseService)
|
||||||
|
{
|
||||||
|
_databaseService = databaseService;
|
||||||
|
|
||||||
|
if(authService.IsAuthenticated)
|
||||||
|
{
|
||||||
|
var nav = new NavigationPage(new VaultListPage());
|
||||||
|
nav.BarBackgroundColor = Color.FromHex("3c8dbc");
|
||||||
|
nav.BarTextColor = Color.FromHex("ffffff");
|
||||||
|
|
||||||
|
MainPage = nav;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var nav = new NavigationPage(new LoginPage());
|
||||||
|
nav.BarBackgroundColor = Color.FromHex("3c8dbc");
|
||||||
|
nav.BarTextColor = Color.FromHex("ffffff");
|
||||||
|
|
||||||
|
MainPage = nav;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainPage.BackgroundColor = Color.FromHex("ecf0f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStart()
|
||||||
|
{
|
||||||
|
// Handle when your app starts
|
||||||
|
_databaseService.CreateTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSleep()
|
||||||
|
{
|
||||||
|
// Handle when your app sleeps
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResume()
|
||||||
|
{
|
||||||
|
// Handle when your app resumes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{B490C5DA-639E-4994-ABD2-54222B8A348E}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Bit.App</RootNamespace>
|
||||||
|
<AssemblyName>Bit.App</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;DEBUG;NETFX_CORE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Abstractions\Services\ISiteService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IFolderService.cs" />
|
||||||
|
<Compile Include="App.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\ISecureStorageService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\ISqlService.cs" />
|
||||||
|
<Compile Include="Behaviors\EmailValidationBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\RequiredValidationBehavior.cs" />
|
||||||
|
<Compile Include="Models\Api\ApiError.cs" />
|
||||||
|
<Compile Include="Models\Api\ApiResult.cs" />
|
||||||
|
<Compile Include="Models\Api\Request\FolderRequest.cs" />
|
||||||
|
<Compile Include="Models\Api\Request\SiteRequest.cs" />
|
||||||
|
<Compile Include="Models\Api\Request\TokenRequest.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\ErrorResponse.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\FolderResponse.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\SiteResponse.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\TokenResponse.cs" />
|
||||||
|
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
|
||||||
|
<Compile Include="Models\Cipher.cs" />
|
||||||
|
<Compile Include="Models\CipherString.cs" />
|
||||||
|
<Compile Include="Models\Data\FolderData.cs" />
|
||||||
|
<Compile Include="Abstractions\IDataObject.cs" />
|
||||||
|
<Compile Include="Models\Data\SiteData.cs" />
|
||||||
|
<Compile Include="Models\Folder.cs" />
|
||||||
|
<Compile Include="Models\Site.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Services\DatabaseService.cs" />
|
||||||
|
<Compile Include="Services\FolderService.cs" />
|
||||||
|
<Compile Include="Services\Repository.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IApiService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IAuthService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\ICryptoService.cs" />
|
||||||
|
<Compile Include="Abstractions\Services\IDatabaseService.cs" />
|
||||||
|
<Compile Include="Services\SiteService.cs" />
|
||||||
|
<Compile Include="Services\AuthService.cs" />
|
||||||
|
<Compile Include="Services\CryptoService.cs" />
|
||||||
|
<Compile Include="Models\View\VaultView.cs" />
|
||||||
|
<Compile Include="Pages\LoginPage.cs" />
|
||||||
|
<Compile Include="Pages\VaultEditFolderPage.cs" />
|
||||||
|
<Compile Include="Pages\VaultAddFolderPage.cs" />
|
||||||
|
<Compile Include="Pages\VaultAddSitePage.cs" />
|
||||||
|
<Compile Include="Pages\VaultViewSitePage.cs" />
|
||||||
|
<Compile Include="Pages\VaultEditSitePage.cs" />
|
||||||
|
<Compile Include="Pages\VaultListPage.cs" />
|
||||||
|
<Compile Include="Services\ApiService.cs" />
|
||||||
|
<Compile Include="Utilities\Extentions.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Portable.BouncyCastle.1.8.1\lib\portable-net45+win8+wpa81+MonoTouch10+MonoAndroid10+xamarinmac20+xamarinios10\crypto.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Practices.Unity, Version=3.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Unity.3.5.1405-prerelease\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ModernHttpClient, Version=2.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\Portable-Net45+WinRT45+WP8+WPA81\ModernHttpClient.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Newtonsoft.Json.8.0.3\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SQLitePCL.raw, Version=0.8.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\SQLitePCL.raw.0.8.6\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCL.raw.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Platform.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Xaml.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1+Xamarin.iOS10\XLabs.Ioc.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||||
|
<Import Project="..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Behaviors
|
||||||
|
{
|
||||||
|
public class EmailValidationBehavior : Behavior<Entry>
|
||||||
|
{
|
||||||
|
private const string EmailRegex = @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
|
||||||
|
@"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
|
||||||
|
|
||||||
|
private static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(EmailValidationBehavior), false);
|
||||||
|
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
|
||||||
|
|
||||||
|
public bool IsValid
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(IsValidProperty); }
|
||||||
|
private set { SetValue(IsValidPropertyKey, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedTo(Entry bindable)
|
||||||
|
{
|
||||||
|
bindable.TextChanged += HandleTextChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
IsValid = Regex.IsMatch(e.NewTextValue, EmailRegex, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
|
||||||
|
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDetachingFrom(Entry bindable)
|
||||||
|
{
|
||||||
|
bindable.TextChanged -= HandleTextChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Behaviors
|
||||||
|
{
|
||||||
|
public class RequiredValidationBehavior : Behavior<Entry>
|
||||||
|
{
|
||||||
|
private static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(RequiredValidationBehavior), false);
|
||||||
|
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
|
||||||
|
|
||||||
|
public bool IsValid
|
||||||
|
{
|
||||||
|
get { return (bool)GetValue(IsValidProperty); }
|
||||||
|
private set { SetValue(IsValidPropertyKey, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAttachedTo(Entry bindable)
|
||||||
|
{
|
||||||
|
bindable.TextChanged += HandleTextChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleTextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
IsValid = !string.IsNullOrWhiteSpace(e.NewTextValue);
|
||||||
|
((Entry)sender).BackgroundColor = IsValid ? Color.Default : Color.Red;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDetachingFrom(Entry bindable)
|
||||||
|
{
|
||||||
|
bindable.TextChanged -= HandleTextChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class ApiError
|
||||||
|
{
|
||||||
|
public string Message { get; set; }
|
||||||
|
public HttpStatusCode StatusCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class ApiResult<T>
|
||||||
|
{
|
||||||
|
private List<ApiError> m_errors = new List<ApiError>();
|
||||||
|
|
||||||
|
public bool Succeeded { get; private set; }
|
||||||
|
public T Result { get; set; }
|
||||||
|
public IEnumerable<ApiError> Errors => m_errors;
|
||||||
|
|
||||||
|
public static ApiResult<T> Success(T result)
|
||||||
|
{
|
||||||
|
return new ApiResult<T>
|
||||||
|
{
|
||||||
|
Succeeded = true,
|
||||||
|
Result = result
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiResult<T> Failed(params ApiError[] errors)
|
||||||
|
{
|
||||||
|
var result = new ApiResult<T> { Succeeded = false };
|
||||||
|
if(errors != null)
|
||||||
|
{
|
||||||
|
result.m_errors.AddRange(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class FolderRequest
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class SiteRequest
|
||||||
|
{
|
||||||
|
public string FolderId { 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class TokenRequest
|
||||||
|
{
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string MasterPasswordHash { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class ErrorResponse
|
||||||
|
{
|
||||||
|
public string Message { get; set; }
|
||||||
|
public Dictionary<string, IEnumerable<string>> ValidationErrors { get; set; }
|
||||||
|
// For use in development environments.
|
||||||
|
public string ExceptionMessage { get; set; }
|
||||||
|
public string ExceptionStackTrace { get; set; }
|
||||||
|
public string InnerExceptionMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class FolderResponse
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class ProfileResponse
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string MasterPasswordHint { get; set; }
|
||||||
|
public string Culture { get; set; }
|
||||||
|
public bool TwoFactorEnabled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class SiteResponse
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string FolderId { 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; }
|
||||||
|
|
||||||
|
// Expandables
|
||||||
|
public FolderResponse Folder { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Bit.App.Models.Api
|
||||||
|
{
|
||||||
|
public class TokenResponse
|
||||||
|
{
|
||||||
|
public string Token { get; set; }
|
||||||
|
public ProfileResponse Profile { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public abstract class Cipher
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string ServerId { get; set; }
|
||||||
|
public CipherString Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class CipherString
|
||||||
|
{
|
||||||
|
public CipherString(string encryptedString)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(encryptedString) || !encryptedString.Contains("|"))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(nameof(encryptedString));
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptedString = encryptedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CipherString(string initializationVector, string cipherText)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(initializationVector))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(initializationVector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(cipherText))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(cipherText));
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptedString = string.Format("{0}|{1}", initializationVector, cipherText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EncryptedString { get; private set; }
|
||||||
|
public string InitializationVector { get { return EncryptedString?.Split('|')[0]; } }
|
||||||
|
public string CipherText { get { return EncryptedString?.Split('|')[1]; } }
|
||||||
|
public byte[] InitializationVectorBytes { get { return Convert.FromBase64String(InitializationVector); } }
|
||||||
|
public byte[] CipherTextBytes { get { return Convert.FromBase64String(CipherText); } }
|
||||||
|
|
||||||
|
public string Decrypt()
|
||||||
|
{
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
return cryptoService.Decrypt(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using SQLite;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Data
|
||||||
|
{
|
||||||
|
[Table("Folder")]
|
||||||
|
public class FolderData : IDataObject<int>
|
||||||
|
{
|
||||||
|
public FolderData()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public FolderData(Folder folder)
|
||||||
|
{
|
||||||
|
Id = folder.Id;
|
||||||
|
ServerId = folder.ServerId;
|
||||||
|
Name = folder.Name?.EncryptedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
[AutoIncrement]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string ServerId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public Folder ToFolder()
|
||||||
|
{
|
||||||
|
return new Folder(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using SQLite;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Data
|
||||||
|
{
|
||||||
|
[Table("Site")]
|
||||||
|
public class SiteData : IDataObject<int>
|
||||||
|
{
|
||||||
|
public SiteData()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public SiteData(Site site)
|
||||||
|
{
|
||||||
|
Id = site.Id;
|
||||||
|
ServerId = site.ServerId;
|
||||||
|
FolderId = site.FolderId;
|
||||||
|
ServerFolderId = site.ServerFolderId;
|
||||||
|
Name = site.Name?.EncryptedString;
|
||||||
|
Uri = site.Uri?.EncryptedString;
|
||||||
|
Username = site.Username?.EncryptedString;
|
||||||
|
Password = site.Password?.EncryptedString;
|
||||||
|
Notes = site.Notes?.EncryptedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrimaryKey]
|
||||||
|
[AutoIncrement]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string ServerId { get; set; }
|
||||||
|
public int? FolderId { get; set; }
|
||||||
|
public string ServerFolderId { 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 DateTime RevisionDateTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public Site ToSite()
|
||||||
|
{
|
||||||
|
return new Site(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class Folder : Cipher
|
||||||
|
{
|
||||||
|
public Folder()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Folder(FolderData data)
|
||||||
|
{
|
||||||
|
Id = data.Id;
|
||||||
|
ServerId = data.ServerId;
|
||||||
|
Name = data.Name != null ? new CipherString(data.Name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Folder(FolderResponse response)
|
||||||
|
{
|
||||||
|
ServerId = response.Id;
|
||||||
|
Name = response.Name != null ? new CipherString(response.Name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FolderData ToFolderData()
|
||||||
|
{
|
||||||
|
return new FolderData(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class Site : Cipher
|
||||||
|
{
|
||||||
|
public Site()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Site(SiteData data)
|
||||||
|
{
|
||||||
|
Id = data.Id;
|
||||||
|
ServerId = data.ServerId;
|
||||||
|
FolderId = data.FolderId;
|
||||||
|
ServerFolderId = data.ServerFolderId;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Site(SiteResponse response)
|
||||||
|
{
|
||||||
|
ServerId = response.Id;
|
||||||
|
ServerFolderId = response.FolderId;
|
||||||
|
Name = response.Name != null ? new CipherString(response.Name) : null;
|
||||||
|
Uri = response.Uri != null ? new CipherString(response.Uri) : null;
|
||||||
|
Username = response.Username != null ? new CipherString(response.Username) : null;
|
||||||
|
Password = response.Password != null ? new CipherString(response.Password) : null;
|
||||||
|
Notes = response.Notes != null ? new CipherString(response.Notes) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? FolderId { get; set; }
|
||||||
|
public string ServerFolderId { get; set; }
|
||||||
|
public CipherString Uri { get; set; }
|
||||||
|
public CipherString Username { get; set; }
|
||||||
|
public CipherString Password { get; set; }
|
||||||
|
public CipherString Notes { get; set; }
|
||||||
|
|
||||||
|
public SiteData ToSiteData()
|
||||||
|
{
|
||||||
|
return new SiteData(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.View
|
||||||
|
{
|
||||||
|
public class VaultView
|
||||||
|
{
|
||||||
|
public class Site
|
||||||
|
{
|
||||||
|
public Site(Models.Site site)
|
||||||
|
{
|
||||||
|
Id = site.Id;
|
||||||
|
Name = site.Name?.Decrypt();
|
||||||
|
Username = site.Username?.Decrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Folder : ObservableCollection<Site>
|
||||||
|
{
|
||||||
|
public Folder(string name) { Name = name; }
|
||||||
|
|
||||||
|
public Folder(IEnumerable<Models.Site> sites)
|
||||||
|
{
|
||||||
|
Name = "(none)";
|
||||||
|
foreach(var site in sites)
|
||||||
|
{
|
||||||
|
Items.Add(new Site(site));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Folder(Models.Folder folder, IEnumerable<Models.Site> sites)
|
||||||
|
: this(sites)
|
||||||
|
{
|
||||||
|
Id = folder.Id;
|
||||||
|
Name = folder.Name?.Decrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string FirstLetter { get { return Name.Substring(0, 1); } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Behaviors;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class LoginPage : ContentPage
|
||||||
|
{
|
||||||
|
public LoginPage()
|
||||||
|
{
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
var authService = Resolver.Resolve<IAuthService>();
|
||||||
|
|
||||||
|
var emailEntry = new Entry
|
||||||
|
{
|
||||||
|
Keyboard = Keyboard.Email,
|
||||||
|
Placeholder = "Email Address"
|
||||||
|
};
|
||||||
|
|
||||||
|
emailEntry.Behaviors.Add(new RequiredValidationBehavior());
|
||||||
|
emailEntry.Behaviors.Add(new EmailValidationBehavior());
|
||||||
|
|
||||||
|
var masterPasswordEntry = new Entry
|
||||||
|
{
|
||||||
|
IsPassword = true,
|
||||||
|
Placeholder = "Master Password"
|
||||||
|
};
|
||||||
|
|
||||||
|
masterPasswordEntry.Behaviors.Add(new RequiredValidationBehavior());
|
||||||
|
|
||||||
|
var loginButton = new Button
|
||||||
|
{
|
||||||
|
Text = "Log In",
|
||||||
|
Command = new Command(async () =>
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(emailEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", "The Email Address field is required.", "Ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(masterPasswordEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", "The Master Password field is required.", "Ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = cryptoService.MakeKeyFromPassword(masterPasswordEntry.Text, emailEntry.Text);
|
||||||
|
|
||||||
|
var request = new TokenRequest
|
||||||
|
{
|
||||||
|
Email = emailEntry.Text,
|
||||||
|
MasterPasswordHash = cryptoService.HashPasswordBase64(key, masterPasswordEntry.Text)
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await authService.TokenPostAsync(request);
|
||||||
|
if(!response.Succeeded)
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptoService.Key = key;
|
||||||
|
authService.Token = response.Result.Token;
|
||||||
|
await Navigation.PushAsync(new VaultListPage());
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
var stackLayout = new StackLayout
|
||||||
|
{
|
||||||
|
Padding = new Thickness(10, 50, 10, 0)
|
||||||
|
};
|
||||||
|
stackLayout.Children.Add(emailEntry);
|
||||||
|
stackLayout.Children.Add(masterPasswordEntry);
|
||||||
|
stackLayout.Children.Add(loginButton);
|
||||||
|
|
||||||
|
Title = "Log In";
|
||||||
|
Content = stackLayout;
|
||||||
|
NavigationPage.SetHasNavigationBar(this, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultAddFolderPage : ContentPage
|
||||||
|
{
|
||||||
|
public VaultAddFolderPage()
|
||||||
|
{
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
var folderService = Resolver.Resolve<IFolderService>();
|
||||||
|
|
||||||
|
var nameEntry = new Entry();
|
||||||
|
|
||||||
|
var stackLayout = new StackLayout();
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Name" });
|
||||||
|
stackLayout.Children.Add(nameEntry);
|
||||||
|
|
||||||
|
var scrollView = new ScrollView
|
||||||
|
{
|
||||||
|
Content = stackLayout,
|
||||||
|
Orientation = ScrollOrientation.Vertical
|
||||||
|
};
|
||||||
|
|
||||||
|
var saveToolBarItem = new ToolbarItem("Save", null, async () =>
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(nameEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", "The Name field is required.", "Ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var folder = new Folder
|
||||||
|
{
|
||||||
|
Name = new CipherString(nameEntry.Text)
|
||||||
|
};
|
||||||
|
await folderService.SaveAsync(folder);
|
||||||
|
await Navigation.PopAsync();
|
||||||
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
|
Title = "Add Folder";
|
||||||
|
Content = scrollView;
|
||||||
|
ToolbarItems.Add(saveToolBarItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultAddSitePage : ContentPage
|
||||||
|
{
|
||||||
|
public VaultAddSitePage()
|
||||||
|
{
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
var siteService = Resolver.Resolve<ISiteService>();
|
||||||
|
|
||||||
|
var uriEntry = new Entry { Keyboard = Keyboard.Url };
|
||||||
|
var nameEntry = new Entry();
|
||||||
|
var folderEntry = new Entry { };
|
||||||
|
var usernameEntry = new Entry();
|
||||||
|
var passwordEntry = new Entry { IsPassword = true };
|
||||||
|
var notesEditor = new Editor();
|
||||||
|
|
||||||
|
var stackLayout = new StackLayout();
|
||||||
|
stackLayout.Children.Add(new Label { Text = "URI" });
|
||||||
|
stackLayout.Children.Add(uriEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Name" });
|
||||||
|
stackLayout.Children.Add(nameEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Folder" });
|
||||||
|
stackLayout.Children.Add(folderEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Username" });
|
||||||
|
stackLayout.Children.Add(usernameEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Password" });
|
||||||
|
stackLayout.Children.Add(passwordEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = "Notes" });
|
||||||
|
stackLayout.Children.Add(notesEditor);
|
||||||
|
|
||||||
|
var scrollView = new ScrollView
|
||||||
|
{
|
||||||
|
Content = stackLayout,
|
||||||
|
Orientation = ScrollOrientation.Vertical
|
||||||
|
};
|
||||||
|
|
||||||
|
var saveToolBarItem = new ToolbarItem("Save", null, async () =>
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(uriEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", "The Uri field is required.", "Ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(nameEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert("An error has occurred", "The Name field is required.", "Ok");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var site = new Site
|
||||||
|
{
|
||||||
|
Uri = uriEntry.Text.Encrypt(),
|
||||||
|
Name = nameEntry.Text.Encrypt(),
|
||||||
|
Username = usernameEntry.Text?.Encrypt(),
|
||||||
|
Password = passwordEntry.Text?.Encrypt(),
|
||||||
|
Notes = notesEditor.Text?.Encrypt()
|
||||||
|
};
|
||||||
|
|
||||||
|
await siteService.SaveAsync(site);
|
||||||
|
await Navigation.PopAsync();
|
||||||
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
|
Title = "Add Site";
|
||||||
|
Content = scrollView;
|
||||||
|
ToolbarItems.Add(saveToolBarItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultEditFolderPage : ContentPage
|
||||||
|
{
|
||||||
|
public VaultEditFolderPage()
|
||||||
|
{
|
||||||
|
Title = "Edit Folder";
|
||||||
|
Content = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultEditSitePage : ContentPage
|
||||||
|
{
|
||||||
|
public VaultEditSitePage()
|
||||||
|
{
|
||||||
|
Title = "Edit Site";
|
||||||
|
Content = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.View;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultListPage : ContentPage
|
||||||
|
{
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly ISiteService _siteService;
|
||||||
|
private ListView _listView;
|
||||||
|
|
||||||
|
public VaultListPage()
|
||||||
|
{
|
||||||
|
_folderService = Resolver.Resolve<IFolderService>();
|
||||||
|
_siteService = Resolver.Resolve<ISiteService>();
|
||||||
|
|
||||||
|
var addSiteToolBarItem = new ToolbarItem("+", null, async () =>
|
||||||
|
{
|
||||||
|
var addSitePage = new VaultAddSitePage();
|
||||||
|
await Navigation.PushAsync(addSitePage);
|
||||||
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
|
ToolbarItems.Add(addSiteToolBarItem);
|
||||||
|
|
||||||
|
_listView = new ListView
|
||||||
|
{
|
||||||
|
IsGroupingEnabled = true,
|
||||||
|
GroupDisplayBinding = new Binding("Name")
|
||||||
|
};
|
||||||
|
|
||||||
|
_listView.ItemSelected += FolderSelected;
|
||||||
|
_listView.ItemTemplate = new DataTemplate(() =>
|
||||||
|
{
|
||||||
|
var cell = new TextCell();
|
||||||
|
cell.SetBinding<VaultView.Site>(TextCell.TextProperty, s => s.Name);
|
||||||
|
cell.SetBinding<VaultView.Site>(TextCell.DetailProperty, s => s.Username);
|
||||||
|
return cell;
|
||||||
|
});
|
||||||
|
|
||||||
|
Title = "My Vault";
|
||||||
|
Content = _listView;
|
||||||
|
NavigationPage.SetHasBackButton(this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnAppearing()
|
||||||
|
{
|
||||||
|
base.OnAppearing();
|
||||||
|
|
||||||
|
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult();
|
||||||
|
var sites = _siteService.GetAllAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
var folderItems = folders.Select(f => new VaultView.Folder(f, sites.Where(s => s.FolderId == f.Id))).ToList();
|
||||||
|
// add the sites with no folder
|
||||||
|
folderItems.Add(new VaultView.Folder(sites.Where(s => !s.FolderId.HasValue)));
|
||||||
|
_listView.ItemsSource = folderItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FolderSelected(object sender, SelectedItemChangedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Views
|
||||||
|
{
|
||||||
|
public class VaultViewSitePage : ContentPage
|
||||||
|
{
|
||||||
|
private int _siteId;
|
||||||
|
|
||||||
|
public VaultViewSitePage(int siteId)
|
||||||
|
{
|
||||||
|
_siteId = siteId;
|
||||||
|
|
||||||
|
Title = "View Site";
|
||||||
|
Content = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Resources;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Bit.App")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("bitwarden")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: NeutralResourcesLanguage("en")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
using ModernHttpClient;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class ApiService : IApiService
|
||||||
|
{
|
||||||
|
public ApiService()
|
||||||
|
{
|
||||||
|
Client = new HttpClient(new NativeMessageHandler());
|
||||||
|
Client.BaseAddress = new Uri("https://api.bitwarden.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client { get; set; }
|
||||||
|
|
||||||
|
public async Task<ApiResult<T>> HandleErrorAsync<T>(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var error = new ApiError
|
||||||
|
{
|
||||||
|
Message = "An unknown error has occured.",
|
||||||
|
StatusCode = response.StatusCode
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
var errorResponseModel = JsonConvert.DeserializeObject<ErrorResponse>(responseContent);
|
||||||
|
error.Message = errorResponseModel.Message;
|
||||||
|
}
|
||||||
|
catch(JsonReaderException) { }
|
||||||
|
|
||||||
|
return ApiResult<T>.Failed(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Api;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class AuthService : IAuthService
|
||||||
|
{
|
||||||
|
private const string TokenKey = "token";
|
||||||
|
|
||||||
|
private readonly ISecureStorageService _secureStorage;
|
||||||
|
private readonly ICryptoService _cryptoService;
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
|
||||||
|
public AuthService(
|
||||||
|
ISecureStorageService secureStorage,
|
||||||
|
ICryptoService cryptoService,
|
||||||
|
IApiService apiService)
|
||||||
|
{
|
||||||
|
_secureStorage = secureStorage;
|
||||||
|
_cryptoService = cryptoService;
|
||||||
|
_apiService = apiService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var tokenBytes = _secureStorage.Retrieve(TokenKey);
|
||||||
|
return Encoding.UTF8.GetString(tokenBytes, 0, tokenBytes.Length);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
var tokenBytes = Encoding.UTF8.GetBytes(value);
|
||||||
|
_secureStorage.Store(TokenKey, tokenBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_secureStorage.Delete(TokenKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAuthenticated
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _cryptoService.Key != null && Token != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResult<TokenResponse>> TokenPostAsync(TokenRequest request)
|
||||||
|
{
|
||||||
|
var requestContent = JsonConvert.SerializeObject(request);
|
||||||
|
var response = await _apiService.Client.PostAsync("/auth/token", new StringContent(requestContent, Encoding.UTF8, "application/json"));
|
||||||
|
if(!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return await _apiService.HandleErrorAsync<TokenResponse>(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
var responseObj = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
|
||||||
|
return ApiResult<TokenResponse>.Success(responseObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Org.BouncyCastle.Crypto.Digests;
|
||||||
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
|
using Org.BouncyCastle.Crypto.Generators;
|
||||||
|
using Org.BouncyCastle.Crypto.Modes;
|
||||||
|
using Org.BouncyCastle.Crypto.Paddings;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class CryptoService : ICryptoService
|
||||||
|
{
|
||||||
|
private const string KeyKey = "key";
|
||||||
|
private const int InitializationVectorSize = 16;
|
||||||
|
private const int KeySize = 256;
|
||||||
|
private const int Iterations = 5000;
|
||||||
|
|
||||||
|
private readonly PaddedBufferedBlockCipher _cipher;
|
||||||
|
private readonly ISecureStorageService _secureStorage;
|
||||||
|
private KeyParameter _keyParameter;
|
||||||
|
|
||||||
|
public CryptoService(ISecureStorageService secureStorage)
|
||||||
|
{
|
||||||
|
var engine = new AesEngine();
|
||||||
|
var blockCipher = new CbcBlockCipher(engine);
|
||||||
|
_cipher = new PaddedBufferedBlockCipher(blockCipher);
|
||||||
|
|
||||||
|
_secureStorage = secureStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Key
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_keyParameter != null)
|
||||||
|
{
|
||||||
|
_keyParameter.GetKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
var storedKey = _secureStorage.Retrieve(KeyKey);
|
||||||
|
if(storedKey == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_keyParameter = new KeyParameter(storedKey);
|
||||||
|
return _keyParameter.GetKey();
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_secureStorage.Store(KeyKey, value);
|
||||||
|
_keyParameter = new KeyParameter(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Base64Key { get { return Convert.ToBase64String(Key); } }
|
||||||
|
|
||||||
|
public CipherString Encrypt(string plaintextValue)
|
||||||
|
{
|
||||||
|
if(Key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(plaintextValue == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(plaintextValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
|
||||||
|
|
||||||
|
var iv = GenerateRandomInitializationVector();
|
||||||
|
var keyParamWithIV = new ParametersWithIV(_keyParameter, iv, 0, InitializationVectorSize);
|
||||||
|
|
||||||
|
_cipher.Init(true, keyParamWithIV);
|
||||||
|
var encryptedBytes = new byte[_cipher.GetOutputSize(plaintextBytes.Length)];
|
||||||
|
var length = _cipher.ProcessBytes(plaintextBytes, encryptedBytes, 0);
|
||||||
|
_cipher.DoFinal(encryptedBytes, length);
|
||||||
|
|
||||||
|
return new CipherString(Convert.ToBase64String(iv), Convert.ToBase64String(encryptedBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Decrypt(CipherString encyptedValue)
|
||||||
|
{
|
||||||
|
if(Key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encyptedValue == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(encyptedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyParamWithIV = new ParametersWithIV(_keyParameter, encyptedValue.InitializationVectorBytes, 0, InitializationVectorSize);
|
||||||
|
|
||||||
|
_cipher.Init(false, keyParamWithIV);
|
||||||
|
byte[] comparisonBytes = new byte[_cipher.GetOutputSize(encyptedValue.CipherTextBytes.Length)];
|
||||||
|
var length = _cipher.ProcessBytes(encyptedValue.CipherTextBytes, comparisonBytes, 0);
|
||||||
|
_cipher.DoFinal(comparisonBytes, length);
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length).TrimEnd('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] MakeKeyFromPassword(string password, string salt)
|
||||||
|
{
|
||||||
|
if(password == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(salt == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(salt));
|
||||||
|
}
|
||||||
|
|
||||||
|
var passwordBytes = Encoding.UTF8.GetBytes(password);
|
||||||
|
var saltBytes = Encoding.UTF8.GetBytes(salt);
|
||||||
|
|
||||||
|
var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest());
|
||||||
|
generator.Init(passwordBytes, saltBytes, Iterations);
|
||||||
|
return ((KeyParameter)generator.GenerateDerivedMacParameters(KeySize)).GetKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string MakeKeyFromPasswordBase64(string password, string salt)
|
||||||
|
{
|
||||||
|
var key = MakeKeyFromPassword(password, salt);
|
||||||
|
return Convert.ToBase64String(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] HashPassword(byte[] key, string password)
|
||||||
|
{
|
||||||
|
if(key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(Key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(password == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
var passwordBytes = Encoding.UTF8.GetBytes(password);
|
||||||
|
|
||||||
|
var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest());
|
||||||
|
generator.Init(key, passwordBytes, 1);
|
||||||
|
return ((KeyParameter)generator.GenerateDerivedMacParameters(KeySize)).GetKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string HashPasswordBase64(byte[] key, string password)
|
||||||
|
{
|
||||||
|
var hash = HashPassword(key, password);
|
||||||
|
return Convert.ToBase64String(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GenerateRandomInitializationVector()
|
||||||
|
{
|
||||||
|
var rand = new Random();
|
||||||
|
var iv = new byte[InitializationVectorSize];
|
||||||
|
rand.NextBytes(iv);
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class DatabaseService : IDatabaseService
|
||||||
|
{
|
||||||
|
protected readonly SQLiteConnection _connection;
|
||||||
|
|
||||||
|
public DatabaseService(ISqlService sqlService)
|
||||||
|
{
|
||||||
|
_connection = sqlService.GetConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateTables()
|
||||||
|
{
|
||||||
|
_connection.CreateTable<FolderData>();
|
||||||
|
_connection.CreateTable<SiteData>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class FolderService : Repository<FolderData, int>, IFolderService
|
||||||
|
{
|
||||||
|
public FolderService(ISqlService sqlite)
|
||||||
|
: base(sqlite) { }
|
||||||
|
|
||||||
|
public new async Task<IEnumerable<Folder>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var data = await base.GetAllAsync();
|
||||||
|
return data.Select(f => new Folder(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveAsync(Folder folder)
|
||||||
|
{
|
||||||
|
var data = new FolderData(folder);
|
||||||
|
data.RevisionDateTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if(folder.Id == 0)
|
||||||
|
{
|
||||||
|
await CreateAsync(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplaceAsync(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.Id = data.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public abstract class Repository<T, TId>
|
||||||
|
where TId : IEquatable<TId>
|
||||||
|
where T : class, IDataObject<TId>, new()
|
||||||
|
{
|
||||||
|
protected readonly SQLiteConnection _connection;
|
||||||
|
|
||||||
|
public Repository(ISqlService sqlite)
|
||||||
|
{
|
||||||
|
_connection = sqlite.GetConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task<T> GetByIdAsync(TId id)
|
||||||
|
{
|
||||||
|
return Task.FromResult(_connection.Get<T>(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task<IEnumerable<T>> GetAllAsync()
|
||||||
|
{
|
||||||
|
return Task.FromResult(_connection.Table<T>().Cast<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task CreateAsync(T obj)
|
||||||
|
{
|
||||||
|
_connection.Insert(obj);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task ReplaceAsync(T obj)
|
||||||
|
{
|
||||||
|
_connection.Update(obj);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task DeleteAsync(T obj)
|
||||||
|
{
|
||||||
|
_connection.Delete<T>(obj.Id);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Bit.App.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class SiteService : Repository<SiteData, int>, ISiteService
|
||||||
|
{
|
||||||
|
public SiteService(ISqlService sqlite)
|
||||||
|
: base(sqlite) { }
|
||||||
|
|
||||||
|
public new async Task<IEnumerable<Site>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var data = await base.GetAllAsync();
|
||||||
|
return data.Select(s => new Site(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveAsync(Site site)
|
||||||
|
{
|
||||||
|
var data = new SiteData(site);
|
||||||
|
data.RevisionDateTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if(site.Id == 0)
|
||||||
|
{
|
||||||
|
await CreateAsync(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplaceAsync(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
site.Id = data.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public static class Extentions
|
||||||
|
{
|
||||||
|
public static CipherString Encrypt(this string s)
|
||||||
|
{
|
||||||
|
if(s == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
return cryptoService.Encrypt(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="CommonServiceLocator" version="1.3" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="modernhttpclient" version="2.4.2" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="Newtonsoft.Json" version="8.0.3" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="Portable.BouncyCastle" version="1.8.1" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
<package id="XLabs.IoC" version="2.0.5782" targetFramework="portable45-net45+win8+wpa81" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
using XLabs.Ioc.Unity;
|
||||||
|
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Services;
|
||||||
|
using Microsoft.Practices.Unity;
|
||||||
|
using Bit.iOS.Services;
|
||||||
|
|
||||||
|
namespace Bit.iOS
|
||||||
|
{
|
||||||
|
// The UIApplicationDelegate for the application. This class is responsible for launching the
|
||||||
|
// User Interface of the application, as well as listening (and optionally responding) to
|
||||||
|
// application events from iOS.
|
||||||
|
[Register("AppDelegate")]
|
||||||
|
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// This method is invoked when the application has loaded and is ready to run. In this
|
||||||
|
// method you should instantiate the window, load the UI into it and then make the window
|
||||||
|
// visible.
|
||||||
|
//
|
||||||
|
// You have 17 seconds to return from this method, or iOS will terminate your application.
|
||||||
|
//
|
||||||
|
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
|
||||||
|
{
|
||||||
|
global::Xamarin.Forms.Forms.Init();
|
||||||
|
|
||||||
|
if(!Resolver.IsSet)
|
||||||
|
{
|
||||||
|
SetIoc();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadApplication(new App.App(Resolver.Resolve<IAuthService>(), Resolver.Resolve<IDatabaseService>()));
|
||||||
|
|
||||||
|
return base.FinishedLaunching(app, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetIoc()
|
||||||
|
{
|
||||||
|
var container = new UnityContainer();
|
||||||
|
|
||||||
|
container
|
||||||
|
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ISecureStorageService, KeyChainStorageService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IApiService, ApiService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ICryptoService, CryptoService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IAuthService, AuthService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<IFolderService, FolderService>(new ContainerControlledLifetimeManager())
|
||||||
|
.RegisterType<ISiteService, SiteService>(new ContainerControlledLifetimeManager());
|
||||||
|
|
||||||
|
Resolver.SetResolver(new UnityResolver(container));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict/>
|
||||||
|
</plist>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>UIDeviceFamily</key>
|
||||||
|
<array>
|
||||||
|
<integer>1</integer>
|
||||||
|
<integer>2</integer>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>8.0</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>bitwarden</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.bitwarden.bitwarden</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleIconFiles</key>
|
||||||
|
<array>
|
||||||
|
<string>Icon-60@2x.png</string>
|
||||||
|
<string>Icon-76.png</string>
|
||||||
|
<string>Icon-76@2x.png</string>
|
||||||
|
<string>Default.png</string>
|
||||||
|
<string>Default@2x.png</string>
|
||||||
|
<string>Default-568h@2x.png</string>
|
||||||
|
<string>Default-Portrait.png</string>
|
||||||
|
<string>Default-Portrait@2x.png</string>
|
||||||
|
<string>Icon-Small-40.png</string>
|
||||||
|
<string>Icon-Small-40@2x.png</string>
|
||||||
|
<string>Icon-Small.png</string>
|
||||||
|
<string>Icon-Small@2x.png</string>
|
||||||
|
</array>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>0.0.1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS
|
||||||
|
{
|
||||||
|
public class Application
|
||||||
|
{
|
||||||
|
// This is the main entry point of the application.
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// if you want to use a different Application Delegate class from "AppDelegate"
|
||||||
|
// you can specify it here.
|
||||||
|
UIApplication.Main(args, null, "AppDelegate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Bit.iOS")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("bitwarden")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 729 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 955 B |
After Width: | Height: | Size: 7.1 KiB |
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="X5k-f2-b5h">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="gAE-YM-kbH">
|
||||||
|
<objects>
|
||||||
|
<viewController id="X5k-f2-b5h" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Y8P-hJ-Z43"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="9ZL-r4-8FZ"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="yd7-JS-zBw">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="Icon-60.png" translatesAutoresizingMaskIntoConstraints="NO" id="23">
|
||||||
|
<rect key="frame" x="270" y="270" width="60" height="60"/>
|
||||||
|
<rect key="contentStretch" x="0.0" y="0.0" width="0.0" height="0.0"/>
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="0.20392156862745098" green="0.59607843137254901" blue="0.85882352941176465" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="23" firstAttribute="centerY" secondItem="yd7-JS-zBw" secondAttribute="centerY" priority="1" id="39"/>
|
||||||
|
<constraint firstItem="23" firstAttribute="centerX" secondItem="yd7-JS-zBw" secondAttribute="centerX" priority="1" id="41"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="XAI-xm-WK6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="349" y="339"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="Icon-60.png" width="180" height="180"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
|
@ -0,0 +1,91 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Foundation;
|
||||||
|
using Security;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Services
|
||||||
|
{
|
||||||
|
public class KeyChainStorageService : ISecureStorageService
|
||||||
|
{
|
||||||
|
public void Store(string key, byte[] dataBytes)
|
||||||
|
{
|
||||||
|
using(var data = NSData.FromArray(dataBytes))
|
||||||
|
using(var newRecord = GetKeyRecord(key, data))
|
||||||
|
{
|
||||||
|
Delete(key);
|
||||||
|
CheckError(SecKeyChain.Add(newRecord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Retrieve(string key)
|
||||||
|
{
|
||||||
|
SecStatusCode resultCode;
|
||||||
|
|
||||||
|
using(var existingRecord = GetKeyRecord(key))
|
||||||
|
using(var record = SecKeyChain.QueryAsRecord(existingRecord, out resultCode))
|
||||||
|
{
|
||||||
|
if(resultCode == SecStatusCode.ItemNotFound)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckError(resultCode);
|
||||||
|
return record.Generic.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(string key)
|
||||||
|
{
|
||||||
|
using(var record = GetExistingRecord(key))
|
||||||
|
{
|
||||||
|
if(record != null)
|
||||||
|
{
|
||||||
|
CheckError(SecKeyChain.Remove(record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string key)
|
||||||
|
{
|
||||||
|
using(var existingRecord = GetExistingRecord(key))
|
||||||
|
{
|
||||||
|
return existingRecord != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckError(SecStatusCode resultCode, [CallerMemberName] string caller = null)
|
||||||
|
{
|
||||||
|
if(resultCode != SecStatusCode.Success)
|
||||||
|
{
|
||||||
|
throw new Exception(string.Format("Failed to execute {0}. Result code: {1}", caller, resultCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecRecord GetKeyRecord(string key, NSData data = null)
|
||||||
|
{
|
||||||
|
var record = new SecRecord(SecKind.GenericPassword)
|
||||||
|
{
|
||||||
|
Service = NSBundle.MainBundle.BundleIdentifier,
|
||||||
|
Account = key
|
||||||
|
};
|
||||||
|
|
||||||
|
if(data != null)
|
||||||
|
{
|
||||||
|
record.Generic = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecRecord GetExistingRecord(string key)
|
||||||
|
{
|
||||||
|
var existingRecord = GetKeyRecord(key);
|
||||||
|
|
||||||
|
SecStatusCode resultCode;
|
||||||
|
SecKeyChain.QueryAsRecord(existingRecord, out resultCode);
|
||||||
|
|
||||||
|
return resultCode == SecStatusCode.Success ? existingRecord : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Services
|
||||||
|
{
|
||||||
|
public class SqlService : ISqlService
|
||||||
|
{
|
||||||
|
public SQLite.SQLiteConnection GetConnection()
|
||||||
|
{
|
||||||
|
var sqliteFilename = "bitwarden.db3";
|
||||||
|
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
|
||||||
|
var libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder
|
||||||
|
var path = Path.Combine(libraryPath, sqliteFilename);
|
||||||
|
|
||||||
|
Console.WriteLine(path);
|
||||||
|
var conn = new SQLite.SQLiteConnection(path);
|
||||||
|
|
||||||
|
// Return the database connection
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
|
||||||
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{1F78403F-9A28-405B-9289-B9DBEB55F074}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Bit.iOS</RootNamespace>
|
||||||
|
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
|
||||||
|
<AssemblyName>BitiOS</AssemblyName>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
<MtouchArch>i386, x86_64</MtouchArch>
|
||||||
|
<MtouchLink>None</MtouchLink>
|
||||||
|
<MtouchDebug>true</MtouchDebug>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<MtouchLink>None</MtouchLink>
|
||||||
|
<MtouchArch>i386, x86_64</MtouchArch>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\iPhone\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||||
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
|
<MtouchDebug>true</MtouchDebug>
|
||||||
|
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\iPhone\Release</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
|
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>True</Optimize>
|
||||||
|
<OutputPath>bin\iPhone\Ad-Hoc</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>False</ConsolePause>
|
||||||
|
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||||
|
<BuildIpa>True</BuildIpa>
|
||||||
|
<CodesignProvision>Automatic:AdHoc</CodesignProvision>
|
||||||
|
<CodesignKey>iPhone Distribution</CodesignKey>
|
||||||
|
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<Optimize>True</Optimize>
|
||||||
|
<OutputPath>bin\iPhone\AppStore</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>False</ConsolePause>
|
||||||
|
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||||
|
<CodesignProvision>Automatic:AppStore</CodesignProvision>
|
||||||
|
<CodesignKey>iPhone Distribution</CodesignKey>
|
||||||
|
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Services\KeyChainStorageService.cs" />
|
||||||
|
<Compile Include="Main.cs" />
|
||||||
|
<Compile Include="AppDelegate.cs" />
|
||||||
|
<Compile Include="Services\SqlService.cs" />
|
||||||
|
<None Include="Entitlements.plist" />
|
||||||
|
<None Include="Info.plist" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<ITunesArtwork Include="iTunesArtwork" />
|
||||||
|
<ITunesArtwork Include="iTunesArtwork@2x" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BundleResource Include="Resources\Default-568h%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Default-Portrait.png" />
|
||||||
|
<BundleResource Include="Resources\Default-Portrait%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Default.png" />
|
||||||
|
<BundleResource Include="Resources\Default%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-60%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-60%403x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-76.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-76%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small-40.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small-40%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small-40%403x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small%402x.png" />
|
||||||
|
<BundleResource Include="Resources\Icon-Small%403x.png" />
|
||||||
|
<InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Practices.Unity, Version=3.5.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Unity.3.5.1405-prerelease\lib\portable-net45+wp80+win8+wpa81+MonoAndroid10+MonoTouch10\Microsoft.Practices.Unity.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ModernHttpClient, Version=2.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\modernhttpclient.2.4.2\lib\Xamarin.iOS10\ModernHttpClient.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\sqlite-net-pcl.1.1.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Platform.iOS, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Xamarin.Forms.2.2.0.31\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Xamarin.iOS" />
|
||||||
|
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="XLabs.Ioc.Unity, Version=2.0.5782.12230, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\XLabs.IoC.Unity.2.0.5782\lib\portable-net45+netcore45+wp8+MonoAndroid1+MonoTouch1\XLabs.Ioc.Unity.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\App\App.csproj">
|
||||||
|
<Project>{b490c5da-639e-4994-abd2-54222b8a348e}</Project>
|
||||||
|
<Name>App</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\packages\SQLitePCL.raw.0.8.6\build\Xamarin.iOS10\SQLitePCL.raw.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCL.raw.0.8.6\build\Xamarin.iOS10\SQLitePCL.raw.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<Import Project="..\..\packages\SQLitePCL.raw.0.8.6\build\Xamarin.iOS10\SQLitePCL.raw.targets" Condition="Exists('..\..\packages\SQLitePCL.raw.0.8.6\build\Xamarin.iOS10\SQLitePCL.raw.targets')" />
|
||||||
|
<Import Project="..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.2.0.31\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
|
||||||
|
</Project>
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="CommonServiceLocator" version="1.3" targetFramework="xamarinios10" />
|
||||||
|
<package id="modernhttpclient" version="2.4.2" targetFramework="xamarinios10" />
|
||||||
|
<package id="sqlite-net-pcl" version="1.1.1" targetFramework="xamarinios10" />
|
||||||
|
<package id="SQLitePCL.raw" version="0.8.6" targetFramework="xamarinios10" />
|
||||||
|
<package id="Unity" version="3.5.1405-prerelease" targetFramework="xamarinios10" />
|
||||||
|
<package id="Xamarin.Forms" version="2.2.0.31" targetFramework="xamarinios10" />
|
||||||
|
<package id="XLabs.IoC" version="2.0.5782" targetFramework="xamarinios10" />
|
||||||
|
<package id="XLabs.IoC.Unity" version="2.0.5782" targetFramework="xamarinios10" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{A300DCE1-8D10-4267-B96A-CB01AEB7C220}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Bit.App.Test</RootNamespace>
|
||||||
|
<AssemblyName>Bit.App.Test</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||||
|
<IsCodedUITest>False</IsCodedUITest>
|
||||||
|
<TestProjectType>UnitTest</TestProjectType>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="NSubstitute, Version=1.10.0.0, Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="xunit.assert, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="xunit.core, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="xunit.execution.desktop, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise />
|
||||||
|
</Choose>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="CryptoServiceTests.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\App\App.csproj">
|
||||||
|
<Project>{b490c5da-639e-4994-abd2-54222b8a348e}</Project>
|
||||||
|
<Name>App</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Services;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.App.Test
|
||||||
|
{
|
||||||
|
public class CryptoServiceTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void MakeKeyFromPasswordBase64()
|
||||||
|
{
|
||||||
|
var service = new CryptoService(Substitute.For<ISecureStorageService>());
|
||||||
|
var key = service.MakeKeyFromPasswordBase64("123456", "salt");
|
||||||
|
Assert.Equal(key, GetKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HashPasswordBase64()
|
||||||
|
{
|
||||||
|
var service = new CryptoService(Substitute.For<ISecureStorageService>());
|
||||||
|
var key = Convert.FromBase64String(GetKey());
|
||||||
|
var hash = service.HashPasswordBase64(key, "123456");
|
||||||
|
Assert.Equal(hash, "7Bsl4ponrsFu0jGl4yMeLZp5tKqx6g4tLrXhMszIsjQ=");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EncryptDecrypt()
|
||||||
|
{
|
||||||
|
var value = "hi";
|
||||||
|
Assert.Equal(EncryptDecryptValue(value), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EncryptDecryptLongValue()
|
||||||
|
{
|
||||||
|
var value = "This is a really long value that should encrypt and decrypt just fine too.";
|
||||||
|
Assert.Equal(EncryptDecryptValue(value), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EncryptDecryptValue(string value)
|
||||||
|
{
|
||||||
|
var storage = Substitute.For<ISecureStorageService>();
|
||||||
|
storage.Retrieve("key").Returns(Convert.FromBase64String(GetKey()));
|
||||||
|
|
||||||
|
var service = new CryptoService(storage);
|
||||||
|
var encryptedHi = service.Encrypt(value);
|
||||||
|
return service.Decrypt(encryptedHi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetKey()
|
||||||
|
{
|
||||||
|
return "QpSYI5k0bLQXEygUEHn4wMII3ERatuWDFBszk7JAhbQ=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("App.Test")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("App.Test")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("a300dce1-8d10-4267-b96a-cb01aeb7c220")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="NSubstitute" version="1.10.0.0" targetFramework="net46" />
|
||||||
|
<package id="xunit" version="2.1.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.abstractions" version="2.0.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.assert" version="2.1.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.core" version="2.1.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net46" />
|
||||||
|
<package id="xunit.runner.visualstudio" version="2.1.0" targetFramework="net46" />
|
||||||
|
</packages>
|