Implemented GetFilename method in JavaFileStorage providers and updated usage in C# components. This resolves a bug with loading the OTP aux file in SkyDrive and Google Drive.

Fixed bug which prohibited creating databases on FTP/HTTP/WebDav (no credentials were queried)

Fixed bug which prohibited to use the Android 4.4 KITKAT file picker

Removed permission for internal file browser to allow using the internal picker in 4.4 as well (Security Exception)
This commit is contained in:
Philipp Crocoll 2013-12-16 06:50:02 +01:00
parent 36af3ade2a
commit 1704e44afc
15 changed files with 135 additions and 68 deletions

View File

@ -430,8 +430,7 @@ namespace keepass2android.Io
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
UrlUtil.GetFileName(ioc.Path));
return _cachedStorage.GetFilenameWithoutPathAndExt(ioc);
}
public bool RequiresCredentials(IOConnectionInfo ioc)

View File

@ -154,7 +154,7 @@ namespace keepass2android.Io
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
UrlUtil.GetFileName(IocToPath(ioc)));
_jfs.GetFilename(IocToPath(ioc)));
}
public bool RequiresCredentials(IOConnectionInfo ioc)

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="con" path="com.google.gdt.eclipse.managedapis.MANAGED_API_CONTAINER/drive-v2r102lv1.16.0-rc"/>
<classpathentry exported="true" kind="lib" path="C:/Users/Philipp/AppData/Local/Android/android-sdk/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -507,4 +507,9 @@ public class DropboxFileStorage extends JavaFileStorageBase {
return path;
}
@Override
public String getFilename(String path) throws Exception {
return path.substring(path.lastIndexOf("/")+1);
}
}

View File

@ -11,6 +11,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import keepass2android.javafilestorage.JavaFileStorageBase.InvalidPathException;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
@ -238,6 +240,27 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
return mAccount;
}
public String getFilename() throws InvalidPathException {
String[] parts = mAccountLocalPath.split("/");
String lastPart = parts[parts.length-1];
int indexOfSeparator = lastPart.lastIndexOf(NAME_ID_SEP);
if (indexOfSeparator < 0) {
throw new InvalidPathException("cannot extract filename from " + mAccountLocalPath);
}
String name = lastPart.substring(0, indexOfSeparator);
try {
name = decode(name);
} catch (UnsupportedEncodingException e) {
// ignore
}
return name;
}
};
@ -805,6 +828,15 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
}
return gdrivePath.getDisplayName();
}
@Override
public String getFilename(String path) throws Exception
{
GDrivePath gdrivePath = new GDrivePath();
gdrivePath.setPathWithoutVerify(path);
return gdrivePath.getFilename();
}
}

View File

