Wysyłaj dane urządzenia przy logowaniu
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package pl.firmatpp.kierowca.data
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import pl.firmatpp.kierowca.BuildConfig
|
||||
import pl.firmatpp.kierowca.data.model.DriverDeviceInfo
|
||||
|
||||
class DeviceInfoProvider(
|
||||
private val context: Context,
|
||||
private val tokenStore: TokenStore,
|
||||
) {
|
||||
suspend fun currentDeviceInfo(): DriverDeviceInfo =
|
||||
DriverDeviceInfo(
|
||||
deviceId = tokenStore.deviceId(),
|
||||
androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID),
|
||||
brand = Build.BRAND,
|
||||
manufacturer = Build.MANUFACTURER,
|
||||
model = Build.MODEL,
|
||||
device = Build.DEVICE,
|
||||
product = Build.PRODUCT,
|
||||
androidVersion = Build.VERSION.RELEASE,
|
||||
sdkInt = Build.VERSION.SDK_INT,
|
||||
appVersion = BuildConfig.VERSION_NAME,
|
||||
serialNumber = readSerialNumber(),
|
||||
)
|
||||
|
||||
private fun readSerialNumber(): String? =
|
||||
runCatching {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Build.getSerial()
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
Build.SERIAL
|
||||
}
|
||||
}.getOrNull()
|
||||
?.takeUnless { it.isBlank() || it.equals(Build.UNKNOWN, ignoreCase = true) }
|
||||
}
|
||||
@@ -19,12 +19,13 @@ class DriverRepository(
|
||||
private val context: Context,
|
||||
private val api: MobileDriverApi = ApiFactory.mobileDriverApi(),
|
||||
private val tokenStore: TokenStore = TokenStore(context),
|
||||
private val deviceInfoProvider: DeviceInfoProvider = DeviceInfoProvider(context, tokenStore),
|
||||
) {
|
||||
suspend fun requestOtp(phoneNumber: String): OtpResponse =
|
||||
api.requestOtp(RequestOtpBody(phoneNumber))
|
||||
|
||||
suspend fun verifyOtp(phoneNumber: String, code: String, deviceName: String): DriverDto {
|
||||
val response = api.verifyOtp(VerifyOtpBody(phoneNumber, code, deviceName))
|
||||
val response = api.verifyOtp(VerifyOtpBody(phoneNumber, code, deviceName, deviceInfoProvider.currentDeviceInfo()))
|
||||
val token = response.accessToken ?: error("Brak tokenu sesji.")
|
||||
tokenStore.save(token)
|
||||
return response.driver ?: error("Brak danych kierowcy.")
|
||||
|
||||
@@ -6,11 +6,13 @@ import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.util.UUID
|
||||
|
||||
private val Context.driverDataStore by preferencesDataStore(name = "driver_session")
|
||||
|
||||
class TokenStore(private val context: Context) {
|
||||
private val tokenKey = stringPreferencesKey("access_token")
|
||||
private val deviceIdKey = stringPreferencesKey("device_id")
|
||||
|
||||
suspend fun save(token: String) {
|
||||
context.driverDataStore.edit { preferences ->
|
||||
@@ -22,6 +24,21 @@ class TokenStore(private val context: Context) {
|
||||
.map { it[tokenKey] }
|
||||
.first()
|
||||
|
||||
suspend fun deviceId(): String {
|
||||
val existing = context.driverDataStore.data
|
||||
.map { it[deviceIdKey] }
|
||||
.first()
|
||||
|
||||
if (!existing.isNullOrBlank()) return existing
|
||||
|
||||
val generated = UUID.randomUUID().toString()
|
||||
context.driverDataStore.edit { preferences ->
|
||||
preferences[deviceIdKey] = generated
|
||||
}
|
||||
|
||||
return generated
|
||||
}
|
||||
|
||||
suspend fun clear() {
|
||||
context.driverDataStore.edit { it.remove(tokenKey) }
|
||||
}
|
||||
|
||||
@@ -6,6 +6,21 @@ data class VerifyOtpBody(
|
||||
val phoneNumber: String,
|
||||
val code: String,
|
||||
val deviceName: String,
|
||||
val device: DriverDeviceInfo,
|
||||
)
|
||||
|
||||
data class DriverDeviceInfo(
|
||||
val deviceId: String,
|
||||
val androidId: String?,
|
||||
val brand: String?,
|
||||
val manufacturer: String?,
|
||||
val model: String?,
|
||||
val device: String?,
|
||||
val product: String?,
|
||||
val androidVersion: String?,
|
||||
val sdkInt: Int,
|
||||
val appVersion: String?,
|
||||
val serialNumber: String?,
|
||||
)
|
||||
|
||||
data class OtpResponse(
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = resolve(__dirname, '..');
|
||||
|
||||
function readSource(path) {
|
||||
return readFileSync(resolve(root, path), 'utf8');
|
||||
}
|
||||
|
||||
test('driver app sends Android device metadata during OTP verification', () => {
|
||||
const models = readSource('app/src/main/java/pl/firmatpp/kierowca/data/model/DriverModels.kt');
|
||||
const repository = readSource('app/src/main/java/pl/firmatpp/kierowca/data/DriverRepository.kt');
|
||||
const deviceInfo = readSource('app/src/main/java/pl/firmatpp/kierowca/data/DeviceInfoProvider.kt');
|
||||
|
||||
assert.match(models, /data class DriverDeviceInfo/);
|
||||
assert.match(models, /val device: DriverDeviceInfo/);
|
||||
assert.match(repository, /DeviceInfoProvider/);
|
||||
assert.match(repository, /deviceInfoProvider\.currentDeviceInfo/);
|
||||
assert.match(deviceInfo, /Settings\.Secure\.ANDROID_ID/);
|
||||
assert.match(deviceInfo, /Build\.MANUFACTURER/);
|
||||
assert.match(deviceInfo, /Build\.MODEL/);
|
||||
assert.match(deviceInfo, /BuildConfig\.VERSION_NAME/);
|
||||
});
|
||||
Reference in New Issue
Block a user