public override void OnCreate() { InitThaiCalendarCrashFix(); base.OnCreate(); Kp2aLog.Log("Creating application " + PackageName + ". Version=" + PackageManager.GetPackageInfo(PackageName, 0).VersionCode); CreateNotificationChannels(); Kp2a.OnCreate(this); AndroidEnvironment.UnhandledExceptionRaiser += MyApp_UnhandledExceptionHandler; IntentFilter intentFilter = new IntentFilter(); intentFilter.AddAction(Intents.LockDatabase); intentFilter.AddAction(Intents.CloseDatabase); Context.RegisterReceiver(broadcastReceiver, intentFilter); }
Database TryLoad(MemoryStream databaseStream) { //create a copy of the stream so we can try again if we get an exception which indicates we should change parameters //This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors. //Alternatives would involve increased traffic (if file is on remote) and slower loading times, so this seems to be the best choice. MemoryStream workingCopy = new MemoryStream(); databaseStream.CopyTo(workingCopy); workingCopy.Seek(0, SeekOrigin.Begin); //reset stream if we need to reuse it later: databaseStream.Seek(0, SeekOrigin.Begin); //now let's go: try { Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent); Kp2aLog.Log("LoadDB OK"); Finish(true, _format.SuccessMessage); return(newDb); } catch (OldFormatException) { _format = new KdbDatabaseFormat(_app); return(TryLoad(databaseStream)); } catch (InvalidCompositeKeyException) { KcpPassword passwordKey = (KcpPassword)_compositeKey.GetUserKey(typeof(KcpPassword)); if ((passwordKey != null) && (passwordKey.Password.ReadString() == "") && (_compositeKey.UserKeyCount > 1)) { //if we don't get a password, we don't know whether this means "empty password" or "no password" //retry without password: _compositeKey.RemoveUserKey(passwordKey); //retry: return(TryLoad(databaseStream)); } else { throw; } } }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == RequestCodePluginAccess) { if (new PluginDatabase(this).HasAcceptedScope(_pluginPackage, _requiredScope)) { //user granted access. Search for the requested credentials: StartQuery(); } else { //user didn't grant access SetResult(Result.Canceled); Finish(); } } if (requestCode == RequestCodeQuery) { if (resultCode == KeePass.ExitCloseAfterTaskComplete) { //double check we really have the permission if (!new PluginDatabase(this).HasAcceptedScope(_pluginPackage, _requiredScope)) { Kp2aLog.LogUnexpectedError(new Exception("Ohoh! Scope not available, shouldn't get here. Malicious app somewhere?")); SetResult(Result.Canceled); Finish(); return; } //return credentials to caller: Intent credentialData = new Intent(); PluginHost.AddEntryToIntent(credentialData, App.Kp2a.GetDb().LastOpenedEntry); SetResult(Result.Ok, credentialData); Finish(); } else { SetResult(Result.Canceled); Finish(); } } }
/// <summary> /// Tries to extract the task from the data given as an Intent object in OnActivityResult. If successful, the task is assigned, /// otherwise, false is returned. /// </summary> public static bool TryGetFromActivityResult(Intent data, ref AppTask task) { if (data == null) { Kp2aLog.Log("TryGetFromActivityResult: no data"); return(false); } AppTask tempTask = CreateFromBundle(data.Extras, null); if (tempTask == null) { Kp2aLog.Log("No AppTask in OnActivityResult"); return(false); } task = tempTask; Kp2aLog.Log("AppTask " + task + " in OnActivityResult"); return(true); }
public void Lock(bool allowQuickUnlock = true) { if (OpenDatabases.Any()) { if (QuickUnlockEnabled && allowQuickUnlock && GetDbForQuickUnlock().KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) && !((KcpPassword)App.Kp2a.GetDbForQuickUnlock().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty) { if (!QuickLocked) { Kp2aLog.Log("QuickLocking database"); QuickLocked = true; LastOpenedEntry = null; BroadcastDatabaseAction(Application.Context, Strings.ActionLockDatabase); } else { Kp2aLog.Log("Database already QuickLocked"); } } else { Kp2aLog.Log("Locking database"); BroadcastDatabaseAction(Application.Context, Strings.ActionCloseDatabase); // Couldn't quick-lock, so unload database(s) instead _openAttempts.Clear(); _openDatabases.Clear(); _currentDatabase = null; LastOpenedEntry = null; QuickLocked = false; } } else { Kp2aLog.Log("Database not loaded, couldn't lock"); } _currentlyWaitingXcKey = null; UpdateOngoingNotification(); Application.Context.SendBroadcast(new Intent(Intents.DatabaseLocked)); }
protected override void OnStart() { base.OnStart(); Kp2aLog.Log("FileSelect.OnStart"); //if no database is loaded: load the most recent database if ((Intent.GetBooleanExtra(NoForwardToPasswordActivity, false) == false) && _dbHelper.HasRecentFiles() && !App.Kp2a.OpenDatabases.Any()) { ICursor filesCursor = _dbHelper.FetchAllFiles(); StartManagingCursor(filesCursor); filesCursor.MoveToFirst(); IOConnectionInfo ioc = _dbHelper.CursorToIoc(filesCursor); if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false) { LaunchPasswordActivityForIoc(ioc); } } }
public override bool Init() { Kp2aLog.Log("FP: Init for Dec"); try { _keystore.Load(null); var key = _keystore.GetKey(GetAlias(_keyId), null); var ivParams = new IvParameterSpec(_iv); _cipher.Init(CipherMode.DecryptMode, key, ivParams); _cryptoObject = new BiometricPrompt.CryptoObject(_cipher); return(true); } catch (KeyPermanentlyInvalidatedException e) { Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString()); return(false); } catch (KeyStoreException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (CertificateException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (UnrecoverableKeyException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (IOException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (InvalidKeyException e) { throw new RuntimeException(FailedToInitCipher, e); } }
public void BroadcastDatabaseAction(Context ctx, string action) { Intent i = new Intent(action); //seems like this can happen. This code is for debugging. if (App.Kp2a.GetDb().Ioc == null) { Kp2aLog.LogUnexpectedError(new Exception("App.Kp2a.GetDb().Ioc is null")); return; } i.PutExtra(Strings.ExtraDatabaseFileDisplayname, App.Kp2a.GetFileStorage(App.Kp2a.GetDb().Ioc).GetDisplayName(App.Kp2a.GetDb().Ioc)); i.PutExtra(Strings.ExtraDatabaseFilepath, App.Kp2a.GetDb().Ioc.Path); foreach (var plugin in new PluginDatabase(ctx).GetPluginsWithAcceptedScope(Strings.ScopeDatabaseActions)) { i.SetPackage(plugin); ctx.SendBroadcast(i); } }
protected override void OnCreate(Bundle bundle) { _design.ApplyTheme(); base.OnCreate(bundle); Kp2aLog.Log("SelectStorageLocationActivity.OnCreate"); if (IsStorageSelectionForSave) { throw new Exception("save is not yet implemented. In StartSelectFile, no handler for onCreate is passed."); } bool allowThirdPartyGet = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, false); bool allowThirdPartySend = Intent.GetBooleanExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false); bool isRecreated = false; if (bundle == null) { State = new Bundle(); } else { State = (Bundle)bundle.Clone(); var selectedIocString = bundle.GetString(BundleKeySelectedIoc, null); if (selectedIocString != null) { _selectedIoc = IOConnectionInfo.UnserializeFromString(selectedIocString); } isRecreated = true; } //todo: handle orientation change while dialog is shown if (!isRecreated) { StartFileStorageSelection(RequestCodeFileStorageSelectionForPrimarySelect, allowThirdPartyGet, allowThirdPartySend); } }
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { Kp2aLog.Log("OnRequestPermissionsResult " + (requestCode == FingerprintPermissionRequestCode) + ((grantResults.Length > 0) && (grantResults[0] == Permission.Granted))); if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (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; Kp2aLog.Log("_fingerprintPermissionGranted"); } }
public void UpdateSubMessage(String submessage) { Kp2aLog.Log("status submessage: " + submessage); _submessage = submessage; if (_app != null && _progressDialog != null && _handler != null) { _handler.Post(() => { if (!String.IsNullOrEmpty(submessage)) { _progressDialog.SetMessage(_message + " (" + submessage + ")"); } else { _progressDialog.SetMessage(_message); } } ); } }
protected override void OnCreate(Bundle savedInstanceState) { _design.ApplyTheme(); base.OnCreate(savedInstanceState); //see comment to this in PasswordActivity. //Note that this activity is affected even though it's finished when the app is closed because it //seems that the "app launch intent" is re-delivered, so this might end up here. if ((_appTask == null) && (Intent.Flags.HasFlag(ActivityFlags.LaunchedFromHistory))) { _appTask = new NullTask(); } else { _appTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent); } Kp2aLog.Log("KeePass.OnCreate"); }
public override void OnReceive(Context context, Intent intent) { if (intent.GetStringExtra(Strings.ExtraEntryId) != _activity.Entry.Uuid.ToHexString()) { Kp2aLog.Log("received field for wrong entry " + intent.GetStringExtra(Strings.ExtraEntryId)); return; } if (!new PluginDatabase(context).IsValidAccessToken(intent.GetStringExtra(Strings.ExtraSender), intent.GetStringExtra(Strings.ExtraAccessToken), Strings.ScopeCurrentEntry)) { Kp2aLog.Log("received field with invalid access token from " + intent.GetStringExtra(Strings.ExtraSender)); return; } string key = intent.GetStringExtra(Strings.ExtraFieldId); string value = intent.GetStringExtra(Strings.ExtraFieldValue); bool isProtected = intent.GetBooleanExtra(Strings.ExtraFieldProtected, false); _activity.SetPluginField(key, value, isProtected); }
private bool OpenAutoExecEntries(Database db) { try { string thisDevice = KeeAutoExecExt.ThisDeviceId; foreach (var autoOpenItem in KeeAutoExecExt.GetAutoExecItems(db.KpDatabase)) { if (!autoOpenItem.Enabled) { continue; } if (!KeeAutoExecExt.IsDeviceEnabled(autoOpenItem, thisDevice, out _)) { continue; } if (!IsValidIoc(autoOpenItem)) { continue; } IOConnectionInfo dbIoc; if (KeeAutoExecExt.TryGetDatabaseIoc(autoOpenItem, out dbIoc) && App.Kp2a.TryGetDatabase(dbIoc) == null && App.Kp2a.AttemptedToOpenBefore(dbIoc) == false ) { if (KeeAutoExecExt.AutoOpenEntry(this, autoOpenItem, false, new ActivityLaunchModeRequestCode(ReqCodeOpenNewDb))) { LaunchingOther = true; return(true); } } } } catch (Exception e) { Kp2aLog.LogUnexpectedError(e); } return(false); }
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { Kp2aLog.Log("OnRequestPermissionsResult " + (requestCode == FingerprintPermissionRequestCode) + ((grantResults.Length > 0) && (grantResults[0] == Permission.Granted))); if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (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()); if (_fingerprintIdentifier != null) { b.SetNegativeButton(Resource.String.disable_sensor, (senderAlert, alertArgs) => { btn.SetImageResource(Resource.Drawable.ic_fingerprint_error); _fingerprintIdentifier?.StopListening(); _fingerprintIdentifier = null; }); } else { b.SetNegativeButton(Resource.String.enable_sensor, (senderAlert, alertArgs) => { InitFingerprintUnlock(); }); } b.Show(); }; _fingerprintPermissionGranted = true; Kp2aLog.Log("_fingerprintPermissionGranted"); if (_onResumeDone) { //it seems the permission result is called after onResume sometimes. Repeat fingerprint unlock then. InitFingerprintUnlock(); } } }
public override bool Init() { Kp2aLog.Log("FP: Init for Enc "); try { _keystore.Load(null); var key = _keystore.GetKey(GetAlias(_keyId), null); _cipher.Init(CipherMode.EncryptMode, key); _cryptoObject = new FingerprintManager.CryptoObject(_cipher); return(true); } catch (KeyPermanentlyInvalidatedException) { return(false); } catch (KeyStoreException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (CertificateException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (UnrecoverableKeyException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (IOException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(FailedToInitCipher, e); } catch (InvalidKeyException e) { throw new RuntimeException(FailedToInitCipher, e); } }
public override void OnDestroy() { base.OnDestroy(); var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.Cancel(UnlockedWarningId); // Quick Unlock notification should be removed automatically by the service (if present), as it was the foreground notification. Kp2aLog.Log("OngoingNotificationsService.OnDestroy"); // If the service is killed, then lock the database immediately if (App.Kp2a.DatabaseIsUnlocked) { App.Kp2a.LockDatabase(); } //also remove any notifications of the app notificationManager.CancelAll(); UnregisterReceiver(_screenOffReceiver); }
protected override void OnStart() { base.OnStart(); Kp2aLog.Log("KeePass.OnStart"); ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this); bool showChangeLog = false; try { PackageInfo packageInfo = PackageManager.GetPackageInfo(PackageName, 0); int lastInfoVersionCode = prefs.GetInt(GetString(Resource.String.LastInfoVersionCode_key), 0); if (packageInfo.VersionCode > lastInfoVersionCode) { showChangeLog = true; ISharedPreferencesEditor edit = prefs.Edit(); edit.PutInt(GetString(Resource.String.LastInfoVersionCode_key), packageInfo.VersionCode); EditorCompat.Apply(edit); } } catch (PackageManager.NameNotFoundException) { } #if DEBUG showChangeLog = false; #endif if (showChangeLog) { ChangeLog.ShowChangeLog(this, LaunchNextActivity); } else { LaunchNextActivity(); } }
public void StartListening(FingerprintManager.AuthenticationCallback callback) { if (!IsFingerprintAuthAvailable) { return; } Kp2aLog.Log("FP: StartListening "); var thisSignal = new CancellationSignal(); _cancellationSignal = thisSignal; _cancellationSignal.CancelEvent += (sender, args) => { if (_cancellationSignal == thisSignal) { _cancellationSignal = null; } }; _selfCancelled = false; _callback = callback; _fingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null); }
protected override void OnCreate(Bundle bundle) { _design.ApplyTheme(); base.OnCreate(bundle); Intent i = new Intent(this, typeof(PasswordActivity)); i.SetAction(Intents.StartWithOtp); //things to consider: // PasswordActivity should be resumed if currently active -> this is why single top is used and why PasswordActivity is started // If PasswordActivity is not open already, it may be the wrong place to send our OTP to because maybe the user first needs to select // a file (which might require UI action like entering credentials, all of which is handled in FileSelectActivity) // FileSelectActivity is not on the back stack, it finishes itself. // -> PasswordActivity needs to handle this and return to FSA. i.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop); try { string otp = GetOtpFromIntent(Intent); if (otp == null) { throw new Exception("Otp must not be null!"); } i.PutExtra(Intents.OtpExtraKey, otp); } catch (Exception e) { Kp2aLog.LogUnexpectedError(e); Toast.MakeText(this, "No Yubikey OTP found!", ToastLength.Long).Show(); Finish(); return; } StartActivity(i); Finish(); }
public override void Run() { if (Success) { // Update the ongoing notification App.Kp2a.UpdateOngoingNotification(); if (PreferenceManager.GetDefaultSharedPreferences(_activity).GetBoolean(_activity.GetString(Resource.String.RememberRecentFiles_key), _activity.Resources.GetBoolean(Resource.Boolean.RememberRecentFiles_default))) { // Add to recent files FileDbHelper dbHelper = App.Kp2a.FileDbHelper; //TODO: getFilename always returns "" -> bug? dbHelper.CreateFile(_ioc, Filename); } Intent data = new Intent(); data.PutExtra("ioc", IOConnectionInfo.SerializeToString(_ioc)); _activity.SetResult(Result.Ok, data); _activity.Finish(); } else { DisplayMessage(_activity); try { App.Kp2a.GetFileStorage(_ioc).Delete(_ioc); } catch (Exception e) { //not nice, but not a catastrophic failure if we can't delete the file: Kp2aLog.Log("couldn't delete file after failure! " + e); } } }
public static void CopyToClipboard(Context context, String text) { Android.Content.ClipboardManager clipboardManager = (ClipboardManager)context.GetSystemService(Context.ClipboardService); ClipData clipData = Android.Content.ClipData.NewPlainText("KP2A", text); clipboardManager.PrimaryClip = clipData; if (text == "") { //on some devices, adding empty text does not seem to work. Try again with some garbage. clipData = Android.Content.ClipData.NewPlainText("KP2A", "***"); clipboardManager.PrimaryClip = clipData; //seems to work better on some devices: try { clipboardManager.Text = text; } catch (Exception exception) { Kp2aLog.LogUnexpectedError(exception); } } }
private void OnUseOfflineCacheChanged(object sender, Preference.PreferenceChangeEventArgs e) { //ensure the user gets a matching database if (App.Kp2a.GetDb().Loaded&& !App.Kp2a.GetDb().Ioc.IsLocalFile()) { App.Kp2a.LockDatabase(false); } if (!(bool)e.NewValue) { AlertDialog.Builder builder = new AlertDialog.Builder(Activity); builder.SetTitle(GetString(Resource.String.ClearOfflineCache_title)); builder.SetMessage(GetString(Resource.String.ClearOfflineCache_question)); builder.SetPositiveButton(App.Kp2a.GetResourceString(UiStringKey.yes), (o, args) => { try { App.Kp2a.ClearOfflineCache(); } catch (Exception ex) { Kp2aLog.LogUnexpectedError(ex); Toast.MakeText(Application.Context, ex.Message, ToastLength.Long).Show(); } } ); builder.SetNegativeButton(App.Kp2a.GetResourceString(UiStringKey.no), (o, args) => { ((CheckBoxPreference)e.Preference).Checked = true; } ); builder.SetCancelable(false); Dialog dialog = builder.Create(); dialog.Show(); } }
/** * Indicates whether the specified action can be used as an intent. This * method queries the package manager for installed packages that can * respond to an intent with the specified action. If no suitable package is * found, this method returns false. * * @param context The application's environment. * @param action The Intent action to check for availability. * * @return True if an Intent with the specified action can be sent and * responded to, false otherwise. */ static bool IsIntentAvailable(Context context, String action, String type, List <String> categories) { PackageManager packageManager = context.PackageManager; Intent intent = new Intent(action); if (type != null) { intent.SetType(type); } if (categories != null) { categories.ForEach(c => intent.AddCategory(c)); } IList <ResolveInfo> list = packageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly); foreach (ResolveInfo i in list) { Kp2aLog.Log(i.ActivityInfo.ApplicationInfo.PackageName); } return(list.Count > 0); }
private void ShowToast() { string pluginDisplayName = _pluginPackage; try { pluginDisplayName = PackageManager.GetApplicationLabel(PackageManager.GetApplicationInfo(_pluginPackage, 0)); } catch (Exception e) { Kp2aLog.LogUnexpectedError(e); } if (String.IsNullOrEmpty(_requestedUrl)) { Toast.MakeText(this, GetString(Resource.String.query_credentials, new Java.Lang.Object[] { pluginDisplayName }), ToastLength.Long).Show(); } else { Toast.MakeText(this, GetString(Resource.String.query_credentials_for_url, new Java.Lang.Object[] { pluginDisplayName, _requestedUrl }), ToastLength.Long).Show(); }; }
/// <summary> /// Creates a symmetric key in the Android Key Store which can only be used after the user /// has authenticated with biometry. /// </summary> private void CreateKey() { try { _keystore.Load(null); _keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId), KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) .SetBlockModes(KeyProperties.BlockModeCbc) // Require the user to authenticate with biometry to authorize every use // of the key .SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7) .SetUserAuthenticationRequired(true) .Build()); _keyGen.GenerateKey(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } catch (InvalidAlgorithmParameterException e) { throw new RuntimeException(e); } catch (CertificateException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (System.Exception e) { Kp2aLog.LogUnexpectedError(e); } }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { Kp2aLog.Log("LockingActivity: OnActivityResult " + (requestCode == RequestCodeChallengeYubikey ? "yubichall" : "")); base.OnActivityResult(requestCode, resultCode, data); if ((requestCode == RequestCodeChallengeYubikey) && (CurrentlyWaitingKey != null)) { if (resultCode == Result.Ok) { byte[] challengeResponse = data.GetByteArrayExtra("response"); if ((challengeResponse != null) && (challengeResponse.Length > 0)) { CurrentlyWaitingKey.Response = challengeResponse; } else { CurrentlyWaitingKey.Error = "Did not receive a valid response."; } } else { CurrentlyWaitingKey.Error = "Cancelled Yubichallenge."; } } }
public static void Start(Context ctx) { ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx); String sTimeout = prefs.GetString(ctx.GetString(Resource.String.app_timeout_key), ctx.GetString(Resource.String.clipboard_timeout_default)); long timeout; if (!long.TryParse(sTimeout, out timeout)) { timeout = DefaultTimeout; } if (timeout == -1) { // No timeout don't start timeout service return; } long triggerTime = Java.Lang.JavaSystem.CurrentTimeMillis() + timeout; AlarmManager am = (AlarmManager)ctx.GetSystemService(Context.AlarmService); Kp2aLog.Log("Timeout start"); am.Set(AlarmType.Rtc, triggerTime, BuildIntent(ctx)); }
public override void Run() { try { try { //make sure the file data is stored in the recent files list even if loading fails SaveFileData(_ioc, _keyfileOrProvider); StatusLogger.UpdateMessage(UiStringKey.loading_database); //get the stream data into a single stream variable (databaseStream) regardless whether its preloaded or not: MemoryStream preloadedMemoryStream = _databaseData == null ? null : _databaseData.Result; MemoryStream databaseStream; if (preloadedMemoryStream != null) { databaseStream = preloadedMemoryStream; } else { using (Stream s = _app.GetFileStorage(_ioc).OpenFileForRead(_ioc)) { databaseStream = new MemoryStream(); s.CopyTo(databaseStream); databaseStream.Seek(0, SeekOrigin.Begin); } } //ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess: _format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_app.GetFileStorage(_ioc).GetFileExtension(_ioc))); TryLoad(databaseStream); success = true; } catch (Exception e) { this.Exception = e; throw; } } catch (KeyFileException) { Kp2aLog.Log("KeyFileException"); Finish(false, /*TODO Localize: use Keepass error text KPRes.KeyFileError (including "or invalid format")*/ _app.GetResourceString(UiStringKey.keyfile_does_not_exist), false, Exception); } catch (AggregateException e) { string message = e.Message; foreach (var innerException in e.InnerExceptions) { message = innerException.Message; // Override the message shown with the last (hopefully most recent) inner exception Kp2aLog.LogUnexpectedError(innerException); } Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + message, false, Exception); return; } catch (DuplicateUuidsException e) { Kp2aLog.Log(e.ToString()); Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + e.Message + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception); return; } catch (Exception e) { if (!(e is InvalidCompositeKeyException)) { Kp2aLog.LogUnexpectedError(e); } Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception); return; } }
public override void Run() { if (!_dontSave) { try { if (_db.CanWrite == false) { //this should only happen if there is a problem in the UI so that the user sees an edit interface. Finish(false, "Cannot save changes. File is read-only!"); return; } string message = _app.GetResourceString(UiStringKey.saving_database); if (ShowDatabaseIocInStatus) { message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")"; } StatusLogger.UpdateMessage(message); IOConnectionInfo ioc = _db.Ioc; IFileStorage fileStorage = _app.GetFileStorage(ioc); if (_streamForOrigFile == null) { if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave)) || (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); return; } } if ( (_streamForOrigFile != null) || fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) || //first try to use the fast change detection (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare: ) { //ask user... _app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion, UiStringKey.YesSynchronize, UiStringKey.NoOverwrite, //yes = sync (sender, args) => { Action runHandler = () => { //note: when synced, the file might be downloaded once again from the server. Caching the data //in the hashing function would solve this but increases complexity. I currently assume the files are //small. MergeIn(fileStorage, ioc); PerformSaveWithoutCheck(fileStorage, ioc); _db.UpdateGlobals(); Finish(true); }; RunInWorkerThread(runHandler); }, //no = overwrite (sender, args) => { RunInWorkerThread(() => { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); }); }, //cancel (sender, args) => { RunInWorkerThread(() => Finish(false)); }, _ctx ); } else { PerformSaveWithoutCheck(fileStorage, ioc); Finish(true); } } catch (Exception e) { /* TODO KPDesktop: * catch(Exception exSave) * { * MessageService.ShowSaveWarning(pd.IOConnectionInfo, exSave, true); * bSuccess = false; * } */ Kp2aLog.LogUnexpectedError(e); Finish(false, e.Message); return; } } else { Finish(true); } }