@ -120,6 +120,9 @@ public class FileEntry {
public String getDisplayName(String path);
//returns something like "myfile.txt" from the given path, i.e. it's displayable and only the last part of the path
public String getFilename(String path) throws Exception;
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
public String getCurrentFileVersionFast(String path);

View File

@ -404,19 +404,6 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
throw new SkyDriveException(message, code);
}
}
private SkyDriveObject tryAddFileToCache(SkyDrivePath skyDrivePath) {
try {
SkyDriveObject obj = getSkyDriveObject(skyDrivePath);
if (obj != null) {
mFolderCache.put(obj.getId(), obj);
}
return obj;
} catch (Exception e) {
return null;
}
}
private SkyDriveObject tryAddToCache(String skyDriveId) {
try {
@ -799,4 +786,11 @@ public class SkyDriveFileStorage extends JavaFileStorageBase {
}
@Override
public String getFilename(String path) throws Exception {
SkyDrivePath p = new SkyDrivePath();
p.setPathWithoutVerify(path);
return p.getFilename();
}
}

View File

@ -2,8 +2,8 @@
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -388,7 +388,7 @@ namespace keepass2android
return filename;
}
private void OnCreateButton(string filename)
private bool OnCreateButton(string filename)
{
// Make sure file name exists
if (filename.Length == 0)
@ -396,20 +396,21 @@ namespace keepass2android
Toast.MakeText(this,
Resource.String.error_filename_required,
ToastLength.Long).Show();
return;
return false;
}
IOConnectionInfo ioc = new IOConnectionInfo { Path = filename };
IFileStorage fileStorage;
try
{
App.Kp2a.GetFileStorage(ioc);
fileStorage = App.Kp2a.GetFileStorage(ioc);
}
catch (NoFileStorageFoundException)
{
Toast.MakeText(this,
"Unexpected scheme in "+filename,
ToastLength.Long).Show();
return;
return false;
}
if (ioc.IsLocalFile())
@ -425,7 +426,7 @@ namespace keepass2android
Toast.MakeText(this,
Resource.String.error_invalid_path,
ToastLength.Long).Show();
return;
return false;
}
if (!parent.Exists())
@ -436,7 +437,7 @@ namespace keepass2android
Toast.MakeText(this,
Resource.String.error_could_not_create_parent,
ToastLength.Long).Show();
return;
return false;
}
}
@ -450,16 +451,30 @@ namespace keepass2android
GetText(Resource.String.error_file_not_create) + " "
+ ex.LocalizedMessage,
ToastLength.Long).Show();
return;
return false;
}
_ioc = ioc;
UpdateIocView();
}
if (fileStorage.RequiresCredentials(ioc))
{
Util.QueryCredentials(ioc, AfterQueryCredentials, this);
}
else
{
_ioc = ioc;
UpdateIocView();
}
return true;
}
private void AfterQueryCredentials(IOConnectionInfo ioc)
{
_ioc = ioc;
UpdateIocView();
}
private class LaunchGroupActivity : FileOnFinish
{
readonly CreateDatabaseActivity _activity;

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="31" android:versionName="0.9.2-r2" package="keepass2android.keepass2android" android:installLocation="auto">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="32" android:versionName="0.9.2-r3" package="keepass2android.keepass2android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14" />
<permission android:description="@string/permission_desc" android:icon="@drawable/ic_launcher" android:label="KP2A internal file browsing" android:name="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing" android:protectionLevel="signature" />
<application android:label="keepass2android" android:icon="@drawable/ic_launcher">
@ -21,7 +21,7 @@
</activity>
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android.android-filechooser.localfile" android:exported="false" />
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android.android-filechooser.history" android:exported="false" />
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light" android:permission="keepass2android.keepass2android.permission.KP2aInternalFileBrowsing">
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<data android:mimeType="*/*" />

View File

@ -5834,7 +5834,7 @@ namespace keepass2android
16843055,
16843056,
16843057,
16843788};
16843754};
// aapt resource value: 4
public const int MenuView_android_headerBackground = 4;

View File

@ -114,12 +114,14 @@ namespace keepass2android
* @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)
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);
@ -130,10 +132,11 @@ namespace keepass2android
public static void ShowBrowseDialog(string filename, Activity act, int requestCodeBrowse, bool forSaving)
{
if ((!forSaving) && (IsIntentAvailable(act, Intent.ActionGetContent, "file/*")))
if ((!forSaving) && (IsIntentAvailable(act, Intent.ActionGetContent, "*/*", new List<string> { Intent.CategoryOpenable})))
{
Intent i = new Intent(Intent.ActionGetContent);
i.SetType("file/*");
i.SetType("*/*");
i.AddCategory(Intent.CategoryOpenable);
act.StartActivityForResult(i, requestCodeBrowse);
}
@ -207,7 +210,7 @@ namespace keepass2android
return ((int)Android.OS.Build.VERSION.SdkInt >= 14) && (activity.ActionBar != null);
}
public delegate void FileSelectedHandler(string filename);
public delegate bool FileSelectedHandler(string filename);
public static void ShowFilenameDialog(Activity activity, FileSelectedHandler onOpen, FileSelectedHandler onCreate, bool showBrowseButton,
string defaultFilename, string detailsText, int requestCodeBrowse)
@ -233,7 +236,8 @@ namespace keepass2android
openButton.Click += (sender, args) =>
{
String fileName = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text;
onOpen(fileName);
if (onOpen(fileName))
dialog.Dismiss();
};
// Create button
@ -241,7 +245,8 @@ namespace keepass2android
createButton.Click += (sender, args) =>
{
String fileName = ((EditText)dialog.FindViewById(Resource.Id.file_filename)).Text;
onCreate(fileName);
if (onCreate(fileName))
dialog.Dismiss();
};
Button cancelButton = (Button) dialog.FindViewById(Resource.Id.fnv_cancel);
@ -261,6 +266,32 @@ namespace keepass2android
};
}
public static void QueryCredentials(IOConnectionInfo ioc, Action<IOConnectionInfo> afterQueryCredentials, Activity activity)
{
//Build dialog to query credentials:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.SetTitle(activity.GetString(Resource.String.credentials_dialog_title));
builder.SetPositiveButton(activity.GetString(Android.Resource.String.Ok), (dlgSender, dlgEvt) =>
{
Dialog dlg = (Dialog)dlgSender;
string username = ((EditText)dlg.FindViewById(Resource.Id.cred_username)).Text;
string password = ((EditText)dlg.FindViewById(Resource.Id.cred_password)).Text;
int credentialRememberMode = ((Spinner)dlg.FindViewById(Resource.Id.cred_remember_mode)).SelectedItemPosition;
ioc.UserName = username;
ioc.Password = password;
ioc.CredSaveMode = (IOCredSaveMode)credentialRememberMode;
afterQueryCredentials(ioc);
});
builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.url_credentials, null));
builder.SetNeutralButton(activity.GetString(Android.Resource.String.Cancel),
(dlgSender, dlgEvt) => { });
Dialog dialog = builder.Create();
dialog.Show();
((EditText)dialog.FindViewById(Resource.Id.cred_username)).Text = ioc.UserName;
((EditText)dialog.FindViewById(Resource.Id.cred_password)).Text = ioc.Password;
((Spinner)dialog.FindViewById(Resource.Id.cred_remember_mode)).SetSelection((int)ioc.CredSaveMode);
}
}
}

