2013-02-23 11:43:42 -05:00
/ *
This file is part of Keepass2Android , Copyright 2013 Philipp Crocoll . This file is based on Keepassdroid , Copyright Brian Pellin .
Keepass2Android is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2014-01-26 08:27:27 -05:00
the Free Software Foundation , either version 3 of the License , or
2013-02-23 11:43:42 -05:00
( at your option ) any later version .
Keepass2Android is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Keepass2Android . If not , see < http : //www.gnu.org/licenses/>.
* /
using System ;
2013-11-17 01:17:15 -05:00
using System.Collections.Generic ;
2013-11-20 13:14:57 -05:00
using System.IO ;
2013-07-17 14:19:17 -04:00
using System.Threading.Tasks ;
2013-11-20 13:14:57 -05:00
using System.Xml ;
using System.Xml.Serialization ;
2016-01-02 15:29:26 -05:00
using Android ;
2013-02-23 11:43:42 -05:00
using Android.App ;
using Android.Content ;
2013-11-17 01:17:15 -05:00
using Android.Database ;
2014-11-08 15:29:36 -05:00
using Android.Graphics.Drawables ;
2013-02-23 11:43:42 -05:00
using Android.OS ;
using Android.Runtime ;
using Android.Views ;
2015-02-17 00:05:48 -05:00
using Android.Views.InputMethods ;
2013-02-23 11:43:42 -05:00
using Android.Widget ;
using Java.Net ;
using Android.Preferences ;
using Android.Text ;
using Android.Content.PM ;
2015-08-10 02:07:42 -04:00
using Android.Graphics ;
2016-01-02 06:31:30 -05:00
using Android.Hardware.Fingerprints ;
using Android.Provider ;
2015-08-10 02:07:42 -04:00
using Android.Support.Design.Widget ;
using Android.Support.V4.Widget ;
using Android.Support.V7.App ;
2016-01-02 06:31:30 -05:00
using Java.Lang ;
2015-08-10 02:07:42 -04:00
using keepass2android ;
2013-02-23 11:43:42 -05:00
using KeePassLib.Keys ;
using KeePassLib.Serialization ;
2013-11-20 13:14:57 -05:00
using KeePassLib.Utility ;
2014-05-29 14:28:49 -04:00
using Keepass2android.Pluginsdk ;
2013-11-17 01:17:15 -05:00
using OtpKeyProv ;
2013-10-07 00:28:06 -04:00
using keepass2android.Io ;
2013-11-17 01:17:15 -05:00
using keepass2android.Utils ;
2015-08-10 02:07:42 -04:00
2013-11-20 13:14:57 -05:00
using File = Java . IO . File ;
using FileNotFoundException = Java . IO . FileNotFoundException ;
2015-08-10 02:07:42 -04:00
2013-11-17 01:17:15 -05:00
using Object = Java . Lang . Object ;
using Process = Android . OS . Process ;
2015-08-10 02:07:42 -04:00
2014-03-25 15:51:41 -04:00
using KeeChallenge ;
2015-08-10 02:07:42 -04:00
using AlertDialog = Android . App . AlertDialog ;
2016-01-02 06:31:30 -05:00
using Enum = System . Enum ;
using Exception = System . Exception ;
using String = System . String ;
2015-09-15 15:45:04 -04:00
using Toolbar = Android . Support . V7 . Widget . Toolbar ;
2013-02-23 11:43:42 -05:00
namespace keepass2android
{
2014-01-28 01:47:08 -05:00
[ Activity ( Label = "@string/app_name" ,
2015-09-15 15:45:04 -04:00
ConfigurationChanges = ConfigChanges . Orientation ,
2014-01-28 01:47:08 -05:00
LaunchMode = LaunchMode . SingleInstance ,
2015-09-15 15:45:04 -04:00
WindowSoftInputMode = SoftInput . AdjustResize ,
Theme = "@style/MyTheme_Blue" ) ] /*caution: also contained in AndroidManifest.xml*/
2016-01-03 19:58:54 -05:00
[IntentFilter(new[] { "kp2a.action.PasswordActivity" } , Categories = new [ ] { Intent . CategoryDefault } ) ]
public class PasswordActivity : LockingActivity , IFingerprintAuthCallback
2016-01-02 06:31:30 -05:00
{
2013-11-17 01:17:15 -05:00
enum KeyProviders
{
//int values correspond to indices in passwordSpinner
None = 0 ,
KeyFile = 1 ,
2013-11-20 13:14:57 -05:00
Otp = 2 ,
2014-03-25 15:51:41 -04:00
OtpRecovery = 3 ,
2014-05-24 23:36:52 -04:00
Challenge = 4 ,
2014-03-25 15:51:41 -04:00
ChalRecovery = 5
2013-11-17 01:17:15 -05:00
}
2013-06-15 06:40:01 -04:00
public const String KeyDefaultFilename = "defaultFileName" ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
public const String KeyFilename = "fileName" ;
private const String KeyKeyfile = "keyFile" ;
2014-01-27 06:44:03 -05:00
private const String KeyPassword = "password" ;
2013-09-17 00:53:18 -04:00
public const String KeyServerusername = "serverCredUser" ;
public const String KeyServerpassword = "serverCredPwd" ;
public const String KeyServercredmode = "serverCredRememberMode" ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
private const String ViewIntent = "android.intent.action.VIEW" ;
2013-09-16 22:53:14 -04:00
private const string ShowpasswordKey = "ShowPassword" ;
2013-11-17 01:17:15 -05:00
private const string KeyProviderIdOtp = "KP2A-OTP" ;
2013-11-20 13:14:57 -05:00
private const string KeyProviderIdOtpRecovery = "KP2A-OTPSecret" ;
2014-03-25 15:51:41 -04:00
private const string KeyProviderIdChallenge = "KP2A-Chal" ;
private const string KeyProviderIdChallengeRecovery = "KP2A-ChalSecret" ;
2013-11-20 13:14:57 -05:00
private const int RequestCodePrepareDbFile = 1000 ;
private const int RequestCodePrepareOtpAuxFile = 1001 ;
2014-04-02 00:57:04 -04:00
private const int RequestCodeChallengeYubikey = 1002 ;
2014-11-08 15:29:36 -05:00
private const int RequestCodeSelectKeyfile = 1003 ;
2014-12-06 23:14:50 -05:00
private const int RequestCodePrepareKeyFile = 1004 ;
2015-06-10 16:13:44 -04:00
private const int RequestCodeSelectAuxFile = 1005 ;
2014-12-06 23:14:50 -05:00
2013-07-25 08:47:05 -04:00
private Task < MemoryStream > _loadDbTask ;
2015-12-27 02:50:45 -05:00
private bool _loadDbTaskOffline ; //indicate if preloading was started with offline mode
2013-06-15 06:40:01 -04:00
private IOConnectionInfo _ioConnection ;
2013-11-17 01:17:15 -05:00
private String _keyFileOrProvider ;
2013-11-20 13:14:57 -05:00
bool _showPassword ;
2013-11-17 01:17:15 -05:00
internal AppTask AppTask ;
private bool _killOnDestroy ;
private string _password = "" ;
2013-11-17 11:01:53 -05:00
//OTPs which should be entered into the OTP fields as soon as these become visible
2013-11-20 13:14:57 -05:00
private List < String > _pendingOtps = new List < string > ( ) ;
2013-11-17 11:01:53 -05:00
2013-11-17 01:17:15 -05:00
KeyProviders KeyProviderType
{
get
{
if ( _keyFileOrProvider = = null )
return KeyProviders . None ;
if ( _keyFileOrProvider = = KeyProviderIdOtp )
return KeyProviders . Otp ;
2013-11-20 13:14:57 -05:00
if ( _keyFileOrProvider = = KeyProviderIdOtpRecovery )
return KeyProviders . OtpRecovery ;
2014-03-25 15:51:41 -04:00
if ( _keyFileOrProvider = = KeyProviderIdChallenge )
2014-05-24 23:36:52 -04:00
return KeyProviders . Challenge ;
2014-03-25 15:51:41 -04:00
if ( _keyFileOrProvider = = KeyProviderIdChallengeRecovery )
return KeyProviders . ChalRecovery ;
2013-11-17 01:17:15 -05:00
return KeyProviders . KeyFile ;
}
}
2013-06-15 06:40:01 -04:00
private bool _rememberKeyfile ;
ISharedPreferences _prefs ;
2013-02-23 11:43:42 -05:00
2013-08-10 14:49:59 -04:00
private bool _starting ;
2013-11-17 01:17:15 -05:00
private OtpInfo _otpInfo ;
2015-06-10 16:13:44 -04:00
private IOConnectionInfo _otpAuxIoc ;
2014-03-25 15:51:41 -04:00
private ChallengeInfo _chalInfo ;
2014-05-22 00:42:43 -04:00
private byte [ ] _challengeSecret ;
2015-02-09 15:56:05 -05:00
private KeeChallengeProv _challengeProv ;
2013-11-20 13:14:57 -05:00
private readonly int [ ] _otpTextViewIds = new [ ] { Resource . Id . otp1 , Resource . Id . otp2 , Resource . Id . otp3 , Resource . Id . otp4 , Resource . Id . otp5 , Resource . Id . otp6 } ;
private const string OtpInfoKey = "OtpInfoKey" ;
private const string EnteredOtpsKey = "EnteredOtpsKey" ;
private const string PendingOtpsKey = "PendingOtpsKey" ;
private const string PasswordKey = "PasswordKey" ;
private const string KeyFileOrProviderKey = "KeyFileOrProviderKey" ;
2013-08-07 13:34:43 -04:00
2014-03-25 15:51:41 -04:00
2014-03-31 01:24:02 -04:00
private bool _performingLoad ;
2015-01-05 22:01:46 -05:00
private bool _keepPasswordInOnResume ;
2015-08-10 02:07:42 -04:00
private Typeface _passwordFont ;
2015-01-05 22:01:46 -05:00
2015-08-10 02:07:42 -04:00
private ActionBarDrawerToggle mDrawerToggle ;
private DrawerLayout _drawerLayout ;
2014-02-02 01:03:40 -05:00
2015-08-10 02:07:42 -04:00
public PasswordActivity ( IntPtr javaReference , JniHandleOwnership transfer )
2013-02-23 11:43:42 -05:00
: base ( javaReference , transfer )
2015-12-21 23:42:02 -05:00
{
_activityDesign = new ActivityDesign ( this ) ;
}
2013-02-23 11:43:42 -05:00
public PasswordActivity ( )
{
2015-12-21 23:42:02 -05:00
_activityDesign = new ActivityDesign ( this ) ;
2013-02-23 11:43:42 -05:00
}
2013-09-17 00:53:18 -04:00
public static void PutIoConnectionToIntent ( IOConnectionInfo ioc , Intent i )
2013-02-23 11:43:42 -05:00
{
2013-06-15 06:40:01 -04:00
i . PutExtra ( KeyFilename , ioc . Path ) ;
i . PutExtra ( KeyServerusername , ioc . UserName ) ;
i . PutExtra ( KeyServerpassword , ioc . Password ) ;
i . PutExtra ( KeyServercredmode , ( int ) ioc . CredSaveMode ) ;
2013-02-23 11:43:42 -05:00
}
public static void SetIoConnectionFromIntent ( IOConnectionInfo ioc , Intent i )
{
2013-06-15 06:40:01 -04:00
ioc . Path = i . GetStringExtra ( KeyFilename ) ;
ioc . UserName = i . GetStringExtra ( KeyServerusername ) ? ? "" ;
ioc . Password = i . GetStringExtra ( KeyServerpassword ) ? ? "" ;
ioc . CredSaveMode = ( IOCredSaveMode ) i . GetIntExtra ( KeyServercredmode , ( int ) IOCredSaveMode . NoSave ) ;
2013-02-23 11:43:42 -05:00
}
2013-05-30 02:29:08 -04:00
public static void Launch ( Activity act , String fileName , AppTask appTask ) {
2013-06-15 06:40:01 -04:00
File dbFile = new File ( fileName ) ;
2013-02-23 11:43:42 -05:00
if ( ! dbFile . Exists ( ) ) {
2013-06-15 06:40:01 -04:00
throw new FileNotFoundException ( ) ;
2013-02-23 11:43:42 -05:00
}
Intent i = new Intent ( act , typeof ( PasswordActivity ) ) ;
2014-05-21 00:43:56 -04:00
i . SetFlags ( ActivityFlags . ForwardResult ) ;
2013-06-15 06:40:01 -04:00
i . PutExtra ( KeyFilename , fileName ) ;
2013-05-30 00:54:25 -04:00
appTask . ToIntent ( i ) ;
2013-11-17 11:01:53 -05:00
2014-05-21 00:43:56 -04:00
act . StartActivity ( i ) ;
2013-02-23 11:43:42 -05:00
}
2013-05-30 02:29:08 -04:00
public static void Launch ( Activity act , IOConnectionInfo ioc , AppTask appTask )
2013-02-23 11:43:42 -05:00
{
if ( ioc . IsLocalFile ( ) )
{
2013-05-30 00:54:25 -04:00
Launch ( act , ioc . Path , appTask ) ;
2013-02-23 11:43:42 -05:00
return ;
}
Intent i = new Intent ( act , typeof ( PasswordActivity ) ) ;
2013-11-17 11:01:53 -05:00
2013-02-23 11:43:42 -05:00
PutIoConnectionToIntent ( ioc , i ) ;
2014-05-21 00:43:56 -04:00
i . SetFlags ( ActivityFlags . ForwardResult ) ;
2013-02-23 11:43:42 -05:00
2013-05-30 00:54:25 -04:00
appTask . ToIntent ( i ) ;
2013-02-23 11:43:42 -05:00
2014-05-16 11:15:43 -04:00
act . StartActivity ( i ) ;
2013-02-23 11:43:42 -05:00
}
public void LaunchNextActivity ( )
{
2013-06-15 06:40:01 -04:00
AppTask . AfterUnlockDatabase ( this ) ;
2013-02-23 11:43:42 -05:00
}
protected override void OnActivityResult ( int requestCode , Result resultCode , Intent data )
{
base . OnActivityResult ( requestCode , resultCode , data ) ;
2015-01-05 22:01:46 -05:00
_keepPasswordInOnResume = true ;
2013-07-06 10:11:38 -04:00
Kp2aLog . Log ( "PasswordActivity.OnActivityResult " + resultCode + "/" + requestCode ) ;
2013-02-23 11:43:42 -05:00
2014-05-16 11:15:43 -04:00
AppTask . TryGetFromActivityResult ( data , ref AppTask ) ;
2013-02-23 11:43:42 -05:00
//NOTE: original code from k eepassdroid used switch ((Android.App.Result)requestCode) { (but doesn't work here, although k eepassdroid works)
switch ( resultCode ) {
2013-08-07 13:34:43 -04:00
2014-05-16 11:15:43 -04:00
case KeePass . ExitNormal : // Returned to this screen using the Back key
if ( PreferenceManager . GetDefaultSharedPreferences ( this )
. GetBoolean ( GetString ( Resource . String . LockWhenNavigateBack_key ) , false ) )
{
App . Kp2a . LockDatabase ( ) ;
}
//by leaving the app with the back button, the user probably wants to cancel the task
//The activity might be resumed (through Android's recent tasks list), then use a NullTask:
AppTask = new NullTask ( ) ;
Finish ( ) ;
2013-08-07 13:34:43 -04:00
break ;
2013-06-15 06:40:01 -04:00
case KeePass . ExitLock :
2013-08-03 14:58:01 -04:00
// The database has already been locked, and the quick unlock screen will be shown if appropriate
2014-12-16 23:58:55 -05:00
_rememberKeyfile = _prefs . GetBoolean ( GetString ( Resource . String . keyfile_key ) , Resources . GetBoolean ( Resource . Boolean . keyfile_default ) ) ; //update value
if ( ( KeyProviderType = = KeyProviders . KeyFile ) & & ( _rememberKeyfile ) )
{
//check if the keyfile was changed (by importing to internal directory)
var newKeyFile = GetKeyFile ( _ioConnection . Path ) ;
if ( newKeyFile ! = _keyFileOrProvider )
{
_keyFileOrProvider = newKeyFile ;
UpdateKeyfileIocView ( ) ;
}
}
2013-02-23 11:43:42 -05:00
break ;
2013-06-15 06:40:01 -04:00
case KeePass . ExitCloseAfterTaskComplete :
2013-08-07 13:34:43 -04:00
// Do not lock the database
2013-06-15 06:40:01 -04:00
SetResult ( KeePass . ExitCloseAfterTaskComplete ) ;
2013-02-23 11:43:42 -05:00
Finish ( ) ;
break ;
2013-09-03 15:57:13 -04:00
case KeePass . ExitClose :
SetResult ( KeePass . ExitClose ) ;
Finish ( ) ;
break ;
2013-06-15 06:40:01 -04:00
case KeePass . ExitReloadDb :
2014-12-19 15:26:18 -05:00
2013-06-14 00:14:50 -04:00
if ( App . Kp2a . GetDb ( ) . Loaded )
2013-03-15 02:07:45 -04:00
{
2014-12-19 15:26:18 -05:00
//remember the composite key for reloading:
var compositeKey = App . Kp2a . GetDb ( ) . KpDatabase . MasterKey ;
//lock the database:
App . Kp2a . LockDatabase ( false ) ;
//reload the database (without most other stuff performed in PerformLoadDatabase.
// We're assuming that the db file (and if appropriate also the key file) are still available
// and there's no need to re-init the file storage. if it is, loading will fail and the user has
// to retry with typing the full password, but that's intended to avoid showing the password to a
// a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
Handler handler = new Handler ( ) ;
OnFinish onFinish = new AfterLoad ( handler , this ) ;
_performingLoad = true ;
LoadDb task = new LoadDb ( App . Kp2a , _ioConnection , _loadDbTask , compositeKey , _keyFileOrProvider , onFinish ) ;
_loadDbTask = null ; // prevent accidental re-use
new ProgressTask ( App . Kp2a , this , task ) . Run ( ) ;
2013-03-15 02:07:45 -04:00
}
2014-12-19 15:26:18 -05:00
2013-03-15 02:07:45 -04:00
break ;
2014-11-08 15:29:36 -05:00
case Result . Ok :
if ( requestCode = = RequestCodeSelectKeyfile )
{
IOConnectionInfo ioc = new IOConnectionInfo ( ) ;
SetIoConnectionFromIntent ( ioc , data ) ;
_keyFileOrProvider = IOConnectionInfo . SerializeToString ( ioc ) ;
UpdateKeyfileIocView ( ) ;
2013-02-23 11:43:42 -05:00
}
break ;
2013-10-07 00:28:06 -04:00
case ( Result ) FileStorageResults . FileUsagePrepared :
2013-11-17 01:17:15 -05:00
if ( requestCode = = RequestCodePrepareDbFile )
2014-12-06 23:14:50 -05:00
{
if ( KeyProviderType = = KeyProviders . KeyFile )
{
2015-08-10 02:07:42 -04:00
//TODO: if the user has not yet selected a keyfile, _keyFileOrProvider is empty which
//gives an (unhandled) exception here
2014-12-06 23:14:50 -05:00
var iocKeyfile = IOConnectionInfo . UnserializeFromString ( _keyFileOrProvider ) ;
App . Kp2a . GetFileStorage ( iocKeyfile )
. PrepareFileUsage ( new FileStorageSetupInitiatorActivity ( this , OnActivityResult , null ) , iocKeyfile ,
RequestCodePrepareKeyFile , false ) ;
}
else
PerformLoadDatabase ( ) ;
}
if ( requestCode = = RequestCodePrepareKeyFile )
{
2013-11-17 01:17:15 -05:00
PerformLoadDatabase ( ) ;
2014-12-06 23:14:50 -05:00
}
2013-11-17 01:17:15 -05:00
if ( requestCode = = RequestCodePrepareOtpAuxFile )
2014-03-25 15:51:41 -04:00
{
2015-06-10 16:13:44 -04:00
GetAuxFileLoader ( ) . LoadAuxFile ( true ) ;
2014-03-25 15:51:41 -04:00
}
2014-04-02 00:57:04 -04:00
break ;
2013-02-23 11:43:42 -05:00
}
2015-06-10 16:13:44 -04:00
if ( requestCode = = RequestCodeSelectAuxFile & & resultCode = = Result . Ok )
{
IOConnectionInfo auxFileIoc = new IOConnectionInfo ( ) ;
SetIoConnectionFromIntent ( auxFileIoc , data ) ;
PreferenceManager . GetDefaultSharedPreferences ( this ) . Edit ( )
. PutString ( "KP2A.PasswordAct.AuxFileIoc" + IOConnectionInfo . SerializeToString ( _ioConnection ) ,
IOConnectionInfo . SerializeToString ( auxFileIoc ) )
. Apply ( ) ;
GetAuxFileLoader ( ) . LoadAuxFile ( false ) ;
}
2014-05-22 00:42:43 -04:00
if ( requestCode = = RequestCodeChallengeYubikey & & resultCode = = Result . Ok )
{
2014-06-06 00:23:36 -04:00
try
{
2015-02-09 15:56:05 -05:00
_challengeProv = new KeeChallengeProv ( ) ;
2014-06-06 00:23:36 -04:00
byte [ ] challengeResponse = data . GetByteArrayExtra ( "response" ) ;
2015-02-09 15:56:05 -05:00
_challengeSecret = _challengeProv . GetSecret ( _chalInfo , challengeResponse ) ;
2014-06-06 00:23:36 -04:00
Array . Clear ( challengeResponse , 0 , challengeResponse . Length ) ;
}
catch ( Exception e )
{
Kp2aLog . Log ( e . ToString ( ) ) ;
Toast . MakeText ( this , "Error: " + e . Message , ToastLength . Long ) . Show ( ) ;
return ;
}
2014-05-22 00:42:43 -04:00
UpdateOkButtonState ( ) ;
2014-05-24 23:36:52 -04:00
FindViewById ( Resource . Id . otpInitView ) . Visibility = ViewStates . Gone ;
2014-05-22 00:42:43 -04:00
if ( _challengeSecret ! = null )
{
new LoadingDialog < object , object , object > ( this , true ,
//doInBackground
delegate
{
//save aux file
try
{
2015-02-09 15:56:05 -05:00
ChallengeInfo temp = _challengeProv . Encrypt ( _challengeSecret ) ;
2014-05-22 00:42:43 -04:00
IFileStorage fileStorage = App . Kp2a . GetOtpAuxFileStorage ( _ioConnection ) ;
IOConnectionInfo iocAux = fileStorage . GetFilePath ( fileStorage . GetParentPath ( _ioConnection ) ,
fileStorage . GetFilenameWithoutPathAndExt ( _ioConnection ) + ".xml" ) ;
if ( ! temp . Save ( iocAux ) )
{
Toast . MakeText ( this , Resource . String . ErrorUpdatingChalAuxFile , ToastLength . Long ) . Show ( ) ;
return false ;
}
2014-06-06 00:23:36 -04:00
2014-05-22 00:42:43 -04:00
}
catch ( Exception e )
{
Kp2aLog . Log ( e . ToString ( ) ) ;
}
return null ;
}
, delegate
{
} ) . Execute ( ) ;
}
else
{
Toast . MakeText ( this , Resource . String . bad_resp , ToastLength . Long ) . Show ( ) ;
return ;
}
2013-02-23 11:43:42 -05:00
}
}
2015-06-10 16:13:44 -04:00
private AuxFileLoader GetAuxFileLoader ( )
{
if ( _keyFileOrProvider = = KeyProviderIdChallenge )
{
return new ChallengeAuxFileLoader ( this ) ;
}
else
{
return new OtpAuxFileLoader ( this ) ;
}
}
2014-11-08 15:29:36 -05:00
private void UpdateKeyfileIocView ( )
{
//store keyfile in the view so that we can show the selected keyfile again if the user switches to another key provider and back to key file
FindViewById < TextView > ( Resource . Id . label_keyfilename ) . Tag = _keyFileOrProvider ;
if ( string . IsNullOrEmpty ( _keyFileOrProvider ) )
{
FindViewById < TextView > ( Resource . Id . filestorage_label ) . Visibility = ViewStates . Gone ;
FindViewById < ImageView > ( Resource . Id . filestorage_logo ) . Visibility = ViewStates . Gone ;
FindViewById < TextView > ( Resource . Id . label_keyfilename ) . Text = Resources . GetString ( Resource . String . no_keyfile_selected ) ;
return ;
}
var ioc = IOConnectionInfo . UnserializeFromString ( _keyFileOrProvider ) ;
string displayPath = App . Kp2a . GetFileStorage ( ioc ) . GetDisplayName ( ioc ) ;
int protocolSeparatorPos = displayPath . IndexOf ( "://" , StringComparison . Ordinal ) ;
string protocolId = protocolSeparatorPos < 0 ?
"file" : displayPath . Substring ( 0 , protocolSeparatorPos ) ;
Drawable drawable = App . Kp2a . GetResourceDrawable ( "ic_storage_" + protocolId ) ;
FindViewById < ImageView > ( Resource . Id . filestorage_logo ) . SetImageDrawable ( drawable ) ;
FindViewById < ImageView > ( Resource . Id . filestorage_logo ) . Visibility = ViewStates . Visible ;
String title = App . Kp2a . GetResourceString ( "filestoragename_" + protocolId ) ;
FindViewById < TextView > ( Resource . Id . filestorage_label ) . Text = title ;
FindViewById < TextView > ( Resource . Id . filestorage_label ) . Visibility = ViewStates . Visible ;
FindViewById < TextView > ( Resource . Id . label_keyfilename ) . Text = protocolSeparatorPos < 0 ?
displayPath :
displayPath . Substring ( protocolSeparatorPos + 3 ) ;
}
2015-06-10 16:13:44 -04:00
private abstract class AuxFileLoader
2013-11-17 01:17:15 -05:00
{
2015-06-10 16:13:44 -04:00
protected readonly PasswordActivity Activity ;
protected AuxFileLoader ( PasswordActivity activity )
{
Activity = activity ;
}
public void LoadAuxFile ( bool triggerSelectAuxManuallyOnFailure )
{
new LoadingDialog < object , object , object > ( Activity , true ,
//doInBackground
delegate
2013-11-17 01:17:15 -05:00
{
2015-06-10 16:13:44 -04:00
try
{
var iocAux = GetDefaultAuxLocation ( ) ;
LoadFile ( iocAux ) ;
}
catch ( Exception e )
{
Kp2aLog . Log ( e . ToString ( ) ) ;
//retry with saved ioc
try
{
var savedManualIoc = IOConnectionInfo . UnserializeFromString (
PreferenceManager . GetDefaultSharedPreferences ( Activity ) . GetString (
"KP2A.PasswordAct.AuxFileIoc" + IOConnectionInfo . SerializeToString ( Activity . _ioConnection ) , null ) ) ;
LoadFile ( ( savedManualIoc ) ) ;
}
catch ( Exception e2 )
{
Kp2aLog . Log ( e2 . ToString ( ) ) ;
}
}
return null ;
2013-11-17 01:17:15 -05:00
}
2015-06-10 16:13:44 -04:00
, delegate
{
if ( ! AuxDataLoaded )
{
if ( triggerSelectAuxManuallyOnFailure )
{
Intent intent = new Intent ( Activity , typeof ( SelectStorageLocationActivity ) ) ;
intent . PutExtra ( FileStorageSelectionActivity . AllowThirdPartyAppGet , true ) ;
intent . PutExtra ( FileStorageSelectionActivity . AllowThirdPartyAppSend , false ) ;
intent . PutExtra ( FileStorageSetupDefs . ExtraIsForSave , false ) ;
intent . PutExtra ( SelectStorageLocationActivity . ExtraKeyWritableRequirements , ( int ) SelectStorageLocationActivity . WritableRequirements . WriteDemanded ) ;
Activity . StartActivityForResult ( intent , RequestCodeSelectAuxFile ) ;
}
else
{
Toast . MakeText ( Activity , GetErrorMessage ( ) , ToastLength . Long ) . Show ( ) ;
}
return ;
}
HandleSuccess ( ) ;
} ) . Execute ( ) ;
2013-11-17 11:01:53 -05:00
2015-06-10 16:13:44 -04:00
}
protected abstract bool AuxDataLoaded { get ; }
protected abstract void LoadFile ( IOConnectionInfo iocAux ) ;
protected abstract void HandleSuccess ( ) ;
protected abstract string GetErrorMessage ( ) ;
protected abstract IOConnectionInfo GetDefaultAuxLocation ( ) ;
2013-11-17 01:17:15 -05:00
}
2013-11-11 00:38:15 -05:00
2015-06-10 16:13:44 -04:00
private class OtpAuxFileLoader : AuxFileLoader
{
public OtpAuxFileLoader ( PasswordActivity activity ) : base ( activity )
{
}
protected override bool AuxDataLoaded
{
get { return Activity . _otpInfo ! = null ; }
}
protected override void LoadFile ( IOConnectionInfo iocAux )
{
Activity . _otpInfo = OtpInfo . Load ( iocAux ) ;
Activity . _otpAuxIoc = iocAux ;
}
private static IOConnectionInfo GetAuxFileIoc ( IOConnectionInfo databaseIoc )
{
IFileStorage fileStorage = App . Kp2a . GetOtpAuxFileStorage ( databaseIoc ) ;
var parentPath = fileStorage . GetParentPath ( databaseIoc ) ;
var filename = fileStorage . GetFilenameWithoutPathAndExt ( databaseIoc ) + OathHotpKeyProv . AuxFileExt ;
IOConnectionInfo iocAux = fileStorage . GetFilePath ( parentPath , filename ) ;
return iocAux ;
}
private static IOConnectionInfo GetAuxFileIoc ( KeyProviderQueryContext ctx )
{
IOConnectionInfo ioc = ctx . DatabaseIOInfo . CloneDeep ( ) ;
var iocAux = GetAuxFileIoc ( ioc ) ;
return iocAux ;
}
protected override void HandleSuccess ( )
{
IList < string > prefilledOtps = Activity . _pendingOtps ;
Activity . ShowOtpEntry ( prefilledOtps ) ;
Activity . _pendingOtps . Clear ( ) ;
}
protected override string GetErrorMessage ( )
{
return Activity . GetString ( Resource . String . CouldntLoadOtpAuxFile ) + " " +
Activity . GetString ( Resource . String . CouldntLoadOtpAuxFile_Hint ) ;
}
protected override IOConnectionInfo GetDefaultAuxLocation ( )
{
return GetAuxFileIoc ( Activity . _ioConnection ) ;
}
}
private class ChallengeAuxFileLoader : AuxFileLoader
{
public ChallengeAuxFileLoader ( PasswordActivity activity ) : base ( activity )
{
}
protected override void HandleSuccess ( )
{
Intent chalIntent = new Intent ( "com.yubichallenge.NFCActivity.CHALLENGE" ) ;
chalIntent . PutExtra ( "challenge" , Activity . _chalInfo . Challenge ) ;
chalIntent . PutExtra ( "slot" , 2 ) ;
IList < ResolveInfo > activities = Activity . PackageManager . QueryIntentActivities ( chalIntent , 0 ) ;
bool isIntentSafe = activities . Count > 0 ;
if ( isIntentSafe )
{
Activity . StartActivityForResult ( chalIntent , RequestCodeChallengeYubikey ) ;
}
else
{
AlertDialog . Builder b = new AlertDialog . Builder ( Activity ) ;
b . SetMessage ( Resource . String . YubiChallengeNotInstalled ) ;
b . SetPositiveButton ( Android . Resource . String . Ok ,
delegate
{
Util . GotoUrl ( Activity , Activity . GetString ( Resource . String . MarketURL ) + "com.yubichallenge" ) ;
} ) ;
b . SetNegativeButton ( Resource . String . cancel , delegate { } ) ;
b . Create ( ) . Show ( ) ;
}
}
protected override string GetErrorMessage ( )
{
return Activity . GetString ( Resource . String . CouldntLoadChalAuxFile ) +
" " +
Activity . GetString (
Resource . String . CouldntLoadChalAuxFile_Hint ) ;
}
protected override bool AuxDataLoaded
{
get { return Activity . _chalInfo ! = null ; }
}
protected override void LoadFile ( IOConnectionInfo iocAux )
{
Activity . _chalInfo = ChallengeInfo . Load ( iocAux ) ;
}
protected override IOConnectionInfo GetDefaultAuxLocation ( )
{
IFileStorage fileStorage =
App . Kp2a . GetOtpAuxFileStorage ( Activity . _ioConnection ) ;
IOConnectionInfo iocAux =
fileStorage . GetFilePath (
fileStorage . GetParentPath ( Activity . _ioConnection ) ,
fileStorage . GetFilenameWithoutPathAndExt ( Activity . _ioConnection ) +
".xml" ) ;
return iocAux ;
}
}
2014-03-25 15:51:41 -04:00
2013-11-20 13:14:57 -05:00
private void ShowOtpEntry ( IList < string > prefilledOtps )
{
FindViewById ( Resource . Id . otpInitView ) . Visibility = ViewStates . Gone ;
FindViewById ( Resource . Id . otpEntry ) . Visibility = ViewStates . Visible ;
int c = 0 ;
foreach ( int otpId in _otpTextViewIds )
{
c + + ;
var otpTextView = FindViewById < EditText > ( otpId ) ;
if ( c < = prefilledOtps . Count )
{
otpTextView . Text = prefilledOtps [ c - 1 ] ;
}
else
{
otpTextView . Text = "" ;
}
otpTextView . Hint = GetString ( Resource . String . otp_hint , new Object [ ] { c } ) ;
otpTextView . SetFilters ( new IInputFilter [ ] { new InputFilterLengthFilter ( ( int ) _otpInfo . OtpLength ) } ) ;
if ( c > _otpInfo . OtpsRequired )
{
otpTextView . Visibility = ViewStates . Gone ;
}
else
{
otpTextView . TextChanged + = ( sender , args ) = > { UpdateOkButtonState ( ) ; } ;
}
}
}
2015-09-15 15:45:04 -04:00
int count = 1 ;
private DrawerLayout mDrawerLayout ;
//private RecyclerView mDrawerList;
private string mDrawerTitle ;
private MeasuringRelativeLayout . MeasureArgs _measureArgs ;
2015-12-21 23:42:02 -05:00
private ActivityDesign _activityDesign ;
2016-01-02 06:31:30 -05:00
private FingerprintDecryption _fingerprintDec ;
private bool _fingerprintPermissionGranted ;
2015-12-21 23:42:02 -05:00
2015-09-15 15:45:04 -04:00
internal class MyActionBarDrawerToggle : ActionBarDrawerToggle
{
PasswordActivity owner ;
public MyActionBarDrawerToggle ( PasswordActivity activity , DrawerLayout layout , int imgRes , int openRes , int closeRes )
: base ( activity , layout , openRes , closeRes )
{
owner = activity ;
}
public override void OnDrawerClosed ( View drawerView )
{
owner . SupportActionBar . Title = owner . Title ;
owner . InvalidateOptionsMenu ( ) ;
}
public override void OnDrawerOpened ( View drawerView )
{
owner . SupportActionBar . Title = owner . mDrawerTitle ;
owner . InvalidateOptionsMenu ( ) ;
}
}
private void UncollapseToolbar ( )
{
AppBarLayout appbarLayout = FindViewById < AppBarLayout > ( Resource . Id . appbar ) ;
var tmp = appbarLayout . LayoutParameters ;
CoordinatorLayout . LayoutParams p = tmp . JavaCast < CoordinatorLayout . LayoutParams > ( ) ;
var tmp2 = p . Behavior ;
var behavior = tmp2 . JavaCast < AppBarLayout . Behavior > ( ) ;
if ( behavior = = null )
{
p . Behavior = behavior = new AppBarLayout . Behavior ( ) ;
}
behavior . OnNestedFling ( FindViewById < CoordinatorLayout > ( Resource . Id . main_content ) , appbarLayout , null , 0 , - 10000 , false ) ;
}
private void CollapseToolbar ( )
{
AppBarLayout appbarLayout = FindViewById < AppBarLayout > ( Resource . Id . appbar ) ;
ViewGroup . LayoutParams tmp = appbarLayout . LayoutParameters ;
CoordinatorLayout . LayoutParams p = tmp . JavaCast < CoordinatorLayout . LayoutParams > ( ) ;
var tmp2 = p . Behavior ;
var behavior = tmp2 . JavaCast < AppBarLayout . Behavior > ( ) ;
if ( behavior = = null )
{
p . Behavior = behavior = new AppBarLayout . Behavior ( ) ;
}
behavior . OnNestedFling ( FindViewById < CoordinatorLayout > ( Resource . Id . main_content ) , appbarLayout , null , 0 , 200 , true ) ;
}
2013-02-23 11:43:42 -05:00
protected override void OnCreate ( Bundle savedInstanceState )
{
2015-12-21 23:42:02 -05:00
_activityDesign . ApplyTheme ( ) ;
2015-12-22 07:23:21 -05:00
base . OnCreate ( savedInstanceState ) ;
2015-09-15 15:45:04 -04:00
2015-02-11 02:41:59 -05:00
//use FlagSecure to make sure the last (revealed) character of the master password is not visible in recent apps
if ( PreferenceManager . GetDefaultSharedPreferences ( this ) . GetBoolean (
GetString ( Resource . String . ViewDatabaseSecure_key ) , true ) )
{
Window . SetFlags ( WindowManagerFlags . Secure , WindowManagerFlags . Secure ) ;
}
2013-02-23 11:43:42 -05:00
Intent i = Intent ;
2013-11-20 13:14:57 -05:00
2014-05-16 11:15:43 -04:00
//only load the AppTask if this is the "first" OnCreate (not because of kill/resume, i.e. savedInstanceState==null)
// and if the activity is not launched from history (i.e. recent tasks) because this would mean that
// the Activity was closed already (user cancelling the task or task complete) but is restarted due recent tasks.
// Don't re-start the task (especially bad if tak was complete already)
2014-05-21 00:43:56 -04:00
if ( Intent . Flags . HasFlag ( ActivityFlags . LaunchedFromHistory ) )
2014-05-16 11:15:43 -04:00
{
AppTask = new NullTask ( ) ;
}
else
{
2015-09-15 15:45:04 -04:00
AppTask = AppTask . GetTaskInOnCreate ( savedInstanceState , Intent ) ;
2014-05-16 11:15:43 -04:00
}
2015-09-15 15:45:04 -04:00
2013-11-20 13:14:57 -05:00
2013-02-23 11:43:42 -05:00
String action = i . Action ;
2015-09-15 15:45:04 -04:00
2013-06-15 06:40:01 -04:00
_prefs = PreferenceManager . GetDefaultSharedPreferences ( this ) ;
_rememberKeyfile = _prefs . GetBoolean ( GetString ( Resource . String . keyfile_key ) , Resources . GetBoolean ( Resource . Boolean . keyfile_default ) ) ;
2013-02-23 11:43:42 -05:00
2013-06-15 06:40:01 -04:00
_ioConnection = new IOConnectionInfo ( ) ;
2013-02-23 11:43:42 -05:00
2013-03-20 20:01:02 -04:00
2013-06-15 06:40:01 -04:00
if ( action ! = null & & action . Equals ( ViewIntent ) )
2013-02-23 11:43:42 -05:00
{
2013-11-20 13:14:57 -05:00
if ( ! GetIocFromViewIntent ( i ) ) return ;
2015-09-15 15:45:04 -04:00
}
2013-11-17 11:01:53 -05:00
else if ( ( action ! = null ) & & ( action . Equals ( Intents . StartWithOtp ) ) )
{
2013-11-20 13:14:57 -05:00
if ( ! GetIocFromOtpIntent ( savedInstanceState , i ) ) return ;
2015-01-05 22:01:46 -05:00
_keepPasswordInOnResume = true ;
2013-11-17 11:01:53 -05:00
}
else
2013-02-23 11:43:42 -05:00
{
2013-06-15 06:40:01 -04:00
SetIoConnectionFromIntent ( _ioConnection , i ) ;
2014-12-06 23:14:50 -05:00
var keyFileFromIntent = i . GetStringExtra ( KeyKeyfile ) ;
if ( keyFileFromIntent ! = null )
{
Kp2aLog . Log ( "try get keyfile from intent" ) ;
_keyFileOrProvider = IOConnectionInfo . SerializeToString ( IOConnectionInfo . FromPath ( keyFileFromIntent ) ) ;
Kp2aLog . Log ( "try get keyfile from intent ok" ) ;
}
else
{
_keyFileOrProvider = null ;
}
2014-01-27 06:44:03 -05:00
_password = i . GetStringExtra ( KeyPassword ) ? ? "" ;
2013-11-17 01:17:15 -05:00
if ( string . IsNullOrEmpty ( _keyFileOrProvider ) )
2013-02-23 11:43:42 -05:00
{
2013-11-17 01:17:15 -05:00
_keyFileOrProvider = GetKeyFile ( _ioConnection . Path ) ;
2013-02-23 11:43:42 -05:00
}
2015-01-05 22:01:46 -05:00
if ( ( ! string . IsNullOrEmpty ( _keyFileOrProvider ) ) | | ( _password ! = "" ) )
{
_keepPasswordInOnResume = true ;
}
2013-02-23 11:43:42 -05:00
}
2013-08-07 13:34:43 -04:00
if ( App . Kp2a . GetDb ( ) . Loaded & & App . Kp2a . GetDb ( ) . Ioc ! = null & &
App . Kp2a . GetDb ( ) . Ioc . GetDisplayName ( ) ! = _ioConnection . GetDisplayName ( ) )
{
// A different database is currently loaded, unload it before loading the new one requested
App . Kp2a . LockDatabase ( false ) ;
}
2013-02-23 11:43:42 -05:00
SetContentView ( Resource . Layout . password ) ;
2015-08-10 02:07:42 -04:00
2015-09-15 15:45:04 -04:00
InitializeToolbar ( ) ;
2015-08-10 02:07:42 -04:00
2015-09-15 15:45:04 -04:00
InitializeFilenameView ( ) ;
2013-06-01 13:24:42 -04:00
2013-11-20 13:14:57 -05:00
if ( KeyProviderType = = KeyProviders . KeyFile )
2014-11-08 15:29:36 -05:00
{
UpdateKeyfileIocView ( ) ;
}
2013-06-01 13:24:42 -04:00
2015-09-15 15:45:04 -04:00
var passwordEdit = FindViewById < EditText > ( Resource . Id . password_edit ) ;
passwordEdit . TextChanged + =
2013-11-17 01:17:15 -05:00
( sender , args ) = >
{
2015-08-10 02:07:42 -04:00
_password = passwordEdit . Text ;
2013-11-17 01:17:15 -05:00
UpdateOkButtonState ( ) ;
} ;
2015-08-10 02:07:42 -04:00
passwordEdit . EditorAction + = ( sender , args ) = >
2015-09-15 15:45:04 -04:00
{
if ( ( args . ActionId = = ImeAction . Done ) | | ( ( args . ActionId = = ImeAction . ImeNull ) & & ( args . Event . Action = = KeyEventActions . Down ) ) )
OnOk ( ) ;
} ;
2013-06-01 13:24:42 -04:00
2013-11-20 13:14:57 -05:00
FindViewById < EditText > ( Resource . Id . pass_otpsecret ) . TextChanged + = ( sender , args ) = > UpdateOkButtonState ( ) ;
2014-01-27 06:44:03 -05:00
passwordEdit . Text = _password ;
2013-06-01 13:24:42 -04:00
2015-08-10 02:07:42 -04:00
var passwordFont = Typeface . CreateFromAsset ( Assets , "SourceCodePro-Regular.ttf" ) ;
passwordEdit . Typeface = passwordFont ;
2015-09-15 15:45:04 -04:00
2015-08-10 02:07:42 -04:00
InitializeBottomBarButtons ( ) ;
2013-11-20 13:14:57 -05:00
InitializePasswordModeSpinner ( ) ;
InitializeOtpSecretSpinner ( ) ;
2015-09-15 15:45:04 -04:00
InitializeNavDrawerButtons ( ) ;
2015-08-10 02:07:42 -04:00
2013-11-20 13:14:57 -05:00
UpdateOkButtonState ( ) ;
2015-09-15 15:45:04 -04:00
2013-11-20 13:14:57 -05:00
InitializeTogglePasswordButton ( ) ;
InitializeKeyfileBrowseButton ( ) ;
2015-12-27 02:50:45 -05:00
InitializeOptionCheckboxes ( ) ;
2013-11-20 13:14:57 -05:00
RestoreState ( savedInstanceState ) ;
2014-01-27 06:44:03 -05:00
if ( i . GetBooleanExtra ( "launchImmediately" , false ) )
{
App . Kp2a . GetFileStorage ( _ioConnection )
. PrepareFileUsage ( new FileStorageSetupInitiatorActivity ( this , OnActivityResult , null ) , _ioConnection ,
RequestCodePrepareDbFile , false ) ;
}
2015-09-15 15:45:04 -04:00
mDrawerTitle = this . Title ;
mDrawerLayout = FindViewById < DrawerLayout > ( Resource . Id . drawer_layout ) ;
var rootview = FindViewById < MeasuringRelativeLayout > ( Resource . Id . relative_layout ) ;
rootview . ViewTreeObserver . GlobalLayout + = ( sender , args2 ) = >
{
Android . Util . Log . Debug ( "KP2A" , "GlobalLayout" ) ;
var args = _measureArgs ;
if ( args = = null )
return ;
Android . Util . Log . Debug ( "KP2A" , "ActualHeight=" + args . ActualHeight ) ;
Android . Util . Log . Debug ( "KP2A" , "ProposedHeight=" + args . ProposedHeight ) ;
if ( args . ActualHeight < args . ProposedHeight )
UncollapseToolbar ( ) ;
if ( args . ActualHeight > args . ProposedHeight )
CollapseToolbar ( ) ;
} ;
rootview . MeasureEvent + = ( sender , args ) = >
{
//Snackbar.Make(rootview, "height="+args.ActualHeight, Snackbar.LengthLong).Show();
this . _measureArgs = args ;
} ;
2016-01-02 15:29:26 -05:00
if ( ( int ) Build . VERSION . SdkInt > = 23 )
RequestPermissions ( new [ ] { Manifest . Permission . UseFingerprint } , FingerprintPermissionRequestCode ) ;
2016-01-02 06:31:30 -05:00
2013-11-20 13:14:57 -05:00
}
2016-01-02 06:31:30 -05:00
const int FingerprintPermissionRequestCode = 0 ;
2013-11-20 13:14:57 -05:00
2016-01-02 06:31:30 -05:00
public override void OnRequestPermissionsResult ( int requestCode , string [ ] permissions , Permission [ ] grantResults )
{
if ( requestCode = = FingerprintPermissionRequestCode & & grantResults [ 0 ] = = Permission . Granted )
{
var btn = FindViewById < ImageButton > ( Resource . Id . fingerprintbtn ) ;
btn . Click + = ( sender , args ) = >
{
AlertDialog . Builder b = new AlertDialog . Builder ( this ) ;
b . SetTitle ( Resource . String . fingerprint_prefs ) ;
b . SetMessage ( btn . Tag . ToString ( ) ) ;
b . SetPositiveButton ( Android . Resource . String . Ok , ( o , eventArgs ) = > ( ( Dialog ) o ) . Dismiss ( ) ) ;
b . Show ( ) ;
} ;
_fingerprintPermissionGranted = true ;
}
}
private void ClearFingerprintUnlockData ( )
{
ISharedPreferencesEditor edit = PreferenceManager . GetDefaultSharedPreferences ( this ) . Edit ( ) ;
edit . PutString ( Database . GetFingerprintPrefKey ( _ioConnection ) , "" ) ;
edit . PutString ( Database . GetFingerprintModePrefKey ( _ioConnection ) , FingerprintUnlockMode . Disabled . ToString ( ) ) ;
edit . Commit ( ) ;
}
public void OnFingerprintError ( string message )
{
var btn = FindViewById < ImageButton > ( Resource . Id . fingerprintbtn ) ;
btn . SetImageResource ( Resource . Drawable . ic_fingerprint_error ) ;
btn . PostDelayed ( ( ) = >
{
btn . SetImageResource ( Resource . Drawable . ic_fp_40px ) ;
btn . Tag = GetString ( Resource . String . fingerprint_unlock_hint ) ;
} , 1300 ) ;
Toast . MakeText ( this , message , ToastLength . Long ) . Show ( ) ;
}
public void OnFingerprintAuthSucceeded ( )
{
var btn = FindViewById < ImageButton > ( Resource . Id . fingerprintbtn ) ;
btn . SetImageResource ( Resource . Drawable . ic_fingerprint_success ) ;
var masterPassword = _fingerprintDec . DecryptStored ( Database . GetFingerprintPrefKey ( _ioConnection ) ) ;
_password = FindViewById < EditText > ( Resource . Id . password_edit ) . Text = masterPassword ;
btn . PostDelayed ( ( ) = >
{
//re-init fingerprint unlock in case something goes wrong with opening the database
InitFingerprintUnlock ( ) ;
//fire
2016-01-02 15:57:49 -05:00
OnOk ( true ) ;
2016-01-02 06:31:30 -05:00
} , 1000 ) ;
}
private void InitializeNavDrawerButtons ( )
2015-08-10 02:07:42 -04:00
{
FindViewById ( Resource . Id . btn_nav_change_db ) . Click + = ( sender , args ) = >
{
GoToFileSelectActivity ( ) ;
} ;
FindViewById ( Resource . Id . btn_nav_donate ) . Click + = ( sender , args ) = >
{
Util . GotoDonateUrl ( this ) ;
} ;
FindViewById ( Resource . Id . btn_nav_about ) . Click + = ( sender , args ) = >
{
AboutDialog dialog = new AboutDialog ( this ) ;
dialog . Show ( ) ;
} ;
FindViewById ( Resource . Id . btn_nav_settings ) . Click + = ( sender , args ) = >
{
AppSettingsActivity . Launch ( this ) ;
} ;
}
private void InitializeToolbar ( )
{
2015-09-13 06:33:24 -04:00
var toolbar = FindViewById < Android . Support . V7 . Widget . Toolbar > ( Resource . Id . mytoolbar ) ;
2015-08-10 02:07:42 -04:00
SetSupportActionBar ( toolbar ) ;
var collapsingToolbar = FindViewById < CollapsingToolbarLayout > ( Resource . Id . collapsing_toolbar ) ;
collapsingToolbar . SetTitle ( GetString ( Resource . String . unlock_database_title ) ) ;
_drawerLayout = FindViewById < DrawerLayout > ( Resource . Id . drawer_layout ) ;
mDrawerToggle = new ActionBarDrawerToggle ( this , _drawerLayout ,
Resource . String . menu_open ,
Resource . String . menu_close ) ;
_drawerLayout . SetDrawerListener ( mDrawerToggle ) ;
SupportActionBar . SetDisplayHomeAsUpEnabled ( true ) ;
SupportActionBar . SetHomeButtonEnabled ( true ) ;
mDrawerToggle . SyncState ( ) ;
}
public override void OnBackPressed ( )
{
if ( _drawerLayout . IsDrawerOpen ( ( int ) GravityFlags . Start ) )
{
_drawerLayout . CloseDrawer ( ( int ) GravityFlags . Start ) ;
return ;
}
base . OnBackPressed ( ) ;
}
private void InitializeOtpSecretSpinner ( )
2013-11-20 13:14:57 -05:00
{
Spinner spinner = FindViewById < Spinner > ( Resource . Id . otpsecret_format_spinner ) ;
ArrayAdapter < String > spinnerArrayAdapter = new ArrayAdapter < String > ( this , Android . Resource . Layout . SimpleSpinnerDropDownItem , EncodingUtil . Formats ) ;
spinner . Adapter = spinnerArrayAdapter ;
}
private bool GetIocFromOtpIntent ( Bundle savedInstanceState , Intent i )
{
//create called after detecting an OTP via NFC
//this means the Activity was not on the back stack before, i.e. no database has been selected
_ioConnection = null ;
//see if we can get a database from recent:
if ( App . Kp2a . FileDbHelper . HasRecentFiles ( ) )
{
ICursor filesCursor = App . Kp2a . FileDbHelper . FetchAllFiles ( ) ;
StartManagingCursor ( filesCursor ) ;
filesCursor . MoveToFirst ( ) ;
IOConnectionInfo ioc = App . Kp2a . FileDbHelper . CursorToIoc ( filesCursor ) ;
if ( App . Kp2a . GetFileStorage ( ioc ) . RequiresSetup ( ioc ) = = false )
{
IFileStorage fileStorage = App . Kp2a . GetFileStorage ( ioc ) ;
if ( ! fileStorage . RequiresCredentials ( ioc ) )
{
//ok, we can use this file
_ioConnection = ioc ;
}
}
}
if ( _ioConnection = = null )
{
//We need to go to FileSelectActivity first.
//For security reasons: discard the OTP (otherwise the user might not select a database now and forget
//about the OTP, but it would still be stored in the Intents and later be passed to PasswordActivity again.
Toast . MakeText ( this , GetString ( Resource . String . otp_discarded_because_no_db ) , ToastLength . Long ) . Show ( ) ;
GoToFileSelectActivity ( ) ;
return false ;
}
2015-06-23 08:33:18 -04:00
//assume user wants to use OTP (for static password, they need to open KP2A first and select the key provider type, then see OnNewIntent)
2013-11-20 13:14:57 -05:00
_keyFileOrProvider = KeyProviderIdOtp ;
if ( savedInstanceState = = null ) //only when not re-creating
{
//remember the OTP for later use
_pendingOtps . Add ( i . GetStringExtra ( Intents . OtpExtraKey ) ) ;
i . RemoveExtra ( Intents . OtpExtraKey ) ;
}
return true ;
}
private bool GetIocFromViewIntent ( Intent i )
{
//started from "view" intent (e.g. from file browser)
_ioConnection . Path = i . DataString ;
if ( ! _ioConnection . Path . Substring ( 0 , 7 ) . Equals ( "file://" ) )
{
//TODO: this might no longer be required as we can handle http(s) and ftp as well (but we need server credentials therefore)
Toast . MakeText ( this , Resource . String . error_can_not_handle_uri , ToastLength . Long ) . Show ( ) ;
Finish ( ) ;
return false ;
}
_ioConnection . Path = URLDecoder . Decode ( _ioConnection . Path . Substring ( 7 ) ) ;
if ( _ioConnection . Path . Length = = 0 )
{
// No file name
Toast . MakeText ( this , Resource . String . FileNotFound , ToastLength . Long ) . Show ( ) ;
Finish ( ) ;
return false ;
}
File dbFile = new File ( _ioConnection . Path ) ;
if ( ! dbFile . Exists ( ) )
{
// File does not exist
Toast . MakeText ( this , Resource . String . FileNotFound , ToastLength . Long ) . Show ( ) ;
Finish ( ) ;
return false ;
}
_keyFileOrProvider = GetKeyFile ( _ioConnection . Path ) ;
return true ;
}
2015-08-10 02:07:42 -04:00
private void InitializeBottomBarButtons ( )
2013-11-20 13:14:57 -05:00
{
Button confirmButton = ( Button ) FindViewById ( Resource . Id . pass_ok ) ;
2013-10-07 00:28:06 -04:00
confirmButton . Click + = ( sender , e ) = >
2013-02-23 11:43:42 -05:00
{
2015-02-17 00:05:48 -05:00
OnOk ( ) ;
2013-11-20 13:14:57 -05:00
} ;
2015-08-10 02:07:42 -04:00
2016-01-04 09:34:58 -05:00
var changeDbButton = FindViewById < Button > ( Resource . Id . change_db ) ;
string label = changeDbButton . Text ;
2015-10-29 15:31:34 -04:00
if ( label . EndsWith ( "<22> " ) )
2016-01-04 09:34:58 -05:00
changeDbButton . Text = label . Substring ( 0 , label . Length - 1 ) ;
changeDbButton . Click + = ( sender , args ) = > GoToFileSelectActivity ( ) ;
Util . MoveBottomBarButtons ( Resource . Id . change_db , Resource . Id . pass_ok , Resource . Id . bottom_bar , this ) ;
2013-11-20 13:14:57 -05:00
}
2016-01-02 15:57:49 -05:00
private void OnOk ( bool usedFingerprintUnlock = false )
2015-02-17 00:05:48 -05:00
{
2016-01-02 15:57:49 -05:00
UsedFingerprintUnlock = usedFingerprintUnlock ;
2015-02-17 00:05:48 -05:00
App . Kp2a . GetFileStorage ( _ioConnection )
. PrepareFileUsage ( new FileStorageSetupInitiatorActivity ( this , OnActivityResult , null ) , _ioConnection ,
RequestCodePrepareDbFile , false ) ;
}
2016-01-02 15:57:49 -05:00
public bool UsedFingerprintUnlock { get ; set ; }
2013-11-20 13:14:57 -05:00
private void InitializeTogglePasswordButton ( )
{
ImageButton btnTogglePassword = ( ImageButton ) FindViewById ( Resource . Id . toggle_password ) ;
btnTogglePassword . Click + = ( sender , e ) = >
{
_showPassword = ! _showPassword ;
MakePasswordMaskedOrVisible ( ) ;
2013-10-07 00:28:06 -04:00
} ;
2015-09-15 00:25:17 -04:00
Android . Graphics . PorterDuff . Mode mMode = Android . Graphics . PorterDuff . Mode . SrcAtop ;
Color color = new Color ( 224 , 224 , 224 ) ;
btnTogglePassword . SetColorFilter ( color , mMode ) ;
2013-11-20 13:14:57 -05:00
}
2013-11-11 00:38:15 -05:00
2013-11-20 13:14:57 -05:00
private void InitializeKeyfileBrowseButton ( )
{
2014-11-08 15:29:36 -05:00
var browseButton = ( Button ) FindViewById ( Resource . Id . btn_change_location ) ;
browseButton . Click + = ( sender , evt ) = >
2013-11-20 13:14:57 -05:00
{
2014-11-08 15:29:36 -05:00
Intent intent = new Intent ( this , typeof ( SelectStorageLocationActivity ) ) ;
intent . PutExtra ( FileStorageSelectionActivity . AllowThirdPartyAppGet , true ) ;
intent . PutExtra ( FileStorageSelectionActivity . AllowThirdPartyAppSend , false ) ;
intent . PutExtra ( FileStorageSetupDefs . ExtraIsForSave , false ) ;
StartActivityForResult ( intent , RequestCodeSelectKeyfile ) ;
2013-11-20 13:14:57 -05:00
} ;
}
private void InitializePasswordModeSpinner ( )
{
2013-11-17 01:17:15 -05:00
Spinner passwordModeSpinner = FindViewById < Spinner > ( Resource . Id . password_mode_spinner ) ;
if ( passwordModeSpinner ! = null )
{
UpdateKeyProviderUiState ( ) ;
passwordModeSpinner . SetSelection ( ( int ) KeyProviderType ) ;
passwordModeSpinner . ItemSelected + = ( sender , args ) = >
{
switch ( args . Position )
{
case 0 :
_keyFileOrProvider = null ;
break ;
case 1 :
2013-11-25 15:06:37 -05:00
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
2014-11-08 15:29:36 -05:00
_keyFileOrProvider = ( FindViewById ( Resource . Id . label_keyfilename ) . Tag ? ? "" ) . ToString ( ) ;
2013-11-17 01:17:15 -05:00
break ;
case 2 :
_keyFileOrProvider = KeyProviderIdOtp ;
break ;
2013-11-20 13:14:57 -05:00
case 3 :
_keyFileOrProvider = KeyProviderIdOtpRecovery ;
break ;
2014-03-25 15:51:41 -04:00
case 4 :
_keyFileOrProvider = KeyProviderIdChallenge ;
break ;
case 5 :
_keyFileOrProvider = KeyProviderIdChallengeRecovery ;
break ;
2013-11-17 01:17:15 -05:00
default :
2013-11-20 13:14:57 -05:00
throw new Exception ( "Unexpected position " + args . Position + " / " +
( ( ICursor ) ( ( AdapterView ) sender ) . GetItemAtPosition ( args . Position ) ) . GetString ( 1 ) ) ;
2013-11-17 01:17:15 -05:00
}
UpdateKeyProviderUiState ( ) ;
} ;
FindViewById ( Resource . Id . init_otp ) . Click + = ( sender , args ) = >
{
2014-03-25 15:51:41 -04:00
App . Kp2a . GetOtpAuxFileStorage ( _ioConnection )
. PrepareFileUsage ( new FileStorageSetupInitiatorActivity ( this , OnActivityResult , null ) , _ioConnection ,
RequestCodePrepareOtpAuxFile , false ) ;
2013-11-17 01:17:15 -05:00
} ;
}
2015-09-16 23:26:13 -04:00
2013-11-20 13:14:57 -05:00
}
2013-11-17 01:17:15 -05:00
2013-11-20 13:14:57 -05:00
private void RestoreState ( Bundle savedInstanceState )
{
if ( savedInstanceState ! = null )
2013-02-23 11:43:42 -05:00
{
2013-11-20 13:14:57 -05:00
_showPassword = savedInstanceState . GetBoolean ( ShowpasswordKey , false ) ;
MakePasswordMaskedOrVisible ( ) ;
2014-11-08 15:29:36 -05:00
_keyFileOrProvider = savedInstanceState . GetString ( KeyFileOrProviderKey ) ;
2015-09-13 06:33:24 -04:00
_password = FindViewById < EditText > ( Resource . Id . password_edit ) . Text = savedInstanceState . GetString ( PasswordKey ) ;
2013-11-20 13:14:57 -05:00
_pendingOtps = new List < string > ( savedInstanceState . GetStringArrayList ( PendingOtpsKey ) ) ;
string otpInfoString = savedInstanceState . GetString ( OtpInfoKey ) ;
if ( otpInfoString ! = null )
2013-02-23 11:43:42 -05:00
{
2013-11-20 13:14:57 -05:00
XmlSerializer xs = new XmlSerializer ( typeof ( OtpInfo ) ) ;
_otpInfo = ( OtpInfo ) xs . Deserialize ( new StringReader ( otpInfoString ) ) ;
2013-04-26 06:43:06 -04:00
2013-11-20 13:14:57 -05:00
var enteredOtps = savedInstanceState . GetStringArrayList ( EnteredOtpsKey ) ;
ShowOtpEntry ( enteredOtps ) ;
}
UpdateKeyProviderUiState ( ) ;
}
2013-07-25 08:47:05 -04:00
}
2013-11-17 01:17:15 -05:00
private void UpdateOkButtonState ( )
2013-10-07 00:28:06 -04:00
{
2015-08-10 02:07:42 -04:00
bool enabled = false ;
2013-11-17 01:17:15 -05:00
switch ( KeyProviderType )
2013-10-07 00:28:06 -04:00
{
2013-11-17 01:17:15 -05:00
case KeyProviders . None :
2015-08-10 02:07:42 -04:00
enabled = true ;
2013-11-17 01:17:15 -05:00
break ;
case KeyProviders . KeyFile :
2015-08-10 02:07:42 -04:00
enabled = _keyFileOrProvider ! = "" | | _password ! = "" ;
2013-11-17 01:17:15 -05:00
break ;
case KeyProviders . Otp :
2015-08-10 02:07:42 -04:00
enabled = true ;
2013-11-17 01:17:15 -05:00
if ( _otpInfo = = null )
enabled = false ;
else
{
int c = 0 ;
foreach ( int otpId in _otpTextViewIds )
{
c + + ;
var otpTextView = FindViewById < EditText > ( otpId ) ;
if ( ( c < = _otpInfo . OtpsRequired ) & & ( otpTextView . Text = = "" ) )
{
enabled = false ;
break ;
}
}
}
2015-08-10 02:07:42 -04:00
2013-11-17 01:17:15 -05:00
break ;
2013-11-20 13:14:57 -05:00
case KeyProviders . OtpRecovery :
2014-05-24 23:36:52 -04:00
case KeyProviders . ChalRecovery :
2015-08-10 02:07:42 -04:00
enabled = FindViewById < EditText > ( Resource . Id . pass_otpsecret ) . Text ! = "" ;
2013-11-20 13:14:57 -05:00
break ;
2014-05-24 23:36:52 -04:00
case KeyProviders . Challenge :
2015-08-10 02:07:42 -04:00
enabled = _challengeSecret ! = null ;
2014-03-25 15:51:41 -04:00
break ;
2013-11-17 01:17:15 -05:00
default :
throw new ArgumentOutOfRangeException ( ) ;
}
2015-08-10 02:07:42 -04:00
FindViewById ( Resource . Id . pass_ok ) . Enabled = enabled ;
2015-09-04 02:12:32 -04:00
2013-11-17 01:17:15 -05:00
}
private void UpdateKeyProviderUiState ( )
{
FindViewById ( Resource . Id . keyfileLine ) . Visibility = KeyProviderType = = KeyProviders . KeyFile
? ViewStates . Visible
: ViewStates . Gone ;
2014-11-08 15:29:36 -05:00
if ( KeyProviderType = = KeyProviders . KeyFile )
{
UpdateKeyfileIocView ( ) ;
}
2013-11-17 01:17:15 -05:00
FindViewById ( Resource . Id . otpView ) . Visibility = KeyProviderType = = KeyProviders . Otp
? ViewStates . Visible
: ViewStates . Gone ;
2013-11-20 13:14:57 -05:00
2014-05-24 23:36:52 -04:00
FindViewById ( Resource . Id . otpSecretLine ) . Visibility = ( KeyProviderType = = KeyProviders . OtpRecovery | | KeyProviderType = = KeyProviders . ChalRecovery )
2013-11-20 13:14:57 -05:00
? ViewStates . Visible
: ViewStates . Gone ;
2013-11-17 11:01:53 -05:00
if ( KeyProviderType = = KeyProviders . Otp )
{
FindViewById ( Resource . Id . otps_pending ) . Visibility = _pendingOtps . Count > 0 ? ViewStates . Visible : ViewStates . Gone ;
}
2014-03-25 15:51:41 -04:00
2014-05-24 23:36:52 -04:00
if ( KeyProviderType = = KeyProviders . Challenge )
2014-03-25 15:51:41 -04:00
{
FindViewById ( Resource . Id . otpView ) . Visibility = ViewStates . Visible ;
2014-05-22 00:42:43 -04:00
FindViewById ( Resource . Id . otps_pending ) . Visibility = ViewStates . Gone ;
2014-03-25 15:51:41 -04:00
}
2013-11-17 01:17:15 -05:00
UpdateOkButtonState ( ) ;
}
private void PerformLoadDatabase ( )
{
2014-12-06 23:14:50 -05:00
//put loading into background thread to allow loading the key file (potentially over network)
new SimpleLoadingDialog ( this , GetString ( Resource . String . loading ) ,
true , ( ) = >
{
CompositeKey compositeKey ;
2014-12-16 23:58:55 -05:00
string errorMessage ;
if ( ! CreateCompositeKey ( out compositeKey , out errorMessage ) ) return ( ( ) = >
{
Toast . MakeText ( this , errorMessage , ToastLength . Long ) . Show ( ) ;
} ) ;
2014-12-06 23:14:50 -05:00
return ( ) = > { PerformLoadDatabaseWithCompositeKey ( compositeKey ) ; } ;
} ) . Execute ( ) ;
2014-03-31 01:24:02 -04:00
2014-12-06 23:14:50 -05:00
}
private void PerformLoadDatabaseWithCompositeKey ( CompositeKey compositeKey )
{
CheckBox cbQuickUnlock = ( CheckBox ) FindViewById ( Resource . Id . enable_quickunlock ) ;
App . Kp2a . SetQuickUnlockEnabled ( cbQuickUnlock . Checked ) ;
2015-12-27 02:50:45 -05:00
if ( App . Kp2a . OfflineMode ! = _loadDbTaskOffline )
{
//keep the loading result if we loaded in online-mode (now offline) and the task is completed
if ( ! App . Kp2a . OfflineMode | | ! _loadDbTask . IsCompleted )
{
//discard the pre-loading task
_loadDbTask = null ;
}
}
2014-12-06 23:14:50 -05:00
//avoid password being visible while loading:
_showPassword = false ;
MakePasswordMaskedOrVisible ( ) ;
Handler handler = new Handler ( ) ;
OnFinish onFinish = new AfterLoad ( handler , this ) ;
_performingLoad = true ;
LoadDb task = ( KeyProviderType = = KeyProviders . Otp )
? new SaveOtpAuxFileAndLoadDb ( App . Kp2a , _ioConnection , _loadDbTask , compositeKey , _keyFileOrProvider ,
onFinish , this )
: new LoadDb ( App . Kp2a , _ioConnection , _loadDbTask , compositeKey , _keyFileOrProvider , onFinish ) ;
_loadDbTask = null ; // prevent accidental re-use
SetNewDefaultFile ( ) ;
new ProgressTask ( App . Kp2a , this , task ) . Run ( ) ;
}
2014-12-16 23:58:55 -05:00
private bool CreateCompositeKey ( out CompositeKey compositeKey , out string errorMessage )
2014-12-06 23:14:50 -05:00
{
2014-12-16 23:58:55 -05:00
errorMessage = null ;
2014-12-06 23:14:50 -05:00
//no need to check for validity of password because if this method is called, the Ok button was enabled (i.e. there was a valid password)
compositeKey = new CompositeKey ( ) ;
2013-11-17 01:17:15 -05:00
compositeKey . AddUserKey ( new KcpPassword ( _password ) ) ;
2014-10-26 01:18:05 -04:00
if ( KeyProviderType = = KeyProviders . KeyFile )
2013-11-17 01:17:15 -05:00
{
try
{
2014-11-08 15:29:36 -05:00
if ( _keyFileOrProvider = = "" )
throw new System . IO . FileNotFoundException ( ) ;
var ioc = IOConnectionInfo . UnserializeFromString ( _keyFileOrProvider ) ;
using ( var stream = App . Kp2a . GetFileStorage ( ioc ) . OpenFileForRead ( ioc ) )
{
byte [ ] keyfileData = StreamToMemoryStream ( stream ) . ToArray ( ) ;
compositeKey . AddUserKey ( new KcpKeyFile ( keyfileData , ioc , true ) ) ;
}
2013-11-17 01:17:15 -05:00
}
2014-11-08 15:29:36 -05:00
catch ( System . IO . FileNotFoundException e )
2013-11-17 01:17:15 -05:00
{
Kp2aLog . Log ( e . ToString ( ) ) ;
2014-12-16 23:58:55 -05:00
errorMessage = App . Kp2a . GetResourceString ( UiStringKey . keyfile_does_not_exist ) ;
2014-12-06 23:14:50 -05:00
return false ;
2013-11-17 01:17:15 -05:00
}
2014-11-08 15:29:36 -05:00
catch ( Exception e )
{
Kp2aLog . Log ( e . ToString ( ) ) ;
2014-12-16 23:58:55 -05:00
errorMessage = e . Message ;
2014-12-06 23:14:50 -05:00
return false ;
2014-11-08 15:29:36 -05:00
}
2013-11-17 01:17:15 -05:00
}
else if ( KeyProviderType = = KeyProviders . Otp )
{
try
{
2013-11-22 15:47:13 -05:00
var lOtps = GetOtpsFromUi ( ) ;
2014-10-26 01:18:05 -04:00
Kp2aLog . Log ( "received " + lOtps . Count + " otps." ) ;
2013-11-22 15:47:13 -05:00
OathHotpKeyProv . CreateOtpSecret ( lOtps , _otpInfo ) ;
2013-11-17 01:17:15 -05:00
}
2014-10-26 01:18:05 -04:00
catch ( Exception e )
2013-11-17 01:17:15 -05:00
{
2014-10-26 01:18:05 -04:00
Kp2aLog . Log ( e . ToString ( ) ) ;
2014-12-16 23:58:55 -05:00
errorMessage = GetString ( Resource . String . OtpKeyError ) ;
2013-11-17 01:17:15 -05:00
2014-12-06 23:14:50 -05:00
return false ;
2013-11-17 01:17:15 -05:00
}
compositeKey . AddUserKey ( new KcpCustomKey ( OathHotpKeyProv . Name , _otpInfo . Secret , true ) ) ;
2013-10-07 00:28:06 -04:00
}
2014-05-24 23:36:52 -04:00
else if ( ( KeyProviderType = = KeyProviders . OtpRecovery ) | | ( KeyProviderType = = KeyProviders . ChalRecovery ) )
2013-11-20 13:14:57 -05:00
{
Spinner stpDataFmtSpinner = FindViewById < Spinner > ( Resource . Id . otpsecret_format_spinner ) ;
EditText secretEdit = FindViewById < EditText > ( Resource . Id . pass_otpsecret ) ;
2014-12-06 23:14:50 -05:00
byte [ ] pbSecret = EncodingUtil . ParseKey ( secretEdit . Text , ( OtpDataFmt ) stpDataFmtSpinner . SelectedItemPosition ) ;
2013-11-20 13:14:57 -05:00
if ( pbSecret ! = null )
{
compositeKey . AddUserKey ( new KcpCustomKey ( OathHotpKeyProv . Name , pbSecret , true ) ) ;
}
else
{
2014-12-16 23:58:55 -05:00
errorMessage = GetString ( Resource . String . CouldntParseOtpSecret ) ;
2014-12-06 23:14:50 -05:00
return false ;
2013-11-20 13:14:57 -05:00
}
}
2014-12-06 23:14:50 -05:00
else if ( KeyProviderType = = KeyProviders . Challenge )
{
compositeKey . AddUserKey ( new KcpCustomKey ( KeeChallengeProv . Name , _challengeSecret , true ) ) ;
}
return true ;
2013-10-07 00:28:06 -04:00
}
2013-11-22 15:47:13 -05:00
private List < string > GetOtpsFromUi ( )
2013-11-20 13:14:57 -05:00
{
List < string > lOtps = new List < string > ( ) ;
foreach ( int otpId in _otpTextViewIds )
{
string otpText = FindViewById < EditText > ( otpId ) . Text ;
if ( ! String . IsNullOrEmpty ( otpText ) )
lOtps . Add ( otpText ) ;
}
return lOtps ;
}
2013-11-17 01:17:15 -05:00
2013-08-31 07:58:00 -04:00
private void MakePasswordMaskedOrVisible ( )
{
2015-09-13 06:33:24 -04:00
TextView password = ( TextView ) FindViewById ( Resource . Id . password_edit ) ;
2013-08-31 07:58:00 -04:00
if ( _showPassword )
{
password . InputType = InputTypes . ClassText | InputTypes . TextVariationVisiblePassword ;
2015-08-10 02:07:42 -04:00
SetPasswordTypeface ( password ) ;
2013-08-31 07:58:00 -04:00
}
else
{
password . InputType = InputTypes . ClassText | InputTypes . TextVariationPassword ;
}
2015-08-10 02:07:42 -04:00
2013-08-31 07:58:00 -04:00
}
2016-01-02 06:31:30 -05:00
protected override void OnPause ( )
{
base . OnPause ( ) ;
if ( _fingerprintDec ! = null )
{
_fingerprintDec . StopListening ( ) ;
}
}
private void SetPasswordTypeface ( TextView textView )
2015-08-10 02:07:42 -04:00
{
if ( _passwordFont = = null )
{
_passwordFont = Typeface . CreateFromAsset ( Assets , "SourceCodePro-Regular.ttf" ) ;
}
textView . Typeface = _passwordFont ;
}
private void SetNewDefaultFile ( )
2013-08-09 16:31:30 -04:00
{
//Don't allow the current file to be the default if we don't have stored credentials
bool makeFileDefault ;
if ( ( _ioConnection . IsLocalFile ( ) = = false ) & & ( _ioConnection . CredSaveMode ! = IOCredSaveMode . SaveCred ) )
{
makeFileDefault = false ;
}
else
{
makeFileDefault = true ;
}
String newDefaultFileName ;
if ( makeFileDefault )
{
newDefaultFileName = _ioConnection . Path ;
}
else
{
newDefaultFileName = "" ;
}
ISharedPreferencesEditor editor = _prefs . Edit ( ) ;
editor . PutString ( KeyDefaultFilename , newDefaultFileName ) ;
EditorCompat . Apply ( editor ) ;
}
2013-07-25 08:47:05 -04:00
protected override void OnStart ( )
{
base . OnStart ( ) ;
2013-08-10 14:49:59 -04:00
_starting = true ;
2013-09-06 16:56:29 -04:00
ISharedPreferences prefs = PreferenceManager . GetDefaultSharedPreferences ( this ) ;
long usageCount = prefs . GetLong ( GetString ( Resource . String . UsageCount_key ) , 0 ) ;
2014-04-01 01:26:10 -04:00
if ( usageCount > 5 )
2013-09-06 16:56:29 -04:00
{
2014-04-01 01:26:10 -04:00
DonateReminder . ShowDonateReminderIfAppropriate ( this ) ;
2013-09-06 16:56:29 -04:00
}
2013-07-17 14:19:17 -04:00
}
2014-01-25 22:38:12 -05:00
private MemoryStream PreloadDbFile ( )
2013-07-17 14:19:17 -04:00
{
2013-08-15 13:49:27 -04:00
if ( KdbpFile . GetFormatToUse ( _ioConnection ) = = KdbxFormat . ProtocolBuffers )
{
Kp2aLog . Log ( "Preparing kdbp serializer" ) ;
KdbpFile . PrepareSerializer ( ) ;
}
2013-07-25 08:47:05 -04:00
Kp2aLog . Log ( "Pre-loading database file starting" ) ;
2013-07-17 14:19:17 -04:00
var fileStorage = App . Kp2a . GetFileStorage ( _ioConnection ) ;
var stream = fileStorage . OpenFileForRead ( _ioConnection ) ;
2014-11-08 15:29:36 -05:00
var memoryStream = StreamToMemoryStream ( stream ) ;
Kp2aLog . Log ( "Pre-loading database file completed" ) ;
return memoryStream ;
}
private static MemoryStream StreamToMemoryStream ( Stream stream )
{
2013-07-17 14:19:17 -04:00
var memoryStream = stream as MemoryStream ;
if ( memoryStream = = null )
{
2014-11-08 15:29:36 -05:00
// Read the stream into memory
2013-07-17 14:19:17 -04:00
int capacity = 4096 ; // Default initial capacity, if stream can't report it.
if ( stream . CanSeek )
{
2014-11-08 15:29:36 -05:00
capacity = ( int ) stream . Length ;
2013-07-17 14:19:17 -04:00
}
memoryStream = new MemoryStream ( capacity ) ;
2013-08-04 04:38:15 -04:00
stream . CopyTo ( memoryStream ) ;
2013-07-17 14:19:17 -04:00
stream . Close ( ) ;
2014-11-08 15:29:36 -05:00
memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
2013-07-17 14:19:17 -04:00
}
return memoryStream ;
2013-02-23 11:43:42 -05:00
}
2013-05-30 00:54:25 -04:00
protected override void OnSaveInstanceState ( Bundle outState )
{
base . OnSaveInstanceState ( outState ) ;
2013-06-15 06:40:01 -04:00
AppTask . ToBundle ( outState ) ;
2013-09-16 22:53:14 -04:00
outState . PutBoolean ( ShowpasswordKey , _showPassword ) ;
2013-11-20 13:14:57 -05:00
outState . PutString ( KeyFileOrProviderKey , _keyFileOrProvider ) ;
outState . PutString ( PasswordKey , _password ) ;
outState . PutStringArrayList ( PendingOtpsKey , _pendingOtps ) ;
if ( _otpInfo ! = null )
{
2013-11-22 15:47:13 -05:00
outState . PutStringArrayList ( EnteredOtpsKey , GetOtpsFromUi ( ) ) ;
2013-11-20 13:14:57 -05:00
var sw = new StringWriter ( ) ;
var xws = OtpInfo . XmlWriterSettings ( ) ;
XmlWriter xw = XmlWriter . Create ( sw , xws ) ;
XmlSerializer xs = new XmlSerializer ( typeof ( OtpInfo ) ) ;
xs . Serialize ( xw , _otpInfo ) ;
xw . Close ( ) ;
outState . PutString ( OtpInfoKey , sw . ToString ( ) ) ;
}
2015-09-15 15:45:04 -04:00
2013-11-17 11:01:53 -05:00
}
protected override void OnNewIntent ( Intent intent )
{
base . OnNewIntent ( intent ) ;
//this method is called from the NfcOtpActivity's startActivity() if the activity is already running
//note: it's not called in other cases because OnNewIntent requires the activity to be on top already
//which is never the case when started from another activity (in the same task).
//NfcOtpActivity sets the ClearTop flag to get OnNewIntent called.
if ( ( intent ! = null ) & & ( intent . HasExtra ( Intents . OtpExtraKey ) ) )
{
string otp = intent . GetStringExtra ( Intents . OtpExtraKey ) ;
2015-06-23 08:33:18 -04:00
if ( this . KeyProviderType = = KeyProviders . Otp )
2013-11-17 11:01:53 -05:00
{
2015-06-23 08:33:18 -04:00
_keepPasswordInOnResume = true ;
if ( _otpInfo = = null )
{
//Entering OTPs not yet initialized:
_pendingOtps . Add ( otp ) ;
UpdateKeyProviderUiState ( ) ;
}
else
2013-11-17 11:01:53 -05:00
{
2015-06-23 08:33:18 -04:00
//Entering OTPs is initialized. Write OTP into first empty field:
bool foundEmptyField = false ;
foreach ( int otpId in _otpTextViewIds )
{
EditText otpEdit = FindViewById < EditText > ( otpId ) ;
if ( ( otpEdit . Visibility = = ViewStates . Visible ) & & String . IsNullOrEmpty ( otpEdit . Text ) )
{
otpEdit . Text = otp ;
foundEmptyField = true ;
break ;
}
}
//did we find a field?
if ( ! foundEmptyField )
2013-11-17 11:01:53 -05:00
{
2015-06-23 08:33:18 -04:00
Toast . MakeText ( this , GetString ( Resource . String . otp_discarded_no_space ) , ToastLength . Long ) . Show ( ) ;
2013-11-17 11:01:53 -05:00
}
}
2015-06-23 08:33:18 -04:00
Spinner passwordModeSpinner = FindViewById < Spinner > ( Resource . Id . password_mode_spinner ) ;
if ( passwordModeSpinner . SelectedItemPosition ! = ( int ) KeyProviders . Otp )
2013-11-17 11:01:53 -05:00
{
2015-06-23 08:33:18 -04:00
passwordModeSpinner . SetSelection ( ( int ) KeyProviders . Otp ) ;
}
2013-11-17 11:01:53 -05:00
}
2015-06-23 08:33:18 -04:00
else
2013-11-17 11:01:53 -05:00
{
2015-06-23 08:33:18 -04:00
//assume the key should be used as static password
2015-09-13 06:33:24 -04:00
FindViewById < EditText > ( Resource . Id . password_edit ) . Text + = otp ;
2013-11-17 11:01:53 -05:00
}
2015-06-23 08:33:18 -04:00
2013-11-17 11:01:53 -05:00
}
2013-05-30 00:54:25 -04:00
}
2013-02-23 11:43:42 -05:00
2013-08-07 13:34:43 -04:00
protected override void OnResume ( )
{
2013-02-23 11:43:42 -05:00
base . OnResume ( ) ;
2015-12-21 23:42:02 -05:00
_activityDesign . ReapplyTheme ( ) ;
2013-02-23 11:43:42 -05:00
2015-12-27 02:50:45 -05:00
CheckBox cbOfflineMode = ( CheckBox ) FindViewById ( Resource . Id . work_offline ) ;
App . Kp2a . OfflineMode = cbOfflineMode . Checked = App . Kp2a . OfflineModePreference ; //this won't overwrite new user settings because every change is directly saved in settings
LinearLayout offlineModeContainer = FindViewById < LinearLayout > ( Resource . Id . work_offline_container ) ;
if ( App . Kp2a . GetFileStorage ( _ioConnection ) is IOfflineSwitchable )
{
offlineModeContainer . Visibility = ViewStates . Visible ;
}
else
{
offlineModeContainer . Visibility = ViewStates . Gone ;
App . Kp2a . OfflineMode = false ;
}
2015-09-15 15:45:04 -04:00
EditText pwd = FindViewById < EditText > ( Resource . Id . password_edit ) ;
pwd . PostDelayed ( ( ) = >
{
InputMethodManager keyboard = ( InputMethodManager ) GetSystemService ( Context . InputMethodService ) ;
keyboard . ShowSoftInput ( pwd , 0 ) ;
} , 50 ) ;
2014-02-02 01:03:40 -05:00
2013-11-11 00:38:15 -05:00
View killButton = FindViewById ( Resource . Id . kill_app ) ;
if ( PreferenceManager . GetDefaultSharedPreferences ( this )
. GetBoolean ( GetString ( Resource . String . show_kill_app_key ) , false ) )
{
killButton . Click + = ( sender , args ) = >
{
_killOnDestroy = true ;
Finish ( ) ;
} ;
killButton . Visibility = ViewStates . Visible ;
}
else
{
killButton . Visibility = ViewStates . Gone ;
}
2015-09-15 15:45:04 -04:00
2015-01-05 22:01:46 -05:00
if ( ! _keepPasswordInOnResume )
{
2015-02-17 00:05:48 -05:00
if (
PreferenceManager . GetDefaultSharedPreferences ( this )
. GetBoolean ( GetString ( Resource . String . ClearPasswordOnLeave_key ) , true ) )
{
ClearEnteredPassword ( ) ;
}
2015-01-05 22:01:46 -05:00
}
_keepPasswordInOnResume = false ;
2013-08-31 07:58:00 -04:00
MakePasswordMaskedOrVisible ( ) ;
2013-11-25 15:06:37 -05:00
UpdateOkButtonState ( ) ;
2014-05-24 23:36:52 -04:00
if ( KeyProviderType = = KeyProviders . Challenge )
{
FindViewById ( Resource . Id . otpInitView ) . Visibility = _challengeSecret = = null ? ViewStates . Visible : ViewStates . Gone ;
}
2013-08-07 13:34:43 -04:00
// OnResume is run every time the activity comes to the foreground. This code should only run when the activity is started (OnStart), but must
// be run in OnResume rather than OnStart so that it always occurrs after OnActivityResult (when re-creating a killed activity, OnStart occurs before OnActivityResult)
2014-03-31 01:24:02 -04:00
//use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult)
//use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbTask to exist when we reload later!)
if ( _starting & & ! IsFinishing & & ! _performingLoad )
2013-02-23 11:43:42 -05:00
{
2013-08-10 14:49:59 -04:00
_starting = false ;
2013-08-07 13:34:43 -04:00
if ( App . Kp2a . DatabaseIsUnlocked )
2013-02-23 11:43:42 -05:00
{
LaunchNextActivity ( ) ;
}
2013-08-07 13:34:43 -04:00
else if ( App . Kp2a . QuickUnlockEnabled & & App . Kp2a . QuickLocked )
{
var i = new Intent ( this , typeof ( QuickUnlock ) ) ;
PutIoConnectionToIntent ( _ioConnection , i ) ;
Kp2aLog . Log ( "Starting QuickUnlock" ) ;
StartActivityForResult ( i , 0 ) ;
}
2013-09-17 00:53:18 -04:00
else
2013-02-23 11:43:42 -05:00
{
2013-09-17 00:53:18 -04:00
//database not yet loaded.
//check if pre-loading is enabled but wasn't started yet:
2013-10-08 11:01:47 -04:00
if ( _loadDbTask = = null & & _prefs . GetBoolean ( GetString ( Resource . String . PreloadDatabaseEnabled_key ) , true ) )
2013-09-17 00:53:18 -04:00
{
// Create task to kick off file loading while the user enters the password
2014-01-25 22:38:12 -05:00
_loadDbTask = Task . Factory . StartNew < MemoryStream > ( PreloadDbFile ) ;
2015-12-27 02:50:45 -05:00
_loadDbTaskOffline = App . Kp2a . OfflineMode ;
2013-09-17 00:53:18 -04:00
}
2013-02-23 11:43:42 -05:00
}
}
2016-01-02 06:31:30 -05:00
if ( _fingerprintPermissionGranted )
{
InitFingerprintUnlock ( ) ;
}
else
{
FindViewById < ImageButton > ( Resource . Id . fingerprintbtn ) . Visibility = ViewStates . Gone ;
}
}
private void InitFingerprintUnlock ( )
{
var btn = FindViewById < ImageButton > ( Resource . Id . fingerprintbtn ) ;
try
{
FingerprintUnlockMode um ;
Enum . TryParse ( _prefs . GetString ( Database . GetFingerprintModePrefKey ( _ioConnection ) , "" ) , out um ) ;
btn . Visibility = ( um = = FingerprintUnlockMode . FullUnlock ) ? ViewStates . Visible : ViewStates . Gone ;
if ( um ! = FingerprintUnlockMode . FullUnlock )
{
return ;
}
FingerprintModule fpModule = new FingerprintModule ( this ) ;
_fingerprintDec = new FingerprintDecryption ( fpModule , Database . GetFingerprintPrefKey ( _ioConnection ) , this ,
Database . GetFingerprintPrefKey ( _ioConnection ) ) ;
btn . Tag = GetString ( Resource . String . fingerprint_unlock_hint ) ;
if ( _fingerprintDec . InitCipher ( ) )
{
btn . SetImageResource ( Resource . Drawable . ic_fp_40px ) ;
_fingerprintDec . StartListening ( new FingerprintAuthCallbackAdapter ( this , this ) ) ;
}
else
{
//key invalidated permanently
btn . SetImageResource ( Resource . Drawable . ic_fingerprint_error ) ;
btn . Tag = GetString ( Resource . String . fingerprint_unlock_failed ) ;
_fingerprintDec = null ;
ClearFingerprintUnlockData ( ) ;
}
}
catch ( Exception e )
{
btn . SetImageResource ( Resource . Drawable . ic_fingerprint_error ) ;
btn . Tag = "Error initializing Fingerprint Unlock: " + e ;
_fingerprintDec = null ;
}
2013-02-23 11:43:42 -05:00
}
2016-01-02 06:31:30 -05:00
2015-12-27 02:50:45 -05:00
private void InitializeOptionCheckboxes ( ) {
2013-02-23 11:43:42 -05:00
CheckBox cbQuickUnlock = ( CheckBox ) FindViewById ( Resource . Id . enable_quickunlock ) ;
2013-06-15 06:40:01 -04:00
cbQuickUnlock . Checked = _prefs . GetBoolean ( GetString ( Resource . String . QuickUnlockDefaultEnabled_key ) , true ) ;
2015-12-27 02:50:45 -05:00
CheckBox cbOfflineMode = ( CheckBox ) FindViewById ( Resource . Id . work_offline ) ;
cbOfflineMode . CheckedChange + = ( sender , args ) = >
{
App . Kp2a . OfflineModePreference = App . Kp2a . OfflineMode = args . IsChecked ;
} ;
2013-02-23 11:43:42 -05:00
}
2015-06-10 16:13:44 -04:00
2013-06-15 06:40:01 -04:00
private String GetKeyFile ( String filename ) {
if ( _rememberKeyfile ) {
2013-11-25 15:06:37 -05:00
string keyfile = App . Kp2a . FileDbHelper . GetKeyFileForFile ( filename ) ;
2014-12-06 23:14:50 -05:00
if ( String . IsNullOrEmpty ( keyfile ) )
2013-11-25 15:06:37 -05:00
return null ; //signal no key file
2014-12-06 23:14:50 -05:00
2015-06-10 16:13:44 -04:00
if ( KeyProviderType = = KeyProviders . KeyFile )
2014-12-06 23:14:50 -05:00
{
2015-06-10 16:13:44 -04:00
//test if the filename is properly encoded.
try
{
Kp2aLog . Log ( "test if stored filename is ok" ) ;
IOConnectionInfo . UnserializeFromString ( keyfile ) ;
Kp2aLog . Log ( "...ok" ) ;
}
catch ( Exception e )
{
//it's not. This is probably because we're upgrading from app version <= 45
//where the keyfile was stored plain text and not serialized
Kp2aLog . Log ( "no, it's not: " + e . GetType ( ) . Name ) ;
var serializedKeyFile = IOConnectionInfo . SerializeToString ( IOConnectionInfo . FromPath ( keyfile ) ) ;
Kp2aLog . Log ( "now it is!" ) ;
return serializedKeyFile ;
}
2014-12-06 23:14:50 -05:00
}
2013-11-25 15:06:37 -05:00
return keyfile ;
2013-02-23 11:43:42 -05:00
} else {
2013-11-17 01:17:15 -05:00
return null ;
2013-02-23 11:43:42 -05:00
}
}
2013-11-20 13:14:57 -05:00
private void InitializeFilenameView ( ) {
2013-10-27 10:06:57 -04:00
SetEditText ( Resource . Id . filename , App . Kp2a . GetFileStorage ( _ioConnection ) . GetDisplayName ( _ioConnection ) ) ;
2015-08-10 02:07:42 -04:00
2013-02-23 11:43:42 -05:00
}
2013-11-11 00:38:15 -05:00
protected override void OnDestroy ( )
{
base . OnDestroy ( ) ;
if ( _killOnDestroy )
Process . KillProcess ( Process . MyPid ( ) ) ;
}
2013-02-23 11:43:42 -05:00
/ *
private void errorMessage ( CharSequence text )
{
Toast . MakeText ( this , text , ToastLength . Long ) . Show ( ) ;
}
* /
2013-11-20 13:14:57 -05:00
2013-06-15 06:40:01 -04:00
private void SetEditText ( int resId , String str ) {
2013-02-23 11:43:42 -05:00
TextView te = ( TextView ) FindViewById ( resId ) ;
//assert(te == null);
if ( te ! = null ) {
te . Text = str ;
}
}
public override bool OnOptionsItemSelected ( IMenuItem item ) {
switch ( item . ItemId ) {
2015-08-10 02:07:42 -04:00
case Android . Resource . Id . Home :
_drawerLayout . OpenDrawer ( Android . Support . V4 . View . GravityCompat . Start ) ;
return true ;
2013-02-23 11:43:42 -05:00
}
return base . OnOptionsItemSelected ( item ) ;
}
2013-09-17 00:53:18 -04:00
private void GoToFileSelectActivity ( )
{
Intent intent = new Intent ( this , typeof ( FileSelectActivity ) ) ;
2013-10-02 22:15:40 -04:00
intent . PutExtra ( FileSelectActivity . NoForwardToPasswordActivity , true ) ;
2013-09-17 00:53:18 -04:00
AppTask . ToIntent ( intent ) ;
2014-05-16 11:15:43 -04:00
intent . AddFlags ( ActivityFlags . ForwardResult ) ;
StartActivity ( intent ) ;
2013-09-17 00:53:18 -04:00
Finish ( ) ;
}
2013-02-23 11:43:42 -05:00
private class AfterLoad : OnFinish {
2013-06-15 06:40:01 -04:00
readonly PasswordActivity _act ;
2013-08-04 04:38:15 -04:00
public AfterLoad ( Handler handler , PasswordActivity act ) : base ( handler )
{
2013-06-15 16:02:48 -04:00
_act = act ;
2013-02-23 11:43:42 -05:00
}
2013-11-20 13:14:57 -05:00
2013-11-22 15:47:13 -05:00
public override void Run ( )
{
2016-01-02 06:31:30 -05:00
if ( Success )
2013-08-04 04:38:15 -04:00
{
2016-01-02 06:31:30 -05:00
2014-05-22 00:42:43 -04:00
_act . ClearEnteredPassword ( ) ;
2014-05-29 14:28:49 -04:00
_act . BroadcastOpenDatabase ( ) ;
2013-11-20 13:14:57 -05:00
GC . Collect ( ) ; // Ensure temporary memory used while loading is collected
2016-01-02 06:31:30 -05:00
}
2016-01-02 15:57:49 -05:00
if ( Exception is InvalidCompositeKeyException )
{
if ( _act . UsedFingerprintUnlock )
{
//disable fingerprint unlock if master password changed
_act . ClearFingerprintUnlockData ( ) ;
_act . InitFingerprintUnlock ( ) ;
Message = _act . GetString ( Resource . String . fingerprint_disabled_wrong_masterkey ) ;
}
}
2016-01-02 06:31:30 -05:00
2015-01-05 22:01:46 -05:00
if ( ( Message ! = null ) & & ( Message . Length > 150 ) ) //show long messages as dialog
{
new AlertDialog . Builder ( _act ) . SetMessage ( Message )
. SetPositiveButton ( Android . Resource . String . Ok ,
2015-02-19 14:30:26 -05:00
( sender , args ) = >
{
( ( Dialog ) sender ) . Dismiss ( ) ;
_act . LaunchNextActivity ( ) ;
} )
. SetCancelable ( false )
2015-01-05 22:01:46 -05:00
. Show ( ) ;
2015-02-19 14:30:26 -05:00
2015-01-05 22:01:46 -05:00
}
else
{
DisplayMessage ( _act ) ;
2015-02-19 14:30:26 -05:00
if ( Success )
{
_act . LaunchNextActivity ( ) ;
}
2015-01-05 22:01:46 -05:00
}
2016-01-02 15:57:49 -05:00
2014-03-31 01:24:02 -04:00
_act . _performingLoad = false ;
2013-02-23 11:43:42 -05:00
}
}
2013-11-22 15:47:13 -05:00
2014-05-29 14:28:49 -04:00
private void BroadcastOpenDatabase ( )
{
App . Kp2a . BroadcastDatabaseAction ( this , Strings . ActionOpenDatabase ) ;
}
2014-05-22 00:42:43 -04:00
private void ClearEnteredPassword ( )
{
2015-09-13 06:33:24 -04:00
SetEditText ( Resource . Id . password_edit , "" ) ;
2014-05-22 00:42:43 -04:00
SetEditText ( Resource . Id . pass_otpsecret , "" ) ;
foreach ( int otpId in _otpTextViewIds )
{
SetEditText ( otpId , "" ) ;
}
2014-05-24 23:36:52 -04:00
if ( _challengeSecret ! = null )
{
Array . Clear ( _challengeSecret , 0 , _challengeSecret . Length ) ;
_challengeSecret = null ;
}
2014-05-22 00:42:43 -04:00
}
2016-01-04 09:34:58 -05:00
2013-11-22 15:47:13 -05:00
class SaveOtpAuxFileAndLoadDb : LoadDb
{
private readonly PasswordActivity _act ;
public SaveOtpAuxFileAndLoadDb ( IKp2aApp app , IOConnectionInfo ioc , Task < MemoryStream > databaseData , CompositeKey compositeKey , string keyfileOrProvider , OnFinish finish , PasswordActivity act ) : base ( app , ioc , databaseData , compositeKey , keyfileOrProvider , finish )
{
_act = act ;
}
public override void Run ( )
{
try
{
StatusLogger . UpdateMessage ( UiStringKey . SavingOtpAuxFile ) ;
KeyProviderQueryContext ctx = new KeyProviderQueryContext ( _act . _ioConnection , false , false ) ;
2015-06-10 16:13:44 -04:00
if ( ! OathHotpKeyProv . CreateAuxFile ( _act . _otpInfo , ctx , _act . _otpAuxIoc ) )
2013-11-22 15:47:13 -05:00
Toast . MakeText ( _act , _act . GetString ( Resource . String . ErrorUpdatingOtpAuxFile ) , ToastLength . Long ) . Show ( ) ;
2015-06-10 16:13:44 -04:00
App . Kp2a . GetDb ( ) . OtpAuxFileIoc = _act . _otpAuxIoc ;
2013-11-22 15:47:13 -05:00
}
catch ( Exception e )
{
Kp2aLog . Log ( e . Message ) ;
Toast . MakeText ( _act , _act . GetString ( Resource . String . ErrorUpdatingOtpAuxFile ) + " " + e . Message ,
ToastLength . Long ) . Show ( ) ;
}
base . Run ( ) ;
}
}
2013-02-23 11:43:42 -05:00
}
2016-01-02 06:31:30 -05:00
public interface IFingerprintAuthCallback
{
void OnFingerprintAuthSucceeded ( ) ;
void OnFingerprintError ( string toString ) ;
}
2013-02-23 11:43:42 -05:00
}