Skip to content

Commit

Permalink
- fix records parsing failure on unknown fields (now skips)
Browse files Browse the repository at this point in the history
- cleaned up decryptRecord()
  • Loading branch information
borrow-checker committed Sep 25, 2024
1 parent f7ec4fb commit a1cfa3d
Showing 1 changed file with 68 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,31 @@ data class KeeperFile(
val data: KeeperFileData,
val url: String,
val thumbnailUrl: String?
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as KeeperFile

if (!fileKey.contentEquals(other.fileKey)) return false
if (fileUid != other.fileUid) return false
if (data != other.data) return false
if (url != other.url) return false
if (thumbnailUrl != other.thumbnailUrl) return false

return true
}

override fun hashCode(): Int {
var result = fileKey.contentHashCode()
result = 31 * result + fileUid.hashCode()
result = 31 * result + data.hashCode()
result = 31 * result + url.hashCode()
result = 31 * result + (thumbnailUrl?.hashCode() ?: 0)
return result
}
}

data class KeeperFileUpload(
val name: String,
Expand Down Expand Up @@ -744,22 +768,18 @@ private fun fetchAndDecryptSecrets(
if (response.records != null) {
response.records.forEach {
val recordKey = decrypt(it.recordKey, appKey)
val decryptedRecord = decryptRecord(it, recordKey)
if (decryptedRecord != null) {
records.add(decryptedRecord)
}
decryptRecord(it, recordKey).onSuccess { keeperRecord -> records.add(keeperRecord) }
}
}
if (response.folders != null) {
response.folders.forEach { folder ->
val folderKey = decrypt(folder.folderKey, appKey)
folder.records!!.forEach { record ->
val recordKey = decrypt(record.recordKey, folderKey)
val decryptedRecord = decryptRecord(record, recordKey)
if (decryptedRecord != null) {
decryptedRecord.folderUid = folder.folderUid
decryptedRecord.folderKey = folderKey
records.add(decryptedRecord)
decryptRecord(record, recordKey).onSuccess { keeperRecord ->
keeperRecord.folderUid = folder.folderUid
keeperRecord.folderKey = folderKey
records.add(keeperRecord)
}
}
}
Expand All @@ -777,46 +797,45 @@ private fun fetchAndDecryptSecrets(
}

@ExperimentalSerializationApi
private fun decryptRecord(record: SecretsManagerResponseRecord, recordKey: ByteArray): KeeperRecord? {
val decryptedRecord = decrypt(record.data, recordKey)

val files: MutableList<KeeperFile> = mutableListOf()

if (record.files != null) {
record.files.forEach {
val fileKey = decrypt(it.fileKey, recordKey)
val decryptedFile = decrypt(it.data, fileKey)
files.add(
KeeperFile(
fileKey,
it.fileUid,
Json.decodeFromString(bytesToString(decryptedFile)),
it.url,
it.thumbnailUrl
)
)
}
}

// When SDK is behind/ahead of record/field type definitions then
// strict mapping between JSON attributes and object properties
// will fail on any unknown field/key - currently just log the error
// and continue without the field - nb! field will be lost on save
var recordData: KeeperRecordData? = null
try {
recordData = Json.decodeFromString<KeeperRecordData>(bytesToString(decryptedRecord))
} catch (e: Exception) {
// New/missing field: Polymorphic serializer was not found for class discriminator 'UNKNOWN'...
// New/missing field property (field def updated): Encountered unknown key 'UNKNOWN'.
// Avoid 'ignoreUnknownKeys = true' to prevent erasing new properties on save/update
println("Record ${record.recordUid} has unexpected data properties (ignored).\n"+
" Error parsing record type - KSM SDK is behind/ahead of record/field type definitions." +
" Please upgrade to latest version. If you need assistance please email support@keepersecurity.com")
//println(e.message)
recordData = nonStrictJson.decodeFromString<KeeperRecordData>(bytesToString(decryptedRecord))
private fun decryptRecord(encryptedRecord: SecretsManagerResponseRecord, recordKey: ByteArray): Result<KeeperRecord> {

val decryptedRecord = decrypt(encryptedRecord.data, recordKey)

val decryptedRecordFiles = encryptedRecord.files?.map { recordFile ->
val fileKey = decrypt(recordFile.fileKey, recordKey)
val decryptedFile = decrypt(recordFile.data, fileKey)
KeeperFile(
fileKey,
recordFile.fileUid,
Json.decodeFromString(bytesToString(decryptedFile)),
recordFile.url,
recordFile.thumbnailUrl
)
} ?: emptyList()

val recordData: KeeperRecordData = try {
Json.decodeFromString(bytesToString(decryptedRecord))
} catch (e: SerializationException) {
System.err.println(
"""
Record ${encryptedRecord.recordUid} has unexpected data properties (ignored).
Error parsing record type - KSM SDK is behind/ahead of record/field type definitions.
Please upgrade to latest version. If you need assistance please email
""".trimIndent()
)
return Result.failure(e)
}

return if (recordData != null) KeeperRecord(recordKey, record.recordUid, null, null, record.innerFolderUid, recordData, record.revision, files) else null
val keeperRecord = KeeperRecord(
recordKey = recordKey,
recordUid = encryptedRecord.recordUid,
folderUid = null,
folderKey = null,
innerFolderUid = encryptedRecord.innerFolderUid,
data = recordData,
revision = encryptedRecord.revision,
files = decryptedRecordFiles
)
return Result.success(keeperRecord)
}

@ExperimentalSerializationApi
Expand Down

0 comments on commit a1cfa3d

Please sign in to comment.