Merge pull request #543 from PhilippC/1.07

first 1.07 features
This commit is contained in:
PhilippC
2018-09-12 04:53:01 +02:00
committed by GitHub
44 changed files with 1300 additions and 285 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,64 @@
<?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>

View File

@@ -0,0 +1,48 @@
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; }
}

View File

@@ -0,0 +1,24 @@
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.

View File

@@ -0,0 +1,30 @@
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")]

View File

@@ -0,0 +1,14 @@
<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>

View File

@@ -0,0 +1,13 @@
<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>

View File

@@ -0,0 +1,13 @@
<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>

View File

@@ -60,7 +60,6 @@
</LibraryProjectZip>
<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" />
@@ -82,6 +81,10 @@
</XamarinComponentReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AdalBindings\AdalBindings.csproj">
<Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project>
<Name>AdalBindings</Name>
</ProjectReference>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" />
</ItemGroup>
<ItemGroup>
@@ -153,4 +156,4 @@
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okio-1.13.0.jar" />
</ItemGroup>
</Project>
</Project>

View File

@@ -11,6 +11,8 @@
<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.pcloud.sdk']" />
<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.http']" />

View File

@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdalBindings", "AdalBindings\AdalBindings.csproj", "{0B109C0E-0514-4340-8779-5BD6A0DDE84E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -158,19 +160,25 @@ Global
{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}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|Any CPU.Build.0 = 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 = Release|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.ReleaseNoNet|x64.ActiveCfg = Release|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.Build.0 = Debug|Any CPU
{3C0F7FE5-639F-4422-A087-8B26CF862D1B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -285,16 +293,54 @@ Global
{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|x64.ActiveCfg = ReleaseNoNet|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|Win32.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Debug|x64.Build.0 = Debug|Any CPU
{48574278-4779-4B3A-A9E4-9CF1BC285D0B}.Release|Win32.Build.0 = 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|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
{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
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Win32.ActiveCfg = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|Win32.Build.0 = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|x64.ActiveCfg = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Debug|x64.Build.0 = Debug|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Any CPU.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Win32.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|Win32.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|x64.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.Release|x64.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{0B109C0E-0514-4340-8779-5BD6A0DDE84E}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -5,8 +5,8 @@ namespace keepass2android.Io
{
public class SftpFileStorage: JavaFileStorage
{
public SftpFileStorage(IKp2aApp app) :
base(new Keepass2android.Javafilestorage.SftpStorage(), app)
public SftpFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.SftpStorage(ctx.ApplicationContext), app)
{
}

View File

@@ -156,6 +156,10 @@
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AdalBindings\AdalBindings.csproj">
<Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project>
<Name>AdalBindings</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>

View File

@@ -63,8 +63,9 @@
<TransformFile Include="Transforms\EnumMethods.xml" />
<TransformFile Include="Transforms\Metadata.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<ItemGroup>
<Folder Include="libs\" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
</Project>

View File

@@ -4,8 +4,13 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}</ProjectGuid>
<ProjectTypeGuids>{6322E8A7-5C46-4E8C-8B19-448B7BC95DC1};{E1126D83-ADAB-4E4F-81F7-4B0A645A68C7}</ProjectTypeGuids>
<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>
@@ -21,6 +26,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>0</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@@ -31,6 +37,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'">
<OutputPath>bin\ReleaseNoNet\</OutputPath>
@@ -46,12 +53,18 @@
<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" />
@@ -60,6 +73,7 @@
<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.
@@ -72,4 +86,5 @@
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.0.1.jar" />
</ItemGroup>
</Project>

View File

@@ -6,4 +6,5 @@
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>

View File

@@ -53,8 +53,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-debug.aar">
<Link>Jars\app-debug.aar</Link>
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
<Link>Jars\app-release.aar</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />

View File

@@ -1,15 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="keepass2android.javafilestorage"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="8"
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>

View File

@@ -0,0 +1,169 @@
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+"?");
}
}
}

View File