View File

@ -236,29 +236,7 @@ namespace keepass2android
if (fileStorage.RequiresCredentials(ioc))
{
//Build dialog to query credentials:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle(GetString(Resource.String.credentials_dialog_title));
builder.SetPositiveButton(GetString(Android.Resource.String.Ok), (dlgSender, dlgEvt) =>
{
Dialog dlg = (Dialog)dlgSender;
string username = ((EditText)dlg.FindViewById(Resource.Id.cred_username)).Text;
string password = ((EditText)dlg.FindViewById(Resource.Id.cred_password)).Text;
int credentialRememberMode = ((Spinner)dlg.FindViewById(Resource.Id.cred_remember_mode)).SelectedItemPosition;
ioc.UserName = username;
ioc.Password = password;
ioc.CredSaveMode = (IOCredSaveMode)credentialRememberMode;
PasswordActivity.Launch(this, ioc, AppTask);
Finish();
});
builder.SetView(LayoutInflater.Inflate(Resource.Layout.url_credentials, null));
builder.SetNeutralButton(GetString(Android.Resource.String.Cancel),
(dlgSender, dlgEvt) => {});
Dialog dialog = builder.Create();
dialog.Show();
((EditText)dialog.FindViewById(Resource.Id.cred_username)).Text = ioc.UserName;
((EditText)dialog.FindViewById(Resource.Id.cred_password)).Text = ioc.Password;
((Spinner)dialog.FindViewById(Resource.Id.cred_remember_mode)).SetSelection((int)ioc.CredSaveMode);
Util.QueryCredentials(ioc, AfterQueryCredentials, this);
}
else
{
@ -272,7 +250,15 @@ namespace keepass2android
}
}
}
private void AfterQueryCredentials(IOConnectionInfo ioc)
{
PasswordActivity.Launch(this, ioc, AppTask);
Finish();
}
protected override void OnListItemClick(ListView l, View v, int position, long id) {
base.OnListItemClick(l, v, position, id);
@ -284,7 +270,7 @@ namespace keepass2android
App.Kp2a.GetFileStorage(ioc)
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), ioc, 0, false);
}
private void OnOpenButton(String fileName)
private bool OnOpenButton(String fileName)
{
IOConnectionInfo ioc = new IOConnectionInfo
@ -293,7 +279,9 @@ namespace keepass2android
};
LaunchPasswordActivityForIoc(ioc);
return true;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)

View File

@ -29,7 +29,7 @@
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_KEYTRANSFORM;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;INCLUDE_KEYBOARD;EXCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>