mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Merge branch 'feature/javaLang_ClassCastException' into develop
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
KeePassDX(2.8)
|
||||
*
|
||||
* Fix TOTP period (> 60s)
|
||||
|
||||
KeePassDX(2.7)
|
||||
* Add blocklists for autofill
|
||||
|
||||
@@ -6,23 +6,23 @@ import junit.framework.TestCase
|
||||
class UnsignedIntTest: TestCase() {
|
||||
|
||||
fun testUInt() {
|
||||
val standardInt = UnsignedInt(15).toInt()
|
||||
val standardInt = UnsignedInt(15).toKotlinInt()
|
||||
assertEquals(15, standardInt)
|
||||
val unsignedInt = UnsignedInt(-1).toLong()
|
||||
val unsignedInt = UnsignedInt(-1).toKotlinLong()
|
||||
assertEquals(4294967295L, unsignedInt)
|
||||
}
|
||||
|
||||
fun testMaxValue() {
|
||||
val maxValue = UnsignedInt.MAX_VALUE.toLong()
|
||||
val maxValue = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
assertEquals(4294967295L, maxValue)
|
||||
val longValue = UnsignedInt.fromLong(4294967295L).toLong()
|
||||
val longValue = UnsignedInt.fromKotlinLong(4294967295L).toKotlinLong()
|
||||
assertEquals(longValue, maxValue)
|
||||
}
|
||||
|
||||
fun testLong() {
|
||||
val longValue = UnsignedInt.fromLong(50L).toInt()
|
||||
val longValue = UnsignedInt.fromKotlinLong(50L).toKotlinInt()
|
||||
assertEquals(50, longValue)
|
||||
val uIntLongValue = UnsignedInt.fromLong(4294967290).toLong()
|
||||
val uIntLongValue = UnsignedInt.fromKotlinLong(4294967290).toKotlinLong()
|
||||
assertEquals(4294967290, uIntLongValue)
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class ValuesTest : TestCase() {
|
||||
}
|
||||
|
||||
private fun testReadWriteByte(value: Byte) {
|
||||
val dest: Byte = UnsignedInt(UnsignedInt.fromByte(value)).toByte()
|
||||
val dest: Byte = UnsignedInt(UnsignedInt.fromKotlinByte(value)).toKotlinByte()
|
||||
assert(value == dest)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
||||
UnsignedInt(it)
|
||||
}
|
||||
val memory = kdfParameters.getUInt64(PARAM_MEMORY)?.div(MEMORY_BLOCK_SIZE)?.let {
|
||||
UnsignedInt.fromLong(it)
|
||||
UnsignedInt.fromKotlinLong(it)
|
||||
}
|
||||
val iterations = kdfParameters.getUInt64(PARAM_ITERATIONS)?.let {
|
||||
UnsignedInt.fromLong(it)
|
||||
UnsignedInt.fromKotlinLong(it)
|
||||
}
|
||||
val version = kdfParameters.getUInt32(PARAM_VERSION)?.let {
|
||||
UnsignedInt(it)
|
||||
@@ -124,16 +124,16 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
||||
|
||||
override fun getParallelism(kdfParameters: KdfParameters): Long {
|
||||
return kdfParameters.getUInt32(PARAM_PARALLELISM)?.let {
|
||||
UnsignedInt(it).toLong()
|
||||
UnsignedInt(it).toKotlinLong()
|
||||
} ?: defaultParallelism
|
||||
}
|
||||
|
||||
override fun setParallelism(kdfParameters: KdfParameters, parallelism: Long) {
|
||||
kdfParameters.setUInt32(PARAM_PARALLELISM, UnsignedInt.fromLong(parallelism))
|
||||
kdfParameters.setUInt32(PARAM_PARALLELISM, UnsignedInt.fromKotlinLong(parallelism))
|
||||
}
|
||||
|
||||
override val defaultParallelism: Long
|
||||
get() = DEFAULT_PARALLELISM.toLong()
|
||||
get() = DEFAULT_PARALLELISM.toKotlinLong()
|
||||
|
||||
override val minParallelism: Long
|
||||
get() = MIN_PARALLELISM
|
||||
@@ -173,13 +173,13 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
||||
private val MAX_VERSION = UnsignedInt(0x13)
|
||||
|
||||
private const val MIN_SALT = 8
|
||||
private val MAX_SALT = UnsignedInt.MAX_VALUE.toLong()
|
||||
private val MAX_SALT = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
|
||||
private const val MIN_ITERATIONS: Long = 1L
|
||||
private const val MAX_ITERATIONS = 4294967295L
|
||||
|
||||
private const val MIN_MEMORY = (1024 * 8).toLong()
|
||||
private val MAX_MEMORY = UnsignedInt.MAX_VALUE.toLong()
|
||||
private val MAX_MEMORY = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
private const val MEMORY_BLOCK_SIZE: Long = 1024L
|
||||
|
||||
private const val MIN_PARALLELISM: Long = 1L
|
||||
|
||||
@@ -34,12 +34,12 @@ public class Argon2Native {
|
||||
return nTransformMasterKey(
|
||||
password,
|
||||
salt,
|
||||
parallelism.toInt(),
|
||||
memory.toInt(),
|
||||
iterations.toInt(),
|
||||
parallelism.toKotlinInt(),
|
||||
memory.toKotlinInt(),
|
||||
iterations.toKotlinInt(),
|
||||
secretKey,
|
||||
associatedData,
|
||||
version.toInt());
|
||||
version.toKotlinInt());
|
||||
}
|
||||
|
||||
private static native byte[] nTransformMasterKey(byte[] password, byte[] salt, int parallelism,
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class KdfEngine : ObjectNameResource, Serializable {
|
||||
get() = 1
|
||||
|
||||
open val maxKeyRounds: Long
|
||||
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||
get() = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
|
||||
/*
|
||||
* MEMORY
|
||||
@@ -73,7 +73,7 @@ abstract class KdfEngine : ObjectNameResource, Serializable {
|
||||
get() = 1
|
||||
|
||||
open val maxMemoryUsage: Long
|
||||
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||
get() = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
|
||||
/*
|
||||
* PARALLELISM
|
||||
@@ -94,7 +94,7 @@ abstract class KdfEngine : ObjectNameResource, Serializable {
|
||||
get() = 1L
|
||||
|
||||
open val maxParallelism: Long
|
||||
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||
get() = UnsignedInt.MAX_VALUE.toKotlinLong()
|
||||
|
||||
companion object {
|
||||
const val UNKNOWN_VALUE: Long = -1L
|
||||
|
||||
@@ -58,7 +58,7 @@ class AutoType : Parcelable {
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeByte((if (enabled) 1 else 0).toByte())
|
||||
dest.writeInt(obfuscationOptions.toInt())
|
||||
dest.writeInt(obfuscationOptions.toKotlinInt())
|
||||
dest.writeString(defaultSequence)
|
||||
ParcelableUtil.writeStringParcelableMap(dest, windowSeqPairs)
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeParcelable(iconCustom, flags)
|
||||
dest.writeLong(usageCount.toLong())
|
||||
dest.writeLong(usageCount.toKotlinLong())
|
||||
dest.writeParcelable(locationChanged, flags)
|
||||
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
||||
ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
|
||||
@@ -334,7 +334,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
||||
override fun touch(modified: Boolean, touchParents: Boolean) {
|
||||
super.touch(modified, touchParents)
|
||||
// TODO unsigned long
|
||||
usageCount = UnsignedLong(usageCount.toLong() + 1)
|
||||
usageCount = UnsignedLong(usageCount.toKotlinLong() + 1)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -102,7 +102,7 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeParcelable(iconCustom, flags)
|
||||
dest.writeLong(usageCount.toLong())
|
||||
dest.writeLong(usageCount.toKotlinLong())
|
||||
dest.writeParcelable(locationChanged, flags)
|
||||
// TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeString(notes)
|
||||
|
||||
@@ -97,11 +97,11 @@ class DatabaseHeaderKDB : DatabaseHeader() {
|
||||
const val BUF_SIZE = 124
|
||||
|
||||
fun matchesHeader(sig1: UnsignedInt, sig2: UnsignedInt): Boolean {
|
||||
return sig1.toInt() == PWM_DBSIG_1.toInt() && sig2.toInt() == DBSIG_2.toInt()
|
||||
return sig1.toKotlinInt() == PWM_DBSIG_1.toKotlinInt() && sig2.toKotlinInt() == DBSIG_2.toKotlinInt()
|
||||
}
|
||||
|
||||
fun compatibleHeaders(one: UnsignedInt, two: UnsignedInt): Boolean {
|
||||
return one.toInt() and -0x100 == two.toInt() and -0x100
|
||||
return one.toKotlinInt() and -0x100 == two.toKotlinInt() and -0x100
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,10 +176,10 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
private fun readHeaderField(dis: LittleEndianDataInputStream): Boolean {
|
||||
val fieldID = dis.read().toByte()
|
||||
|
||||
val fieldSize: Int = if (version.toLong() < FILE_VERSION_32_4.toLong()) {
|
||||
val fieldSize: Int = if (version.toKotlinLong() < FILE_VERSION_32_4.toKotlinLong()) {
|
||||
dis.readUShort()
|
||||
} else {
|
||||
dis.readUInt().toInt()
|
||||
dis.readUInt().toKotlinInt()
|
||||
}
|
||||
|
||||
var fieldData: ByteArray? = null
|
||||
@@ -202,20 +202,20 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
|
||||
PwDbHeaderV4Fields.MasterSeed -> masterSeed = fieldData
|
||||
|
||||
PwDbHeaderV4Fields.TransformSeed -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||
PwDbHeaderV4Fields.TransformSeed -> if (version.toKotlinLong() < FILE_VERSION_32_4.toKotlinLong())
|
||||
transformSeed = fieldData
|
||||
|
||||
PwDbHeaderV4Fields.TransformRounds -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||
PwDbHeaderV4Fields.TransformRounds -> if (version.toKotlinLong() < FILE_VERSION_32_4.toKotlinLong())
|
||||
setTransformRound(fieldData)
|
||||
|
||||
PwDbHeaderV4Fields.EncryptionIV -> encryptionIV = fieldData
|
||||
|
||||
PwDbHeaderV4Fields.InnerRandomstreamKey -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||
PwDbHeaderV4Fields.InnerRandomstreamKey -> if (version.toKotlinLong() < FILE_VERSION_32_4.toKotlinLong())
|
||||
innerRandomStreamKey = fieldData
|
||||
|
||||
PwDbHeaderV4Fields.StreamStartBytes -> streamStartBytes = fieldData
|
||||
|
||||
PwDbHeaderV4Fields.InnerRandomStreamID -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||
PwDbHeaderV4Fields.InnerRandomStreamID -> if (version.toKotlinLong() < FILE_VERSION_32_4.toKotlinLong())
|
||||
setRandomStreamID(fieldData)
|
||||
|
||||
PwDbHeaderV4Fields.KdfParameters -> databaseV4.kdfParameters = KdfParameters.deserialize(fieldData)
|
||||
@@ -261,7 +261,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
}
|
||||
|
||||
val flag = bytes4ToUInt(pbFlags)
|
||||
if (flag.toLong() < 0 || flag.toLong() >= CompressionAlgorithm.values().size) {
|
||||
if (flag.toKotlinLong() < 0 || flag.toKotlinLong() >= CompressionAlgorithm.values().size) {
|
||||
throw IOException("Unrecognized compression flag.")
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
}
|
||||
|
||||
val id = bytes4ToUInt(streamID)
|
||||
if (id.toInt() < 0 || id.toInt() >= CrsAlgorithm.values().size) {
|
||||
if (id.toKotlinInt() < 0 || id.toKotlinInt() >= CrsAlgorithm.values().size) {
|
||||
throw IOException("Invalid stream id.")
|
||||
}
|
||||
|
||||
@@ -292,8 +292,8 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
* @return true if it's a supported version
|
||||
*/
|
||||
private fun validVersion(version: UnsignedInt): Boolean {
|
||||
return version.toInt() and FILE_VERSION_CRITICAL_MASK.toInt() <=
|
||||
FILE_VERSION_32_4.toInt() and FILE_VERSION_CRITICAL_MASK.toInt()
|
||||
return version.toKotlinInt() and FILE_VERSION_CRITICAL_MASK.toKotlinInt() <=
|
||||
FILE_VERSION_32_4.toKotlinInt() and FILE_VERSION_CRITICAL_MASK.toKotlinInt()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -306,7 +306,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
val FILE_VERSION_32_4 = UnsignedInt(0x00040000)
|
||||
|
||||
fun getCompressionFromFlag(flag: UnsignedInt): CompressionAlgorithm? {
|
||||
return when (flag.toInt()) {
|
||||
return when (flag.toKotlinInt()) {
|
||||
0 -> CompressionAlgorithm.None
|
||||
1 -> CompressionAlgorithm.GZip
|
||||
else -> null
|
||||
|
||||
@@ -90,16 +90,16 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
|
||||
// Select algorithm
|
||||
when {
|
||||
header.flags.toInt() and DatabaseHeaderKDB.FLAG_RIJNDAEL.toInt() != 0 -> {
|
||||
header.flags.toKotlinInt() and DatabaseHeaderKDB.FLAG_RIJNDAEL.toKotlinInt() != 0 -> {
|
||||
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.AESRijndael
|
||||
}
|
||||
header.flags.toInt() and DatabaseHeaderKDB.FLAG_TWOFISH.toInt() != 0 -> {
|
||||
header.flags.toKotlinInt() and DatabaseHeaderKDB.FLAG_TWOFISH.toKotlinInt() != 0 -> {
|
||||
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.Twofish
|
||||
}
|
||||
else -> throw InvalidAlgorithmDatabaseException()
|
||||
}
|
||||
|
||||
mDatabaseToOpen.numberKeyEncryptionRounds = header.numKeyEncRounds.toLong()
|
||||
mDatabaseToOpen.numberKeyEncryptionRounds = header.numKeyEncRounds.toKotlinLong()
|
||||
|
||||
// Generate transformedMasterKey from masterKey
|
||||
mDatabaseToOpen.makeFinalKey(
|
||||
@@ -160,11 +160,11 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
var newEntry: EntryKDB? = null
|
||||
var currentGroupNumber = 0
|
||||
var currentEntryNumber = 0
|
||||
while (currentGroupNumber < header.numGroups.toLong()
|
||||
|| currentEntryNumber < header.numEntries.toLong()) {
|
||||
while (currentGroupNumber < header.numGroups.toKotlinLong()
|
||||
|| currentEntryNumber < header.numEntries.toKotlinLong()) {
|
||||
|
||||
val fieldType = cipherInputStream.readBytes2ToUShort()
|
||||
val fieldSize = cipherInputStream.readBytes4ToUInt().toInt()
|
||||
val fieldSize = cipherInputStream.readBytes4ToUInt().toKotlinInt()
|
||||
|
||||
when (fieldType) {
|
||||
0x0000 -> {
|
||||
@@ -175,7 +175,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
when (fieldSize) {
|
||||
4 -> {
|
||||
newGroup = mDatabaseToOpen.createGroup().apply {
|
||||
setGroupId(cipherInputStream.readBytes4ToUInt().toInt())
|
||||
setGroupId(cipherInputStream.readBytes4ToUInt().toKotlinInt())
|
||||
}
|
||||
}
|
||||
16 -> {
|
||||
@@ -194,7 +194,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
} ?:
|
||||
newEntry?.let { entry ->
|
||||
val groupKDB = mDatabaseToOpen.createGroup()
|
||||
groupKDB.nodeId = NodeIdInt(cipherInputStream.readBytes4ToUInt().toInt())
|
||||
groupKDB.nodeId = NodeIdInt(cipherInputStream.readBytes4ToUInt().toKotlinInt())
|
||||
entry.parent = groupKDB
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
group.creationTime = cipherInputStream.readBytes5ToDate()
|
||||
} ?:
|
||||
newEntry?.let { entry ->
|
||||
var iconId = cipherInputStream.readBytes4ToUInt().toInt()
|
||||
var iconId = cipherInputStream.readBytes4ToUInt().toKotlinInt()
|
||||
// Clean up after bug that set icon ids to -1
|
||||
if (iconId == -1) {
|
||||
iconId = 0
|
||||
@@ -237,7 +237,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
}
|
||||
0x0007 -> {
|
||||
newGroup?.let { group ->
|
||||
group.icon = mDatabaseToOpen.iconFactory.getIcon(cipherInputStream.readBytes4ToUInt().toInt())
|
||||
group.icon = mDatabaseToOpen.iconFactory.getIcon(cipherInputStream.readBytes4ToUInt().toKotlinInt())
|
||||
} ?:
|
||||
newEntry?.let { entry ->
|
||||
entry.password = cipherInputStream.readBytesToString(fieldSize,false)
|
||||
@@ -253,7 +253,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
||||
}
|
||||
0x0009 -> {
|
||||
newGroup?.let { group ->
|
||||
group.groupFlags = cipherInputStream.readBytes4ToUInt().toInt()
|
||||
group.groupFlags = cipherInputStream.readBytes4ToUInt().toKotlinInt()
|
||||
} ?:
|
||||
newEntry?.let { entry ->
|
||||
entry.creationTime = cipherInputStream.readBytes5ToDate()
|
||||
|
||||
@@ -132,7 +132,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
}
|
||||
|
||||
val isPlain: InputStream
|
||||
if (mDatabase.kdbxVersion.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (mDatabase.kdbxVersion.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
|
||||
val decrypted = attachCipherStream(databaseInputStream, cipher)
|
||||
val dataDecrypted = LittleEndianDataInputStream(decrypted)
|
||||
@@ -180,7 +180,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
else -> isPlain
|
||||
}
|
||||
|
||||
if (mDatabase.kdbxVersion.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (mDatabase.kdbxVersion.toKotlinLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
loadInnerHeader(inputStreamXml, header)
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
header: DatabaseHeaderKDBX): Boolean {
|
||||
val fieldId = dataInputStream.read().toByte()
|
||||
|
||||
val size = dataInputStream.readUInt().toInt()
|
||||
val size = dataInputStream.readUInt().toKotlinInt()
|
||||
if (size < 0) throw IOException("Corrupted file")
|
||||
|
||||
var data = ByteArray(0)
|
||||
@@ -492,7 +492,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemNotes, ignoreCase = true)) {
|
||||
ctxGroup?.notes = readString(xpp)
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||
ctxGroup?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toInt())
|
||||
ctxGroup?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||
ctxGroup?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemTimes, ignoreCase = true)) {
|
||||
@@ -546,7 +546,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
KdbContext.Entry -> if (name.equals(DatabaseKDBXXML.ElemUuid, ignoreCase = true)) {
|
||||
ctxEntry?.nodeId = NodeIdUUID(readUuid(xpp))
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toInt())
|
||||
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toKotlinInt())
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||
ctxEntry?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
||||
} else if (name.equals(DatabaseKDBXXML.ElemFgColor, ignoreCase = true)) {
|
||||
@@ -819,7 +819,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
val sDate = readString(xpp)
|
||||
var utcDate: Date? = null
|
||||
|
||||
if (mDatabase.kdbxVersion.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (mDatabase.kdbxVersion.toKotlinLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
var buf = Base64.decode(sDate, BASE_64_FLAG)
|
||||
if (buf.size != 8) {
|
||||
val buf8 = ByteArray(8)
|
||||
|
||||
@@ -90,7 +90,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, uIntTo4Bytes(DatabaseHeaderKDBX.getFlagFromCompression(databaseKDBX.compressionAlgorithm)))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)
|
||||
|
||||
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformSeed, header.transformSeed)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformRounds, longTo8Bytes(databaseKDBX.numberKeyEncryptionRounds))
|
||||
} else {
|
||||
@@ -101,7 +101,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.EncryptionIV, header.encryptionIV)
|
||||
}
|
||||
|
||||
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomstreamKey, header.innerRandomStreamKey)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.StreamStartBytes, header.streamStartBytes)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomStreamID, uIntTo4Bytes(header.innerRandomStream!!.id))
|
||||
@@ -136,7 +136,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun writeHeaderFieldSize(size: Int) {
|
||||
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
los.writeUShort(size)
|
||||
} else {
|
||||
los.writeInt(size)
|
||||
|
||||
@@ -40,7 +40,7 @@ class DatabaseInnerHeaderOutputKDBX(private val database: DatabaseKDBX,
|
||||
dataOutputStream.writeInt(4)
|
||||
if (header.innerRandomStream == null)
|
||||
throw IOException("Can't write innerRandomStream")
|
||||
dataOutputStream.writeInt(header.innerRandomStream!!.id.toInt())
|
||||
dataOutputStream.writeInt(header.innerRandomStream!!.id.toKotlinInt())
|
||||
|
||||
val streamKeySize = header.innerRandomStreamKey.size
|
||||
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.InnerRandomstreamKey.toInt())
|
||||
|
||||
@@ -118,10 +118,10 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
|
||||
|
||||
when {
|
||||
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.AESRijndael -> {
|
||||
header.flags = UnsignedInt(header.flags.toInt() or DatabaseHeaderKDB.FLAG_RIJNDAEL.toInt())
|
||||
header.flags = UnsignedInt(header.flags.toKotlinInt() or DatabaseHeaderKDB.FLAG_RIJNDAEL.toKotlinInt())
|
||||
}
|
||||
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.Twofish -> {
|
||||
header.flags = UnsignedInt(header.flags.toInt() or DatabaseHeaderKDB.FLAG_TWOFISH.toInt())
|
||||
header.flags = UnsignedInt(header.flags.toKotlinInt() or DatabaseHeaderKDB.FLAG_TWOFISH.toKotlinInt())
|
||||
}
|
||||
else -> throw DatabaseOutputException("Unsupported algorithm.")
|
||||
}
|
||||
@@ -129,7 +129,7 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
|
||||
header.version = DatabaseHeaderKDB.DBVER_DW
|
||||
header.numGroups = UnsignedInt(mDatabaseKDB.numberOfGroups())
|
||||
header.numEntries = UnsignedInt(mDatabaseKDB.numberOfEntries())
|
||||
header.numKeyEncRounds = UnsignedInt.fromLong(mDatabaseKDB.numberKeyEncryptionRounds)
|
||||
header.numKeyEncRounds = UnsignedInt.fromKotlinLong(mDatabaseKDB.numberKeyEncryptionRounds)
|
||||
|
||||
setIVs(header)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
header = outputHeader(mOS)
|
||||
|
||||
val osPlain: OutputStream
|
||||
osPlain = if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
osPlain = if (header!!.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
val cos = attachStreamEncryptor(header!!, mOS)
|
||||
cos.write(header!!.streamStartBytes)
|
||||
|
||||
@@ -105,7 +105,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
else -> osPlain
|
||||
}
|
||||
|
||||
if (header!!.version.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header!!.version.toKotlinLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
val ihOut = DatabaseInnerHeaderOutputKDBX(mDatabaseKDBX, header!!, osXml)
|
||||
ihOut.output()
|
||||
}
|
||||
@@ -209,7 +209,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
writeObject(DatabaseKDBXXML.ElemDbDescChanged, mDatabaseKDBX.descriptionChanged.date)
|
||||
writeObject(DatabaseKDBXXML.ElemDbDefaultUser, mDatabaseKDBX.defaultUserName, true)
|
||||
writeObject(DatabaseKDBXXML.ElemDbDefaultUserChanged, mDatabaseKDBX.defaultUserNameChanged.date)
|
||||
writeObject(DatabaseKDBXXML.ElemDbMntncHistoryDays, mDatabaseKDBX.maintenanceHistoryDays.toLong())
|
||||
writeObject(DatabaseKDBXXML.ElemDbMntncHistoryDays, mDatabaseKDBX.maintenanceHistoryDays.toKotlinLong())
|
||||
writeObject(DatabaseKDBXXML.ElemDbColor, mDatabaseKDBX.color)
|
||||
writeObject(DatabaseKDBXXML.ElemDbKeyChanged, mDatabaseKDBX.keyLastChanged.date)
|
||||
writeObject(DatabaseKDBXXML.ElemDbKeyChangeRec, mDatabaseKDBX.keyChangeRecDays)
|
||||
@@ -230,7 +230,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
writeUuid(DatabaseKDBXXML.ElemLastTopVisibleGroup, mDatabaseKDBX.lastTopVisibleGroupUUID)
|
||||
|
||||
// Seem to work properly if always in meta
|
||||
if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong())
|
||||
if (header!!.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong())
|
||||
writeMetaBinaries()
|
||||
|
||||
writeCustomData(mDatabaseKDBX.customData)
|
||||
@@ -274,7 +274,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
Log.e(TAG, "Unable to retrieve header", unknownKDF)
|
||||
}
|
||||
|
||||
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
header.innerRandomStream = CrsAlgorithm.Salsa20
|
||||
header.innerRandomStreamKey = ByteArray(32)
|
||||
} else {
|
||||
@@ -288,7 +288,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
throw DatabaseOutputException("Invalid random cipher")
|
||||
}
|
||||
|
||||
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
random.nextBytes(header.streamStartBytes)
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
|
||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||
private fun writeObject(name: String, value: Date) {
|
||||
if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||
if (header!!.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
|
||||
writeObject(name, DatabaseKDBXXML.DateFormatter.format(value))
|
||||
} else {
|
||||
val dt = DateTime(value)
|
||||
@@ -489,7 +489,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
xml.startTag(null, DatabaseKDBXXML.ElemAutoType)
|
||||
|
||||
writeObject(DatabaseKDBXXML.ElemAutoTypeEnabled, autoType.enabled)
|
||||
writeObject(DatabaseKDBXXML.ElemAutoTypeObfuscation, autoType.obfuscationOptions.toLong())
|
||||
writeObject(DatabaseKDBXXML.ElemAutoTypeObfuscation, autoType.obfuscationOptions.toKotlinLong())
|
||||
|
||||
if (autoType.defaultSequence.isNotEmpty()) {
|
||||
writeObject(DatabaseKDBXXML.ElemAutoTypeDefaultSeq, autoType.defaultSequence, true)
|
||||
@@ -629,7 +629,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
writeObject(DatabaseKDBXXML.ElemLastAccessTime, node.lastAccessTime.date)
|
||||
writeObject(DatabaseKDBXXML.ElemExpiryTime, node.expiryTime.date)
|
||||
writeObject(DatabaseKDBXXML.ElemExpires, node.expires)
|
||||
writeObject(DatabaseKDBXXML.ElemUsageCount, node.usageCount.toLong())
|
||||
writeObject(DatabaseKDBXXML.ElemUsageCount, node.usageCount.toKotlinLong())
|
||||
writeObject(DatabaseKDBXXML.ElemLocationChanged, node.locationChanged.date)
|
||||
|
||||
xml.endTag(null, DatabaseKDBXXML.ElemTimes)
|
||||
|
||||
@@ -104,7 +104,7 @@ class EntryOutputKDB
|
||||
val binaryData = mEntry.binaryData
|
||||
val binaryDataLength = binaryData?.length() ?: 0L
|
||||
// Write data length
|
||||
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromLong(binaryDataLength)))
|
||||
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength)))
|
||||
// Write data
|
||||
if (binaryDataLength > 0) {
|
||||
binaryData?.getInputDataStream().use { inputStream ->
|
||||
|
||||
@@ -81,7 +81,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
||||
bufferPos = 0
|
||||
|
||||
val index = baseStream.readUInt()
|
||||
if (index.toLong() != bufferIndex) {
|
||||
if (index.toKotlinLong() != bufferIndex) {
|
||||
throw IOException("Invalid data format")
|
||||
}
|
||||
bufferIndex++
|
||||
@@ -91,7 +91,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
||||
throw IOException("Invalid data format")
|
||||
}
|
||||
|
||||
val bufferSize = baseStream.readBytes4ToUInt().toInt()
|
||||
val bufferSize = baseStream.readBytes4ToUInt().toKotlinInt()
|
||||
if (bufferSize == 0) {
|
||||
for (hash in 0 until HASH_SIZE) {
|
||||
if (storedHash[hash].toInt() != 0) {
|
||||
@@ -141,7 +141,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
||||
if (!readHashedBlock()) return -1
|
||||
}
|
||||
|
||||
val output = UnsignedInt.fromByte(buffer[bufferPos]).toInt()
|
||||
val output = UnsignedInt.fromKotlinByte(buffer[bufferPos]).toKotlinInt()
|
||||
bufferPos++
|
||||
|
||||
return output
|
||||
|
||||
@@ -99,7 +99,7 @@ class HashedBlockOutputStream : OutputStream {
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun writeHashedBlock() {
|
||||
baseStream.writeUInt(UnsignedInt.fromLong(bufferIndex))
|
||||
baseStream.writeUInt(UnsignedInt.fromKotlinLong(bufferIndex))
|
||||
bufferIndex++
|
||||
|
||||
if (bufferPos > 0) {
|
||||
|
||||
@@ -44,7 +44,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
||||
if (!readSafeBlock()) return -1
|
||||
}
|
||||
|
||||
val output = UnsignedInt.fromByte(buffer[bufferPos]).toInt()
|
||||
val output = UnsignedInt.fromKotlinByte(buffer[bufferPos]).toKotlinInt()
|
||||
bufferPos++
|
||||
|
||||
return output
|
||||
@@ -101,7 +101,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
||||
val blockSize = bytes4ToUInt(pbBlockSize)
|
||||
bufferPos = 0
|
||||
|
||||
buffer = baseStream.readBytes(blockSize.toInt())
|
||||
buffer = baseStream.readBytes(blockSize.toKotlinInt())
|
||||
|
||||
if (verify) {
|
||||
val cmpHmac: ByteArray
|
||||
@@ -135,7 +135,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
||||
|
||||
blockIndex++
|
||||
|
||||
if (blockSize.toLong() == 0L) {
|
||||
if (blockSize.toKotlinLong() == 0L) {
|
||||
endOfStream = true
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -171,11 +171,11 @@ fun bytes5ToDate(buf: ByteArray, calendar: Calendar = Calendar.getInstance()): D
|
||||
System.arraycopy(buf, 0, cDate, 0, dateSize)
|
||||
|
||||
val readOffset = 0
|
||||
val dw1 = UnsignedInt.fromByte(cDate[readOffset]).toInt()
|
||||
val dw2 = UnsignedInt.fromByte(cDate[readOffset + 1]).toInt()
|
||||
val dw3 = UnsignedInt.fromByte(cDate[readOffset + 2]).toInt()
|
||||
val dw4 = UnsignedInt.fromByte(cDate[readOffset + 3]).toInt()
|
||||
val dw5 = UnsignedInt.fromByte(cDate[readOffset + 4]).toInt()
|
||||
val dw1 = UnsignedInt.fromKotlinByte(cDate[readOffset]).toKotlinInt()
|
||||
val dw2 = UnsignedInt.fromKotlinByte(cDate[readOffset + 1]).toKotlinInt()
|
||||
val dw3 = UnsignedInt.fromKotlinByte(cDate[readOffset + 2]).toKotlinInt()
|
||||
val dw4 = UnsignedInt.fromKotlinByte(cDate[readOffset + 3]).toKotlinInt()
|
||||
val dw5 = UnsignedInt.fromKotlinByte(cDate[readOffset + 4]).toKotlinInt()
|
||||
|
||||
// Unpack 5 byte structure to date and time
|
||||
val year = dw1 shl 6 or (dw2 shr 2)
|
||||
@@ -199,7 +199,7 @@ fun bytes5ToDate(buf: ByteArray, calendar: Calendar = Calendar.getInstance()): D
|
||||
fun uIntTo4Bytes(value: UnsignedInt): ByteArray {
|
||||
val buf = ByteArray(4)
|
||||
for (i in 0 until 4) {
|
||||
buf[i] = (value.toInt().ushr(8 * i) and 0xFF).toByte()
|
||||
buf[i] = (value.toKotlinInt().ushr(8 * i) and 0xFF).toByte()
|
||||
}
|
||||
return buf
|
||||
}
|
||||
@@ -246,8 +246,8 @@ fun dateTo5Bytes(date: Date, calendar: Calendar = Calendar.getInstance()): ByteA
|
||||
val minute = calendar.get(Calendar.MINUTE)
|
||||
val second = calendar.get(Calendar.SECOND)
|
||||
|
||||
buf[0] = UnsignedInt(year shr 6 and 0x0000003F).toByte()
|
||||
buf[1] = UnsignedInt(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003)).toByte()
|
||||
buf[0] = UnsignedInt(year shr 6 and 0x0000003F).toKotlinByte()
|
||||
buf[1] = UnsignedInt(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003)).toKotlinByte()
|
||||
buf[2] = (month and 0x00000003 shl 6
|
||||
or (day and 0x0000001F shl 1) or (hour shr 4 and 0x00000001)).toByte()
|
||||
buf[3] = (hour and 0x0000000F shl 4 or (minute shr 2 and 0x0000000F)).toByte()
|
||||
|
||||
@@ -21,31 +21,31 @@ package com.kunzisoft.keepass.utils
|
||||
|
||||
class UnsignedInt(private var unsignedValue: Int) {
|
||||
|
||||
constructor(unsignedValue: UnsignedInt) : this(unsignedValue.toInt())
|
||||
constructor(unsignedValue: UnsignedInt) : this(unsignedValue.toKotlinInt())
|
||||
|
||||
/**
|
||||
* Get the int value
|
||||
*/
|
||||
fun toInt(): Int {
|
||||
fun toKotlinInt(): Int {
|
||||
return unsignedValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an unsigned Integer to Long
|
||||
*/
|
||||
fun toLong(): Long {
|
||||
fun toKotlinLong(): Long {
|
||||
return unsignedValue.toLong() and INT_TO_LONG_MASK
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an unsigned Integer to Byte
|
||||
*/
|
||||
fun toByte(): Byte {
|
||||
fun toKotlinByte(): Byte {
|
||||
return (unsignedValue and 0xFF).toByte()
|
||||
}
|
||||
|
||||
override fun toString():String {
|
||||
return toLong().toString()
|
||||
return toKotlinLong().toString()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -72,12 +72,12 @@ class UnsignedInt(private var unsignedValue: Int) {
|
||||
/**
|
||||
* Convert a byte to an unsigned byte
|
||||
*/
|
||||
fun fromByte(value: Byte): UnsignedInt {
|
||||
fun fromKotlinByte(value: Byte): UnsignedInt {
|
||||
return UnsignedInt(value.toInt() and 0xFF)
|
||||
}
|
||||
|
||||
@Throws(NumberFormatException::class)
|
||||
fun fromLong(value: Long): UnsignedInt {
|
||||
fun fromKotlinLong(value: Long): UnsignedInt {
|
||||
if (value > UINT_MAX_VALUE)
|
||||
throw NumberFormatException("UInt value > $UINT_MAX_VALUE")
|
||||
return UnsignedInt(value.toInt())
|
||||
|
||||
@@ -24,7 +24,7 @@ class UnsignedLong(private var unsignedValue: Long) {
|
||||
/**
|
||||
* Convert an unsigned Integer to Long
|
||||
*/
|
||||
fun toLong(): Long {
|
||||
fun toKotlinLong(): Long {
|
||||
return unsignedValue
|
||||
}
|
||||
|
||||
|
||||
@@ -127,13 +127,13 @@ open class VariantDictionary {
|
||||
if (bType == VdType.None) {
|
||||
break
|
||||
}
|
||||
val nameLen = inputStream.readUInt().toInt()
|
||||
val nameLen = inputStream.readUInt().toKotlinInt()
|
||||
val nameBuf = inputStream.readBytes(nameLen)
|
||||
if (nameLen != nameBuf.size) {
|
||||
throw IOException("Invalid format")
|
||||
}
|
||||
val name = String(nameBuf, UTF8Charset)
|
||||
val valueLen = inputStream.readUInt().toInt()
|
||||
val valueLen = inputStream.readUInt().toKotlinInt()
|
||||
val valueBuf = inputStream.readBytes(valueLen)
|
||||
if (valueLen != valueBuf.size) {
|
||||
throw IOException("Invalid format")
|
||||
@@ -149,7 +149,7 @@ open class VariantDictionary {
|
||||
dictionary.setBool(name, valueBuf[0] != 0.toByte())
|
||||
}
|
||||
VdType.Int32 -> if (valueLen == 4) {
|
||||
dictionary.setInt32(name, bytes4ToUInt(valueBuf).toInt())
|
||||
dictionary.setInt32(name, bytes4ToUInt(valueBuf).toKotlinInt())
|
||||
}
|
||||
VdType.Int64 -> if (valueLen == 8) {
|
||||
dictionary.setInt64(name, bytes64ToLong(valueBuf))
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
*
|
||||
* Fix TOTP period (> 60s)
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
*
|
||||
* Correction de la période pour le TOTP (> 60s)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user