@@ -2,7 +2,9 @@ package keepass2android.javafilestorage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
@@ -13,6 +15,7 @@ import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.KeyPair;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
@@ -21,6 +24,7 @@ import com.jcraft.jsch.UserInfo;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
public class SftpStorage extends JavaFileStorageBase {
@@ -35,8 +39,10 @@ public class SftpStorage extends JavaFileStorageBase {
public String localPath;
public int port;
}
Context _appContext;
public SftpStorage() {
public SftpStorage(Context appContext) {
_appContext = appContext;
}
@@ -318,12 +324,28 @@ public class SftpStorage extends JavaFileStorageBase {
jsch = new JSch();
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);
UserInfo ui = new SftpUserInfo(ci.password);
UserInfo ui = new SftpUserInfo(ci.password,_appContext);
session.setUserInfo(ui);
session.setConfig("PreferredAuthentications",
"password,publickey");
session.setConfig("PreferredAuthentications", "publickey,password");
session.connect();
@@ -336,6 +358,37 @@ public class SftpStorage extends JavaFileStorageBase {
}
@NonNull
private String getBaseDir() {
return _appContext.getFilesDir().getAbsolutePath();
}
@NonNull
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)
throws UnsupportedEncodingException {
ConnectionInfo ci = new ConnectionInfo();

View File

@@ -1,14 +1,119 @@
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 com.jcraft.jsch.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;
public SftpUserInfo(String password) {
public SftpUserInfo(String password, Context appContext)
{
_password = password;
_appContext = appContext;
}
@Override
@@ -35,12 +140,15 @@ public class SftpUserInfo implements UserInfo {
@Override
public boolean promptYesNo(String message) {
return true; //continue all operations without user action
return (Boolean)dance("yesno", message);
//test with https://www.sftp.net/public-online-sftp-servers?
}
@Override
public void showMessage(String message) {
Log.d("KP2AJ", message);
public void showMessage(String message)
{
dance("message", message);
}
}

View File

@@ -0,0 +1,4 @@
<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>

View File

@@ -135,7 +135,12 @@ package com.crocoapps.javafilestoragetest;
import group.pals.android.lib.ui.filechooser.FileChooserActivity;
import group.pals.android.lib.ui.filechooser.providers.BaseFileProviderUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
@@ -526,9 +531,9 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
}
static JavaFileStorage createStorageToTest(Context ctx, Context appContext, boolean simulateRestart) {
//storageToTest = new SftpStorage();
storageToTest = new SftpStorage(ctx.getApplicationContext());
//storageToTest = new SkyDriveFileStorage("000000004010C234", appContext);
storageToTest = new OneDriveStorage(appContext, "000000004010C234");
//storageToTest = new OneDriveStorage(appContext, "000000004010C234");
//storageToTest = new GoogleDriveFileStorage();
/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
@Override
@@ -662,6 +667,20 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
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
public void performManualFileSelect(boolean isForSave, final int requestCode,
String protocolId)
@@ -669,6 +688,30 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
if (protocolId.equals("sftp"))
{
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)
.setView(view)
.setTitle("Enter SFTP credentials")

View File

@@ -63,6 +63,9 @@
android:singleLine="true"
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>

View File

@@ -24,7 +24,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@@ -521,6 +521,7 @@ public class KP2AKeyboard extends InputMethodService
mOrientation = conf.orientation;
reloadKeyboards();
}
updateKp2aKeyLabels();
mConfigurationChanging = true;
super.onConfigurationChanged(conf);
mConfigurationChanging = false;
@@ -545,6 +546,7 @@ public class KP2AKeyboard extends InputMethodService
mKeyboardSwitcher.setKeyboardMode(
KeyboardSwitcher.MODE_TEXT, 0);
}
updateKp2aKeyLabels();
return mKeyboardSwitcher.getInputView();
}
@@ -706,6 +708,7 @@ public class KP2AKeyboard extends InputMethodService
attribute.imeOptions);
}
}
updateKp2aKeyLabels();
}
private void updateShowKp2aMode() {
@@ -1365,7 +1368,8 @@ public class KP2AKeyboard extends InputMethodService
}
private void onKp2aPasswordKeyPressed() {
commitStringForTyping(KeyboardData.availableFields.get(KeyboardData.kp2aFieldIndex+1));
if (KeyboardData.availableFields.size() > KeyboardData.kp2aFieldIndex+1) //some entries may have only title, then there are no two buttons available
commitStringForTyping(KeyboardData.availableFields.get(KeyboardData.kp2aFieldIndex+1));
}
@@ -1394,38 +1398,61 @@ public class KP2AKeyboard extends InputMethodService
updateKp2aKeyLabels();
}
String makeShort(String input, int lineLength)
{
String result = input;
if (input.length() > lineLength)
{
result = input.substring(0,lineLength-1)+"";
}
return result;
}
private void updateKp2aKeyLabels() {
for (Keyboard.Key key : mKeyboardSwitcher.getInputView().getKeyboard().getKeys()) {
boolean isFirstKey = false;
boolean isSecondKey = false;
for (int code : key.codes) {
if (code == -201)
isFirstKey = true;
if (code == -202)
isSecondKey = true;
}
if ((mKeyboardSwitcher.getInputView() != null)
&& (mKeyboardSwitcher.getInputView().getKeyboard() != null))
{
for (Keyboard.Key key : mKeyboardSwitcher.getInputView().getKeyboard().getKeys()) {
boolean isFirstKey = false;
boolean isSecondKey = false;
for (int code : key.codes) {
if (code == -201)
isFirstKey = true;
if (code == -202)
isSecondKey = true;
}
int fieldIndex = -1;
if (isFirstKey) {
fieldIndex = KeyboardData.kp2aFieldIndex;
}
if (isSecondKey)
{
fieldIndex = KeyboardData.kp2aFieldIndex+1;
}
if (fieldIndex >= 0)
{
String displayName = KeyboardData.availableFields.get(fieldIndex).displayName;
if ("Password".equals(KeyboardData.availableFields.get(fieldIndex).key))
displayName = getString(R.string.kp2a_password); //might be a shorter variant
if ("UserName".equals(KeyboardData.availableFields.get(fieldIndex).key ))
displayName = getString(R.string.kp2a_user); //might be a shorter variant
key.label = displayName;
int fieldIndex = -1;
if (isFirstKey) {
fieldIndex = KeyboardData.kp2aFieldIndex;
}
if (isSecondKey) {
fieldIndex = KeyboardData.kp2aFieldIndex + 1;
}
if (fieldIndex >= 0) {
key.label = "";
if (fieldIndex < KeyboardData.availableFields.size()) {
String displayName = "";
StringForTyping fieldData = KeyboardData.availableFields.get(fieldIndex);
if (fieldData != null) {
displayName = makeShort(fieldData.displayName, 10);
if ("Password".equals(fieldData.key))
displayName = getString(R.string.kp2a_password); //might be a shorter variant
if ("UserName".equals(fieldData.key))
displayName = getString(R.string.kp2a_user); //might be a shorter variant
}
key.label = displayName;
}
}
}
mKeyboardSwitcher.getInputView().invalidateAllKeys();
}
}
private void onKp2aKeyPressed() {
@@ -1455,14 +1482,135 @@ public class KP2AKeyboard extends InputMethodService
}
}
private void showKp2aDialog() {
final EditorInfo attribute = getCurrentInputEditorInfo();
final String clientPackageName = attribute.packageName;
private void showKp2aDialog()
{
boolean androidP = android.os.Build.VERSION.SDK_INT >= 28;
//due to a change in Android P, showing the dialog as dialog does not work (only visible
// above the keyboard, not above the target application). Use an activity here.
// However, this is not perfect as it has another behavior regarding which task is
// in foreground, e.g. Chrome closes the IME when the activity is brought up which causes
// trouble entering data. So we still use the dialog in previous android versions.
if (androidP)
{
final EditorInfo attribute = getCurrentInputEditorInfo();
final String clientPackageName = attribute.packageName;
Intent i = new Intent(this, Kp2aDialog.class);
i.putExtra("clientPackageName", clientPackageName);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
else
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String title = "Keepass2Android";
List<StringForTyping> availableFields = keepass2android.kbbridge.KeyboardData.availableFields;
final EditorInfo attribute = getCurrentInputEditorInfo();
attribute.dump(new Printer() {
@Override
public void println(String x) {
Log.d("KP2AK", x);
}
}, "");
final ArrayList<StringForTyping> items = new ArrayList<StringForTyping>();
for (StringForTyping entry : availableFields) {
items.add(entry.clone());
}
StringForTyping openOrChangeEntry = new StringForTyping();
if (keepass2android.kbbridge.KeyboardData.entryName == null) {
openOrChangeEntry.displayName = openOrChangeEntry.key = getString(R.string.open_entry);
} else {
openOrChangeEntry.displayName = openOrChangeEntry.key = getString(R.string.change_entry);
}
openOrChangeEntry.value = "KP2ASPECIAL_SelectEntryTask";
items.add(openOrChangeEntry);
final String clientPackageName = attribute.packageName;
if ((clientPackageName != null) && (clientPackageName != "")) {
StringForTyping searchEntry = new StringForTyping();
try {
searchEntry.key = searchEntry.displayName
= getString(R.string.open_entry_for_app, new Object[]{clientPackageName});
} catch (java.util.FormatFlagsConversionMismatchException e) //buggy crowdin support for Arabic?
{
android.util.Log.e("KP2A", "Please report this error to crocoapps@gmail.com");
android.util.Log.e("KP2A", e.toString());
searchEntry.key = searchEntry.displayName
= "Search entry for app";
}
searchEntry.value = "KP2ASPECIAL_SearchUrlTask";
items.add(searchEntry);
}
builder.setTitle(title);
CharSequence[] itemNames = new CharSequence[items.size()];
int i = 0;
for (StringForTyping sft : items)
itemNames[i++] = sft.displayName;
builder.setItems(itemNames,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (items.get(item).value.startsWith("KP2ASPECIAL")) {
//change entry
String packageName = getApplicationContext().getPackageName();
Intent startKp2aIntent = getPackageManager().getLaunchIntentForPackage(packageName);
if (startKp2aIntent != null) {
startKp2aIntent.addCategory(Intent.CATEGORY_LAUNCHER);
startKp2aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
String value = items.get(item).value;
String taskName = value.substring("KP2ASPECIAL_".length());
startKp2aIntent.putExtra("KP2A_APPTASK", taskName);
if (taskName.equals("SearchUrlTask")) {
startKp2aIntent.putExtra("UrlToSearch", "androidapp://" + clientPackageName);
}
startActivity(startKp2aIntent);
} else Log.w("KP2AK", "didn't find intent for " + packageName);
} else {
StringForTyping theItem = items.get(item);
commitStringForTyping(theItem);
}
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog
AlertDialog dialog = builder.create();
Window window = dialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
lp.token = inputView.getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(lp);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.show();
}
Intent i = new Intent(this, Kp2aDialog.class);
i.putExtra("clientPackageName", clientPackageName);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
public void commitStringForTyping(StringForTyping theItem) {
@@ -1480,7 +1628,7 @@ public class KP2AKeyboard extends InputMethodService
Log.d("KP2AK", "committing text for " + theItem.key);
commitKp2aString(theItem.value, getCurrentInputEditorInfo());
}
@@ -1789,6 +1937,7 @@ public class KP2AKeyboard extends InputMethodService
}
setCandidatesViewShown(true);
updateInputViewShown();
updateKp2aKeyLabels();
postUpdateSuggestions();
}
});

