mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-25 10:42:17 -05:00
Key files can be opened from deliberate locations
TODO: fix a problem with .kdb-files and key files Added very basic and not yet functional AndroidContentStorage.cs
This commit is contained in:
parent
2e4c3e3490
commit
3239131a84
2
.gitignore
vendored
2
.gitignore
vendored
@ -282,3 +282,5 @@ Thumbs.db
|
||||
/src/java/MasterKee
|
||||
|
||||
/src/PluginSdkBinding/obj/ReleaseNoNet
|
||||
/src/MasterKeeWinPlugin/bin/Release
|
||||
/src/SamplePlugin
|
||||
|
@ -20,7 +20,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>False</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;INCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;EXCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
|
@ -41,7 +41,7 @@ namespace KeePassLib.Keys
|
||||
/// </summary>
|
||||
public sealed class KcpKeyFile : IUserKey
|
||||
{
|
||||
private string m_strPath;
|
||||
private IOConnectionInfo m_ioc;
|
||||
private ProtectedBinary m_pbKeyData;
|
||||
|
||||
/// <summary>
|
||||
@ -49,7 +49,7 @@ namespace KeePassLib.Keys
|
||||
/// </summary>
|
||||
public string Path
|
||||
{
|
||||
get { return m_strPath; }
|
||||
get { return m_ioc.Path; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -62,6 +62,11 @@ namespace KeePassLib.Keys
|
||||
get { return m_pbKeyData; }
|
||||
}
|
||||
|
||||
public IOConnectionInfo Ioc
|
||||
{
|
||||
get { return m_ioc; }
|
||||
}
|
||||
|
||||
public KcpKeyFile(string strKeyFile)
|
||||
{
|
||||
Construct(IOConnectionInfo.FromPath(strKeyFile), false);
|
||||
@ -82,9 +87,13 @@ namespace KeePassLib.Keys
|
||||
Construct(iocKeyFile, bThrowIfDbFile);
|
||||
}
|
||||
|
||||
private void Construct(IOConnectionInfo iocFile, bool bThrowIfDbFile)
|
||||
public KcpKeyFile(byte[] keyFileContents, IOConnectionInfo iocKeyFile, bool bThrowIfDbFile)
|
||||
{
|
||||
Construct(keyFileContents, iocKeyFile, bThrowIfDbFile);
|
||||
}
|
||||
|
||||
private void Construct(byte[] pbFileData, IOConnectionInfo iocKeyFile, bool bThrowIfDbFile)
|
||||
{
|
||||
byte[] pbFileData = IOConnection.ReadFile(iocFile);
|
||||
if (pbFileData == null) throw new Java.IO.FileNotFoundException();
|
||||
|
||||
if (bThrowIfDbFile && (pbFileData.Length >= 8))
|
||||
@ -110,12 +119,18 @@ namespace KeePassLib.Keys
|
||||
|
||||
if (pbKey == null) throw new InvalidOperationException();
|
||||
|
||||
m_strPath = iocFile.Path;
|
||||
m_ioc = iocKeyFile;
|
||||
m_pbKeyData = new ProtectedBinary(true, pbKey);
|
||||
|
||||
MemUtil.ZeroByteArray(pbKey);
|
||||
}
|
||||
|
||||
private void Construct(IOConnectionInfo iocFile, bool bThrowIfDbFile)
|
||||
{
|
||||
byte[] pbFileData = IOConnection.ReadFile(iocFile);
|
||||
Construct(pbFileData, iocFile, bThrowIfDbFile);
|
||||
}
|
||||
|
||||
// public void Clear()
|
||||
// {
|
||||
// m_strPath = string.Empty;
|
||||
|
183
src/Kp2aBusinessLogic/Io/AndroidContentStorage.cs
Normal file
183
src/Kp2aBusinessLogic/Io/AndroidContentStorage.cs
Normal file
@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Serialization;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
//TODOC,TOTEST, TODO: unimplemented methods?
|
||||
public class AndroidContentStorage: IFileStorage
|
||||
{
|
||||
private readonly Context _ctx;
|
||||
|
||||
public AndroidContentStorage(Context ctx)
|
||||
{
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
public IEnumerable<string> SupportedProtocols
|
||||
{
|
||||
get { yield return "content"; }
|
||||
}
|
||||
|
||||
public void Delete(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream OpenFileForRead(IOConnectionInfo ioc)
|
||||
{
|
||||
return _ctx.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(ioc.Path));
|
||||
}
|
||||
|
||||
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
|
||||
{
|
||||
return new AndroidContentWriteTransaction(ioc.Path, _ctx);
|
||||
}
|
||||
|
||||
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public bool RequiresCredentials(IOConnectionInfo ioc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CreateDirectory(IOConnectionInfo ioc, string newDirName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool RequiresSetup(IOConnectionInfo ioConnection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string IocToPath(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path;
|
||||
}
|
||||
|
||||
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
activity.IocToIntent(intent, new IOConnectionInfo() { Path = protocolId + "://" });
|
||||
activity.OnImmediateResult(requestCode, (int)FileStorageResults.FileChooserPrepared, intent);
|
||||
}
|
||||
|
||||
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
|
||||
bool alwaysReturnSuccess)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
activity.IocToIntent(intent, ioc);
|
||||
activity.OnImmediateResult(requestCode, (int)FileStorageResults.FileUsagePrepared, intent);
|
||||
}
|
||||
|
||||
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnResume(IFileStorageSetupActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnStart(IFileStorageSetupActivity activity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetDisplayName(IOConnectionInfo ioc)
|
||||
{
|
||||
return ioc.Path;
|
||||
}
|
||||
|
||||
public string CreateFilePath(string parent, string newFilename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidContentWriteTransaction : IWriteTransaction
|
||||
{
|
||||
private readonly string _path;
|
||||
private readonly Context _ctx;
|
||||
private MemoryStream _memoryStream;
|
||||
|
||||
public AndroidContentWriteTransaction(string path, Context ctx)
|
||||
{
|
||||
_path = path;
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_memoryStream.Dispose();
|
||||
}
|
||||
|
||||
public Stream OpenFile()
|
||||
{
|
||||
_memoryStream = new MemoryStream();
|
||||
return _memoryStream;
|
||||
}
|
||||
|
||||
public void CommitWrite()
|
||||
{
|
||||
using (Stream outputStream = _ctx.ContentResolver.OpenOutputStream(Android.Net.Uri.Parse(_path)))
|
||||
{
|
||||
outputStream.Write(_memoryStream.ToArray(), 0, (int)_memoryStream.Length);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;INCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;EXCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
@ -64,6 +64,7 @@
|
||||
<Compile Include="DataExchange\Formats\KeePassKdb2x.cs" />
|
||||
<Compile Include="DataExchange\Formats\KeePassXml2x.cs" />
|
||||
<Compile Include="DataExchange\PwExportInfo.cs" />
|
||||
<Compile Include="Io\AndroidContentStorage.cs" />
|
||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||
<Compile Include="Io\CachingFileStorage.cs" />
|
||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
||||
|
@ -11,5 +11,5 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-20
|
||||
target=android-19
|
||||
android.library=true
|
||||
|
Binary file not shown.
@ -47,10 +47,14 @@ package com.keepassdroid.database;
|
||||
|
||||
// Java
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
@ -125,18 +129,18 @@ public class PwDatabaseV3 {
|
||||
|
||||
|
||||
|
||||
public void setMasterKey(String key, String keyFileName)
|
||||
public void setMasterKey(String key, InputStream keyfileStream)
|
||||
throws InvalidKeyFileException, IOException {
|
||||
assert( key != null && keyFileName != null );
|
||||
assert( key != null && keyfileStream != null );
|
||||
|
||||
masterKey = getMasterKey(key, keyFileName);
|
||||
masterKey = getMasterKey(key, keyfileStream);
|
||||
}
|
||||
|
||||
protected byte[] getCompositeKey(String key, String keyFileName)
|
||||
protected byte[] getCompositeKey(String key, InputStream keyfileStream)
|
||||
throws InvalidKeyFileException, IOException {
|
||||
assert(key != null && keyFileName != null);
|
||||
assert(key != null && keyfileStream != null);
|
||||
|
||||
byte[] fileKey = getFileKey(keyFileName);
|
||||
byte[] fileKey = getFileKey(keyfileStream);
|
||||
|
||||
byte[] passwordKey = getPasswordKey(key);
|
||||
|
||||
@ -152,45 +156,39 @@ public class PwDatabaseV3 {
|
||||
return md.digest(fileKey);
|
||||
}
|
||||
|
||||
protected byte[] getFileKey(String fileName)
|
||||
protected byte[] getFileKey(InputStream keyfileStream)
|
||||
throws InvalidKeyFileException, IOException {
|
||||
assert(fileName != null);
|
||||
assert(keyfileStream != null);
|
||||
|
||||
File keyfile = new File(fileName);
|
||||
|
||||
if ( ! keyfile.exists() ) {
|
||||
throw new InvalidKeyFileException();
|
||||
byte[] buff = new byte[8000];
|
||||
|
||||
int bytesRead = 0;
|
||||
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
|
||||
while ((bytesRead = keyfileStream.read(buff)) != -1) {
|
||||
bao.write(buff, 0, bytesRead);
|
||||
}
|
||||
|
||||
byte[] key = loadXmlKeyFile(fileName);
|
||||
if ( key != null ) {
|
||||
return key;
|
||||
}
|
||||
byte[] keyFileData = bao.toByteArray();
|
||||
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(keyfile);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new InvalidKeyFileException();
|
||||
}
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(keyFileData);
|
||||
|
||||
BufferedInputStream bis = new BufferedInputStream(fis, 64);
|
||||
|
||||
long fileSize = keyfile.length();
|
||||
if ( fileSize == 0 ) {
|
||||
throw new KeyFileEmptyException();
|
||||
} else if ( fileSize == 32 ) {
|
||||
|
||||
if ( keyFileData.length == 32 ) {
|
||||
byte[] outputKey = new byte[32];
|
||||
if ( bis.read(outputKey, 0, 32) != 32 ) {
|
||||
if ( bin.read(outputKey, 0, 32) != 32 ) {
|
||||
throw new IOException("Error reading key.");
|
||||
}
|
||||
|
||||
return outputKey;
|
||||
} else if ( fileSize == 64 ) {
|
||||
} else if ( keyFileData.length == 64 ) {
|
||||
byte[] hex = new byte[64];
|
||||
|
||||
bis.mark(64);
|
||||
if ( bis.read(hex, 0, 64) != 64 ) {
|
||||
bin.mark(64);
|
||||
if ( bin.read(hex, 0, 64) != 64 ) {
|
||||
throw new IOException("Error reading key.");
|
||||
}
|
||||
|
||||
@ -198,7 +196,7 @@ public class PwDatabaseV3 {
|
||||
return hexStringToByteArray(new String(hex));
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// Key is not base 64, treat it as binary data
|
||||
bis.reset();
|
||||
bin.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,7 +212,7 @@ public class PwDatabaseV3 {
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
int bytesRead = bis.read(buffer, 0, 2048);
|
||||
bytesRead = bin.read(buffer, 0, 2048);
|
||||
if ( bytesRead == -1 ) break; // End of file
|
||||
|
||||
md.update(buffer, 0, bytesRead);
|
||||
@ -495,16 +493,16 @@ public class PwDatabaseV3 {
|
||||
return newId;
|
||||
}
|
||||
|
||||
public byte[] getMasterKey(String key, String keyFileName)
|
||||
public byte[] getMasterKey(String key, InputStream keyfileStream)
|
||||
throws InvalidKeyFileException, IOException {
|
||||
assert (key != null && keyFileName != null);
|
||||
assert (key != null && keyfileStream != null);
|
||||
|
||||
if (key.length() > 0 && keyFileName.length() > 0) {
|
||||
return getCompositeKey(key, keyFileName);
|
||||
if (key.length() > 0 && keyfileStream != null) {
|
||||
return getCompositeKey(key, keyfileStream);
|
||||
} else if (key.length() > 0) {
|
||||
return getPasswordKey(key);
|
||||
} else if (keyFileName.length() > 0) {
|
||||
return getFileKey(keyFileName);
|
||||
} else if (keyfileStream != null) {
|
||||
return getFileKey(keyfileStream);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Key cannot be empty.");
|
||||
}
|
||||
@ -515,11 +513,6 @@ public class PwDatabaseV3 {
|
||||
return getPasswordKey(key, "ISO-8859-1");
|
||||
}
|
||||
|
||||
protected byte[] loadXmlKeyFile(String fileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long getNumRounds() {
|
||||
return numKeyEncRounds;
|
||||
|
@ -123,13 +123,13 @@ public class ImporterV3 {
|
||||
* @throws InvalidAlgorithmParameterException if error decrypting main file body.
|
||||
* @throws ShortBufferException if error decrypting main file body.
|
||||
*/
|
||||
public PwDatabaseV3 openDatabase( InputStream inStream, String password, String keyfile )
|
||||
public PwDatabaseV3 openDatabase( InputStream inStream, String password, InputStream keyfileStream )
|
||||
throws IOException, InvalidDBException
|
||||
{
|
||||
return openDatabase(inStream, password, keyfile, new UpdateStatus());
|
||||
return openDatabase(inStream, password, keyfileStream, new UpdateStatus());
|
||||
}
|
||||
|
||||
public PwDatabaseV3 openDatabase( InputStream inStream, String password, String keyfile, UpdateStatus status )
|
||||
public PwDatabaseV3 openDatabase( InputStream inStream, String password, InputStream keyfileStream, UpdateStatus status )
|
||||
throws IOException, InvalidDBException
|
||||
{
|
||||
PwDatabaseV3 newManager;
|
||||
@ -175,7 +175,7 @@ public class ImporterV3 {
|
||||
}
|
||||
|
||||
newManager = createDB();
|
||||
newManager.setMasterKey( password, keyfile );
|
||||
newManager.setMasterKey( password, keyfileStream );
|
||||
|
||||
// Select algorithm
|
||||
if( (hdr.flags & PwDbHeaderV3.FLAG_RIJNDAEL) != 0 ) {
|
||||
|
Binary file not shown.
@ -327,9 +327,9 @@ namespace keepass2android
|
||||
defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, OnReceiveSftpData);
|
||||
Util.ShowSftpDialog(this, OnReceiveSftpData, () => { });
|
||||
else
|
||||
Util.ShowFilenameDialog(this, OnCreateButton, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Util.ShowFilenameDialog(this, OnCreateButton, null, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
), true, RequestCodeDbFilename, protocolId);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
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
|
||||
@ -682,7 +682,7 @@ namespace keepass2android
|
||||
addBinaryButton.SetCompoundDrawablesWithIntrinsicBounds( Resources.GetDrawable(Android.Resource.Drawable.IcMenuAdd) , null, null, null);
|
||||
addBinaryButton.Click += (sender, e) =>
|
||||
{
|
||||
Util.ShowBrowseDialog("/mnt/sdcard", this, Intents.RequestCodeFileBrowseForBinary, false);
|
||||
Util.ShowBrowseDialog(this, Intents.RequestCodeFileBrowseForBinary, false);
|
||||
|
||||
};
|
||||
binariesGroup.AddView(addBinaryButton,layoutParams);
|
||||
|
@ -61,9 +61,9 @@ namespace keepass2android
|
||||
defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, OnReceiveSftpData);
|
||||
Util.ShowSftpDialog(this, OnReceiveSftpData, () => { });
|
||||
else
|
||||
Util.ShowFilenameDialog(this, OnCreateButton, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Util.ShowFilenameDialog(this, OnCreateButton, null, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
), true, RequestCodeDbFilename, protocolId);
|
||||
|
@ -14,7 +14,7 @@ namespace keepass2android
|
||||
[Activity (Label = "@string/app_name", ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden , Theme="@style/NoTitleBar")]
|
||||
public class FileStorageSelectionActivity : ListActivity
|
||||
{
|
||||
private ActivityDesign _design;
|
||||
private readonly ActivityDesign _design;
|
||||
|
||||
private FileStorageAdapter _fileStorageAdapter;
|
||||
|
||||
@ -42,6 +42,9 @@ namespace keepass2android
|
||||
//put file:// to the top
|
||||
_protocolIds.Remove("file");
|
||||
_protocolIds.Insert(0, "file");
|
||||
//remove "content" (covered by androidget)
|
||||
_protocolIds.Remove("content");
|
||||
|
||||
if (context.Intent.GetBooleanExtra(AllowThirdPartyAppGet, false))
|
||||
_protocolIds.Add("androidget");
|
||||
if (context.Intent.GetBooleanExtra(AllowThirdPartyAppSend, false))
|
||||
|
@ -24,6 +24,7 @@ using System.Xml.Serialization;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
@ -86,7 +87,7 @@ namespace keepass2android
|
||||
private const int RequestCodePrepareDbFile = 1000;
|
||||
private const int RequestCodePrepareOtpAuxFile = 1001;
|
||||
private const int RequestCodeChallengeYubikey = 1002;
|
||||
|
||||
private const int RequestCodeSelectKeyfile = 1003;
|
||||
|
||||
private Task<MemoryStream> _loadDbTask;
|
||||
private IOConnectionInfo _ioConnection;
|
||||
@ -137,6 +138,7 @@ namespace keepass2android
|
||||
private ActivityDesign _design;
|
||||
private bool _performingLoad;
|
||||
|
||||
|
||||
public PasswordActivity (IntPtr javaReference, JniHandleOwnership transfer)
|
||||
: base(javaReference, transfer)
|
||||
{
|
||||
@ -258,26 +260,20 @@ namespace keepass2android
|
||||
|
||||
KcpKeyFile kcpKeyfile = (KcpKeyFile)App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof(KcpKeyFile));
|
||||
|
||||
SetEditText(Resource.Id.pass_keyfile, kcpKeyfile.Path);
|
||||
FindViewById<TextView>(Resource.Id.label_keyfilename).Text =
|
||||
App.Kp2a.GetFileStorage(kcpKeyfile.Ioc).GetDisplayName(kcpKeyfile.Ioc);
|
||||
|
||||
}
|
||||
}
|
||||
App.Kp2a.LockDatabase(false);
|
||||
break;
|
||||
case Result.Ok: // Key file browse dialog OK'ed.
|
||||
if (requestCode == Intents.RequestCodeFileBrowseForKeyfile) {
|
||||
string filename = Util.IntentToFilename(data, this);
|
||||
if (filename != null) {
|
||||
if (filename.StartsWith("file://")) {
|
||||
filename = filename.Substring(7);
|
||||
}
|
||||
|
||||
filename = URLDecoder.Decode(filename);
|
||||
|
||||
EditText fn = (EditText) FindViewById(Resource.Id.pass_keyfile);
|
||||
fn.Text = filename;
|
||||
|
||||
}
|
||||
case Result.Ok:
|
||||
if (requestCode == RequestCodeSelectKeyfile)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
SetIoConnectionFromIntent(ioc, data);
|
||||
_keyFileOrProvider = IOConnectionInfo.SerializeToString(ioc);
|
||||
UpdateKeyfileIocView();
|
||||
}
|
||||
break;
|
||||
case (Result)FileStorageResults.FileUsagePrepared:
|
||||
@ -354,6 +350,39 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void LoadOtpFile()
|
||||
{
|
||||
new LoadingDialog<object, object, object>(this, true,
|
||||
@ -543,14 +572,11 @@ namespace keepass2android
|
||||
InitializeFilenameView();
|
||||
|
||||
if (KeyProviderType == KeyProviders.KeyFile)
|
||||
SetEditText(Resource.Id.pass_keyfile, _keyFileOrProvider);
|
||||
|
||||
FindViewById<EditText>(Resource.Id.pass_keyfile).TextChanged +=
|
||||
(sender, args) =>
|
||||
{
|
||||
_keyFileOrProvider = FindViewById<EditText>(Resource.Id.pass_keyfile).Text;
|
||||
UpdateOkButtonState();
|
||||
};
|
||||
UpdateKeyfileIocView();
|
||||
}
|
||||
|
||||
|
||||
|
||||
FindViewById<EditText>(Resource.Id.password).TextChanged +=
|
||||
(sender, args) =>
|
||||
@ -705,20 +731,14 @@ namespace keepass2android
|
||||
|
||||
private void InitializeKeyfileBrowseButton()
|
||||
{
|
||||
ImageButton browse = (ImageButton) FindViewById(Resource.Id.browse_button);
|
||||
browse.Click += (sender, evt) =>
|
||||
var browseButton = (Button)FindViewById(Resource.Id.btn_change_location);
|
||||
browseButton.Click += (sender, evt) =>
|
||||
{
|
||||
string filename = null;
|
||||
if (!String.IsNullOrEmpty(_ioConnection.Path))
|
||||
{
|
||||
File keyfile = new File(_ioConnection.Path);
|
||||
File parent = keyfile.ParentFile;
|
||||
if (parent != null)
|
||||
{
|
||||
filename = parent.AbsolutePath;
|
||||
}
|
||||
}
|
||||
Util.ShowBrowseDialog(filename, this, Intents.RequestCodeFileBrowseForKeyfile, false);
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
@ -738,7 +758,7 @@ namespace keepass2android
|
||||
break;
|
||||
case 1:
|
||||
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
|
||||
_keyFileOrProvider = FindViewById<EditText>(Resource.Id.pass_keyfile).Text;
|
||||
_keyFileOrProvider = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
|
||||
break;
|
||||
case 2:
|
||||
_keyFileOrProvider = KeyProviderIdOtp;
|
||||
@ -779,7 +799,7 @@ namespace keepass2android
|
||||
_showPassword = savedInstanceState.GetBoolean(ShowpasswordKey, false);
|
||||
MakePasswordMaskedOrVisible();
|
||||
|
||||
_keyFileOrProvider = FindViewById<EditText>(Resource.Id.pass_keyfile).Text = savedInstanceState.GetString(KeyFileOrProviderKey);
|
||||
_keyFileOrProvider = savedInstanceState.GetString(KeyFileOrProviderKey);
|
||||
_password = FindViewById<EditText>(Resource.Id.password).Text = savedInstanceState.GetString(PasswordKey);
|
||||
|
||||
_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey));
|
||||
@ -850,6 +870,11 @@ namespace keepass2android
|
||||
FindViewById(Resource.Id.keyfileLine).Visibility = KeyProviderType == KeyProviders.KeyFile
|
||||
? ViewStates.Visible
|
||||
: ViewStates.Gone;
|
||||
if (KeyProviderType == KeyProviders.KeyFile)
|
||||
{
|
||||
UpdateKeyfileIocView();
|
||||
}
|
||||
|
||||
FindViewById(Resource.Id.otpView).Visibility = KeyProviderType == KeyProviders.Otp
|
||||
? ViewStates.Visible
|
||||
: ViewStates.Gone;
|
||||
@ -880,12 +905,26 @@ namespace keepass2android
|
||||
{
|
||||
try
|
||||
{
|
||||
compositeKey.AddUserKey(new KcpKeyFile(_keyFileOrProvider));
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
catch (System.IO.FileNotFoundException e)
|
||||
{
|
||||
Kp2aLog.Log(e.ToString());
|
||||
Toast.MakeText(this, App.Kp2a.GetResourceString(UiStringKey.keyfile_does_not_exist), ToastLength.Long).Show();
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Kp2aLog.Log(e.ToString());
|
||||
Toast.MakeText(this, App.Kp2a.GetResourceString(UiStringKey.keyfile_does_not_exist), ToastLength.Long).Show();
|
||||
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1032,10 +1071,19 @@ namespace keepass2android
|
||||
var fileStorage = App.Kp2a.GetFileStorage(_ioConnection);
|
||||
var stream = fileStorage.OpenFileForRead(_ioConnection);
|
||||
|
||||
var memoryStream = StreamToMemoryStream(stream);
|
||||
|
||||
Kp2aLog.Log("Pre-loading database file completed");
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private static MemoryStream StreamToMemoryStream(Stream stream)
|
||||
{
|
||||
var memoryStream = stream as MemoryStream;
|
||||
if (memoryStream == null)
|
||||
{
|
||||
// Read the file into memory
|
||||
// Read the stream into memory
|
||||
int capacity = 4096; // Default initial capacity, if stream can't report it.
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
@ -1044,11 +1092,8 @@ namespace keepass2android
|
||||
memoryStream = new MemoryStream(capacity);
|
||||
stream.CopyTo(memoryStream);
|
||||
stream.Close();
|
||||
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
Kp2aLog.Log("Pre-loading database file completed");
|
||||
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
|
6126
src/keepass2android/Resources/Resource.designer.cs
generated
6126
src/keepass2android/Resources/Resource.designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -86,25 +86,61 @@ android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_menu_view" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/keyfileLine"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/pass_keyfile"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="bottom"
|
||||
android:hint="@string/entry_keyfile" />
|
||||
<ImageButton
|
||||
android:id="@+id/browse_button"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/keyfile_heading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_launcher_folder_small" />
|
||||
android:text="@string/keyfile_heading" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/filestorage_logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_storage_file"
|
||||
android:padding="5dp"
|
||||
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filestorage_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="Local file (TODO!)"
|
||||
android:textSize="16dp" >
|
||||
</TextView>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label_keyfilename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="[path]"
|
||||
android:layout_marginLeft="18dp"
|
||||
/>
|
||||
|
||||
<Button android:id="@+id/btn_change_location"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_change_location"
|
||||
style="@style/TextAppearance_SubElement"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/otpView"
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
<string name="ShowGroupInEntry_title">Show group name in entry view</string>
|
||||
|
||||
<string name="unknown_uri_scheme">Sorry! Keepass2Android cannot handle the returned URI %1$s. Please contact the developer!</string>
|
||||
|
||||
<string name="security_prefs">Security</string>
|
||||
<string name="display_prefs">Display</string>
|
||||
<string name="password_access_prefs">Password entry access</string>
|
||||
@ -68,6 +70,7 @@
|
||||
<string name="entry_expires">Expires</string>
|
||||
<string name="entry_group_name">Group Name</string>
|
||||
<string name="entry_keyfile">Key file (optional)</string>
|
||||
<string name="keyfile_heading">Key file</string>
|
||||
<string name="entry_modified">Modified</string>
|
||||
<string name="entry_password">Password</string>
|
||||
<string name="entry_save">Save</string>
|
||||
@ -114,6 +117,7 @@
|
||||
<string name="invalid_algorithm">Invalid algorithm.</string>
|
||||
<string name="invalid_db_sig">Database format not recognized.</string>
|
||||
<string name="keyfile_does_not_exist">Key file does not exist.</string>
|
||||
<string name="no_keyfile_selected">No key file selected.</string>
|
||||
<string name="keyfile_is_empty">Key file is empty.</string>
|
||||
<string name="length">Length</string>
|
||||
<string name="list_size_title">Group list size</string>
|
||||
|
245
src/keepass2android/SelectStorageLocationActivity.cs
Normal file
245
src/keepass2android/SelectStorageLocationActivity.cs
Normal file
@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using KeePassLib.Serialization;
|
||||
using keepass2android.Io;
|
||||
using Environment = Android.OS.Environment;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "")]
|
||||
public class SelectStorageLocationActivity : Activity
|
||||
{
|
||||
private ActivityDesign _design;
|
||||
private bool _isRecreated;
|
||||
private const int RequestCodeFileStorageSelection = 983713;
|
||||
|
||||
public SelectStorageLocationActivity()
|
||||
{
|
||||
_design = new ActivityDesign(this);
|
||||
}
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
|
||||
_design.ApplyTheme();
|
||||
|
||||
|
||||
Kp2aLog.Log("SelectStorageLocationActivity.OnCreate");
|
||||
|
||||
IsForSave = Intent.GetBooleanExtra(FileStorageSetupDefs.ExtraIsForSave, false);
|
||||
if (IsForSave)
|
||||
{
|
||||
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);
|
||||
if (bundle == null)
|
||||
State = new Bundle();
|
||||
else
|
||||
{
|
||||
State = (Bundle)bundle.Clone();
|
||||
_isRecreated = true;
|
||||
}
|
||||
|
||||
if (!_isRecreated)
|
||||
{
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, allowThirdPartyGet);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, allowThirdPartySend);
|
||||
StartActivityForResult(intent, RequestCodeFileStorageSelection);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected Bundle State { get; set; }
|
||||
|
||||
protected bool IsForSave { get; set; }
|
||||
|
||||
|
||||
protected override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
base.OnSaveInstanceState(outState);
|
||||
|
||||
outState.PutAll(State);
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
_design.ReapplyTheme();
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == RequestCodeFileStorageSelection)
|
||||
{
|
||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||
{
|
||||
|
||||
string protocolId = data.GetStringExtra("protocolId");
|
||||
|
||||
if (protocolId == "androidget")
|
||||
{
|
||||
Util.ShowBrowseDialog(this, Intents.RequestCodeFileBrowseForOpen, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
|
||||
OnActivityResult,
|
||||
defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, OnReceivedSftpData, ReturnCancel);
|
||||
else
|
||||
Util.ShowFilenameDialog(this, OnOpenButton, null, ReturnCancel, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
), false, 0, protocolId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
#else
|
||||
ReturnIoc(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx" });
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE")))
|
||||
{
|
||||
Toast.MakeText(this, data.GetStringExtra("EXTRA_ERROR_MESSAGE"), ToastLength.Long).Show();
|
||||
}
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (requestCode == Intents.RequestCodeFileBrowseForOpen)
|
||||
{
|
||||
if (resultCode == Result.Ok)
|
||||
{
|
||||
string filename = Util.IntentToFilename(data, this);
|
||||
if (filename != null)
|
||||
{
|
||||
if (filename.StartsWith("file://"))
|
||||
{
|
||||
filename = filename.Substring(7);
|
||||
filename = Java.Net.URLDecoder.Decode(filename);
|
||||
}
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = filename
|
||||
};
|
||||
|
||||
ReturnIoc(ioc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Data.Scheme == "content")
|
||||
{
|
||||
ReturnIoc(IOConnectionInfo.FromPath(data.DataString));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.MakeText(this, Resources.GetString(Resource.String.unknown_uri_scheme, new Java.Lang.Object[] {data.DataString}),
|
||||
ToastLength.Long).Show();
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnCancel();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void ReturnCancel()
|
||||
{
|
||||
SetResult(Result.Canceled);
|
||||
Finish();
|
||||
}
|
||||
|
||||
private void ReturnIoc(IOConnectionInfo ioc)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
PasswordActivity.PutIoConnectionToIntent(ioc, intent);
|
||||
SetResult(Result.Ok, intent);
|
||||
Finish();
|
||||
|
||||
}
|
||||
|
||||
private bool OnReceivedSftpData(string filename)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
#else
|
||||
ReturnIoc(ioc);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
private void StartFileChooser(string defaultPath)
|
||||
{
|
||||
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
||||
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||
if (defaultPath.StartsWith("file://"))
|
||||
{
|
||||
fileProviderAuthority = PackageName+".android-filechooser.localfile";
|
||||
}
|
||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||
defaultPath);
|
||||
|
||||
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
|
||||
#endif
|
||||
private bool OnOpenButton(String fileName)
|
||||
{
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = fileName
|
||||
};
|
||||
|
||||
ReturnIoc(ioc);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -141,7 +141,7 @@ namespace keepass2android
|
||||
return list.Count > 0;
|
||||
}
|
||||
|
||||
public static void ShowBrowseDialog(string filename, Activity act, int requestCodeBrowse, bool forSaving)
|
||||
public static void ShowBrowseDialog(Activity act, int requestCodeBrowse, bool forSaving)
|
||||
{
|
||||
if ((!forSaving) && (IsIntentAvailable(act, Intent.ActionGetContent, "*/*", new List<string> { Intent.CategoryOpenable})))
|
||||
{
|
||||
@ -223,7 +223,7 @@ namespace keepass2android
|
||||
|
||||
public delegate bool FileSelectedHandler(string filename);
|
||||
|
||||
public static void ShowSftpDialog(Activity activity, FileSelectedHandler onStartBrowse)
|
||||
public static void ShowSftpDialog(Activity activity, FileSelectedHandler onStartBrowse, Action onCancel)
|
||||
{
|
||||
#if !EXCLUDE_JAVAFILESTORAGE
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
@ -244,7 +244,7 @@ namespace keepass2android
|
||||
password);
|
||||
onStartBrowse(sftpPath);
|
||||
});
|
||||
builder.SetNegativeButton(Android.Resource.String.Cancel, (sender, args) => {});
|
||||
builder.SetNegativeButton(Android.Resource.String.Cancel, onCancel);
|
||||
builder.SetTitle(activity.GetString(Resource.String.enter_sftp_login_title));
|
||||
Dialog dialog = builder.Create();
|
||||
|
||||
@ -252,8 +252,22 @@ namespace keepass2android
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void ShowFilenameDialog(Activity activity, FileSelectedHandler onOpen, FileSelectedHandler onCreate, bool showBrowseButton,
|
||||
string defaultFilename, string detailsText, int requestCodeBrowse)
|
||||
class DismissListener: Java.Lang.Object, IDialogInterfaceOnDismissListener
|
||||
{
|
||||
private readonly Action _onDismiss;
|
||||
|
||||
public DismissListener(Action onDismiss)
|
||||
{
|
||||
_onDismiss = onDismiss;
|
||||
}
|
||||
|
||||
public void OnDismiss(IDialogInterface dialog)
|
||||
{
|
||||
_onDismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowFilenameDialog(Activity activity, FileSelectedHandler onOpen, FileSelectedHandler onCreate, Action onCancel, bool showBrowseButton, string defaultFilename, string detailsText, int requestCodeBrowse)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.file_selection_filename, null));
|
||||
@ -262,6 +276,7 @@ namespace keepass2android
|
||||
|
||||
Button openButton = (Button) dialog.FindViewById(Resource.Id.open);
|
||||
Button createButton = (Button) dialog.FindViewById(Resource.Id.create);
|
||||
|
||||
TextView enterFilenameDetails = (TextView) dialog.FindViewById(Resource.Id.label_open_by_filename_details);
|
||||
openButton.Visibility = onOpen != null ? ViewStates.Visible : ViewStates.Gone;
|
||||
createButton.Visibility = onCreate != null? ViewStates.Visible : ViewStates.Gone;
|
||||
@ -290,7 +305,15 @@ namespace keepass2android
|
||||
};
|
||||
|
||||
Button cancelButton = (Button) dialog.FindViewById(Resource.Id.fnv_cancel);
|
||||
cancelButton.Click += (sender, e) => dialog.Dismiss();
|
||||
cancelButton.Click += delegate
|
||||
{
|
||||
dialog.Dismiss();
|
||||
|
||||
};
|
||||
|
||||
if (onCancel != null)
|
||||
dialog.SetOnDismissListener(new DismissListener(onCancel));
|
||||
|
||||
|
||||
ImageButton browseButton = (ImageButton) dialog.FindViewById(Resource.Id.browse_button);
|
||||
if (!showBrowseButton)
|
||||
@ -301,7 +324,7 @@ namespace keepass2android
|
||||
{
|
||||
string filename = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text;
|
||||
|
||||
Util.ShowBrowseDialog(filename, activity, requestCodeBrowse, onCreate != null);
|
||||
Util.ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null);
|
||||
|
||||
};
|
||||
|
||||
|
@ -443,7 +443,8 @@ namespace keepass2android
|
||||
new SftpFileStorage(this),
|
||||
#endif
|
||||
#endif
|
||||
new BuiltInFileStorage(this)
|
||||
new BuiltInFileStorage(this),
|
||||
new AndroidContentStorage(Application.Context)
|
||||
};
|
||||
}
|
||||
return _fileStorages;
|
||||
|
@ -69,6 +69,7 @@ namespace keepass2android
|
||||
view.FileSelectButtons _fileSelectButtons;
|
||||
|
||||
internal AppTask AppTask;
|
||||
private const int RequestCodeSelectIoc = 456;
|
||||
|
||||
public const string NoForwardToPasswordActivity = "NoForwardToPasswordActivity";
|
||||
|
||||
@ -129,9 +130,11 @@ namespace keepass2android
|
||||
|
||||
EventHandler openFileButtonClick = (sender, e) =>
|
||||
{
|
||||
Intent intent = new Intent(this, typeof(FileStorageSelectionActivity));
|
||||
Intent intent = new Intent(this, typeof(SelectStorageLocationActivity));
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true);
|
||||
StartActivityForResult(intent, 0);
|
||||
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
|
||||
intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false);
|
||||
StartActivityForResult(intent, RequestCodeSelectIoc);
|
||||
|
||||
};
|
||||
openFileButton.Click += openFileButtonClick;
|
||||
@ -294,19 +297,7 @@ namespace keepass2android
|
||||
App.Kp2a.GetFileStorage(ioc)
|
||||
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), ioc, 0, false);
|
||||
}
|
||||
private bool OnOpenButton(String fileName)
|
||||
{
|
||||
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = fileName
|
||||
};
|
||||
|
||||
LaunchPasswordActivityForIoc(ioc);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
@ -326,59 +317,6 @@ namespace keepass2android
|
||||
|
||||
FillData();
|
||||
|
||||
if (resultCode == KeePass.ExitFileStorageSelectionOk)
|
||||
{
|
||||
|
||||
string protocolId = data.GetStringExtra("protocolId");
|
||||
|
||||
if (protocolId == "androidget")
|
||||
{
|
||||
string defaultFilename = Environment.ExternalStorageDirectory +
|
||||
GetString(Resource.String.default_file_path);
|
||||
Util.ShowBrowseDialog(defaultFilename, this, Intents.RequestCodeFileBrowseForOpen, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Kp2a.GetFileStorage(protocolId).StartSelectFile(new FileStorageSetupInitiatorActivity(this,
|
||||
OnActivityResult,
|
||||
defaultPath =>
|
||||
{
|
||||
if (defaultPath.StartsWith("sftp://"))
|
||||
Util.ShowSftpDialog(this, OnReceivedSftpData);
|
||||
else
|
||||
Util.ShowFilenameDialog(this, OnOpenButton, null, false, defaultPath, GetString(Resource.String.enter_filename_details_url),
|
||||
Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
), false, 0, protocolId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ( (requestCode == Intents.RequestCodeFileBrowseForCreate
|
||||
|| requestCode == Intents.RequestCodeFileBrowseForOpen)
|
||||
&& resultCode == Result.Ok) {
|
||||
string filename = Util.IntentToFilename(data, this);
|
||||
if (filename != null) {
|
||||
if (filename.StartsWith("file://")) {
|
||||
filename = filename.Substring(7);
|
||||
filename = Java.Net.URLDecoder.Decode(filename);
|
||||
}
|
||||
|
||||
if (requestCode == Intents.RequestCodeFileBrowseForOpen)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo
|
||||
{
|
||||
Path = filename
|
||||
};
|
||||
|
||||
LaunchPasswordActivityForIoc(ioc);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (resultCode == (Result)FileStorageResults.FileUsagePrepared)
|
||||
{
|
||||
@ -386,49 +324,16 @@ namespace keepass2android
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
LaunchPasswordActivityForIoc(ioc);
|
||||
}
|
||||
if (resultCode == (Result)FileStorageResults.FileChooserPrepared)
|
||||
|
||||
if ((resultCode == Result.Ok) && (requestCode == RequestCodeSelectIoc))
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
PasswordActivity.SetIoConnectionFromIntent(ioc, data);
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
#else
|
||||
LaunchPasswordActivityForIoc(new IOConnectionInfo { Path = "/mnt/sdcard/keepass/yubi.kdbx"});
|
||||
#endif
|
||||
}
|
||||
if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE")))
|
||||
{
|
||||
Toast.MakeText(this, data.GetStringExtra("EXTRA_ERROR_MESSAGE"), ToastLength.Long).Show();
|
||||
}
|
||||
}
|
||||
|
||||
private bool OnReceivedSftpData(string filename)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
StartFileChooser(ioc.Path);
|
||||
#else
|
||||
LaunchPasswordActivityForIoc(ioc);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !EXCLUDE_FILECHOOSER
|
||||
private void StartFileChooser(string defaultPath)
|
||||
{
|
||||
Kp2aLog.Log("FSA: defaultPath="+defaultPath);
|
||||
string fileProviderAuthority = FileChooserFileProvider.TheAuthority;
|
||||
if (defaultPath.StartsWith("file://"))
|
||||
{
|
||||
fileProviderAuthority = PackageName+".android-filechooser.localfile";
|
||||
}
|
||||
Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(this, fileProviderAuthority,
|
||||
defaultPath);
|
||||
|
||||
StartActivityForResult(i, Intents.RequestCodeFileBrowseForOpen);
|
||||
}
|
||||
|
||||
#endif
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
@ -58,6 +58,12 @@ namespace keepass2android.fileselect
|
||||
|
||||
}
|
||||
|
||||
protected override void OnRestart()
|
||||
{
|
||||
base.OnRestart();
|
||||
_isRecreated = true;
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
@ -30,7 +30,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;INCLUDE_KEYBOARD;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE;EXCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>False</ConsolePause>
|
||||
@ -85,9 +85,6 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="Mono.Android.Support.v4" />
|
||||
<Reference Include="GooglePlayServicesFroyoLib">
|
||||
<HintPath>..\Components\googleplayservicesfroyo-9.0\lib\android\GooglePlayServicesFroyoLib.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="addons\OtpKeyProv\EncodingUtil.cs" />
|
||||
@ -138,6 +135,7 @@
|
||||
<Compile Include="fileselect\FileSelectActivity.cs" />
|
||||
<Compile Include="fileselect\FileDbHelper.cs" />
|
||||
<Compile Include="search\SearchProvider.cs" />
|
||||
<Compile Include="SelectStorageLocationActivity.cs" />
|
||||
<Compile Include="services\OngoingNotificationsService.cs" />
|
||||
<Compile Include="settings\DatabaseSettingsActivity.cs" />
|
||||
<Compile Include="intents\Intents.cs" />
|
||||
@ -832,12 +830,6 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\text_with_help.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<XamarinComponentReference Include="googleplayservicesfroyo">
|
||||
<Version>9.0</Version>
|
||||
<Visible>False</Visible>
|
||||
</XamarinComponentReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\ic_storage_skydrive.png" />
|
||||
</ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user