Skip to content

Commit 8266be3

Browse files
issue #1223 a port of Mime.processDecoded() (#1267)
* issue #1223 a port of Mime.processDecoded() * Fixed JUnit tests that relate to Android side.| #1267 * Fixed MsgBlockFactory.| #1267 * Fixes after code review * Fix javadoc comment Co-authored-by: Ivan Pizhenko <IvanPizhenko@users.noreply.github.com> Co-authored-by: DenBond7 <DenBond7@gmail.com>
1 parent e336f06 commit 8266be3

25 files changed

+1549
-16
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
3+
* Contributors:
4+
* Ivan Pizhenko
5+
*/
6+
7+
package com.flowcrypt.email.api.retrofit.response.model.node
8+
9+
import android.net.Uri
10+
import android.os.Parcel
11+
import android.os.Parcelable
12+
import com.google.gson.annotations.Expose
13+
14+
data class EncryptedAttMsgBlock(@Expose override val content: String?,
15+
@Expose val attMeta: AttMeta) : MsgBlock {
16+
17+
var fileUri: Uri? = null
18+
19+
@Expose
20+
override val complete: Boolean = true
21+
@Expose
22+
override val type: MsgBlock.Type = MsgBlock.Type.ENCRYPTED_ATT
23+
24+
constructor(source: Parcel) : this(
25+
source.readString(),
26+
source.readParcelable<AttMeta>(AttMeta::class.java.classLoader)!!
27+
) {
28+
fileUri = source.readParcelable<Uri>(Uri::class.java.classLoader)
29+
}
30+
31+
override fun describeContents(): Int {
32+
return 0
33+
}
34+
35+
override fun writeToParcel(dest: Parcel, flags: Int) =
36+
with(dest) {
37+
writeParcelable(type, flags)
38+
writeString(content)
39+
writeParcelable(attMeta, flags)
40+
writeParcelable(fileUri, flags)
41+
}
42+
43+
companion object {
44+
@JvmField
45+
val CREATOR: Parcelable.Creator<EncryptedAttMsgBlock> = object : Parcelable.Creator<EncryptedAttMsgBlock> {
46+
override fun createFromParcel(source: Parcel): EncryptedAttMsgBlock {
47+
source.readParcelable<MsgBlock.Type>(MsgBlock.Type::class.java.classLoader)
48+
return EncryptedAttMsgBlock(source)
49+
}
50+
51+
override fun newArray(size: Int): Array<EncryptedAttMsgBlock?> = arrayOfNulls(size)
52+
}
53+
}
54+
}

FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/model/node/GenericMsgBlock.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ data class GenericMsgBlock(
2727
@Expose override val complete: Boolean
2828
) : MsgBlock {
2929

30-
constructor(source: Parcel, type: MsgBlock.Type) : this(
30+
constructor(type: MsgBlock.Type, source: Parcel) : this(
3131
type,
3232
source.readString(),
3333
1 == source.readInt()
@@ -38,7 +38,7 @@ data class GenericMsgBlock(
3838
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
3939
writeParcelable(type, flags)
4040
writeString(content)
41-
writeInt((if (complete) 1 else 0))
41+
writeInt(if (complete) 1 else 0)
4242
}
4343

4444
companion object {

FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/model/node/MsgBlock.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package com.flowcrypt.email.api.retrofit.response.model.node
88
import android.os.Parcel
99
import android.os.Parcelable
1010
import com.google.gson.annotations.SerializedName
11+
import java.lang.IllegalArgumentException
1112

1213
interface MsgBlock : Parcelable {
1314
val type: Type
@@ -69,7 +70,13 @@ interface MsgBlock : Parcelable {
6970
CERTIFICATE,
7071

7172
@SerializedName("signature")
72-
SIGNATURE;
73+
SIGNATURE,
74+
75+
@SerializedName("signedText")
76+
SIGNED_TEXT,
77+
78+
@SerializedName("signedHtml")
79+
SIGNED_HTML;
7380

7481
override fun describeContents(): Int {
7582
return 0
@@ -87,12 +94,25 @@ interface MsgBlock : Parcelable {
8794
}
8895

8996
val keyBlockTypes = setOf(PUBLIC_KEY, PRIVATE_KEY)
97+
9098
val replaceableBlockTypes = setOf(
9199
PUBLIC_KEY, PRIVATE_KEY, SIGNED_MSG, ENCRYPTED_MSG, ENCRYPTED_MSG_LINK
92100
)
101+
93102
val wellKnownBlockTypes = setOf(
94103
PUBLIC_KEY, PRIVATE_KEY, SIGNED_MSG, ENCRYPTED_MSG
95104
)
105+
106+
val signedBlocks = setOf(SIGNED_TEXT, SIGNED_HTML, SIGNED_MSG)
107+
108+
fun ofSerializedName(serializedName: String): Type {
109+
for (v in values()) {
110+
val field = Type::class.java.getField(v.name)
111+
val annotation = field.getAnnotation(SerializedName::class.java)
112+
if (annotation != null && annotation.value == serializedName) return v
113+
}
114+
throw IllegalArgumentException("Unknown block type serialized name '$serializedName'")
115+
}
96116
}
97117
}
98118

FlowCrypt/src/main/java/com/flowcrypt/email/api/retrofit/response/model/node/MsgBlockFactory.kt

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ object MsgBlockFactory {
1212
val supportedMsgBlockTypes = listOf(
1313
MsgBlock.Type.PUBLIC_KEY,
1414
MsgBlock.Type.DECRYPT_ERROR,
15-
MsgBlock.Type.DECRYPTED_ATT
15+
MsgBlock.Type.DECRYPTED_ATT,
16+
MsgBlock.Type.ENCRYPTED_ATT,
17+
MsgBlock.Type.SIGNED_HTML,
18+
MsgBlock.Type.SIGNED_TEXT
1619
)
1720

1821
@JvmStatic
@@ -21,24 +24,41 @@ object MsgBlockFactory {
2124
MsgBlock.Type.PUBLIC_KEY -> PublicKeyMsgBlock(source)
2225
MsgBlock.Type.DECRYPT_ERROR -> DecryptErrorMsgBlock(source)
2326
MsgBlock.Type.DECRYPTED_ATT -> DecryptedAttMsgBlock(source)
24-
else -> GenericMsgBlock(source, type)
27+
MsgBlock.Type.ENCRYPTED_ATT -> EncryptedAttMsgBlock(source)
28+
MsgBlock.Type.SIGNED_TEXT, MsgBlock.Type.SIGNED_HTML, MsgBlock.Type.SIGNED_MSG -> {
29+
SignedBlock(source)
30+
}
31+
else -> GenericMsgBlock(type, source)
2532
}
2633
}
2734

2835
@JvmStatic
29-
fun fromContent(type: MsgBlock.Type, content: String, missingEnd: Boolean = false): MsgBlock {
36+
fun fromContent(
37+
type: MsgBlock.Type,
38+
content: String?,
39+
missingEnd: Boolean = false,
40+
signature: String? = null
41+
): MsgBlock {
3042
val complete = !missingEnd
3143
return when (type) {
3244
MsgBlock.Type.PUBLIC_KEY -> PublicKeyMsgBlock(content, complete, null)
3345
MsgBlock.Type.DECRYPT_ERROR -> DecryptErrorMsgBlock(content, complete, null)
46+
MsgBlock.Type.SIGNED_TEXT -> {
47+
SignedBlock(SignedBlock.Type.SIGNED_TEXT, content, complete, signature)
48+
}
49+
MsgBlock.Type.SIGNED_HTML -> {
50+
SignedBlock(SignedBlock.Type.SIGNED_HTML, content, complete, signature)
51+
}
3452
else -> GenericMsgBlock(type, content, complete)
3553
}
3654
}
3755

3856
@JvmStatic
39-
fun fromAttachment(type: MsgBlock.Type, content: String, attMeta: AttMeta): MsgBlock {
57+
fun fromAttachment(type: MsgBlock.Type, content: String?, attMeta: AttMeta): MsgBlock {
4058
return when (type) {
4159
MsgBlock.Type.DECRYPTED_ATT -> DecryptedAttMsgBlock(content, true, attMeta, null)
60+
MsgBlock.Type.ENCRYPTED_ATT -> EncryptedAttMsgBlock(content, attMeta)
61+
MsgBlock.Type.PLAIN_ATT -> PlainAttMsgBlock(content, attMeta)
4262
else ->
4363
throw IllegalArgumentException("Can't create block of type ${type.name} from attachment")
4464
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
3+
* Contributors:
4+
* Ivan Pizhenko
5+
*/
6+
7+
package com.flowcrypt.email.api.retrofit.response.model.node
8+
9+
import android.net.Uri
10+
import android.os.Parcel
11+
import android.os.Parcelable
12+
import com.google.gson.annotations.Expose
13+
14+
data class PlainAttMsgBlock(
15+
@Expose override val content: String?,
16+
@Expose val attMeta: AttMeta
17+
) : MsgBlock {
18+
19+
var fileUri: Uri? = null
20+
21+
@Expose
22+
override val complete: Boolean = true
23+
24+
@Expose
25+
override val type: MsgBlock.Type = MsgBlock.Type.PLAIN_ATT
26+
27+
constructor(source: Parcel) : this(
28+
source.readString(),
29+
source.readParcelable<AttMeta>(AttMeta::class.java.classLoader)!!
30+
) {
31+
fileUri = source.readParcelable(Uri::class.java.classLoader)
32+
}
33+
34+
override fun describeContents(): Int {
35+
return 0
36+
}
37+
38+
override fun writeToParcel(dest: Parcel, flags: Int) =
39+
with(dest) {
40+
writeParcelable(type, flags)
41+
writeString(content)
42+
writeParcelable(attMeta, flags)
43+
writeParcelable(fileUri, flags)
44+
}
45+
46+
companion object {
47+
@JvmField
48+
val CREATOR: Parcelable.Creator<PlainAttMsgBlock> = object : Parcelable.Creator<PlainAttMsgBlock> {
49+
override fun createFromParcel(source: Parcel): PlainAttMsgBlock {
50+
source.readParcelable<MsgBlock.Type>(MsgBlock.Type::class.java.classLoader)
51+
return PlainAttMsgBlock(source)
52+
}
53+
54+
override fun newArray(size: Int): Array<PlainAttMsgBlock?> = arrayOfNulls(size)
55+
}
56+
}
57+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
3+
* Contributors:
4+
* Ivan Pizhenko
5+
*/
6+
7+
package com.flowcrypt.email.api.retrofit.response.model.node
8+
9+
import android.os.Parcel
10+
import android.os.Parcelable
11+
import com.google.gson.annotations.Expose
12+
13+
/**
14+
* Message block which represents content with a signature.
15+
*/
16+
data class SignedBlock(
17+
@Expose val signedType: Type,
18+
@Expose override val content: String?,
19+
@Expose override val complete: Boolean,
20+
@Expose val signature: String?
21+
) : MsgBlock {
22+
23+
@Expose
24+
override val type: MsgBlock.Type = when (signedType) {
25+
Type.SIGNED_MSG -> MsgBlock.Type.SIGNED_MSG
26+
Type.SIGNED_TEXT -> MsgBlock.Type.SIGNED_TEXT
27+
Type.SIGNED_HTML -> MsgBlock.Type.SIGNED_HTML
28+
}
29+
30+
constructor(source: Parcel) : this(
31+
source.readParcelable<Type>(Type::class.java.classLoader)
32+
?: throw IllegalArgumentException("Undefined type"),
33+
source.readString(),
34+
1 == source.readInt(),
35+
source.readString()
36+
)
37+
38+
override fun describeContents() = 0
39+
40+
override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
41+
writeParcelable(type, flags)
42+
writeParcelable(signedType, flags)
43+
writeString(content)
44+
writeInt(if (complete) 1 else 0)
45+
writeString(signature)
46+
}
47+
48+
enum class Type : Parcelable {
49+
SIGNED_MSG,
50+
SIGNED_TEXT,
51+
SIGNED_HTML;
52+
53+
override fun describeContents(): Int {
54+
return 0
55+
}
56+
57+
override fun writeToParcel(dest: Parcel, flags: Int) {
58+
dest.writeInt(ordinal)
59+
}
60+
61+
companion object {
62+
@JvmField
63+
val CREATOR: Parcelable.Creator<Type> = object : Parcelable.Creator<Type> {
64+
override fun createFromParcel(source: Parcel): Type = values()[source.readInt()]
65+
override fun newArray(size: Int): Array<Type?> = arrayOfNulls(size)
66+
}
67+
}
68+
}
69+
70+
companion object {
71+
@JvmField
72+
val CREATOR: Parcelable.Creator<MsgBlock> = object : Parcelable.Creator<MsgBlock> {
73+
override fun createFromParcel(source: Parcel): MsgBlock {
74+
val partType = source.readParcelable<MsgBlock.Type>(MsgBlock.Type::class.java.classLoader)!!
75+
return MsgBlockFactory.fromParcel(partType, source)
76+
}
77+
78+
override fun newArray(size: Int): Array<MsgBlock?> = arrayOfNulls(size)
79+
}
80+
}
81+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
3+
* Contributors:
4+
* Ivan Pizhenko
5+
*/
6+
7+
package com.flowcrypt.email.extensions.javax.mail
8+
9+
import javax.mail.BodyPart
10+
import javax.mail.MessagingException
11+
12+
fun BodyPart.hasFileName(): Boolean {
13+
return try {
14+
this.fileName != null
15+
} catch (ex: MessagingException) {
16+
false
17+
}
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
3+
* Contributors:
4+
* Ivan Pizhenko
5+
*/
6+
7+
package com.flowcrypt.email.extensions.javax.mail
8+
9+
import java.util.Locale
10+
import javax.mail.Part
11+
12+
fun Part.isInline(): Boolean {
13+
return (this.disposition?.toLowerCase(Locale.getDefault()) ?: "") == Part.INLINE
14+
}

FlowCrypt/src/main/java/com/flowcrypt/email/extensions/kotlin/StringExt.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,11 @@ fun String.countOfMatchesZeroOneOrMore(needle: String): Int {
4444
}
4545
return result
4646
}
47+
48+
fun String.normalizeEol(): String {
49+
return this.replace("\r\n", "\n").replace('\r', '\n')
50+
}
51+
52+
fun String.removeUtf8Bom(): String {
53+
return if (this.startsWith("\uFEFF")) this.substring(1) else this
54+
}

FlowCrypt/src/main/java/com/flowcrypt/email/security/pgp/PgpArmor.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,19 @@ object PgpArmor {
260260
}
261261

262262
private val lineSeparatorBytes = Strings.lineSeparator().toByteArray()
263+
264+
@JvmStatic
265+
fun clip(text: String): String? {
266+
val unknown = ARMOR_HEADER_DICT[MsgBlock.Type.UNKNOWN]!!
267+
if (text.contains(unknown.begin) && text.contains(unknown.end)) {
268+
val match = blockRegex.find(text)
269+
if (match != null) return text.substring(match.range)
270+
}
271+
return null
272+
}
273+
274+
private val blockRegex = Regex(
275+
"(-----BEGIN PGP (MESSAGE|SIGNED MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----[\\s\\S]+" +
276+
"-----END PGP (MESSAGE|SIGNATURE|PUBLIC KEY BLOCK)-----)"
277+
)
263278
}

0 commit comments

Comments
 (0)