1
1
package org.exploit.keeper.db
2
2
3
3
import org.exploit.keeper.service.key.KeyOps
4
- import org.mapdb.DB
5
- import org.mapdb.DBMaker
6
- import org.mapdb.HTreeMap
7
- import org.mapdb.Serializer
8
- import org.slf4j.Logger
9
- import org.slf4j.LoggerFactory
4
+ import org.rocksdb.*
10
5
import java.io.Closeable
11
- import java.io.File
6
+ import java.nio.charset.StandardCharsets
12
7
13
8
class LMKDB (dbPath : String , private var opsProvider : () -> KeyOps ) : Closeable {
14
- private val db: DB = DBMaker .fileDB(File (dbPath))
15
- .fileMmapEnable()
16
- .transactionEnable()
17
- .make()
18
-
19
- val private : KeyStore = KeyStore (PRIVATE_KEY_MAP )
20
- val public: KeyStore = NoOpsKeyStore (PUBLIC_KEY_MAP )
9
+ private val db: TransactionDB
10
+ private val cfHandles: List <ColumnFamilyHandle >
11
+ private val writeOpts: WriteOptions
12
+ val private: KeyStore
13
+ val public: KeyStore
14
+
15
+ init {
16
+ RocksDB .loadLibrary()
17
+
18
+ writeOpts = WriteOptions ()
19
+
20
+ val options = DBOptions ()
21
+ .setCreateIfMissing(true )
22
+ .setCreateMissingColumnFamilies(true )
23
+
24
+ val txnOptions = TransactionDBOptions ()
25
+
26
+ val cfDescs = listOf (
27
+ ColumnFamilyDescriptor (RocksDB .DEFAULT_COLUMN_FAMILY ),
28
+ ColumnFamilyDescriptor (PRIVATE_KEY_MAP .toByteArray()),
29
+ ColumnFamilyDescriptor (PUBLIC_KEY_MAP .toByteArray())
30
+ )
31
+
32
+ val handles = ArrayList <ColumnFamilyHandle >()
33
+ db = TransactionDB .open(options, txnOptions, dbPath, cfDescs, handles)
34
+
35
+ cfHandles = handles
36
+ val cfMap = mapOf (
37
+ PRIVATE_KEY_MAP to cfHandles[1 ],
38
+ PUBLIC_KEY_MAP to cfHandles[2 ]
39
+ )
40
+ private = KeyStore (PRIVATE_KEY_MAP , cfMap[PRIVATE_KEY_MAP ]!! )
41
+ public = NoOpsKeyStore (PUBLIC_KEY_MAP , cfMap[PUBLIC_KEY_MAP ]!! )
42
+ }
21
43
22
44
fun isInitialized (): Boolean = private.hasKey(SENTINEL_KEY )
23
45
24
46
fun writeSentinel (ops : KeyOps ) = private.saveRaw(SENTINEL_KEY , ops.encrypt(SENTINEL_VAL ))
25
47
26
48
fun checkValidKey (ops : KeyOps ): Boolean =
27
- private.getRaw(SENTINEL_KEY )?.let { ops.decrypt(it).contentEquals(SENTINEL_VAL ) }
28
- ? : false
49
+ private.getRaw(SENTINEL_KEY )?.let { ops.decrypt(it).contentEquals(SENTINEL_VAL ) } ? : false
29
50
30
- override fun close () = db.close()
31
-
32
- open inner class KeyStore (val mapName : String ) {
33
- private val map: HTreeMap <String , ByteArray > by lazy {
34
- db.hashMap(mapName, Serializer .STRING , Serializer .BYTE_ARRAY ).createOrOpen()
35
- }
51
+ override fun close () {
52
+ cfHandles.forEach { it.close() }
53
+ db.close()
54
+ }
36
55
56
+ open inner class KeyStore (private val mapName : String , private val cf : ColumnFamilyHandle ) {
37
57
open fun save (id : String , raw : ByteArray ) {
38
58
val enc = opsProvider().encrypt(raw)
39
- map[id] = enc
40
- db.commit()
59
+ db.beginTransaction(writeOpts).use { tx ->
60
+ tx.put(cf, id.toByteArray(StandardCharsets .UTF_8 ), enc)
61
+ tx.commit()
62
+ }
41
63
}
42
64
43
65
open fun saveRaw (id : String , raw : ByteArray ) {
44
- map[id] = raw
45
- db.commit()
66
+ db.beginTransaction(writeOpts).use { tx ->
67
+ tx.put(cf, id.toByteArray(StandardCharsets .UTF_8 ), raw)
68
+ tx.commit()
69
+ }
46
70
}
47
71
48
72
open fun get (id : String ): ByteArray? =
49
- map[id] ?.let { opsProvider().decrypt(it) }
73
+ db.get(cf, id.toByteArray( StandardCharsets . UTF_8 )) ?.let { opsProvider().decrypt(it) }
50
74
51
75
open fun getRaw (id : String ): ByteArray? =
52
- map[id]
76
+ db.get(cf, id.toByteArray( StandardCharsets . UTF_8 ))
53
77
54
78
open fun hasKey (id : String ): Boolean =
55
- map.containsKey(id)
79
+ db.get(cf, id.toByteArray( StandardCharsets . UTF_8 )) != null
56
80
57
81
open fun delete (id : String ) {
58
- map.remove(id); db.commit()
82
+ db.beginTransaction(writeOpts).use { tx ->
83
+ tx.delete(cf, id.toByteArray(StandardCharsets .UTF_8 ))
84
+ tx.commit()
85
+ }
59
86
}
60
87
}
61
88
62
- inner class NoOpsKeyStore (mapName : String ) : KeyStore(mapName) {
89
+ inner class NoOpsKeyStore (mapName : String , private val cf : ColumnFamilyHandle ) : KeyStore(mapName, cf ) {
63
90
override fun save (id : String , raw : ByteArray ) {
64
- db.hashMap(mapName, Serializer .STRING , Serializer .BYTE_ARRAY )
65
- .createOrOpen()[id] = raw ; db.commit()
91
+ db.beginTransaction(writeOpts).use { tx ->
92
+ tx.put(cf, id.toByteArray(StandardCharsets .UTF_8 ), raw)
93
+ tx.commit()
94
+ }
66
95
}
96
+
67
97
override fun get (id : String ): ByteArray? =
68
- db.hashMap(mapName, Serializer .STRING , Serializer .BYTE_ARRAY )
69
- .createOrOpen()[id]
98
+ db.get(cf, id.toByteArray(StandardCharsets .UTF_8 ))
70
99
}
71
100
72
101
private companion object {
73
- val LOGGER : Logger = LoggerFactory .getLogger(LMKDB ::class .java)
74
- const val SENTINEL_KEY = " __meta__"
75
102
val SENTINEL_VAL = " BK-v1" .toByteArray()
76
103
104
+ const val SENTINEL_KEY = " __meta__"
77
105
const val PRIVATE_KEY_MAP = " privateKey"
78
- private const val PUBLIC_KEY_MAP = " publicKey"
106
+ const val PUBLIC_KEY_MAP = " publicKey"
79
107
}
80
108
}
0 commit comments