GLEGram 12.5 — Initial public release

Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
This commit is contained in:
Leeksov
2026-04-06 09:48:12 +03:00
commit 4647310322
39685 changed files with 11052678 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "SGFakeLocation",
module_name = "SGFakeLocation",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//Swiftgram/SGSimpleSettings:SGSimpleSettings",
"//Swiftgram/SGStrings:SGStrings",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Display:Display",
"//submodules/TelegramPresentationData:TelegramPresentationData",
],
visibility = [
"//visibility:public",
],
)
+321
View File
@@ -0,0 +1,321 @@
import Foundation
import UIKit
import CoreLocation
#if canImport(SGSimpleSettings)
import SGSimpleSettings
#endif
public final class FakeLocationManager: NSObject {
public static let shared = FakeLocationManager()
private var locationManagers: NSHashTable<CLLocationManager> = NSHashTable.weakObjects()
private var periodicUpdateTimer: Foundation.Timer?
private let timerInterval: TimeInterval = 20.0
private override init() {
super.init()
setupAppLifecycleObservers()
}
private func setupAppLifecycleObservers() {
NotificationCenter.default.addObserver(
self,
selector: #selector(appDidBecomeActive),
name: UIApplication.didBecomeActiveNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(appDidEnterBackground),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
}
@objc private func appDidBecomeActive() {
startPeriodicUpdates()
}
@objc private func appDidEnterBackground() {
stopPeriodicUpdates()
}
private func startPeriodicUpdates() {
if periodicUpdateTimer != nil {
return
}
#if canImport(SGSimpleSettings)
guard SGSimpleSettings.shared.fakeLocationEnabled else {
return
}
sendFakeLocationToAllManagers()
periodicUpdateTimer = Foundation.Timer.scheduledTimer(
withTimeInterval: timerInterval,
repeats: true
) { [weak self] _ in
self?.sendFakeLocationToAllManagers()
}
if let timer = periodicUpdateTimer {
RunLoop.current.add(timer, forMode: .common)
}
#endif
}
private func stopPeriodicUpdates() {
periodicUpdateTimer?.invalidate()
periodicUpdateTimer = nil
}
private func sendFakeLocationToAllManagers() {
#if canImport(SGSimpleSettings)
guard SGSimpleSettings.shared.fakeLocationEnabled else {
stopPeriodicUpdates()
return
}
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
guard latitude != 0.0 && longitude != 0.0 else {
return
}
for manager in locationManagers.allObjects {
sendFakeLocationToManager(manager)
}
#endif
}
func addLocationManager(_ manager: CLLocationManager) {
locationManagers.add(manager)
}
func sendFakeLocationToManager(_ manager: CLLocationManager) {
#if canImport(SGSimpleSettings)
guard SGSimpleSettings.shared.fakeLocationEnabled else { return }
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
guard latitude != 0.0 && longitude != 0.0 else { return }
let fakeLocation = CLLocation(
coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
altitude: 0,
horizontalAccuracy: 10,
verticalAccuracy: 10,
timestamp: Date()
)
let fakeLocations = [fakeLocation]
if let delegate = manager.delegate {
delegate.locationManager?(manager, didUpdateLocations: fakeLocations)
}
#endif
}
}
extension CLLocationManager {
private static var swizzled = false
private static var originalStartUpdatingLocationIMP: IMP?
private static var originalRequestLocationIMP: IMP?
private static var originalLocationGetterIMP: IMP?
private static var originalSetDelegateIMP: IMP?
private static var originalRequestAlwaysAuthorizationIMP: IMP?
private static var originalRequestWhenInUseAuthorizationIMP: IMP?
private static var originalAuthorizationStatusGetterIMP: IMP?
private static var originalStaticAuthorizationStatusIMP: IMP?
public static func swizzleLocationMethods() {
guard !swizzled else { return }
swizzled = true
let startUpdatingLocationSelector = #selector(CLLocationManager.startUpdatingLocation)
let requestLocationSelector = #selector(CLLocationManager.requestLocation)
let locationGetterSelector = #selector(getter: CLLocationManager.location)
let setDelegateSelector = #selector(setter: CLLocationManager.delegate)
let requestAlwaysAuthorizationSelector = #selector(CLLocationManager.requestAlwaysAuthorization)
let requestWhenInUseAuthorizationSelector = #selector(CLLocationManager.requestWhenInUseAuthorization)
let authorizationStatusSelector = NSSelectorFromString("authorizationStatus")
let staticAuthorizationStatusSelector = #selector(CLLocationManager.authorizationStatus)
if let method = class_getInstanceMethod(CLLocationManager.self, startUpdatingLocationSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_startUpdatingLocation)) {
originalStartUpdatingLocationIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
if #available(iOS 9.0, *) {
if let method = class_getInstanceMethod(CLLocationManager.self, requestLocationSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestLocation)) {
originalRequestLocationIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
}
if let method = class_getInstanceMethod(CLLocationManager.self, locationGetterSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_location)) {
originalLocationGetterIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
if let method = class_getInstanceMethod(CLLocationManager.self, setDelegateSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_setDelegate(_:))) {
originalSetDelegateIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
if let method = class_getInstanceMethod(CLLocationManager.self, requestAlwaysAuthorizationSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestAlwaysAuthorization)) {
originalRequestAlwaysAuthorizationIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
if let method = class_getInstanceMethod(CLLocationManager.self, requestWhenInUseAuthorizationSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_requestWhenInUseAuthorization)) {
originalRequestWhenInUseAuthorizationIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
if #available(iOS 14.0, *) {
if let method = class_getInstanceMethod(CLLocationManager.self, authorizationStatusSelector),
let swizzledMethod = class_getInstanceMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_authorizationStatus)) {
originalAuthorizationStatusGetterIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
}
if let method = class_getClassMethod(CLLocationManager.self, staticAuthorizationStatusSelector),
let swizzledMethod = class_getClassMethod(CLLocationManager.self, #selector(CLLocationManager.swizzled_staticAuthorizationStatus)) {
originalStaticAuthorizationStatusIMP = method_getImplementation(method)
method_exchangeImplementations(method, swizzledMethod)
}
}
@objc private func swizzled_setDelegate(_ delegate: CLLocationManagerDelegate?) {
if let originalIMP = CLLocationManager.originalSetDelegateIMP {
typealias MethodType = @convention(c) (AnyObject, Selector, CLLocationManagerDelegate?) -> Void
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
methodFunc(self, #selector(setter: CLLocationManager.delegate), delegate)
}
FakeLocationManager.shared.addLocationManager(self)
#if canImport(SGSimpleSettings)
if SGSimpleSettings.shared.fakeLocationEnabled {
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
if latitude != 0.0 && longitude != 0.0 {
self.stopUpdatingLocation()
FakeLocationManager.shared.sendFakeLocationToManager(self)
}
}
#endif
}
@objc private func swizzled_startUpdatingLocation() {
FakeLocationManager.shared.addLocationManager(self)
#if canImport(SGSimpleSettings)
if SGSimpleSettings.shared.fakeLocationEnabled {
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
if latitude != 0.0 && longitude != 0.0 {
FakeLocationManager.shared.sendFakeLocationToManager(self)
return
}
}
#endif
if let originalIMP = CLLocationManager.originalStartUpdatingLocationIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
methodFunc(self, #selector(startUpdatingLocation))
}
}
@available(iOS 9.0, *)
@objc private func swizzled_requestLocation() {
#if canImport(SGSimpleSettings)
if SGSimpleSettings.shared.fakeLocationEnabled {
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
if latitude != 0.0 && longitude != 0.0 {
FakeLocationManager.shared.sendFakeLocationToManager(self)
return
}
}
#endif
if let originalIMP = CLLocationManager.originalRequestLocationIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
methodFunc(self, #selector(requestLocation))
}
}
@objc private func swizzled_location() -> CLLocation? {
#if canImport(SGSimpleSettings)
if SGSimpleSettings.shared.fakeLocationEnabled {
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
if latitude != 0.0 && longitude != 0.0 {
return CLLocation(
coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
altitude: 0,
horizontalAccuracy: 10,
verticalAccuracy: 10,
timestamp: Date()
)
}
}
#endif
if let originalIMP = CLLocationManager.originalLocationGetterIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> CLLocation?
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
return methodFunc(self, #selector(getter: CLLocationManager.location))
}
return nil
}
@objc private func swizzled_requestAlwaysAuthorization() {
if let originalIMP = CLLocationManager.originalRequestAlwaysAuthorizationIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
methodFunc(self, #selector(requestAlwaysAuthorization))
}
}
@objc private func swizzled_requestWhenInUseAuthorization() {
if let originalIMP = CLLocationManager.originalRequestWhenInUseAuthorizationIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> Void
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
methodFunc(self, #selector(requestWhenInUseAuthorization))
}
}
@available(iOS 14.0, *)
@objc private func swizzled_authorizationStatus() -> CLAuthorizationStatus {
if let originalIMP = CLLocationManager.originalAuthorizationStatusGetterIMP {
typealias MethodType = @convention(c) (AnyObject, Selector) -> CLAuthorizationStatus
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
return methodFunc(self, NSSelectorFromString("authorizationStatus"))
}
return .notDetermined
}
@objc private static func swizzled_staticAuthorizationStatus() -> CLAuthorizationStatus {
if let originalIMP = CLLocationManager.originalStaticAuthorizationStatusIMP {
typealias MethodType = @convention(c) (AnyClass, Selector) -> CLAuthorizationStatus
let methodFunc = unsafeBitCast(originalIMP, to: MethodType.self)
return methodFunc(CLLocationManager.self, #selector(CLLocationManager.authorizationStatus))
}
return .notDetermined
}
}
@@ -0,0 +1,201 @@
import Foundation
import UIKit
import MapKit
import CoreLocation
#if canImport(SGSimpleSettings)
import SGSimpleSettings
#endif
#if canImport(SGStrings)
import SGStrings
#endif
import Display
import TelegramPresentationData
public final class FakeLocationPickerController: ViewController {
private let presentationData: PresentationData
private var mapView: MKMapView!
private var currentPin: MKPointAnnotation?
private var saveButton: UIButton!
private var mapTypeControl: UISegmentedControl!
private var onSave: (() -> Void)?
public init(presentationData: PresentationData, onSave: (() -> Void)? = nil) {
self.presentationData = presentationData
self.onSave = onSave
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
let lang = presentationData.strings.baseLanguageCode
self.title = (lang == "ru" ? "Выбор местоположения" : "Pick Location")
let backItem = UIBarButtonItem(backButtonAppearanceWithTitle: presentationData.strings.Common_Back, target: self, action: #selector(self.backPressed))
self.navigationItem.leftBarButtonItem = backItem
}
@objc private func backPressed() {
navigateBack()
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func loadView() {
super.loadView()
view.backgroundColor = presentationData.theme.list.plainBackgroundColor
mapView = MKMapView()
mapView.delegate = self
mapView.showsUserLocation = false
mapView.translatesAutoresizingMaskIntoConstraints = false
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
mapView.addGestureRecognizer(tapGesture)
let lang = presentationData.strings.baseLanguageCode
let mapTypeItems = [
(lang == "ru" ? "Обычная" : "Standard"),
(lang == "ru" ? "Спутник" : "Satellite"),
(lang == "ru" ? "Гибрид" : "Hybrid")
]
mapTypeControl = UISegmentedControl(items: mapTypeItems)
mapTypeControl.selectedSegmentIndex = 0
mapTypeControl.addTarget(self, action: #selector(mapTypeChanged(_:)), for: .valueChanged)
mapTypeControl.translatesAutoresizingMaskIntoConstraints = false
saveButton = UIButton(type: .system)
let saveButtonTitle = (lang == "ru" ? "Сохранить" : "Save")
saveButton.setTitle(saveButtonTitle, for: .normal)
saveButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
saveButton.backgroundColor = presentationData.theme.list.itemAccentColor
saveButton.setTitleColor(.white, for: .normal)
saveButton.layer.cornerRadius = 12
saveButton.addTarget(self, action: #selector(savePressed), for: .touchUpInside)
saveButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(mapView)
view.addSubview(mapTypeControl)
view.addSubview(saveButton)
NSLayoutConstraint.activate([
mapView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
saveButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
saveButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
saveButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16),
saveButton.heightAnchor.constraint(equalToConstant: 50),
mapTypeControl.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
mapTypeControl.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
mapTypeControl.bottomAnchor.constraint(equalTo: saveButton.topAnchor, constant: -12),
mapTypeControl.heightAnchor.constraint(equalToConstant: 32)
])
view.bringSubviewToFront(saveButton)
view.bringSubviewToFront(mapTypeControl)
loadSavedLocation()
}
@objc private func mapTapped(_ gesture: UITapGestureRecognizer) {
let point = gesture.location(in: mapView)
let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
addPinAt(coordinate: coordinate)
#if canImport(SGSimpleSettings)
SGSimpleSettings.shared.fakeLatitude = coordinate.latitude
SGSimpleSettings.shared.fakeLongitude = coordinate.longitude
SGSimpleSettings.shared.synchronizeShared()
#endif
}
@objc private func mapTypeChanged(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
case 1:
mapView.mapType = .satellite
case 2:
mapView.mapType = .hybrid
default:
break
}
}
@objc private func savePressed() {
#if canImport(SGSimpleSettings)
if let coordinate = currentPin?.coordinate {
SGSimpleSettings.shared.fakeLatitude = coordinate.latitude
SGSimpleSettings.shared.fakeLongitude = coordinate.longitude
SGSimpleSettings.shared.synchronizeShared()
onSave?()
}
#endif
navigateBack()
}
private func navigateBack() {
if let nav = self.navigationController, nav.viewControllers.count > 1 {
nav.popViewController(animated: true)
} else {
self.dismiss(animated: true)
}
}
private func loadSavedLocation() {
#if canImport(SGSimpleSettings)
let latitude = SGSimpleSettings.shared.fakeLatitude
let longitude = SGSimpleSettings.shared.fakeLongitude
if latitude != 0.0 && longitude != 0.0 {
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
addPinAt(coordinate: coordinate)
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
mapView.setRegion(region, animated: false)
} else {
// Default to Moscow if no location is set
let defaultCoordinate = CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6176)
let region = MKCoordinateRegion(center: defaultCoordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: false)
}
#else
let defaultCoordinate = CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6176)
let region = MKCoordinateRegion(center: defaultCoordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: false)
#endif
}
private func addPinAt(coordinate: CLLocationCoordinate2D) {
if let existingPin = currentPin {
mapView.removeAnnotation(existingPin)
}
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
currentPin = annotation
mapView.addAnnotation(annotation)
}
}
extension FakeLocationPickerController: MKMapViewDelegate {
public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let identifier = "FakeLocationPin"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
return annotationView
}
}