From 8f1c9019be82d365fa1c412000a636331bcd1300 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 2 Dec 2025 01:43:04 +0800 Subject: [PATCH 1/2] Passkeys --- Telegram/BUILD | 1 + .../AuthorizationSequenceController.swift | 10 +- ...rizationSequencePhoneEntryController.swift | 24 ++- ...tionSequencePhoneEntryControllerNode.swift | 50 ++++- .../PrivacyAndSecurityController.swift | 2 +- .../Sources/Account/Account.swift | 8 +- .../TelegramCore/Sources/Authorization.swift | 182 ++++++++++-------- .../Sources/Network/Network.swift | 16 ++ .../Components/Settings/PasskeysScreen/BUILD | 1 + .../Sources/PasskeysScreen.swift | 4 +- .../PasskeysScreenIntroComponent.swift | 2 +- .../Sources/PasskeysScreenListComponent.swift | 47 ++++- .../Menu/Passkeys.imageset/Contents.json | 12 ++ .../Menu/Passkeys.imageset/key_30.pdf | Bin 0 -> 11847 bytes .../Menu/TwoStepAuth.imageset/Contents.json | 2 +- .../Menu/TwoStepAuth.imageset/Icon-5.pdf | 114 ----------- .../Menu/TwoStepAuth.imageset/lock_30.pdf | Bin 0 -> 11909 bytes .../Resources/Animations/passkey_logo.tgs | Bin 0 -> 44400 bytes 18 files changed, 264 insertions(+), 211 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/key_30.pdf delete mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/TwoStepAuth.imageset/Icon-5.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Menu/TwoStepAuth.imageset/lock_30.pdf create mode 100644 submodules/TelegramUI/Resources/Animations/passkey_logo.tgs diff --git a/Telegram/BUILD b/Telegram/BUILD index aacae96803..74b3ecae94 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -496,6 +496,7 @@ associated_domains_fragment = "" if telegram_bundle_id not in official_bundle_id applinks:t.me applinks:*.t.me webcredentials:t.me + webcredentials:telegram.org """ diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index 9c9c03a5d3..b6d861d6f2 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -324,6 +324,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth accountManager: self.sharedContext.accountManager, account: self.account, passkey: passkey, + foreignDatacenter: nil, forcedPasswordSetupNotice: { value in guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else { return nil @@ -332,7 +333,14 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth }, syncContacts: syncContacts ) - |> deliverOnMainQueue).startStrict(next: { _ in + |> deliverOnMainQueue).startStrict(next: { [weak self] result in + guard let self else { + return + } + if result.updatedAccount !== self.account { + self.account = result.updatedAccount + self.inAppPurchaseManager = InAppPurchaseManager(engine: .unauthorized(self.engine)) + } }, error: { [weak self, weak controller] error in Queue.mainQueue().async { if let strongSelf = self, let controller { diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift index ac22728099..54855476a3 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift @@ -157,6 +157,12 @@ public final class AuthorizationSequencePhoneEntryController: ViewController, MF strongSelf.account = account strongSelf.accountUpdated?(account) } + self.controllerNode.retryPasskey = { [weak self] in + guard let self else { + return + } + self.loadAndPresentPasskey(force: true) + } if let (code, name, number) = self.currentData { self.controllerNode.codeAndNumber = (code, name, number) @@ -194,7 +200,11 @@ public final class AuthorizationSequencePhoneEntryController: ViewController, MF self.controllerNode.updateCountryCode() } - if #available(iOS 15.0, *) { + self.loadAndPresentPasskey(force: false) + } + + private func loadAndPresentPasskey(force: Bool) { + if #available(iOS 16.0, *) { Task { @MainActor [weak self] in guard let self, let account = self.account else { return @@ -235,7 +245,11 @@ public final class AuthorizationSequencePhoneEntryController: ViewController, MF let authController = ASAuthorizationController(authorizationRequests: [platformKeyRequest]) authController.delegate = self authController.presentationContextProvider = self - authController.performRequests() + if force { + authController.performRequests() + } else { + authController.performRequests(options: [.preferImmediatelyAvailableCredentials]) + } } } } @@ -290,6 +304,12 @@ public final class AuthorizationSequencePhoneEntryController: ViewController, MF } public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: any Error) { + if (error as NSError).domain == "com.apple.AuthenticationServices.AuthorizationError" && (error as NSError).code == 1001 { + self.controllerNode.updateDisplayPasskeyLoginOption() + if let validLayout = self.validLayout { + self.containerLayoutUpdated(validLayout, transition: .immediate) + } + } } public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift index fafaac93ba..189f8e7c13 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift @@ -15,6 +15,7 @@ import TelegramAnimatedStickerNode import SolidRoundedButtonNode import AuthorizationUtils import ManagedAnimationNode +import Markdown private final class PhoneAndCountryNode: ASDisplayNode { let strings: PresentationStrings @@ -312,7 +313,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { private let managedAnimationNode: ManagedPhoneAnimationNode private let titleNode: ASTextNode private let titleActivateAreaNode: AccessibilityAreaNode - private let noticeNode: ASTextNode + private let noticeNode: ImmediateTextNode private let noticeActivateAreaNode: AccessibilityAreaNode private let phoneAndCountryNode: PhoneAndCountryNode private let contactSyncNode: ContactSyncNode @@ -323,6 +324,8 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { private let tokenEventsDisposable = MetaDisposable() var accountUpdated: ((UnauthorizedAccount) -> Void)? + var retryPasskey: (() -> Void)? + private let debugAction: () -> Void var currentNumber: String { @@ -405,7 +408,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { self.titleActivateAreaNode = AccessibilityAreaNode() self.titleActivateAreaNode.accessibilityTraits = .staticText - self.noticeNode = ASTextNode() + self.noticeNode = ImmediateTextNode() self.noticeNode.maximumNumberOfLines = 0 self.noticeNode.isUserInteractionEnabled = true self.noticeNode.displaysAsynchronously = false @@ -443,6 +446,23 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { self.addSubnode(self.managedAnimationNode) self.contactSyncNode.isHidden = true + self.noticeNode.highlightAttributeAction = { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] { + return NSAttributedString.Key(rawValue: "URL") + } else { + return nil + } + } + self.noticeNode.tapAttributeAction = { [weak self] attributes, _ in + guard let self else { + return + } + if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] as? String { + self.retryPasskey?() + } + } + self.noticeNode.linkHighlightColor = theme.list.itemAccentColor.withAlphaComponent(0.2) + self.phoneAndCountryNode.selectCountryCode = { [weak self] in self?.selectCountryCode?() } @@ -484,7 +504,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { super.didLoad() self.titleNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugTap(_:)))) - #if DEBUG + #if DEBUG && false self.noticeNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.debugQrTap(_:)))) #endif } @@ -555,6 +575,28 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { let _ = self.phoneAndCountryNode.processNumberChange(number: self.phoneAndCountryNode.phoneInputNode.number) } + func updateDisplayPasskeyLoginOption() { + //TODO:localize + if self.account == nil { + return + } + let attributedText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("Enter your phone number\nor [log in using Passkey >](passkey)", attributes: MarkdownAttributes( + body: MarkdownAttributeSet(font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor), + bold: MarkdownAttributeSet(font: Font.semibold(17.0), textColor: self.theme.list.itemPrimaryTextColor), + link: MarkdownAttributeSet(font: Font.regular(17.0), textColor: self.theme.list.itemAccentColor), + linkAttribute: { url in + return ("URL", url) + } + ))) + let chevronImage = generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: self.theme.list.itemAccentColor) + + if let range = attributedText.string.range(of: ">"), let chevronImage { + attributedText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: attributedText.string)) + } + + self.noticeNode.attributedText = attributedText + } + func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { var insets = layout.insets(options: []) insets.top = layout.statusBarHeight ?? 20.0 @@ -576,7 +618,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { let noticeInset: CGFloat = self.account == nil ? 32.0 : 0.0 - let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0 + noticeInset, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude)) + let noticeSize = self.noticeNode.updateLayout(CGSize(width: min(274.0 + noticeInset, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude)) let proceedHeight = self.proceedNode.updateLayout(width: maximumWidth - inset * 2.0, transition: transition) let proceedSize = CGSize(width: maximumWidth - inset * 2.0, height: proceedHeight) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index ee04c6c975..c7ec6407bb 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -501,7 +501,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { arguments.openTwoStepVerification(data) }) case let .passkeys(_, text, value): - return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, icon: UIImage(bundleImageName: "Settings/Menu/TwoStepAuth")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: { + return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, icon: UIImage(bundleImageName: "Settings/Menu/Passkeys")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: { arguments.openPasskeys() }) case let .messageAutoremoveTimeout(_, text, value): diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 076f486ed2..262176da07 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -340,7 +340,13 @@ public func accountWithId(accountManager: AccountManager map { network -> AccountResult in return .unauthorized(UnauthorizedAccount(accountManager: accountManager, networkArguments: networkArguments, id: id, rootPath: rootPath, basePath: path, testingEnvironment: beginWithTestingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection)) } diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 7d9c14bf2e..db7ce4dd78 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -1183,91 +1183,117 @@ public final class AuthorizationPasskeyData { } } -public func authorizeWithPasskey(accountManager: AccountManager, account: UnauthorizedAccount, passkey: AuthorizationPasskeyData, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?, syncContacts: Bool) -> Signal { - return account.postbox.transaction { transaction -> Signal in - return account.network.request(Api.functions.auth.finishPasskeyLogin(flags: 0, credential: .inputPasskeyCredentialPublicKey(id: passkey.id, rawId: passkey.id, response: .inputPasskeyResponseLogin(clientData: .dataJSON(data: passkey.clientData), authenticatorData: Buffer(data: passkey.authenticatorData), signature: Buffer(data: passkey.signature), userHandle: passkey.userHandle)), fromDcId: nil, fromAuthKeyId: nil), automaticFloodWait: false) - |> map { authorization in - return .authorization(authorization) - } - |> `catch` { error -> Signal in - switch (error.errorCode, error.errorDescription ?? "") { - case (401, "SESSION_PASSWORD_NEEDED"): - return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) - |> mapError { error -> AuthorizationCodeVerificationError in - if error.errorDescription.hasPrefix("FLOOD_WAIT") { - return .limitExceeded - } else { - return .generic - } - } - |> mapToSignal { result -> Signal in - switch result { - case let .password(_, _, _, _, hint, _, _, _, _, _, _): - return .single(.password(hint: hint ?? "")) - } - } - case let (_, errorDescription): - if errorDescription.hasPrefix("FLOOD_WAIT") { - return .fail(.limitExceeded) - } else if errorDescription == "PHONE_CODE_INVALID" || errorDescription == "EMAIL_CODE_INVALID" { - return .fail(.invalidCode) - } else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" { - return .fail(.codeExpired) - } else if errorDescription == "PHONE_NUMBER_UNOCCUPIED" { - return .single(.signUp) - } else if errorDescription == "EMAIL_TOKEN_INVALID" { - return .fail(.invalidEmailToken) - } else if errorDescription == "EMAIL_ADDRESS_INVALID" { - return .fail(.invalidEmailAddress) - } else { - return .fail(.generic) - } +public final class AuthorizeWithPasskeyResult { + public let updatedAccount: UnauthorizedAccount + + init(updatedAccount: UnauthorizedAccount) { + self.updatedAccount = updatedAccount + } +} + +public func authorizeWithPasskey(accountManager: AccountManager, account: UnauthorizedAccount, passkey: AuthorizationPasskeyData, foreignDatacenter: (id: Int, authKeyId: Int64)?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?, syncContacts: Bool) -> Signal { + let userHandle = passkey.userHandle.components(separatedBy: ":") + var targetDatacenterId: Int? + if foreignDatacenter == nil && userHandle.count >= 2 { + targetDatacenterId = Int(userHandle[0]) + } + + if let targetDatacenterId, account.masterDatacenterId != Int32(targetDatacenterId) { + let initialDatacenterId = account.masterDatacenterId + return account.network.getAuthKeyId() + |> castError(AuthorizationCodeVerificationError.self) + |> mapToSignal { sourceAuthKeyId -> Signal in + let updatedAccount = account.changedMasterDatacenterId(accountManager: accountManager, masterDatacenterId: Int32(targetDatacenterId)) + return updatedAccount + |> mapToSignalPromotingError { updatedAccount -> Signal in + return authorizeWithPasskey(accountManager: accountManager, account: updatedAccount, passkey: passkey, foreignDatacenter: (Int(initialDatacenterId), sourceAuthKeyId), forcedPasswordSetupNotice: forcedPasswordSetupNotice, syncContacts: syncContacts) } } - |> mapToSignal { result -> Signal in - return account.postbox.transaction { transaction -> Signal in - switch result { - case .signUp: - return .fail(.generic) - 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))) - return .single(.loggedIn) - case let .authorization(authorization): - switch authorization { - case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user): - if let futureAuthToken = futureAuthToken { - storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData()) - } - - let user = TelegramUser(user: user) - var isSupportUser = false - if let phone = user.phone, phone.hasPrefix("42") { - isSupportUser = true - } - let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil, invalidatedChannels: []) - initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) - transaction.setState(state) - if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) { - transaction.setNoticeEntry(key: value.0, value: value.1) - } - return accountManager.transaction { transaction -> AuthorizeWithCodeResult in - switchToAuthorizedAccount(transaction: transaction, account: account, isSupportUser: isSupportUser) - return .loggedIn - } - |> castError(AuthorizationCodeVerificationError.self) - case .authorizationSignUpRequired: - return .fail(.generic) + } + + var flags: Int32 = 0 + if foreignDatacenter != nil { + flags |= 1 << 0 + } + return account.network.request(Api.functions.auth.finishPasskeyLogin(flags: flags, credential: .inputPasskeyCredentialPublicKey(id: passkey.id, rawId: passkey.id, response: .inputPasskeyResponseLogin(clientData: .dataJSON(data: passkey.clientData), authenticatorData: Buffer(data: passkey.authenticatorData), signature: Buffer(data: passkey.signature), userHandle: passkey.userHandle)), fromDcId: (foreignDatacenter?.id).flatMap(Int32.init), fromAuthKeyId: foreignDatacenter?.authKeyId), automaticFloodWait: false) + |> map { authorization in + return .authorization(authorization) + } + |> `catch` { error -> Signal in + switch (error.errorCode, error.errorDescription ?? "") { + case (401, "SESSION_PASSWORD_NEEDED"): + return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) + |> mapError { error -> AuthorizationCodeVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else { + return .generic } } - } - |> mapError { _ -> AuthorizationCodeVerificationError in - } - |> switchToLatest + |> mapToSignal { result -> Signal in + switch result { + case let .password(_, _, _, _, hint, _, _, _, _, _, _): + return .single(.password(hint: hint ?? "")) + } + } + case let (_, errorDescription): + if errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if errorDescription == "PHONE_CODE_INVALID" || errorDescription == "EMAIL_CODE_INVALID" { + return .fail(.invalidCode) + } else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" { + return .fail(.codeExpired) + } else if errorDescription == "PHONE_NUMBER_UNOCCUPIED" { + return .single(.signUp) + } else if errorDescription == "EMAIL_TOKEN_INVALID" { + return .fail(.invalidEmailToken) + } else if errorDescription == "EMAIL_ADDRESS_INVALID" { + return .fail(.invalidEmailAddress) + } else { + return .fail(.generic) + } } } - |> mapError { _ -> AuthorizationCodeVerificationError in + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Signal in + switch result { + case .signUp: + return .fail(.generic) + 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))) + return .single(AuthorizeWithPasskeyResult(updatedAccount: account)) + case let .authorization(authorization): + switch authorization { + case let .authorization(_, otherwiseReloginDays, _, futureAuthToken, user): + if let futureAuthToken = futureAuthToken { + storeFutureLoginToken(accountManager: accountManager, token: futureAuthToken.makeData()) + } + + let user = TelegramUser(user: user) + var isSupportUser = false + if let phone = user.phone, phone.hasPrefix("42") { + isSupportUser = true + } + let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil, invalidatedChannels: []) + initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) + transaction.setState(state) + if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) { + transaction.setNoticeEntry(key: value.0, value: value.1) + } + return accountManager.transaction { transaction -> AuthorizeWithPasskeyResult in + switchToAuthorizedAccount(transaction: transaction, account: account, isSupportUser: isSupportUser) + return AuthorizeWithPasskeyResult(updatedAccount: account) + } + |> castError(AuthorizationCodeVerificationError.self) + case .authorizationSignUpRequired: + return .fail(.generic) + } + } + } + |> mapError { _ -> AuthorizationCodeVerificationError in + } + |> switchToLatest } - |> switchToLatest } public enum PasswordRecoveryRequestError { diff --git a/submodules/TelegramCore/Sources/Network/Network.swift b/submodules/TelegramCore/Sources/Network/Network.swift index f9dd1d6c1e..75e53aa7b6 100644 --- a/submodules/TelegramCore/Sources/Network/Network.swift +++ b/submodules/TelegramCore/Sources/Network/Network.swift @@ -1065,6 +1065,22 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate { } } + public func getAuthKeyId() -> Signal { + let mtContext = self.mtProto.context + let datacenterId = self.datacenterId + return Signal { subscriber in + MTContext.contextQueue().dispatch(onQueue: { + var result: Int64 = 0 + if let authInfo = mtContext?.authInfoForDatacenter(withId: datacenterId, selector: .persistent) { + result = authInfo.authKeyId + } + subscriber.putNext(result) + }) + + return EmptyDisposable + } + } + public func requestWithAdditionalInfo(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse), info: NetworkRequestAdditionalInfo, tag: NetworkRequestDependencyTag? = nil, automaticFloodWait: Bool = true, onFloodWaitError: ((String) -> Void)? = nil) -> Signal, MTRpcError> { let requestService = self.requestService return Signal { subscriber in diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/BUILD b/submodules/TelegramUI/Components/Settings/PasskeysScreen/BUILD index 0c4a7d0c38..38a7d38057 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/BUILD @@ -29,6 +29,7 @@ swift_library( "//submodules/TelegramUI/Components/LottieComponent", "//submodules/TelegramUI/Components/ListSectionComponent", "//submodules/TelegramUI/Components/ListActionItemComponent", + "//submodules/TelegramUI/Components/EmojiStatusComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift index c5fd773915..329071ad5d 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift @@ -169,12 +169,12 @@ final class PasskeysScreenComponent: Component { } let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }) //TODO:localize - controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Passkey?", text: "Once deleted, this passkey can't be used to log in.\n\nDon't forget to remove it from your password manager too.", actions: [TextAlertAction(type: .destructiveAction, title: "Delete", action: { [weak self] in + controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Delete Passkey?", text: "Once deleted, this passkey can't be used to log in.\n\nDon't forget to remove it from your password manager too.", actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { + }), TextAlertAction(type: .destructiveAction, title: "Delete", action: { [weak self] in guard let self else { return } self.deletePasskey(id: id) - }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { })]), in: .window(.root)) } diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift index e87589c9fc..bb49ae5cd1 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift @@ -114,7 +114,7 @@ final class PasskeysScreenIntroComponent: Component { let iconSize = self.icon.update( transition: .immediate, component: AnyComponent(LottieComponent( - content: LottieComponent.AppBundleContent(name: "TwoFactorSetupIntro"), + content: LottieComponent.AppBundleContent(name: "passkey_logo"), loop: false )), environment: {}, diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenListComponent.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenListComponent.swift index 4cd18eedd6..dfafe38578 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenListComponent.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenListComponent.swift @@ -12,6 +12,7 @@ import BundleIconComponent import ListSectionComponent import ListActionItemComponent import TelegramCore +import EmojiStatusComponent final class PasskeysScreenListComponent: Component { let context: AccountContext @@ -112,7 +113,7 @@ final class PasskeysScreenListComponent: Component { let iconSize = self.icon.update( transition: .immediate, component: AnyComponent(LottieComponent( - content: LottieComponent.AppBundleContent(name: "TwoFactorSetupIntro"), + content: LottieComponent.AppBundleContent(name: "passkey_logo"), loop: false )), environment: {}, @@ -184,6 +185,43 @@ final class PasskeysScreenListComponent: Component { dateFormatter.dateStyle = .medium let dateString = dateFormatter.string(from: Date(timeIntervalSince1970: Double(passkey.date))) + let iconComponent: AnyComponentWithIdentity + if let emojiId = passkey.emojiId { + iconComponent = AnyComponentWithIdentity( + id: "lottie", + component: AnyComponent(TransformContents( + content: AnyComponent(EmojiStatusComponent( + context: component.context, + animationCache: component.context.animationCache, + animationRenderer: component.context.animationRenderer, + content: .animation( + content: .customEmoji(fileId: emojiId), + size: CGSize(width: 40.0, height: 40.0), + placeholderColor: component.theme.list.mediaPlaceholderColor, + themeColor: nil, + loopMode: .count(1) + ), + size: CGSize(width: 40.0, height: 40.0), + isVisibleForAnimations: true, + action: nil + )), + translation: CGPoint(x: 0.0, y: 1.0) + )) + ) + } else { + iconComponent = AnyComponentWithIdentity( + id: "icon", + component: AnyComponent(BundleIconComponent(name: "Settings/Menu/Passkeys", tintColor: nil)) + ) + } + + //TODO:localize + var subtitleString = "created \(dateString)" + if let lastUsageDate = passkey.lastUsageDate { + let lastUsedDateString = dateFormatter.string(from: Date(timeIntervalSince1970: Double(lastUsageDate))) + subtitleString.append(" • used \(lastUsedDateString)") + } + listSectionItems.append(AnyComponentWithIdentity(id: passkey.id, component: AnyComponent(ListActionItemComponent( theme: component.theme, title: AnyComponent(VStack([ @@ -197,7 +235,7 @@ final class PasskeysScreenListComponent: Component { ))), AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: "created \(dateString)", + string: subtitleString, font: Font.regular(14.0), textColor: component.theme.list.itemSecondaryTextColor )), @@ -205,10 +243,7 @@ final class PasskeysScreenListComponent: Component { ))) ], alignment: .left, spacing: 2.0)), leftIcon: .custom( - AnyComponentWithIdentity( - id: "icon", - component: AnyComponent(BundleIconComponent(name: "Settings/Menu/TwoStepAuth", tintColor: nil)) - ), + iconComponent, false ), accessory: nil, diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/Contents.json new file mode 100644 index 0000000000..be5de9e9a0 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "key_30.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/key_30.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Passkeys.imageset/key_30.pdf new file mode 100644 index 0000000000000000000000000000000000000000..301727da150c80ea8c59baa02bff657057ad7797 GIT binary patch literal 11847 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 AeE> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm -1.000000 0.584314 0.000000 scn -0.000000 18.799999 m -0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c -1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c -5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c -18.799999 30.000000 l -22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c -27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c -30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c -30.000000 11.200001 l -30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c -28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c -24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c -11.200000 0.000000 l -7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c -2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c -0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c -0.000000 18.799999 l -h -f -n -Q -q --1.000000 -0.000000 -0.000000 1.000000 25.000000 6.000000 cm -1.000000 1.000000 1.000000 scn -6.650000 19.000000 m -2.945000 19.000000 0.000000 16.055000 0.000000 12.350000 c -0.000000 8.645000 2.945000 5.700001 6.650000 5.700001 c -7.500165 5.700001 8.310955 5.861581 9.054688 6.145313 c -10.450001 4.750000 l -12.350000 4.750000 l -12.350000 2.850000 l -14.250000 2.850000 l -14.250000 0.950001 l -14.903126 0.296875 l -15.093125 0.106874 15.300938 0.000000 15.585938 0.000000 c -18.049999 0.000000 l -18.619999 0.000000 19.000000 0.380001 19.000000 0.950001 c -19.000000 3.414062 l -19.000000 3.699062 18.893126 3.906875 18.703125 4.096874 c -12.854687 9.945312 l -13.138419 10.689045 13.299999 11.499835 13.299999 12.350000 c -13.299999 16.055000 10.355000 19.000000 6.650000 19.000000 c -h -5.225000 16.150000 m -6.555000 16.150000 7.600000 15.105000 7.600000 13.775000 c -7.600000 12.445000 6.555000 11.400000 5.225000 11.400000 c -3.895000 11.400000 2.850000 12.445000 2.850000 13.775000 c -2.850000 15.105000 3.895000 16.150000 5.225000 16.150000 c -h -f* -n -Q - -endstream -endobj - -3 0 obj - 1987 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Type /Catalog - /Pages 5 0 R - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000002077 00000 n -0000002100 00000 n -0000002273 00000 n -0000002347 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2406 -%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/TwoStepAuth.imageset/lock_30.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/TwoStepAuth.imageset/lock_30.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b1f6efd7ab03b2d4fe446927b793d10b37ba808a GIT binary patch literal 11909 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 z%0A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 M0ebyUnEB5G0E!1?{Qv*} literal 0 HcmV?d00001 From 2967648b2b0957e2a780f2a6191dd3083ca4dd84 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 2 Dec 2025 01:51:40 +0800 Subject: [PATCH 2/2] Update icons --- .../PasskeysScreen/Sources/PasskeysScreen.swift | 2 +- .../Sources/PasskeysScreenIntroComponent.swift | 6 +++--- .../Settings/Passkeys/Contents.json | 9 +++++++++ .../Passkeys/Intro1.imageset/Contents.json | 12 ++++++++++++ .../Settings/Passkeys/Intro1.imageset/key.pdf | Bin 0 -> 5170 bytes .../Passkeys/Intro2.imageset/Contents.json | 12 ++++++++++++ .../Settings/Passkeys/Intro2.imageset/faceid.pdf | Bin 0 -> 5921 bytes .../Passkeys/Intro3.imageset/Contents.json | 12 ++++++++++++ .../Settings/Passkeys/Intro3.imageset/lock.pdf | Bin 0 -> 5021 bytes 9 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/key.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro2.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro2.imageset/faceid.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro3.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro3.imageset/lock.pdf diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift index 329071ad5d..bedfb253ea 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreen.swift @@ -204,7 +204,7 @@ final class PasskeysScreenComponent: Component { } if let credentialId = decodeBase64(passkey.id) { do { - try await updater.reportUnknownPublicKeyCredential(relyingPartyIdentifier: "t.me", credentialID: credentialId) + try await updater.reportUnknownPublicKeyCredential(relyingPartyIdentifier: "telegram.org", credentialID: credentialId) } catch let e { Logger.shared.log("Passkeys", "reportUnknownPublicKeyCredential error: \(e)") } diff --git a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift index bb49ae5cd1..28df5748a5 100644 --- a/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift +++ b/submodules/TelegramUI/Components/Settings/PasskeysScreen/Sources/PasskeysScreenIntroComponent.swift @@ -182,17 +182,17 @@ final class PasskeysScreenIntroComponent: Component { } let itemDescs: [ItemDesc] = [ ItemDesc( - icon: "Chat List/Archive/IconArchived", + icon: "Settings/Passkeys/Intro1", title: "Create a Passkey", text: "Make a passkey to sign in easily and safely." ), ItemDesc( - icon: "Chat List/Archive/IconHide", + icon: "Settings/Passkeys/Intro2", title: "Log in with Face ID", text: "Use Face ID, Touch ID, or your passcode to sign in." ), ItemDesc( - icon: "Chat List/Archive/IconStories", + icon: "Settings/Passkeys/Intro3", title: "Store Passkey Securely", text: "Your passkey is safely kept in your iCloud Keychain." ) diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Contents.json new file mode 100644 index 0000000000..6e965652df --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/Contents.json new file mode 100644 index 0000000000..7ee24619ad --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "key.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/key.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Passkeys/Intro1.imageset/key.pdf new file mode 100644 index 0000000000000000000000000000000000000000..29928ca1db021dc0ac96449916dfaa3cc92f376f GIT binary patch literal 5170 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 HFx31%;?$b( literal 0 HcmV?d00001