Use an 8-digit token for each car so it is easy to share.
This commit is contained in:
1 parent
0224e8f395
commit
b95cbefeab
6 files changed
+42
-15
No files matched your search
@@ -253,7 +253,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
db.execSQL(
|
||||
"""
|
||||
INSERT INTO cars (carName, raceClass, discipline, token, updatedAt, syncRev, deleted, pending)
|
||||
VALUES ('$DEFAULT_CAR', '$DEFAULT_CLASS', '$DEFAULT_DISCIPLINE', lower(hex(randomblob(32))), 1, 0, 0, 1)
|
||||
VALUES ('$DEFAULT_CAR', '$DEFAULT_CLASS', '$DEFAULT_DISCIPLINE', printf('%08d', abs(random()) % 100000000), 1, 0, 0, 1)
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -132,6 +132,15 @@ interface RaceDao {
|
||||
@Query("SELECT * FROM cars WHERE id = :id")
|
||||
suspend fun carById(id: Long): Car?
|
||||
|
||||
@Query("UPDATE race_nights SET pending = 1 WHERE carId = :carId")
|
||||
suspend fun markNightsPending(carId: Long)
|
||||
|
||||
@Query("UPDATE runs SET pending = 1 WHERE nightId IN (SELECT id FROM race_nights WHERE carId = :carId)")
|
||||
suspend fun markRunsPending(carId: Long)
|
||||
|
||||
@Query("UPDATE setup_sheets SET pending = 1 WHERE carId = :carId")
|
||||
suspend fun markSheetsPending(carId: Long)
|
||||
|
||||
@Query("SELECT * FROM cars WHERE token = :token LIMIT 1")
|
||||
suspend fun carByToken(token: String): Car?
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.racingapp.pitlog.data
|
||||
|
||||
import java.security.MessageDigest
|
||||
import java.security.SecureRandom
|
||||
import java.util.UUID
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -24,28 +25,39 @@ suspend fun ensureCars(dao: RaceDao, preferences: SyncPreferences) {
|
||||
preferences.selectedCarId = id
|
||||
return
|
||||
}
|
||||
val first = cars.firstOrNull { !it.deleted } ?: cars.first()
|
||||
if (first.token.isBlank()) {
|
||||
val kept = preferences.token.trim().ifBlank { newCarToken() }
|
||||
val rev = if (kept == preferences.token.trim() && first.syncRev == 0L) preferences.rev else first.syncRev
|
||||
dao.updateCar(first.copy(token = kept, syncRev = rev, pending = true))
|
||||
for (car in cars) {
|
||||
if (isEightDigitToken(car.token)) continue
|
||||
val source = car.token.ifBlank { preferences.token.trim() }
|
||||
val next = if (source.isBlank()) newCarToken() else eightDigitToken(source)
|
||||
dao.updateCar(car.copy(token = next, syncRev = 0, pending = true))
|
||||
dao.markNightsPending(car.id)
|
||||
dao.markRunsPending(car.id)
|
||||
dao.markSheetsPending(car.id)
|
||||
}
|
||||
val first = cars.firstOrNull { !it.deleted } ?: cars.first()
|
||||
val selected = preferences.selectedCarId
|
||||
if (selected == 0L || cars.none { it.id == selected && !it.deleted }) {
|
||||
preferences.selectedCarId = first.id
|
||||
}
|
||||
}
|
||||
|
||||
fun newCarToken(): String {
|
||||
val bytes = ByteArray(32)
|
||||
SecureRandom().nextBytes(bytes)
|
||||
return bytes.joinToString("") { "%02x".format(it) }
|
||||
fun newCarToken(): String = "%08d".format(SecureRandom().nextInt(100_000_000))
|
||||
|
||||
fun eightDigitToken(current: String): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256").digest(current.toByteArray(Charsets.UTF_8))
|
||||
var value = 0L
|
||||
for (index in 0 until 4) {
|
||||
value = (value shl 8) or (digest[index].toLong() and 0xff)
|
||||
}
|
||||
return "%08d".format(value % 100_000_000L)
|
||||
}
|
||||
|
||||
fun isEightDigitToken(token: String): Boolean = token.length == 8 && token.all { it.isDigit() }
|
||||
|
||||
fun cleanCarToken(raw: String): String {
|
||||
val line = raw.trim().lineSequence().firstOrNull().orEmpty().trim()
|
||||
val withoutLabel = if (line.startsWith("token:", ignoreCase = true)) line.substringAfter(":").trim() else line
|
||||
return withoutLabel.lowercase()
|
||||
return withoutLabel.filter { !it.isWhitespace() }.lowercase()
|
||||
}
|
||||
|
||||
class Repository(
|
||||
@@ -125,7 +137,7 @@ class Repository(
|
||||
|
||||
suspend fun joinCar(raw: String): String {
|
||||
val token = cleanCarToken(raw)
|
||||
if (token.length < 16 || token.any { it !in '0'..'9' && it !in 'a'..'f' }) {
|
||||
if (!isEightDigitToken(token)) {
|
||||
return "That token doesn't look right."
|
||||
}
|
||||
val existing = dao.carByToken(token)
|
||||
|
||||
Reference in new issue
Block a user