View File

@@ -30,6 +30,7 @@ using Android.Widget;
using Android.Preferences;
using Android.Text.Method;
using System.Globalization;
using System.Net;
using Android.Content.PM;
using Android.Webkit;
using Android.Graphics;
@@ -540,9 +541,12 @@ namespace keepass2android
binaryDirectory = CacheDir.Path + File.Separator + AttachmentContentProvider.AttachmentCacheSubDir;
string filepart = key;
if (writeToCacheDirectory)
filepart = filepart.Replace(" ", "");
var targetFile = new File(binaryDirectory, filepart);
if (writeToCacheDirectory)
{
Java.Lang.String javaFilename = new Java.Lang.String(filepart);
filepart = javaFilename.ReplaceAll("[^a-zA-Z0-9.-]", "_");
}
var targetFile = new File(binaryDirectory, filepart);
File parent = targetFile.ParentFile;
@@ -1022,7 +1026,12 @@ namespace keepass2android
{
case Resource.Id.menu_donate:
return Util.GotoDonateUrl(this);
case Resource.Id.menu_toggle_pass:
case Resource.Id.menu_delete:
DeleteEntry task = new DeleteEntry(this, App.Kp2a, Entry,
new ActionOnFinish(this, (success, message, activity) => { if (success) { RequiresRefresh(); Finish();}}));
task.Start();
break;
case Resource.Id.menu_toggle_pass:
if (_showPassword)
{
item.SetTitle(Resource.String.show_password);

View File

@@ -279,7 +279,17 @@ namespace keepass2android
}
private void CreateNewFromKpEntryTemplate(Database db, PwEntry templateEntry)
protected override void OnStart()
{
base.OnStart();
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false))
{
CopyToClipboardService.ActivateKeyboard(this);
}
}
private void CreateNewFromKpEntryTemplate(Database db, PwEntry templateEntry)
{
var entry = new PwEntry(true, true);
KpEntryTemplatedEdit.InitializeEntry(entry, templateEntry);

View File

@@ -42,15 +42,49 @@ namespace keepass2android
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.sftpcredentials, null);
if (!defaultPath.EndsWith(_schemeSeparator))
var spinner = dlgContents.FindViewById<Spinner>(Resource.Id.sftp_auth_mode_spinner);
dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Click += (sender, args) =>
{
var fileStorage = new Keepass2android.Javafilestorage.SftpStorage();
var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext);
string pub_filename = fileStorage.CreateKeyPair();
Intent sendIntent = new Intent();
sendIntent.SetAction(Intent.ActionSend);
sendIntent.PutExtra(Intent.ExtraText, System.IO.File.ReadAllText(pub_filename));
sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android sftp public key");
sendIntent.SetType("text/plain");
activity.StartActivity(Intent.CreateChooser(sendIntent, "Send public key to..."));
};
spinner.ItemSelected += (sender, args) =>
{
if (spinner.SelectedItemPosition == 0)
{
dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Visibility = ViewStates.Visible;
dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Visibility = ViewStates.Gone;
}
else
{
dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Visibility = ViewStates.Gone;
dlgContents.FindViewById<Button>(Resource.Id.send_public_key_button).Visibility = ViewStates.Visible;
}
};
if (!defaultPath.EndsWith(_schemeSeparator))
{
var fileStorage = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext);
SftpStorage.ConnectionInfo ci = fileStorage.SplitStringToConnectionInfo(defaultPath);
dlgContents.FindViewById<EditText>(Resource.Id.sftp_host).Text = ci.Host;
dlgContents.FindViewById<EditText>(Resource.Id.sftp_port).Text = ci.Port.ToString();
dlgContents.FindViewById<EditText>(Resource.Id.sftp_user).Text = ci.Username;
dlgContents.FindViewById<EditText>(Resource.Id.sftp_password).Text = ci.Password;
dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text = ci.LocalPath;
if (string.IsNullOrEmpty(ci.Password))
{
spinner.SetSelection(1);
}
}
builder.SetView(dlgContents);
@@ -67,7 +101,7 @@ namespace keepass2android
string initialPath = dlgContents.FindViewById<EditText>(Resource.Id.sftp_initial_dir).Text;
if (string.IsNullOrEmpty(initialPath))
initialPath = "/";
string sftpPath = new Keepass2android.Javafilestorage.SftpStorage().BuildFullPath(host, port, initialPath, user,
string sftpPath = new Keepass2android.Javafilestorage.SftpStorage(activity.ApplicationContext).BuildFullPath(host, port, initialPath, user,
password);
onStartBrowse(sftpPath);
});

View File

