From 842711de04bd33cb780a100e549bea5b6df8ba2e Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 12 Sep 2025 10:55:11 +0200 Subject: [PATCH] Auth debug email --- .../Telegram-iOS/en.lproj/Localizable.strings | 44 ++++++++---- .../GenerateStrings/GenerateStrings.py | 2 +- submodules/AuthorizationUI/BUILD | 1 + .../AuthorizationSequencePaymentScreen.swift | 67 ++++++++++--------- .../Sources/DebugAccountsController.swift | 4 ++ .../DeviceModel/Sources/DeviceModel.swift | 11 +++ 6 files changed, 82 insertions(+), 47 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 53acaef12c..69bac6dd6d 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -452,20 +452,6 @@ "Login.PhoneGenericEmailBody" = "I'm trying to use my mobile phone number: %1$@\nBut Telegram shows an error. Please help.\n\nError: %2$@\nApp version: %3$@\nOS version: %4$@\nLocale: %5$@\nMNC: %6$@"; "Login.PhonePaidEmailSubject" = "Payment Issue"; -"Login.PhonePaidEmailBody" = "Hello Telegram Support,\n\nI’m experiencing an issue with an in-app purchase on iOS.\nMy phone number: %1$@\nApple ID (email used in the App Store): \nApp version: %2$@\nDevice model / iOS version: %3$@\nApp Store country/region: %4$@\nDate & time of attempt (with timezone): %5$@\nExact error message: \n\n#payment_failed"; - -"Login.PhoneTitle" = "Your Phone"; -"Login.PhonePlaceholder" = "Your phone number"; -"Login.CountryCode" = "Country Code"; -"Login.InvalidCountryCode" = "Invalid Country Code"; - -"Login.InfoTitle" = "Your Info"; -"Login.InfoAvatarAdd" = "add"; -"Login.InfoAvatarPhoto" = "photo"; -"Login.InfoFirstNamePlaceholder" = "First Name"; -"Login.InfoLastNamePlaceholder" = "Last Name"; -"Login.InfoDeletePhoto" = "Remove Photo"; -"Login.InfoHelp" = "Enter your name and add a profile photo."; // Login.SelectCountry "Login.SelectCountry.Title" = "Country"; @@ -15015,3 +15001,33 @@ Sorry for the inconvenience."; "Gift.Options.Collectibles.Text" = "Collectible gifts are unique digital items you can exchange or sell."; "Gift.Upgrade.UpgradeFor" = "Upgrade for %@"; + +"Login.PhonePaidEmailText" = "1. NAME OF YOUR PHONE CARRIER: + +2. (OPTIONAL) WRITE YOUR COMMENT HERE: + +================================================= +Device: %1$@ +OS version: %2$@ +Locale: %3$@ + +Target phone: %4$@ + +App: %5$@ +App version: %6$@ + +Issue: %7$@ +Error: %8$@"; + +"Login.PhoneTitle" = "Your Phone"; +"Login.PhonePlaceholder" = "Your phone number"; +"Login.CountryCode" = "Country Code"; +"Login.InvalidCountryCode" = "Invalid Country Code"; + +"Login.InfoTitle" = "Your Info"; +"Login.InfoAvatarAdd" = "add"; +"Login.InfoAvatarPhoto" = "photo"; +"Login.InfoFirstNamePlaceholder" = "First Name"; +"Login.InfoLastNamePlaceholder" = "Last Name"; +"Login.InfoDeletePhoto" = "Remove Photo"; +"Login.InfoHelp" = "Enter your name and add a profile photo."; diff --git a/build-system/GenerateStrings/GenerateStrings.py b/build-system/GenerateStrings/GenerateStrings.py index 31741133a1..e10ff2b8a7 100644 --- a/build-system/GenerateStrings/GenerateStrings.py +++ b/build-system/GenerateStrings/GenerateStrings.py @@ -88,7 +88,7 @@ def parse_positional_arguments(string: str) -> [PositionalArgument]: result = list() implicit_index = 0 - argument = re.compile(r'%((\d)\$)?([@d])', re.U) + argument = re.compile(r'%((\d+)\$)?([@d])', re.U) start_position = 0 while True: m = argument.search(string, start_position) diff --git a/submodules/AuthorizationUI/BUILD b/submodules/AuthorizationUI/BUILD index fc3eb3f659..5a48a9b381 100644 --- a/submodules/AuthorizationUI/BUILD +++ b/submodules/AuthorizationUI/BUILD @@ -46,6 +46,7 @@ swift_library( "//submodules/InAppPurchaseManager", "//submodules/TelegramUI/Components/Premium/PremiumCoinComponent", "//submodules/TelegramUI/Components/PlainButtonComponent", + "//submodules/Utils/DeviceModel", ], visibility = [ "//visibility:public", diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 31ae741d74..332f744dbb 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -28,6 +28,7 @@ import CoreTelephony import PhoneNumberFormat import PlainButtonComponent import StoreKit +import DeviceModel final class AuthorizationSequencePaymentScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -169,22 +170,12 @@ final class AuthorizationSequencePaymentScreenComponent: Component { text: errorText, actions: [ TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}), - TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak controller] in - guard let controller else { + TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in + guard let self else { return } - let formattedNumber = formatPhoneNumber(component.phoneNumber) - let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" - let systemVersion = UIDevice.current.systemVersion - let locale = Locale.current.identifier - let carrier = CTCarrier() - let mnc = carrier.mobileNetworkCode ?? "none" - let errorString: String = "\(errorCode): \(errorText)" - var body = presentationData.strings.Login_PhoneGenericEmailBody(formattedNumber, errorString, appVersion, systemVersion, locale, mnc).string - body.append("\n#paidauth") - - AuthorizationSequenceController.presentEmailComposeController(address: component.supportEmailAddress, subject: component.supportEmailSubject, body: body, from: controller, presentationData: presentationData) + self.displaySendEmail(error: errorText, errorCode: "\(errorCode)") }) ] ) @@ -198,6 +189,35 @@ final class AuthorizationSequencePaymentScreenComponent: Component { }) } + private func displaySendEmail(error: String?, errorCode: String?) { + guard let component = self.component, let environment = self.environment, let controller = environment.controller() else { + return + } + + let formattedNumber = "\(component.phoneNumber)" + let device = DeviceModel.currentModelCode() + let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" + let systemVersion = UIDevice.current.systemVersion + let locale = Locale.current.identifier + + let issue = error ?? "unknown" + let errorCode = errorCode ?? "unknown" + + let body = environment.strings.Login_PhonePaidEmailText( + device, + systemVersion, + locale, + formattedNumber, + "1", + appVersion, + issue, + errorCode + ).string + + let presentationData = component.presentationData + AuthorizationSequenceController.presentEmailComposeController(address: component.supportEmailAddress, subject: environment.strings.Login_PhonePaidEmailSubject, body: body, from: controller, presentationData: presentationData) + } + func update(component: AuthorizationSequencePaymentScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { self.isUpdating = true defer { @@ -230,7 +250,6 @@ final class AuthorizationSequencePaymentScreenComponent: Component { let sideInset: CGFloat = 16.0 + environment.safeInsets.left - let presentationData = component.presentationData let helpButtonSize = self.helpButton.update( transition: transition, component: AnyComponent(PlainButtonComponent( @@ -240,26 +259,10 @@ final class AuthorizationSequencePaymentScreenComponent: Component { minSize: CGSize(width: 0.0, height: 44.0), contentInsets: UIEdgeInsets(top: 0.0, left: 8.0, bottom: 0.0, right: 8.0), action: { [weak self] in - guard let self, let environment = self.environment, let controller = environment.controller() else { + guard let self else { return } - let formattedNumber = formatPhoneNumber(component.phoneNumber) - let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" - let systemVersion = UIDevice.current.systemVersion - let region = SKPaymentQueue.default().storefront?.countryCode ?? "" - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss zzz" - let dateString = dateFormatter.string(from: Date()) - - let body = environment.strings.Login_PhonePaidEmailBody( - formattedNumber, - appVersion, - systemVersion, - region, - dateString - ).string - - AuthorizationSequenceController.presentEmailComposeController(address: component.supportEmailAddress, subject: environment.strings.Login_PhonePaidEmailSubject, body: body, from: controller, presentationData: presentationData) + self.displaySendEmail(error: nil, errorCode: nil) }, animateScale: false, animateContents: false diff --git a/submodules/DebugSettingsUI/Sources/DebugAccountsController.swift b/submodules/DebugSettingsUI/Sources/DebugAccountsController.swift index a5e45f7e75..d90e35e19a 100644 --- a/submodules/DebugSettingsUI/Sources/DebugAccountsController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugAccountsController.swift @@ -123,6 +123,10 @@ public func debugAccountsController(context: AccountContext, accountManager: Acc if case .internal = context.sharedContext.applicationBindings.appBuildType { context.sharedContext.beginNewAuth(testingEnvironment: false) + } else { + #if DEBUG + context.sharedContext.beginNewAuth(testingEnvironment: false) + #endif } }), ActionSheetButtonItem(title: "Test", color: .accent, action: { diff --git a/submodules/Utils/DeviceModel/Sources/DeviceModel.swift b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift index 572a05d9ae..25fd13fa55 100644 --- a/submodules/Utils/DeviceModel/Sources/DeviceModel.swift +++ b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift @@ -372,6 +372,17 @@ public enum DeviceModel: CaseIterable, Equatable { public static let current = DeviceModel() + public static func currentModelCode() -> String { + var systemInfo = utsname() + uname(&systemInfo) + let modelCode = withUnsafePointer(to: &systemInfo.machine) { + $0.withMemoryRebound(to: CChar.self, capacity: 1) { + ptr in String.init(validatingUTF8: ptr) + } + } + return modelCode ?? "unknown" + } + private init() { var systemInfo = utsname() uname(&systemInfo)