openpgp-ktx: import at 95eed95fb5654e9dcfe32c3712ae97385e186396
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
fa2a93769f
commit
7b25bf8783
17 changed files with 1762 additions and 0 deletions
14
openpgp-ktx/README.md
Normal file
14
openpgp-ktx/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# openpgp-ktx [![Download](https://api.bintray.com/packages/android-password-store/openpgp-ktx/openpgp-ktx/images/download.svg)](https://bintray.com/android-password-store/openpgp-ktx/openpgp-ktx/_latestVersion)
|
||||
|
||||
Reimplementation of [OpenKeychain]'s integration library [openpgp-api]. Written entirely in Kotlin, it leverages Jetpack to be compatible with modern apps, unlike the original library.
|
||||
|
||||
## Using this with your projects
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation("com.github.androidpasswordstore:openpgp-ktx:<latest-version>")
|
||||
}
|
||||
```
|
||||
|
||||
[OpenKeychain]: https://github.com/open-keychain/open-keychain
|
||||
[openpgp-api]: https://github.com/open-keychain/openpgp-api
|
272
openpgp-ktx/api/openpgp-ktx.api
Normal file
272
openpgp-ktx/api/openpgp-ktx.api
Normal file
|
@ -0,0 +1,272 @@
|
|||
public final class me/msfjarvis/openpgpktx/AutocryptPeerUpdate : android/os/Parcelable {
|
||||
public static final field CREATOR Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$CREATOR;
|
||||
public fun <init> ()V
|
||||
public synthetic fun <init> (Landroid/os/Parcel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun createAutocryptPeerUpdate ([BLjava/util/Date;)Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate;
|
||||
public fun describeContents ()I
|
||||
public final fun getEffectiveDate ()Ljava/util/Date;
|
||||
public final fun getKeyData ()[B
|
||||
public final fun getPreferEncrypt ()Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt;
|
||||
public final fun hasKeyData ()Z
|
||||
public fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/AutocryptPeerUpdate$CREATOR : android/os/Parcelable$Creator {
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public fun createFromParcel (Landroid/os/Parcel;)Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
public fun newArray (I)[Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate;
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt : java/lang/Enum {
|
||||
public static final field MUTUAL Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt;
|
||||
public static final field NOPREFERENCE Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt;
|
||||
public static fun valueOf (Ljava/lang/String;)Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt;
|
||||
public static fun values ()[Lme/msfjarvis/openpgpktx/AutocryptPeerUpdate$PreferEncrypt;
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/util/OpenPgpApi {
|
||||
public static final field ACTION_BACKUP Ljava/lang/String;
|
||||
public static final field ACTION_CHECK_PERMISSION Ljava/lang/String;
|
||||
public static final field ACTION_CLEARTEXT_SIGN Ljava/lang/String;
|
||||
public static final field ACTION_DECRYPT_METADATA Ljava/lang/String;
|
||||
public static final field ACTION_DECRYPT_VERIFY Ljava/lang/String;
|
||||
public static final field ACTION_DETACHED_SIGN Ljava/lang/String;
|
||||
public static final field ACTION_ENCRYPT Ljava/lang/String;
|
||||
public static final field ACTION_GET_KEY Ljava/lang/String;
|
||||
public static final field ACTION_GET_KEY_IDS Ljava/lang/String;
|
||||
public static final field ACTION_GET_SIGN_KEY_ID Ljava/lang/String;
|
||||
public static final field ACTION_QUERY_AUTOCRYPT_STATUS Ljava/lang/String;
|
||||
public static final field ACTION_SIGN_AND_ENCRYPT Ljava/lang/String;
|
||||
public static final field ACTION_UPDATE_AUTOCRYPT_PEER Ljava/lang/String;
|
||||
public static final field API_VERSION I
|
||||
public static final field AUTOCRYPT_STATUS_AVAILABLE I
|
||||
public static final field AUTOCRYPT_STATUS_DISCOURAGE I
|
||||
public static final field AUTOCRYPT_STATUS_MUTUAL I
|
||||
public static final field AUTOCRYPT_STATUS_UNAVAILABLE I
|
||||
public static final field Companion Lme/msfjarvis/openpgpktx/util/OpenPgpApi$Companion;
|
||||
public static final field EXTRA_API_VERSION Ljava/lang/String;
|
||||
public static final field EXTRA_AUTOCRYPT_PEER_GOSSIP_UPDATES Ljava/lang/String;
|
||||
public static final field EXTRA_AUTOCRYPT_PEER_ID Ljava/lang/String;
|
||||
public static final field EXTRA_AUTOCRYPT_PEER_UPDATE Ljava/lang/String;
|
||||
public static final field EXTRA_BACKUP_SECRET Ljava/lang/String;
|
||||
public static final field EXTRA_DATA_LENGTH Ljava/lang/String;
|
||||
public static final field EXTRA_DECRYPTION_RESULT Ljava/lang/String;
|
||||
public static final field EXTRA_DETACHED_SIGNATURE Ljava/lang/String;
|
||||
public static final field EXTRA_ENABLE_COMPRESSION Ljava/lang/String;
|
||||
public static final field EXTRA_KEY_ID Ljava/lang/String;
|
||||
public static final field EXTRA_KEY_IDS Ljava/lang/String;
|
||||
public static final field EXTRA_KEY_IDS_SELECTED Ljava/lang/String;
|
||||
public static final field EXTRA_MINIMIZE Ljava/lang/String;
|
||||
public static final field EXTRA_MINIMIZE_USER_ID Ljava/lang/String;
|
||||
public static final field EXTRA_OPPORTUNISTIC_ENCRYPTION Ljava/lang/String;
|
||||
public static final field EXTRA_ORIGINAL_FILENAME Ljava/lang/String;
|
||||
public static final field EXTRA_PASSPHRASE Ljava/lang/String;
|
||||
public static final field EXTRA_PROGRESS_MESSENGER Ljava/lang/String;
|
||||
public static final field EXTRA_REQUEST_ASCII_ARMOR Ljava/lang/String;
|
||||
public static final field EXTRA_SENDER_ADDRESS Ljava/lang/String;
|
||||
public static final field EXTRA_SIGN_KEY_ID Ljava/lang/String;
|
||||
public static final field EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING Ljava/lang/String;
|
||||
public static final field EXTRA_USER_ID Ljava/lang/String;
|
||||
public static final field EXTRA_USER_IDS Ljava/lang/String;
|
||||
public static final field RESULT_AUTOCRYPT_STATUS Ljava/lang/String;
|
||||
public static final field RESULT_CHARSET Ljava/lang/String;
|
||||
public static final field RESULT_CODE Ljava/lang/String;
|
||||
public static final field RESULT_CODE_ERROR I
|
||||
public static final field RESULT_CODE_SUCCESS I
|
||||
public static final field RESULT_CODE_USER_INTERACTION_REQUIRED I
|
||||
public static final field RESULT_DECRYPTION Ljava/lang/String;
|
||||
public static final field RESULT_DETACHED_SIGNATURE Ljava/lang/String;
|
||||
public static final field RESULT_ERROR Ljava/lang/String;
|
||||
public static final field RESULT_INSECURE_DETAIL_INTENT Ljava/lang/String;
|
||||
public static final field RESULT_INTENT Ljava/lang/String;
|
||||
public static final field RESULT_KEYS_CONFIRMED Ljava/lang/String;
|
||||
public static final field RESULT_KEY_IDS Ljava/lang/String;
|
||||
public static final field RESULT_METADATA Ljava/lang/String;
|
||||
public static final field RESULT_OVERRIDE_CRYPTO_WARNING Ljava/lang/String;
|
||||
public static final field RESULT_SIGNATURE Ljava/lang/String;
|
||||
public static final field RESULT_SIGNATURE_MICALG Ljava/lang/String;
|
||||
public static final field SERVICE_INTENT_2 Ljava/lang/String;
|
||||
public fun <init> (Landroid/content/Context;Lorg/openintents/openpgp/IOpenPgpService2;)V
|
||||
public final fun executeApi (Landroid/content/Intent;Ljava/io/InputStream;Ljava/io/OutputStream;)Landroid/content/Intent;
|
||||
public final fun executeApiAsync (Landroid/content/Intent;Ljava/io/InputStream;Ljava/io/OutputStream;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/util/OpenPgpApi$Companion {
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/util/OpenPgpServiceConnection {
|
||||
public fun <init> (Landroid/content/Context;Ljava/lang/String;)V
|
||||
public fun <init> (Landroid/content/Context;Ljava/lang/String;Lme/msfjarvis/openpgpktx/util/OpenPgpServiceConnection$OnBound;)V
|
||||
public final fun bindToService ()V
|
||||
public final fun getService ()Lorg/openintents/openpgp/IOpenPgpService2;
|
||||
public final fun isBound ()Z
|
||||
public final fun unbindFromService ()V
|
||||
}
|
||||
|
||||
public abstract interface class me/msfjarvis/openpgpktx/util/OpenPgpServiceConnection$OnBound {
|
||||
public abstract fun onBound (Lorg/openintents/openpgp/IOpenPgpService2;)V
|
||||
public abstract fun onError (Ljava/lang/Exception;)V
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/util/OpenPgpUtils {
|
||||
public static final field INSTANCE Lme/msfjarvis/openpgpktx/util/OpenPgpUtils;
|
||||
public static final field PARSE_RESULT_MESSAGE I
|
||||
public static final field PARSE_RESULT_NO_PGP I
|
||||
public static final field PARSE_RESULT_SIGNED_MESSAGE I
|
||||
public final fun convertKeyIdToHex (J)Ljava/lang/String;
|
||||
public final fun createUserId (Lme/msfjarvis/openpgpktx/util/OpenPgpUtils$UserId;)Ljava/lang/String;
|
||||
public final fun isAvailable (Landroid/content/Context;)Z
|
||||
public final fun parseMessage (Ljava/lang/String;)I
|
||||
public final fun splitUserId (Ljava/lang/String;)Lme/msfjarvis/openpgpktx/util/OpenPgpUtils$UserId;
|
||||
}
|
||||
|
||||
public final class me/msfjarvis/openpgpktx/util/OpenPgpUtils$UserId : java/io/Serializable {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public final fun getComment ()Ljava/lang/String;
|
||||
public final fun getEmail ()Ljava/lang/String;
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface class org/openintents/openpgp/IOpenPgpService2 : android/os/IInterface {
|
||||
public abstract fun createOutputPipe (I)Landroid/os/ParcelFileDescriptor;
|
||||
public abstract fun execute (Landroid/content/Intent;Landroid/os/ParcelFileDescriptor;I)Landroid/content/Intent;
|
||||
}
|
||||
|
||||
public class org/openintents/openpgp/IOpenPgpService2$Default : org/openintents/openpgp/IOpenPgpService2 {
|
||||
public fun <init> ()V
|
||||
public fun asBinder ()Landroid/os/IBinder;
|
||||
public fun createOutputPipe (I)Landroid/os/ParcelFileDescriptor;
|
||||
public fun execute (Landroid/content/Intent;Landroid/os/ParcelFileDescriptor;I)Landroid/content/Intent;
|
||||
}
|
||||
|
||||
public abstract class org/openintents/openpgp/IOpenPgpService2$Stub : android/os/Binder, org/openintents/openpgp/IOpenPgpService2 {
|
||||
public fun <init> ()V
|
||||
public fun asBinder ()Landroid/os/IBinder;
|
||||
public static fun asInterface (Landroid/os/IBinder;)Lorg/openintents/openpgp/IOpenPgpService2;
|
||||
public static fun getDefaultImpl ()Lorg/openintents/openpgp/IOpenPgpService2;
|
||||
public fun onTransact (ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
|
||||
public static fun setDefaultImpl (Lorg/openintents/openpgp/IOpenPgpService2;)Z
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpDecryptionResult : android/os/Parcelable {
|
||||
public static final field CREATOR Lorg/openintents/openpgp/OpenPgpDecryptionResult$CREATOR;
|
||||
public static final field RESULT_ENCRYPTED I
|
||||
public static final field RESULT_INSECURE I
|
||||
public static final field RESULT_NOT_ENCRYPTED I
|
||||
public fun <init> ()V
|
||||
public synthetic fun <init> (I[B[BLkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun describeContents ()I
|
||||
public final fun getDecryptedSessionKey ()[B
|
||||
public final fun getResult ()I
|
||||
public final fun getSessionKey ()[B
|
||||
public final fun hasDecryptedSessionKey ()Z
|
||||
public fun toString ()Ljava/lang/String;
|
||||
public fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpDecryptionResult$CREATOR : android/os/Parcelable$Creator {
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public fun createFromParcel (Landroid/os/Parcel;)Lorg/openintents/openpgp/OpenPgpDecryptionResult;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
public fun newArray (I)[Lorg/openintents/openpgp/OpenPgpDecryptionResult;
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpError : android/os/Parcelable {
|
||||
public static final field CLIENT_SIDE_ERROR I
|
||||
public static final field CREATOR Lorg/openintents/openpgp/OpenPgpError$CREATOR;
|
||||
public static final field GENERIC_ERROR I
|
||||
public static final field INCOMPATIBLE_API_VERSIONS I
|
||||
public static final field NO_OR_WRONG_PASSPHRASE I
|
||||
public static final field NO_USER_IDS I
|
||||
public static final field OPPORTUNISTIC_MISSING_KEYS I
|
||||
public fun <init> ()V
|
||||
public fun describeContents ()I
|
||||
public final fun getErrorId ()I
|
||||
public final fun getMessage ()Ljava/lang/String;
|
||||
public final fun setErrorId (I)V
|
||||
public final fun setMessage (Ljava/lang/String;)V
|
||||
public fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpError$CREATOR : android/os/Parcelable$Creator {
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public fun createFromParcel (Landroid/os/Parcel;)Lorg/openintents/openpgp/OpenPgpError;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
public fun newArray (I)[Lorg/openintents/openpgp/OpenPgpError;
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpMetadata : android/os/Parcelable {
|
||||
public static final field CREATOR Lorg/openintents/openpgp/OpenPgpMetadata$CREATOR;
|
||||
public fun <init> ()V
|
||||
public fun describeContents ()I
|
||||
public final fun getCharset ()Ljava/lang/String;
|
||||
public final fun getFilename ()Ljava/lang/String;
|
||||
public final fun getMimeType ()Ljava/lang/String;
|
||||
public final fun getModificationTime ()J
|
||||
public final fun getOriginalSize ()J
|
||||
public final fun setCharset (Ljava/lang/String;)V
|
||||
public final fun setFilename (Ljava/lang/String;)V
|
||||
public final fun setMimeType (Ljava/lang/String;)V
|
||||
public final fun setModificationTime (J)V
|
||||
public final fun setOriginalSize (J)V
|
||||
public fun toString ()Ljava/lang/String;
|
||||
public fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpMetadata$CREATOR : android/os/Parcelable$Creator {
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public fun createFromParcel (Landroid/os/Parcel;)Lorg/openintents/openpgp/OpenPgpMetadata;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
public fun newArray (I)[Lorg/openintents/openpgp/OpenPgpMetadata;
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpSignatureResult : android/os/Parcelable {
|
||||
public static final field CREATOR Lorg/openintents/openpgp/OpenPgpSignatureResult$CREATOR;
|
||||
public static final field RESULT_INVALID_KEY_EXPIRED I
|
||||
public static final field RESULT_INVALID_KEY_INSECURE I
|
||||
public static final field RESULT_INVALID_KEY_REVOKED I
|
||||
public static final field RESULT_INVALID_SIGNATURE I
|
||||
public static final field RESULT_KEY_MISSING I
|
||||
public static final field RESULT_NO_SIGNATURE I
|
||||
public static final field RESULT_VALID_KEY_CONFIRMED I
|
||||
public static final field RESULT_VALID_KEY_UNCONFIRMED I
|
||||
public synthetic fun <init> (ILjava/lang/String;JLjava/util/ArrayList;Ljava/util/ArrayList;Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;Ljava/lang/Boolean;Ljava/util/Date;Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public synthetic fun <init> (Landroid/os/Parcel;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun describeContents ()I
|
||||
public final fun getConfirmedUserIds ()Ljava/util/List;
|
||||
public final fun getUserIds ()Ljava/util/List;
|
||||
public fun toString ()Ljava/lang/String;
|
||||
public final fun withAutocryptPeerResult (Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;)Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public final fun withSignatureOnlyFlag (Z)Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public fun writeToParcel (Landroid/os/Parcel;I)V
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult : java/lang/Enum {
|
||||
public static final field MISMATCH Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;
|
||||
public static final field NEW Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;
|
||||
public static final field OK Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;
|
||||
public static fun valueOf (Ljava/lang/String;)Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;
|
||||
public static fun values ()[Lorg/openintents/openpgp/OpenPgpSignatureResult$AutocryptPeerResult;
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpSignatureResult$CREATOR : android/os/Parcelable$Creator {
|
||||
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
|
||||
public fun createFromParcel (Landroid/os/Parcel;)Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public final fun createWithInvalidSignature ()Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public final fun createWithKeyMissing (JLjava/util/Date;)Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public final fun createWithNoSignature ()Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public final fun createWithValidSignature (ILjava/lang/String;JLjava/util/ArrayList;Ljava/util/ArrayList;Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;Ljava/util/Date;)Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
public synthetic fun newArray (I)[Ljava/lang/Object;
|
||||
public fun newArray (I)[Lorg/openintents/openpgp/OpenPgpSignatureResult;
|
||||
}
|
||||
|
||||
public final class org/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult : java/lang/Enum {
|
||||
public static final field UNKNOWN Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
public static final field USER_ID_CONFIRMED Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
public static final field USER_ID_MISSING Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
public static final field USER_ID_UNCONFIRMED Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
public static fun valueOf (Ljava/lang/String;)Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
public static fun values ()[Lorg/openintents/openpgp/OpenPgpSignatureResult$SenderStatusResult;
|
||||
}
|
||||
|
28
openpgp-ktx/build.gradle.kts
Normal file
28
openpgp-ktx/build.gradle.kts
Normal file
|
@ -0,0 +1,28 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
id("maven-publish")
|
||||
kotlin("android")
|
||||
`aps-plugin`
|
||||
}
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildFeatures.aidl = true
|
||||
|
||||
kotlin {
|
||||
explicitApi()
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = freeCompilerArgs + listOf(
|
||||
"-Xexplicit-api=strict"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(Dependencies.Kotlin.Coroutines.core)
|
||||
}
|
1
openpgp-ktx/consumer-proguard-rules.pro
Normal file
1
openpgp-ktx/consumer-proguard-rules.pro
Normal file
|
@ -0,0 +1 @@
|
|||
-keep class org.openintents.openpgp.**
|
17
openpgp-ktx/gradle.properties
Normal file
17
openpgp-ktx/gradle.properties
Normal file
|
@ -0,0 +1,17 @@
|
|||
GROUP=com.github.androidpasswordstore
|
||||
VERSION_NAME=2.2.0
|
||||
POM_ARTIFACT_ID=openpgp-ktx
|
||||
POM_ARTIFACT_DESCRIPTION=Reimplementation of OpenKeychain's integration library in Kotlin
|
||||
|
||||
POM_URL=https://github.com/Android-Password-Store/android-password-store
|
||||
POM_SCM_URL=https://github.com/Android-Password-Store/android-password-store
|
||||
POM_SCM_CONNECTION=scm:git:https://github.com/Android-Password-Store/android-password-store.git
|
||||
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com:Android-Password-Store/android-password-store
|
||||
|
||||
POM_LICENSE_NAME=LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
POM_LICENSE_URL=https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
POM_LICENSE_DIST=repo
|
||||
|
||||
POM_DEVELOPER_ID=android-password-store
|
||||
POM_DEVELOPER_NAME=The Android Password Store Authors
|
||||
POM_DEVELOPER_EMAIL=aps@msfjarvis.dev
|
1
openpgp-ktx/src/main/AndroidManifest.xml
Normal file
1
openpgp-ktx/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1 @@
|
|||
<manifest package="me.msfjarvis.openpgpktx" />
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: GPL-3.0-Only
|
||||
*/
|
||||
package org.openintents.openpgp;
|
||||
|
||||
interface IOpenPgpService2 {
|
||||
|
||||
/**
|
||||
* see org.openintents.openpgp.util.OpenPgpApi for documentation
|
||||
*/
|
||||
ParcelFileDescriptor createOutputPipe(in int pipeId);
|
||||
|
||||
/**
|
||||
* see org.openintents.openpgp.util.OpenPgpApi for documentation
|
||||
*/
|
||||
Intent execute(in Intent data, in ParcelFileDescriptor input, int pipeId);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
package me.msfjarvis.openpgpktx
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
import java.util.Date
|
||||
|
||||
public class AutocryptPeerUpdate() : Parcelable {
|
||||
|
||||
private var keyData: ByteArray? = null
|
||||
private var effectiveDate: Date? = null
|
||||
private lateinit var preferEncrypt: PreferEncrypt
|
||||
|
||||
internal constructor(
|
||||
keyData: ByteArray?,
|
||||
effectiveDate: Date?,
|
||||
preferEncrypt: PreferEncrypt
|
||||
) : this() {
|
||||
this.keyData = keyData
|
||||
this.effectiveDate = effectiveDate
|
||||
this.preferEncrypt = preferEncrypt
|
||||
}
|
||||
|
||||
private constructor(source: Parcel, version: Int) : this() {
|
||||
keyData = source.createByteArray()
|
||||
effectiveDate = if (source.readInt() != 0) Date(source.readLong()) else null
|
||||
preferEncrypt = PreferEncrypt.values()[source.readInt()]
|
||||
}
|
||||
|
||||
public fun createAutocryptPeerUpdate(
|
||||
keyData: ByteArray?,
|
||||
timestamp: Date?
|
||||
): AutocryptPeerUpdate {
|
||||
return AutocryptPeerUpdate(keyData, timestamp, PreferEncrypt.NOPREFERENCE)
|
||||
}
|
||||
|
||||
public fun getKeyData(): ByteArray? {
|
||||
return keyData
|
||||
}
|
||||
|
||||
public fun hasKeyData(): Boolean {
|
||||
return keyData != null
|
||||
}
|
||||
|
||||
public fun getEffectiveDate(): Date? {
|
||||
return effectiveDate
|
||||
}
|
||||
|
||||
public fun getPreferEncrypt(): PreferEncrypt? {
|
||||
return preferEncrypt
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
/**
|
||||
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||
* [.PARCELABLE_VERSION].
|
||||
*/
|
||||
dest.writeInt(PARCELABLE_VERSION)
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
val sizePosition = dest.dataPosition()
|
||||
dest.writeInt(0)
|
||||
val startPosition = dest.dataPosition()
|
||||
// version 1
|
||||
dest.writeByteArray(keyData)
|
||||
if (effectiveDate != null) {
|
||||
dest.writeInt(1)
|
||||
dest.writeLong(effectiveDate!!.time)
|
||||
} else {
|
||||
dest.writeInt(0)
|
||||
}
|
||||
dest.writeInt(preferEncrypt.ordinal)
|
||||
// Go back and write the size
|
||||
val parcelableSize = dest.dataPosition() - startPosition
|
||||
dest.setDataPosition(sizePosition)
|
||||
dest.writeInt(parcelableSize)
|
||||
dest.setDataPosition(startPosition + parcelableSize)
|
||||
}
|
||||
|
||||
public companion object CREATOR : Creator<AutocryptPeerUpdate> {
|
||||
|
||||
private const val PARCELABLE_VERSION = 1
|
||||
override fun createFromParcel(source: Parcel): AutocryptPeerUpdate? {
|
||||
val version = source.readInt() // parcelableVersion
|
||||
val parcelableSize = source.readInt()
|
||||
val startPosition = source.dataPosition()
|
||||
val vr = AutocryptPeerUpdate(source, version)
|
||||
// skip over all fields added in future versions of this parcel
|
||||
source.setDataPosition(startPosition + parcelableSize)
|
||||
return vr
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<AutocryptPeerUpdate?>? {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
public enum class PreferEncrypt {
|
||||
NOPREFERENCE, MUTUAL
|
||||
}
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
@file:Suppress("Unused")
|
||||
|
||||
package me.msfjarvis.openpgpktx.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.openintents.openpgp.IOpenPgpService2
|
||||
import org.openintents.openpgp.OpenPgpError
|
||||
|
||||
public class OpenPgpApi(private val context: Context, private val service: IOpenPgpService2) {
|
||||
|
||||
private val pipeIdGen: AtomicInteger = AtomicInteger()
|
||||
|
||||
public suspend fun executeApiAsync(
|
||||
data: Intent?,
|
||||
inputStream: InputStream?,
|
||||
outputStream: OutputStream?,
|
||||
callback: (intent: Intent?) -> Unit
|
||||
) {
|
||||
val result = executeApi(data, inputStream, outputStream)
|
||||
withContext(Dispatchers.Main) {
|
||||
callback.invoke(result)
|
||||
}
|
||||
}
|
||||
|
||||
public fun executeApi(data: Intent?, inputStream: InputStream?, outputStream: OutputStream?): Intent? {
|
||||
var input: ParcelFileDescriptor? = null
|
||||
return try {
|
||||
if (inputStream != null) {
|
||||
input = ParcelFileDescriptorUtil.pipeFrom(inputStream)
|
||||
}
|
||||
executeApi(data, input, outputStream)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception in executeApi call", e)
|
||||
val result = Intent()
|
||||
result.putExtra(RESULT_CODE, RESULT_CODE_ERROR)
|
||||
result.putExtra(
|
||||
RESULT_ERROR,
|
||||
OpenPgpError(
|
||||
OpenPgpError.CLIENT_SIDE_ERROR,
|
||||
e.message
|
||||
)
|
||||
)
|
||||
result
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "IOException when closing ParcelFileDescriptor!", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* InputStream and OutputStreams are always closed after operating on them!
|
||||
*/
|
||||
private fun executeApi(
|
||||
data: Intent?,
|
||||
input: ParcelFileDescriptor?,
|
||||
os: OutputStream?
|
||||
): Intent? {
|
||||
var output: ParcelFileDescriptor? = null
|
||||
return try {
|
||||
// always send version from client
|
||||
data?.putExtra(EXTRA_API_VERSION, API_VERSION)
|
||||
val result: Intent
|
||||
var pumpThread: Thread? = null
|
||||
var outputPipeId = 0
|
||||
if (os != null) {
|
||||
outputPipeId = pipeIdGen.incrementAndGet()
|
||||
output = service.createOutputPipe(outputPipeId)
|
||||
pumpThread = ParcelFileDescriptorUtil.pipeTo(os, output)
|
||||
}
|
||||
// blocks until result is ready
|
||||
result = service.execute(data, input, outputPipeId)
|
||||
// set class loader to current context to allow unparcelling
|
||||
// of OpenPgpError and OpenPgpSignatureResult
|
||||
// http://stackoverflow.com/a/3806769
|
||||
result.setExtrasClassLoader(context.classLoader)
|
||||
// wait for ALL data being pumped from remote side
|
||||
pumpThread?.join()
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception in executeApi call", e)
|
||||
val result = Intent()
|
||||
result.putExtra(RESULT_CODE, RESULT_CODE_ERROR)
|
||||
result.putExtra(
|
||||
RESULT_ERROR,
|
||||
OpenPgpError(
|
||||
OpenPgpError.CLIENT_SIDE_ERROR,
|
||||
e.message
|
||||
)
|
||||
)
|
||||
result
|
||||
} finally {
|
||||
// close() is required to halt the TransferThread
|
||||
if (output != null) {
|
||||
try {
|
||||
output.close()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "IOException when closing ParcelFileDescriptor!", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public companion object {
|
||||
|
||||
private const val TAG = "OpenPgp API"
|
||||
|
||||
public const val SERVICE_INTENT_2: String = "org.openintents.openpgp.IOpenPgpService2"
|
||||
|
||||
/**
|
||||
* see CHANGELOG.md
|
||||
*/
|
||||
public const val API_VERSION: Int = 11
|
||||
|
||||
/**
|
||||
* General extras
|
||||
* --------------
|
||||
*
|
||||
* required extras:
|
||||
* int EXTRA_API_VERSION (always required)
|
||||
*
|
||||
* returned extras:
|
||||
* int RESULT_CODE (RESULT_CODE_ERROR, RESULT_CODE_SUCCESS or RESULT_CODE_USER_INTERACTION_REQUIRED)
|
||||
* OpenPgpError RESULT_ERROR (if RESULT_CODE == RESULT_CODE_ERROR)
|
||||
* PendingIntent RESULT_INTENT (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED)
|
||||
*/
|
||||
|
||||
/**
|
||||
* General extras
|
||||
* --------------
|
||||
*
|
||||
* required extras:
|
||||
* int EXTRA_API_VERSION (always required)
|
||||
*
|
||||
* returned extras:
|
||||
* int RESULT_CODE (RESULT_CODE_ERROR, RESULT_CODE_SUCCESS or RESULT_CODE_USER_INTERACTION_REQUIRED)
|
||||
* OpenPgpError RESULT_ERROR (if RESULT_CODE == RESULT_CODE_ERROR)
|
||||
* PendingIntent RESULT_INTENT (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED)
|
||||
*/
|
||||
/**
|
||||
* This action performs no operation, but can be used to check if the App has permission
|
||||
* to access the API in general, returning a user interaction PendingIntent otherwise.
|
||||
* This can be used to trigger the permission dialog explicitly.
|
||||
*
|
||||
* This action uses no extras.
|
||||
*/
|
||||
public const val ACTION_CHECK_PERMISSION: String = "org.openintents.openpgp.action.CHECK_PERMISSION"
|
||||
|
||||
/**
|
||||
* Sign text resulting in a cleartext signature
|
||||
* Some magic pre-processing of the text is done to convert it to a format usable for
|
||||
* cleartext signatures per RFC 4880 before the text is actually signed:
|
||||
* - end cleartext with newline
|
||||
* - remove whitespaces on line endings
|
||||
*
|
||||
* required extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
*
|
||||
* optional extras:
|
||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||
*/
|
||||
public const val ACTION_CLEARTEXT_SIGN: String = "org.openintents.openpgp.action.CLEARTEXT_SIGN"
|
||||
|
||||
/**
|
||||
* Sign text or binary data resulting in a detached signature.
|
||||
* No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!
|
||||
* The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.
|
||||
*
|
||||
* required extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
*
|
||||
* optional extras:
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
|
||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||
*
|
||||
* returned extras:
|
||||
* byte[] RESULT_DETACHED_SIGNATURE
|
||||
* String RESULT_SIGNATURE_MICALG (contains the name of the used signature algorithm as a string)
|
||||
*/
|
||||
public const val ACTION_DETACHED_SIGN: String = "org.openintents.openpgp.action.DETACHED_SIGN"
|
||||
|
||||
/**
|
||||
* Encrypt
|
||||
*
|
||||
* required extras:
|
||||
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
||||
* or
|
||||
* long[] EXTRA_KEY_IDS
|
||||
*
|
||||
* optional extras:
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||
*/
|
||||
public const val ACTION_ENCRYPT: String = "org.openintents.openpgp.action.ENCRYPT"
|
||||
|
||||
/**
|
||||
* Sign and encrypt
|
||||
*
|
||||
* required extras:
|
||||
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
|
||||
* or
|
||||
* long[] EXTRA_KEY_IDS
|
||||
*
|
||||
* optional extras:
|
||||
* long EXTRA_SIGN_KEY_ID (key id of signing key)
|
||||
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
|
||||
* char[] EXTRA_PASSPHRASE (key passphrase)
|
||||
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
|
||||
* boolean EXTRA_ENABLE_COMPRESSION (enable ZLIB compression, default ist true)
|
||||
*/
|
||||
public const val ACTION_SIGN_AND_ENCRYPT: String = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT"
|
||||
|
||||
public const val ACTION_QUERY_AUTOCRYPT_STATUS: String =
|
||||
"org.openintents.openpgp.action.QUERY_AUTOCRYPT_STATUS"
|
||||
|
||||
/**
|
||||
* Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,
|
||||
* and also signed-only input.
|
||||
* OutputStream is optional, e.g., for verifying detached signatures!
|
||||
*
|
||||
* If OpenPgpSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_KEY_MISSING
|
||||
* in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
|
||||
* On all other status, in addition a PendingIntent is returned via RESULT_INTENT to open
|
||||
* the key view in OpenKeychain.
|
||||
*
|
||||
* optional extras:
|
||||
* byte[] EXTRA_DETACHED_SIGNATURE (detached signature)
|
||||
*
|
||||
* returned extras:
|
||||
* OpenPgpSignatureResult RESULT_SIGNATURE
|
||||
* OpenPgpDecryptionResult RESULT_DECRYPTION
|
||||
* OpenPgpDecryptMetadata RESULT_METADATA
|
||||
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
|
||||
*/
|
||||
public const val ACTION_DECRYPT_VERIFY: String = "org.openintents.openpgp.action.DECRYPT_VERIFY"
|
||||
|
||||
/**
|
||||
* Decrypts the header of an encrypted file to retrieve metadata such as original filename.
|
||||
*
|
||||
* This does not decrypt the actual content of the file.
|
||||
*
|
||||
* returned extras:
|
||||
* OpenPgpDecryptMetadata RESULT_METADATA
|
||||
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
|
||||
*/
|
||||
public const val ACTION_DECRYPT_METADATA: String = "org.openintents.openpgp.action.DECRYPT_METADATA"
|
||||
|
||||
/**
|
||||
* Select key id for signing
|
||||
*
|
||||
* optional extras:
|
||||
* String EXTRA_USER_ID
|
||||
*
|
||||
* returned extras:
|
||||
* long EXTRA_SIGN_KEY_ID
|
||||
*/
|
||||
public const val ACTION_GET_SIGN_KEY_ID: String = "org.openintents.openpgp.action.GET_SIGN_KEY_ID"
|
||||
|
||||
/**
|
||||
* Get key ids based on given user ids (=emails)
|
||||
*
|
||||
* required extras:
|
||||
* String[] EXTRA_USER_IDS
|
||||
*
|
||||
* returned extras:
|
||||
* long[] RESULT_KEY_IDS
|
||||
*/
|
||||
public const val ACTION_GET_KEY_IDS: String = "org.openintents.openpgp.action.GET_KEY_IDS"
|
||||
|
||||
/**
|
||||
* This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key
|
||||
* corresponding to the given key id in its database.
|
||||
*
|
||||
* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key.
|
||||
* The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.
|
||||
*
|
||||
* If an Output stream has been defined the whole public key is returned.
|
||||
* required extras:
|
||||
* long EXTRA_KEY_ID
|
||||
*
|
||||
* optional extras:
|
||||
* String EXTRA_REQUEST_ASCII_ARMOR (request that the returned key is encoded in ASCII Armor)
|
||||
*/
|
||||
public const val ACTION_GET_KEY: String = "org.openintents.openpgp.action.GET_KEY"
|
||||
|
||||
/**
|
||||
* Backup all keys given by EXTRA_KEY_IDS and if requested their secret parts.
|
||||
* The encrypted backup will be written to the OutputStream.
|
||||
* The client app has no access to the backup code used to encrypt the backup!
|
||||
* This operation always requires user interaction with RESULT_CODE_USER_INTERACTION_REQUIRED!
|
||||
*
|
||||
* required extras:
|
||||
* long[] EXTRA_KEY_IDS (keys that should be included in the backup)
|
||||
* boolean EXTRA_BACKUP_SECRET (also backup secret keys)
|
||||
*/
|
||||
public const val ACTION_BACKUP: String = "org.openintents.openpgp.action.BACKUP"
|
||||
|
||||
public const val ACTION_UPDATE_AUTOCRYPT_PEER: String =
|
||||
"org.openintents.openpgp.action.UPDATE_AUTOCRYPT_PEER"
|
||||
|
||||
/* Intent extras */
|
||||
public const val EXTRA_API_VERSION: String = "api_version"
|
||||
|
||||
// ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
|
||||
// request ASCII Armor for output
|
||||
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
|
||||
public const val EXTRA_REQUEST_ASCII_ARMOR: String = "ascii_armor"
|
||||
|
||||
// ACTION_DETACHED_SIGN
|
||||
public const val RESULT_DETACHED_SIGNATURE: String = "detached_signature"
|
||||
public const val RESULT_SIGNATURE_MICALG: String = "signature_micalg"
|
||||
|
||||
// ENCRYPT, SIGN_AND_ENCRYPT, QUERY_AUTOCRYPT_STATUS
|
||||
public const val EXTRA_USER_IDS: String = "user_ids"
|
||||
public const val EXTRA_KEY_IDS: String = "key_ids"
|
||||
public const val EXTRA_KEY_IDS_SELECTED: String = "key_ids_selected"
|
||||
public const val EXTRA_SIGN_KEY_ID: String = "sign_key_id"
|
||||
|
||||
public const val RESULT_KEYS_CONFIRMED: String = "keys_confirmed"
|
||||
public const val RESULT_AUTOCRYPT_STATUS: String = "autocrypt_status"
|
||||
public const val AUTOCRYPT_STATUS_UNAVAILABLE: Int = 0
|
||||
public const val AUTOCRYPT_STATUS_DISCOURAGE: Int = 1
|
||||
public const val AUTOCRYPT_STATUS_AVAILABLE: Int = 2
|
||||
public const val AUTOCRYPT_STATUS_MUTUAL: Int = 3
|
||||
|
||||
// optional extras:
|
||||
public const val EXTRA_PASSPHRASE: String = "passphrase"
|
||||
public const val EXTRA_ORIGINAL_FILENAME: String = "original_filename"
|
||||
public const val EXTRA_ENABLE_COMPRESSION: String = "enable_compression"
|
||||
public const val EXTRA_OPPORTUNISTIC_ENCRYPTION: String = "opportunistic"
|
||||
|
||||
// GET_SIGN_KEY_ID
|
||||
public const val EXTRA_USER_ID: String = "user_id"
|
||||
|
||||
// GET_KEY
|
||||
public const val EXTRA_KEY_ID: String = "key_id"
|
||||
public const val EXTRA_MINIMIZE: String = "minimize"
|
||||
public const val EXTRA_MINIMIZE_USER_ID: String = "minimize_user_id"
|
||||
public const val RESULT_KEY_IDS: String = "key_ids"
|
||||
|
||||
// BACKUP
|
||||
public const val EXTRA_BACKUP_SECRET: String = "backup_secret"
|
||||
|
||||
/* Service Intent returns */
|
||||
public const val RESULT_CODE: String = "result_code"
|
||||
|
||||
// get actual error object from RESULT_ERROR
|
||||
public const val RESULT_CODE_ERROR: Int = 0
|
||||
|
||||
// success!
|
||||
public const val RESULT_CODE_SUCCESS: Int = 1
|
||||
|
||||
// get PendingIntent from RESULT_INTENT, start PendingIntent with startIntentSenderForResult,
|
||||
// and execute service method again in onActivityResult
|
||||
public const val RESULT_CODE_USER_INTERACTION_REQUIRED: Int = 2
|
||||
|
||||
public const val RESULT_ERROR: String = "error"
|
||||
public const val RESULT_INTENT: String = "intent"
|
||||
|
||||
// DECRYPT_VERIFY
|
||||
public const val EXTRA_DETACHED_SIGNATURE: String = "detached_signature"
|
||||
public const val EXTRA_PROGRESS_MESSENGER: String = "progress_messenger"
|
||||
public const val EXTRA_DATA_LENGTH: String = "data_length"
|
||||
public const val EXTRA_DECRYPTION_RESULT: String = "decryption_result"
|
||||
public const val EXTRA_SENDER_ADDRESS: String = "sender_address"
|
||||
public const val EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING: String = "support_override_crpto_warning"
|
||||
public const val EXTRA_AUTOCRYPT_PEER_ID: String = "autocrypt_peer_id"
|
||||
public const val EXTRA_AUTOCRYPT_PEER_UPDATE: String = "autocrypt_peer_update"
|
||||
public const val EXTRA_AUTOCRYPT_PEER_GOSSIP_UPDATES: String = "autocrypt_peer_gossip_updates"
|
||||
public const val RESULT_SIGNATURE: String = "signature"
|
||||
public const val RESULT_DECRYPTION: String = "decryption"
|
||||
public const val RESULT_METADATA: String = "metadata"
|
||||
public const val RESULT_INSECURE_DETAIL_INTENT: String = "insecure_detail_intent"
|
||||
public const val RESULT_OVERRIDE_CRYPTO_WARNING: String = "override_crypto_warning"
|
||||
|
||||
// This will be the charset which was specified in the headers of ascii armored input, if any
|
||||
public const val RESULT_CHARSET: String = "charset"
|
||||
|
||||
// INTERNAL, must not be used
|
||||
internal const val EXTRA_CALL_UUID1 = "call_uuid1"
|
||||
internal const val EXTRA_CALL_UUID2 = "call_uuid2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
package me.msfjarvis.openpgpktx.util
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import org.openintents.openpgp.IOpenPgpService2
|
||||
|
||||
public class OpenPgpServiceConnection(context: Context, providerPackageName: String?) {
|
||||
|
||||
// callback interface
|
||||
public interface OnBound {
|
||||
|
||||
public fun onBound(service: IOpenPgpService2)
|
||||
public fun onError(e: Exception)
|
||||
}
|
||||
|
||||
private val mApplicationContext: Context = context.applicationContext
|
||||
public var service: IOpenPgpService2? = null
|
||||
private set
|
||||
private val mProviderPackageName: String? = providerPackageName
|
||||
private var mOnBoundListener: OnBound? = null
|
||||
|
||||
/**
|
||||
* Create new connection with callback
|
||||
*
|
||||
* @param context
|
||||
* @param providerPackageName specify package name of OpenPGP provider,
|
||||
* e.g., "org.sufficientlysecure.keychain"
|
||||
* @param onBoundListener callback, executed when connection to service has been established
|
||||
*/
|
||||
public constructor(
|
||||
context: Context,
|
||||
providerPackageName: String?,
|
||||
onBoundListener: OnBound?
|
||||
) : this(context, providerPackageName) {
|
||||
mOnBoundListener = onBoundListener
|
||||
}
|
||||
|
||||
public val isBound: Boolean
|
||||
get() = service != null
|
||||
|
||||
private val mServiceConnection: ServiceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
this@OpenPgpServiceConnection.service = IOpenPgpService2.Stub.asInterface(service)
|
||||
mOnBoundListener?.onBound(this@OpenPgpServiceConnection.service!!)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
service = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If not already bound, bind to service!
|
||||
*/
|
||||
public fun bindToService() {
|
||||
if (service == null) {
|
||||
// if not already bound...
|
||||
try {
|
||||
val serviceIntent = Intent(OpenPgpApi.SERVICE_INTENT_2)
|
||||
// NOTE: setPackage is very important to restrict the intent to this provider only!
|
||||
serviceIntent.setPackage(mProviderPackageName)
|
||||
val connect = mApplicationContext.bindService(
|
||||
serviceIntent, mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE
|
||||
)
|
||||
if (!connect) {
|
||||
throw Exception("bindService() returned false!")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
mOnBoundListener?.onError(e)
|
||||
}
|
||||
} else {
|
||||
// already bound, but also inform client about it with callback
|
||||
mOnBoundListener?.onBound(service!!)
|
||||
}
|
||||
}
|
||||
|
||||
public fun unbindFromService() {
|
||||
mApplicationContext.unbindService(mServiceConnection)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
package me.msfjarvis.openpgpktx.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.text.TextUtils
|
||||
import java.io.Serializable
|
||||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
|
||||
public object OpenPgpUtils {
|
||||
|
||||
private val PGP_MESSAGE: Pattern = Pattern.compile(
|
||||
".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*",
|
||||
Pattern.DOTALL
|
||||
)
|
||||
private val PGP_SIGNED_MESSAGE: Pattern = Pattern.compile(
|
||||
".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
|
||||
Pattern.DOTALL
|
||||
)
|
||||
private val USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$")
|
||||
private val EMAIL_PATTERN = Pattern.compile("^<?\"?([^<>\"]*@[^<>\"]*\\.[^<>\"]*)\"?>?$")
|
||||
public const val PARSE_RESULT_NO_PGP: Int = -1
|
||||
public const val PARSE_RESULT_MESSAGE: Int = 0
|
||||
public const val PARSE_RESULT_SIGNED_MESSAGE: Int = 1
|
||||
|
||||
public fun parseMessage(message: String): Int {
|
||||
val matcherSigned = PGP_SIGNED_MESSAGE.matcher(message)
|
||||
val matcherMessage = PGP_MESSAGE.matcher(message)
|
||||
return when {
|
||||
matcherMessage.matches() -> PARSE_RESULT_MESSAGE
|
||||
matcherSigned.matches() -> PARSE_RESULT_SIGNED_MESSAGE
|
||||
else -> PARSE_RESULT_NO_PGP
|
||||
}
|
||||
}
|
||||
|
||||
public fun isAvailable(context: Context): Boolean {
|
||||
val intent = Intent(OpenPgpApi.SERVICE_INTENT_2)
|
||||
val resInfo =
|
||||
context.packageManager.queryIntentServices(intent, 0)
|
||||
return resInfo.isNotEmpty()
|
||||
}
|
||||
|
||||
public fun convertKeyIdToHex(keyId: Long): String {
|
||||
return "0x" + convertKeyIdToHex32bit(keyId shr 32) + convertKeyIdToHex32bit(
|
||||
keyId
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertKeyIdToHex32bit(keyId: Long): String {
|
||||
var hexString =
|
||||
java.lang.Long.toHexString(keyId and 0xffffffffL).toLowerCase(Locale.ENGLISH)
|
||||
while (hexString.length < 8) {
|
||||
hexString = "0$hexString"
|
||||
}
|
||||
return hexString
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits userId string into naming part, email part, and comment part.
|
||||
* See SplitUserIdTest for examples.
|
||||
*/
|
||||
public fun splitUserId(userId: String): UserId {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
val matcher = USER_ID_PATTERN.matcher(userId)
|
||||
if (matcher.matches()) {
|
||||
var name = if (matcher.group(1).isEmpty()) null else matcher.group(1)
|
||||
val comment = matcher.group(2)
|
||||
var email = matcher.group(3)
|
||||
if (email != null && name != null) {
|
||||
val emailMatcher = EMAIL_PATTERN.matcher(name)
|
||||
if (emailMatcher.matches() && email == emailMatcher.group(1)) {
|
||||
email = emailMatcher.group(1)
|
||||
name = null
|
||||
}
|
||||
}
|
||||
if (email == null && name != null) {
|
||||
val emailMatcher = EMAIL_PATTERN.matcher(name)
|
||||
if (emailMatcher.matches()) {
|
||||
email = emailMatcher.group(1)
|
||||
name = null
|
||||
}
|
||||
}
|
||||
return UserId(name, email, comment)
|
||||
}
|
||||
}
|
||||
return UserId(null, null, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a composed user id. Returns null if name, email and comment are empty.
|
||||
*/
|
||||
public fun createUserId(userId: UserId): String? {
|
||||
val userIdBuilder = StringBuilder()
|
||||
if (!TextUtils.isEmpty(userId.name)) {
|
||||
userIdBuilder.append(userId.name)
|
||||
}
|
||||
if (!TextUtils.isEmpty(userId.comment)) {
|
||||
userIdBuilder.append(" (")
|
||||
userIdBuilder.append(userId.comment)
|
||||
userIdBuilder.append(")")
|
||||
}
|
||||
if (!TextUtils.isEmpty(userId.email)) {
|
||||
userIdBuilder.append(" <")
|
||||
userIdBuilder.append(userId.email)
|
||||
userIdBuilder.append(">")
|
||||
}
|
||||
return if (userIdBuilder.isEmpty()) null else userIdBuilder.toString()
|
||||
}
|
||||
|
||||
public class UserId(public val name: String?, public val email: String?, public val comment: String?) : Serializable
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
package me.msfjarvis.openpgpktx.util
|
||||
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.ParcelFileDescriptor.AutoCloseInputStream
|
||||
import android.os.ParcelFileDescriptor.AutoCloseOutputStream
|
||||
import android.util.Log
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
internal object ParcelFileDescriptorUtil {
|
||||
|
||||
private const val TAG = "PFDUtils"
|
||||
|
||||
@Throws(IOException::class)
|
||||
internal fun pipeFrom(inputStream: InputStream): ParcelFileDescriptor {
|
||||
val pipe = ParcelFileDescriptor.createPipe()
|
||||
val readSide = pipe[0]
|
||||
val writeSide = pipe[1]
|
||||
TransferThread(inputStream, AutoCloseOutputStream(writeSide))
|
||||
.start()
|
||||
return readSide
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
internal fun pipeTo(outputStream: OutputStream, output: ParcelFileDescriptor?): TransferThread {
|
||||
val t = TransferThread(AutoCloseInputStream(output), outputStream)
|
||||
t.start()
|
||||
return t
|
||||
}
|
||||
|
||||
internal class TransferThread(val `in`: InputStream, private val out: OutputStream) : Thread("IPC Transfer Thread") {
|
||||
|
||||
override fun run() {
|
||||
val buf = ByteArray(4096)
|
||||
var len: Int
|
||||
try {
|
||||
while (`in`.read(buf).also { len = it } > 0) {
|
||||
out.write(buf, 0, len)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "IOException when writing to out", e)
|
||||
} finally {
|
||||
try {
|
||||
`in`.close()
|
||||
} catch (ignored: IOException) {
|
||||
}
|
||||
try {
|
||||
out.close()
|
||||
} catch (ignored: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
isDaemon = true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
@file:JvmName("OpenPgpDecryptionResult")
|
||||
|
||||
package org.openintents.openpgp
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
|
||||
public class OpenPgpDecryptionResult() : Parcelable {
|
||||
|
||||
private var result = 0
|
||||
private var sessionKey: ByteArray? = null
|
||||
private var decryptedSessionKey: ByteArray? = null
|
||||
|
||||
private constructor(result: Int) : this() {
|
||||
this.result = result
|
||||
sessionKey = null
|
||||
decryptedSessionKey = null
|
||||
}
|
||||
|
||||
private constructor(
|
||||
result: Int,
|
||||
sessionKey: ByteArray?,
|
||||
decryptedSessionKey: ByteArray?
|
||||
) : this() {
|
||||
this.result = result
|
||||
if (sessionKey == null != (decryptedSessionKey == null)) {
|
||||
throw AssertionError("sessionkey must be null iff decryptedSessionKey is null")
|
||||
}
|
||||
this.sessionKey = sessionKey
|
||||
this.decryptedSessionKey = decryptedSessionKey
|
||||
}
|
||||
|
||||
public fun getResult(): Int {
|
||||
return result
|
||||
}
|
||||
|
||||
public fun hasDecryptedSessionKey(): Boolean {
|
||||
return sessionKey != null
|
||||
}
|
||||
|
||||
public fun getSessionKey(): ByteArray? {
|
||||
return if (sessionKey == null) {
|
||||
null
|
||||
} else sessionKey!!.copyOf(sessionKey!!.size)
|
||||
}
|
||||
|
||||
public fun getDecryptedSessionKey(): ByteArray? {
|
||||
return if (sessionKey == null || decryptedSessionKey == null) {
|
||||
null
|
||||
} else decryptedSessionKey!!.copyOf(decryptedSessionKey!!.size)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
/**
|
||||
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||
* [.PARCELABLE_VERSION].
|
||||
*/
|
||||
dest.writeInt(PARCELABLE_VERSION)
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
val sizePosition = dest.dataPosition()
|
||||
dest.writeInt(0)
|
||||
val startPosition = dest.dataPosition()
|
||||
// version 1
|
||||
dest.writeInt(result)
|
||||
// version 2
|
||||
dest.writeByteArray(sessionKey)
|
||||
dest.writeByteArray(decryptedSessionKey)
|
||||
// Go back and write the size
|
||||
val parcelableSize = dest.dataPosition() - startPosition
|
||||
dest.setDataPosition(sizePosition)
|
||||
dest.writeInt(parcelableSize)
|
||||
dest.setDataPosition(startPosition + parcelableSize)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "\nresult: $result"
|
||||
}
|
||||
|
||||
public companion object CREATOR : Creator<OpenPgpDecryptionResult> {
|
||||
|
||||
/**
|
||||
* Since there might be a case where new versions of the client using the library getting
|
||||
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||
* system for the parcels sent between the clients and the providers.
|
||||
*/
|
||||
private const val PARCELABLE_VERSION = 2
|
||||
|
||||
// content not encrypted
|
||||
public const val RESULT_NOT_ENCRYPTED: Int = -1
|
||||
|
||||
// insecure!
|
||||
public const val RESULT_INSECURE: Int = 0
|
||||
|
||||
// encrypted
|
||||
public const val RESULT_ENCRYPTED: Int = 1
|
||||
|
||||
override fun createFromParcel(source: Parcel): OpenPgpDecryptionResult? {
|
||||
val version = source.readInt() // parcelableVersion
|
||||
val parcelableSize = source.readInt()
|
||||
val startPosition = source.dataPosition()
|
||||
val result = source.readInt()
|
||||
val sessionKey = if (version > 1) source.createByteArray() else null
|
||||
val decryptedSessionKey =
|
||||
if (version > 1) source.createByteArray() else null
|
||||
val vr =
|
||||
OpenPgpDecryptionResult(result, sessionKey, decryptedSessionKey)
|
||||
// skip over all fields added in future versions of this parcel
|
||||
source.setDataPosition(startPosition + parcelableSize)
|
||||
return vr
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<OpenPgpDecryptionResult?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
@file:JvmName("OpenPgpError")
|
||||
|
||||
package org.openintents.openpgp
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
|
||||
public class OpenPgpError() : Parcelable {
|
||||
|
||||
public var errorId: Int = 0
|
||||
public var message: String? = null
|
||||
|
||||
private constructor(parcel: Parcel) : this() {
|
||||
errorId = parcel.readInt()
|
||||
message = parcel.readString()
|
||||
}
|
||||
|
||||
internal constructor(errorId: Int, message: String?) : this() {
|
||||
this.errorId = errorId
|
||||
this.message = message
|
||||
}
|
||||
|
||||
internal constructor(b: OpenPgpError) : this() {
|
||||
errorId = b.errorId
|
||||
message = b.message
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
/**
|
||||
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||
* [PARCELABLE_VERSION].
|
||||
*/
|
||||
dest.writeInt(PARCELABLE_VERSION)
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
val sizePosition = dest.dataPosition()
|
||||
dest.writeInt(0)
|
||||
val startPosition = dest.dataPosition()
|
||||
// version 1
|
||||
dest.writeInt(errorId)
|
||||
dest.writeString(message)
|
||||
// Go back and write the size
|
||||
val parcelableSize = dest.dataPosition() - startPosition
|
||||
dest.setDataPosition(sizePosition)
|
||||
dest.writeInt(parcelableSize)
|
||||
dest.setDataPosition(startPosition + parcelableSize)
|
||||
}
|
||||
|
||||
public companion object CREATOR : Creator<OpenPgpError> {
|
||||
|
||||
/**
|
||||
* Since there might be a case where new versions of the client using the library getting
|
||||
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||
* system for the parcels sent between the clients and the providers.
|
||||
*/
|
||||
private const val PARCELABLE_VERSION = 1
|
||||
|
||||
// possible values for errorId
|
||||
public const val CLIENT_SIDE_ERROR: Int = -1
|
||||
public const val GENERIC_ERROR: Int = 0
|
||||
public const val INCOMPATIBLE_API_VERSIONS: Int = 1
|
||||
public const val NO_OR_WRONG_PASSPHRASE: Int = 2
|
||||
public const val NO_USER_IDS: Int = 3
|
||||
public const val OPPORTUNISTIC_MISSING_KEYS: Int = 4
|
||||
|
||||
override fun createFromParcel(source: Parcel): OpenPgpError? {
|
||||
source.readInt() // parcelableVersion
|
||||
val parcelableSize = source.readInt()
|
||||
val startPosition = source.dataPosition()
|
||||
val error = OpenPgpError()
|
||||
error.errorId = source.readInt()
|
||||
error.message = source.readString()
|
||||
// skip over all fields added in future versions of this parcel
|
||||
source.setDataPosition(startPosition + parcelableSize)
|
||||
return error
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<OpenPgpError?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
@file:JvmName("OpenPgpMetadata")
|
||||
|
||||
package org.openintents.openpgp
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
|
||||
public class OpenPgpMetadata() : Parcelable {
|
||||
|
||||
public var filename: String? = null
|
||||
public var mimeType: String? = null
|
||||
public var charset: String? = null
|
||||
public var modificationTime: Long = 0
|
||||
public var originalSize: Long = 0
|
||||
|
||||
private constructor(
|
||||
filename: String?,
|
||||
mimeType: String?,
|
||||
modificationTime: Long,
|
||||
originalSize: Long,
|
||||
charset: String?
|
||||
) : this() {
|
||||
this.filename = filename
|
||||
this.mimeType = mimeType
|
||||
this.modificationTime = modificationTime
|
||||
this.originalSize = originalSize
|
||||
this.charset = charset
|
||||
}
|
||||
|
||||
private constructor(
|
||||
filename: String?,
|
||||
mimeType: String?,
|
||||
modificationTime: Long,
|
||||
originalSize: Long
|
||||
) : this() {
|
||||
this.filename = filename
|
||||
this.mimeType = mimeType
|
||||
this.modificationTime = modificationTime
|
||||
this.originalSize = originalSize
|
||||
}
|
||||
|
||||
private constructor(b: OpenPgpMetadata) : this() {
|
||||
filename = b.filename
|
||||
mimeType = b.mimeType
|
||||
modificationTime = b.modificationTime
|
||||
originalSize = b.originalSize
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
/**
|
||||
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||
* [PARCELABLE_VERSION].
|
||||
*/
|
||||
dest.writeInt(PARCELABLE_VERSION)
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
val sizePosition = dest.dataPosition()
|
||||
dest.writeInt(0)
|
||||
val startPosition = dest.dataPosition()
|
||||
// version 1
|
||||
dest.writeString(filename)
|
||||
dest.writeString(mimeType)
|
||||
dest.writeLong(modificationTime)
|
||||
dest.writeLong(originalSize)
|
||||
// version 2
|
||||
dest.writeString(charset)
|
||||
// Go back and write the size
|
||||
val parcelableSize = dest.dataPosition() - startPosition
|
||||
dest.setDataPosition(sizePosition)
|
||||
dest.writeInt(parcelableSize)
|
||||
dest.setDataPosition(startPosition + parcelableSize)
|
||||
}
|
||||
|
||||
public companion object CREATOR : Creator<OpenPgpMetadata> {
|
||||
|
||||
/**
|
||||
* Since there might be a case where new versions of the client using the library getting
|
||||
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||
* system for the parcels sent between the clients and the providers.
|
||||
*/
|
||||
private const val PARCELABLE_VERSION = 2
|
||||
|
||||
override fun createFromParcel(source: Parcel): OpenPgpMetadata? {
|
||||
val version = source.readInt() // parcelableVersion
|
||||
val parcelableSize = source.readInt()
|
||||
val startPosition = source.dataPosition()
|
||||
val vr = OpenPgpMetadata()
|
||||
vr.filename = source.readString()
|
||||
vr.mimeType = source.readString()
|
||||
vr.modificationTime = source.readLong()
|
||||
vr.originalSize = source.readLong()
|
||||
if (version >= 2) {
|
||||
vr.charset = source.readString()
|
||||
}
|
||||
// skip over all fields added in future versions of this parcel
|
||||
source.setDataPosition(startPosition + parcelableSize)
|
||||
return vr
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<OpenPgpMetadata?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
var out = "\nfilename: $filename"
|
||||
out += "\nmimeType: $mimeType"
|
||||
out += "\nmodificationTime: $modificationTime"
|
||||
out += "\noriginalSize: $originalSize"
|
||||
out += "\ncharset: $charset"
|
||||
return out
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright © 2019 The Android Password Authors. All Rights Reserved.
|
||||
* SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
|
||||
*/
|
||||
@file:JvmName("OpenPgpSignatureResult")
|
||||
|
||||
package org.openintents.openpgp
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
import java.util.Date
|
||||
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
|
||||
|
||||
public class OpenPgpSignatureResult : Parcelable {
|
||||
|
||||
private val result: Int
|
||||
private val keyId: Long
|
||||
private val primaryUserId: String?
|
||||
private val userIds: ArrayList<String>?
|
||||
private val confirmedUserIds: ArrayList<String>?
|
||||
private val senderStatusResult: SenderStatusResult?
|
||||
private val signatureTimestamp: Date?
|
||||
private val autocryptPeerentityResult: AutocryptPeerResult?
|
||||
|
||||
private constructor(
|
||||
signatureStatus: Int,
|
||||
signatureUserId: String?,
|
||||
keyId: Long,
|
||||
userIds: ArrayList<String>?,
|
||||
confirmedUserIds: ArrayList<String>?,
|
||||
senderStatusResult: SenderStatusResult?,
|
||||
signatureOnly: Boolean?,
|
||||
signatureTimestamp: Date?,
|
||||
autocryptPeerentityResult: AutocryptPeerResult?
|
||||
) {
|
||||
result = signatureStatus
|
||||
primaryUserId = signatureUserId
|
||||
this.keyId = keyId
|
||||
this.userIds = userIds
|
||||
this.confirmedUserIds = confirmedUserIds
|
||||
this.senderStatusResult = senderStatusResult
|
||||
this.signatureTimestamp = signatureTimestamp
|
||||
this.autocryptPeerentityResult = autocryptPeerentityResult
|
||||
}
|
||||
|
||||
private constructor(source: Parcel, version: Int) {
|
||||
result = source.readInt()
|
||||
// we dropped support for signatureOnly, but need to skip the value for compatibility
|
||||
source.readByte()
|
||||
primaryUserId = source.readString()
|
||||
keyId = source.readLong()
|
||||
userIds = if (version > 1) {
|
||||
source.createStringArrayList()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
// backward compatibility for this exact version
|
||||
if (version > 2) {
|
||||
senderStatusResult = readEnumWithNullAndFallback(
|
||||
source,
|
||||
SenderStatusResult.values(),
|
||||
SenderStatusResult.UNKNOWN
|
||||
)
|
||||
confirmedUserIds = source.createStringArrayList()
|
||||
} else {
|
||||
senderStatusResult = SenderStatusResult.UNKNOWN
|
||||
confirmedUserIds = null
|
||||
}
|
||||
signatureTimestamp = if (version > 3) {
|
||||
if (source.readInt() > 0) Date(source.readLong()) else null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
autocryptPeerentityResult = if (version > 4) {
|
||||
readEnumWithNullAndFallback(
|
||||
source,
|
||||
AutocryptPeerResult.values(),
|
||||
null
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
public fun getUserIds(): List<String> {
|
||||
return (userIds ?: arrayListOf()).toList()
|
||||
}
|
||||
|
||||
public fun getConfirmedUserIds(): List<String> {
|
||||
return (confirmedUserIds ?: arrayListOf()).toList()
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
/**
|
||||
* NOTE: When adding fields in the process of updating this API, make sure to bump
|
||||
* [.PARCELABLE_VERSION].
|
||||
*/
|
||||
dest.writeInt(PARCELABLE_VERSION)
|
||||
// Inject a placeholder that will store the parcel size from this point on
|
||||
// (not including the size itself).
|
||||
val sizePosition = dest.dataPosition()
|
||||
dest.writeInt(0)
|
||||
val startPosition = dest.dataPosition()
|
||||
// version 1
|
||||
dest.writeInt(result)
|
||||
// signatureOnly is deprecated since version 3. we pass a dummy value for compatibility
|
||||
dest.writeByte(0.toByte())
|
||||
dest.writeString(primaryUserId)
|
||||
dest.writeLong(keyId)
|
||||
// version 2
|
||||
dest.writeStringList(userIds)
|
||||
// version 3
|
||||
writeEnumWithNull(dest, senderStatusResult)
|
||||
dest.writeStringList(confirmedUserIds)
|
||||
// version 4
|
||||
if (signatureTimestamp != null) {
|
||||
dest.writeInt(1)
|
||||
dest.writeLong(signatureTimestamp.time)
|
||||
} else {
|
||||
dest.writeInt(0)
|
||||
}
|
||||
// version 5
|
||||
writeEnumWithNull(dest, autocryptPeerentityResult)
|
||||
// Go back and write the size
|
||||
val parcelableSize = dest.dataPosition() - startPosition
|
||||
dest.setDataPosition(sizePosition)
|
||||
dest.writeInt(parcelableSize)
|
||||
dest.setDataPosition(startPosition + parcelableSize)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
var out = "\nresult: $result"
|
||||
out += "\nprimaryUserId: $primaryUserId"
|
||||
out += "\nuserIds: $userIds"
|
||||
out += "\nkeyId: " + OpenPgpUtils.convertKeyIdToHex(keyId)
|
||||
return out
|
||||
}
|
||||
|
||||
@Deprecated("")
|
||||
public fun withSignatureOnlyFlag(signatureOnly: Boolean): OpenPgpSignatureResult {
|
||||
return OpenPgpSignatureResult(
|
||||
result, primaryUserId, keyId, userIds, confirmedUserIds,
|
||||
senderStatusResult, signatureOnly, signatureTimestamp, autocryptPeerentityResult
|
||||
)
|
||||
}
|
||||
|
||||
public fun withAutocryptPeerResult(autocryptPeerentityResult: AutocryptPeerResult?): OpenPgpSignatureResult {
|
||||
return OpenPgpSignatureResult(
|
||||
result, primaryUserId, keyId, userIds, confirmedUserIds,
|
||||
senderStatusResult, null, signatureTimestamp, autocryptPeerentityResult
|
||||
)
|
||||
}
|
||||
|
||||
public enum class SenderStatusResult {
|
||||
UNKNOWN, USER_ID_CONFIRMED, USER_ID_UNCONFIRMED, USER_ID_MISSING;
|
||||
}
|
||||
|
||||
public enum class AutocryptPeerResult {
|
||||
OK, NEW, MISMATCH;
|
||||
}
|
||||
|
||||
public companion object CREATOR : Creator<OpenPgpSignatureResult> {
|
||||
|
||||
/**
|
||||
* Since there might be a case where new versions of the client using the library getting
|
||||
* old versions of the protocol (and thus old versions of this class), we need a versioning
|
||||
* system for the parcels sent between the clients and the providers.
|
||||
*/
|
||||
private const val PARCELABLE_VERSION = 5
|
||||
|
||||
// content not signed
|
||||
public const val RESULT_NO_SIGNATURE: Int = -1
|
||||
|
||||
// invalid signature!
|
||||
public const val RESULT_INVALID_SIGNATURE: Int = 0
|
||||
|
||||
// successfully verified signature, with confirmed key
|
||||
public const val RESULT_VALID_KEY_CONFIRMED: Int = 1
|
||||
|
||||
// no key was found for this signature verification
|
||||
public const val RESULT_KEY_MISSING: Int = 2
|
||||
|
||||
// successfully verified signature, but with unconfirmed key
|
||||
public const val RESULT_VALID_KEY_UNCONFIRMED: Int = 3
|
||||
|
||||
// key has been revoked -> invalid signature!
|
||||
public const val RESULT_INVALID_KEY_REVOKED: Int = 4
|
||||
|
||||
// key is expired -> invalid signature!
|
||||
public const val RESULT_INVALID_KEY_EXPIRED: Int = 5
|
||||
|
||||
// insecure cryptographic algorithms/protocol -> invalid signature!
|
||||
public const val RESULT_INVALID_KEY_INSECURE: Int = 6
|
||||
|
||||
override fun createFromParcel(source: Parcel): OpenPgpSignatureResult? {
|
||||
val version = source.readInt() // parcelableVersion
|
||||
val parcelableSize = source.readInt()
|
||||
val startPosition = source.dataPosition()
|
||||
val vr = OpenPgpSignatureResult(source, version)
|
||||
// skip over all fields added in future versions of this parcel
|
||||
source.setDataPosition(startPosition + parcelableSize)
|
||||
return vr
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<OpenPgpSignatureResult?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
|
||||
public fun createWithValidSignature(
|
||||
signatureStatus: Int,
|
||||
primaryUserId: String?,
|
||||
keyId: Long,
|
||||
userIds: ArrayList<String>?,
|
||||
confirmedUserIds: ArrayList<String>?,
|
||||
senderStatusResult: SenderStatusResult?,
|
||||
signatureTimestamp: Date?
|
||||
): OpenPgpSignatureResult {
|
||||
require(!(signatureStatus == RESULT_NO_SIGNATURE || signatureStatus == RESULT_KEY_MISSING || signatureStatus == RESULT_INVALID_SIGNATURE)) { "can only use this method for valid types of signatures" }
|
||||
return OpenPgpSignatureResult(
|
||||
signatureStatus, primaryUserId, keyId, userIds, confirmedUserIds,
|
||||
senderStatusResult, null, signatureTimestamp, null
|
||||
)
|
||||
}
|
||||
|
||||
public fun createWithNoSignature(): OpenPgpSignatureResult {
|
||||
return OpenPgpSignatureResult(
|
||||
RESULT_NO_SIGNATURE,
|
||||
null,
|
||||
0L,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
public fun createWithKeyMissing(keyId: Long, signatureTimestamp: Date?): OpenPgpSignatureResult {
|
||||
return OpenPgpSignatureResult(
|
||||
RESULT_KEY_MISSING,
|
||||
null,
|
||||
keyId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
signatureTimestamp,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
public fun createWithInvalidSignature(): OpenPgpSignatureResult {
|
||||
return OpenPgpSignatureResult(
|
||||
RESULT_INVALID_SIGNATURE,
|
||||
null,
|
||||
0L,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun <T : Enum<T>?> readEnumWithNullAndFallback(
|
||||
source: Parcel,
|
||||
enumValues: Array<T>,
|
||||
fallback: T?
|
||||
): T? {
|
||||
val valueOrdinal = source.readInt()
|
||||
if (valueOrdinal == -1) {
|
||||
return null
|
||||
}
|
||||
return if (valueOrdinal >= enumValues.size) {
|
||||
fallback
|
||||
} else enumValues[valueOrdinal]
|
||||
}
|
||||
|
||||
private fun writeEnumWithNull(dest: Parcel, enumValue: Enum<*>?) {
|
||||
if (enumValue == null) {
|
||||
dest.writeInt(-1)
|
||||
return
|
||||
}
|
||||
dest.writeInt(enumValue.ordinal)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
include(":autofill-parser")
|
||||
include(":app")
|
||||
include(":openpgp-ktx")
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
|
|
Loading…
Reference in a new issue