Skip to content

Commit 913d6cd

Browse files
committed
add EncryptedEventStream
1 parent 4a7732c commit 913d6cd

File tree

2 files changed

+103
-6
lines changed

2 files changed

+103
-6
lines changed

core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventStream.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ interface EventStream {
8585
fun readAsStream(source: String): InputStream?
8686
}
8787

88-
class InMemoryEventStream: EventStream {
89-
private val directory = ConcurrentHashMap<String, InMemoryFile>()
88+
open class InMemoryEventStream: EventStream {
89+
protected val directory = ConcurrentHashMap<String, InMemoryFile>()
9090

91-
private var currFile: InMemoryFile? = null
91+
protected open var currFile: InMemoryFile? = null
9292

9393
override val length: Long
9494
get() = (currFile?.length ?: 0).toLong()
@@ -154,7 +154,7 @@ class InMemoryEventStream: EventStream {
154154
}
155155
}
156156

157-
class FileEventStream(
157+
open class FileEventStream(
158158
internal val directory: File
159159
): EventStream {
160160

@@ -163,9 +163,9 @@ class FileEventStream(
163163
registerShutdownHook()
164164
}
165165

166-
private var fs: FileOutputStream? = null
166+
protected open var fs: FileOutputStream? = null
167167

168-
private var currFile: File? = null
168+
protected open var currFile: File? = null
169169

170170
override val length: Long
171171
get() = currFile?.length() ?: 0
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.segment.analytics.next
2+
3+
import com.segment.analytics.kotlin.core.Analytics
4+
import com.segment.analytics.kotlin.core.Storage
5+
import com.segment.analytics.kotlin.core.StorageProvider
6+
import com.segment.analytics.kotlin.core.utilities.FileEventStream
7+
import com.segment.analytics.kotlin.core.utilities.PropertiesFile
8+
import com.segment.analytics.kotlin.core.utilities.StorageImpl
9+
import java.io.File
10+
import java.io.FileOutputStream
11+
import java.io.InputStream
12+
import java.security.Key
13+
import javax.crypto.Cipher
14+
import javax.crypto.CipherInputStream
15+
import javax.crypto.CipherOutputStream
16+
import javax.crypto.KeyGenerator
17+
18+
class EncryptedEventStream(
19+
directory: File,
20+
private val key: Key
21+
) : FileEventStream(directory) {
22+
23+
private var cipherOutputStream: CipherOutputStream? = null
24+
25+
private val encryptedCipher = EncryptionUtil.getCipher(key, Cipher.ENCRYPT_MODE)
26+
27+
override var fs: FileOutputStream?
28+
get() = super.fs
29+
set(value) {
30+
if (value == null) {
31+
cipherOutputStream = null
32+
}
33+
else {
34+
cipherOutputStream = CipherOutputStream(value, encryptedCipher)
35+
}
36+
}
37+
38+
override fun write(content: String) {
39+
cipherOutputStream?.run {
40+
write(content.toByteArray())
41+
flush()
42+
}
43+
}
44+
45+
override fun close() {
46+
cipherOutputStream?.close()
47+
super.close()
48+
}
49+
50+
override fun readAsStream(source: String): InputStream? {
51+
val stream = super.readAsStream(source)
52+
return if (stream == null) {
53+
null
54+
} else {
55+
val cipher = EncryptionUtil.getCipher(key, Cipher.DECRYPT_MODE)
56+
CipherInputStream(super.readAsStream(source), cipher)
57+
}
58+
}
59+
}
60+
61+
object EncryptedStorageProvider : StorageProvider {
62+
63+
override fun createStorage(vararg params: Any): Storage {
64+
if (params.isEmpty() || params[0] !is Analytics || params[1] !is Key) {
65+
throw IllegalArgumentException("Invalid parameters for ConcreteStorageProvider. ConcreteStorageProvider requires at least 1 parameter and the first argument has to be an instance of Analytics")
66+
}
67+
68+
val analytics = params[0] as Analytics
69+
val key = params[1] as Key
70+
val config = analytics.configuration
71+
72+
val directory = File("/tmp/analytics-kotlin/${config.writeKey}")
73+
val eventDirectory = File(directory, "events")
74+
val fileIndexKey = "segment.events.file.index.${config.writeKey}"
75+
val userPrefs = File(directory, "analytics-kotlin-${config.writeKey}.properties")
76+
77+
val propertiesFile = PropertiesFile(userPrefs)
78+
val eventStream = EncryptedEventStream(eventDirectory, key)
79+
return StorageImpl(propertiesFile, eventStream, analytics.store, config.writeKey, fileIndexKey, analytics.fileIODispatcher)
80+
}
81+
}
82+
83+
object EncryptionUtil {
84+
private const val ALGORITHM = "AES"
85+
86+
fun generateKey(): Key {
87+
val keyGen = KeyGenerator.getInstance(ALGORITHM)
88+
keyGen.init(128) // AES 128-bit key
89+
return keyGen.generateKey()
90+
}
91+
92+
fun getCipher(key: Key, mode: Int): Cipher {
93+
val cipher = Cipher.getInstance(ALGORITHM)
94+
cipher.init(mode, key)
95+
return cipher
96+
}
97+
}

0 commit comments

Comments
 (0)