@@ -19,7 +19,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Net;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
@@ -38,16 +38,12 @@ using Android.Preferences;
using Android.Text;
using Android.Content.PM;
using Android.Graphics;
using Android.Hardware.Fingerprints;
using Android.Provider;
using Android.Support.Design.Widget;
using Android.Support.V4.Widget;
using Android.Support.V7.App;
using Java.Lang;
using keepass2android;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using KeePassLib.Utility;
using Keepass2android.Pluginsdk;
using OtpKeyProv;
using keepass2android.Io;
@@ -60,12 +56,10 @@ using Object = Java.Lang.Object;
using Process = Android.OS.Process;
using KeeChallenge;
using KeePassLib.Cryptography.KeyDerivation;
using AlertDialog = Android.App.AlertDialog;
using Enum = System.Enum;
using Exception = System.Exception;
using String = System.String;
using Toolbar = Android.Support.V7.Widget.Toolbar;
namespace keepass2android
{
@@ -80,15 +74,13 @@ namespace keepass2android
enum KeyProviders
{
//int values correspond to indices in passwordSpinner
None = 0,
KeyFile = 1,
Otp = 2,
OtpRecovery = 3,
Challenge = 4,
ChalRecovery = 5,
ChallengeXC = 6 //KeepassXC compatible Challenge-Response
}
ChallengeXC = 6, //KeepassXC compatible Challenge-Response
}
public const String KeyDefaultFilename = "defaultFileName";
@@ -106,9 +98,9 @@ namespace keepass2android
private const string KeyProviderIdChallenge = "KP2A-Chal";
private const string KeyProviderIdChallengeRecovery = "KP2A-ChalSecret";
private const string KeyProviderIdChallengeXC = "KP2A-ChalXC";
private const int RequestCodePrepareDbFile = 1000;
private const int RequestCodePrepareDbFile = 1000;
private const int RequestCodePrepareOtpAuxFile = 1001;
private const int RequestCodeSelectKeyfile = 1003;
@@ -120,7 +112,7 @@ namespace keepass2android
private bool _loadDbTaskOffline; //indicate if preloading was started with offline mode
private IOConnectionInfo _ioConnection;
private String _keyFileOrProvider;
private String _keyFile;
bool _showPassword;
internal AppTask AppTask;
@@ -130,27 +122,8 @@ namespace keepass2android
private List<String> _pendingOtps = new List<string>();
KeyProviders KeyProviderType
{
get
{
if (_keyFileOrProvider == null)
return KeyProviders.None;
if (_keyFileOrProvider == KeyProviderIdOtp)
return KeyProviders.Otp;
if (_keyFileOrProvider == KeyProviderIdOtpRecovery)
return KeyProviders.OtpRecovery;
if (_keyFileOrProvider == KeyProviderIdChallenge)
return KeyProviders.Challenge;
if (_keyFileOrProvider == KeyProviderIdChallengeRecovery)
return KeyProviders.ChalRecovery;
if (_keyFileOrProvider == KeyProviderIdChallengeXC)
return KeyProviders.ChallengeXC;
return KeyProviders.KeyFile;
}
}
private HashSet<KeyProviders> KeyProviderTypes = new HashSet<KeyProviders>();
private bool _rememberKeyfile;
ISharedPreferences _prefs;
@@ -253,7 +226,6 @@ namespace keepass2android
AppTask.TryGetFromActivityResult(data, ref AppTask);
//NOTE: original code from k eepassdroid used switch ((Android.App.Result)requestCode) { (but doesn't work here, although k eepassdroid works)
switch(resultCode) {
case KeePass.ExitNormal: // Returned to this screen using the Back key
@@ -271,13 +243,13 @@ namespace keepass2android
// The database has already been locked, and the quick unlock screen will be shown if appropriate
_rememberKeyfile = _prefs.GetBoolean(GetString(Resource.String.keyfile_key), Resources.GetBoolean(Resource.Boolean.keyfile_default)); //update value
if ((KeyProviderType == KeyProviders.KeyFile) && (_rememberKeyfile))
if (KeyProviderHasKeyFile() && (_rememberKeyfile))
{
//check if the keyfile was changed (by importing to internal directory)
var newKeyFile = GetKeyFile(_ioConnection.Path);
if (newKeyFile != _keyFileOrProvider)
var newKeyProviderString = LoadKeyProviderStringForIoc(_ioConnection.Path);
if (newKeyProviderString != GetKeyProviderString())
{
_keyFileOrProvider = newKeyFile;
SetKeyProviderFromString(newKeyProviderString);
UpdateKeyfileIocView();
}
}
@@ -310,7 +282,7 @@ namespace keepass2android
Handler handler = new Handler();
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
_performingLoad = true;
LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, onFinish);
LoadDb task = new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish);
_loadDbFileTask = null; // prevent accidental re-use
new ProgressTask(App.Kp2a, this, task).Run();
}
@@ -321,20 +293,20 @@ namespace keepass2android
{
IOConnectionInfo ioc = new IOConnectionInfo();
SetIoConnectionFromIntent(ioc, data);
_keyFileOrProvider = IOConnectionInfo.SerializeToString(ioc);
_keyFile = IOConnectionInfo.SerializeToString(ioc);
UpdateKeyfileIocView();
}
break;
case (Result)FileStorageResults.FileUsagePrepared:
if (requestCode == RequestCodePrepareDbFile)
{
if (KeyProviderType == KeyProviders.KeyFile)
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
{
//if the user has not yet selected a keyfile, _keyFileOrProvider is empty
if (string.IsNullOrEmpty(_keyFileOrProvider) == false)
//if the user has not yet selected a keyfile, _keyFile is empty
if (string.IsNullOrEmpty(_keyFile) == false)
{
var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider);
var iocKeyfile = IOConnectionInfo.UnserializeFromString(_keyFile);
App.Kp2a.GetFileStorage(iocKeyfile)
.PrepareFileUsage(new FileStorageSetupInitiatorActivity(this, OnActivityResult, null), iocKeyfile,
@@ -428,16 +400,17 @@ namespace keepass2android
else
{
Toast.MakeText(this, Resource.String.bad_resp, ToastLength.Long).Show();
return;
}
}
}
}
private AuxFileLoader GetAuxFileLoader()
private AuxFileLoader GetAuxFileLoader()
{
if (_keyFileOrProvider == KeyProviderIdChallenge)
{
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
{
return new ChallengeAuxFileLoader(this);
}
else
@@ -448,8 +421,8 @@ namespace keepass2android
private void UpdateKeyfileIocView()
{
//store keyfile in the view so that we can show the selected keyfile again if the user switches to another key provider and back to key file
FindViewById<TextView>(Resource.Id.label_keyfilename).Tag = _keyFileOrProvider;
if (string.IsNullOrEmpty(_keyFileOrProvider))
FindViewById<TextView>(Resource.Id.label_keyfilename).Tag = _keyFile;
if (string.IsNullOrEmpty(_keyFile))
{
FindViewById<TextView>(Resource.Id.filestorage_label).Visibility = ViewStates.Gone;
FindViewById<ImageView>(Resource.Id.filestorage_logo).Visibility = ViewStates.Gone;
@@ -457,7 +430,7 @@ namespace keepass2android
return;
}
var ioc = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider);
var ioc = IOConnectionInfo.UnserializeFromString(_keyFile);
string displayPath = App.Kp2a.GetFileStorage(ioc).GetDisplayName(ioc);
int protocolSeparatorPos = displayPath.IndexOf("://", StringComparison.Ordinal);
string protocolId = protocolSeparatorPos < 0 ?
@@ -531,7 +504,7 @@ namespace keepass2android
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppGet, true);
intent.PutExtra(FileStorageSelectionActivity.AllowThirdPartyAppSend, false);
intent.PutExtra(FileStorageSetupDefs.ExtraIsForSave, false);
intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int)SelectStorageLocationActivity.WritableRequirements.WriteDemanded);
intent.PutExtra(SelectStorageLocationActivity.ExtraKeyWritableRequirements, (int)SelectStorageLocationActivityBase.WritableRequirements.WriteDemanded);
Activity.StartActivityForResult(intent, RequestCodeSelectAuxFile);
}
else
@@ -586,16 +559,7 @@ namespace keepass2android
IOConnectionInfo iocAux = fileStorage.GetFilePath(parentPath, filename);
return iocAux;
}
private static IOConnectionInfo GetAuxFileIoc(KeyProviderQueryContext ctx)
{
IOConnectionInfo ioc = ctx.DatabaseIOInfo.CloneDeep();
var iocAux = GetAuxFileIoc(ioc);
return iocAux;
}
protected override void HandleSuccess()
{
@@ -700,9 +664,7 @@ namespace keepass2android
int count = 1;
private DrawerLayout mDrawerLayout;
//private RecyclerView mDrawerList;
private string mDrawerTitle;
private MeasuringRelativeLayout.MeasureArgs _measureArgs;
private ActivityDesign _activityDesign;
@@ -716,7 +678,7 @@ namespace keepass2android
{
PasswordActivity owner;
public MyActionBarDrawerToggle(PasswordActivity activity, DrawerLayout layout, int imgRes, int openRes, int closeRes)
public MyActionBarDrawerToggle(PasswordActivity activity, DrawerLayout layout, int openRes, int closeRes)
: base(activity, layout, openRes, closeRes)
{
owner = activity;
@@ -822,19 +784,22 @@ namespace keepass2android
if (keyFileFromIntent != null)
{
Kp2aLog.Log("try get keyfile from intent");
_keyFileOrProvider = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyFileFromIntent));
_keyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyFileFromIntent));
KeyProviderTypes.Clear();
KeyProviderTypes.Add(KeyProviders.KeyFile);
Kp2aLog.Log("try get keyfile from intent ok");
}
else
{
_keyFileOrProvider = null;
}
_keyFile = null;
KeyProviderTypes.Clear();
}
_password = i.GetStringExtra(KeyPassword) ?? "";
if (string.IsNullOrEmpty(_keyFileOrProvider))
if (!KeyProviderTypes.Any())
{
_keyFileOrProvider = GetKeyFile(_ioConnection.Path);
SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path));
}
if ((!string.IsNullOrEmpty(_keyFileOrProvider)) || (_password != ""))
if ((!string.IsNullOrEmpty(_keyFile)) || (_password != ""))
{
_keepPasswordInOnResume = true;
}
@@ -853,7 +818,7 @@ namespace keepass2android
InitializeFilenameView();
if (KeyProviderType == KeyProviders.KeyFile)
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
{
UpdateKeyfileIocView();
}
@@ -905,8 +870,8 @@ namespace keepass2android
}
mDrawerTitle = this.Title;
mDrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
mDrawerTitle = Title;
FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
var rootview = FindViewById<MeasuringRelativeLayout>(Resource.Id.relative_layout);
rootview.ViewTreeObserver.GlobalLayout += (sender, args2) =>
{
@@ -924,16 +889,116 @@ namespace keepass2android
rootview.MeasureEvent += (sender, args) =>
{
//Snackbar.Make(rootview, "height="+args.ActualHeight, Snackbar.LengthLong).Show();
this._measureArgs = args;
_measureArgs = args;
};
if ((int)Build.VERSION.SdkInt >= 23)
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FingerprintPermissionRequestCode);
}
const int FingerprintPermissionRequestCode = 99;
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
private const string Kp2aKeyProviderStringPrefix = "_KP2A_KEYTYPES:";
private string GetKeyProviderString()
{
if (!KeyProviderTypes.Any())
return null;
string result = Kp2aKeyProviderStringPrefix;
foreach (KeyProviders type in KeyProviderTypes)
{
result += type.ToString();
if (type == KeyProviders.KeyFile)
{
result += WebUtility.UrlEncode(_keyFile) + ";";
}
}
return result;
}
private void SetKeyProviderFromString(string keyProviderString)
{
KeyProviderTypes.Clear();
if (string.IsNullOrEmpty(keyProviderString))
{
_keyFile = null;
return;
}
if (keyProviderString.StartsWith(Kp2aKeyProviderStringPrefix))
{
keyProviderString = keyProviderString.Substring(Kp2aKeyProviderStringPrefix.Length);
foreach (string type in keyProviderString.Split(';'))
{
if (!type.Trim().Any())
continue;
if (type.StartsWith(KeyProviders.KeyFile.ToString()))
{
_keyFile = WebUtility.UrlDecode(type.Substring(KeyProviders.KeyFile.ToString().Length));
KeyProviderTypes.Add(KeyProviders.KeyFile);
continue;
}
foreach (KeyProviders providerType in Enum.GetValues(typeof(KeyProviders)))
{
if (type == providerType.ToString())
{
KeyProviderTypes.Add(providerType);
break;
}
}
}
}
else
{
//legacy mode
_keyFile = null;
if (keyProviderString == KeyProviderIdOtp)
KeyProviderTypes.Add(KeyProviders.Otp);
else if (keyProviderString == KeyProviderIdOtpRecovery)
KeyProviderTypes.Add(KeyProviders.OtpRecovery);
else if (keyProviderString == KeyProviderIdChallenge)
KeyProviderTypes.Add(KeyProviders.Challenge);
else if (keyProviderString == KeyProviderIdChallengeRecovery)
KeyProviderTypes.Add(KeyProviders.ChalRecovery);
else if (keyProviderString == KeyProviderIdChallengeXC)
KeyProviderTypes.Add(KeyProviders.ChallengeXC);
else
{
KeyProviderTypes.Add(KeyProviders.KeyFile);
_keyFile = keyProviderString;
}
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
{
//test if the filename is properly encoded.
try
{
Kp2aLog.Log("test if stored filename is ok");
IOConnectionInfo.UnserializeFromString(_keyFile);
Kp2aLog.Log("...ok");
}
catch (Exception e)
{
//it's not. This is probably because we're upgrading from app version <= 45
//where the keyfile was stored plain text and not serialized
Kp2aLog.Log("no, it's not: " + e.GetType().Name);
var serializedKeyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(_keyFile));
Kp2aLog.Log("now it is!");
_keyFile = serializedKeyFile;
}
}
}
}
const int FingerprintPermissionRequestCode = 99;
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
if ((requestCode == FingerprintPermissionRequestCode) && (grantResults.Length > 0) && (grantResults[0] == Permission.Granted))
{
@@ -982,9 +1047,10 @@ namespace keepass2android
{
var masterPassword = _fingerprintDec.DecryptStored(Database.GetFingerprintPrefKey(_ioConnection));
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = masterPassword;
FindViewById<EditText>(Resource.Id.password_edit).Enabled = false; //prevent accidental modification of password
}
catch (Java.Security.GeneralSecurityException ex)
}
catch (Java.Security.GeneralSecurityException)
{
HandleFingerprintKeyInvalidated();
return;
@@ -992,8 +1058,9 @@ namespace keepass2android
btn.PostDelayed(() =>
{
//fire
OnOk(true);
//fire
OnOk(true);
FindViewById<EditText>(Resource.Id.password_edit).Enabled = true;
}, 500);
}
@@ -1011,7 +1078,7 @@ namespace keepass2android
};
FindViewById(Resource.Id.btn_nav_donate).Visibility =
PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(this.GetString(Resource.String.NoDonateOption_key), false)
.GetBoolean(GetString(Resource.String.NoDonateOption_key), false)
? ViewStates.Gone
: ViewStates.Visible;
FindViewById(Resource.Id.btn_nav_about).Click += (sender, args) =>
@@ -1059,7 +1126,7 @@ namespace keepass2android
Resource.String.menu_close);
_drawerLayout.SetDrawerListener(mDrawerToggle);
_drawerLayout?.SetDrawerListener(mDrawerToggle);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
@@ -1126,9 +1193,10 @@ namespace keepass2android
}
//assume user wants to use OTP (for static password, they need to open KP2A first and select the key provider type, then see OnNewIntent)
_keyFileOrProvider = KeyProviderIdOtp;
KeyProviderTypes.Clear();
KeyProviderTypes.Add(KeyProviders.Otp);
if (savedInstanceState == null) //only when not re-creating
if (savedInstanceState == null) //only when not re-creating
{
//remember the OTP for later use
_pendingOtps.Add(i.GetStringExtra(Intents.OtpExtraKey));
@@ -1178,7 +1246,7 @@ namespace keepass2android
}
_keyFileOrProvider = GetKeyFile(_ioConnection.Path);
SetKeyProviderFromString(LoadKeyProviderStringForIoc(_ioConnection.Path));
return true;
}
@@ -1241,33 +1309,58 @@ namespace keepass2android
if (passwordModeSpinner != null)
{
UpdateKeyProviderUiState();
passwordModeSpinner.SetSelection((int) KeyProviderType);
int spinnerPos = 0;
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
{
if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC))
spinnerPos = 7;
else spinnerPos = 1;
}
else if (KeyProviderTypes.Contains(KeyProviders.Otp))
spinnerPos = 2;
else if (KeyProviderTypes.Contains(KeyProviders.OtpRecovery))
spinnerPos = 3;
else if (KeyProviderTypes.Contains(KeyProviders.Challenge))
spinnerPos = 4;
else if (KeyProviderTypes.Contains(KeyProviders.ChalRecovery))
spinnerPos = 5;
else if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC))
spinnerPos = 6;
passwordModeSpinner.SetSelection(spinnerPos);
passwordModeSpinner.ItemSelected += (sender, args) =>
{
{
KeyProviderTypes.Clear();
_keyFile = null;
switch (args.Position)
{
case 0:
_keyFileOrProvider = null;
break;
case 1:
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
_keyFileOrProvider = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
_keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
KeyProviderTypes.Add(KeyProviders.KeyFile);
break;
case 2:
_keyFileOrProvider = KeyProviderIdOtp;
break;
KeyProviderTypes.Add(KeyProviders.Otp);
break;
case 3:
_keyFileOrProvider = KeyProviderIdOtpRecovery;
break;
KeyProviderTypes.Add(KeyProviders.OtpRecovery);
break;
case 4:
_keyFileOrProvider = KeyProviderIdChallenge;
break;
KeyProviderTypes.Add(KeyProviders.Challenge);
break;
case 5:
_keyFileOrProvider = KeyProviderIdChallengeRecovery;
break;
KeyProviderTypes.Add(KeyProviders.ChalRecovery);
break;
case 6:
_keyFileOrProvider = KeyProviderIdChallengeXC;
break;
KeyProviderTypes.Add(KeyProviders.ChallengeXC);
break;
case 7:
KeyProviderTypes.Add(KeyProviders.ChallengeXC);
KeyProviderTypes.Add(KeyProviders.KeyFile);
break;
default:
throw new Exception("Unexpected position " + args.Position + " / " +
((ICursor) ((AdapterView) sender).GetItemAtPosition(args.Position)).GetString(1));
@@ -1291,7 +1384,7 @@ namespace keepass2android
_showPassword = savedInstanceState.GetBoolean(ShowpasswordKey, false);
MakePasswordMaskedOrVisible();
_keyFileOrProvider = savedInstanceState.GetString(KeyFileOrProviderKey);
SetKeyProviderFromString(savedInstanceState.GetString(KeyFileOrProviderKey));
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = savedInstanceState.GetString(PasswordKey);
_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey));
@@ -1319,77 +1412,66 @@ namespace keepass2android
private void UpdateOkButtonState()
{
bool enabled = false;
switch (KeyProviderType)
{
case KeyProviders.None:
enabled = true;
break;
case KeyProviders.KeyFile:
enabled = _keyFileOrProvider != "" || _password != "";
break;
case KeyProviders.Otp:
enabled = true;
if (_otpInfo == null)
enabled = false;
else
{
int c = 0;
foreach (int otpId in _otpTextViewIds)
{
c++;
var otpTextView = FindViewById<EditText>(otpId);
if ((c <= _otpInfo.OtpsRequired) && (otpTextView.Text == ""))
{
enabled = false;
break;
}
}
}
break;
case KeyProviders.OtpRecovery:
case KeyProviders.ChalRecovery:
enabled = FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != "";
break;
case KeyProviders.ChallengeXC:
enabled = true;
break;
case KeyProviders.Challenge:
enabled = _challengeSecret != null;
break;
default:
throw new ArgumentOutOfRangeException();
}
bool enabled = true;
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
enabled &= _keyFile != "" || _password != "";
if (KeyProviderTypes.Contains(KeyProviders.Otp))
{
if (_otpInfo == null)
enabled = false;
else
{
int c = 0;
foreach (int otpId in _otpTextViewIds)
{
c++;
var otpTextView = FindViewById<EditText>(otpId);
if ((c <= _otpInfo.OtpsRequired) && (otpTextView.Text == ""))
{
enabled = false;
break;
}
}
}
}
if (KeyProviderTypes.Contains(KeyProviders.OtpRecovery) || KeyProviderTypes.Contains(KeyProviders.ChalRecovery))
{
enabled &= FindViewById<EditText>(Resource.Id.pass_otpsecret).Text != "";
}
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
enabled &= _challengeSecret != null;
FindViewById(Resource.Id.pass_ok).Enabled = enabled;
}
private void UpdateKeyProviderUiState()
{
FindViewById(Resource.Id.keyfileLine).Visibility = KeyProviderType == KeyProviders.KeyFile
FindViewById(Resource.Id.keyfileLine).Visibility = KeyProviderHasKeyFile()
? ViewStates.Visible
: ViewStates.Gone;
if (KeyProviderType == KeyProviders.KeyFile)
if (KeyProviderHasKeyFile())
{
UpdateKeyfileIocView();
}
FindViewById(Resource.Id.otpView).Visibility = KeyProviderType == KeyProviders.Otp
FindViewById(Resource.Id.otpView).Visibility = KeyProviderTypes.Contains(KeyProviders.Otp)
? ViewStates.Visible
: ViewStates.Gone;
FindViewById(Resource.Id.otpSecretLine).Visibility = (KeyProviderType == KeyProviders.OtpRecovery || KeyProviderType == KeyProviders.ChalRecovery)
FindViewById(Resource.Id.otpSecretLine).Visibility = (KeyProviderTypes.Contains(KeyProviders.OtpRecovery) || KeyProviderTypes.Contains(KeyProviders.ChalRecovery))
? ViewStates.Visible
: ViewStates.Gone;
if (KeyProviderType == KeyProviders.Otp)
if (KeyProviderTypes.Contains(KeyProviders.Otp))
{
FindViewById(Resource.Id.otps_pending).Visibility = _pendingOtps.Count > 0 ? ViewStates.Visible : ViewStates.Gone;
}
if (KeyProviderType == KeyProviders.Challenge)
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
{
FindViewById (Resource.Id.otpView).Visibility = ViewStates.Visible;
FindViewById(Resource.Id.otps_pending).Visibility = ViewStates.Gone;
@@ -1397,7 +1479,12 @@ namespace keepass2android
UpdateOkButtonState();
}
private void PerformLoadDatabase()
private bool KeyProviderHasKeyFile()
{
return KeyProviderTypes.Contains(KeyProviders.KeyFile);
}
private void PerformLoadDatabase()
{
_currentlyWaitingKey = null;
if (_performingLoad)
@@ -1450,10 +1537,10 @@ namespace keepass2android
Handler handler = new Handler();
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
LoadDb task = (KeyProviderType == KeyProviders.Otp)
? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider,
LoadDb task = (KeyProviderTypes.Contains(KeyProviders.Otp))
? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(),
onFinish, this)
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, onFinish);
: new LoadDb(this, App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, GetKeyProviderString(), onFinish);
_loadDbFileTask = null; // prevent accidental re-use
SetNewDefaultFile();
@@ -1462,7 +1549,7 @@ namespace keepass2android
}
catch (Exception e)
{
Kp2aLog.LogUnexpectedError(new Exception("cannot load database: "+e + ", c: " + (compositeKey != null) + (_ioConnection != null) + (_keyFileOrProvider != null), e));
Kp2aLog.LogUnexpectedError(new Exception("cannot load database: "+e + ", c: " + (compositeKey != null) + (_ioConnection != null) + (_keyFile != null), e));
throw;
}
@@ -1474,13 +1561,13 @@ namespace keepass2android
//no need to check for validity of password because if this method is called, the Ok button was enabled (i.e. there was a valid password)
compositeKey = new CompositeKey();
compositeKey.AddUserKey(new KcpPassword(_password));
if (KeyProviderType == KeyProviders.KeyFile)
if (KeyProviderTypes.Contains(KeyProviders.KeyFile))
{
try
{
if (_keyFileOrProvider == "")
if (_keyFile == "")
throw new System.IO.FileNotFoundException();
var ioc = IOConnectionInfo.UnserializeFromString(_keyFileOrProvider);
var ioc = IOConnectionInfo.UnserializeFromString(_keyFile);
using (var stream = App.Kp2a.GetFileStorage(ioc).OpenFileForRead(ioc))
{
byte[] keyfileData = StreamToMemoryStream(stream).ToArray();
@@ -1500,7 +1587,7 @@ namespace keepass2android
return false;
}
}
else if (KeyProviderType == KeyProviders.Otp)
if (KeyProviderTypes.Contains(KeyProviders.Otp))
{
try
{
@@ -1517,7 +1604,7 @@ namespace keepass2android
}
compositeKey.AddUserKey(new KcpCustomKey(OathHotpKeyProv.Name, _otpInfo.Secret, true));
}
else if ((KeyProviderType == KeyProviders.OtpRecovery) || (KeyProviderType == KeyProviders.ChalRecovery))
if ((KeyProviderTypes.Contains(KeyProviders.OtpRecovery)) || (KeyProviderTypes.Contains(KeyProviders.ChalRecovery)))
{
Spinner stpDataFmtSpinner = FindViewById<Spinner>(Resource.Id.otpsecret_format_spinner);
EditText secretEdit = FindViewById<EditText>(Resource.Id.pass_otpsecret);
@@ -1533,11 +1620,11 @@ namespace keepass2android
return false;
}
}
else if (KeyProviderType == KeyProviders.Challenge)
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
{
compositeKey.AddUserKey(new KcpCustomKey(KeeChallengeProv.Name, _challengeSecret, true));
}
else if (KeyProviderType == KeyProviders.ChallengeXC)
if (KeyProviderTypes.Contains(KeyProviders.ChallengeXC))
{
_currentlyWaitingKey = new ChallengeXCKey(this, RequestCodeChallengeYubikey);
compositeKey.AddUserKey(_currentlyWaitingKey);
@@ -1624,7 +1711,13 @@ namespace keepass2android
base.OnStart();
_starting = true;
AppTask.CanActivateSearchViewOnStart = true;
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.UseKp2aKeyboardInKp2a_key), false))
{
CopyToClipboardService.ActivateKeyboard(this);
}
AppTask.CanActivateSearchViewOnStart = true;
DonateReminder.ShowDonateReminderIfAppropriate(this);
@@ -1660,7 +1753,7 @@ namespace keepass2android
AppTask.ToBundle(outState);
outState.PutBoolean(ShowpasswordKey, _showPassword);
outState.PutString(KeyFileOrProviderKey, _keyFileOrProvider);
outState.PutString(KeyFileOrProviderKey, GetKeyProviderString());
outState.PutString(PasswordKey, _password);
outState.PutStringArrayList(PendingOtpsKey, _pendingOtps);
if (_otpInfo != null)
@@ -1695,7 +1788,7 @@ namespace keepass2android
{
string otp = intent.GetStringExtra(Intents.OtpExtraKey);
_keepPasswordInOnResume = true;
if (this.KeyProviderType == KeyProviders.Otp)
if (KeyProviderTypes.Contains(KeyProviders.Otp))
{
if (_otpInfo == null)
@@ -1800,7 +1893,7 @@ namespace keepass2android
UpdateOkButtonState();
if (KeyProviderType == KeyProviders.Challenge)
if (KeyProviderTypes.Contains(KeyProviders.Challenge))
{
FindViewById(Resource.Id.otpInitView).Visibility = _challengeSecret == null ? ViewStates.Visible : ViewStates.Gone;
}
@@ -1835,7 +1928,7 @@ namespace keepass2android
if (_loadDbFileTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
{
// Create task to kick off file loading while the user enters the password
_loadDbFileTask = Task.Factory.StartNew<MemoryStream>(PreloadDbFile);
_loadDbFileTask = Task.Factory.StartNew(PreloadDbFile);
_loadDbTaskOffline = App.Kp2a.OfflineMode;
}
}
@@ -1860,7 +1953,7 @@ namespace keepass2android
EditText pwd = (EditText)FindViewById(Resource.Id.password_edit);
pwd.PostDelayed(() =>
{
InputMethodManager keyboard = (InputMethodManager)GetSystemService(Context.InputMethodService);
InputMethodManager keyboard = (InputMethodManager)GetSystemService(InputMethodService);
if (showKeyboard)
keyboard.ShowSoftInput(pwd, 0);
else
@@ -1904,7 +1997,7 @@ namespace keepass2android
{
//exception can happen here if the app was restored from Google Backup (including preferences) but no fingerprint data is there.
btn.SetImageResource(Resource.Drawable.ic_fingerprint_error);
Kp2aLog.Log("failed to init fingerprint unlock:" + e.ToString());
Kp2aLog.Log("failed to init fingerprint unlock:" + e);
string error = GetString(Resource.String.FingerprintInitFailed) + " " +
GetString(Resource.String.fingerprint_reenable2);
@@ -1942,32 +2035,12 @@ namespace keepass2android
}
private String GetKeyFile(String filename) {
private String LoadKeyProviderStringForIoc(String filename) {
if ( _rememberKeyfile ) {
string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(filename);
if (String.IsNullOrEmpty(keyfile))
return null; //signal no key file
if (KeyProviderType == KeyProviders.KeyFile)
{
//test if the filename is properly encoded.
try
{
Kp2aLog.Log("test if stored filename is ok");
IOConnectionInfo.UnserializeFromString(keyfile);
Kp2aLog.Log("...ok");
}
catch (Exception e)
{
//it's not. This is probably because we're upgrading from app version <= 45
//where the keyfile was stored plain text and not serialized
Kp2aLog.Log("no, it's not: " + e.GetType().Name);
var serializedKeyFile = IOConnectionInfo.SerializeToString(IOConnectionInfo.FromPath(keyfile));
Kp2aLog.Log("now it is!");
return serializedKeyFile;
}
}
return keyfile;
} else {
return null;
@@ -2094,8 +2167,8 @@ namespace keepass2android
{
if (_act._prefs.GetBoolean(IoUtil.GetIocPrefKey(_ioConnection, "has_local_backup"), false))
{
Java.Lang.Object changeDb = _act.GetString(Resource.String.menu_change_db);
Message += _act.GetString(Resource.String.HintLocalBackupOtherError, new Java.Lang.Object[] { changeDb });
Object changeDb = _act.GetString(Resource.String.menu_change_db);
Message += _act.GetString(Resource.String.HintLocalBackupOtherError, changeDb);
}
}

View File

@@ -6,6 +6,7 @@
<application android:label="keepass2android"
android:icon="@mipmap/ic_launcher_online"
android:roundIcon="@mipmap/ic_launcher_online_round"
android:networkSecurityConfig="@xml/network_security_config"
>
<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="124"
android:versionName="1.06c"
android:versionCode="127"
android:versionName="1.06f"
package="keepass2android.keepass2android"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26" />
@@ -11,6 +11,8 @@
<application android:label="keepass2android"
android:icon="@mipmap/ic_launcher_online"
android:roundIcon="@mipmap/ic_launcher_online_round"
android:networkSecurityConfig="@xml/network_security_config"
>
<activity android:name="com.dropbox.core.android.AuthActivity" android:launchMode="singleTask" android:configChanges="orientation|keyboard">
<intent-filter>

View File

@@ -7,7 +7,11 @@
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
<application android:label="keepass2android" android:icon="@mipmap/ic_launcher_offline">
<application
android:label="keepass2android"
android:icon="@mipmap/ic_launcher_offline"
android:networkSecurityConfig="@xml/network_security_config"
>
<provider android:name="group.pals.android.lib.ui.filechooser.providers.localfile.LocalFileProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.localfile" android:exported="false" />
<provider android:name="group.pals.android.lib.ui.filechooser.providers.history.HistoryProvider" android:authorities="keepass2android.keepass2android_nonet.android-filechooser.history" android:exported="false" />
<activity android:name="group.pals.android.lib.ui.filechooser.FileChooserActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="user" android:theme="@style/Afc.Theme.Light">

View File

@@ -39,6 +39,26 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:hint="@string/hint_username" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/auth_mode_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sftp_auth_mode" />
<Spinner
android:id="@+id/sftp_auth_mode_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="-4dp"
android:entries="@array/sftp_auth_modes" />
</LinearLayout>
<EditText
android:id="@+id/sftp_password"
@@ -48,6 +68,11 @@
android:singleLine="true"
android:hint="@string/hint_pass"
android:importantForAccessibility="no"/>
<Button android:id="@+id/send_public_key_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/send_public_key" />
<TextView android:id="@+id/initial_dir"
android:layout_width="wrap_content"

View File

@@ -27,6 +27,11 @@
android:icon="@drawable/ic_menu_view"
app:showAsAction="ifRoom"
/>
<item android:id="@+id/menu_delete"
android:icon="@drawable/ic_menu_delete"
android:title="@string/menu_delete"
app:showAsAction="ifRoom"
/>
<item android:id="@+id/menu_donate"
android:title="@string/menu_donate"
app:showAsAction="ifRoom"

View File

@@ -917,6 +917,7 @@ Erstes öffentliches Release</string>
<item>Passwort + Challenge-Response</item>
<item>Passwort + Challenge-Response-Secret (Recovery-Modus)</item>
<item>Passwort + Challenge-Response für Keepass XC</item>
<item>Password + Schlüsseldatei + Challenge-Response für Keepass XC</item>
</string-array>
<string-array name="AcceptAllServerCertificates_options">
<item>Fehler bei Zertifikatsvalidierung ignorieren</item>

View File

@@ -114,8 +114,10 @@
<string name="UseFileTransactions_key">UseFileTransactions</string>
<string name="LockWhenScreenOff_key">LockWhenScreenOff</string>
<string name="LockWhenNavigateBack_key">kp2a_switch_rootedLockWhenNavigateBack</string>
<string name="UseKp2aKeyboardInKp2a_key">UseKp2aKeyboardInKp2a</string>
<string name="NoDonateOption_key">NoDonateOption</string>
<string name="NoDonateOption_key">NoDonateOption</string>
<string name="NoDonationReminder_key">NoDonationReminder</string>
<string name="UseOfflineCache_key">UseOfflineCache</string>

View File

@@ -346,6 +346,11 @@
<string name="LockWhenNavigateBack_title">Lock when leaving app</string>
<string name="LockWhenNavigateBack_summary">Lock the database when leaving the app by pressing the back button.</string>
<string name="UseKp2aKeyboardInKp2a_title">Use built-in keyboard inside Keepass2Android</string>
<string name="UseKp2aKeyboardInKp2a_summary">If you do not trust your standard keyboard provider, check this option to use the built-in keyboard when entering your master password or editing entries.</string>
<string name="ActivateSearchViewOnStart_title">Activate search field on start</string>
<string name="ActivateSearchViewOnStart_summary">Activates search field in the group view after unlocking or when searching for an entry</string>
@@ -510,6 +515,8 @@
<string name="hint_sftp_port">port</string>
<string name="initial_directory">Initial directory (optional):</string>
<string name="enter_sftp_login_title">Enter SFTP login data:</string>
<string name="sftp_auth_mode">Authentication mode</string>
<string name="send_public_key">Send public key...</string>
<string name="enter_ftp_login_title">Enter FTP login data:</string>
@@ -1107,7 +1114,12 @@ Initial public release
<item>Password + Challenge-Response</item>
<item>Password + Challenge-Response secret (recovery mode)</item>
<item>Password + Challenge-Response for Keepass XC</item>
<item>Password + Key file + Challenge-Response for Keepass XC</item>
</string-array>
<string-array name="sftp_auth_modes">
<item>Password</item>
<item>Private/Public key</item>
</string-array>
<string-array name="AcceptAllServerCertificates_options">
<item>Ignore certificate validation failures</item>
<item>Warn when validation fails</item>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>

View File

@@ -200,6 +200,14 @@
android:title="@string/ClearPasswordOnLeave_title"
android:key="@string/ClearPasswordOnLeave_key" />
<CheckBoxPreference
android:enabled="true"
android:persistent="true"
android:summary="@string/UseKp2aKeyboardInKp2a_summary"
android:defaultValue="false"
android:title="@string/UseKp2aKeyboardInKp2a_title"
android:key="@string/UseKp2aKeyboardInKp2a_key" />
</PreferenceScreen>
<PreferenceScreen

View File

@@ -586,7 +586,7 @@ namespace keepass2android
new DropboxAppFolderFileStorage(Application.Context, this),
new GoogleDriveFileStorage(Application.Context, this),
new OneDriveFileStorage(Application.Context, this),
new SftpFileStorage(this),
new SftpFileStorage(Application.Context, this),
new NetFtpFileStorage(Application.Context, this),
new WebDavFileStorage(this),
new PCloudFileStorage(Application.Context, this),

View File

@@ -828,6 +828,10 @@
<Folder Include="SupportLib\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AdalBindings\AdalBindings.csproj">
<Project>{0b109c0e-0514-4340-8779-5bd6a0dde84e}</Project>
<Name>AdalBindings</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4B3A-A9E4-9CF1BC285D0B}</Project>
<Name>JavaFileStorageBindings</Name>
@@ -1869,6 +1873,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\vdots_bright.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\network_security_config.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
@@ -1917,4 +1924,4 @@
<Import Project="..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v7.AppCompat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v7.AppCompat.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.AppCompat.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.v7.AppCompat.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.Design.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Design.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Design.26.1.0.1\build\MonoAndroid80\Xamarin.Android.Support.Design.targets')" />
</Project>
</Project>