mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: UUIDUtils and fixed AAGUID #1421
This commit is contained in:
@@ -50,15 +50,15 @@ import com.google.android.material.tabs.TabLayout
|
|||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.activities.fragments.EntryFragment
|
import com.kunzisoft.keepass.activities.fragments.EntryFragment
|
||||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
|
||||||
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
|
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
|
||||||
import com.kunzisoft.keepass.adapters.TagsAdapter
|
import com.kunzisoft.keepass.adapters.TagsAdapter
|
||||||
|
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||||
|
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
|
||||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import com.kunzisoft.keepass.education.EntryActivityEducation
|
import com.kunzisoft.keepass.education.EntryActivityEducation
|
||||||
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
|
|
||||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||||
import com.kunzisoft.keepass.otp.OtpType
|
import com.kunzisoft.keepass.otp.OtpType
|
||||||
import com.kunzisoft.keepass.services.AttachmentFileNotificationService
|
import com.kunzisoft.keepass.services.AttachmentFileNotificationService
|
||||||
@@ -69,7 +69,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
|
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
|
||||||
import com.kunzisoft.keepass.view.WindowInsetPosition
|
import com.kunzisoft.keepass.view.WindowInsetPosition
|
||||||
import com.kunzisoft.keepass.view.applyWindowInsets
|
import com.kunzisoft.keepass.view.applyWindowInsets
|
||||||
@@ -257,7 +257,7 @@ class EntryActivity : DatabaseLockActivity() {
|
|||||||
mIcon = entryInfo.icon
|
mIcon = entryInfo.icon
|
||||||
// Assign title text
|
// Assign title text
|
||||||
val entryTitle =
|
val entryTitle =
|
||||||
if (entryInfo.title.isNotEmpty()) entryInfo.title else UuidUtil.toHexString(entryInfo.id)
|
entryInfo.title.ifEmpty { entryInfo.id.asHexString() }
|
||||||
collapsingToolbarLayout?.title = entryTitle
|
collapsingToolbarLayout?.title = entryTitle
|
||||||
toolbar?.title = entryTitle
|
toolbar?.title = entryTitle
|
||||||
// Assign tags
|
// Assign tags
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import com.kunzisoft.keepass.database.element.icon.IconImage
|
|||||||
import com.kunzisoft.keepass.model.GroupInfo
|
import com.kunzisoft.keepass.model.GroupInfo
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
import com.kunzisoft.keepass.utils.getParcelableCompat
|
import com.kunzisoft.keepass.utils.getParcelableCompat
|
||||||
import com.kunzisoft.keepass.view.DateTimeFieldView
|
import com.kunzisoft.keepass.view.DateTimeFieldView
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class GroupDialogFragment : DatabaseDialogFragment() {
|
|||||||
searchableView.text = stringFromInheritableBoolean(mGroupInfo.searchable)
|
searchableView.text = stringFromInheritableBoolean(mGroupInfo.searchable)
|
||||||
autoTypeView.text = stringFromInheritableBoolean(mGroupInfo.enableAutoType,
|
autoTypeView.text = stringFromInheritableBoolean(mGroupInfo.enableAutoType,
|
||||||
mGroupInfo.defaultAutoTypeSequence)
|
mGroupInfo.defaultAutoTypeSequence)
|
||||||
val uuid = UuidUtil.toHexString(mGroupInfo.id)
|
val uuid = mGroupInfo.id?.asHexString()
|
||||||
if (uuid == null || uuid.isEmpty()) {
|
if (uuid == null || uuid.isEmpty()) {
|
||||||
uuidContainerView.visibility = View.GONE
|
uuidContainerView.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.model.StreamDirection
|
|||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||||
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
import com.kunzisoft.keepass.view.TemplateView
|
import com.kunzisoft.keepass.view.TemplateView
|
||||||
import com.kunzisoft.keepass.view.hideByFading
|
import com.kunzisoft.keepass.view.hideByFading
|
||||||
import com.kunzisoft.keepass.view.showByFading
|
import com.kunzisoft.keepass.view.showByFading
|
||||||
@@ -184,7 +184,7 @@ class EntryFragment: DatabaseFragment() {
|
|||||||
// customDataView.text = entryInfo?.customData?.toString()
|
// customDataView.text = entryInfo?.customData?.toString()
|
||||||
|
|
||||||
// Assign special data
|
// Assign special data
|
||||||
uuidReferenceView.text = UuidUtil.toHexString(entryInfo?.id)
|
uuidReferenceView.text = entryInfo?.id?.asHexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showClipboardDialog() {
|
private fun showClipboardDialog() {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package com.kunzisoft.keepass.credentialprovider.passkey.data
|
package com.kunzisoft.keepass.credentialprovider.passkey.data
|
||||||
|
|
||||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.Base64Helper.Companion.b64Encode
|
import com.kunzisoft.keepass.credentialprovider.passkey.util.Base64Helper.Companion.b64Encode
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asUUIDBytes
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ class AuthenticatorAttestationResponse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun defaultAttestationObject(): ByteArray {
|
internal fun defaultAttestationObject(): ByteArray {
|
||||||
|
// https://www.w3.org/TR/webauthn-3/#attestation-object
|
||||||
val ao = mutableMapOf<String, Any>()
|
val ao = mutableMapOf<String, Any>()
|
||||||
ao.put("fmt", "none")
|
ao.put("fmt", "none")
|
||||||
ao.put("attStmt", emptyMap<Any, Any>())
|
ao.put("attStmt", emptyMap<Any, Any>())
|
||||||
@@ -80,7 +82,7 @@ class AuthenticatorAttestationResponse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// TODO Authenticator Attestation Global Unique Identifier
|
// Authenticator Attestation Global Unique Identifier
|
||||||
private val AAGUID = ByteArray(16) { 0 }
|
private val AAGUID: ByteArray = "eaecdef2-1c31-5634-8639-f1cbd9c00a08".asUUIDBytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,8 @@ package com.kunzisoft.keepass.database.element.entry
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asUUID
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class FieldReferencesEngine(private val mDatabase: DatabaseKDBX) {
|
class FieldReferencesEngine(private val mDatabase: DatabaseKDBX) {
|
||||||
@@ -79,7 +80,7 @@ class FieldReferencesEngine(private val mDatabase: DatabaseKDBX) {
|
|||||||
'A' -> entryFound?.decodeUrlKey(newRecursionLevel)
|
'A' -> entryFound?.decodeUrlKey(newRecursionLevel)
|
||||||
'P' -> entryFound?.decodePasswordKey(newRecursionLevel)
|
'P' -> entryFound?.decodePasswordKey(newRecursionLevel)
|
||||||
'N' -> entryFound?.decodeNotesKey(newRecursionLevel)
|
'N' -> entryFound?.decodeNotesKey(newRecursionLevel)
|
||||||
'I' -> UuidUtil.toHexString(entryFound?.nodeId?.id)
|
'I' -> entryFound?.nodeId?.id?.asHexString()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
refsCache[fullReference] = data
|
refsCache[fullReference] = data
|
||||||
@@ -127,7 +128,7 @@ class FieldReferencesEngine(private val mDatabase: DatabaseKDBX) {
|
|||||||
'P' -> mDatabase.getEntryByPassword(searchQuery, recursionLevel)
|
'P' -> mDatabase.getEntryByPassword(searchQuery, recursionLevel)
|
||||||
'N' -> mDatabase.getEntryByNotes(searchQuery, recursionLevel)
|
'N' -> mDatabase.getEntryByNotes(searchQuery, recursionLevel)
|
||||||
'I' -> {
|
'I' -> {
|
||||||
UuidUtil.fromHexString(searchQuery)?.let { uuid ->
|
searchQuery.asUUID()?.let { uuid ->
|
||||||
mDatabase.getEntryById(NodeIdUUID(uuid))
|
mDatabase.getEntryById(NodeIdUUID(uuid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ package com.kunzisoft.keepass.database.element.node
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.ParcelUuid
|
import android.os.ParcelUuid
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
import com.kunzisoft.keepass.utils.readParcelableCompat
|
import com.kunzisoft.keepass.utils.readParcelableCompat
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import java.util.UUID
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class NodeIdUUID : NodeId<UUID> {
|
class NodeIdUUID : NodeId<UUID> {
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class NodeIdUUID : NodeId<UUID> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return UuidUtil.toHexString(id) ?: id.toString()
|
return id.asHexString() ?: id.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toVisualString(): String {
|
override fun toVisualString(): String {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import com.kunzisoft.keepass.database.element.Field
|
|||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asUUID
|
||||||
|
|
||||||
class TemplateEngineCompatible(database: DatabaseKDBX): TemplateEngine(database) {
|
class TemplateEngineCompatible(database: DatabaseKDBX): TemplateEngine(database) {
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ class TemplateEngineCompatible(database: DatabaseKDBX): TemplateEngine(database)
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getTemplate(entryKDBX: EntryKDBX): Template? {
|
override fun getTemplate(entryKDBX: EntryKDBX): Template? {
|
||||||
UuidUtil.fromHexString(entryKDBX.getCustomFieldValue(TEMPLATE_ENTRY_UUID))?.let { templateUUID ->
|
entryKDBX.getCustomFieldValue(TEMPLATE_ENTRY_UUID).asUUID()?.let { templateUUID ->
|
||||||
return getTemplateByCache(templateUUID)
|
return getTemplateByCache(templateUUID)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@@ -48,7 +49,7 @@ class TemplateEngineCompatible(database: DatabaseKDBX): TemplateEngine(database)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getTemplateUUIDField(template: Template): Field? {
|
private fun getTemplateUUIDField(template: Template): Field? {
|
||||||
UuidUtil.toHexString(template.uuid)?.let { uuidString ->
|
template.uuid.asHexString()?.let { uuidString ->
|
||||||
return Field(TEMPLATE_ENTRY_UUID,
|
return Field(TEMPLATE_ENTRY_UUID,
|
||||||
ProtectedString(false, uuidString))
|
ProtectedString(false, uuidString))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import com.kunzisoft.keepass.model.PasskeyEntryFields.FIELD_RELYING_PARTY
|
|||||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskeyExclusion
|
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskeyExclusion
|
||||||
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_FIELD
|
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_FIELD
|
||||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOtpExclusion
|
import com.kunzisoft.keepass.otp.OtpEntryFields.isOtpExclusion
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
import com.kunzisoft.keepass.utils.inTheSameDomainAs
|
import com.kunzisoft.keepass.utils.inTheSameDomainAs
|
||||||
|
|
||||||
class SearchHelper {
|
class SearchHelper {
|
||||||
@@ -166,7 +166,7 @@ class SearchHelper {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (searchParameters.searchInUUIDs) {
|
if (searchParameters.searchInUUIDs) {
|
||||||
val hexString = UuidUtil.toHexString(entry.nodeId.id) ?: ""
|
val hexString = entry.nodeId.id.asHexString() ?: ""
|
||||||
if (checkSearchQuery(hexString, searchParameters))
|
if (checkSearchQuery(hexString, searchParameters))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
113
database/src/main/java/com/kunzisoft/keepass/utils/UUIDUtils.kt
Normal file
113
database/src/main/java/com/kunzisoft/keepass/utils/UUIDUtils.kt
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDX.
|
||||||
|
*
|
||||||
|
* KeePassDX is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDX is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.utils
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
object UUIDUtils {
|
||||||
|
fun UUID.asHexString(): String? {
|
||||||
|
try {
|
||||||
|
val buf = uuidTo16Bytes(this)
|
||||||
|
|
||||||
|
val len = buf.size
|
||||||
|
if (len == 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val sb = StringBuilder()
|
||||||
|
|
||||||
|
var bt: Short
|
||||||
|
var high: Char
|
||||||
|
var low: Char
|
||||||
|
for (b in buf) {
|
||||||
|
bt = (b.toInt() and 0xFF).toShort()
|
||||||
|
high = (bt.toInt() ushr 4).toChar()
|
||||||
|
low = (bt.toInt() and 0x0F).toChar()
|
||||||
|
sb.append(byteToChar(high))
|
||||||
|
sb.append(byteToChar(low))
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.asUUID(): UUID? {
|
||||||
|
if (this.length != 32) return null
|
||||||
|
|
||||||
|
val charArray = this.lowercase(Locale.getDefault()).toCharArray()
|
||||||
|
val leastSignificantChars = CharArray(16)
|
||||||
|
val mostSignificantChars = CharArray(16)
|
||||||
|
|
||||||
|
var i = 31
|
||||||
|
while (i >= 0) {
|
||||||
|
if (i >= 16) {
|
||||||
|
mostSignificantChars[32 - i] = charArray[i]
|
||||||
|
mostSignificantChars[31 - i] = charArray[i - 1]
|
||||||
|
} else {
|
||||||
|
leastSignificantChars[16 - i] = charArray[i]
|
||||||
|
leastSignificantChars[15 - i] = charArray[i - 1]
|
||||||
|
}
|
||||||
|
i = i - 2
|
||||||
|
}
|
||||||
|
val standardUUIDString = StringBuilder()
|
||||||
|
standardUUIDString.append(leastSignificantChars)
|
||||||
|
standardUUIDString.append(mostSignificantChars)
|
||||||
|
standardUUIDString.insert(8, '-')
|
||||||
|
standardUUIDString.insert(13, '-')
|
||||||
|
standardUUIDString.insert(18, '-')
|
||||||
|
standardUUIDString.insert(23, '-')
|
||||||
|
return try {
|
||||||
|
UUID.fromString(standardUUIDString.toString())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.asUUID(): UUID {
|
||||||
|
val bb = ByteBuffer.wrap(this)
|
||||||
|
val firstLong = bb.getLong()
|
||||||
|
val secondLong = bb.getLong()
|
||||||
|
return UUID(firstLong, secondLong)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun UUID.asBytes(): ByteArray {
|
||||||
|
return ByteBuffer.allocate(16).apply {
|
||||||
|
putLong(mostSignificantBits)
|
||||||
|
putLong(leastSignificantBits)
|
||||||
|
}.array()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.asUUIDBytes(): ByteArray {
|
||||||
|
return this.asUUID()?.asBytes() ?: ByteArray(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use short to represent unsigned byte
|
||||||
|
private fun byteToChar(bt: Char): Char {
|
||||||
|
return if (bt.code >= 10) {
|
||||||
|
('A'.code + bt.code - 10).toChar()
|
||||||
|
} else {
|
||||||
|
('0'.code + bt.code).toChar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
|
||||||
*
|
|
||||||
* This file is part of KeePassDX.
|
|
||||||
*
|
|
||||||
* KeePassDX is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* KeePassDX is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.kunzisoft.keepass.utils;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static com.kunzisoft.keepass.utils.StreamBytesUtilsKt.uuidTo16Bytes;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public class UuidUtil {
|
|
||||||
|
|
||||||
public static @Nullable String toHexString(@Nullable UUID uuid) {
|
|
||||||
if (uuid == null) { return null; }
|
|
||||||
try {
|
|
||||||
byte[] buf = uuidTo16Bytes(uuid);
|
|
||||||
|
|
||||||
int len = buf.length;
|
|
||||||
if (len == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
short bt;
|
|
||||||
char high, low;
|
|
||||||
for (byte b : buf) {
|
|
||||||
bt = (short) (b & 0xFF);
|
|
||||||
high = (char) (bt >>> 4);
|
|
||||||
low = (char) (bt & 0x0F);
|
|
||||||
sb.append(byteToChar(high));
|
|
||||||
sb.append(byteToChar(low));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @Nullable UUID fromHexString(@Nullable String hexString) {
|
|
||||||
if (hexString == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (hexString.length() != 32)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
char[] charArray = hexString.toLowerCase().toCharArray();
|
|
||||||
char[] leastSignificantChars = new char[16];
|
|
||||||
char[] mostSignificantChars = new char[16];
|
|
||||||
|
|
||||||
for (int i = 31; i >= 0; i = i-2) {
|
|
||||||
if (i >= 16) {
|
|
||||||
mostSignificantChars[32-i] = charArray[i];
|
|
||||||
mostSignificantChars[31-i] = charArray[i-1];
|
|
||||||
} else {
|
|
||||||
leastSignificantChars[16-i] = charArray[i];
|
|
||||||
leastSignificantChars[15-i] = charArray[i-1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StringBuilder standardUUIDString = new StringBuilder();
|
|
||||||
standardUUIDString.append(leastSignificantChars);
|
|
||||||
standardUUIDString.append(mostSignificantChars);
|
|
||||||
standardUUIDString.insert(8, '-');
|
|
||||||
standardUUIDString.insert(13, '-');
|
|
||||||
standardUUIDString.insert(18, '-');
|
|
||||||
standardUUIDString.insert(23, '-');
|
|
||||||
try {
|
|
||||||
return UUID.fromString(standardUUIDString.toString());
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use short to represent unsigned byte
|
|
||||||
private static char byteToChar(char bt) {
|
|
||||||
if (bt >= 10) {
|
|
||||||
return (char)('A' + bt - 10);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (char)('0' + bt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Jeremy Jamet / Kunzisoft.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDX.
|
||||||
|
*
|
||||||
|
* KeePassDX is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDX is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
package com.kunzisoft.keepass.tests.utils
|
package com.kunzisoft.keepass.tests.utils
|
||||||
|
|
||||||
import com.kunzisoft.keepass.utils.UuidUtil
|
import com.kunzisoft.keepass.utils.UUIDUtils.asBytes
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||||
|
import com.kunzisoft.keepass.utils.UUIDUtils.asUUID
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
class UUIDTest: TestCase() {
|
class UUIDTest: TestCase() {
|
||||||
|
|
||||||
fun testUUID() {
|
fun testUUIDString() {
|
||||||
val randomUUID = UUID.randomUUID()
|
val randomUUID = UUID.randomUUID()
|
||||||
val hexStringUUID = UuidUtil.toHexString(randomUUID)
|
val hexStringUUID = randomUUID.asHexString()
|
||||||
val retrievedUUID = UuidUtil.fromHexString(hexStringUUID)
|
val retrievedUUID = hexStringUUID?.asUUID()
|
||||||
|
assertEquals(randomUUID, retrievedUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testUUIDBytes() {
|
||||||
|
val randomUUID = UUID.randomUUID()
|
||||||
|
val byteArrayUUID = randomUUID.asBytes()
|
||||||
|
val retrievedUUID = byteArrayUUID.asUUID()
|
||||||
assertEquals(randomUUID, retrievedUUID)
|
assertEquals(randomUUID, retrievedUUID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user