Compare commits
13 Commits
Branch_b0f
...
1.06f-none
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8468049935 | ||
|
|
7cef6c8566 | ||
|
|
98f2a139e9 | ||
|
|
832d3b3a95 | ||
|
|
37867634cd | ||
|
|
d9713f8e18 | ||
|
|
c583b58cb9 | ||
|
|
bfeaf5dbf5 | ||
|
|
0907fa5685 | ||
|
|
ff8dc76c75 | ||
|
|
0b09e2790f | ||
|
|
781350aa5f | ||
|
|
9716130336 |
@@ -4,7 +4,3 @@ files:
|
|||||||
/src/keepass2android/Resources/values-%two_letters_code%/%original_file_name%
|
/src/keepass2android/Resources/values-%two_letters_code%/%original_file_name%
|
||||||
translate_attributes: '0'
|
translate_attributes: '0'
|
||||||
content_segmentation: '0'
|
content_segmentation: '0'
|
||||||
languages_mapping:
|
|
||||||
two_letters_code:
|
|
||||||
zh-CN: zh
|
|
||||||
zh-TW: zh-rTW
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Keepass2Android's apk is pretty big, e.g. when comparing to Keepassdroid. The ma
|
|||||||
|
|
||||||
Here's a list of what is contained in the Keepass2Android 0.9.1 application package:
|
Here's a list of what is contained in the Keepass2Android 0.9.1 application package:
|
||||||
|
|
||||||
```
|
{{
|
||||||
Mono for Android
|
Mono for Android
|
||||||
.net dlls 5.0 MB
|
.net dlls 5.0 MB
|
||||||
Runtime 2.5 MB
|
Runtime 2.5 MB
|
||||||
@@ -22,4 +22,4 @@ Java/Mono bindings 0.5 MB
|
|||||||
rest 0.3 MB
|
rest 0.3 MB
|
||||||
|
|
||||||
TOTAL 13 MB
|
TOTAL 13 MB
|
||||||
```
|
}}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
<h1 align="center"><img src="/src/keepass2android/Resources/mipmap-xxxhdpi/ic_launcher_online.png" align="center" width="100" alt="Keepass2Android Logo">Keepass2Android</h1>
|
|
||||||
|
|
||||||
|
|
||||||
# What is Keepass2Android?
|
# What is Keepass2Android?
|
||||||
Keepass2Android is a password manager app. It allows to store and retrieve passwords and other sensitive information in a file called "database". This database is secured with a so-called master password. The master password typically is a strong password and can be complemented with a second factor for additional security.
|
Keepass2Android is a password manager app. It allows to store and retrieve passwords and other sensitive information in a file called "database". This database is secured with a so-called master password. The master password typically is a strong password and can be complemented with a second factor for additional security.
|
||||||
The password database file can be synchronized across different devices. This works best using one of the built-in cloud storage options, but can also be performed with third-party apps. Keepass2Android is compatible with Keepass 1 and Keepass 2 on Windows and KeepassX on Linux.
|
The password database file can be synchronized across different devices. This works best using one of the built-in cloud storage options, but can also be performed with third-party apps. Keepass2Android is compatible with Keepass 1 and Keepass 2 on Windows and KeepassX on Linux.
|
||||||
@@ -18,4 +15,4 @@ Beta-releases can be obtained by opting in to the [Beta testing channel](https:/
|
|||||||
# How do I learn more?
|
# How do I learn more?
|
||||||
Please see the [documentation](Documentation.md).
|
Please see the [documentation](Documentation.md).
|
||||||
|
|
||||||
[](https://www.bitrise.io/app/43a23ab54dee9f7e)
|
[](https://www.bitrise.io/app/43a23ab54dee9f7e)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
@@ -1,64 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProductVersion>8.0.30703</ProductVersion>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<ProjectGuid>{0B109C0E-0514-4340-8779-5BD6A0DDE84E}</ProjectGuid>
|
|
||||||
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>AdalBindings</RootNamespace>
|
|
||||||
<AssemblyName>AdalBindings</AssemblyName>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
|
||||||
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Mono.Android" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Jars\AboutJars.txt" />
|
|
||||||
<None Include="Additions\AboutAdditions.txt" />
|
|
||||||
<LibraryProjectZip Include="Jars\adal-1.14.0.aar" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<TransformFile Include="Transforms\Metadata.xml" />
|
|
||||||
<TransformFile Include="Transforms\EnumFields.xml" />
|
|
||||||
<TransformFile Include="Transforms\EnumMethods.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedReferenceJar Include="Jars\gson-2.3.1.jar" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
Additions allow you to add arbitrary C# to the generated classes
|
|
||||||
before they are compiled. This can be helpful for providing convenience
|
|
||||||
methods or adding pure C# classes.
|
|
||||||
|
|
||||||
== Adding Methods to Generated Classes ==
|
|
||||||
|
|
||||||
Let's say the library being bound has a Rectangle class with a constructor
|
|
||||||
that takes an x and y position, and a width and length size. It will look like
|
|
||||||
this:
|
|
||||||
|
|
||||||
public partial class Rectangle
|
|
||||||
{
|
|
||||||
public Rectangle (int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
// JNI bindings
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Imagine we want to add a constructor to this class that takes a Point and
|
|
||||||
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
|
|
||||||
with a partial class containing our new method:
|
|
||||||
|
|
||||||
public partial class Rectangle
|
|
||||||
{
|
|
||||||
public Rectangle (Point location, Size size) :
|
|
||||||
this (location.X, location.Y, size.Width, size.Height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
At compile time, the additions class will be added to the generated class
|
|
||||||
and the final assembly will a Rectangle class with both constructors.
|
|
||||||
|
|
||||||
|
|
||||||
== Adding C# Classes ==
|
|
||||||
|
|
||||||
Another thing that can be done is adding fully C# managed classes to the
|
|
||||||
generated library. In the above example, let's assume that there isn't a
|
|
||||||
Point class available in Java or our library. The one we create doesn't need
|
|
||||||
to interact with Java, so we'll create it like a normal class in C#.
|
|
||||||
|
|
||||||
By adding a Point.cs file with this class, it will end up in the binding library:
|
|
||||||
|
|
||||||
public class Point
|
|
||||||
{
|
|
||||||
public int X { get; set; }
|
|
||||||
public int Y { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
This directory is for Android .jars.
|
|
||||||
|
|
||||||
There are 2 types of jars that are supported:
|
|
||||||
|
|
||||||
== Input Jar ==
|
|
||||||
|
|
||||||
This is the jar that bindings should be generated for.
|
|
||||||
|
|
||||||
For example, if you were binding the Google Maps library, this would
|
|
||||||
be Google's "maps.jar".
|
|
||||||
|
|
||||||
Set the build action for these jars in the properties page to "InputJar".
|
|
||||||
|
|
||||||
|
|
||||||
== Reference Jars ==
|
|
||||||
|
|
||||||
These are jars that are referenced by the input jar. C# bindings will
|
|
||||||
not be created for these jars. These jars will be used to resolve
|
|
||||||
types used by the input jar.
|
|
||||||
|
|
||||||
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
|
|
||||||
based on the Target Framework selected.
|
|
||||||
|
|
||||||
Set the build action for these jars in the properties page to "ReferenceJar".
|
|
||||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Android.App;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("AdalBindings")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("AdalBindings")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<enum-field-mappings>
|
|
||||||
<!--
|
|
||||||
This example converts the constants Fragment_id, Fragment_name,
|
|
||||||
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
|
|
||||||
to an enum called Android.Support.V4.App.FragmentTagType with values
|
|
||||||
Id, Name, and Tag.
|
|
||||||
|
|
||||||
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
|
|
||||||
<field jni-name="Fragment_name" clr-name="Name" value="0" />
|
|
||||||
<field jni-name="Fragment_id" clr-name="Id" value="1" />
|
|
||||||
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
|
|
||||||
</mapping>
|
|
||||||
-->
|
|
||||||
</enum-field-mappings>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<enum-method-mappings>
|
|
||||||
<!--
|
|
||||||
This example changes the Java method:
|
|
||||||
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
|
|
||||||
to be:
|
|
||||||
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
|
|
||||||
when bound in C#.
|
|
||||||
|
|
||||||
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
|
|
||||||
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
|
|
||||||
</mapping>
|
|
||||||
-->
|
|
||||||
</enum-method-mappings>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<metadata>
|
|
||||||
<!--
|
|
||||||
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
|
|
||||||
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
|
|
||||||
|
|
||||||
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
|
|
||||||
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
|
|
||||||
-->
|
|
||||||
<remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='AuthenticationActivity']" />
|
|
||||||
<remove-node path="/api/package[@name='com.microsoft.aad.adal']/class[@name='DateTimeAdapter']" />
|
|
||||||
<remove-node path="/api/package[@name='com.microsoft.aad.adal']" />
|
|
||||||
|
|
||||||
</metadata>
|
|
||||||
@@ -60,6 +60,7 @@
|
|||||||
</LibraryProjectZip>
|
</LibraryProjectZip>
|
||||||
<None Include="Jars\AboutJars.txt" />
|
<None Include="Jars\AboutJars.txt" />
|
||||||
<None Include="Additions\AboutAdditions.txt" />
|
<None Include="Additions\AboutAdditions.txt" />
|
||||||
|
<LibraryProjectZip Include="Jars\adal-1.14.0.aar" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TransformFile Include="Transforms\Metadata.xml" />
|
<TransformFile Include="Transforms\Metadata.xml" />
|
||||||
@@ -80,9 +81,6 @@
|
|||||||
<Visible>False</Visible>
|
<Visible>False</Visible>
|
||||||
</XamarinComponentReference>
|
</XamarinComponentReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
|
<EmbeddedReferenceJar Include="Jars\okhttp-digest-1.7.jar" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
<remove-node path="/api/package[@name='com.jcraft.jsch.jcraft']" />
|
<remove-node path="/api/package[@name='com.jcraft.jsch.jcraft']" />
|
||||||
<remove-node path="/api/package[@name='com.jcraft.jzlib']" />
|
<remove-node path="/api/package[@name='com.jcraft.jzlib']" />
|
||||||
|
|
||||||
<remove-node path="/api/package[@name='com.pcloud.sdk']" />
|
|
||||||
|
|
||||||
<remove-node path="/api/package[@name='com.dropbox.core']" />
|
<remove-node path="/api/package[@name='com.dropbox.core']" />
|
||||||
<remove-node path="/api/package[@name='com.dropbox.core.util']" />
|
<remove-node path="/api/package[@name='com.dropbox.core.util']" />
|
||||||
<remove-node path="/api/package[@name='com.dropbox.core.http']" />
|
<remove-node path="/api/package[@name='com.dropbox.core.http']" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.27004.2009
|
VisualStudioVersion = 15.0.27130.2010
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aBusinessLogic", "Kp2aBu
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwofishCipher", "TwofishCipher\TwofishCipher.csproj", "{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaFileStorageBindings", "JavaFileStorageBindings\JavaFileStorageBindings.csproj", "{48574278-4779-4B3A-A9E4-9CF1BC285D0B}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidFileChooserBinding", "AndroidFileChooserBinding\AndroidFileChooserBinding.csproj", "{3C0F7FE5-639F-4422-A087-8B26CF862D1B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KP2AKdbLibraryBinding", "KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj", "{70D3844A-D9FA-4A64-B205-A84C6A822196}"
|
||||||
@@ -23,12 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginSdkBinding", "PluginS
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.FtpClient.Android", "netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj", "{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -111,8 +105,8 @@ Global
|
|||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|Win32.Build.0 = Release|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = Debug|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = Debug|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
@@ -153,30 +147,6 @@ Global
|
|||||||
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.Build.0 = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.ActiveCfg = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.Build.0 = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
@@ -189,8 +159,8 @@ Global
|
|||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
@@ -207,8 +177,8 @@ Global
|
|||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{70D3844A-D9FA-4A64-B205-A84C6A822196}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
@@ -225,8 +195,8 @@ Global
|
|||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
{3DA3911E-36DE-465E-8F15-F1991B6437E5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
||||||
@@ -255,24 +225,6 @@ Global
|
|||||||
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
|
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
|
||||||
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
||||||
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
|
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|Win32.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
|
|
||||||
{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
@@ -291,30 +243,6 @@ Global
|
|||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
|
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Win32.Build.0 = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.ActiveCfg = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|Win32.Build.0 = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
|
|
||||||
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using keepass2android;
|
|
||||||
#if KeePassUAP
|
#if KeePassUAP
|
||||||
using Org.BouncyCastle.Crypto;
|
using Org.BouncyCastle.Crypto;
|
||||||
using Org.BouncyCastle.Crypto.Engines;
|
using Org.BouncyCastle.Crypto.Engines;
|
||||||
@@ -144,7 +144,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
|
|||||||
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
|
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
|
||||||
ulong uNumRounds)
|
ulong uNumRounds)
|
||||||
{
|
{
|
||||||
Kp2aLog.Log("Warning: transforming key managed. Expect this to be slow!");
|
|
||||||
#if KeePassUAP
|
#if KeePassUAP
|
||||||
KeyParameter kp = new KeyParameter(pbKeySeed32);
|
KeyParameter kp = new KeyParameter(pbKeySeed32);
|
||||||
AesEngine aes = new AesEngine();
|
AesEngine aes = new AesEngine();
|
||||||
|
|||||||
@@ -38,11 +38,9 @@ namespace KeePassLib.Keys
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// <summary>
|
// /// <summary>
|
||||||
// /// Clear the key and securely erase all security-critical information.
|
// /// Clear the key and securely erase all security-critical information.
|
||||||
// /// </summary>
|
// /// </summary>
|
||||||
// void Clear();
|
// void Clear();
|
||||||
|
|
||||||
uint GetMinKdbxVersion();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,12 +45,7 @@ namespace KeePassLib.Keys
|
|||||||
get { return m_pbKey; }
|
get { return m_pbKey; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMinKdbxVersion()
|
public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash)
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash)
|
|
||||||
{
|
{
|
||||||
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
|
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
|
||||||
Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
|
Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
|
||||||
|
|||||||
@@ -64,12 +64,7 @@ namespace KeePassLib.Keys
|
|||||||
get { return m_pbKeyData; }
|
get { return m_pbKeyData; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMinKdbxVersion()
|
public IOConnectionInfo Ioc
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IOConnectionInfo Ioc
|
|
||||||
{
|
{
|
||||||
get { return m_ioc; }
|
get { return m_ioc; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,7 @@ namespace KeePassLib.Keys
|
|||||||
get { return m_pbKeyData; }
|
get { return m_pbKeyData; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMinKdbxVersion()
|
public KcpPassword(byte[] pbPasswordUtf8)
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KcpPassword(byte[] pbPasswordUtf8)
|
|
||||||
{
|
{
|
||||||
SetKey(pbPasswordUtf8);
|
SetKey(pbPasswordUtf8);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,12 +60,7 @@ namespace KeePassLib.Keys
|
|||||||
get { return m_pbKeyData; }
|
get { return m_pbKeyData; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMinKdbxVersion()
|
/// <summary>
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Construct a user account key.
|
/// Construct a user account key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public KcpUserAccount()
|
public KcpUserAccount()
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
if (!File.Exists(LogFilename))
|
if (!File.Exists(LogFilename))
|
||||||
{
|
{
|
||||||
File.Create(LogFilename).Dispose();
|
File.Create(LogFilename);
|
||||||
_logToFile = true;
|
_logToFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -100,7 +100,8 @@ namespace keepass2android
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
while (File.Exists(LogFilename + "." + count))
|
while (File.Exists(LogFilename + "." + count))
|
||||||
count++;
|
count++;
|
||||||
File.Move(LogFilename, LogFilename + "." + count);
|
if (count > 0)
|
||||||
|
File.Move(LogFilename, LogFilename + "." + count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ namespace KeePassLib.Native
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Kp2aLog.Log(e.ToString());
|
Kp2aLog.Log(e.Message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -485,6 +485,12 @@ namespace KeePassLib
|
|||||||
set { m_pbHashOfLastIO = value; }
|
set { m_pbHashOfLastIO = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool UseFileTransactions
|
||||||
|
{
|
||||||
|
get { return m_bUseFileTransactions; }
|
||||||
|
set { m_bUseFileTransactions = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public bool UseFileLocks
|
public bool UseFileLocks
|
||||||
{
|
{
|
||||||
get { return m_bUseFileLocks; }
|
get { return m_bUseFileLocks; }
|
||||||
|
|||||||
@@ -360,12 +360,5 @@ namespace KeePassLib.Serialization
|
|||||||
m_ioCredProtMode = IOCredProtMode.None;
|
m_ioCredProtMode = IOCredProtMode.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSameFileAs(IOConnectionInfo other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
return false;
|
|
||||||
return Path == other.Path && UserName == other.UserName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ using System.Diagnostics;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
@@ -127,8 +126,8 @@ namespace KeePassLib.Serialization
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const uint FileVersion32 = 0x00040000;
|
private const uint FileVersion32 = 0x00040000;
|
||||||
|
|
||||||
public const uint FileVersion32_4 = 0x00040000; // First of 4.x series
|
internal const uint FileVersion32_4 = 0x00040000; // First of 4.x series
|
||||||
public const uint FileVersion32_3 = 0x00030001; // Old format 3.1
|
internal const uint FileVersion32_3 = 0x00030001; // Old format 3.1
|
||||||
|
|
||||||
private const uint FileVersionCriticalMask = 0xFFFF0000;
|
private const uint FileVersionCriticalMask = 0xFFFF0000;
|
||||||
|
|
||||||
@@ -373,19 +372,16 @@ namespace KeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
if(m_uForceVersion != 0) return m_uForceVersion;
|
if(m_uForceVersion != 0) return m_uForceVersion;
|
||||||
|
|
||||||
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
|
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
|
||||||
uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max();
|
|
||||||
|
AesKdf kdfAes = new AesKdf();
|
||||||
AesKdf kdfAes = new AesKdf();
|
|
||||||
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
|
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
|
||||||
return Math.Max(FileVersion32, minVersionForKeys);
|
return FileVersion32;
|
||||||
|
|
||||||
if(m_pwDatabase.PublicCustomData.Count > 0)
|
if(m_pwDatabase.PublicCustomData.Count > 0)
|
||||||
return Math.Max(FileVersion32, minVersionForKeys);
|
return FileVersion32;
|
||||||
|
|
||||||
|
bool bCustomData = false;
|
||||||
|
|
||||||
bool bCustomData = false;
|
|
||||||
GroupHandler gh = delegate(PwGroup pg)
|
GroupHandler gh = delegate(PwGroup pg)
|
||||||
{
|
{
|
||||||
if(pg == null) { Debug.Assert(false); return true; }
|
if(pg == null) { Debug.Assert(false); return true; }
|
||||||
@@ -400,10 +396,9 @@ namespace KeePassLib.Serialization
|
|||||||
};
|
};
|
||||||
gh(m_pwDatabase.RootGroup);
|
gh(m_pwDatabase.RootGroup);
|
||||||
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
|
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
|
||||||
if(bCustomData)
|
if(bCustomData) return FileVersion32;
|
||||||
return Math.Max(FileVersion32, minVersionForKeys);
|
|
||||||
|
|
||||||
return Math.Max(FileVersion32_3, minVersionForKeys); ; // KDBX 3.1 is sufficient
|
return FileVersion32_3; // KDBX 3.1 is sufficient
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,
|
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
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 keepass2android.Io;
|
|
||||||
using KeePassLib;
|
|
||||||
using KeePassLib.Interfaces;
|
|
||||||
using KeePassLib.Utility;
|
|
||||||
|
|
||||||
namespace keepass2android
|
|
||||||
{
|
|
||||||
public class ElementAndDatabaseId
|
|
||||||
{
|
|
||||||
private const char Separator = '+';
|
|
||||||
|
|
||||||
public ElementAndDatabaseId(Database db, IStructureItem element)
|
|
||||||
{
|
|
||||||
DatabaseId = db.IocAsHexString();
|
|
||||||
ElementIdString = element.Uuid.ToHexString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ElementAndDatabaseId(string fullId)
|
|
||||||
{
|
|
||||||
string[] parts = fullId.Split(Separator);
|
|
||||||
if (parts.Length != 2)
|
|
||||||
throw new Exception("Invalid full id " + fullId);
|
|
||||||
DatabaseId = parts[0];
|
|
||||||
ElementIdString = parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DatabaseId { get; set; }
|
|
||||||
public string ElementIdString { get; set; }
|
|
||||||
public PwUuid ElementId { get { return new PwUuid(MemUtil.HexStringToByteArray(ElementIdString));} }
|
|
||||||
|
|
||||||
public string FullId
|
|
||||||
{
|
|
||||||
get { return DatabaseId + Separator + ElementIdString; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
@@ -10,7 +9,6 @@ using KeePassLib;
|
|||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using KeePassLib.Interfaces;
|
|
||||||
#if !NoNet
|
#if !NoNet
|
||||||
using Keepass2android.Javafilestorage;
|
using Keepass2android.Javafilestorage;
|
||||||
#endif
|
#endif
|
||||||
@@ -35,41 +33,31 @@ namespace keepass2android
|
|||||||
/// This also contains methods which are UI specific and should be replacable for testing.
|
/// This also contains methods which are UI specific and should be replacable for testing.
|
||||||
public interface IKp2aApp : ICertificateValidationHandler
|
public interface IKp2aApp : ICertificateValidationHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
|
/// Locks the currently open database, quicklocking if available (unless false is passed for allowQuickUnlock)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Lock(bool allowQuickUnlock);
|
void LockDatabase(bool allowQuickUnlock = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the specified data as the currently open database, as unlocked.
|
||||||
|
/// </summary>
|
||||||
|
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey,
|
||||||
|
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the specified data as the currently open database, as unlocked.
|
/// Returns the current database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Database LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat, bool makeCurrent);
|
Database GetDb();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
HashSet<PwGroup> DirtyGroups { get; }
|
/// Tell the app that the file from ioc was opened with keyfile.
|
||||||
|
/// </summary>
|
||||||
void MarkAllGroupsAsDirty();
|
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the current database
|
|
||||||
/// </summary>
|
|
||||||
Database CurrentDb { get; }
|
|
||||||
|
|
||||||
IEnumerable<Database> OpenDatabases { get; }
|
|
||||||
void CloseDatabase(Database db);
|
|
||||||
|
|
||||||
Database FindDatabaseForElement(IStructureItem element);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tell the app that the file from ioc was opened with keyfile.
|
|
||||||
/// </summary>
|
|
||||||
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, bool updateTimestamp, string displayName = "");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new database and returns it
|
/// Creates a new database and returns it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Database CreateNewDatabase(bool makeCurrent);
|
Database CreateNewDatabase();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the user-displayable string identified by stringKey
|
/// Returns the user-displayable string identified by stringKey
|
||||||
@@ -88,8 +76,7 @@ namespace keepass2android
|
|||||||
EventHandler<DialogClickEventArgs> yesHandler,
|
EventHandler<DialogClickEventArgs> yesHandler,
|
||||||
EventHandler<DialogClickEventArgs> noHandler,
|
EventHandler<DialogClickEventArgs> noHandler,
|
||||||
EventHandler<DialogClickEventArgs> cancelHandler,
|
EventHandler<DialogClickEventArgs> cancelHandler,
|
||||||
Context ctx,
|
Context ctx);
|
||||||
string messageSuffix = "");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asks the user the question "messageKey" with the options Yes/No/Cancel, but the yes/no strings can be selected freely, calls the handler corresponding to the answer.
|
/// Asks the user the question "messageKey" with the options Yes/No/Cancel, but the yes/no strings can be selected freely, calls the handler corresponding to the answer.
|
||||||
@@ -99,8 +86,7 @@ namespace keepass2android
|
|||||||
EventHandler<DialogClickEventArgs> yesHandler,
|
EventHandler<DialogClickEventArgs> yesHandler,
|
||||||
EventHandler<DialogClickEventArgs> noHandler,
|
EventHandler<DialogClickEventArgs> noHandler,
|
||||||
EventHandler<DialogClickEventArgs> cancelHandler,
|
EventHandler<DialogClickEventArgs> cancelHandler,
|
||||||
Context ctx,
|
Context ctx);
|
||||||
string messageSuffix = "");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a Handler object which can run tasks on the UI thread
|
/// Returns a Handler object which can run tasks on the UI thread
|
||||||
@@ -125,10 +111,6 @@ namespace keepass2android
|
|||||||
bool CheckForDuplicateUuids { get; }
|
bool CheckForDuplicateUuids { get; }
|
||||||
#if !NoNet
|
#if !NoNet
|
||||||
ICertificateErrorHandler CertificateErrorHandler { get; }
|
ICertificateErrorHandler CertificateErrorHandler { get; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,8 @@ namespace keepass2android.Io
|
|||||||
|
|
||||||
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
|
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
return IoUtil.GetParentPath(ioc);
|
//TODO: required for OTP Aux file retrieval
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
|
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
|
||||||
|
|||||||
@@ -255,8 +255,7 @@ namespace keepass2android.Io
|
|||||||
if (ioc.IsLocalFile())
|
if (ioc.IsLocalFile())
|
||||||
{
|
{
|
||||||
bool requiresPermission = !(ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath)
|
bool requiresPermission = !(ioc.Path.StartsWith(activity.Activity.FilesDir.CanonicalPath)
|
||||||
|| ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath)
|
|| ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath));
|
||||||
|| ioc.Path.StartsWith(IoUtil.GetInternalDirectory(activity.Activity).CanonicalPath));
|
|
||||||
|
|
||||||
var extDirectory = activity.Activity.GetExternalFilesDir(null);
|
var extDirectory = activity.Activity.GetExternalFilesDir(null);
|
||||||
if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath)))
|
if ((extDirectory != null) && (ioc.Path.StartsWith(extDirectory.CanonicalPath)))
|
||||||
|
|||||||
@@ -65,28 +65,22 @@ namespace keepass2android.Io
|
|||||||
|
|
||||||
protected readonly OfflineSwitchableFileStorage _cachedStorage;
|
protected readonly OfflineSwitchableFileStorage _cachedStorage;
|
||||||
private readonly ICacheSupervisor _cacheSupervisor;
|
private readonly ICacheSupervisor _cacheSupervisor;
|
||||||
private readonly string _legacyCacheDir;
|
private readonly string _streamCacheDir;
|
||||||
private readonly string _cacheDir;
|
|
||||||
|
|
||||||
public CachingFileStorage(IFileStorage cachedStorage, Context cacheDirContext, ICacheSupervisor cacheSupervisor)
|
public CachingFileStorage(IFileStorage cachedStorage, string cacheDir, ICacheSupervisor cacheSupervisor)
|
||||||
{
|
{
|
||||||
_cachedStorage = new OfflineSwitchableFileStorage(cachedStorage);
|
_cachedStorage = new OfflineSwitchableFileStorage(cachedStorage);
|
||||||
_cacheSupervisor = cacheSupervisor;
|
_cacheSupervisor = cacheSupervisor;
|
||||||
_legacyCacheDir = cacheDirContext.CacheDir.Path + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator;
|
_streamCacheDir = cacheDir + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator;
|
||||||
if (!Directory.Exists(_legacyCacheDir))
|
if (!Directory.Exists(_streamCacheDir))
|
||||||
Directory.CreateDirectory(_legacyCacheDir);
|
Directory.CreateDirectory(_streamCacheDir);
|
||||||
|
|
||||||
_cacheDir = IoUtil.GetInternalDirectory(cacheDirContext).Path + Java.IO.File.Separator + "OfflineCache" + Java.IO.File.Separator;
|
}
|
||||||
if (!Directory.Exists(_cacheDir))
|
|
||||||
Directory.CreateDirectory(_cacheDir);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearCache()
|
public void ClearCache()
|
||||||
{
|
{
|
||||||
IoUtil.DeleteDir(new Java.IO.File(_legacyCacheDir), true);
|
IoUtil.DeleteDir(new Java.IO.File(_streamCacheDir), true);
|
||||||
IoUtil.DeleteDir(new Java.IO.File(_cacheDir), true);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } }
|
public IEnumerable<string> SupportedProtocols { get { return _cachedStorage.SupportedProtocols; } }
|
||||||
|
|
||||||
@@ -111,11 +105,7 @@ namespace keepass2android.Io
|
|||||||
{
|
{
|
||||||
SHA256Managed sha256 = new SHA256Managed();
|
SHA256Managed sha256 = new SHA256Managed();
|
||||||
string iocAsHexString = MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())))+".cache";
|
string iocAsHexString = MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())))+".cache";
|
||||||
if (File.Exists(_legacyCacheDir + iocAsHexString))
|
return _streamCacheDir + iocAsHexString;
|
||||||
return _legacyCacheDir + iocAsHexString;
|
|
||||||
|
|
||||||
return _cacheDir + iocAsHexString;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCached(IOConnectionInfo ioc)
|
public bool IsCached(IOConnectionInfo ioc)
|
||||||
@@ -178,9 +168,7 @@ namespace keepass2android.Io
|
|||||||
if (!IsCached(ioc))
|
if (!IsCached(ioc))
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
#if DEBUG
|
Kp2aLog.Log("couldn't open from remote " + ioc.Path);
|
||||||
Kp2aLog.Log("couldn't open from remote " + ioc.Path);
|
|
||||||
#endif
|
|
||||||
Kp2aLog.Log(ex.ToString());
|
Kp2aLog.Log(ex.ToString());
|
||||||
|
|
||||||
_cacheSupervisor.CouldntOpenFromRemote(ioc, ex);
|
_cacheSupervisor.CouldntOpenFromRemote(ioc, ex);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ namespace keepass2android.Io
|
|||||||
{
|
{
|
||||||
public partial class DropboxFileStorage
|
public partial class DropboxFileStorage
|
||||||
{
|
{
|
||||||
private const string AppKey = "dummy";
|
private const string AppKey = "";
|
||||||
private const string AppSecret = "dummy";
|
private const string AppSecret = "";
|
||||||
}
|
}
|
||||||
public partial class DropboxAppFolderFileStorage
|
public partial class DropboxAppFolderFileStorage
|
||||||
{
|
{
|
||||||
private const string AppKey = "dummy";
|
private const string AppKey = "";
|
||||||
private const string AppSecret = "dummy";
|
private const string AppSecret = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,6 +233,7 @@ namespace keepass2android.Io
|
|||||||
|
|
||||||
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
public FileDescription GetFileDescription(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
|
Kp2aLog.Log("GetFileDescription "+ioc.Path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
|
return ConvertToFileDescription(Jfs.GetFileEntry(IocToPath(ioc)));
|
||||||
@@ -301,9 +302,7 @@ namespace keepass2android.Io
|
|||||||
|
|
||||||
public void OnResume(IFileStorageSetupActivity activity)
|
public void OnResume(IFileStorageSetupActivity activity)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path);
|
Kp2aLog.Log("JFS/OnResume Ioc.Path=" +activity.Ioc.Path+". Path="+((IJavaFileStorageFileStorageSetupActivity)activity).Path);
|
||||||
#endif
|
|
||||||
_jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity));
|
_jfs.OnResume(((IJavaFileStorageFileStorageSetupActivity) activity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,4 +366,4 @@ namespace keepass2android.Io
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
#if !EXCLUDE_JAVAFILESTORAGE
|
|
||||||
|
|
||||||
namespace keepass2android.Io
|
|
||||||
{
|
|
||||||
public partial class PCloudFileStorage: JavaFileStorage
|
|
||||||
{
|
|
||||||
private const string ClientId = "CkRWTQXY6Lm";
|
|
||||||
|
|
||||||
public PCloudFileStorage(Context ctx, IKp2aApp app) :
|
|
||||||
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId), app)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool UserShouldBackup
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -5,8 +5,8 @@ namespace keepass2android.Io
|
|||||||
{
|
{
|
||||||
public class SftpFileStorage: JavaFileStorage
|
public class SftpFileStorage: JavaFileStorage
|
||||||
{
|
{
|
||||||
public SftpFileStorage(Context ctx, IKp2aApp app) :
|
public SftpFileStorage(IKp2aApp app) :
|
||||||
base(new Keepass2android.Javafilestorage.SftpStorage(ctx.ApplicationContext), app)
|
base(new Keepass2android.Javafilestorage.SftpStorage(), app)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ namespace keepass2android.Io
|
|||||||
yield return "http";
|
yield return "http";
|
||||||
yield return "https";
|
yield return "https";
|
||||||
yield return "owncloud";
|
yield return "owncloud";
|
||||||
yield return "nextcloud";
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool UserShouldBackup
|
public override bool UserShouldBackup
|
||||||
@@ -39,15 +38,12 @@ namespace keepass2android.Io
|
|||||||
get { return true; }
|
get { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string owncloudPrefix = "owncloud://";
|
public static string Owncloud2Webdav(string owncloudUrl)
|
||||||
public static string nextcloudPrefix = "nextcloud://";
|
|
||||||
|
|
||||||
public static string Owncloud2Webdav(string owncloudUrl, string prefix)
|
|
||||||
{
|
{
|
||||||
|
string owncloudPrefix = "owncloud://";
|
||||||
if (owncloudUrl.StartsWith(prefix))
|
if (owncloudUrl.StartsWith(owncloudPrefix))
|
||||||
{
|
{
|
||||||
owncloudUrl = owncloudUrl.Substring(prefix.Length);
|
owncloudUrl = owncloudUrl.Substring(owncloudPrefix.Length);
|
||||||
}
|
}
|
||||||
if (!owncloudUrl.Contains("://"))
|
if (!owncloudUrl.Contains("://"))
|
||||||
owncloudUrl = "https://" + owncloudUrl;
|
owncloudUrl = "https://" + owncloudUrl;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE;NoNet;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||||
@@ -53,7 +53,6 @@
|
|||||||
<Reference Include="mscorlib" />
|
<Reference Include="mscorlib" />
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Xamarin.Android.Arch.Core.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Xamarin.Android.Arch.Core.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
@@ -91,7 +90,7 @@
|
|||||||
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
||||||
<Compile Include="database\edit\AddTemplateEntries.cs" />
|
<Compile Include="database\edit\AddTemplateEntries.cs" />
|
||||||
<Compile Include="database\edit\CopyEntry.cs" />
|
<Compile Include="database\edit\CopyEntry.cs" />
|
||||||
<Compile Include="database\edit\DeleteMultipleItemsFromOneDatabase.cs" />
|
<Compile Include="database\edit\DeleteMultipleItems.cs" />
|
||||||
<Compile Include="database\edit\EditGroup.cs" />
|
<Compile Include="database\edit\EditGroup.cs" />
|
||||||
<Compile Include="database\edit\MoveElements.cs" />
|
<Compile Include="database\edit\MoveElements.cs" />
|
||||||
<Compile Include="database\KdbDatabaseFormat.cs" />
|
<Compile Include="database\KdbDatabaseFormat.cs" />
|
||||||
@@ -103,25 +102,15 @@
|
|||||||
<Compile Include="DataExchange\Formats\KeePassKdb2x.cs" />
|
<Compile Include="DataExchange\Formats\KeePassKdb2x.cs" />
|
||||||
<Compile Include="DataExchange\Formats\KeePassXml2x.cs" />
|
<Compile Include="DataExchange\Formats\KeePassXml2x.cs" />
|
||||||
<Compile Include="DataExchange\PwExportInfo.cs" />
|
<Compile Include="DataExchange\PwExportInfo.cs" />
|
||||||
<Compile Include="ElementAndDatabaseId.cs" />
|
|
||||||
<Compile Include="Io\AndroidContentStorage.cs" />
|
<Compile Include="Io\AndroidContentStorage.cs" />
|
||||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||||
<Compile Include="Io\CachingFileStorage.cs" />
|
<Compile Include="Io\CachingFileStorage.cs" />
|
||||||
<Compile Include="Io\DropboxFileStorage.cs" />
|
|
||||||
<Compile Include="Io\DropboxFileStorageKeys.cs" />
|
|
||||||
<Compile Include="Io\FileDescription.cs" />
|
<Compile Include="Io\FileDescription.cs" />
|
||||||
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
<Compile Include="Io\FileStorageSetupActivity.cs" />
|
||||||
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
<Compile Include="Io\FileStorageSetupInitiatorActivity.cs" />
|
||||||
<Compile Include="Io\GDriveFileStorage.cs" />
|
|
||||||
<Compile Include="Io\IFileStorage.cs" />
|
<Compile Include="Io\IFileStorage.cs" />
|
||||||
<Compile Include="Io\IoUtil.cs" />
|
<Compile Include="Io\IoUtil.cs" />
|
||||||
<Compile Include="Io\JavaFileStorage.cs" />
|
|
||||||
<Compile Include="Io\NetFtpFileStorage.cs" />
|
|
||||||
<Compile Include="Io\OfflineSwitchableFileStorage.cs" />
|
<Compile Include="Io\OfflineSwitchableFileStorage.cs" />
|
||||||
<Compile Include="Io\PCloudFileStorage.cs" />
|
|
||||||
<Compile Include="Io\SftpFileStorage.cs" />
|
|
||||||
<Compile Include="Io\OneDriveFileStorage.cs" />
|
|
||||||
<Compile Include="Io\WebDavFileStorage.cs" />
|
|
||||||
<Compile Include="IProgressDialog.cs" />
|
<Compile Include="IProgressDialog.cs" />
|
||||||
<Compile Include="PreferenceKey.cs" />
|
<Compile Include="PreferenceKey.cs" />
|
||||||
<Compile Include="SelectStorageLocationActivityBase.cs" />
|
<Compile Include="SelectStorageLocationActivityBase.cs" />
|
||||||
@@ -130,15 +119,15 @@
|
|||||||
<Compile Include="database\edit\ActionOnFinish.cs" />
|
<Compile Include="database\edit\ActionOnFinish.cs" />
|
||||||
<Compile Include="database\edit\AddEntry.cs" />
|
<Compile Include="database\edit\AddEntry.cs" />
|
||||||
<Compile Include="database\edit\AddGroup.cs" />
|
<Compile Include="database\edit\AddGroup.cs" />
|
||||||
<Compile Include="database\edit\CreateDB.cs" />
|
<Compile Include="database\edit\CreateDb.cs" />
|
||||||
<Compile Include="database\edit\DeleteEntry.cs" />
|
<Compile Include="database\edit\DeleteEntry.cs" />
|
||||||
<Compile Include="database\edit\DeleteGroup.cs" />
|
<Compile Include="database\edit\DeleteGroup.cs" />
|
||||||
<Compile Include="database\edit\DeleteRunnable.cs" />
|
<Compile Include="database\edit\DeleteRunnable.cs" />
|
||||||
<Compile Include="database\edit\FileOnFinish.cs" />
|
<Compile Include="database\edit\FileOnFinish.cs" />
|
||||||
<Compile Include="database\edit\LoadDB.cs" />
|
<Compile Include="database\edit\LoadDb.cs" />
|
||||||
<Compile Include="database\edit\OnFinish.cs" />
|
<Compile Include="database\edit\OnFinish.cs" />
|
||||||
<Compile Include="database\edit\RunnableOnFinish.cs" />
|
<Compile Include="database\edit\RunnableOnFinish.cs" />
|
||||||
<Compile Include="database\edit\SaveDB.cs" />
|
<Compile Include="database\edit\SaveDb.cs" />
|
||||||
<Compile Include="database\edit\SetPassword.cs" />
|
<Compile Include="database\edit\SetPassword.cs" />
|
||||||
<Compile Include="database\edit\UpdateEntry.cs" />
|
<Compile Include="database\edit\UpdateEntry.cs" />
|
||||||
<Compile Include="IKp2aApp.cs" />
|
<Compile Include="IKp2aApp.cs" />
|
||||||
@@ -157,10 +146,6 @@
|
|||||||
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
|
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
|
|
||||||
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
|
|
||||||
<Name>JavaFileStorageBindings</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
<ProjectReference Include="..\KeePassLib2Android\KeePassLib2Android.csproj">
|
||||||
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
|
<Project>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</Project>
|
||||||
<Name>KeePassLib2Android</Name>
|
<Name>KeePassLib2Android</Name>
|
||||||
@@ -169,10 +154,6 @@
|
|||||||
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
|
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
|
||||||
<Name>KP2AKdbLibraryBinding</Name>
|
<Name>KP2AKdbLibraryBinding</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\netftpandroid\System.Net.FtpClient\System.Net.FtpClient.Android.csproj">
|
|
||||||
<Project>{146FD497-BA03-4740-B6C5-5C84EA8FCDE2}</Project>
|
|
||||||
<Name>System.Net.FtpClient.Android</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
|
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
|
||||||
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
|
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
|
||||||
<Name>TwofishCipher</Name>
|
<Name>TwofishCipher</Name>
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
public void UpdateMessage (String message)
|
public void UpdateMessage (String message)
|
||||||
{
|
{
|
||||||
Kp2aLog.Log("status message: " + message);
|
_message = message;
|
||||||
_message = message;
|
|
||||||
if ( _app!= null && _progressDialog != null && _handler != null ) {
|
if ( _app!= null && _progressDialog != null && _handler != null ) {
|
||||||
_handler.Post(() => {_progressDialog.SetMessage(message); } );
|
_handler.Post(() => {_progressDialog.SetMessage(message); } );
|
||||||
}
|
}
|
||||||
@@ -61,7 +60,6 @@ namespace keepass2android
|
|||||||
|
|
||||||
public void UpdateSubMessage(String submessage)
|
public void UpdateSubMessage(String submessage)
|
||||||
{
|
{
|
||||||
Kp2aLog.Log("status submessage: " + submessage);
|
|
||||||
_submessage = submessage;
|
_submessage = submessage;
|
||||||
if (_app != null && _progressDialog != null && _handler != null)
|
if (_app != null && _progressDialog != null && _handler != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace keepass2android
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// EqualityComparer implementation to compare PwGroups based on their Id
|
/// EqualityComparer implementation to compare PwGroups based on their Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
|
class PwGroupEqualityFromIdComparer: IEqualityComparer<PwGroup>
|
||||||
{
|
{
|
||||||
#region IEqualityComparer implementation
|
#region IEqualityComparer implementation
|
||||||
public bool Equals (PwGroup x, PwGroup y)
|
public bool Equals (PwGroup x, PwGroup y)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ namespace keepass2android
|
|||||||
PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) {IsVirtual = true};
|
PwGroup pgResults = new PwGroup(true, true, strGroupName, PwIcon.EMailSearch) {IsVirtual = true};
|
||||||
if (String.IsNullOrWhiteSpace(host))
|
if (String.IsNullOrWhiteSpace(host))
|
||||||
return pgResults;
|
return pgResults;
|
||||||
foreach (PwEntry entry in database.EntriesById.Values)
|
foreach (PwEntry entry in database.Entries.Values)
|
||||||
{
|
{
|
||||||
string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField);
|
string otherUrl = entry.Strings.ReadSafe(PwDefs.UrlField);
|
||||||
otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References));
|
otherUrl = SprEngine.Compile(otherUrl, new SprContext(entry, database.KpDatabase, SprCompileFlags.References));
|
||||||
|
|||||||
@@ -86,8 +86,6 @@ namespace keepass2android
|
|||||||
ReadOnlyReason_PreKitKat,
|
ReadOnlyReason_PreKitKat,
|
||||||
ReadOnlyReason_ReadOnlyFlag,
|
ReadOnlyReason_ReadOnlyFlag,
|
||||||
ReadOnlyReason_ReadOnlyKitKat,
|
ReadOnlyReason_ReadOnlyKitKat,
|
||||||
ReadOnlyReason_LocalBackup,
|
ReadOnlyReason_LocalBackup
|
||||||
Ok,
|
|
||||||
cancel
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
|
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||||
if (fileStorage is CachingFileStorage)
|
if (fileStorage is CachingFileStorage)
|
||||||
{
|
{
|
||||||
@@ -49,7 +49,7 @@ namespace keepass2android
|
|||||||
hashingRemoteStream.CopyTo(remoteData);
|
hashingRemoteStream.CopyTo(remoteData);
|
||||||
hashingRemoteStream.Close();
|
hashingRemoteStream.Close();
|
||||||
|
|
||||||
if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
|
if (!MemUtil.ArraysEqual(_app.GetDb().KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
|
||||||
{
|
{
|
||||||
_app.TriggerReload(_context);
|
_app.TriggerReload(_context);
|
||||||
Finish(true);
|
Finish(true);
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ using KeePassLib;
|
|||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using keepass2android.Io;
|
using keepass2android.Io;
|
||||||
using KeePassLib.Interfaces;
|
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
using String = System.String;
|
using String = System.String;
|
||||||
@@ -34,23 +33,27 @@ using String = System.String;
|
|||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
|
|
||||||
public class Database
|
public class Database {
|
||||||
{
|
|
||||||
public HashSet<IStructureItem> Elements = new HashSet<IStructureItem>();
|
|
||||||
public Dictionary<PwUuid, PwGroup> GroupsById = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
|
public Dictionary<PwUuid, PwGroup> Groups = new Dictionary<PwUuid, PwGroup>(new PwUuidEqualityComparer());
|
||||||
public Dictionary<PwUuid, PwEntry> EntriesById = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
|
public Dictionary<PwUuid, PwEntry> Entries = new Dictionary<PwUuid, PwEntry>(new PwUuidEqualityComparer());
|
||||||
|
public HashSet<PwGroup> Dirty = new HashSet<PwGroup>(new PwGroupEqualityFromIdComparer());
|
||||||
public PwGroup Root;
|
public PwGroup Root;
|
||||||
public PwDatabase KpDatabase;
|
public PwDatabase KpDatabase;
|
||||||
public IOConnectionInfo Ioc
|
public IOConnectionInfo Ioc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
return KpDatabase == null ? null : KpDatabase.IOConnectionInfo;
|
||||||
return KpDatabase?.IOConnectionInfo;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Information about the last opened entry. Includes the entry but also transformed fields.
|
||||||
|
/// </summary>
|
||||||
|
public PwEntryOutput LastOpenedEntry { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// if an OTP key was used, this property tells the location of the OTP auxiliary file.
|
/// if an OTP key was used, this property tells the location of the OTP auxiliary file.
|
||||||
/// Must be set after loading.
|
/// Must be set after loading.
|
||||||
@@ -70,14 +73,31 @@ namespace keepass2android
|
|||||||
_app = app;
|
_app = app;
|
||||||
CanWrite = true; //default
|
CanWrite = true; //default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _loaded;
|
||||||
|
|
||||||
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
|
private bool _reloadRequested;
|
||||||
|
private IDatabaseFormat _databaseFormat = new KdbxDatabaseFormat(KdbxFormat.Default);
|
||||||
|
|
||||||
public bool ReloadRequested { get; set; }
|
public bool ReloadRequested
|
||||||
|
{
|
||||||
|
get { return _reloadRequested; }
|
||||||
|
set { _reloadRequested = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public bool DidOpenFileChange()
|
public bool Loaded {
|
||||||
|
get { return _loaded;}
|
||||||
|
set { _loaded = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DidOpenFileChange()
|
||||||
{
|
{
|
||||||
|
if (Loaded == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
|
return _app.GetFileStorage(Ioc).CheckForFileChangeFast(Ioc, LastFileVersion);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -92,20 +112,32 @@ namespace keepass2android
|
|||||||
Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo);
|
Stream s = databaseData ?? fileStorage.OpenFileForRead(iocInfo);
|
||||||
var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
|
var fileVersion = _app.GetFileStorage(iocInfo).GetCurrentFileVersionFast(iocInfo);
|
||||||
PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat);
|
PopulateDatabaseFromStream(pwDatabase, s, iocInfo, compositeKey, status, databaseFormat);
|
||||||
LastFileVersion = fileVersion;
|
try
|
||||||
|
{
|
||||||
|
LastFileVersion = fileVersion;
|
||||||
|
|
||||||
status.UpdateSubMessage("");
|
status.UpdateSubMessage("");
|
||||||
|
|
||||||
Root = pwDatabase.RootGroup;
|
Root = pwDatabase.RootGroup;
|
||||||
PopulateGlobals(Root);
|
PopulateGlobals(Root);
|
||||||
|
|
||||||
|
|
||||||
KpDatabase = pwDatabase;
|
KpDatabase = pwDatabase;
|
||||||
SearchHelper = new SearchDbHelper(app);
|
SearchHelper = new SearchDbHelper(app);
|
||||||
|
|
||||||
_databaseFormat = databaseFormat;
|
_databaseFormat = databaseFormat;
|
||||||
|
|
||||||
CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo);
|
CanWrite = databaseFormat.CanWrite && !fileStorage.IsReadOnly(iocInfo);
|
||||||
|
Loaded = true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -187,7 +219,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
public void SaveData() {
|
public void SaveData() {
|
||||||
|
|
||||||
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions)))
|
KpDatabase.UseFileTransactions = _app.GetBooleanPreference(PreferenceKey.UseFileTransactions);
|
||||||
|
using (IWriteTransaction trans = _app.GetFileStorage(Ioc).OpenWriteTransaction(Ioc, KpDatabase.UseFileTransactions))
|
||||||
{
|
{
|
||||||
DatabaseFormat.Save(KpDatabase, trans.OpenFile());
|
DatabaseFormat.Save(KpDatabase, trans.OpenFile());
|
||||||
|
|
||||||
@@ -206,18 +239,14 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
if (checkForDuplicateUuids)
|
if (checkForDuplicateUuids)
|
||||||
{
|
{
|
||||||
if (EntriesById.ContainsKey(e.Uuid))
|
if (Entries.ContainsKey(e.Uuid))
|
||||||
{
|
{
|
||||||
throw new DuplicateUuidsException("Same UUID for entries '"+EntriesById[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'.");
|
throw new DuplicateUuidsException("Same UUID for entries '"+Entries[e.Uuid].Strings.ReadSafe(PwDefs.TitleField)+"' and '"+e.Strings.ReadSafe(PwDefs.TitleField)+"'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
EntriesById [e.Uuid] = e;
|
Entries [e.Uuid] = e;
|
||||||
Elements.Add(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupsById[currentGroup.Uuid] = currentGroup;
|
|
||||||
Elements.Add(currentGroup);
|
|
||||||
foreach (PwGroup g in childGroups)
|
foreach (PwGroup g in childGroups)
|
||||||
{
|
{
|
||||||
if (checkForDuplicateUuids)
|
if (checkForDuplicateUuids)
|
||||||
@@ -229,6 +258,7 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
* */
|
* */
|
||||||
}
|
}
|
||||||
|
Groups[g.Uuid] = g;
|
||||||
PopulateGlobals(g);
|
PopulateGlobals(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,15 +266,33 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids);
|
PopulateGlobals(currentGroup, _app.CheckForDuplicateUuids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clear() {
|
||||||
|
_loaded = false;
|
||||||
|
|
||||||
|
Groups.Clear();
|
||||||
|
Entries.Clear();
|
||||||
|
Dirty.Clear();
|
||||||
|
DrawableFactory.Clear();
|
||||||
|
|
||||||
|
Root = null;
|
||||||
|
KpDatabase = null;
|
||||||
|
|
||||||
|
CanWrite = true;
|
||||||
|
_reloadRequested = false;
|
||||||
|
OtpAuxFileIoc = null;
|
||||||
|
LastOpenedEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkAllGroupsAsDirty() {
|
||||||
|
foreach ( PwGroup group in Groups.Values ) {
|
||||||
|
Dirty.Add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
public void UpdateGlobals()
|
|
||||||
{
|
|
||||||
EntriesById.Clear();
|
|
||||||
GroupsById.Clear();
|
|
||||||
Elements.Clear();
|
|
||||||
PopulateGlobals(Root);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|||||||
@@ -216,16 +216,9 @@ namespace keepass2android
|
|||||||
|
|
||||||
private DateTime JavaTimeToCSharp(long javatime)
|
private DateTime JavaTimeToCSharp(long javatime)
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
var utcTime = new DateTime(1970, 1, 1).AddMilliseconds(javatime);
|
|
||||||
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, TimeZoneInfo.Local);
|
|
||||||
}
|
|
||||||
catch (ArgumentOutOfRangeException)
|
|
||||||
{
|
|
||||||
return DateTime.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var utcTime = new DateTime(1970, 1, 1).AddMilliseconds(javatime);
|
||||||
|
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, TimeZoneInfo.Local);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ namespace keepass2android
|
|||||||
public class PwEntryOutput
|
public class PwEntryOutput
|
||||||
{
|
{
|
||||||
private readonly PwEntry _entry;
|
private readonly PwEntry _entry;
|
||||||
private readonly Database _db;
|
private readonly PwDatabase _db;
|
||||||
private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
|
private readonly ProtectedStringDictionary _outputStrings = new ProtectedStringDictionary();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs the PwEntryOutput by replacing the placeholders
|
/// Constructs the PwEntryOutput by replacing the placeholders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PwEntryOutput(PwEntry entry, Database db)
|
public PwEntryOutput(PwEntry entry, PwDatabase db)
|
||||||
{
|
{
|
||||||
_entry = entry;
|
_entry = entry;
|
||||||
_db = db;
|
_db = db;
|
||||||
@@ -34,7 +34,7 @@ namespace keepass2android
|
|||||||
string GetStringAndReplacePlaceholders(string key)
|
string GetStringAndReplacePlaceholders(string key)
|
||||||
{
|
{
|
||||||
String value = Entry.Strings.ReadSafe(key);
|
String value = Entry.Strings.ReadSafe(key);
|
||||||
value = SprEngine.Compile(value, new SprContext(Entry, _db.KpDatabase, SprCompileFlags.All));
|
value = SprEngine.Compile(value, new SprContext(Entry, _db, SprCompileFlags.All));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
|
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||||
if (!(fileStorage is CachingFileStorage))
|
if (!(fileStorage is CachingFileStorage))
|
||||||
{
|
{
|
||||||
@@ -70,12 +70,10 @@ namespace keepass2android
|
|||||||
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
||||||
}
|
}
|
||||||
_saveDb = null;
|
_saveDb = null;
|
||||||
}), _app.CurrentDb, false, remoteData);
|
}), false, remoteData);
|
||||||
_saveDb.Run();
|
_saveDb.Run();
|
||||||
|
|
||||||
_app.CurrentDb.UpdateGlobals();
|
_app.GetDb().MarkAllGroupsAsDirty();
|
||||||
|
|
||||||
_app.MarkAllGroupsAsDirty();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -105,7 +103,6 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Kp2aLog.LogUnexpectedError(e);
|
|
||||||
Finish(false, e.Message);
|
Finish(false, e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace keepass2android
|
|||||||
public class AddEntry : RunnableOnFinish {
|
public class AddEntry : RunnableOnFinish {
|
||||||
protected Database Db
|
protected Database Db
|
||||||
{
|
{
|
||||||
get { return _app.CurrentDb; }
|
get { return _app.GetDb(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
@@ -37,13 +37,13 @@ namespace keepass2android
|
|||||||
return new AddEntry(ctx, app, entry, parentGroup, finish);
|
return new AddEntry(ctx, app, entry, parentGroup, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddEntry(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
|
protected AddEntry(Activity ctx, IKp2aApp app, PwEntry entry, PwGroup parentGroup, OnFinish finish):base(ctx, finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_parentGroup = parentGroup;
|
_parentGroup = parentGroup;
|
||||||
_app = app;
|
_app = app;
|
||||||
_entry = entry;
|
_entry = entry;
|
||||||
|
|
||||||
_onFinishToRun = new AfterAdd(ctx, app.CurrentDb, entry, app,OnFinishToRun);
|
_onFinishToRun = new AfterAdd(ctx, app.GetDb(), entry, OnFinishToRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
@@ -68,13 +68,12 @@ namespace keepass2android
|
|||||||
private class AfterAdd : OnFinish {
|
private class AfterAdd : OnFinish {
|
||||||
private readonly Database _db;
|
private readonly Database _db;
|
||||||
private readonly PwEntry _entry;
|
private readonly PwEntry _entry;
|
||||||
private readonly IKp2aApp _app;
|
|
||||||
|
|
||||||
public AfterAdd(Activity activity, Database db, PwEntry entry, IKp2aApp app, OnFinish finish):base(activity, finish) {
|
public AfterAdd(Activity activity, Database db, PwEntry entry, OnFinish finish):base(activity, finish) {
|
||||||
_db = db;
|
_db = db;
|
||||||
_entry = entry;
|
_entry = entry;
|
||||||
_app = app;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -84,12 +83,11 @@ namespace keepass2android
|
|||||||
PwGroup parent = _entry.ParentGroup;
|
PwGroup parent = _entry.ParentGroup;
|
||||||
|
|
||||||
// Mark parent group dirty
|
// Mark parent group dirty
|
||||||
_app.DirtyGroups.Add(parent);
|
_db.Dirty.Add(parent);
|
||||||
|
|
||||||
// Add entry to global
|
// Add entry to global
|
||||||
_db.EntriesById[_entry.Uuid] = _entry;
|
_db.Entries[_entry.Uuid] = _entry;
|
||||||
_db.Elements.Add(_entry);
|
|
||||||
|
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
||||||
|
|||||||
@@ -26,16 +26,13 @@ namespace keepass2android
|
|||||||
public class AddGroup : RunnableOnFinish {
|
public class AddGroup : RunnableOnFinish {
|
||||||
internal Database Db
|
internal Database Db
|
||||||
{
|
{
|
||||||
get { return _app.CurrentDb; }
|
get { return _app.GetDb(); }
|
||||||
}
|
}
|
||||||
|
private IKp2aApp _app;
|
||||||
public IKp2aApp App { get => _app; }
|
|
||||||
|
|
||||||
private IKp2aApp _app;
|
|
||||||
private readonly String _name;
|
private readonly String _name;
|
||||||
private readonly int _iconId;
|
private readonly int _iconId;
|
||||||
private readonly PwUuid _groupCustomIconId;
|
private readonly PwUuid _groupCustomIconId;
|
||||||
public PwGroup Group;
|
internal PwGroup Group;
|
||||||
internal PwGroup Parent;
|
internal PwGroup Parent;
|
||||||
protected bool DontSave;
|
protected bool DontSave;
|
||||||
readonly Activity _ctx;
|
readonly Activity _ctx;
|
||||||
@@ -70,11 +67,9 @@ namespace keepass2android
|
|||||||
Group.CustomIconUuid = _groupCustomIconId;
|
Group.CustomIconUuid = _groupCustomIconId;
|
||||||
}
|
}
|
||||||
Parent.AddGroup(Group, true);
|
Parent.AddGroup(Group, true);
|
||||||
_app.CurrentDb.GroupsById[Group.Uuid] = Group;
|
|
||||||
_app.CurrentDb.Elements.Add(Group);
|
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, DontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, DontSave);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
@@ -91,15 +86,13 @@ namespace keepass2android
|
|||||||
|
|
||||||
if ( Success ) {
|
if ( Success ) {
|
||||||
// Mark parent group dirty
|
// Mark parent group dirty
|
||||||
_addGroup.App.DirtyGroups.Add(_addGroup.Parent);
|
_addGroup.Db.Dirty.Add(_addGroup.Parent);
|
||||||
|
|
||||||
// Add group to global list
|
// Add group to global list
|
||||||
_addGroup.Db.GroupsById[_addGroup.Group.Uuid] = _addGroup.Group;
|
_addGroup.Db.Groups[_addGroup.Group.Uuid] = _addGroup.Group;
|
||||||
_addGroup.Db.Elements.Add(_addGroup.Group);
|
|
||||||
} else {
|
} else {
|
||||||
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
StatusLogger.UpdateMessage(UiStringKey.UndoingChanges);
|
||||||
_addGroup.Parent.Groups.Remove(_addGroup.Group);
|
_addGroup.Parent.Groups.Remove(_addGroup.Group);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Run();
|
base.Run();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
public class AddTemplateEntries : RunnableOnFinish {
|
public class AddTemplateEntries : RunnableOnFinish {
|
||||||
|
|
||||||
public class TemplateEntry
|
class TemplateEntry
|
||||||
{
|
{
|
||||||
public UiStringKey Title { get; set; }
|
public UiStringKey Title { get; set; }
|
||||||
public PwIcon Icon { get; set; }
|
public PwIcon Icon { get; set; }
|
||||||
@@ -47,12 +47,11 @@ namespace keepass2android
|
|||||||
void AddToEntry(IKp2aApp app, PwEntry entry, int position);
|
void AddToEntry(IKp2aApp app, PwEntry entry, int position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FieldType
|
internal enum FieldType
|
||||||
{
|
{
|
||||||
Inline, ProtectedInline
|
Inline, ProtectedInline
|
||||||
}
|
}
|
||||||
|
internal enum SpecialFieldKey
|
||||||
public enum SpecialFieldKey
|
|
||||||
{
|
{
|
||||||
ExpDate, OverrideUrl, Tags
|
ExpDate, OverrideUrl, Tags
|
||||||
}
|
}
|
||||||
@@ -126,7 +125,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
protected Database Db
|
protected Database Db
|
||||||
{
|
{
|
||||||
get { return _app.CurrentDb; }
|
get { return _app.GetDb(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
@@ -141,7 +140,7 @@ namespace keepass2android
|
|||||||
//_onFinishToRun = new AfterAdd(this, OnFinishToRun);
|
//_onFinishToRun = new AfterAdd(this, OnFinishToRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
|
static readonly List<TemplateEntry> TemplateEntries = new List<TemplateEntry>()
|
||||||
{
|
{
|
||||||
new TemplateEntry()
|
new TemplateEntry()
|
||||||
{
|
{
|
||||||
@@ -286,23 +285,12 @@ namespace keepass2android
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool ContainsAllTemplates(Database db)
|
public static bool ContainsAllTemplates(IKp2aApp app)
|
||||||
{
|
{
|
||||||
return TemplateEntries.All(t =>
|
return TemplateEntries.All(t => app.GetDb().Entries.ContainsKey(t.Uuid));
|
||||||
{
|
|
||||||
string hexId = t.Uuid.ToHexString();
|
|
||||||
|
|
||||||
return db.EntriesById.Any(kvp => kvp.Key.Equals(t.Uuid) ||
|
|
||||||
kvp.Value.Strings.ReadSafe(TemplateIdStringKey) == hexId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string TemplateIdStringKey
|
public override void Run() {
|
||||||
{
|
|
||||||
get { return "KP2A_TemplateId"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Run() {
|
|
||||||
StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
|
StatusLogger.UpdateMessage(UiStringKey.AddingEntry);
|
||||||
|
|
||||||
List<PwEntry> addedEntries;
|
List<PwEntry> addedEntries;
|
||||||
@@ -310,10 +298,10 @@ namespace keepass2android
|
|||||||
|
|
||||||
if (addedEntries.Any())
|
if (addedEntries.Any())
|
||||||
{
|
{
|
||||||
_app.DirtyGroups.Add(templateGroup);
|
_app.GetDb().Dirty.Add(templateGroup);
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
@@ -327,28 +315,26 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
PwGroup templateGroup;
|
PwGroup templateGroup;
|
||||||
if (!_app.CurrentDb.GroupsById.TryGetValue(_app.CurrentDb.KpDatabase.EntryTemplatesGroup, out templateGroup))
|
if (!_app.GetDb().Groups.TryGetValue(_app.GetDb().KpDatabase.EntryTemplatesGroup, out templateGroup))
|
||||||
{
|
{
|
||||||
//create template group
|
//create template group
|
||||||
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
|
templateGroup = new PwGroup(true, true, _app.GetResourceString(UiStringKey.TemplateGroupName), PwIcon.Folder);
|
||||||
_app.CurrentDb.KpDatabase.RootGroup.AddGroup(templateGroup, true);
|
_app.GetDb().KpDatabase.RootGroup.AddGroup(templateGroup, true);
|
||||||
_app.CurrentDb.KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
|
_app.GetDb().KpDatabase.EntryTemplatesGroup = templateGroup.Uuid;
|
||||||
_app.CurrentDb.KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
|
_app.GetDb().KpDatabase.EntryTemplatesGroupChanged = DateTime.Now;
|
||||||
_app.DirtyGroups.Add(_app.CurrentDb.KpDatabase.RootGroup);
|
_app.GetDb().Dirty.Add(_app.GetDb().KpDatabase.RootGroup);
|
||||||
_app.CurrentDb.GroupsById[templateGroup.Uuid] = templateGroup;
|
_app.GetDb().Groups[templateGroup.Uuid] = templateGroup;
|
||||||
_app.CurrentDb.Elements.Add(templateGroup);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
addedEntries = new List<PwEntry>();
|
addedEntries = new List<PwEntry>();
|
||||||
|
|
||||||
foreach (var template in TemplateEntries)
|
foreach (var template in TemplateEntries)
|
||||||
{
|
{
|
||||||
if (_app.CurrentDb.EntriesById.ContainsKey(template.Uuid))
|
if (_app.GetDb().Entries.ContainsKey(template.Uuid))
|
||||||
continue;
|
continue;
|
||||||
PwEntry entry = CreateEntry(template);
|
PwEntry entry = CreateEntry(template);
|
||||||
templateGroup.AddEntry(entry, true);
|
templateGroup.AddEntry(entry, true);
|
||||||
addedEntries.Add(entry);
|
addedEntries.Add(entry);
|
||||||
_app.CurrentDb.EntriesById[entry.Uuid] = entry;
|
_app.GetDb().Entries[entry.Uuid] = entry;
|
||||||
}
|
}
|
||||||
return templateGroup;
|
return templateGroup;
|
||||||
}
|
}
|
||||||
@@ -387,12 +373,8 @@ namespace keepass2android
|
|||||||
base.Run();
|
base.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static bool IsTemplateId(PwUuid pwUuid)
|
|
||||||
{
|
|
||||||
return TemplateEntries.Any(te => te.Uuid.Equals(pwUuid));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,22 +27,23 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
|
|
||||||
public class CreateDb : RunnableOnFinish {
|
public class CreateDb : RunnableOnFinish {
|
||||||
private readonly IOConnectionInfo _ioc;
|
|
||||||
|
private const ulong DefaultEncryptionRounds = PwDefs.DefaultKeyEncryptionRounds;
|
||||||
|
|
||||||
|
private readonly IOConnectionInfo _ioc;
|
||||||
private readonly bool _dontSave;
|
private readonly bool _dontSave;
|
||||||
private readonly Activity _ctx;
|
private readonly Activity _ctx;
|
||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
private CompositeKey _key;
|
private CompositeKey _key;
|
||||||
private readonly bool _makeCurrent;
|
|
||||||
|
|
||||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, bool makeCurrent): base(ctx, finish) {
|
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave): base(ctx, finish) {
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_ioc = ioc;
|
_ioc = ioc;
|
||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
_makeCurrent = makeCurrent;
|
_app = app;
|
||||||
_app = app;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key, bool makeCurrent)
|
public CreateDb(IKp2aApp app, Activity ctx, IOConnectionInfo ioc, OnFinish finish, bool dontSave, CompositeKey key)
|
||||||
: base(ctx, finish)
|
: base(ctx, finish)
|
||||||
{
|
{
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
@@ -50,13 +51,12 @@ namespace keepass2android
|
|||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
_app = app;
|
_app = app;
|
||||||
_key = key;
|
_key = key;
|
||||||
_makeCurrent = makeCurrent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
StatusLogger.UpdateMessage(UiStringKey.progress_create);
|
StatusLogger.UpdateMessage(UiStringKey.progress_create);
|
||||||
Database db = _app.CreateNewDatabase(_makeCurrent);
|
Database db = _app.CreateNewDatabase();
|
||||||
|
|
||||||
db.KpDatabase = new KeePassLib.PwDatabase();
|
db.KpDatabase = new KeePassLib.PwDatabase();
|
||||||
|
|
||||||
@@ -74,6 +74,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
// Set Database state
|
// Set Database state
|
||||||
db.Root = db.KpDatabase.RootGroup;
|
db.Root = db.KpDatabase.RootGroup;
|
||||||
|
db.Loaded = true;
|
||||||
db.SearchHelper = new SearchDbHelper(_app);
|
db.SearchHelper = new SearchDbHelper(_app);
|
||||||
|
|
||||||
// Add a couple default groups
|
// Add a couple default groups
|
||||||
@@ -87,14 +88,12 @@ namespace keepass2android
|
|||||||
addTemplates.AddTemplates(out addedEntries);
|
addTemplates.AddTemplates(out addedEntries);
|
||||||
|
|
||||||
// Commit changes
|
// Commit changes
|
||||||
SaveDb save = new SaveDb(_ctx, _app, db, OnFinishToRun, _dontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
_onFinishToRun = null;
|
_onFinishToRun = null;
|
||||||
save.Run();
|
save.Run();
|
||||||
|
|
||||||
db.UpdateGlobals();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
|
public DeleteEntry(Activity activiy, IKp2aApp app, PwEntry entry, OnFinish finish):base(activiy, finish, app) {
|
||||||
Ctx = activiy;
|
Ctx = activiy;
|
||||||
Db = app.FindDatabaseForElement(entry);
|
Db = app.GetDb();
|
||||||
_entry = entry;
|
_entry = entry;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
|
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_entry.ParentGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace keepass2android
|
|||||||
*/
|
*/
|
||||||
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
|
private void SetMembers(Activity activity, IKp2aApp app, PwGroup group, bool dontSave)
|
||||||
{
|
{
|
||||||
base.SetMembers(activity, app.FindDatabaseForElement(group));
|
base.SetMembers(activity, app.GetDb());
|
||||||
|
|
||||||
_group = group;
|
_group = group;
|
||||||
DontSave = dontSave;
|
DontSave = dontSave;
|
||||||
@@ -58,7 +58,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Db.DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
|
return App.GetDb().DatabaseFormat.CanRecycle && CanRecycleGroup(_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ using KeePassLib.Interfaces;
|
|||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
public class DeleteMultipleItemsFromOneDatabase : DeleteRunnable
|
public class DeleteMultipleItems : DeleteRunnable
|
||||||
{
|
{
|
||||||
private readonly List<IStructureItem> _elementsToDelete;
|
private readonly List<IStructureItem> _elementsToDelete;
|
||||||
private readonly bool _canRecycle;
|
private readonly bool _canRecycle;
|
||||||
|
|
||||||
public DeleteMultipleItemsFromOneDatabase(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
|
public DeleteMultipleItems(Activity activity, Database db, List<IStructureItem> elementsToDelete, OnFinish finish, IKp2aApp app)
|
||||||
: base(activity, finish, app)
|
: base(activity, finish, app)
|
||||||
{
|
{
|
||||||
_elementsToDelete = elementsToDelete;
|
_elementsToDelete = elementsToDelete;
|
||||||
@@ -21,13 +21,12 @@ namespace keepass2android
|
|||||||
//determine once. The property is queried for each delete operation, but might return false
|
//determine once. The property is queried for each delete operation, but might return false
|
||||||
//after one entry/group is deleted (and thus in recycle bin and thus can't be recycled anymore)
|
//after one entry/group is deleted (and thus in recycle bin and thus can't be recycled anymore)
|
||||||
_canRecycle = DetermineCanRecycle();
|
_canRecycle = DetermineCanRecycle();
|
||||||
ShowDatabaseIocInStatus = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DetermineCanRecycle()
|
private bool DetermineCanRecycle()
|
||||||
{
|
{
|
||||||
Android.Util.Log.Debug("KP2A", "CanRecycle?");
|
Android.Util.Log.Debug("KP2A", "CanRecycle?");
|
||||||
if (!Db.DatabaseFormat.CanRecycle)
|
if (!App.GetDb().DatabaseFormat.CanRecycle)
|
||||||
{
|
{
|
||||||
Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format.");
|
Android.Util.Log.Debug("KP2A", "CanRecycle? No because of DB format.");
|
||||||
return false;
|
return false;
|
||||||
@@ -100,8 +100,7 @@ namespace keepass2android
|
|||||||
};
|
};
|
||||||
|
|
||||||
Db.KpDatabase.RootGroup.AddGroup(pgRecycleBin, true);
|
Db.KpDatabase.RootGroup.AddGroup(pgRecycleBin, true);
|
||||||
Db.GroupsById[pgRecycleBin.Uuid] = pgRecycleBin;
|
Db.Groups[pgRecycleBin.Uuid] = pgRecycleBin;
|
||||||
Db.Elements.Add(pgRecycleBin);
|
|
||||||
Db.KpDatabase.RecycleBinUuid = pgRecycleBin.Uuid;
|
Db.KpDatabase.RecycleBinUuid = pgRecycleBin.Uuid;
|
||||||
|
|
||||||
bGroupListUpdateRequired = true;
|
bGroupListUpdateRequired = true;
|
||||||
@@ -122,27 +121,24 @@ namespace keepass2android
|
|||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
string messageSuffix = ShowDatabaseIocInStatus ? "(" + App.GetFileStorage(Db.Ioc).GetDisplayName(Db.Ioc) + ")" : "";
|
if (CanRecycle)
|
||||||
|
|
||||||
if (CanRecycle)
|
|
||||||
{
|
{
|
||||||
App.AskYesNoCancel(UiStringKey.AskDeletePermanently_title,
|
App.AskYesNoCancel(UiStringKey.AskDeletePermanently_title,
|
||||||
QuestionRecycleResourceId,
|
QuestionRecycleResourceId,
|
||||||
(dlgSender, dlgEvt) =>
|
(dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
DeletePermanently = true;
|
DeletePermanently = true;
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
|
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) =>
|
(dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
DeletePermanently = false;
|
DeletePermanently = false;
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
(dlgSender, dlgEvt) => { },
|
(dlgSender, dlgEvt) => { },
|
||||||
Ctx, messageSuffix);
|
Ctx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -153,12 +149,12 @@ namespace keepass2android
|
|||||||
QuestionNoRecycleResourceId,
|
QuestionNoRecycleResourceId,
|
||||||
(dlgSender, dlgEvt) =>
|
(dlgSender, dlgEvt) =>
|
||||||
{
|
{
|
||||||
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
ProgressTask pt = new ProgressTask(App, Ctx, this);
|
||||||
pt.Run();
|
pt.Run();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
(dlgSender, dlgEvt) => { },
|
(dlgSender, dlgEvt) => { },
|
||||||
Ctx, messageSuffix);
|
Ctx);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -186,8 +182,7 @@ namespace keepass2android
|
|||||||
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
|
PwDeletedObject pdo = new PwDeletedObject(pe.Uuid, dtNow);
|
||||||
pd.DeletedObjects.Add(pdo);
|
pd.DeletedObjects.Add(pdo);
|
||||||
touchedGroups.Add(pgParent);
|
touchedGroups.Add(pgParent);
|
||||||
Db.EntriesById.Remove(pe.Uuid);
|
Db.Entries.Remove(pe.Uuid);
|
||||||
Db.Elements.Remove(pe);
|
|
||||||
}
|
}
|
||||||
else // Recycle
|
else // Recycle
|
||||||
{
|
{
|
||||||
@@ -220,41 +215,31 @@ namespace keepass2android
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
foreach (var g in touchedGroups)
|
foreach (var g in touchedGroups)
|
||||||
App.DirtyGroups.Add(g);
|
Db.Dirty.Add(g);
|
||||||
foreach (var g in permanentlyDeletedGroups)
|
foreach (var g in permanentlyDeletedGroups)
|
||||||
{
|
{
|
||||||
//remove groups from global lists if present there
|
//remove groups from global lists if present there
|
||||||
App.DirtyGroups.Remove(g);
|
Db.Dirty.Remove(g);
|
||||||
Db.GroupsById.Remove(g.Uuid);
|
Db.Groups.Remove(g.Uuid);
|
||||||
Db.Elements.Remove(g);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Let's not bother recovering from a failure to save. It is too much work.
|
// Let's not bother recovering from a failure to save. It is too much work.
|
||||||
App.Lock(false);
|
App.LockDatabase(false);
|
||||||
}
|
}
|
||||||
}, OnFinishToRun);
|
}, OnFinishToRun);
|
||||||
|
|
||||||
// Commit database
|
// Commit database
|
||||||
SaveDb save = new SaveDb(Ctx, App, Db, OnFinishToRun, false);
|
SaveDb save = new SaveDb(Ctx, App, OnFinishToRun, false);
|
||||||
save.ShowDatabaseIocInStatus = ShowDatabaseIocInStatus;
|
save.SetStatusLogger(StatusLogger);
|
||||||
|
|
||||||
save.SetStatusLogger(StatusLogger);
|
|
||||||
save.Run();
|
save.Run();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowDatabaseIocInStatus
|
protected abstract void PerformDelete(List<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups);
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void PerformDelete(List<PwGroup> touchedGroups, List<PwGroup> permanentlyDeletedGroups);
|
|
||||||
|
|
||||||
public abstract UiStringKey StatusMessage { get; }
|
public abstract UiStringKey StatusMessage { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,9 @@ namespace keepass2android
|
|||||||
public class EditGroup : RunnableOnFinish {
|
public class EditGroup : RunnableOnFinish {
|
||||||
internal Database Db
|
internal Database Db
|
||||||
{
|
{
|
||||||
get { return _app.FindDatabaseForElement(Group); }
|
get { return _app.GetDb(); }
|
||||||
}
|
}
|
||||||
|
private IKp2aApp _app;
|
||||||
public IKp2aApp App { get => _app; }
|
|
||||||
|
|
||||||
private IKp2aApp _app;
|
|
||||||
private readonly String _name;
|
private readonly String _name;
|
||||||
private readonly PwIcon _iconId;
|
private readonly PwIcon _iconId;
|
||||||
private readonly PwUuid _customIconId;
|
private readonly PwUuid _customIconId;
|
||||||
@@ -60,7 +57,7 @@ namespace keepass2android
|
|||||||
Group.Touch(true);
|
Group.Touch(true);
|
||||||
|
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _app, Db, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
@@ -79,10 +76,10 @@ namespace keepass2android
|
|||||||
|
|
||||||
if ( Success ) {
|
if ( Success ) {
|
||||||
// Mark parent group dirty
|
// Mark parent group dirty
|
||||||
_editGroup.App.DirtyGroups.Add(_editGroup.Group.ParentGroup);
|
_editGroup.Db.Dirty.Add(_editGroup.Group.ParentGroup);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
_editGroup._app.Lock(false);
|
_editGroup._app.LockDatabase(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Run();
|
base.Run();
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using keepass2android.database.edit;
|
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
@@ -37,25 +36,20 @@ namespace keepass2android
|
|||||||
private readonly bool _rememberKeyfile;
|
private readonly bool _rememberKeyfile;
|
||||||
IDatabaseFormat _format;
|
IDatabaseFormat _format;
|
||||||
|
|
||||||
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish, bool updateLastUsageTimestamp, bool makeCurrent): base(activity, finish)
|
public LoadDb(Activity activity, IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(activity, finish)
|
||||||
{
|
{
|
||||||
_app = app;
|
_app = app;
|
||||||
_ioc = ioc;
|
_ioc = ioc;
|
||||||
_databaseData = databaseData;
|
_databaseData = databaseData;
|
||||||
_compositeKey = compositeKey;
|
_compositeKey = compositeKey;
|
||||||
_keyfileOrProvider = keyfileOrProvider;
|
_keyfileOrProvider = keyfileOrProvider;
|
||||||
_updateLastUsageTimestamp = updateLastUsageTimestamp;
|
|
||||||
_makeCurrent = makeCurrent;
|
|
||||||
|
|
||||||
|
|
||||||
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool success = false;
|
|
||||||
private bool _updateLastUsageTimestamp;
|
public override void Run()
|
||||||
private readonly bool _makeCurrent;
|
|
||||||
|
|
||||||
public override void Run()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -84,10 +78,6 @@ namespace keepass2android
|
|||||||
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
|
//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(_ioc));
|
_format = new KdbxDatabaseFormat(KdbpFile.GetFormatToUse(_ioc));
|
||||||
TryLoad(databaseStream);
|
TryLoad(databaseStream);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
success = true;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -99,7 +89,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
Kp2aLog.Log("KeyFileException");
|
Kp2aLog.Log("KeyFileException");
|
||||||
Finish(false, /*TODO Localize: use Keepass error text KPRes.KeyFileError (including "or invalid format")*/
|
Finish(false, /*TODO Localize: use Keepass error text KPRes.KeyFileError (including "or invalid format")*/
|
||||||
_app.GetResourceString(UiStringKey.keyfile_does_not_exist), false, Exception);
|
_app.GetResourceString(UiStringKey.keyfile_does_not_exist), Exception);
|
||||||
}
|
}
|
||||||
catch (AggregateException e)
|
catch (AggregateException e)
|
||||||
{
|
{
|
||||||
@@ -110,20 +100,20 @@ namespace keepass2android
|
|||||||
// Override the message shown with the last (hopefully most recent) inner exception
|
// Override the message shown with the last (hopefully most recent) inner exception
|
||||||
Kp2aLog.LogUnexpectedError(innerException);
|
Kp2aLog.LogUnexpectedError(innerException);
|
||||||
}
|
}
|
||||||
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + message, false, Exception);
|
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + message, Exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (DuplicateUuidsException e)
|
catch (DuplicateUuidsException e)
|
||||||
{
|
{
|
||||||
Kp2aLog.Log(e.ToString());
|
Kp2aLog.Log(e.ToString());
|
||||||
Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + e.Message + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), false, Exception);
|
Finish(false, _app.GetResourceString(UiStringKey.DuplicateUuidsError) + " " + e.Message + _app.GetResourceString(UiStringKey.DuplicateUuidsErrorAdditional), Exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (!(e is InvalidCompositeKeyException))
|
if (!(e is InvalidCompositeKeyException))
|
||||||
Kp2aLog.LogUnexpectedError(e);
|
Kp2aLog.LogUnexpectedError(e);
|
||||||
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, false, Exception);
|
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, Exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +125,7 @@ namespace keepass2android
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Exception Exception { get; set; }
|
public Exception Exception { get; set; }
|
||||||
|
|
||||||
Database TryLoad(MemoryStream databaseStream)
|
private void 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
|
//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.
|
//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.
|
||||||
@@ -148,16 +138,19 @@ namespace keepass2android
|
|||||||
//now let's go:
|
//now let's go:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Database newDb = _app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format, _makeCurrent);
|
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _format);
|
||||||
Kp2aLog.Log("LoadDB OK");
|
Kp2aLog.Log("LoadDB OK");
|
||||||
|
|
||||||
|
//make sure the stored access time for the actual file is more recent than that of its backup
|
||||||
|
Thread.Sleep(10);
|
||||||
|
SaveFileData(_ioc, _keyfileOrProvider);
|
||||||
|
|
||||||
Finish(true, _format.SuccessMessage);
|
Finish(true, _format.SuccessMessage);
|
||||||
return newDb;
|
|
||||||
}
|
}
|
||||||
catch (OldFormatException)
|
catch (OldFormatException)
|
||||||
{
|
{
|
||||||
_format = new KdbDatabaseFormat(_app);
|
_format = new KdbDatabaseFormat(_app);
|
||||||
return TryLoad(databaseStream);
|
TryLoad(databaseStream);
|
||||||
}
|
}
|
||||||
catch (InvalidCompositeKeyException)
|
catch (InvalidCompositeKeyException)
|
||||||
{
|
{
|
||||||
@@ -169,7 +162,7 @@ namespace keepass2android
|
|||||||
//retry without password:
|
//retry without password:
|
||||||
_compositeKey.RemoveUserKey(passwordKey);
|
_compositeKey.RemoveUserKey(passwordKey);
|
||||||
//retry:
|
//retry:
|
||||||
return TryLoad(databaseStream);
|
TryLoad(databaseStream);
|
||||||
}
|
}
|
||||||
else throw;
|
else throw;
|
||||||
}
|
}
|
||||||
@@ -182,7 +175,7 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
keyfileOrProvider = "";
|
keyfileOrProvider = "";
|
||||||
}
|
}
|
||||||
_app.StoreOpenedFileAsRecent(ioc, keyfileOrProvider, _updateLastUsageTimestamp);
|
_app.StoreOpenedFileAsRecent(ioc, keyfileOrProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
@@ -51,19 +50,10 @@ namespace keepass2android.database.edit
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<Database> removeDatabases = new HashSet<Database>();
|
|
||||||
Database addDatabase = _app.FindDatabaseForElement(_targetGroup);
|
|
||||||
if (addDatabase == null)
|
|
||||||
{
|
|
||||||
Finish(false, "Did not find target database. Did you lock it?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var elementToMove in _elementsToMove)
|
foreach (var elementToMove in _elementsToMove)
|
||||||
{
|
{
|
||||||
|
|
||||||
_app.DirtyGroups.Add(elementToMove.ParentGroup);
|
_app.GetDb().Dirty.Add(elementToMove.ParentGroup);
|
||||||
|
|
||||||
|
|
||||||
PwGroup pgParent = elementToMove.ParentGroup;
|
PwGroup pgParent = elementToMove.ParentGroup;
|
||||||
if (pgParent != _targetGroup)
|
if (pgParent != _targetGroup)
|
||||||
@@ -73,14 +63,8 @@ namespace keepass2android.database.edit
|
|||||||
PwEntry entry = elementToMove as PwEntry;
|
PwEntry entry = elementToMove as PwEntry;
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
var dbRem = _app.FindDatabaseForElement(entry);
|
|
||||||
removeDatabases.Add(dbRem);
|
|
||||||
dbRem.EntriesById.Remove(entry.Uuid);
|
|
||||||
dbRem.Elements.Remove(entry);
|
|
||||||
pgParent.Entries.Remove(entry);
|
pgParent.Entries.Remove(entry);
|
||||||
_targetGroup.AddEntry(entry, true, true);
|
_targetGroup.AddEntry(entry, true, true);
|
||||||
addDatabase.EntriesById.Add(entry.Uuid, entry);
|
|
||||||
addDatabase.Elements.Add(entry);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -90,60 +74,27 @@ namespace keepass2android.database.edit
|
|||||||
Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere));
|
Finish(false, _app.GetResourceString(UiStringKey.CannotMoveGroupHere));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dbRem = _app.FindDatabaseForElement(@group);
|
|
||||||
if (dbRem == null)
|
|
||||||
{
|
|
||||||
Finish(false, "Did not find source database. Did you lock it?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbRem.GroupsById.Remove(group.Uuid);
|
|
||||||
dbRem.Elements.Remove(group);
|
|
||||||
removeDatabases.Add(dbRem);
|
|
||||||
pgParent.Groups.Remove(group);
|
pgParent.Groups.Remove(group);
|
||||||
_targetGroup.AddGroup(group, true, true);
|
_targetGroup.AddGroup(group, true, true);
|
||||||
addDatabase.GroupsById.Add(group.Uuid, group);
|
|
||||||
addDatabase.Elements.Add(group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_onFinishToRun = new ActionOnFinish(ActiveActivity, (success, message, activity) =>
|
||||||
|
{
|
||||||
|
if (!success)
|
||||||
|
{ // Let's not bother recovering from a failure.
|
||||||
|
_app.LockDatabase(false);
|
||||||
|
}
|
||||||
|
}, OnFinishToRun);
|
||||||
|
|
||||||
|
// Save
|
||||||
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, false);
|
||||||
|
save.SetStatusLogger(StatusLogger);
|
||||||
//first save the database where we added the elements
|
save.Run();
|
||||||
var allDatabasesToSave = new List<Database> {addDatabase};
|
|
||||||
//then all databases where we removed elements:
|
|
||||||
removeDatabases.RemoveWhere(db => db == addDatabase);
|
|
||||||
allDatabasesToSave.AddRange(removeDatabases);
|
|
||||||
|
|
||||||
int indexToSave = 0;
|
|
||||||
bool allSavesSuccess = true;
|
|
||||||
void ContinueSave(bool success, string message, Activity activeActivity)
|
|
||||||
{
|
|
||||||
allSavesSuccess &= success;
|
|
||||||
indexToSave++;
|
|
||||||
if (indexToSave == allDatabasesToSave.Count)
|
|
||||||
{
|
|
||||||
OnFinishToRun.SetResult(allSavesSuccess);
|
|
||||||
OnFinishToRun.Run();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SaveDb saveDb = new SaveDb(_ctx, _app, allDatabasesToSave[indexToSave], new ActionOnFinish(activeActivity, ContinueSave), false);
|
|
||||||
saveDb.SetStatusLogger(StatusLogger);
|
|
||||||
saveDb.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1;
|
|
||||||
saveDb.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SaveDb save = new SaveDb(_ctx, _app, allDatabasesToSave[0], new ActionOnFinish(ActiveActivity, ContinueSave), false);
|
|
||||||
save.SetStatusLogger(StatusLogger);
|
|
||||||
save.ShowDatabaseIocInStatus = allDatabasesToSave.Count > 1;
|
|
||||||
save.Run();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Android;
|
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
@@ -29,14 +28,8 @@ namespace keepass2android
|
|||||||
protected bool Success;
|
protected bool Success;
|
||||||
protected String Message;
|
protected String Message;
|
||||||
protected Exception Exception;
|
protected Exception Exception;
|
||||||
|
|
||||||
protected bool ImportantMessage
|
protected OnFinish BaseOnFinish;
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected OnFinish BaseOnFinish;
|
|
||||||
protected Handler Handler;
|
protected Handler Handler;
|
||||||
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
|
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
|
||||||
private Activity _activeActivity;
|
private Activity _activeActivity;
|
||||||
@@ -84,22 +77,20 @@ namespace keepass2android
|
|||||||
Handler = null;
|
Handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResult(bool success, string message, bool importantMessage, Exception exception) {
|
public void SetResult(bool success, string message, Exception exception) {
|
||||||
Success = success;
|
Success = success;
|
||||||
Message = message;
|
Message = message;
|
||||||
ImportantMessage = importantMessage;
|
|
||||||
Exception = exception;
|
Exception = exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetResult(bool success) {
|
||||||
public void SetResult(bool success) {
|
|
||||||
Success = success;
|
Success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Run() {
|
public virtual void Run() {
|
||||||
if (BaseOnFinish == null) return;
|
if (BaseOnFinish == null) return;
|
||||||
// Pass on result on call finish
|
// Pass on result on call finish
|
||||||
BaseOnFinish.SetResult(Success, Message, ImportantMessage, Exception);
|
BaseOnFinish.SetResult(Success, Message, Exception);
|
||||||
|
|
||||||
if ( Handler != null ) {
|
if ( Handler != null ) {
|
||||||
Handler.Post(BaseOnFinish.Run);
|
Handler.Post(BaseOnFinish.Run);
|
||||||
@@ -109,31 +100,14 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void DisplayMessage(Context ctx) {
|
protected void DisplayMessage(Context ctx) {
|
||||||
DisplayMessage(ctx, Message, ImportantMessage);
|
DisplayMessage(ctx, Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DisplayMessage(Context ctx, string message, bool makeDialog)
|
public static void DisplayMessage(Context ctx, string message)
|
||||||
{
|
{
|
||||||
if ( !String.IsNullOrEmpty(message) ) {
|
if ( !String.IsNullOrEmpty(message) ) {
|
||||||
Kp2aLog.Log("OnFinish message: " + message);
|
Kp2aLog.Log("OnFinish message: "+message);
|
||||||
if (makeDialog && ctx != null)
|
Toast.MakeText(ctx ?? Application.Context, message, ToastLength.Long).Show();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
|
||||||
|
|
||||||
builder.SetMessage(message)
|
|
||||||
.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ((Dialog)sender).Dismiss())
|
|
||||||
.Show();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
Toast.MakeText(ctx, message, ToastLength.Long).Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Toast.MakeText(ctx ?? Application.Context, message, ToastLength.Long).Show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Finish(bool result, String message, bool importantMessage = false, Exception exception = null) {
|
protected void Finish(bool result, String message, Exception exception = null) {
|
||||||
if ( OnFinishToRun != null ) {
|
if ( OnFinishToRun != null ) {
|
||||||
OnFinishToRun.SetResult(result, message, importantMessage, exception);
|
OnFinishToRun.SetResult(result, message, exception);
|
||||||
OnFinishToRun.Run();
|
OnFinishToRun.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
public class SaveDb : RunnableOnFinish {
|
public class SaveDb : RunnableOnFinish {
|
||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
private readonly Database _db;
|
private readonly bool _dontSave;
|
||||||
private readonly bool _dontSave;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
|
/// stream for reading the data from the original file. If this is set to a non-null value, we know we need to sync
|
||||||
@@ -44,10 +43,9 @@ namespace keepass2android
|
|||||||
private readonly Context _ctx;
|
private readonly Context _ctx;
|
||||||
private Thread _workerThread;
|
private Thread _workerThread;
|
||||||
|
|
||||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish, bool dontSave)
|
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave)
|
||||||
: base(ctx, finish)
|
: base(ctx, finish)
|
||||||
{
|
{
|
||||||
_db = db;
|
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_app = app;
|
_app = app;
|
||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
@@ -61,55 +59,46 @@ namespace keepass2android
|
|||||||
/// <param name="finish"></param>
|
/// <param name="finish"></param>
|
||||||
/// <param name="dontSave"></param>
|
/// <param name="dontSave"></param>
|
||||||
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
|
/// <param name="streamForOrigFile">Stream for reading the data from the (changed) original location</param>
|
||||||
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, Database db, bool dontSave, Stream streamForOrigFile)
|
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish, bool dontSave, Stream streamForOrigFile)
|
||||||
: base(ctx, finish)
|
: base(ctx, finish)
|
||||||
{
|
{
|
||||||
_db = db;
|
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_app = app;
|
_app = app;
|
||||||
_dontSave = dontSave;
|
_dontSave = dontSave;
|
||||||
_streamForOrigFile = streamForOrigFile;
|
_streamForOrigFile = streamForOrigFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveDb(Activity ctx, IKp2aApp app, Database db, OnFinish finish)
|
public SaveDb(Activity ctx, IKp2aApp app, OnFinish finish)
|
||||||
: base(ctx, finish)
|
: base(ctx, finish)
|
||||||
{
|
{
|
||||||
_ctx = ctx;
|
_ctx = ctx;
|
||||||
_app = app;
|
_app = app;
|
||||||
_db = db;
|
_dontSave = false;
|
||||||
_dontSave = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowDatabaseIocInStatus { get; set; }
|
|
||||||
|
public override void Run ()
|
||||||
public override void Run ()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!_dontSave)
|
if (!_dontSave)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_db.CanWrite == false)
|
if (_app.GetDb().CanWrite == false)
|
||||||
{
|
{
|
||||||
//this should only happen if there is a problem in the UI so that the user sees an edit interface.
|
//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!");
|
Finish(false,"Cannot save changes. File is read-only!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string message = _app.GetResourceString(UiStringKey.saving_database);
|
StatusLogger.UpdateMessage(UiStringKey.saving_database);
|
||||||
|
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
||||||
if (ShowDatabaseIocInStatus)
|
|
||||||
message += " (" + _app.GetFileStorage(_db.Ioc).GetDisplayName(_db.Ioc) + ")";
|
|
||||||
|
|
||||||
StatusLogger.UpdateMessage(message);
|
|
||||||
|
|
||||||
IOConnectionInfo ioc = _db.Ioc;
|
|
||||||
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
||||||
|
|
||||||
if (_streamForOrigFile == null)
|
if (_streamForOrigFile == null)
|
||||||
{
|
{
|
||||||
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|
if ((!_app.GetBooleanPreference(PreferenceKey.CheckForFileChangesOnSave))
|
||||||
|| (_db.KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
|| (_app.GetDb().KpDatabase.HashOfFileOnDisk == null)) //first time saving
|
||||||
{
|
{
|
||||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
Finish(true);
|
Finish(true);
|
||||||
@@ -120,8 +109,8 @@ namespace keepass2android
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
(_streamForOrigFile != null)
|
(_streamForOrigFile != null)
|
||||||
|| fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) //first try to use the fast change detection
|
|| fileStorage.CheckForFileChangeFast(ioc, _app.GetDb().LastFileVersion) //first try to use the fast change detection
|
||||||
|| (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
|
|| (FileHashChanged(ioc, _app.GetDb().KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -139,7 +128,6 @@ namespace keepass2android
|
|||||||
//small.
|
//small.
|
||||||
MergeIn(fileStorage, ioc);
|
MergeIn(fileStorage, ioc);
|
||||||
PerformSaveWithoutCheck(fileStorage, ioc);
|
PerformSaveWithoutCheck(fileStorage, ioc);
|
||||||
_db.UpdateGlobals();
|
|
||||||
Finish(true);
|
Finish(true);
|
||||||
};
|
};
|
||||||
RunInWorkerThread(runHandler);
|
RunInWorkerThread(runHandler);
|
||||||
@@ -229,13 +217,13 @@ namespace keepass2android
|
|||||||
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.SynchronizingDatabase));
|
||||||
|
|
||||||
PwDatabase pwImp = new PwDatabase();
|
PwDatabase pwImp = new PwDatabase();
|
||||||
PwDatabase pwDatabase = _db.KpDatabase;
|
PwDatabase pwDatabase = _app.GetDb().KpDatabase;
|
||||||
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
|
pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey);
|
||||||
pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
|
pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep();
|
||||||
pwImp.MasterKey = pwDatabase.MasterKey;
|
pwImp.MasterKey = pwDatabase.MasterKey;
|
||||||
var stream = GetStreamForBaseFile(fileStorage, ioc);
|
var stream = GetStreamForBaseFile(fileStorage, ioc);
|
||||||
|
|
||||||
_db.DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null);
|
_app.GetDb().DatabaseFormat.PopulateDatabaseFromStream(pwImp, stream, null);
|
||||||
|
|
||||||
|
|
||||||
pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
|
pwDatabase.MergeIn(pwImp, PwMergeMethod.Synchronize, null);
|
||||||
@@ -261,8 +249,8 @@ namespace keepass2android
|
|||||||
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
|
private void PerformSaveWithoutCheck(IFileStorage fileStorage, IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
StatusLogger.UpdateSubMessage("");
|
StatusLogger.UpdateSubMessage("");
|
||||||
_db.SaveData();
|
_app.GetDb().SaveData();
|
||||||
_db.LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
_app.GetDb().LastFileVersion = fileStorage.GetCurrentFileVersionFast(ioc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] HashOriginalFile(IOConnectionInfo iocFile)
|
public byte[] HashOriginalFile(IOConnectionInfo iocFile)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace keepass2android
|
|||||||
public override void Run ()
|
public override void Run ()
|
||||||
{
|
{
|
||||||
StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
|
StatusLogger.UpdateMessage(UiStringKey.SettingPassword);
|
||||||
PwDatabase pm = _app.CurrentDb.KpDatabase;
|
PwDatabase pm = _app.GetDb().KpDatabase;
|
||||||
CompositeKey newKey = new CompositeKey ();
|
CompositeKey newKey = new CompositeKey ();
|
||||||
if (String.IsNullOrEmpty (_password) == false) {
|
if (String.IsNullOrEmpty (_password) == false) {
|
||||||
newKey.AddUserKey (new KcpPassword (_password));
|
newKey.AddUserKey (new KcpPassword (_password));
|
||||||
@@ -74,7 +74,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
// Save Database
|
// Save Database
|
||||||
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
_onFinishToRun = new AfterSave(ActiveActivity, previousKey, previousMasterKeyChanged, pm, OnFinishToRun);
|
||||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun, _dontSave);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun, _dontSave);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
public override void Run() {
|
public override void Run() {
|
||||||
// Commit to disk
|
// Commit to disk
|
||||||
SaveDb save = new SaveDb(_ctx, _app, _app.CurrentDb, OnFinishToRun);
|
SaveDb save = new SaveDb(_ctx, _app, OnFinishToRun);
|
||||||
save.SetStatusLogger(StatusLogger);
|
save.SetStatusLogger(StatusLogger);
|
||||||
save.Run();
|
save.Run();
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ namespace keepass2android
|
|||||||
if ( parent != null ) {
|
if ( parent != null ) {
|
||||||
|
|
||||||
// Mark parent group dirty
|
// Mark parent group dirty
|
||||||
_app.DirtyGroups.Add(parent);
|
_app.GetDb().Dirty.Add(parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,6 @@
|
|||||||
<TransformFile Include="Transforms\EnumMethods.xml" />
|
<TransformFile Include="Transforms\EnumMethods.xml" />
|
||||||
<TransformFile Include="Transforms\Metadata.xml" />
|
<TransformFile Include="Transforms\Metadata.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
|
<ItemGroup />
|
||||||
<ItemGroup>
|
<Import Project="$(MSBuildExtensionsPath)\Novell\Xamarin.Android.Bindings.targets" />
|
||||||
<Folder Include="libs\" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
Additions allow you to add arbitrary C# to the generated classes
|
|
||||||
before they are compiled. This can be helpful for providing convenience
|
|
||||||
methods or adding pure C# classes.
|
|
||||||
|
|
||||||
== Adding Methods to Generated Classes ==
|
|
||||||
|
|
||||||
Let's say the library being bound has a Rectangle class with a constructor
|
|
||||||
that takes an x and y position, and a width and length size. It will look like
|
|
||||||
this:
|
|
||||||
|
|
||||||
public partial class Rectangle
|
|
||||||
{
|
|
||||||
public Rectangle (int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
// JNI bindings
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Imagine we want to add a constructor to this class that takes a Point and
|
|
||||||
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
|
|
||||||
with a partial class containing our new method:
|
|
||||||
|
|
||||||
public partial class Rectangle
|
|
||||||
{
|
|
||||||
public Rectangle (Point location, Size size) :
|
|
||||||
this (location.X, location.Y, size.Width, size.Height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
At compile time, the additions class will be added to the generated class
|
|
||||||
and the final assembly will a Rectangle class with both constructors.
|
|
||||||
|
|
||||||
|
|
||||||
== Adding C# Classes ==
|
|
||||||
|
|
||||||
Another thing that can be done is adding fully C# managed classes to the
|
|
||||||
generated library. In the above example, let's assume that there isn't a
|
|
||||||
Point class available in Java or our library. The one we create doesn't need
|
|
||||||
to interact with Java, so we'll create it like a normal class in C#.
|
|
||||||
|
|
||||||
By adding a Point.cs file with this class, it will end up in the binding library:
|
|
||||||
|
|
||||||
public class Point
|
|
||||||
{
|
|
||||||
public int X { get; set; }
|
|
||||||
public int Y { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
This directory is for Android .jars.
|
|
||||||
|
|
||||||
There are 2 types of jars that are supported:
|
|
||||||
|
|
||||||
== Input Jar ==
|
|
||||||
|
|
||||||
This is the jar that bindings should be generated for.
|
|
||||||
|
|
||||||
For example, if you were binding the Google Maps library, this would
|
|
||||||
be Google's "maps.jar".
|
|
||||||
|
|
||||||
Set the build action for these jars in the properties page to "InputJar".
|
|
||||||
|
|
||||||
|
|
||||||
== Reference Jars ==
|
|
||||||
|
|
||||||
These are jars that are referenced by the input jar. C# bindings will
|
|
||||||
not be created for these jars. These jars will be used to resolve
|
|
||||||
types used by the input jar.
|
|
||||||
|
|
||||||
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
|
|
||||||
based on the Target Framework selected.
|
|
||||||
|
|
||||||
Set the build action for these jars in the properties page to "ReferenceJar".
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,90 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}</ProjectGuid>
|
|
||||||
|
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>PCloudBindings</RootNamespace>
|
|
||||||
<AssemblyName>PCouldBindings</AssemblyName>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
|
|
||||||
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>0</WarningLevel>
|
|
||||||
|
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'">
|
|
||||||
<OutputPath>bin\ReleaseNoNet\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Mono.Android" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<None Include="Jars\AboutJars.txt" />
|
|
||||||
<None Include="Additions\AboutAdditions.txt" />
|
|
||||||
<LibraryProjectZip Include="Jars\pcloud-sdk-android-1.0.1.aar" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<TransformFile Include="Transforms\Metadata.xml" />
|
|
||||||
<TransformFile Include="Transforms\EnumFields.xml" />
|
|
||||||
<TransformFile Include="Transforms\EnumMethods.xml" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.0.1.jar" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Android.App;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("PCloudBindings")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("PCloudBindings")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2013")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<enum-field-mappings>
|
|
||||||
<!--
|
|
||||||
This example converts the constants Fragment_id, Fragment_name,
|
|
||||||
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
|
|
||||||
to an enum called Android.Support.V4.App.FragmentTagType with values
|
|
||||||
Id, Name, and Tag.
|
|
||||||
|
|
||||||
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
|
|
||||||
<field jni-name="Fragment_name" clr-name="Name" value="0" />
|
|
||||||
<field jni-name="Fragment_id" clr-name="Id" value="1" />
|
|
||||||
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
|
|
||||||
</mapping>
|
|
||||||
-->
|
|
||||||
</enum-field-mappings>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<enum-method-mappings>
|
|
||||||
<!--
|
|
||||||
This example changes the Java method:
|
|
||||||
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
|
|
||||||
to be:
|
|
||||||
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
|
|
||||||
when bound in C#.
|
|
||||||
|
|
||||||
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
|
|
||||||
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
|
|
||||||
</mapping>
|
|
||||||
-->
|
|
||||||
</enum-method-mappings>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<metadata>
|
|
||||||
<!--
|
|
||||||
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
|
|
||||||
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
|
|
||||||
|
|
||||||
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
|
|
||||||
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
|
|
||||||
-->
|
|
||||||
<remove-node path="/api/package[@name='com.pcloud.sdk']" />
|
|
||||||
</metadata>
|
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\Keepass2AndroidPluginSDK2-release.aar">
|
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
|
||||||
<Link>Jars\Keepass2AndroidPluginSDK2-release.aar</Link>
|
<Link>Jars\app-release.aar</Link>
|
||||||
</LibraryProjectZip>
|
</LibraryProjectZip>
|
||||||
<None Include="Jars\AboutJars.txt" />
|
<None Include="Jars\AboutJars.txt" />
|
||||||
<None Include="Additions\AboutAdditions.txt" />
|
<None Include="Additions\AboutAdditions.txt" />
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo '*****************************************'
|
|
||||||
echo '********** Building Java parts **********'
|
|
||||||
echo '*****************************************'
|
|
||||||
./build-java.sh
|
|
||||||
|
|
||||||
echo '*****************************************'
|
|
||||||
echo '******** Building Xamarin parts *********'
|
|
||||||
echo '*****************************************'
|
|
||||||
./build-xamarin.sh
|
|
||||||
|
|
||||||
echo '*****************************************'
|
|
||||||
echo '************** Building APK *************'
|
|
||||||
echo '*****************************************'
|
|
||||||
./build-apk.sh
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo 'Congratulations! You you can find the target APK in src/keepass2android/bin/Debug/.'
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
pushd ../keepass2android
|
|
||||||
|
|
||||||
xabuild keepass2android.csproj /t:SignAndroidPackage "$@"
|
|
||||||
|
|
||||||
popd
|
|
||||||
@@ -7,7 +7,4 @@ call gradlew assemble
|
|||||||
cd ..\Keepass2AndroidPluginSDK2
|
cd ..\Keepass2AndroidPluginSDK2
|
||||||
call gradlew assemble
|
call gradlew assemble
|
||||||
|
|
||||||
cd ..\PluginQR
|
cd ..\..\build-scripts
|
||||||
call gradlew assemble
|
|
||||||
|
|
||||||
cd ..\..\build-scripts
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
pushd ../java/
|
|
||||||
|
|
||||||
pushd JavaFileStorageTest-AS
|
|
||||||
./gradlew assemble
|
|
||||||
popd
|
|
||||||
|
|
||||||
pushd KP2ASoftkeyboard_AS
|
|
||||||
./gradlew assemble
|
|
||||||
popd
|
|
||||||
|
|
||||||
pushd Keepass2AndroidPluginSDK2
|
|
||||||
./gradlew assemble
|
|
||||||
popd
|
|
||||||
|
|
||||||
pushd PluginQR
|
|
||||||
./gradlew assemble
|
|
||||||
popd
|
|
||||||
|
|
||||||
popd
|
|
||||||
@@ -6,11 +6,11 @@ if exist "DropboxFileStorageKeys.cs" (
|
|||||||
)
|
)
|
||||||
|
|
||||||
cd ..\..\keepass2android
|
cd ..\..\keepass2android
|
||||||
call UseManifestDebug.bat
|
call UseManifestNoNet.bat
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
|
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
|
||||||
|
|
||||||
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Debug" /p:Platform="Any CPU"
|
msbuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Release" /p:Platform="Any CPU"
|
||||||
|
|
||||||
cd build-scripts
|
cd build-scripts
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
pushd ..
|
|
||||||
|
|
||||||
pushd Kp2aBusinessLogic/Io
|
|
||||||
|
|
||||||
if [ -f "DropboxFileStorageKeys.cs" ]
|
|
||||||
then
|
|
||||||
echo "DropboxFileStorageKeys.cs found."
|
|
||||||
else
|
|
||||||
cp DropboxFileStorageKeysDummy.cs DropboxFileStorageKeys.cs
|
|
||||||
fi
|
|
||||||
|
|
||||||
popd
|
|
||||||
|
|
||||||
pushd keepass2android
|
|
||||||
./UseManifestDebug.sh
|
|
||||||
popd
|
|
||||||
|
|
||||||
# call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64
|
|
||||||
|
|
||||||
xabuild KeePass.sln /target:keepass2android /p:BuildProjectReferences=true /p:Configuration="Debug" /p:Platform="Any CPU" "$@"
|
|
||||||
|
|
||||||
popd
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# How to build Keepass2Android
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Keepass2Android is a Mono for Android app. This means that you need Xamarin's Mono for Android to build it. However, it also uses several components written in Java, so there are also Android-Studio projects involved. To make things even worse, parts of the keyboard and kdb-library are written in native code.
|
|
||||||
The current build-scripts assume that the native libraries are already built (they are included in the repo).
|
|
||||||
|
|
||||||
To build KP2A from scratch, make sure that you have Xamarin's Mono for Android installed and also install Android Studio. Make sure that both point to the same Android SDK location.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Install Xamarin.Android
|
|
||||||
- Fetch all submodules (`git submodule init && git submodule update`)
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
### On Windows
|
|
||||||
|
|
||||||
```bat
|
|
||||||
cd build-scripts
|
|
||||||
build-java.bat
|
|
||||||
build-xamarin.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
build-java.bat will call gradlew for several Java modules. build-xamarin.bat will first make sure that you have all files at their place. (There is a "secret" file for Dropbox SDK keys which is not in the repo, this is replaced with a dummy file. There are also different Android Manifest files depending on the configuration which is selected by calling the appropriate script.)
|
|
||||||
|
|
||||||
**Notes:**
|
|
||||||
|
|
||||||
- For building the java parts, it is suggested to keep a short name (e.g. "c:\projects\keepass2android") for the root project directory. Otherwise the Windows path length limit might be hit when building.
|
|
||||||
- Before building the java parts, make sure you have set the ANDROID_HOME variable or create a local.properties file inside the directories with a gradlew file. It is recommended to use the same SDK location as that of the Xamarin build.
|
|
||||||
|
|
||||||
### On Linux
|
|
||||||
|
|
||||||
- Install [Mono](https://www.mono-project.com/)
|
|
||||||
- Install Xamarin.Android
|
|
||||||
- Option 1: Use the mono-project [CI builds](https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-linux/lastSuccessfulBuild/Azure/)
|
|
||||||
- Option 2: [Build it from source](https://github.com/xamarin/xamarin-android/blob/master/Documentation/README.md#building-from-source)
|
|
||||||
- Setup your environment:
|
|
||||||
- Add `xabuild` to your path: `export PATH=/path/to/xamarin.android-oss/bin/Release/bin/:$PATH`
|
|
||||||
- Setup your `ANDROID_HOME` if it's not already: `export ANDROID_HOME=/path/to/android/`
|
|
||||||
- Alternatively, you can set your `ANDROID_SDK_PATH` and `ANDROID_NDK_PATH`.
|
|
||||||
- Build [jar2xml](https://github.com/xamarin/jar2xml) and copy `jar2xml.jar` to `/path/to/xamarin.android-oss/bin/Release/lib/xamarin.android/xbuild/Xamarin/Android/`
|
|
||||||
- Install [libzip](https://libzip.org/) for your distribution.
|
|
||||||
- Note: Xamarin seems to require `libzip4`, yet most distributions only ships `libzip5`. As a dirty workaround, it's possible to symlink `libzip.so.5` to `libzip.so.4`. Luckily, it appears to be working.
|
|
||||||
- `sudo ln -s /usr/lib/libzip.so.5 /usr/lib/libzip.so.4`
|
|
||||||
- Install NuGet dependencies:
|
|
||||||
- `cd src/ && nuget restore KeePass.sln`
|
|
||||||
- Build:
|
|
||||||
- Option 1: `cd build-scripts && ./build-all.sh`
|
|
||||||
- Option 2:
|
|
||||||
- Build the Java parts: `cd build-scripts/ && ./build-java.sh`
|
|
||||||
- Build the Xamarin parts: `./build-xamarin.sh`
|
|
||||||
- Build the signed APK: `./build-apk.sh`
|
|
||||||
- Enjoy:
|
|
||||||
- `adb install ../keepass2android/bin/Debug/keepass2android.keepass2android_debug-Signed.apk`
|
|
||||||
23
src/build.readme.txt
Normal file
23
src/build.readme.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
How to build Keepass2Android
|
||||||
|
|
||||||
|
* Overview *
|
||||||
|
Keepass2Android is a Mono for Android app. This means that you need Xamarin's Mono for Android to build it. However, it also uses several components written in Java, so there are also Android-Studio projects involved. To make things even worse, parts of the keyboard and kdb-library are written in native code.
|
||||||
|
The current build-scripts assume that the native libraries are already built (they are included in the repo).
|
||||||
|
|
||||||
|
To build KP2A from scratch, make sure that you have Xamarin's Mono for Android installed and also install Android Studio. Make sure that both point to the same Android SDK location.
|
||||||
|
|
||||||
|
On Windows you can use
|
||||||
|
|
||||||
|
cd build-scripts
|
||||||
|
build-java.bat
|
||||||
|
build-xamarin.bat
|
||||||
|
|
||||||
|
build-java.bat will call gradlew for several Java modules. build-xamarin.bat will first make sure that you have all files at their place. (There is a "secret" file for Dropbox SDK keys which is not in the repo, this is replaced with a dummy file. There are also different Android Manifest files depending on the configuration which is selected by calling the appropriate script.)
|
||||||
|
|
||||||
|
|
||||||
|
* Notes *
|
||||||
|
- Please don't forget to update the git submodules before building.
|
||||||
|
- For building the java parts on Windows, it is suggested to keep a short name (e.g. "c:\projects\keepass2android") for the root project directory. Otherwise the Windows path length limit might be hit when building.
|
||||||
|
- Before building the java parts, make sure you have set the ANDROID_HOME variable or create a local.properties file inside the directories with a gradlew file. It is recommended to use the same SDK location as that of the Xamarin build.
|
||||||
|
|
||||||
|
|
||||||
@@ -35,12 +35,6 @@ dependencies {
|
|||||||
compile('com.onedrive.sdk:onedrive-sdk-android:1.2.0') {
|
compile('com.onedrive.sdk:onedrive-sdk-android:1.2.0') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
compile 'com.pcloud.sdk:java-core:1.0.1'
|
|
||||||
compile 'com.pcloud.sdk:android:1.0.1'
|
|
||||||
compile('com.microsoft.graph:msgraph-sdk-android:1.2.+')
|
|
||||||
compile ('com.microsoft.identity.client:msal:0.1.+') {
|
|
||||||
exclude group: 'com.android.support', module: 'appcompat-v7'
|
|
||||||
}
|
|
||||||
compile 'com.google.code.gson:gson:2.3.1'
|
compile 'com.google.code.gson:gson:2.3.1'
|
||||||
compile 'com.microsoft.services.msa:msa-auth:0.8.6'
|
compile 'com.microsoft.services.msa:msa-auth:0.8.6'
|
||||||
compile 'com.microsoft.aad:adal:1.14.0'
|
compile 'com.microsoft.aad:adal:1.14.0'
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="keepass2android.javafilestorage"
|
package="keepass2android.javafilestorage"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="1.0">
|
android:versionName="1.0">
|
||||||
|
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="8"
|
android:minSdkVersion="8"
|
||||||
android:targetSdkVersion="14" />
|
android:targetSdkVersion="14" />
|
||||||
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
<application>
|
|
||||||
<activity
|
|
||||||
android:name=".NotifSlave"
|
|
||||||
android:label="Keepass2Android"></activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
|
|||||||
@@ -190,14 +190,12 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
|
|||||||
String part = parts[parts.length-1];
|
String part = parts[parts.length-1];
|
||||||
logDebug("parsing part " + part);
|
logDebug("parsing part " + part);
|
||||||
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
int indexOfSeparator = part.lastIndexOf(NAME_ID_SEP);
|
||||||
String name = "";
|
|
||||||
if (indexOfSeparator < 0)
|
if (indexOfSeparator < 0)
|
||||||
{
|
{
|
||||||
//seems invalid, but we're very generous here
|
//seems invalid, but we're very generous here
|
||||||
displayName += "/"+part;
|
displayName += "/"+part;
|
||||||
}
|
}
|
||||||
else
|
String name = part.substring(0, indexOfSeparator);
|
||||||
name = part.substring(0, indexOfSeparator);
|
|
||||||
try {
|
try {
|
||||||
name = decode(name);
|
name = decode(name);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ public class FileEntry {
|
|||||||
|
|
||||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
|
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception;
|
||||||
|
|
||||||
public String getCurrentFileVersionFast(String path) throws Exception;
|
public String getCurrentFileVersionFast(String path);
|
||||||
|
|
||||||
public InputStream openFileForRead(String path) throws Exception;
|
public InputStream openFileForRead(String path) throws Exception;
|
||||||
|
|
||||||
@@ -157,4 +157,4 @@ public class FileEntry {
|
|||||||
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data);
|
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data);
|
||||||
public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults);
|
public void onRequestPermissionsResult(FileStorageSetupActivity activity, int requestCode, String[] permissions, int[] grantResults);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
package keepass2android.javafilestorage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
//based on https://github.com/jwise/dumload/blob/master/src/com/joshuawise/dumload/NotifSlave.java
|
|
||||||
public class NotifSlave extends Activity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void say(String s) {
|
|
||||||
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _nextdialog = 0;
|
|
||||||
private Dialog dialog = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id)
|
|
||||||
{
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Create for dialog "+(Integer.toString(id)));
|
|
||||||
if (id != _nextdialog)
|
|
||||||
return null;
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDialog(Dialog d)
|
|
||||||
{
|
|
||||||
_nextdialog++;
|
|
||||||
dialog = d;
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Attempting to show dialog "+(Integer.toString(_nextdialog)));
|
|
||||||
showDialog(_nextdialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
Intent i = getIntent(); /* i *am* not an intent! */
|
|
||||||
final Activity thisact = this;
|
|
||||||
|
|
||||||
final Messenger m = (Messenger)i.getParcelableExtra("keepass2android.sftp.returnmessenger");
|
|
||||||
String reqtype = i.getStringExtra("keepass2android.sftp.reqtype");
|
|
||||||
String prompt = i.getStringExtra("keepass2android.sftp.prompt");
|
|
||||||
|
|
||||||
if (prompt == null || reqtype == null || m == null) /* i.e., we got called by a dummy notification */
|
|
||||||
{
|
|
||||||
this.finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reqtype.equals("yesno")) {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle("Keepass2Android");
|
|
||||||
builder.setMessage(prompt);
|
|
||||||
builder.setCancelable(false);
|
|
||||||
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Responding with a 1.");
|
|
||||||
try {
|
|
||||||
Message me = Message.obtain();
|
|
||||||
me.arg1 = 1;
|
|
||||||
m.send(me);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy.");
|
|
||||||
}
|
|
||||||
dialog.cancel();
|
|
||||||
thisact.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Responding with a 1.");
|
|
||||||
try {
|
|
||||||
Message me = Message.obtain();
|
|
||||||
me.arg1 = 0;
|
|
||||||
m.send(me);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy.");
|
|
||||||
}
|
|
||||||
dialog.cancel();
|
|
||||||
thisact.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
AlertDialog alert = builder.create();
|
|
||||||
showDialog(alert);
|
|
||||||
} else if (reqtype.equals("message")) {
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle("Keepass2Android");
|
|
||||||
builder.setMessage(prompt);
|
|
||||||
builder.setCancelable(false);
|
|
||||||
builder.setNeutralButton("OK", new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
try {
|
|
||||||
Message me = Message.obtain();
|
|
||||||
m.send(me);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy.");
|
|
||||||
}
|
|
||||||
dialog.cancel();
|
|
||||||
thisact.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
AlertDialog alert = builder.create();
|
|
||||||
showDialog(alert);
|
|
||||||
} /*else if (reqtype.equals("password")) {
|
|
||||||
final Dialog d = new Dialog(this);
|
|
||||||
|
|
||||||
d.setContentView(R.layout.notfif_slave);
|
|
||||||
d.setTitle("Keepass2Android");
|
|
||||||
d.setCancelable(false);
|
|
||||||
|
|
||||||
TextView text = (TextView) d.findViewById(R.id.prompt);
|
|
||||||
text.setText(prompt);
|
|
||||||
|
|
||||||
Button ok = (Button) d.findViewById(R.id.ok);
|
|
||||||
ok.setOnClickListener(new View.OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
try {
|
|
||||||
Message me = Message.obtain();
|
|
||||||
me.arg1 = 1;
|
|
||||||
TextView entry = (TextView) d.findViewById(R.id.entry);
|
|
||||||
Bundle b = new Bundle(1);
|
|
||||||
b.putString("response", entry.getText().toString());
|
|
||||||
me.setData(b);
|
|
||||||
m.send(me);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy.");
|
|
||||||
}
|
|
||||||
d.cancel();
|
|
||||||
thisact.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Button cancel = (Button) d.findViewById(R.id.cancel);
|
|
||||||
cancel.setOnClickListener(new View.OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
try {
|
|
||||||
Message me = Message.obtain();
|
|
||||||
me.arg1 = 0;
|
|
||||||
m.send(me);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "Failed to send a message back to my buddy.");
|
|
||||||
}
|
|
||||||
d.cancel();
|
|
||||||
thisact.finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
showDialog(d);
|
|
||||||
} */else {
|
|
||||||
Log.e("KP2AJ.NotifSlave", "What's a "+reqtype+"?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,486 +0,0 @@
|
|||||||
package keepass2android.javafilestorage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
|
||||||
import com.microsoft.graph.core.ClientException;
|
|
||||||
import com.microsoft.graph.core.DefaultClientConfig;
|
|
||||||
import com.microsoft.graph.core.GraphErrorCodes;
|
|
||||||
import com.microsoft.graph.extensions.DriveItem;
|
|
||||||
import com.microsoft.graph.extensions.GraphServiceClient;
|
|
||||||
import com.microsoft.graph.extensions.IDriveItemCollectionPage;
|
|
||||||
import com.microsoft.graph.extensions.IDriveItemCollectionRequestBuilder;
|
|
||||||
import com.microsoft.graph.extensions.IDriveItemRequest;
|
|
||||||
import com.microsoft.graph.extensions.IDriveItemRequestBuilder;
|
|
||||||
import com.microsoft.graph.extensions.IGraphServiceClient;
|
|
||||||
import com.microsoft.identity.client.AuthenticationCallback;
|
|
||||||
import com.microsoft.identity.client.AuthenticationResult;
|
|
||||||
import com.microsoft.identity.client.MsalException;
|
|
||||||
import com.microsoft.identity.client.PublicClientApplication;
|
|
||||||
import com.microsoft.identity.client.User;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
import keepass2android.javafilestorage.onedrive2.GraphServiceClientManager;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Philipp on 20.11.2016.
|
|
||||||
*/
|
|
||||||
public class OneDriveStorage2 extends JavaFileStorageBase
|
|
||||||
{
|
|
||||||
PublicClientApplication mPublicClientApp;
|
|
||||||
|
|
||||||
final HashMap<String /*userid*/, IGraphServiceClient> mClientByUser = new HashMap<String /*userid*/, IGraphServiceClient>();
|
|
||||||
|
|
||||||
private static final String[] scopes = {"openid","offline_access", "https://graph.microsoft.com/Files.ReadWrite","https://graph.microsoft.com/User.Read"};
|
|
||||||
|
|
||||||
|
|
||||||
public OneDriveStorage2(final Activity context, final String clientId) {
|
|
||||||
|
|
||||||
mPublicClientApp = new PublicClientApplication(context, clientId);
|
|
||||||
initAuthenticator(context);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean requiresSetup(String path)
|
|
||||||
{
|
|
||||||
|
|
||||||
return !isConnected(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave, int requestCode) {
|
|
||||||
|
|
||||||
initAuthenticator((Activity)activity.getActivity());
|
|
||||||
|
|
||||||
String path = getProtocolId()+":///";
|
|
||||||
Log.d("KP2AJ", "startSelectFile "+path+", connected: "+path);
|
|
||||||
if (isConnected(null))
|
|
||||||
{
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_IS_FOR_SAVE, isForSave);
|
|
||||||
intent.putExtra(EXTRA_PATH, path);
|
|
||||||
activity.onImmediateResult(requestCode, RESULT_FILECHOOSER_PREPARED, intent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
activity.startSelectFileProcess(path, isForSave, requestCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConnected(String path) {
|
|
||||||
try {
|
|
||||||
if (tryGetMsGraphClient(path) == null)
|
|
||||||
try {
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
Log.d("KP2AJ", "trying silent login");
|
|
||||||
|
|
||||||
String userId = extractUserId(path);
|
|
||||||
final MsalException[] _exception = {null};
|
|
||||||
final AuthenticationResult[] _result = {null};
|
|
||||||
User user = mPublicClientApp.getUser(userId);
|
|
||||||
mPublicClientApp.acquireTokenSilentAsync(scopes, user,
|
|
||||||
new AuthenticationCallback() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccess(AuthenticationResult authenticationResult) {
|
|
||||||
_result[0] = authenticationResult;
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(MsalException exception) {
|
|
||||||
_exception[0] = exception;
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel() {
|
|
||||||
latch.countDown();
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
latch.await();
|
|
||||||
if (_result[0] != null) {
|
|
||||||
buildClient(_result[0]);
|
|
||||||
} else if (_exception[0] != null){
|
|
||||||
_exception[0].printStackTrace();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return tryGetMsGraphClient(path) != null;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private IGraphServiceClient tryGetMsGraphClient(String path) throws Exception
|
|
||||||
{
|
|
||||||
String userId = extractUserId(path);
|
|
||||||
if (mClientByUser.containsKey(userId))
|
|
||||||
return mClientByUser.get(userId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractUserId(String path) throws Exception {
|
|
||||||
String pathWithoutProtocol = removeProtocol(path);
|
|
||||||
String[] parts = pathWithoutProtocol.split("/",1);
|
|
||||||
if (parts.length != 2 || ("".equals(parts[0])))
|
|
||||||
{
|
|
||||||
throw new Exception("path does not contain user");
|
|
||||||
}
|
|
||||||
return parts[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initAuthenticator(Activity activity) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode, boolean alwaysReturnSuccess) {
|
|
||||||
initAuthenticator((Activity)activity.getActivity());
|
|
||||||
if (isConnected(path))
|
|
||||||
{
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_PATH, path);
|
|
||||||
activity.onImmediateResult(requestCode, RESULT_FILEUSAGE_PREPARED, intent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
activity.startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProtocolId() {
|
|
||||||
return "onedrive";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareFileUsage(Context appContext, String path) throws UserInteractionRequiredException {
|
|
||||||
if (!isConnected(null))
|
|
||||||
{
|
|
||||||
throw new UserInteractionRequiredException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
Log.d("KP2AJ", "OnCreate");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume(final FileStorageSetupActivity activity) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private IGraphServiceClient buildClient(AuthenticationResult authenticationResult) throws InterruptedException {
|
|
||||||
|
|
||||||
IGraphServiceClient newClient = new GraphServiceClient.Builder()
|
|
||||||
.fromConfig(DefaultClientConfig.createWithAuthenticationProvider(new GraphServiceClientManager(authenticationResult.getAccessToken())))
|
|
||||||
.buildClient();
|
|
||||||
mClientByUser.put(authenticationResult.getUser().getUserIdentifier(), newClient);
|
|
||||||
|
|
||||||
return newClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String removeProtocol(String path) throws Exception {
|
|
||||||
if (path == null)
|
|
||||||
return null;
|
|
||||||
return path.substring(getProtocolId().length()+3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayName(String path) {
|
|
||||||
|
|
||||||
if (path == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilename(String path) throws Exception {
|
|
||||||
return path.substring(path.lastIndexOf("/")+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCurrentFileVersionFast(String path) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientAndPath
|
|
||||||
{
|
|
||||||
public IGraphServiceClient client;
|
|
||||||
public String oneDrivePath;
|
|
||||||
public IDriveItemRequestBuilder getPathItem()
|
|
||||||
{
|
|
||||||
IDriveItemRequestBuilder pathItem = client.getDrive().getRoot();
|
|
||||||
if ("".equals(oneDrivePath) == false) {
|
|
||||||
pathItem = pathItem.getItemWithPath(oneDrivePath);
|
|
||||||
}
|
|
||||||
return pathItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream openFileForRead(String path) throws Exception {
|
|
||||||
try {
|
|
||||||
ClientAndPath clientAndpath = getOneDriveClientAndPath(path);
|
|
||||||
logDebug("openFileForRead. Path="+path);
|
|
||||||
InputStream result = clientAndpath.client.getDrive()
|
|
||||||
.getRoot()
|
|
||||||
.getItemWithPath(clientAndpath.oneDrivePath)
|
|
||||||
.getContent()
|
|
||||||
.buildRequest()
|
|
||||||
.get();
|
|
||||||
logDebug("ok");
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (ClientException e)
|
|
||||||
{
|
|
||||||
throw convertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClientAndPath getOneDriveClientAndPath(String path) throws Exception {
|
|
||||||
ClientAndPath result = new ClientAndPath();
|
|
||||||
|
|
||||||
String pathWithoutProtocol = removeProtocol(path);
|
|
||||||
String[] parts = pathWithoutProtocol.split("/",2);
|
|
||||||
if (parts.length != 2 || ("".equals(parts[0])))
|
|
||||||
{
|
|
||||||
throw new Exception("path does not contain user");
|
|
||||||
}
|
|
||||||
result.client = mClientByUser.get(parts[0]);
|
|
||||||
result.oneDrivePath = parts[1];
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Exception convertException(ClientException e) {
|
|
||||||
if (e.isError(GraphErrorCodes.ItemNotFound))
|
|
||||||
return new FileNotFoundException(e.getMessage());
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception {
|
|
||||||
try {
|
|
||||||
ClientAndPath clientAndPath = getOneDriveClientAndPath(path);
|
|
||||||
clientAndPath.client.getDrive()
|
|
||||||
.getRoot()
|
|
||||||
.getItemWithPath(clientAndPath.oneDrivePath)
|
|
||||||
.getContent()
|
|
||||||
.buildRequest()
|
|
||||||
.put(data);
|
|
||||||
} catch (ClientException e) {
|
|
||||||
throw convertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createFolder(String parentPath, String newDirName) throws Exception {
|
|
||||||
throw new Exception("not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createFilePath(String parentPath, String newFileName) throws Exception {
|
|
||||||
String path = parentPath;
|
|
||||||
if (!path.endsWith("/"))
|
|
||||||
path = path + "/";
|
|
||||||
path = path + newFileName;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
|
||||||
try {
|
|
||||||
ArrayList<FileEntry> result = new ArrayList<FileEntry>();
|
|
||||||
ClientAndPath clientAndPath = getOneDriveClientAndPath(parentPath);
|
|
||||||
parentPath = clientAndPath.oneDrivePath;
|
|
||||||
|
|
||||||
IDriveItemCollectionPage itemsPage = clientAndPath.getPathItem()
|
|
||||||
.getChildren()
|
|
||||||
.buildRequest()
|
|
||||||
.get();
|
|
||||||
if (parentPath.endsWith("/"))
|
|
||||||
parentPath = parentPath.substring(0,parentPath.length()-1);
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
List<DriveItem> items = itemsPage.getCurrentPage();
|
|
||||||
if (items.isEmpty())
|
|
||||||
return result;
|
|
||||||
|
|
||||||
for (DriveItem i: items)
|
|
||||||
{
|
|
||||||
FileEntry e = getFileEntry(parentPath + "/" + i.name, i);
|
|
||||||
Log.d("KP2AJ", e.path);
|
|
||||||
result.add(e);
|
|
||||||
}
|
|
||||||
IDriveItemCollectionRequestBuilder nextPageReqBuilder = itemsPage.getNextPage();
|
|
||||||
if (nextPageReqBuilder == null)
|
|
||||||
return result;
|
|
||||||
itemsPage = nextPageReqBuilder.buildRequest().get();
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (ClientException e) {
|
|
||||||
throw convertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileEntry getFileEntry(String path, DriveItem i) {
|
|
||||||
FileEntry e = new FileEntry();
|
|
||||||
if (i.size != null)
|
|
||||||
e.sizeInBytes = i.size;
|
|
||||||
else if ((i.remoteItem != null) && (i.remoteItem.size != null))
|
|
||||||
e.sizeInBytes = i.remoteItem.size;
|
|
||||||
|
|
||||||
e.displayName = i.name;
|
|
||||||
e.canRead = e.canWrite = true;
|
|
||||||
e.path = getProtocolId() +"://"+path;
|
|
||||||
if (i.lastModifiedDateTime != null)
|
|
||||||
e.lastModifiedTime = i.lastModifiedDateTime.getTimeInMillis();
|
|
||||||
else if ((i.remoteItem != null)&&(i.remoteItem.lastModifiedDateTime != null))
|
|
||||||
e.lastModifiedTime = i.remoteItem.lastModifiedDateTime.getTimeInMillis();
|
|
||||||
e.isDirectory = (i.folder != null) || ((i.remoteItem != null) && (i.remoteItem.folder != null));
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileEntry getFileEntry(String filename) throws Exception {
|
|
||||||
try {
|
|
||||||
|
|
||||||
ClientAndPath clientAndPath = getOneDriveClientAndPath(filename);
|
|
||||||
IDriveItemRequestBuilder pathItem = clientAndPath.getPathItem();
|
|
||||||
|
|
||||||
IDriveItemRequest request = pathItem.buildRequest();
|
|
||||||
DriveItem item = request.get();
|
|
||||||
return getFileEntry(filename, item);
|
|
||||||
} catch (ClientException e) {
|
|
||||||
throw convertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String path) throws Exception {
|
|
||||||
try {
|
|
||||||
ClientAndPath clientAndPath = getOneDriveClientAndPath(path);
|
|
||||||
clientAndPath.client.getDrive()
|
|
||||||
.getRoot()
|
|
||||||
.getItemWithPath(clientAndPath.oneDrivePath)
|
|
||||||
.buildRequest()
|
|
||||||
.delete();
|
|
||||||
} catch (ClientException e) {
|
|
||||||
throw convertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean acquireTokenRunning = false;
|
|
||||||
@Override
|
|
||||||
public void onStart(final FileStorageSetupActivity activity) {
|
|
||||||
Log.d("KP2AJ", "onStart " + activity.getPath());
|
|
||||||
if (activity.getProcessName().equals(PROCESS_NAME_SELECTFILE))
|
|
||||||
activity.getState().putString(EXTRA_PATH, activity.getPath());
|
|
||||||
|
|
||||||
String userId = activity.getState().getString("OneDriveUser");
|
|
||||||
if (mClientByUser.containsKey(userId)) {
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JavaFileStorage.FileStorageSetupActivity storageSetupAct = activity;
|
|
||||||
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
final AuthenticationResult[] _authenticationResult = {null};
|
|
||||||
MsalException _exception[] = {null};
|
|
||||||
|
|
||||||
if (!acquireTokenRunning) {
|
|
||||||
acquireTokenRunning = true;
|
|
||||||
|
|
||||||
mPublicClientApp.acquireToken((Activity) activity, scopes, new AuthenticationCallback() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(AuthenticationResult authenticationResult) {
|
|
||||||
Log.i(TAG, "authenticating successful");
|
|
||||||
|
|
||||||
try {
|
|
||||||
buildClient(authenticationResult);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
activity.getState().putString(EXTRA_PATH, getProtocolPrefix() + authenticationResult.getUser().getUserIdentifier() + "/");
|
|
||||||
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
acquireTokenRunning = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(MsalException exception) {
|
|
||||||
Log.i(TAG, "authenticating not successful");
|
|
||||||
Intent data = new Intent();
|
|
||||||
data.putExtra(EXTRA_ERROR_MESSAGE, "authenticating not successful");
|
|
||||||
((Activity) activity).setResult(Activity.RESULT_CANCELED, data);
|
|
||||||
((Activity) activity).finish();
|
|
||||||
acquireTokenRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancel() {
|
|
||||||
|
|
||||||
Log.i(TAG, "authenticating cancelled");
|
|
||||||
Intent data = new Intent();
|
|
||||||
data.putExtra(EXTRA_ERROR_MESSAGE, "authenticating not cancelled");
|
|
||||||
((Activity) activity).setResult(Activity.RESULT_CANCELED, data);
|
|
||||||
((Activity) activity).finish();
|
|
||||||
acquireTokenRunning = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) {
|
|
||||||
mPublicClientApp.handleInteractiveRequestRedirect(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,407 +0,0 @@
|
|||||||
package keepass2android.javafilestorage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import com.pcloud.sdk.ApiClient;
|
|
||||||
import com.pcloud.sdk.ApiError;
|
|
||||||
import com.pcloud.sdk.Authenticators;
|
|
||||||
import com.pcloud.sdk.AuthorizationActivity;
|
|
||||||
import com.pcloud.sdk.AuthorizationResult;
|
|
||||||
import com.pcloud.sdk.Call;
|
|
||||||
import com.pcloud.sdk.DataSource;
|
|
||||||
import com.pcloud.sdk.PCloudSdk;
|
|
||||||
import com.pcloud.sdk.RemoteEntry;
|
|
||||||
import com.pcloud.sdk.RemoteFile;
|
|
||||||
import com.pcloud.sdk.RemoteFolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileStorage implementation for PCloud provider.
|
|
||||||
* https://www.pcloud.com/
|
|
||||||
*/
|
|
||||||
public class PCloudFileStorage extends JavaFileStorageBase
|
|
||||||
{
|
|
||||||
final static private int PCLOUD_AUTHORIZATION_REQUEST_CODE = 1001845497;
|
|
||||||
|
|
||||||
final static private String SHARED_PREF_NAME = "PCLOUD";
|
|
||||||
final static private String SHARED_PREF_AUTH_TOKEN = "AUTH_TOKEN";
|
|
||||||
|
|
||||||
private final Context ctx;
|
|
||||||
|
|
||||||
private ApiClient apiClient;
|
|
||||||
private String clientId;
|
|
||||||
|
|
||||||
public PCloudFileStorage(Context ctx, String clientId) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.apiClient = createApiClientFromSharedPrefs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean requiresSetup(String path) {
|
|
||||||
return !this.isConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startSelectFile(FileStorageSetupInitiatorActivity activity, boolean isForSave, int requestCode) {
|
|
||||||
String path = getProtocolId() + "://";
|
|
||||||
activity.startSelectFileProcess(path, isForSave, requestCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareFileUsage(Context appContext, String path) throws Throwable {
|
|
||||||
if (!isConnected()) {
|
|
||||||
throw new UserInteractionRequiredException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareFileUsage(FileStorageSetupInitiatorActivity activity, String path, int requestCode,
|
|
||||||
boolean alwaysReturnSuccess) {
|
|
||||||
if (this.isConnected()) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_PATH, path);
|
|
||||||
activity.onImmediateResult(requestCode, RESULT_FILEUSAGE_PREPARED, intent);
|
|
||||||
} else {
|
|
||||||
activity.startFileUsageProcess(path, requestCode, alwaysReturnSuccess);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProtocolId() {
|
|
||||||
return "pcloud";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayName(String path) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilename(String path) {
|
|
||||||
return path.substring(path.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkForFileChangeFast(String path, String previousFileVersion) throws Exception {
|
|
||||||
if (previousFileVersion == null || "".equals(previousFileVersion)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
RemoteFile remoteFile = this.getRemoteFileByPath(path);
|
|
||||||
|
|
||||||
return !remoteFile.hash().equals(previousFileVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCurrentFileVersionFast(String path) throws Exception {
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
RemoteFile remoteFile = this.getRemoteFileByPath(path);
|
|
||||||
|
|
||||||
return remoteFile.hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream openFileForRead(String path) throws Exception {
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
RemoteFile remoteFile = this.getRemoteFileByPath(path);
|
|
||||||
|
|
||||||
return remoteFile.byteStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception {
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
DataSource dataSource = DataSource.create(data);
|
|
||||||
String filename = path.substring(path.lastIndexOf("/") + 1);
|
|
||||||
String filePath = path.substring(0, path.lastIndexOf("/") + 1);
|
|
||||||
RemoteFolder remoteFolder = this.getRemoteFolderByPath(filePath);
|
|
||||||
|
|
||||||
String tempName = "." + UUID.randomUUID().toString();
|
|
||||||
try {
|
|
||||||
RemoteFile remoteFile = this.apiClient.createFile(remoteFolder, tempName, dataSource).execute();
|
|
||||||
this.apiClient.rename(remoteFile, filename).execute();
|
|
||||||
} catch (ApiError e) {
|
|
||||||
throw convertApiError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createFolder(String parentPath, String newDirName) throws Exception {
|
|
||||||
String parentPathWithoutProtocol = this.cleanPath(parentPath);
|
|
||||||
|
|
||||||
RemoteFolder remoteFolder = this.getRemoteFolderByPath(parentPathWithoutProtocol);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.apiClient.createFolder(remoteFolder, newDirName).execute();
|
|
||||||
} catch (ApiError e) {
|
|
||||||
throw convertApiError(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.createFilePath(parentPath, newDirName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createFilePath(String parentPath, String newFileName) throws Exception {
|
|
||||||
return (
|
|
||||||
this.getProtocolId() + "://" +
|
|
||||||
this.cleanPath(parentPath) +
|
|
||||||
("".equals(newFileName) ? "" : "/") +
|
|
||||||
newFileName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileEntry> listFiles(String parentPath) throws Exception {
|
|
||||||
parentPath = this.cleanPath(parentPath);
|
|
||||||
|
|
||||||
ArrayList<FileEntry> fileEntries = new ArrayList<>();
|
|
||||||
|
|
||||||
RemoteFolder remoteFolder = this.getRemoteFolderByPath(parentPath);
|
|
||||||
|
|
||||||
for (RemoteEntry remoteEntry : remoteFolder.children()) {
|
|
||||||
fileEntries.add(this.convertRemoteEntryToFileEntry(remoteEntry, parentPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileEntry getFileEntry(String path) throws Exception {
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
|
|
||||||
|
|
||||||
return this.convertRemoteEntryToFileEntry(
|
|
||||||
remoteEntry,
|
|
||||||
path.substring(0, path.lastIndexOf("/"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String path) throws Exception {
|
|
||||||
path = this.cleanPath(path);
|
|
||||||
|
|
||||||
RemoteEntry remoteEntry = this.getRemoteFileByPath(path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.apiClient.delete(remoteEntry).execute();
|
|
||||||
} catch (ApiError e) {
|
|
||||||
throw convertApiError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(FileStorageSetupActivity activity, Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume(FileStorageSetupActivity activity) {
|
|
||||||
if (activity.getProcessName().equals(PROCESS_NAME_SELECTFILE)) {
|
|
||||||
activity.getState().putString(EXTRA_PATH, activity.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isConnected()) {
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
} else if (!activity.getState().getBoolean("hasStartedAuth", false)) {
|
|
||||||
Activity castedActivity = (Activity)activity;
|
|
||||||
Intent authIntent = AuthorizationActivity.createIntent(castedActivity, this.clientId);
|
|
||||||
castedActivity.startActivityForResult(authIntent, PCLOUD_AUTHORIZATION_REQUEST_CODE);
|
|
||||||
activity.getState().putBoolean("hasStartedAuth", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(FileStorageSetupActivity activity, int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == PCLOUD_AUTHORIZATION_REQUEST_CODE && data != null) {
|
|
||||||
activity.getState().putBoolean("hasStartedAuth", false);
|
|
||||||
AuthorizationResult result = (AuthorizationResult)(
|
|
||||||
data.getSerializableExtra(AuthorizationActivity.KEY_AUTHORIZATION_RESULT)
|
|
||||||
);
|
|
||||||
this.handleAuthResult(activity, result, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleAuthResult(FileStorageSetupActivity activity, AuthorizationResult authorizationResult,
|
|
||||||
Intent data) {
|
|
||||||
if (authorizationResult == AuthorizationResult.ACCESS_GRANTED) {
|
|
||||||
String authToken = data.getStringExtra(AuthorizationActivity.KEY_ACCESS_TOKEN);
|
|
||||||
setAuthToken(authToken);
|
|
||||||
finishActivityWithSuccess(activity);
|
|
||||||
} else {
|
|
||||||
Activity castedActivity = (Activity)activity;
|
|
||||||
Intent resultData = new Intent();
|
|
||||||
resultData.putExtra(EXTRA_ERROR_MESSAGE, "Authentication failed.");
|
|
||||||
castedActivity.setResult(Activity.RESULT_CANCELED, resultData);
|
|
||||||
castedActivity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart(FileStorageSetupActivity activity) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiClient createApiClientFromSharedPrefs() {
|
|
||||||
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
|
||||||
String authToken = prefs.getString(SHARED_PREF_AUTH_TOKEN, null);
|
|
||||||
return this.createApiClient(authToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiClient createApiClient(String authToken) {
|
|
||||||
if (authToken == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
PCloudSdk.newClientBuilder()
|
|
||||||
.authenticator(Authenticators.newOAuthAuthenticator(authToken))
|
|
||||||
.create()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConnected() {
|
|
||||||
return (this.apiClient != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearAuthToken() {
|
|
||||||
this.apiClient = null;
|
|
||||||
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor edit = prefs.edit();
|
|
||||||
edit.clear();
|
|
||||||
edit.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAuthToken(String authToken) {
|
|
||||||
this.apiClient = this.createApiClient(authToken);
|
|
||||||
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor edit = prefs.edit();
|
|
||||||
edit.putString(SHARED_PREF_AUTH_TOKEN, authToken);
|
|
||||||
edit.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String cleanPath(String path) {
|
|
||||||
return (
|
|
||||||
"/" + path.replaceAll("^(" + Pattern.quote(this.getProtocolId()) + "://)?/*", "")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RemoteFile getRemoteFileByPath(String path) throws Exception {
|
|
||||||
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return remoteEntry.asFile();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
throw new FileNotFoundException(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RemoteFolder getRemoteFolderByPath(String path) throws Exception {
|
|
||||||
RemoteEntry remoteEntry = this.getRemoteEntryByPath(path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return remoteEntry.asFolder();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
throw new FileNotFoundException(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RemoteEntry getRemoteEntryByPath(String path) throws Exception {
|
|
||||||
Call<RemoteFolder> call = this.apiClient.listFolder(RemoteFolder.ROOT_FOLDER_ID, true);
|
|
||||||
|
|
||||||
RemoteFolder folder;
|
|
||||||
try {
|
|
||||||
folder = call.execute();
|
|
||||||
} catch (ApiError apiError) {
|
|
||||||
throw convertApiError(apiError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("/".equals(path)) {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] fileNames = path.substring(1).split("/");
|
|
||||||
RemoteFolder currentFolder = folder;
|
|
||||||
Iterator<String> fileNamesIterator = Arrays.asList(fileNames).iterator();
|
|
||||||
while (true) {
|
|
||||||
String fileName = fileNamesIterator.next();
|
|
||||||
|
|
||||||
Iterator<RemoteEntry> entryIterator = currentFolder.children().iterator();
|
|
||||||
while (true) {
|
|
||||||
RemoteEntry remoteEntry;
|
|
||||||
try {
|
|
||||||
remoteEntry = entryIterator.next();
|
|
||||||
} catch (NoSuchElementException e) {
|
|
||||||
throw new FileNotFoundException(e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentFolder.folderId() == remoteEntry.parentFolderId() && fileName.equals(remoteEntry.name())) {
|
|
||||||
if (!fileNamesIterator.hasNext()) {
|
|
||||||
return remoteEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
currentFolder = remoteEntry.asFolder();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
throw new FileNotFoundException(e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Exception convertApiError(ApiError e) {
|
|
||||||
String strErrorCode = String.valueOf(e.errorCode());
|
|
||||||
if (strErrorCode.startsWith("1") || "2000".equals(strErrorCode) || "2095".equals(strErrorCode)) {
|
|
||||||
this.clearAuthToken();
|
|
||||||
return new UserInteractionRequiredException("Unlinked from PCloud! User must re-link.", e);
|
|
||||||
} else if (strErrorCode.startsWith("2")) {
|
|
||||||
return new FileNotFoundException(e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileEntry convertRemoteEntryToFileEntry(RemoteEntry remoteEntry, String parentPath) {
|
|
||||||
FileEntry fileEntry = new FileEntry();
|
|
||||||
fileEntry.canRead = true;
|
|
||||||
fileEntry.canWrite = true;
|
|
||||||
fileEntry.path = (
|
|
||||||
this.getProtocolId() + "://" +
|
|
||||||
("/".equals(parentPath) ? "" : parentPath) +
|
|
||||||
"/" + remoteEntry.name()
|
|
||||||
);
|
|
||||||
fileEntry.displayName = remoteEntry.name();
|
|
||||||
fileEntry.isDirectory = !remoteEntry.isFile();
|
|
||||||
fileEntry.lastModifiedTime = remoteEntry.lastModified().getTime();
|
|
||||||
|
|
||||||
if (remoteEntry.isFile()) {
|
|
||||||
fileEntry.sizeInBytes = remoteEntry.asFile().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,7 @@ package keepass2android.javafilestorage;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -15,7 +13,6 @@ import com.jcraft.jsch.ChannelSftp;
|
|||||||
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
import com.jcraft.jsch.ChannelSftp.LsEntry;
|
||||||
import com.jcraft.jsch.JSch;
|
import com.jcraft.jsch.JSch;
|
||||||
import com.jcraft.jsch.JSchException;
|
import com.jcraft.jsch.JSchException;
|
||||||
import com.jcraft.jsch.KeyPair;
|
|
||||||
import com.jcraft.jsch.Session;
|
import com.jcraft.jsch.Session;
|
||||||
import com.jcraft.jsch.SftpATTRS;
|
import com.jcraft.jsch.SftpATTRS;
|
||||||
import com.jcraft.jsch.SftpException;
|
import com.jcraft.jsch.SftpException;
|
||||||
@@ -38,10 +35,8 @@ public class SftpStorage extends JavaFileStorageBase {
|
|||||||
public String localPath;
|
public String localPath;
|
||||||
public int port;
|
public int port;
|
||||||
}
|
}
|
||||||
Context _appContext;
|
|
||||||
|
|
||||||
public SftpStorage(Context appContext) {
|
public SftpStorage() {
|
||||||
_appContext = appContext;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,28 +318,12 @@ public class SftpStorage extends JavaFileStorageBase {
|
|||||||
jsch = new JSch();
|
jsch = new JSch();
|
||||||
ConnectionInfo ci = splitStringToConnectionInfo(filename);
|
ConnectionInfo ci = splitStringToConnectionInfo(filename);
|
||||||
|
|
||||||
String base_dir = getBaseDir();
|
|
||||||
jsch.setKnownHosts(base_dir + "/known_hosts");
|
|
||||||
|
|
||||||
String key_filename = getKeyFileName();
|
|
||||||
try{
|
|
||||||
createKeyPair(key_filename);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
jsch.addIdentity(key_filename);
|
|
||||||
} catch (java.lang.Exception e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Session session = jsch.getSession(ci.username, ci.host, ci.port);
|
Session session = jsch.getSession(ci.username, ci.host, ci.port);
|
||||||
UserInfo ui = new SftpUserInfo(ci.password,_appContext);
|
UserInfo ui = new SftpUserInfo(ci.password);
|
||||||
session.setUserInfo(ui);
|
session.setUserInfo(ui);
|
||||||
|
|
||||||
session.setConfig("PreferredAuthentications", "publickey,password");
|
session.setConfig("PreferredAuthentications",
|
||||||
|
"password,publickey");
|
||||||
|
|
||||||
session.connect();
|
session.connect();
|
||||||
|
|
||||||
@@ -357,35 +336,6 @@ public class SftpStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBaseDir() {
|
|
||||||
return _appContext.getFilesDir().getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getKeyFileName() {
|
|
||||||
return getBaseDir() + "/id_kp2a_rsa";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createKeyPair() throws IOException, JSchException {
|
|
||||||
return createKeyPair(getKeyFileName());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createKeyPair(String key_filename) throws JSchException, IOException {
|
|
||||||
String public_key_filename = key_filename + ".pub";
|
|
||||||
File file = new File(key_filename);
|
|
||||||
if (file.exists())
|
|
||||||
return public_key_filename;
|
|
||||||
int type = KeyPair.RSA;
|
|
||||||
KeyPair kpair = KeyPair.genKeyPair(jsch, type, 2048);
|
|
||||||
kpair.writePrivateKey(key_filename);
|
|
||||||
|
|
||||||
kpair.writePublicKey(public_key_filename, "generated by Keepass2Android");
|
|
||||||
//ret = "Fingerprint: " + kpair.getFingerPrint();
|
|
||||||
kpair.dispose();
|
|
||||||
return public_key_filename;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConnectionInfo splitStringToConnectionInfo(String filename)
|
public ConnectionInfo splitStringToConnectionInfo(String filename)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
ConnectionInfo ci = new ConnectionInfo();
|
ConnectionInfo ci = new ConnectionInfo();
|
||||||
|
|||||||
@@ -1,119 +1,14 @@
|
|||||||
package keepass2android.javafilestorage;
|
package keepass2android.javafilestorage;
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.jcraft.jsch.UserInfo;
|
import com.jcraft.jsch.UserInfo;
|
||||||
|
|
||||||
public class SftpUserInfo implements UserInfo {
|
public class SftpUserInfo implements UserInfo {
|
||||||
|
|
||||||
private Object /* pick one type, and fixate on it */ dance(final String type, final String text) /* for inside the thread */
|
|
||||||
{
|
|
||||||
|
|
||||||
final Message msg = Message.obtain();
|
|
||||||
|
|
||||||
/* t(*A*t) */
|
|
||||||
Thread t = new Thread() {
|
|
||||||
public void run() {
|
|
||||||
Looper.prepare();
|
|
||||||
int bogon = (int)SystemClock.elapsedRealtime();
|
|
||||||
|
|
||||||
NotificationManager mNotificationManager = (NotificationManager)_appContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(_appContext);
|
|
||||||
builder.setContentText("SFTP prompt");
|
|
||||||
builder.setSmallIcon(R.drawable.ic_logo_green_foreground);
|
|
||||||
|
|
||||||
|
|
||||||
Handler h = new Handler() {
|
|
||||||
public void handleMessage(Message M) {
|
|
||||||
msg.copyFrom(M);
|
|
||||||
Looper.myLooper().quit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Messenger m = new Messenger(h);
|
|
||||||
|
|
||||||
Intent intent = new Intent(_appContext, NotifSlave.class);
|
|
||||||
|
|
||||||
intent.setAction("keepass2android.sftp.NotifSlave");
|
|
||||||
intent.putExtra("keepass2android.sftp.returnmessenger", m);
|
|
||||||
intent.putExtra("keepass2android.sftp.reqtype", type);
|
|
||||||
intent.putExtra("keepass2android.sftp.prompt", text);
|
|
||||||
intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
|
|
||||||
|
|
||||||
PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, 0);
|
|
||||||
builder.setContentIntent(contentIntent);
|
|
||||||
|
|
||||||
{
|
|
||||||
Intent directIntent = new Intent(_appContext, NotifSlave.class);
|
|
||||||
directIntent.setAction("keepass2android.sftp.NotifSlave");
|
|
||||||
directIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
|
|
||||||
directIntent.putExtra("keepass2android.sftp.returnmessenger", m);
|
|
||||||
directIntent.putExtra("keepass2android.sftp.reqtype", type);
|
|
||||||
directIntent.putExtra("keepass2android.sftp.prompt", text);
|
|
||||||
directIntent.setData((Uri.parse("suckit://" + SystemClock.elapsedRealtime())));
|
|
||||||
_appContext.startActivity(directIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.e("KP2AJFS[thread]", "Notifying...");
|
|
||||||
|
|
||||||
mNotificationManager.notify(bogon, builder.build());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.e("KP2AJFS[thread]", "About to go to 'sleep'...");
|
|
||||||
Looper.loop();
|
|
||||||
Log.e("KP2AJFS[thread]", "And we're alive!");
|
|
||||||
|
|
||||||
Log.e("KP2AJFS[thread]", "result was: "+(Integer.toString(msg.arg1)));
|
|
||||||
|
|
||||||
mNotificationManager.cancel(bogon);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
t.start();
|
|
||||||
try {
|
|
||||||
t.join();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.equals("yesno"))
|
|
||||||
return new Boolean(msg.arg1 == 1);
|
|
||||||
else if (type.equals("message"))
|
|
||||||
return null;
|
|
||||||
else if (type.equals("password")) {
|
|
||||||
if (msg.arg1 == 0)
|
|
||||||
return null;
|
|
||||||
Bundle b = msg.getData();
|
|
||||||
return b.getString("response");
|
|
||||||
} else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Context _appContext;
|
|
||||||
|
|
||||||
String _password;
|
String _password;
|
||||||
|
|
||||||
public SftpUserInfo(String password, Context appContext)
|
public SftpUserInfo(String password) {
|
||||||
{
|
|
||||||
_password = password;
|
_password = password;
|
||||||
_appContext = appContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,15 +35,12 @@ public class SftpUserInfo implements UserInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean promptYesNo(String message) {
|
public boolean promptYesNo(String message) {
|
||||||
return (Boolean)dance("yesno", message);
|
return true; //continue all operations without user action
|
||||||
|
|
||||||
//test with https://www.sftp.net/public-online-sftp-servers?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showMessage(String message)
|
public void showMessage(String message) {
|
||||||
{
|
Log.d("KP2AJ", message);
|
||||||
dance("message", message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
@@ -71,18 +70,9 @@ public class WebDavStorage extends JavaFileStorageBase {
|
|||||||
|
|
||||||
String scheme = filename.substring(0, filename.indexOf("://"));
|
String scheme = filename.substring(0, filename.indexOf("://"));
|
||||||
filename = filename.substring(scheme.length() + 3);
|
filename = filename.substring(scheme.length() + 3);
|
||||||
int idxAt = filename.indexOf('@');
|
String userPwd = filename.substring(0, filename.indexOf('@'));
|
||||||
if (idxAt >= 0)
|
ci.username = decode(userPwd.substring(0, userPwd.indexOf(":")));
|
||||||
{
|
ci.password = decode(userPwd.substring(userPwd.indexOf(":") + 1));
|
||||||
String userPwd = filename.substring(0, idxAt);
|
|
||||||
int idxColon = userPwd.indexOf(":");
|
|
||||||
if (idxColon >= 0);
|
|
||||||
{
|
|
||||||
ci.username = decode(userPwd.substring(0, idxColon));
|
|
||||||
ci.password = decode(userPwd.substring(idxColon + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ci.URL = scheme + "://" +filename.substring(filename.indexOf('@') + 1);
|
ci.URL = scheme + "://" +filename.substring(filename.indexOf('@') + 1);
|
||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
@@ -159,19 +149,13 @@ public class WebDavStorage extends JavaFileStorageBase {
|
|||||||
sslContext.init(null, new TrustManager[] { trustManager }, null);
|
sslContext.init(null, new TrustManager[] { trustManager }, null);
|
||||||
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||||
|
|
||||||
|
|
||||||
builder = builder.sslSocketFactory(sslSocketFactory, trustManager)
|
builder = builder.sslSocketFactory(sslSocketFactory, trustManager)
|
||||||
.hostnameVerifier(new DecoratedHostnameVerifier(OkHostnameVerifier.INSTANCE, mCertificateErrorHandler));
|
.hostnameVerifier(new DecoratedHostnameVerifier(OkHostnameVerifier.INSTANCE, mCertificateErrorHandler));
|
||||||
|
|
||||||
|
|
||||||
builder.connectTimeout(25, TimeUnit.SECONDS);
|
|
||||||
builder.readTimeout(25, TimeUnit.SECONDS);
|
|
||||||
builder.writeTimeout(25, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OkHttpClient client = builder.build();
|
OkHttpClient client = builder.build();
|
||||||
|
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package keepass2android.javafilestorage.onedrive2;
|
|
||||||
|
|
||||||
import com.microsoft.graph.authentication.IAuthenticationProvider;
|
|
||||||
import com.microsoft.graph.core.DefaultClientConfig;
|
|
||||||
import com.microsoft.graph.core.IClientConfig;
|
|
||||||
import com.microsoft.graph.extensions.GraphServiceClient;
|
|
||||||
import com.microsoft.graph.extensions.IGraphServiceClient;
|
|
||||||
import com.microsoft.graph.http.IHttpRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton class that manages a GraphServiceClient object.
|
|
||||||
* It implements IAuthentication provider to authenticate requests using an access token.
|
|
||||||
*/
|
|
||||||
public class GraphServiceClientManager implements IAuthenticationProvider {
|
|
||||||
private IGraphServiceClient mGraphServiceClient;
|
|
||||||
private String mAccessToken;
|
|
||||||
|
|
||||||
public GraphServiceClientManager(String accessToken) {
|
|
||||||
mAccessToken = accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void authenticateRequest(IHttpRequest request) {
|
|
||||||
try {
|
|
||||||
request.addHeader("Authorization", "Bearer " + mAccessToken);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized IGraphServiceClient getGraphServiceClient() {
|
|
||||||
return getGraphServiceClient(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized IGraphServiceClient getGraphServiceClient(IAuthenticationProvider authenticationProvider) {
|
|
||||||
if (mGraphServiceClient == null) {
|
|
||||||
IClientConfig clientConfig = DefaultClientConfig.createWithAuthenticationProvider(
|
|
||||||
authenticationProvider
|
|
||||||
);
|
|
||||||
mGraphServiceClient = new GraphServiceClient.Builder().fromConfig(clientConfig).buildClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
return mGraphServiceClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<vector android:height="24dp" android:viewportHeight="800.0"
|
|
||||||
android:viewportWidth="800.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#ffffff" android:fillType="evenOdd" android:pathData="m318.7,232c13.6,0 24.6,10.9 24.6,24.4 0,13.5 -11,24.4 -24.6,24.4 -13.6,0 -24.6,-10.9 -24.6,-24.4 0,-13.5 11,-24.4 24.6,-24.4zM453.5,256.4c0,13.5 11,24.4 24.6,24.4 13.6,0 24.6,-10.9 24.6,-24.4 0,-13.5 -11,-24.4 -24.6,-24.4 -13.6,0 -24.6,10.9 -24.6,24.4zM399.8,177.7M140.2,600.6v47h517.3v-47zM140.2,350.9v47h517.3v-47zM140.1,481.2h191.8c-0.8,-4.1 -1.2,-8.3 -1.2,-12.4 0,-12.4 3.4,-24.2 9.9,-34.6L140.1,434.2ZM657.5,481.2v-47L454.9,434.2c6.5,10.4 9.8,22.2 9.8,34.6 0,4.1 -0.4,8.3 -1.2,12.4zM140.1,517.4v47h186.6l14.3,-47zM454.3,517.4 L468.7,564.4h188.8v-47zM432.7,565.8 L411.7,496.9 414.4,495.3c10.3,-5.9 16.7,-16.9 16.7,-28.6 0,-18.2 -15,-33 -33.3,-33 -18.3,0 -33.3,14.8 -33.3,33 0,11.8 6.4,22.7 16.7,28.6l2.7,1.6 -21.1,68.9zM507.5,158.5 L507.7,158.2 543.3,106.9c2.4,-3.5 1.8,-8.1 -1.4,-10.3 -3.2,-2.2 -7.7,-1.1 -10.2,2.4l-37.2,53.5 -0.1,0.3c-29.3,-11.8 -62.1,-18.5 -96.8,-18.5 -35.2,0 -68.5,6.9 -98.1,19L261.8,99c-2.4,-3.5 -7,-4.6 -10.2,-2.4 -3.2,2.2 -3.8,6.8 -1.4,10.3l36.2,52.2c-66.8,32.2 -111.9,92.4 -111.9,161.3h42.9c0,-79.1 80.8,-143.5 180.1,-143.5 99.3,0 180.1,64.3 180.1,143.5h42.9c0.2,-69.3 -45.4,-129.8 -113,-161.9z"/>
|
|
||||||
</vector>
|
|
||||||
0
src/java/JavaFileStorage/gradlew
vendored
Executable file → Normal file
0
src/java/JavaFileStorage/gradlew
vendored
Executable file → Normal file
@@ -10,8 +10,6 @@ android {
|
|||||||
targetSdkVersion 23
|
targetSdkVersion 23
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
multiDexEnabled true
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -59,18 +59,6 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="com.microsoft.identity.client.BrowserTabActivity">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<data android:scheme="@string/msalPrefix"
|
|
||||||
android:host="auth" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|
||||||
@@ -80,8 +68,6 @@
|
|||||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -89,8 +89,6 @@ extends Activity implements JavaFileStorage.FileStorageSetupActivity {
|
|||||||
@Override
|
@Override
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
if (getState().containsKey(JavaFileStorage.EXTRA_PATH))
|
|
||||||
return getState().getString(JavaFileStorage.EXTRA_PATH);
|
|
||||||
return getIntent().getStringExtra(JavaFileStorage.EXTRA_PATH);
|
return getIntent().getStringExtra(JavaFileStorage.EXTRA_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,19 +135,17 @@ package com.crocoapps.javafilestoragetest;
|
|||||||
import group.pals.android.lib.ui.filechooser.FileChooserActivity;
|
import group.pals.android.lib.ui.filechooser.FileChooserActivity;
|
||||||
import group.pals.android.lib.ui.filechooser.providers.BaseFileProviderUtils;
|
import group.pals.android.lib.ui.filechooser.providers.BaseFileProviderUtils;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
//import keepass2android.javafilestorage.DropboxCloudRailStorage;
|
//import keepass2android.javafilestorage.DropboxCloudRailStorage;
|
||||||
|
import keepass2android.javafilestorage.DropboxV2Storage;
|
||||||
|
import keepass2android.javafilestorage.ICertificateErrorHandler;
|
||||||
import keepass2android.javafilestorage.JavaFileStorage;
|
import keepass2android.javafilestorage.JavaFileStorage;
|
||||||
import keepass2android.javafilestorage.JavaFileStorage.FileEntry;
|
import keepass2android.javafilestorage.JavaFileStorage.FileEntry;
|
||||||
import keepass2android.javafilestorage.OneDriveStorage2;
|
import keepass2android.javafilestorage.OneDriveStorage;
|
||||||
import keepass2android.javafilestorage.SftpStorage;
|
import keepass2android.javafilestorage.SftpStorage;
|
||||||
import keepass2android.javafilestorage.UserInteractionRequiredException;
|
import keepass2android.javafilestorage.UserInteractionRequiredException;
|
||||||
import keepass2android.javafilestorage.WebDavStorage;
|
import keepass2android.javafilestorage.WebDavStorage;
|
||||||
@@ -203,17 +201,10 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.d("KP2AJ",e.toString());
|
|
||||||
//if exception because folder exists
|
//if exception because folder exists
|
||||||
path = fs.createFilePath(parentPath, testPath);
|
path = fs.createFilePath(parentPath, testPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
String textToUpload2 = "abcdefg";
|
|
||||||
String filename2 = fs.createFilePath(parentPath, "file.txt");
|
|
||||||
/*if (!path.endsWith("/"))
|
|
||||||
path += "/";
|
|
||||||
String filename = path+"file.text";*/
|
|
||||||
fs.uploadFile(filename2,textToUpload2.getBytes(),true);
|
|
||||||
|
|
||||||
FileEntry e1 = fs.getFileEntry(parentPath);
|
FileEntry e1 = fs.getFileEntry(parentPath);
|
||||||
FileEntry e2 = fs.getFileEntry(path);
|
FileEntry e2 = fs.getFileEntry(path);
|
||||||
@@ -535,11 +526,9 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
|
|||||||
}
|
}
|
||||||
|
|
||||||
static JavaFileStorage createStorageToTest(Context ctx, Context appContext, boolean simulateRestart) {
|
static JavaFileStorage createStorageToTest(Context ctx, Context appContext, boolean simulateRestart) {
|
||||||
//storageToTest = new SftpStorage(ctx.getApplicationContext());
|
//storageToTest = new SftpStorage();
|
||||||
//storageToTest = new SkyDriveFileStorage("000000004010C234", appContext);
|
//storageToTest = new SkyDriveFileStorage("000000004010C234", appContext);
|
||||||
storageToTest = new OneDriveStorage2((Activity) ctx, "8374f801-0f55-407d-80cc-9a04fe86d9b2");
|
storageToTest = new OneDriveStorage(appContext, "000000004010C234");
|
||||||
|
|
||||||
|
|
||||||
//storageToTest = new GoogleDriveFileStorage();
|
//storageToTest = new GoogleDriveFileStorage();
|
||||||
/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
|
/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
|
||||||
@Override
|
@Override
|
||||||
@@ -626,7 +615,7 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
|
|||||||
Toast.makeText(this, "requestCode: "+requestCode, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, "requestCode: "+requestCode, Toast.LENGTH_LONG).show();
|
||||||
if (requestCode == 1)
|
if (requestCode == 1)
|
||||||
//new PerformTestTask().execute(path,"TestFileStorage<67>", storageToTest); //use an umlaut to see how that works
|
//new PerformTestTask().execute(path,"TestFileStorage<67>", storageToTest); //use an umlaut to see how that works
|
||||||
new PerformTestTask().execute(path,"TestFileStorage", storageToTest);
|
new PerformTestTask().execute(path,"TestFileStorage", storageToTest);
|
||||||
else
|
else
|
||||||
if (requestCode == 2)
|
if (requestCode == 2)
|
||||||
{
|
{
|
||||||
@@ -673,20 +662,6 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readStream(InputStream is) {
|
|
||||||
StringBuilder sb = new StringBuilder(512);
|
|
||||||
try {
|
|
||||||
Reader r = new InputStreamReader(is, "UTF-8");
|
|
||||||
int c = 0;
|
|
||||||
while ((c = r.read()) != -1) {
|
|
||||||
sb.append((char) c);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performManualFileSelect(boolean isForSave, final int requestCode,
|
public void performManualFileSelect(boolean isForSave, final int requestCode,
|
||||||
String protocolId)
|
String protocolId)
|
||||||
@@ -694,30 +669,6 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
|
|||||||
if (protocolId.equals("sftp"))
|
if (protocolId.equals("sftp"))
|
||||||
{
|
{
|
||||||
final View view = getLayoutInflater().inflate(R.layout.sftp_credentials, null);
|
final View view = getLayoutInflater().inflate(R.layout.sftp_credentials, null);
|
||||||
|
|
||||||
view.findViewById(R.id.send_public_key).setOnClickListener(v -> {
|
|
||||||
Intent sendIntent = new Intent();
|
|
||||||
|
|
||||||
|
|
||||||
SftpStorage sftpStorage = (SftpStorage)storageToTest;
|
|
||||||
try {
|
|
||||||
String pub_filename = sftpStorage.createKeyPair();
|
|
||||||
|
|
||||||
sendIntent.setAction(Intent.ACTION_SEND);
|
|
||||||
sendIntent.putExtra(Intent.EXTRA_TEXT, readStream(new FileInputStream(pub_filename)));
|
|
||||||
|
|
||||||
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "Keepass2Android sftp public key");
|
|
||||||
sendIntent.setType("text/plain");
|
|
||||||
this.startActivity(Intent.createChooser(sendIntent, "Send public key to..."));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Toast.makeText(this,"Failed to create key pair: " + ex.getMessage(), Toast.LENGTH_LONG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.setTitle("Enter SFTP credentials")
|
.setTitle("Enter SFTP credentials")
|
||||||
|
|||||||
@@ -63,9 +63,6 @@
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="/home/philipp"
|
android:text="/home/philipp"
|
||||||
/>
|
/>
|
||||||
<Button android:id="@+id/send_public_key"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="send public key" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user