From 0e7ed8236aa78dec823daaa1dd20114d64e409ee Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Tue, 24 Feb 2026 18:31:58 +0300 Subject: [PATCH 01/13] added readme, chganged constants --- README.MD | 1 + app/src/main/java/ru/myitschool/work/core/Constants.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 README.MD diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..a1a5f44 --- /dev/null +++ b/README.MD @@ -0,0 +1 @@ +penpot deck: https://pp.sicampus.ru/#/workspace?team-id=14a6b474-d5fa-807f-8007-9f0741c1b7ad&file-id=14a6b474-d5fa-807f-8007-9f519b767dc8&page-id=14a6b474-d5fa-807f-8007-9f519b767dc9 \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt index cd36239..d31b4d5 100644 --- a/app/src/main/java/ru/myitschool/work/core/Constants.kt +++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt @@ -1,7 +1,7 @@ package ru.myitschool.work.core object Constants { - const val HOST = "http://localhost:8090" + const val HOST = "http:10.0.0.12//:49165" const val AUTH_URL = "/auth" const val INFO_URL = "/info" const val BOOKING_URL = "/booking" -- 2.47.1 From 8b8a964052226697ae81bc15fa8b649345bdd4ae Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Tue, 24 Feb 2026 18:35:59 +0300 Subject: [PATCH 02/13] fixed ip --- app/src/main/java/ru/myitschool/work/core/Constants.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt index d31b4d5..f997b69 100644 --- a/app/src/main/java/ru/myitschool/work/core/Constants.kt +++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt @@ -1,7 +1,7 @@ package ru.myitschool.work.core object Constants { - const val HOST = "http:10.0.0.12//:49165" + const val HOST = "http://10.0.0.12:49165" const val AUTH_URL = "/auth" const val INFO_URL = "/info" const val BOOKING_URL = "/booking" -- 2.47.1 From 5dc40465748d97757d132f7a7a8d9bc278e3732b Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Tue, 24 Feb 2026 18:58:00 +0300 Subject: [PATCH 03/13] actionbar hid --- app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt b/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt index 54b156d..d373d0c 100644 --- a/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt +++ b/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt @@ -15,6 +15,7 @@ class RootActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() + actionBar?.hide() setContent { WorkTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> -- 2.47.1 From 78233fe2a015956dd1ccfe844f637d619a3b4ddd Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Tue, 24 Feb 2026 20:25:52 +0300 Subject: [PATCH 04/13] chyanged penpot url --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index a1a5f44..7272056 100644 --- a/README.MD +++ b/README.MD @@ -1 +1 @@ -penpot deck: https://pp.sicampus.ru/#/workspace?team-id=14a6b474-d5fa-807f-8007-9f0741c1b7ad&file-id=14a6b474-d5fa-807f-8007-9f519b767dc8&page-id=14a6b474-d5fa-807f-8007-9f519b767dc9 \ No newline at end of file +penpot deck: https://pp.sicampus.ru/#/workspace?team-id=14a6b474-d5fa-807f-8007-9f0741c1b7ad&project-id=14a6b474-d5fa-807f-8007-9f0741c1b7ae&file-id=8e3f3321-7df1-807a-8007-9f6a7201af74&page-id=50b061ab-362d-8056-8007-9d94752aa99f&layout=layers&board-id=6fa8b836-315d-80ad-8007-9f6ddff01da2 \ No newline at end of file -- 2.47.1 From e678f2dc48bd31d1712ce69414989619a2d7a0be Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Wed, 25 Feb 2026 11:30:53 +0300 Subject: [PATCH 05/13] changed ui --- app/src/main/AndroidManifest.xml | 2 +- .../myitschool/work/ui/root/RootActivity.kt | 2 + .../work/ui/screen/auth/AuthIntent.kt | 4 +- .../work/ui/screen/auth/AuthScreen.kt | 70 ++++++++++++++----- app/src/main/res/values/strings.xml | 10 ++- 5 files changed, 67 insertions(+), 21 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a2c02bd..ac75dc3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,7 +18,7 @@ diff --git a/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt b/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt index d373d0c..82b09f5 100644 --- a/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt +++ b/app/src/main/java/ru/myitschool/work/ui/root/RootActivity.kt @@ -1,6 +1,7 @@ package ru.myitschool.work.ui.root import android.os.Bundle +import android.view.WindowManager.LayoutParams import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -16,6 +17,7 @@ class RootActivity : ComponentActivity() { super.onCreate(savedInstanceState) enableEdgeToEdge() actionBar?.hide() + window.setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) setContent { WorkTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt index 74f200a..b4aec57 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt @@ -1,6 +1,6 @@ package ru.myitschool.work.ui.screen.auth sealed interface AuthIntent { - data class Send(val text: String): AuthIntent - data class TextInput(val text: String): AuthIntent + data class Send(val login: String, val password: String): AuthIntent + data class TextInput(val login: String, val password: String): AuthIntent } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt index 4b91b98..5073c93 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt @@ -5,11 +5,17 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable @@ -23,6 +29,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -51,13 +58,27 @@ fun AuthScreen( Column( modifier = Modifier .fillMaxSize() - .padding(all = 24.dp), + .padding(horizontal = 48.dp) + .verticalScroll(rememberScrollState()) + .imePadding(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + Icon( + painter = painterResource(R.drawable.difference), + contentDescription = stringResource(R.string.icon_alter), + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(184.dp) + ) + Spacer(modifier = Modifier.size(48.dp)) Text( - text = stringResource(R.string.auth_title), - style = MaterialTheme.typography.headlineSmall, + text = stringResource(R.string.auth_title_1), + style = MaterialTheme.typography.headlineLarge, + textAlign = TextAlign.Center + ) + Text( + text = stringResource(R.string.auth_title_2), + style = MaterialTheme.typography.titleLarge, textAlign = TextAlign.Center ) when (val currentState = state) { @@ -76,26 +97,43 @@ private fun Content( viewModel: AuthViewModel, state: AuthState.Data ) { - var inputText by remember { mutableStateOf("") } - Spacer(modifier = Modifier.size(16.dp)) - TextField( + var login by remember { mutableStateOf("") } + var password by remember { mutableStateOf("") } + + Spacer(modifier = Modifier.size(48.dp)) + OutlinedTextField( modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), - value = inputText, + value = login, onValueChange = { - inputText = it - viewModel.onIntent(AuthIntent.TextInput(it)) + login = it + viewModel.onIntent(AuthIntent.TextInput(login, password)) }, - label = { Text(stringResource(R.string.auth_label)) } + placeholder = { Text(stringResource(R.string.auth_placeholder_login)) }, + label = { Text(stringResource(R.string.auth_label_login)) } ) Spacer(modifier = Modifier.size(16.dp)) - Button( - modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth(), - onClick = { - viewModel.onIntent(AuthIntent.Send(inputText)) + OutlinedTextField( + modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), + value = password, + onValueChange = { + password = it + viewModel.onIntent(AuthIntent.TextInput(login, password)) }, - enabled = state.isEnabledSend + placeholder = { Text(stringResource(R.string.auth_placeholder_password)) }, + label = { Text(stringResource(R.string.auth_label_passord)) } + ) + Spacer(modifier = Modifier.size(20.dp)) + Button( + modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth().height(64.dp), + onClick = { + viewModel.onIntent(AuthIntent.Send(login, password)) + }, + enabled = state.isEnabledSend, ) { - Text(stringResource(R.string.auth_sign_in)) + Text( + text = stringResource(R.string.auth_sign_in), + style = MaterialTheme.typography.titleMedium, + ) } if (state.error != null) { Text( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a9273cf..82b7cfd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,8 +1,12 @@ Work RootActivity - Привет! Введи код для авторизации - Код + Войдите + Используя аккаунт S-App + Логин + Введите логин + Пароль + Введите пароль Войти Обновить @@ -12,4 +16,6 @@ Забронировать Назад Всё забронировано + + Иконка \ No newline at end of file -- 2.47.1 From 7b4eaffe357f10d50c4490a67de494d79d97d016 Mon Sep 17 00:00:00 2001 From: student-d-sherstnev Date: Wed, 25 Feb 2026 11:32:07 +0300 Subject: [PATCH 06/13] Auth by login and password + password and login validation --- .../work/data/dto/AuthRequestDto.kt | 20 +++++++ .../work/data/repo/AuthRepository.kt | 35 +++++------ .../work/data/repo/BookRepository.kt | 12 ++-- .../work/data/source/NetworkDataSource.kt | 41 +++++++++---- .../auth/CheckAndSaveAuthCodeUseCase.kt | 10 ++-- .../domain/auth/CheckCodeFormatUseCase.kt | 15 +++-- .../work/domain/auth/GetCodeUseCase.kt | 2 +- .../work/ui/screen/auth/AuthIntent.kt | 4 +- .../work/ui/screen/auth/AuthViewModel.kt | 60 ++++++++++++++++--- 9 files changed, 143 insertions(+), 56 deletions(-) create mode 100644 app/src/main/java/ru/myitschool/work/data/dto/AuthRequestDto.kt diff --git a/app/src/main/java/ru/myitschool/work/data/dto/AuthRequestDto.kt b/app/src/main/java/ru/myitschool/work/data/dto/AuthRequestDto.kt new file mode 100644 index 0000000..8c877e9 --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/dto/AuthRequestDto.kt @@ -0,0 +1,20 @@ +package ru.myitschool.work.data.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class AuthRequestDto( + @SerialName("login") + val login: String, + @SerialName("password") + val password: String, +) + +@Serializable +data class AuthResponseDto( + @SerialName("token") + val token: String, + @SerialName("expired") + val expired: Int, +) \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt index e4126dd..f6240b2 100644 --- a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt +++ b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt @@ -8,41 +8,42 @@ import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.firstOrNull import ru.myitschool.work.App +import ru.myitschool.work.data.dto.AuthRequestDto +import ru.myitschool.work.data.dto.AuthResponseDto import ru.myitschool.work.data.source.NetworkDataSource object AuthRepository { private const val STORE = "AUTH-STORE" - private const val CODE_KEY = "CODE" + private const val TOKEN_KEY = "TOKEN" - private var codeCache: String? = null + private var tokenCache: String? = null - suspend fun checkAndSave(text: String): Result { - return NetworkDataSource.checkAuth(text).onSuccess { success -> - if (success) { - codeCache = text - App.context.userDataStore.edit { preferences -> - val prefKey = stringPreferencesKey(CODE_KEY) - preferences[prefKey] = text - } + suspend fun checkAndSave(login: String, password: String): Result { + val data = AuthRequestDto(login=login, password=password) + return NetworkDataSource.checkAuth(data).onSuccess { success -> + tokenCache = success.token + App.context.userDataStore.edit { preferences -> + val prefKey = stringPreferencesKey(TOKEN_KEY) + preferences[prefKey] = success.token } } } - suspend fun getCode(): String? { - if (codeCache == null) { - codeCache = App.context.userDataStore.data + suspend fun getToken(): String? { + if (tokenCache == null) { + tokenCache = App.context.userDataStore.data .firstOrNull() ?.let { preferences -> - preferences[stringPreferencesKey(CODE_KEY)] + preferences[stringPreferencesKey(TOKEN_KEY)] } } - return codeCache + return tokenCache } suspend fun logout() { - codeCache = null + tokenCache = null App.context.userDataStore.edit { preferences -> - val prefKey = stringPreferencesKey(CODE_KEY) + val prefKey = stringPreferencesKey(TOKEN_KEY) preferences.remove(prefKey) } } diff --git a/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt index ea1c581..f60d556 100644 --- a/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt +++ b/app/src/main/java/ru/myitschool/work/data/repo/BookRepository.kt @@ -10,8 +10,8 @@ class BookRepository( private val authRepository: AuthRepository ) { suspend fun getInfo(): Result { - val code = authRepository.getCode() ?: return getNoAuthResult() - return NetworkDataSource.getInfo(code).mapCatching { dto -> + val token = authRepository.getToken() ?: return getNoAuthResult() + return NetworkDataSource.getInfo(token).mapCatching { dto -> MainInfoEntity( name = dto.name ?: error("Name is null"), photoUrl = dto.photoUrl ?: error("Photo url is null"), @@ -26,8 +26,8 @@ class BookRepository( } suspend fun getBookingInfo(): Result> { - val code = authRepository.getCode() ?: return getNoAuthResult() - return NetworkDataSource.getBooking(code).mapCatching { dto -> + val token = authRepository.getToken() ?: return getNoAuthResult() + return NetworkDataSource.getBooking(token).mapCatching { dto -> dto?.map { (date, places) -> BookingData( date = date, @@ -43,9 +43,9 @@ class BookRepository( } suspend fun sendBook(data: BookRequestData): Result { - val code = authRepository.getCode() ?: return getNoAuthResult() + val token = authRepository.getToken() ?: return getNoAuthResult() val dto = BookRequestDto(data.date, data.placeId) - return NetworkDataSource.addBook(code, dto) + return NetworkDataSource.addBook(token, dto) } private fun getNoAuthResult() = Result.failure( IllegalStateException("No auth") diff --git a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt index 85387ac..d78e716 100644 --- a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt @@ -5,6 +5,7 @@ import io.ktor.client.call.body import io.ktor.client.engine.cio.CIO import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.get +import io.ktor.client.request.headers import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.client.statement.bodyAsText @@ -16,6 +17,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import ru.myitschool.work.core.Constants +import ru.myitschool.work.data.dto.AuthRequestDto +import ru.myitschool.work.data.dto.AuthResponseDto import ru.myitschool.work.data.dto.PlaceDto import ru.myitschool.work.data.dto.BookRequestDto import ru.myitschool.work.data.dto.UserDto @@ -36,20 +39,27 @@ object NetworkDataSource { } } - suspend fun checkAuth(code: String): Result = withContext(Dispatchers.IO) { + suspend fun checkAuth(data: AuthRequestDto): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.get(getUrl(code, Constants.AUTH_URL)) + val response = client.post(getUrl(Constants.BOOK_URL)) { + contentType(ContentType.Application.Json) + setBody(data) + } when (response.status) { - HttpStatusCode.OK -> true - else -> false + HttpStatusCode.OK -> response.body() + else -> error(response.bodyAsText()) } } } - suspend fun getInfo(code: String): Result = withContext(Dispatchers.IO) { + suspend fun getInfo(token: String): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - println("!!!!!!!!!!!!!! getInfo $code") - val response = client.get(getUrl(code, Constants.INFO_URL)) + println("!!!!!!!!!!!!!! getInfo") + val response = client.get(getUrl(Constants.INFO_URL)) { + headers { + append("Authorization", "Bearer $token") + } + } if (response.status == HttpStatusCode.OK) { println("!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}") response.body() @@ -60,9 +70,13 @@ object NetworkDataSource { } } - suspend fun getBooking(code: String): Result>?> = withContext(Dispatchers.IO) { + suspend fun getBooking(token: String): Result>?> = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.get(getUrl(code, Constants.BOOKING_URL)) + val response = client.get(getUrl(Constants.BOOKING_URL)) { + headers { + append("Authorization", "Bearer $token") + } + } if (response.status == HttpStatusCode.OK) { response.body>>() } else { @@ -71,11 +85,14 @@ object NetworkDataSource { } } - suspend fun addBook(code: String, data: BookRequestDto): Result = withContext(Dispatchers.IO) { + suspend fun addBook(token: String, data: BookRequestDto): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.post(getUrl(code, Constants.BOOK_URL)) { + val response = client.post(getUrl(Constants.BOOK_URL)) { contentType(ContentType.Application.Json) setBody(data) + headers { + append("Authorization", "Bearer $token") + } } when (response.status) { HttpStatusCode.Created -> true @@ -85,5 +102,5 @@ object NetworkDataSource { } } - private fun getUrl(code: String, targetUrl: String) = "${Constants.HOST}/api/$code$targetUrl" + private fun getUrl(targetUrl: String) = "${Constants.HOST}/api/$targetUrl" } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt index 012fb6f..d246c4f 100644 --- a/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/auth/CheckAndSaveAuthCodeUseCase.kt @@ -1,15 +1,15 @@ package ru.myitschool.work.domain.auth +import ru.myitschool.work.data.dto.AuthResponseDto import ru.myitschool.work.data.repo.AuthRepository class CheckAndSaveAuthCodeUseCase( private val repository: AuthRepository ) { suspend operator fun invoke( - text: String - ): Result { - return repository.checkAndSave(text).mapCatching { success -> - if (!success) error("Code is incorrect") - } + login: String, + password: String + ): Result { + return repository.checkAndSave(login, password) } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt index fe291a0..c12813f 100644 --- a/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/auth/CheckCodeFormatUseCase.kt @@ -2,11 +2,18 @@ package ru.myitschool.work.domain.auth class CheckCodeFormatUseCase { operator fun invoke( - text: String + login: String, password: String ): Boolean { - return text.length == 4 && text.all { char -> - char.isLetterOrDigit() && - ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z') || char.isDigit()) + val passwordList = password.toList() + var passwordCorrect = true + for (i in 1..(passwordList.size - 3)) { + val s = StringBuilder().append(passwordList[i]).append(passwordList[i+1]).append(passwordList[i+2]).toString() + if (login.contains(s)) { + passwordCorrect = false + } } + return login.isNotEmpty() && password.length >= 8 && passwordCorrect && login.all { char -> + char.isLetterOrDigit() && ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z') || char.isDigit()) + } && password.all({ char -> password.count { it == char } < 3 }) && password.count { it == '!' } + password.count { it == '@' } + password.count { it == '#' } + password.count { it == '"' } + password.count { it == '№' } + password.count { it == ';' } + password.count { it == '$' } + password.count { it == '%' } + password.count { it == '^' } + password.count { it == ':' } + password.count { it == '&' } + password.count { it == '?' } + password.count { it == '*' } >= 1 } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt b/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt index a3c22b8..f3a3517 100644 --- a/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt +++ b/app/src/main/java/ru/myitschool/work/domain/auth/GetCodeUseCase.kt @@ -6,6 +6,6 @@ class GetCodeUseCase( private val repository: AuthRepository ) { suspend operator fun invoke(): String? { - return repository.getCode() + return repository.getToken() } } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt index 74f200a..b4aec57 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthIntent.kt @@ -1,6 +1,6 @@ package ru.myitschool.work.ui.screen.auth sealed interface AuthIntent { - data class Send(val text: String): AuthIntent - data class TextInput(val text: String): AuthIntent + data class Send(val login: String, val password: String): AuthIntent + data class TextInput(val login: String, val password: String): AuthIntent } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt index c28f5cd..8ec6f24 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt @@ -1,5 +1,6 @@ package ru.myitschool.work.ui.screen.auth +import android.os.CountDownTimer import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.MutableSharedFlow @@ -28,28 +29,69 @@ class AuthViewModel : ViewModel() { private val _actionFlow: MutableSharedFlow = MutableSharedFlow() val actionFlow: SharedFlow = _actionFlow + private var authTries: Int = 0 + private var timerSecs: Int = 0 + fun onIntent(intent: AuthIntent) { when (intent) { is AuthIntent.Send -> { - viewModelScope.launch { - checkAndSaveAuthCodeUseCase.invoke(intent.text).fold( - onSuccess = { - _actionFlow.emit(AuthAction.Open(MainScreenDestination)) - }, - onFailure = { error -> + if (authTries >= 5) { + timerSecs = 60 + val timer = object : CountDownTimer((timerSecs * 1000).toLong(), 1000) { + override fun onTick(millisUntilFinished: Long) { + timerSecs -= 1 updateStateIfData { oldState -> oldState.copy( - error = error.message + error = "Слишком много попыток входа, попробуйте через $timerSecs секунд" ) } } - ) + + override fun onFinish() { + authTries = 0 + updateStateIfData { oldState -> + oldState.copy( + isEnabledSend = checkCodeFormatUseCase.invoke( + login = intent.login, + password = intent.password + ), + error = null + ) + } + } + } + timer.start() + updateStateIfData { oldState -> + oldState.copy( + error = "Слишком много попыток входа, попробуйте через $timerSecs секунд" + ) + } + } else { + viewModelScope.launch { + checkAndSaveAuthCodeUseCase.invoke(intent.login, intent.password).fold( + onSuccess = { + _actionFlow.emit(AuthAction.Open(MainScreenDestination)) + }, + onFailure = { error -> + authTries += 1 + updateStateIfData { oldState -> + oldState.copy( + error = error.message + ) + } + } + ) + } } } + is AuthIntent.TextInput -> { updateStateIfData { oldState -> oldState.copy( - isEnabledSend = checkCodeFormatUseCase.invoke(intent.text), + isEnabledSend = checkCodeFormatUseCase.invoke( + login = intent.login, + password = intent.password + ), error = null ) } -- 2.47.1 From 1ff34969ba0d62ad5fd90508e37388be51b4c4fe Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Wed, 25 Feb 2026 11:47:22 +0300 Subject: [PATCH 07/13] MINIMAL CHANGES --- .../java/ru/myitschool/work/core/Constants.kt | 2 +- .../work/data/source/NetworkDataSource.kt | 2 +- .../work/ui/screen/auth/AuthScreen.kt | 35 ++++++++++--------- .../work/ui/screen/auth/AuthViewModel.kt | 13 ++----- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt index f997b69..ab0c588 100644 --- a/app/src/main/java/ru/myitschool/work/core/Constants.kt +++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt @@ -1,7 +1,7 @@ package ru.myitschool.work.core object Constants { - const val HOST = "http://10.0.0.12:49165" + const val HOST = "http://10.0.0.103:49165" const val AUTH_URL = "/auth" const val INFO_URL = "/info" const val BOOKING_URL = "/booking" diff --git a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt index d78e716..1405880 100644 --- a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt @@ -102,5 +102,5 @@ object NetworkDataSource { } } - private fun getUrl(targetUrl: String) = "${Constants.HOST}/api/$targetUrl" + private fun getUrl(targetUrl: String) = "${Constants.HOST}/api$targetUrl" } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt index 5073c93..6e82601 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt @@ -64,23 +64,6 @@ fun AuthScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Icon( - painter = painterResource(R.drawable.difference), - contentDescription = stringResource(R.string.icon_alter), - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(184.dp) - ) - Spacer(modifier = Modifier.size(48.dp)) - Text( - text = stringResource(R.string.auth_title_1), - style = MaterialTheme.typography.headlineLarge, - textAlign = TextAlign.Center - ) - Text( - text = stringResource(R.string.auth_title_2), - style = MaterialTheme.typography.titleLarge, - textAlign = TextAlign.Center - ) when (val currentState = state) { is AuthState.Data -> Content(viewModel, currentState) is AuthState.Loading -> { @@ -100,6 +83,24 @@ private fun Content( var login by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } + Icon( + painter = painterResource(R.drawable.difference), + contentDescription = stringResource(R.string.icon_alter), + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(184.dp) + ) + Spacer(modifier = Modifier.size(48.dp)) + Text( + text = stringResource(R.string.auth_title_1), + style = MaterialTheme.typography.headlineLarge, + textAlign = TextAlign.Center + ) + Text( + text = stringResource(R.string.auth_title_2), + style = MaterialTheme.typography.titleLarge, + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.size(48.dp)) OutlinedTextField( modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt index 8ec6f24..3cb44c8 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt @@ -42,6 +42,7 @@ class AuthViewModel : ViewModel() { timerSecs -= 1 updateStateIfData { oldState -> oldState.copy( + isEnabledSend = false, error = "Слишком много попыток входа, попробуйте через $timerSecs секунд" ) } @@ -61,24 +62,16 @@ class AuthViewModel : ViewModel() { } } timer.start() - updateStateIfData { oldState -> - oldState.copy( - error = "Слишком много попыток входа, попробуйте через $timerSecs секунд" - ) - } } else { viewModelScope.launch { + _uiState.update { AuthState.Loading } checkAndSaveAuthCodeUseCase.invoke(intent.login, intent.password).fold( onSuccess = { _actionFlow.emit(AuthAction.Open(MainScreenDestination)) }, onFailure = { error -> authTries += 1 - updateStateIfData { oldState -> - oldState.copy( - error = error.message - ) - } + _uiState.update { AuthState.Data(isEnabledSend = false, error = error.message) } } ) } -- 2.47.1 From eef10332931cb51911701f279cd53d82b67ed72f Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Wed, 25 Feb 2026 11:53:39 +0300 Subject: [PATCH 08/13] icon added --- app/src/main/res/drawable/difference.xml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/src/main/res/drawable/difference.xml diff --git a/app/src/main/res/drawable/difference.xml b/app/src/main/res/drawable/difference.xml new file mode 100644 index 0000000..213c6e8 --- /dev/null +++ b/app/src/main/res/drawable/difference.xml @@ -0,0 +1,9 @@ + + + -- 2.47.1 From f309b2ec593e13bedf3740f577aafffb6d396dee Mon Sep 17 00:00:00 2001 From: student-d-sherstnev Date: Wed, 25 Feb 2026 12:17:33 +0300 Subject: [PATCH 09/13] Auth delay + bug fixes --- .../java/ru/myitschool/work/core/Constants.kt | 3 ++- .../work/ui/screen/auth/AuthViewModel.kt | 16 +++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ru/myitschool/work/core/Constants.kt b/app/src/main/java/ru/myitschool/work/core/Constants.kt index ab0c588..c495a10 100644 --- a/app/src/main/java/ru/myitschool/work/core/Constants.kt +++ b/app/src/main/java/ru/myitschool/work/core/Constants.kt @@ -1,9 +1,10 @@ package ru.myitschool.work.core object Constants { - const val HOST = "http://10.0.0.103:49165" + const val HOST = "http://10.0.0.12:49165" const val AUTH_URL = "/auth" const val INFO_URL = "/info" const val BOOKING_URL = "/booking" const val BOOK_URL = "/book" + const val AUTH_DELAY = 60 } \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt index 3cb44c8..2a33de1 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthViewModel.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import ru.myitschool.work.core.Constants import ru.myitschool.work.data.repo.AuthRepository import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase import ru.myitschool.work.domain.auth.CheckCodeFormatUseCase @@ -32,11 +33,14 @@ class AuthViewModel : ViewModel() { private var authTries: Int = 0 private var timerSecs: Int = 0 + private var login: String = "" + private var password: String = "" + fun onIntent(intent: AuthIntent) { when (intent) { is AuthIntent.Send -> { if (authTries >= 5) { - timerSecs = 60 + timerSecs = Constants.AUTH_DELAY val timer = object : CountDownTimer((timerSecs * 1000).toLong(), 1000) { override fun onTick(millisUntilFinished: Long) { timerSecs -= 1 @@ -53,8 +57,8 @@ class AuthViewModel : ViewModel() { updateStateIfData { oldState -> oldState.copy( isEnabledSend = checkCodeFormatUseCase.invoke( - login = intent.login, - password = intent.password + login = login, + password = password ), error = null ) @@ -79,13 +83,15 @@ class AuthViewModel : ViewModel() { } is AuthIntent.TextInput -> { + login = intent.login + password = intent.password updateStateIfData { oldState -> oldState.copy( isEnabledSend = checkCodeFormatUseCase.invoke( login = intent.login, password = intent.password - ), - error = null + ) && authTries <= 5, + error = if (authTries >= 5) oldState.error else null ) } } -- 2.47.1 From 428c2e9678133a8588fc0e747a430a6b1b420ece Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Wed, 25 Feb 2026 12:23:16 +0300 Subject: [PATCH 10/13] ui changes error field --- .../work/ui/screen/auth/AuthScreen.kt | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt index 6e82601..5b2ec53 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt @@ -2,22 +2,26 @@ package ru.myitschool.work.ui.screen.auth import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imeNestedScroll import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -27,7 +31,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -38,6 +41,7 @@ import androidx.navigation.NavController import ru.myitschool.work.R import ru.myitschool.work.core.TestIds +@OptIn(ExperimentalLayoutApi::class) @Composable fun AuthScreen( viewModel: AuthViewModel = viewModel(), @@ -60,7 +64,8 @@ fun AuthScreen( .fillMaxSize() .padding(horizontal = 48.dp) .verticalScroll(rememberScrollState()) - .imePadding(), + .imePadding() + .imeNestedScroll(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { @@ -104,6 +109,7 @@ private fun Content( Spacer(modifier = Modifier.size(48.dp)) OutlinedTextField( modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), + shape = RoundedCornerShape(8.dp), value = login, onValueChange = { login = it @@ -115,6 +121,7 @@ private fun Content( Spacer(modifier = Modifier.size(16.dp)) OutlinedTextField( modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(), + shape = RoundedCornerShape(8.dp), value = password, onValueChange = { password = it @@ -123,9 +130,29 @@ private fun Content( placeholder = { Text(stringResource(R.string.auth_placeholder_password)) }, label = { Text(stringResource(R.string.auth_label_passord)) } ) + Spacer(modifier = Modifier.size(16.dp)) + if (state.error != null) { + Card( + shape = RoundedCornerShape(20.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.errorContainer, + ) + ) { + Text( + modifier = Modifier.testTag(TestIds.Auth.ERROR).padding(16.dp), + text = state.error, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onErrorContainer, + ) + } + + } Spacer(modifier = Modifier.size(20.dp)) Button( - modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth().height(64.dp), + modifier = Modifier + .testTag(TestIds.Auth.SIGN_BUTTON) + .fillMaxWidth() + .height(64.dp), onClick = { viewModel.onIntent(AuthIntent.Send(login, password)) }, @@ -136,12 +163,4 @@ private fun Content( style = MaterialTheme.typography.titleMedium, ) } - if (state.error != null) { - Text( - modifier = Modifier.testTag(TestIds.Auth.ERROR), - text = state.error, - style = MaterialTheme.typography.bodyMedium, - color = Color.Red, - ) - } } \ No newline at end of file -- 2.47.1 From 70c6452367f1bc000340258a1c1daec747db353d Mon Sep 17 00:00:00 2001 From: student-i-nikolaevskiy Date: Wed, 25 Feb 2026 13:51:33 +0300 Subject: [PATCH 11/13] ui changes tablet --- .../work/ui/screen/auth/AuthScreen.kt | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt index 5b2ec53..f9494e5 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/auth/AuthScreen.kt @@ -1,6 +1,7 @@ package ru.myitschool.work.ui.screen.auth import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Spacer @@ -59,22 +60,24 @@ fun AuthScreen( } } - Column( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 48.dp) - .verticalScroll(rememberScrollState()) - .imePadding() - .imeNestedScroll(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - when (val currentState = state) { - is AuthState.Data -> Content(viewModel, currentState) - is AuthState.Loading -> { - CircularProgressIndicator( - modifier = Modifier.size(64.dp) - ) + BoxWithConstraints { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = if(maxWidth < 400.dp) 48.dp else 200.dp) + .verticalScroll(rememberScrollState()) + .imePadding() + .imeNestedScroll(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + when (val currentState = state) { + is AuthState.Data -> Content(viewModel, currentState) + is AuthState.Loading -> { + CircularProgressIndicator( + modifier = Modifier.size(64.dp) + ) + } } } } @@ -136,7 +139,8 @@ private fun Content( shape = RoundedCornerShape(20.dp), colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.errorContainer, - ) + ), + modifier = Modifier.fillMaxWidth() ) { Text( modifier = Modifier.testTag(TestIds.Auth.ERROR).padding(16.dp), -- 2.47.1 From d08206212ddcce58f676189a2b4aec1286b1d2b7 Mon Sep 17 00:00:00 2001 From: student-d-sherstnev Date: Wed, 25 Feb 2026 13:55:03 +0300 Subject: [PATCH 12/13] AES encryption --- .../ru/myitschool/work/data/AESEncryption.kt | 58 +++++++++++++++++++ .../work/data/repo/AuthRepository.kt | 17 ++++-- .../work/data/source/NetworkDataSource.kt | 16 ++++- 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/ru/myitschool/work/data/AESEncryption.kt diff --git a/app/src/main/java/ru/myitschool/work/data/AESEncryption.kt b/app/src/main/java/ru/myitschool/work/data/AESEncryption.kt new file mode 100644 index 0000000..00e2a8b --- /dev/null +++ b/app/src/main/java/ru/myitschool/work/data/AESEncryption.kt @@ -0,0 +1,58 @@ +package ru.myitschool.work.data + +import android.util.Base64 +import javax.crypto.Cipher +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.PBEKeySpec +import javax.crypto.spec.SecretKeySpec + + +object AESEncyption { + + const val secretKey = "tK5Ugskdkipokuodvknfdk3434weofnf=" + const val salt = "QLlGNHNhYTJTQWZ2bGhpV3U=" + const val iv = "bVQqNFNhRkQ1Njc4UUFaPA==" + + fun encrypt(strToEncrypt: String): String? { + try { + val ivParameterSpec = IvParameterSpec(Base64.decode(iv, Base64.DEFAULT)) + + val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") + val spec = + PBEKeySpec(secretKey.toCharArray(), Base64.decode(salt, Base64.DEFAULT), 10000, 256) + val tmp = factory.generateSecret(spec) + val secretKey = SecretKeySpec(tmp.encoded, "AES") + + val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding") + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec) + return Base64.encodeToString( + cipher.doFinal(strToEncrypt.toByteArray(Charsets.UTF_8)), + Base64.DEFAULT + ) + } catch (e: Exception) { + println("Error while encrypting: $e") + } + return null + } + + fun decrypt(strToDecrypt: String?): String? { + try { + + val ivParameterSpec = IvParameterSpec(Base64.decode(iv, Base64.DEFAULT)) + + val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") + val spec = + PBEKeySpec(secretKey.toCharArray(), Base64.decode(salt, Base64.DEFAULT), 10000, 256) + val tmp = factory.generateSecret(spec) + val secretKey = SecretKeySpec(tmp.encoded, "AES") + + val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding") + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec) + return String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT))) + } catch (e: Exception) { + println("Error while decrypting: $e") + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt index f6240b2..8dffc44 100644 --- a/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt +++ b/app/src/main/java/ru/myitschool/work/data/repo/AuthRepository.kt @@ -8,6 +8,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.firstOrNull import ru.myitschool.work.App +import ru.myitschool.work.data.AESEncyption import ru.myitschool.work.data.dto.AuthRequestDto import ru.myitschool.work.data.dto.AuthResponseDto import ru.myitschool.work.data.source.NetworkDataSource @@ -21,10 +22,13 @@ object AuthRepository { suspend fun checkAndSave(login: String, password: String): Result { val data = AuthRequestDto(login=login, password=password) return NetworkDataSource.checkAuth(data).onSuccess { success -> - tokenCache = success.token - App.context.userDataStore.edit { preferences -> - val prefKey = stringPreferencesKey(TOKEN_KEY) - preferences[prefKey] = success.token + val encryptedTokenCache = AESEncyption.encrypt(success.token) + tokenCache = encryptedTokenCache + if (encryptedTokenCache != null) { + App.context.userDataStore.edit { preferences -> + val prefKey = stringPreferencesKey(TOKEN_KEY) + preferences[prefKey] = encryptedTokenCache + } } } } @@ -37,7 +41,10 @@ object AuthRepository { preferences[stringPreferencesKey(TOKEN_KEY)] } } - return tokenCache + if (tokenCache != null) { + return AESEncyption.decrypt(tokenCache) + } + return null } suspend fun logout() { diff --git a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt index 1405880..dee42cb 100644 --- a/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt +++ b/app/src/main/java/ru/myitschool/work/data/source/NetworkDataSource.kt @@ -22,6 +22,7 @@ import ru.myitschool.work.data.dto.AuthResponseDto import ru.myitschool.work.data.dto.PlaceDto import ru.myitschool.work.data.dto.BookRequestDto import ru.myitschool.work.data.dto.UserDto +import ru.myitschool.work.data.repo.AuthRepository object NetworkDataSource { private val client by lazy { @@ -41,7 +42,7 @@ object NetworkDataSource { suspend fun checkAuth(data: AuthRequestDto): Result = withContext(Dispatchers.IO) { return@withContext runCatching { - val response = client.post(getUrl(Constants.BOOK_URL)) { + val response = client.post(getUrl(Constants.AUTH_URL)) { contentType(ContentType.Application.Json) setBody(data) } @@ -64,6 +65,9 @@ object NetworkDataSource { println("!!!!!!!!!!!!!! getInfo OK ${response.bodyAsText()}") response.body() } else { + if (response.status == HttpStatusCode.Unauthorized) { + AuthRepository.logout() + } println("!!!!!!!!!!!!!! getInfo ERROR ${response.bodyAsText()}") error(response.bodyAsText()) } @@ -80,6 +84,9 @@ object NetworkDataSource { if (response.status == HttpStatusCode.OK) { response.body>>() } else { + if (response.status == HttpStatusCode.Unauthorized) { + AuthRepository.logout() + } error(response.bodyAsText()) } } @@ -97,7 +104,12 @@ object NetworkDataSource { when (response.status) { HttpStatusCode.Created -> true HttpStatusCode.Conflict -> false - else -> error(response.bodyAsText()) + else -> { + if (response.status == HttpStatusCode.Unauthorized) { + AuthRepository.logout() + } + error(response.bodyAsText()) + } } } } -- 2.47.1 From 949c96b7ca94c92dd3eec99520bebe24b3538775 Mon Sep 17 00:00:00 2001 From: student-d-sherstnev Date: Wed, 25 Feb 2026 13:57:52 +0300 Subject: [PATCH 13/13] navigation graph refactor --- .../main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt b/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt index 3590d24..a7fedb0 100644 --- a/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt +++ b/app/src/main/java/ru/myitschool/work/ui/screen/NavigationGraph.kt @@ -13,7 +13,6 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import kotlinx.coroutines.delay import ru.myitschool.work.data.repo.AuthRepository import ru.myitschool.work.domain.auth.GetCodeUseCase import ru.myitschool.work.ui.nav.AppDestination -- 2.47.1