mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
[WIP] Email authorization
This commit is contained in:
@@ -108,7 +108,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
return updatedAccount.network.request(Api.functions.account.getPassword(), automaticFloodWait: false)
|
||||
|> mapToSignal { result -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in
|
||||
switch result {
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _):
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _, _):
|
||||
return .single((.password(hint: hint), updatedAccount))
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
}
|
||||
|> mapToSignal { result -> Signal<(SendCodeResult, UnauthorizedAccount), AuthorizationCodeRequestError> in
|
||||
switch result {
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _):
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _, _):
|
||||
return .single((.password(hint: hint), account))
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|
||||
return account.postbox.transaction { transaction -> UnauthorizedAccount in
|
||||
switch result {
|
||||
case let .password(hint):
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts)))
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts)))
|
||||
case let .sentCode(sentCode):
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
|
||||
@@ -239,10 +239,65 @@ private enum AuthorizationCodeResult {
|
||||
case signUp
|
||||
}
|
||||
|
||||
public enum AuthorizationCode: PostboxCoding, Equatable {
|
||||
private enum CodeType: Int32 {
|
||||
case phoneCode = 0
|
||||
case emailCode = 1
|
||||
case appleToken = 2
|
||||
case googleToken = 3
|
||||
}
|
||||
|
||||
public enum EmailVerification: Equatable {
|
||||
case emailCode(String)
|
||||
case appleToken(String)
|
||||
case googleToken(String)
|
||||
}
|
||||
|
||||
case phoneCode(String)
|
||||
case emailVerification(EmailVerification)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let type = decoder.decodeInt32ForKey("t", orElse: 0)
|
||||
switch type {
|
||||
case CodeType.phoneCode.rawValue:
|
||||
self = .phoneCode(decoder.decodeStringForKey("c", orElse: ""))
|
||||
case CodeType.emailCode.rawValue:
|
||||
self = .emailVerification(.emailCode(decoder.decodeStringForKey("c", orElse: "")))
|
||||
case CodeType.appleToken.rawValue:
|
||||
self = .emailVerification(.appleToken(decoder.decodeStringForKey("c", orElse: "")))
|
||||
case CodeType.googleToken.rawValue:
|
||||
self = .emailVerification(.googleToken(decoder.decodeStringForKey("c", orElse: "")))
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .phoneCode("")
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case let .phoneCode(code):
|
||||
encoder.encodeInt32(CodeType.phoneCode.rawValue, forKey: "t")
|
||||
encoder.encodeString(code, forKey: "c")
|
||||
case let .emailVerification(verification):
|
||||
switch verification {
|
||||
case let .emailCode(code):
|
||||
encoder.encodeInt32(CodeType.emailCode.rawValue, forKey: "t")
|
||||
encoder.encodeString(code, forKey: "c")
|
||||
case let .appleToken(token):
|
||||
encoder.encodeInt32(CodeType.appleToken.rawValue, forKey: "t")
|
||||
encoder.encodeString(token, forKey: "c")
|
||||
case let .googleToken(token):
|
||||
encoder.encodeInt32(CodeType.googleToken.rawValue, forKey: "t")
|
||||
encoder.encodeString(token, forKey: "c")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct AuthorizationSignUpData {
|
||||
let number: String
|
||||
let codeHash: String
|
||||
let code: String
|
||||
let code: AuthorizationCode
|
||||
let termsOfService: UnauthorizedAccountTermsOfService?
|
||||
let syncContacts: Bool
|
||||
}
|
||||
@@ -252,12 +307,153 @@ public enum AuthorizeWithCodeResult {
|
||||
case loggedIn
|
||||
}
|
||||
|
||||
public func authorizeWithCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> {
|
||||
public enum AuthorizationSendEmailCodeError {
|
||||
case generic
|
||||
case limitExceeded
|
||||
case codeExpired
|
||||
case timeout
|
||||
}
|
||||
|
||||
public enum AuthorizationEmailVerificationError {
|
||||
case generic
|
||||
case limitExceeded
|
||||
case codeExpired
|
||||
case invalidCode
|
||||
case timeout
|
||||
}
|
||||
|
||||
public func sendLoginEmailCode(account: UnauthorizedAccount, email: String) -> Signal<Never, AuthorizationSendEmailCodeError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Never, AuthorizationSendEmailCodeError> in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
switch state.contents {
|
||||
case let .confirmationCodeEntry(phoneNumber, _, phoneCodeHash, _, _, syncContacts):
|
||||
return account.network.request(Api.functions.account.sendVerifyEmailCode(purpose: .emailVerifyPurposeLoginSetup(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), email: email), automaticFloodWait: false)
|
||||
|> `catch` { error -> Signal<Api.account.SentEmailCode, AuthorizationSendEmailCodeError> in
|
||||
let errorDescription = error.errorDescription ?? ""
|
||||
if errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .fail(.limitExceeded)
|
||||
} else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" {
|
||||
return .fail(.codeExpired)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, AuthorizationSendEmailCodeError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .sentEmailCode(emailPattern, length):
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: .email(emailPattern: emailPattern, length: length, nextPhoneLoginDate: nil, appleSignInAllowed: false, setup: true), hash: phoneCodeHash, timeout: nil, nextType: nil, syncContacts: syncContacts)))
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> switchToLatest
|
||||
|> mapError { _ -> AuthorizationSendEmailCodeError in
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> AuthorizationSendEmailCodeError in
|
||||
}
|
||||
|> switchToLatest
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func verifyLoginEmail(account: UnauthorizedAccount, code: AuthorizationCode.EmailVerification) -> Signal<Never, AuthorizationEmailVerificationError> {
|
||||
return account.postbox.transaction { transaction -> Signal<Never, AuthorizationEmailVerificationError> in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
switch state.contents {
|
||||
case let .confirmationCodeEntry(phoneNumber, _, phoneCodeHash, _, _, syncContacts):
|
||||
let verification: Api.EmailVerification
|
||||
switch code {
|
||||
case let .emailCode(code):
|
||||
verification = .emailVerificationCode(code: code)
|
||||
case let .appleToken(token):
|
||||
verification = .emailVerificationApple(token: token)
|
||||
case let .googleToken(token):
|
||||
verification = .emailVerificationGoogle(token: token)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.account.verifyEmail(purpose: .emailVerifyPurposeLoginSetup(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), verification: verification), automaticFloodWait: false)
|
||||
|> `catch` { error -> Signal<Api.account.EmailVerified, AuthorizationEmailVerificationError> in
|
||||
let errorDescription = error.errorDescription ?? ""
|
||||
if errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .fail(.limitExceeded)
|
||||
} else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" {
|
||||
return .fail(.codeExpired)
|
||||
} else if errorDescription == "" {
|
||||
return .fail(.invalidCode)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, AuthorizationEmailVerificationError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
switch result {
|
||||
case let .emailVerifiedLogin(_, sentCode):
|
||||
switch sentCode {
|
||||
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):
|
||||
var parsedNextType: AuthorizationCodeNextType?
|
||||
if let nextType = nextType {
|
||||
parsedNextType = AuthorizationCodeNextType(apiType: nextType)
|
||||
}
|
||||
|
||||
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType, syncContacts: syncContacts)))
|
||||
}
|
||||
case .emailVerified:
|
||||
break
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> switchToLatest
|
||||
|> mapError { _ -> AuthorizationEmailVerificationError in
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> AuthorizationEmailVerificationError in
|
||||
}
|
||||
|> switchToLatest
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func authorizeWithCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, code: AuthorizationCode, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> {
|
||||
return account.postbox.transaction { transaction -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> in
|
||||
if let state = transaction.getState() as? UnauthorizedAccountState {
|
||||
switch state.contents {
|
||||
case let .confirmationCodeEntry(number, _, hash, _, _, syncContacts):
|
||||
return account.network.request(Api.functions.auth.signIn(phoneNumber: number, phoneCodeHash: hash, phoneCode: code), automaticFloodWait: false)
|
||||
var flags: Int32 = 0
|
||||
var phoneCode: String?
|
||||
var emailVerification: Api.EmailVerification?
|
||||
|
||||
switch code {
|
||||
case let .phoneCode(code):
|
||||
flags = 1 << 0
|
||||
phoneCode = code
|
||||
case let .emailVerification(verification):
|
||||
flags = 1 << 1
|
||||
switch verification {
|
||||
case let .emailCode(code):
|
||||
emailVerification = .emailVerificationCode(code: code)
|
||||
case let .appleToken(token):
|
||||
emailVerification = .emailVerificationApple(token: token)
|
||||
case let .googleToken(token):
|
||||
emailVerification = .emailVerificationGoogle(token: token)
|
||||
}
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.auth.signIn(flags: flags, phoneNumber: number, phoneCodeHash: hash, phoneCode: phoneCode, emailVerification: emailVerification), automaticFloodWait: false)
|
||||
|> map { authorization in
|
||||
return .authorization(authorization)
|
||||
}
|
||||
@@ -274,7 +470,7 @@ public func authorizeWithCode(accountManager: AccountManager<TelegramAccountMana
|
||||
}
|
||||
|> mapToSignal { result -> Signal<AuthorizationCodeResult, AuthorizationCodeVerificationError> in
|
||||
switch result {
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _):
|
||||
case let .password(_, _, _, _, hint, _, _, _, _, _, _):
|
||||
return .single(.password(hint: hint ?? ""))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user