180 lines
5.1 KiB
C#
180 lines
5.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using Android.Content;
|
|
using Android.OS;
|
|
using Java.IO;
|
|
using KeePassLib.Serialization;
|
|
using KeePassLib.Utility;
|
|
|
|
namespace keepass2android.Io
|
|
{
|
|
public static class IoUtil
|
|
{
|
|
|
|
public static bool TryTakePersistablePermissions(ContentResolver contentResolver, Android.Net.Uri uri)
|
|
{
|
|
if ((int)Build.VERSION.SdkInt >= 19)
|
|
{
|
|
//try to take persistable permissions
|
|
try
|
|
{
|
|
Kp2aLog.Log("TakePersistableUriPermission");
|
|
var takeFlags = (ActivityFlags.GrantReadUriPermission
|
|
| ActivityFlags.GrantWriteUriPermission);
|
|
contentResolver.TakePersistableUriPermission(uri, takeFlags);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Kp2aLog.Log(e.ToString());
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
public static bool DeleteDir(File dir, bool contentsOnly=false)
|
|
{
|
|
if (dir != null && dir.IsDirectory)
|
|
{
|
|
String[] children = dir.List();
|
|
for (int i = 0; i < children.Length; i++)
|
|
{
|
|
bool success = DeleteDir(new File(dir, children[i]));
|
|
if (!success)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (contentsOnly)
|
|
return true;
|
|
|
|
// The directory is now empty so delete it
|
|
return dir.Delete();
|
|
}
|
|
|
|
|
|
public static IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
|
|
{
|
|
var iocParent = ioc.CloneDeep();
|
|
if (iocParent.Path.EndsWith("/"))
|
|
iocParent.Path = iocParent.Path.Substring(0, iocParent.Path.Length - 1);
|
|
|
|
int slashPos = iocParent.Path.LastIndexOf("/", StringComparison.Ordinal);
|
|
if (slashPos == -1)
|
|
iocParent.Path = "";
|
|
else
|
|
{
|
|
iocParent.Path = iocParent.Path.Substring(0, slashPos);
|
|
}
|
|
return iocParent;
|
|
}
|
|
|
|
public static bool IsInInternalDirectory(string path, Context context)
|
|
{
|
|
try
|
|
{
|
|
File filesDir = context.FilesDir.CanonicalFile;
|
|
File noBackupDir = GetInternalDirectory(context).CanonicalFile;
|
|
File ourFile = new File(path).CanonicalFile;
|
|
//http://www.java2s.com/Tutorial/Java/0180__File/Checkswhetherthechilddirectoryisasubdirectoryofthebasedirectory.htm
|
|
|
|
File parentFile = ourFile;
|
|
while (parentFile != null)
|
|
{
|
|
if ((filesDir.Equals(parentFile) || noBackupDir.Equals(parentFile)))
|
|
{
|
|
return true;
|
|
}
|
|
parentFile = parentFile.ParentFile;
|
|
}
|
|
return false;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Kp2aLog.LogUnexpectedError(e);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public static void Copy(IOConnectionInfo targetIoc, IOConnectionInfo sourceIoc, IKp2aApp app)
|
|
{
|
|
IFileStorage sourceStorage = app.GetFileStorage(sourceIoc, false); //don't cache source. file won't be used ever again
|
|
IFileStorage targetStorage = app.GetFileStorage(targetIoc);
|
|
|
|
using (
|
|
var writeTransaction = targetStorage.OpenWriteTransaction(targetIoc,
|
|
app.GetBooleanPreference(
|
|
PreferenceKey.UseFileTransactions)))
|
|
{
|
|
using (var writeStream = writeTransaction.OpenFile())
|
|
{
|
|
sourceStorage.OpenFileForRead(sourceIoc).CopyTo(writeStream);
|
|
}
|
|
writeTransaction.CommitWrite();
|
|
}
|
|
}
|
|
|
|
public static Java.IO.File GetInternalDirectory(Context ctx)
|
|
{
|
|
if ((int)Android.OS.Build.VERSION.SdkInt >= 21)
|
|
return ctx.NoBackupFilesDir;
|
|
else
|
|
return ctx.FilesDir;
|
|
}
|
|
|
|
//creates a local ioc where the sourceIoc can be stored to
|
|
public static IOConnectionInfo GetInternalIoc(IOConnectionInfo sourceIoc, Context ctx)
|
|
{
|
|
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(ctx);
|
|
string targetPath = UrlUtil.GetFileName(sourceIoc.Path);
|
|
targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
|
|
if (targetPath == "")
|
|
targetPath = "internal";
|
|
if (new File(internalDirectory, targetPath).Exists())
|
|
{
|
|
int c = 1;
|
|
var ext = UrlUtil.GetExtension(targetPath);
|
|
var filenameWithoutExt = UrlUtil.StripExtension(targetPath);
|
|
do
|
|
{
|
|
c++;
|
|
targetPath = filenameWithoutExt + c;
|
|
if (!String.IsNullOrEmpty(ext))
|
|
targetPath += "." + ext;
|
|
} while (new File(internalDirectory, targetPath).Exists());
|
|
}
|
|
return IOConnectionInfo.FromPath(new File(internalDirectory, targetPath).CanonicalPath);
|
|
}
|
|
|
|
public static IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app)
|
|
{
|
|
var targetIoc = GetInternalIoc(sourceIoc, ctx);
|
|
|
|
|
|
IoUtil.Copy(targetIoc, sourceIoc, app);
|
|
return targetIoc;
|
|
}
|
|
|
|
public static string GetIocPrefKey(IOConnectionInfo ioc, string suffix)
|
|
{
|
|
var iocAsHexString = IocAsHexString(ioc);
|
|
|
|
return "kp2a_ioc_key_" + iocAsHexString + suffix;
|
|
}
|
|
|
|
|
|
public static string IocAsHexString(IOConnectionInfo ioc)
|
|
{
|
|
SHA256Managed sha256 = new SHA256Managed();
|
|
string iocAsHexString =
|
|
MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
|
|
return iocAsHexString;
|
|
}
|
|
}
|
|
}
|