add 2fa auth
This commit is contained in:
parent
372dc92c8d
commit
1449e003de
@ -46,6 +46,7 @@ final class AuthService {
|
||||
NetworkClient.shared.request(
|
||||
path: "/v1/auth/login/password",
|
||||
method: .post,
|
||||
headers: ["X-Client-Type": "ios"],
|
||||
body: body,
|
||||
requiresAuth: false
|
||||
) { result in
|
||||
@ -84,22 +85,87 @@ final class AuthService {
|
||||
}
|
||||
|
||||
func requestLoginCode(identifier: String, completion: @escaping (Bool, String?) -> Void) {
|
||||
if AppConfig.DEBUG {
|
||||
print("[AuthService] requestLoginCode placeholder for \(identifier)")
|
||||
let payload = LoginCodeRequestPayload(login: identifier)
|
||||
|
||||
guard let body = try? JSONEncoder().encode(payload) else {
|
||||
completion(false, NSLocalizedString("Не удалось сериализовать данные запроса.", comment: ""))
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 0.8) {
|
||||
completion(true, nil)
|
||||
NetworkClient.shared.request(
|
||||
path: "/v1/auth/login/code",
|
||||
method: .post,
|
||||
headers: ["X-Client-Type": "ios"],
|
||||
body: body,
|
||||
requiresAuth: false
|
||||
) { [weak self] result in
|
||||
guard let self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let response):
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
let apiResponse = try decoder.decode(APIResponse<MessagePayload>.self, from: response.data)
|
||||
guard apiResponse.status == "fine" else {
|
||||
let message = apiResponse.detail ?? apiResponse.data.message
|
||||
completion(false, message)
|
||||
return
|
||||
}
|
||||
completion(true, nil)
|
||||
} catch {
|
||||
completion(false, NSLocalizedString("Не удалось обработать ответ сервера.", comment: ""))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(false, self.passwordlessRequestErrorMessage(for: error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loginWithCode(identifier: String, code: String, completion: @escaping (Bool, String?) -> Void) {
|
||||
if AppConfig.DEBUG {
|
||||
print("[AuthService] loginWithCode placeholder for \(identifier) using code \(code)")
|
||||
let payload = VerifyCodeRequestPayload(login: identifier, otp: code)
|
||||
|
||||
guard let body = try? JSONEncoder().encode(payload) else {
|
||||
completion(false, NSLocalizedString("Не удалось сериализовать данные запроса.", comment: ""))
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
|
||||
completion(false, NSLocalizedString("Вход по коду пока недоступен. Заглушка.", comment: ""))
|
||||
NetworkClient.shared.request(
|
||||
path: "/v1/auth/login/verify_code",
|
||||
method: .post,
|
||||
headers: ["X-Client-Type": "ios"],
|
||||
body: body,
|
||||
requiresAuth: false
|
||||
) { [weak self] result in
|
||||
guard let self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let response):
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
let apiResponse = try decoder.decode(APIResponse<TokenPairPayload>.self, from: response.data)
|
||||
guard apiResponse.status == "fine" else {
|
||||
let message = apiResponse.detail ?? NSLocalizedString("Проверьте код и попробуйте снова.", comment: "")
|
||||
completion(false, message)
|
||||
return
|
||||
}
|
||||
|
||||
let tokens = apiResponse.data
|
||||
KeychainService.shared.save(tokens.access_token, forKey: "access_token", service: identifier)
|
||||
KeychainService.shared.save(tokens.refresh_token, forKey: "refresh_token", service: identifier)
|
||||
if let userId = tokens.user_id {
|
||||
KeychainService.shared.save(userId, forKey: "userId", service: identifier)
|
||||
}
|
||||
UserDefaults.standard.set(identifier, forKey: "currentUser")
|
||||
|
||||
NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
|
||||
|
||||
completion(true, nil)
|
||||
} catch {
|
||||
completion(false, NSLocalizedString("Не удалось обработать ответ сервера.", comment: ""))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(false, self.passwordlessVerifyErrorMessage(for: error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,6 +347,70 @@ final class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
private func passwordlessRequestErrorMessage(for error: NetworkError) -> String {
|
||||
switch error {
|
||||
case .network(let err):
|
||||
return String(format: NSLocalizedString("Ошибка сети: %@", comment: ""), err.localizedDescription)
|
||||
case .server(let statusCode, let data):
|
||||
let message = extractMessage(from: data)
|
||||
|
||||
switch statusCode {
|
||||
case 401, 404:
|
||||
return message ?? NSLocalizedString("Аккаунт не найден.", comment: "")
|
||||
case 403:
|
||||
return message ?? NSLocalizedString("Этому аккаунту недоступен вход по коду.", comment: "")
|
||||
case 422:
|
||||
return message ?? NSLocalizedString("Неверный логин. Проверьте и попробуйте снова.", comment: "")
|
||||
case 429:
|
||||
return NSLocalizedString("Слишком много попыток. Попробуйте позже.", comment: "")
|
||||
case 502:
|
||||
return NSLocalizedString("Сервер не отвечает. Попробуйте позже.", comment: "")
|
||||
default:
|
||||
if let message {
|
||||
return message
|
||||
}
|
||||
return String(format: NSLocalizedString("Ошибка сервера: %@", comment: ""), "\(statusCode)")
|
||||
}
|
||||
case .unauthorized:
|
||||
return NSLocalizedString("Необходимо авторизоваться заново.", comment: "")
|
||||
case .invalidURL, .noResponse:
|
||||
return NSLocalizedString("Некорректный ответ от сервера.", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
private func passwordlessVerifyErrorMessage(for error: NetworkError) -> String {
|
||||
switch error {
|
||||
case .network(let err):
|
||||
return String(format: NSLocalizedString("Ошибка сети: %@", comment: ""), err.localizedDescription)
|
||||
case .server(let statusCode, let data):
|
||||
let message = extractMessage(from: data)
|
||||
|
||||
switch statusCode {
|
||||
case 401:
|
||||
return message ?? NSLocalizedString("Неверный или просроченный код.", comment: "")
|
||||
case 403:
|
||||
return message ?? NSLocalizedString("Этот аккаунт недоступен.", comment: "")
|
||||
case 404:
|
||||
return message ?? NSLocalizedString("Аккаунт не найден.", comment: "")
|
||||
case 422:
|
||||
return message ?? NSLocalizedString("Некорректные данные. Проверьте код и логин.", comment: "")
|
||||
case 429:
|
||||
return NSLocalizedString("Слишком много попыток. Попробуйте позже.", comment: "")
|
||||
case 502:
|
||||
return NSLocalizedString("Сервер не отвечает. Попробуйте позже.", comment: "")
|
||||
default:
|
||||
if let message {
|
||||
return message
|
||||
}
|
||||
return String(format: NSLocalizedString("Ошибка сервера: %@", comment: ""), "\(statusCode)")
|
||||
}
|
||||
case .unauthorized:
|
||||
return NSLocalizedString("Сессия недействительна. Авторизуйтесь заново.", comment: "")
|
||||
case .invalidURL, .noResponse:
|
||||
return NSLocalizedString("Некорректный ответ от сервера.", comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
private func mappedRegistrationMessage(for message: String, statusCode: Int) -> String {
|
||||
if statusCode == 400 {
|
||||
if message.contains("Invalid invitation code") {
|
||||
@ -420,6 +550,15 @@ private struct LoginRequest: Encodable {
|
||||
let password: String
|
||||
}
|
||||
|
||||
private struct LoginCodeRequestPayload: Encodable {
|
||||
let login: String
|
||||
}
|
||||
|
||||
private struct VerifyCodeRequestPayload: Encodable {
|
||||
let login: String
|
||||
let otp: String
|
||||
}
|
||||
|
||||
private struct RegisterRequest: Encodable {
|
||||
let login: String
|
||||
let password: String
|
||||
|
||||
@ -208,6 +208,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Аккаунт не найден." : {
|
||||
|
||||
},
|
||||
"Активные сессии" : {
|
||||
"comment" : "Заголовок экрана активных сессий",
|
||||
@ -394,9 +397,6 @@
|
||||
},
|
||||
"Вход и защита аккаунта (заглушка)" : {
|
||||
"comment" : "Раздел настроек безопасности для аутентификации"
|
||||
},
|
||||
"Вход по коду пока недоступен. Заглушка." : {
|
||||
|
||||
},
|
||||
"Вход по паролю" : {
|
||||
|
||||
@ -1272,6 +1272,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Неверный или просроченный код." : {
|
||||
|
||||
},
|
||||
"Неверный код" : {
|
||||
"comment" : "Заголовок ошибки неправильного кода 2FA"
|
||||
@ -1306,6 +1309,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Неверный логин. Проверьте и попробуйте снова." : {
|
||||
|
||||
},
|
||||
"Неверный пароль" : {
|
||||
"comment" : "Неверный пароль",
|
||||
@ -1378,6 +1384,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Некорректные данные. Проверьте код и логин." : {
|
||||
|
||||
},
|
||||
"Некорректный ответ от сервера." : {
|
||||
|
||||
@ -2123,6 +2132,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Проверьте код и попробуйте снова." : {
|
||||
|
||||
},
|
||||
"Проверьте цифры и попробуйте снова." : {
|
||||
"comment" : "Описание ошибки неверного кода 2FA"
|
||||
@ -2376,6 +2388,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Сессия недействительна. Авторизуйтесь заново." : {
|
||||
|
||||
},
|
||||
"Системная" : {
|
||||
"localizations" : {
|
||||
@ -2783,6 +2798,12 @@
|
||||
},
|
||||
"Это устройство" : {
|
||||
"comment" : "Заголовок секции текущего устройства"
|
||||
},
|
||||
"Этому аккаунту недоступен вход по коду." : {
|
||||
|
||||
},
|
||||
"Этот аккаунт недоступен." : {
|
||||
|
||||
},
|
||||
"Я ознакомился и принимаю правила сервиса" : {
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user