├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── Artworks ├── AppIcon.png ├── HavocMarketing.png └── IconDrawer.swift ├── DevKit ├── env.sh ├── roothide.sh ├── rootless.sh ├── sim-install.sh ├── sim-launch.sh └── simulator.sh ├── Headers └── libSandy.h ├── LICENSE ├── Libraries ├── _roothide │ └── libsandy.tbd ├── _rootless │ └── libsandy.tbd └── libsandy.tbd ├── Makefile ├── NoRedirect.plist ├── NoRedirect.xm ├── NoRedirectPrefs ├── Frameworks │ ├── AltList.framework │ │ ├── AltList.tbd │ │ ├── Headers │ │ │ ├── ATLApplicationListControllerBase.h │ │ │ ├── ATLApplicationListMultiSelectionController.h │ │ │ ├── ATLApplicationListSelectionController.h │ │ │ ├── ATLApplicationListSubcontroller.h │ │ │ ├── ATLApplicationListSubcontrollerController.h │ │ │ ├── ATLApplicationSection.h │ │ │ ├── ATLApplicationSelectionCell.h │ │ │ ├── ATLApplicationSubtitleCell.h │ │ │ ├── ATLApplicationSubtitleSwitchCell.h │ │ │ └── AltList.h │ │ ├── Info.plist │ │ └── Modules │ │ │ └── module.modulemap │ ├── Preferences.framework │ │ └── Preferences.tbd │ ├── _roothide │ │ ├── AltList.framework │ │ │ ├── AltList.tbd │ │ │ ├── Headers │ │ │ ├── Info.plist │ │ │ └── Modules │ │ └── Preferences.framework │ │ │ └── Preferences.tbd │ ├── _rootless │ │ ├── AltList.framework │ │ │ ├── AltList.tbd │ │ │ ├── Headers │ │ │ ├── Info.plist │ │ │ └── Modules │ │ └── Preferences.framework │ │ │ └── Preferences.tbd │ └── _simulator │ │ ├── AltList.framework │ │ ├── AltList.tbd │ │ ├── Headers │ │ ├── Info.plist │ │ └── Modules │ │ └── Preferences.framework │ │ └── Preferences.tbd ├── LSApplicationProxy+AltList.h ├── Makefile ├── NoRedirectAppListController.h ├── NoRedirectAppListController.m ├── NoRedirectAppSelectionViewController.h ├── NoRedirectAppSelectionViewController.m ├── NoRedirectAppSpecificViewController.h ├── NoRedirectAppSpecificViewController.m ├── NoRedirectHistoryViewController.h ├── NoRedirectHistoryViewController.m ├── NoRedirectRootListController.h ├── NoRedirectRootListController.m ├── Resources │ ├── App.plist │ ├── Info.plist │ ├── Root.plist │ ├── en.lproj │ │ ├── App.strings │ │ ├── History.strings │ │ ├── InfoPlist.strings │ │ └── Root.strings │ ├── icon@2x.png │ ├── icon@3x.png │ └── zh-Hans.lproj │ │ ├── App.strings │ │ ├── History.strings │ │ ├── InfoPlist.strings │ │ └── Root.strings ├── control └── layout │ └── Library │ └── PreferenceLoader │ └── Preferences │ └── NoRedirectPrefs │ └── Root.plist ├── NoRedirectRecord.h ├── NoRedirectRecord.m ├── README.md ├── control ├── layout └── Library │ └── libSandy │ ├── NoRedirectSafari.plist │ └── NoRedirectSafari_RootHide.plist └── libroot └── dyn.c /.clang-format: -------------------------------------------------------------------------------- 1 | # clang-format 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | AccessModifierOffset: -4 5 | ContinuationIndentWidth: 4 6 | ColumnLimit: 120 -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Package 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - release 8 | 9 | env: 10 | VERSION: 1.0 11 | FINALPACKAGE: 1 12 | HOMEBREW_NO_AUTO_UPDATE: 1 13 | HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 14 | 15 | jobs: 16 | build: 17 | runs-on: macos-14 18 | 19 | steps: 20 | - name: Setup Xcode 21 | uses: maxim-lobanov/setup-xcode@v1 22 | with: 23 | xcode-version: '15.4' 24 | 25 | - name: Setup Environment 26 | run: | 27 | echo "THEOS=$HOME/theos" >> $GITHUB_ENV 28 | echo "THEOS_IGNORE_PARALLEL_BUILDING_NOTICE=yes" >> $HOME/.theosrc 29 | 30 | - name: Setup Theos 31 | run: | 32 | bash -c "$(curl -fsSL https://raw.githubusercontent.com/OwnGoalStudio/theos/ci/auth-token/bin/install-theos)" 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - name: Setup Environment (RootHide) 37 | run: | 38 | echo "THEOS=$HOME/theos-roothide" >> $GITHUB_ENV 39 | 40 | - name: Setup Theos (RootHide) 41 | run: | 42 | bash -c "$(curl -fsSL https://raw.githubusercontent.com/OwnGoalStudio/theos-roothide/ci/auth-token/bin/install-theos)" 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | 46 | - name: Checkout 47 | uses: actions/checkout@v4 48 | 49 | - name: Build (arm) 50 | run: | 51 | source devkit/env.sh 52 | make package 53 | 54 | - name: Build (arm64) 55 | run: | 56 | source devkit/rootless.sh 57 | make package 58 | 59 | - name: Build (arm64e) 60 | run: | 61 | source devkit/roothide.sh 62 | make package 63 | 64 | - name: Collect dSYMs 65 | run: | 66 | find .theos/obj -name "*.dSYM" -exec cp -r {} ./packages/ \; 67 | VERSION=$(grep '^Version:' .theos/_/DEBIAN/control | awk '{print $2}') 68 | echo "VERSION=$VERSION" >> $GITHUB_ENV 69 | 70 | - name: Upload dSYMs 71 | uses: actions/upload-artifact@v4 72 | with: 73 | name: symbols-${{ env.VERSION }} 74 | path: | 75 | ./packages/*.dSYM 76 | 77 | - name: Upload Packages 78 | uses: actions/upload-artifact@v4 79 | with: 80 | name: packages-${{ env.VERSION }} 81 | path: | 82 | ./packages/*.deb 83 | 84 | - name: Release 85 | uses: softprops/action-gh-release@v2 86 | with: 87 | tag_name: v${{ env.VERSION }} 88 | draft: true 89 | prerelease: false 90 | files: | 91 | ./packages/*.deb 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .theos 2 | .cache 3 | /build 4 | /packages 5 | /compile_commands.json 6 | /Artworks/IconDrawer 7 | 8 | # Created by https://www.toptal.com/developers/gitignore/api/swift,xcode,macos 9 | # Edit at https://www.toptal.com/developers/gitignore?templates=swift,xcode,macos 10 | 11 | ### macOS ### 12 | # General 13 | .DS_Store 14 | .AppleDouble 15 | .LSOverride 16 | 17 | # Icon must end with two \r 18 | Icon 19 | 20 | 21 | # Thumbnails 22 | ._* 23 | 24 | # Files that might appear in the root of a volume 25 | .DocumentRevisions-V100 26 | .fseventsd 27 | .Spotlight-V100 28 | .TemporaryItems 29 | .Trashes 30 | .VolumeIcon.icns 31 | .com.apple.timemachine.donotpresent 32 | 33 | # Directories potentially created on remote AFP share 34 | .AppleDB 35 | .AppleDesktop 36 | Network Trash Folder 37 | Temporary Items 38 | .apdisk 39 | 40 | ### macOS Patch ### 41 | # iCloud generated files 42 | *.icloud 43 | 44 | ### Swift ### 45 | # Xcode 46 | # 47 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 48 | 49 | ## User settings 50 | xcuserdata/ 51 | 52 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 53 | *.xcscmblueprint 54 | *.xccheckout 55 | 56 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 57 | build/ 58 | DerivedData/ 59 | *.moved-aside 60 | *.pbxuser 61 | !default.pbxuser 62 | *.mode1v3 63 | !default.mode1v3 64 | *.mode2v3 65 | !default.mode2v3 66 | *.perspectivev3 67 | !default.perspectivev3 68 | 69 | ## Obj-C/Swift specific 70 | *.hmap 71 | 72 | ## App packaging 73 | *.ipa 74 | *.dSYM.zip 75 | *.dSYM 76 | 77 | ## Playgrounds 78 | timeline.xctimeline 79 | playground.xcworkspace 80 | 81 | # Swift Package Manager 82 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 83 | # Packages/ 84 | # Package.pins 85 | # Package.resolved 86 | # *.xcodeproj 87 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 88 | # hence it is not needed unless you have added a package configuration file to your project 89 | # .swiftpm 90 | 91 | .build/ 92 | 93 | # CocoaPods 94 | # We recommend against adding the Pods directory to your .gitignore. However 95 | # you should judge for yourself, the pros and cons are mentioned at: 96 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 97 | # Pods/ 98 | # Add this line if you want to avoid checking in source code from the Xcode workspace 99 | # *.xcworkspace 100 | 101 | # Carthage 102 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 103 | # Carthage/Checkouts 104 | 105 | Carthage/Build/ 106 | 107 | # Accio dependency management 108 | Dependencies/ 109 | .accio/ 110 | 111 | # fastlane 112 | # It is recommended to not store the screenshots in the git repo. 113 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 114 | # For more information about the recommended setup visit: 115 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 116 | 117 | fastlane/report.xml 118 | fastlane/Preview.html 119 | fastlane/screenshots/**/*.png 120 | fastlane/test_output 121 | 122 | # Code Injection 123 | # After new code Injection tools there's a generated folder /iOSInjectionProject 124 | # https://github.com/johnno1962/injectionforxcode 125 | 126 | iOSInjectionProject/ 127 | 128 | ### Xcode ### 129 | 130 | ## Xcode 8 and earlier 131 | 132 | ### Xcode Patch ### 133 | *.xcodeproj/* 134 | !*.xcodeproj/project.pbxproj 135 | !*.xcodeproj/xcshareddata/ 136 | !*.xcodeproj/project.xcworkspace/ 137 | !*.xcworkspace/contents.xcworkspacedata 138 | /*.gcno 139 | **/xcshareddata/WorkspaceSettings.xcsettings 140 | 141 | # End of https://www.toptal.com/developers/gitignore/api/swift,xcode,macos 142 | 143 | -------------------------------------------------------------------------------- /Artworks/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OwnGoalStudio/NoRedirect/90c13f87f5bcfe5eabc8d8e49896006158b4f172/Artworks/AppIcon.png -------------------------------------------------------------------------------- /Artworks/HavocMarketing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OwnGoalStudio/NoRedirect/90c13f87f5bcfe5eabc8d8e49896006158b4f172/Artworks/HavocMarketing.png -------------------------------------------------------------------------------- /Artworks/IconDrawer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IconDrawer.swift 3 | // TRApp 4 | // 5 | // Created by 秋星桥 on 2024/3/6. 6 | // 7 | 8 | // swiftc -parse-as-library IconDrawer.swift 9 | // ./IconDrawer 10 | 11 | import QuickLook 12 | import SwiftUI 13 | 14 | @main 15 | struct DemoApp: App { 16 | var body: some Scene { 17 | WindowGroup { 18 | ContentView() 19 | } 20 | .windowResizability(.contentSize) 21 | } 22 | } 23 | 24 | let previewSize = CGSize(width: 1024, height: 1024) 25 | let symbolWidth: CGFloat = 600 26 | 27 | struct ContentView: View { 28 | var body: some View { 29 | PreviewExporter() 30 | .scaleEffect(.init(width: 0.5, height: 0.5)) 31 | .frame(width: previewSize.width / 2, height: previewSize.height / 2, alignment: .center) 32 | } 33 | } 34 | 35 | struct PreviewWaveformView: View { 36 | let waveWidth: CGFloat = 32 37 | let waveHeight: CGFloat = symbolWidth 38 | let waveSpacing: CGFloat = 32 39 | 40 | struct Waves: Identifiable, Equatable { 41 | var id: UUID = .init() 42 | var height: CGFloat 43 | } 44 | 45 | let waves: [Waves] 46 | 47 | init() { 48 | var builder = [Waves]() 49 | let targetCount = 128 50 | while builder.count < targetCount { 51 | builder.append(.init(height: .random(in: 0.2 ... 1.0))) 52 | } 53 | while builder.count > targetCount { 54 | builder.removeLast() 55 | } 56 | waves = builder 57 | } 58 | 59 | var body: some View { 60 | HStack(alignment: .center, spacing: waveSpacing) { 61 | ForEach(waves) { wave in 62 | RoundedRectangle(cornerRadius: waveWidth / 2) 63 | .frame(width: waveWidth, height: waveHeight * wave.height) 64 | .animation(.spring, value: wave.height) 65 | } 66 | } 67 | .frame(maxHeight: .infinity) 68 | .padding(-8) 69 | } 70 | } 71 | 72 | struct PreviewBannerView: View { 73 | var body: some View { 74 | ZStack { 75 | Image(systemName: "hand.raised.fill") 76 | .resizable() 77 | .aspectRatio(contentMode: .fit) 78 | .frame(width: symbolWidth, height: symbolWidth) 79 | .font(.system(size: symbolWidth, weight: .regular, design: .rounded)) 80 | .opacity(0.88) 81 | .padding(72) 82 | } 83 | .foregroundStyle(.white) 84 | .frame(maxWidth: .infinity, maxHeight: .infinity) 85 | .padding(50) 86 | .background { 87 | LinearGradient( // f74c06, e62314 88 | gradient: Gradient(colors: [ 89 | Color(red: 247 / 255, green: 76 / 255, blue: 6 / 255), 90 | Color(red: 230 / 255, green: 35 / 255, blue: 20 / 255) 91 | ]), 92 | startPoint: .top, 93 | endPoint: .bottom 94 | ) 95 | .ignoresSafeArea() 96 | } 97 | .frame(width: previewSize.width, height: previewSize.height, alignment: .center) 98 | .clipped() 99 | } 100 | } 101 | 102 | struct PreviewExporter: View { 103 | var body: some View { 104 | VStack { 105 | PreviewBannerView() 106 | .onTapGesture { 107 | let renderer = ImageRenderer(content: PreviewBannerView()) 108 | let data = renderer.nsImage!.tiffRepresentation! 109 | let url = URL(fileURLWithPath: NSTemporaryDirectory()) 110 | .appendingPathComponent("AppIcon") 111 | .appendingPathExtension("tiff") 112 | try! data.write(to: url) 113 | NSWorkspace.shared.open(url) 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /DevKit/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export THEOS=$HOME/theos 4 | export THEOS_PACKAGE_SCHEME= 5 | export THEOS_DEVICE_IP=127.0.0.1 6 | export THEOS_DEVICE_PORT=58422 7 | export THEOS_DEVICE_SIMULATOR= 8 | -------------------------------------------------------------------------------- /DevKit/roothide.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export THEOS=$HOME/theos-roothide 4 | export THEOS_PACKAGE_SCHEME=roothide 5 | export THEOS_DEVICE_IP=127.0.0.1 6 | export THEOS_DEVICE_PORT=58422 7 | export THEOS_DEVICE_SIMULATOR= 8 | -------------------------------------------------------------------------------- /DevKit/rootless.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export THEOS=$HOME/theos 4 | export THEOS_PACKAGE_SCHEME=rootless 5 | export THEOS_DEVICE_IP=127.0.0.1 6 | export THEOS_DEVICE_PORT=58422 7 | export THEOS_DEVICE_SIMULATOR= 8 | -------------------------------------------------------------------------------- /DevKit/sim-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$THEOS_DEVICE_SIMULATOR" ]; then 4 | exit 0 5 | fi 6 | 7 | cd $(dirname $0)/.. 8 | 9 | TWEAK_NAMES="NoRedirect" 10 | 11 | for TWEAK_NAME in $TWEAK_NAMES; do 12 | sudo rm -f /opt/simject/$TWEAK_NAME.dylib 13 | sudo cp -v $THEOS_OBJ_DIR/$TWEAK_NAME.dylib /opt/simject/$TWEAK_NAME.dylib 14 | sudo codesign -f -s - /opt/simject/$TWEAK_NAME.dylib 15 | sudo cp -v $PWD/$TWEAK_NAME.plist /opt/simject 16 | done 17 | 18 | BUNDLE_NAMES="NoRedirectPrefs" 19 | 20 | sudo mkdir -p /opt/simject/PreferenceBundles /opt/simject/PreferenceLoader/Preferences 21 | for BUNDLE_NAME in $BUNDLE_NAMES; do 22 | sudo rm -rf /opt/simject/PreferenceBundles/$BUNDLE_NAME.bundle 23 | sudo cp -rv $THEOS_OBJ_DIR/$BUNDLE_NAME.bundle /opt/simject/PreferenceBundles/$BUNDLE_NAME.bundle 24 | sudo codesign -f -s - /opt/simject/PreferenceBundles/$BUNDLE_NAME.bundle 25 | sudo cp -rv $PWD/$BUNDLE_NAME/layout/Library/PreferenceLoader/Preferences/$BUNDLE_NAME /opt/simject/PreferenceLoader/Preferences/ 26 | done 27 | 28 | resim 29 | -------------------------------------------------------------------------------- /DevKit/sim-launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$THEOS_DEVICE_SIMULATOR" ]; then 4 | exit 0 5 | fi 6 | 7 | cd $(dirname $0)/.. 8 | 9 | DEVICE_ID="2458FACD-57EA-44F8-A8E4-C209B9352CD2" 10 | XCODE_PATH=$(xcode-select -p) 11 | 12 | xcrun simctl boot $DEVICE_ID 13 | open $XCODE_PATH/Applications/Simulator.app 14 | -------------------------------------------------------------------------------- /DevKit/simulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export THEOS=$HOME/theos 4 | export THEOS_PACKAGE_SCHEME= 5 | export THEOS_DEVICE_IP= 6 | export THEOS_DEVICE_PORT= 7 | export THEOS_DEVICE_SIMULATOR=1 8 | -------------------------------------------------------------------------------- /Headers/libSandy.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #if defined(__cplusplus) 4 | extern "C" { 5 | #endif 6 | 7 | #define kLibSandySuccess 0 8 | #define kLibSandyErrorXPCFailure 1 9 | #define kLibSandyErrorRestricted 2 10 | 11 | extern int libSandy_applyProfile(const char* profileName); 12 | extern bool libSandy_works(void); 13 | 14 | #if defined(__cplusplus) 15 | } 16 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 i_82 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Libraries/_roothide/libsandy.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ armv7, arm64, arm64e ] 3 | uuids: [ 'armv7: E8393BFB-05A6-3A91-AADC-6BB44C2785B9', 'arm64: 72E35021-8C45-3241-8798-711482EFCB25', 4 | 'arm64e: 0071493A-6940-36B2-BB35-118C4236A273' ] 5 | platform: ios 6 | flags: [ flat_namespace, not_app_extension_safe ] 7 | install-name: '@loader_path/.jbroot/usr/lib/libsandy.dylib' 8 | current-version: 0 9 | compatibility-version: 0 10 | objc-constraint: retain_release 11 | exports: 12 | - archs: [ armv7, arm64, arm64e ] 13 | symbols: [ _libSandy_applyProfile, _libSandy_works ] 14 | undefineds: 15 | - archs: [ armv7 ] 16 | symbols: [ __Unwind_SjLj_Register, __Unwind_SjLj_Resume, 17 | __Unwind_SjLj_Unregister ] 18 | - archs: [ armv7, arm64 ] 19 | symbols: [ dyld_stub_binder ] 20 | - archs: [ arm64, arm64 ] 21 | symbols: [ __Unwind_Resume ] 22 | - archs: [ armv7, arm64, arm64e ] 23 | symbols: [ __Block_object_assign, __Block_object_dispose, 24 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 25 | __NSGetArgv, ___CFConstantStringClassReference, 26 | ___objc_personality_v0, ___stack_chk_fail, 27 | ___stack_chk_guard, __xpc_type_array, 28 | __xpc_type_dictionary, __xpc_type_string, 29 | _dispatch_once, _objc_autoreleaseReturnValue, 30 | _objc_enumerationMutation, _objc_msgSend, 31 | _objc_release, _objc_retain, _objc_retainAutorelease, 32 | _objc_retainAutoreleasedReturnValue, 33 | _sandbox_extension_consume, _xpc_array_apply, 34 | _xpc_connection_create_mach_service, 35 | _xpc_connection_resume, 36 | _xpc_connection_send_message_with_reply_sync, 37 | _xpc_connection_set_event_handler, 38 | _xpc_dictionary_create, _xpc_dictionary_get_bool, 39 | _xpc_dictionary_get_value, _xpc_dictionary_set_int64, 40 | _xpc_dictionary_set_string, _xpc_get_type, 41 | _xpc_string_get_string_ptr ] 42 | objc-classes: [ _NSDictionary, _NSFileManager, _NSString ] 43 | ... 44 | -------------------------------------------------------------------------------- /Libraries/_rootless/libsandy.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ armv7, arm64, arm64e ] 3 | uuids: [ 'armv7: E8393BFB-05A6-3A91-AADC-6BB44C2785B9', 'arm64: 72E35021-8C45-3241-8798-711482EFCB25', 4 | 'arm64e: 0071493A-6940-36B2-BB35-118C4236A273' ] 5 | platform: ios 6 | flags: [ flat_namespace, not_app_extension_safe ] 7 | install-name: '@rpath/libsandy.dylib' 8 | current-version: 0 9 | compatibility-version: 0 10 | objc-constraint: retain_release 11 | exports: 12 | - archs: [ armv7, arm64, arm64e ] 13 | symbols: [ _libSandy_applyProfile, _libSandy_works ] 14 | undefineds: 15 | - archs: [ armv7 ] 16 | symbols: [ __Unwind_SjLj_Register, __Unwind_SjLj_Resume, 17 | __Unwind_SjLj_Unregister ] 18 | - archs: [ armv7, arm64 ] 19 | symbols: [ dyld_stub_binder ] 20 | - archs: [ arm64, arm64 ] 21 | symbols: [ __Unwind_Resume ] 22 | - archs: [ armv7, arm64, arm64e ] 23 | symbols: [ __Block_object_assign, __Block_object_dispose, 24 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 25 | __NSGetArgv, ___CFConstantStringClassReference, 26 | ___objc_personality_v0, ___stack_chk_fail, 27 | ___stack_chk_guard, __xpc_type_array, 28 | __xpc_type_dictionary, __xpc_type_string, 29 | _dispatch_once, _objc_autoreleaseReturnValue, 30 | _objc_enumerationMutation, _objc_msgSend, 31 | _objc_release, _objc_retain, _objc_retainAutorelease, 32 | _objc_retainAutoreleasedReturnValue, 33 | _sandbox_extension_consume, _xpc_array_apply, 34 | _xpc_connection_create_mach_service, 35 | _xpc_connection_resume, 36 | _xpc_connection_send_message_with_reply_sync, 37 | _xpc_connection_set_event_handler, 38 | _xpc_dictionary_create, _xpc_dictionary_get_bool, 39 | _xpc_dictionary_get_value, _xpc_dictionary_set_int64, 40 | _xpc_dictionary_set_string, _xpc_get_type, 41 | _xpc_string_get_string_ptr ] 42 | objc-classes: [ _NSDictionary, _NSFileManager, _NSString ] 43 | ... 44 | -------------------------------------------------------------------------------- /Libraries/libsandy.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ armv7, arm64, arm64e ] 3 | uuids: [ 'armv7: E8393BFB-05A6-3A91-AADC-6BB44C2785B9', 'arm64: 72E35021-8C45-3241-8798-711482EFCB25', 4 | 'arm64e: 0071493A-6940-36B2-BB35-118C4236A273' ] 5 | platform: ios 6 | flags: [ flat_namespace, not_app_extension_safe ] 7 | install-name: '/usr/lib/libsandy.dylib' 8 | current-version: 0 9 | compatibility-version: 0 10 | objc-constraint: retain_release 11 | exports: 12 | - archs: [ armv7, arm64, arm64e ] 13 | symbols: [ _libSandy_applyProfile, _libSandy_works ] 14 | undefineds: 15 | - archs: [ armv7 ] 16 | symbols: [ __Unwind_SjLj_Register, __Unwind_SjLj_Resume, 17 | __Unwind_SjLj_Unregister ] 18 | - archs: [ armv7, arm64 ] 19 | symbols: [ dyld_stub_binder ] 20 | - archs: [ arm64, arm64 ] 21 | symbols: [ __Unwind_Resume ] 22 | - archs: [ armv7, arm64, arm64e ] 23 | symbols: [ __Block_object_assign, __Block_object_dispose, 24 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 25 | __NSGetArgv, ___CFConstantStringClassReference, 26 | ___objc_personality_v0, ___stack_chk_fail, 27 | ___stack_chk_guard, __xpc_type_array, 28 | __xpc_type_dictionary, __xpc_type_string, 29 | _dispatch_once, _objc_autoreleaseReturnValue, 30 | _objc_enumerationMutation, _objc_msgSend, 31 | _objc_release, _objc_retain, _objc_retainAutorelease, 32 | _objc_retainAutoreleasedReturnValue, 33 | _sandbox_extension_consume, _xpc_array_apply, 34 | _xpc_connection_create_mach_service, 35 | _xpc_connection_resume, 36 | _xpc_connection_send_message_with_reply_sync, 37 | _xpc_connection_set_event_handler, 38 | _xpc_dictionary_create, _xpc_dictionary_get_bool, 39 | _xpc_dictionary_get_value, _xpc_dictionary_set_int64, 40 | _xpc_dictionary_set_string, _xpc_get_type, 41 | _xpc_string_get_string_ptr ] 42 | objc-classes: [ _NSDictionary, _NSFileManager, _NSString ] 43 | ... 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export PACKAGE_VERSION := 1.10 2 | 3 | ifeq ($(THEOS_DEVICE_SIMULATOR),1) 4 | TARGET := simulator:clang:latest:14.0 5 | INSTALL_TARGET_PROCESSES := SpringBoard SafariViewService 6 | ARCHS := arm64 x86_64 7 | else 8 | TARGET := iphone:clang:latest:14.0 9 | INSTALL_TARGET_PROCESSES := SpringBoard SafariViewService 10 | ARCHS := arm64 arm64e 11 | endif 12 | 13 | GO_EASY_ON_ME := 1 14 | 15 | include $(THEOS)/makefiles/common.mk 16 | 17 | SUBPROJECTS += NoRedirectPrefs 18 | 19 | include $(THEOS_MAKE_PATH)/aggregate.mk 20 | 21 | TWEAK_NAME := NoRedirect 22 | 23 | NoRedirect_FILES += NoRedirect.xm 24 | NoRedirect_FILES += NoRedirectRecord.m 25 | 26 | ifeq ($(THEOS_PACKAGE_SCHEME),roothide) 27 | NoRedirect_FILES += libroot/dyn.c 28 | endif 29 | 30 | NoRedirect_CFLAGS += -fobjc-arc 31 | NoRedirect_CFLAGS += -IHeaders 32 | 33 | ifeq ($(THEOS_PACKAGE_SCHEME),roothide) 34 | NoRedirect_LDFLAGS += -LLibraries/_roothide 35 | else 36 | ifeq ($(THEOS_PACKAGE_SCHEME),rootless) 37 | NoRedirect_LDFLAGS += -LLibraries/_rootless 38 | else 39 | NoRedirect_LDFLAGS += -LLibraries 40 | endif 41 | endif 42 | 43 | ifeq ($(THEOS_DEVICE_SIMULATOR),) 44 | NoRedirect_LIBRARIES += sandy 45 | endif 46 | 47 | include $(THEOS_MAKE_PATH)/tweak.mk 48 | 49 | export THEOS_OBJ_DIR 50 | after-all:: 51 | @devkit/sim-install.sh 52 | -------------------------------------------------------------------------------- /NoRedirect.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OwnGoalStudio/NoRedirect/90c13f87f5bcfe5eabc8d8e49896006158b4f172/NoRedirect.plist -------------------------------------------------------------------------------- /NoRedirect.xm: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | 6 | #import "NoRedirectRecord.h" 7 | 8 | @interface BSProcessHandle : NSObject 9 | @property(getter=isValid, nonatomic, assign, readonly) BOOL valid; 10 | @property(nonatomic, assign, readonly) int pid; 11 | @property(nonatomic, copy, readonly) NSString *bundleIdentifier; 12 | @property(nonatomic, copy, readonly) NSString *name; 13 | @end 14 | 15 | @interface SBApplicationProcessState : NSObject 16 | @property(nonatomic, assign, readonly) int pid; 17 | @property(getter=isRunning, nonatomic, assign, readonly) BOOL running; 18 | @property(getter=isForeground, nonatomic, assign, readonly) BOOL foreground; 19 | @end 20 | 21 | @interface SBApplication : NSObject 22 | @property(nonatomic, copy, readonly) NSString *bundleIdentifier; 23 | @property(nonatomic, strong, readonly) SBApplicationProcessState *processState; 24 | @end 25 | 26 | @interface SBApplicationSceneEntity : NSObject 27 | @property(nonatomic, strong, readonly) SBApplication *application; 28 | @property(nonatomic, copy, readonly) NSSet *actions; 29 | @end 30 | 31 | @interface SBLayoutElement : NSObject 32 | @property(nonatomic, copy, readonly) NSString *uniqueIdentifier; 33 | @end 34 | 35 | @interface SBLayoutState : NSObject 36 | @property(nonatomic, readonly) NSSet *elements; 37 | - (SBLayoutElement *)elementWithRole:(long long)arg1; 38 | @end 39 | 40 | @interface SBWorkspaceApplicationSceneTransitionContext : NSObject 41 | @property(nonatomic, copy, readonly) NSSet *applicationSceneEntities; 42 | @property(nonatomic, copy, readonly) NSSet *previousApplicationSceneEntities; 43 | @property(nonatomic, strong, readonly) SBLayoutState *previousLayoutState; 44 | @property(nonatomic, strong, readonly) SBLayoutState *layoutState; 45 | - (void)setBackground:(BOOL)arg1; 46 | @end 47 | 48 | @interface SBWorkspaceTransitionRequest : NSObject 49 | @property(nonatomic, copy, readonly) NSSet *toApplicationSceneEntities; 50 | @property(nonatomic, copy, readonly) NSSet *fromApplicationSceneEntities; 51 | @property(nonatomic, copy, readonly) NSString *eventLabel; 52 | @property(nonatomic, strong, readonly) BSProcessHandle *originatingProcess; 53 | @property(nonatomic, strong, readonly) SBWorkspaceApplicationSceneTransitionContext *applicationContext; 54 | - (void)declineWithReason:(id)arg1; 55 | @end 56 | 57 | @interface SBApplicationInfo : NSObject 58 | @property(nonatomic, copy, readonly) NSString *bundleIdentifier; 59 | @end 60 | 61 | @interface UIViewController (NoRedirect) 62 | - (NSString *)_hostApplicationBundleIdentifier; 63 | @end 64 | 65 | @interface _SFBrowserContentViewController : UIViewController 66 | - (void)_dismiss; 67 | @end 68 | 69 | static BOOL gEnabled = YES; 70 | static BOOL gRecordingEnabled = NO; 71 | static BOOL gIsSafariViewService = NO; 72 | 73 | static NSSet *gForbiddenLaunchSources = nil; 74 | static NSSet *gForbiddenLaunchDestinations = nil; 75 | 76 | static NSSet *gForbiddenLaunchSourcesForAppStore = nil; 77 | static NSSet *gForbiddenLaunchSourcesForSafariServices = nil; 78 | 79 | static NSSet *gUseLenientModeSources = nil; 80 | static NSSet *gUseHandledSimulationSources = nil; 81 | 82 | // %@->%@ 83 | static NSSet *gCustomAllowedMappings = nil; 84 | static NSSet *gCustomForbiddenMappings = nil; 85 | 86 | static NSMutableDictionary *gLastTransitionStamps = nil; 87 | 88 | static void ReloadPrefs(void) { 89 | static NSUserDefaults *prefs = nil; 90 | if (!prefs) { 91 | if (gIsSafariViewService) { 92 | prefs = [[NSUserDefaults alloc] 93 | initWithSuiteName:@"/var/mobile/Library/Preferences/com.82flex.noredirectprefs.plist"]; 94 | } else { 95 | prefs = [[NSUserDefaults alloc] initWithSuiteName:@"com.82flex.noredirectprefs"]; 96 | } 97 | } 98 | 99 | NSDictionary *settings = [prefs dictionaryRepresentation]; 100 | 101 | gEnabled = settings[@"IsEnabled"] ? [settings[@"IsEnabled"] boolValue] : YES; 102 | gRecordingEnabled = settings[@"IsRecordingEnabled"] ? [settings[@"IsRecordingEnabled"] boolValue] : NO; 103 | HBLogDebug(@"Enabled: %@, Recording Enabled: %@", gEnabled ? @"YES" : @"NO", gRecordingEnabled ? @"YES" : @"NO"); 104 | 105 | NSMutableSet *forbiddenLaunchSources = [NSMutableSet set]; 106 | for (NSString *key in settings) { 107 | if ([key hasPrefix:@"IsBlockedFromLaunchingOthers/"] && [settings[key] boolValue]) { 108 | NSString *appId = [key substringFromIndex:29]; 109 | [forbiddenLaunchSources addObject:appId]; 110 | } 111 | } 112 | gForbiddenLaunchSources = [forbiddenLaunchSources copy]; 113 | HBLogDebug(@"Forbidden Launch Sources: %@", forbiddenLaunchSources); 114 | 115 | NSMutableSet *forbiddenLaunchDestinations = [NSMutableSet set]; 116 | for (NSString *key in settings) { 117 | if ([key hasPrefix:@"IsBlockedFromBeingLaunched/"] && [settings[key] boolValue]) { 118 | NSString *appId = [key substringFromIndex:27]; 119 | [forbiddenLaunchDestinations addObject:appId]; 120 | } 121 | } 122 | gForbiddenLaunchDestinations = [forbiddenLaunchDestinations copy]; 123 | HBLogDebug(@"Forbidden Launch Destinations: %@", forbiddenLaunchDestinations); 124 | 125 | NSMutableSet *forbiddenLaunchSourcesForAppStore = [NSMutableSet set]; 126 | for (NSString *key in settings) { 127 | if ([key hasPrefix:@"IsBlockedFromLaunchingAppStore/"] && [settings[key] boolValue]) { 128 | NSString *appId = [key substringFromIndex:31]; 129 | [forbiddenLaunchSourcesForAppStore addObject:appId]; 130 | } 131 | } 132 | gForbiddenLaunchSourcesForAppStore = [forbiddenLaunchSourcesForAppStore copy]; 133 | HBLogDebug(@"Forbidden Launch Sources for App Store: %@", forbiddenLaunchSourcesForAppStore); 134 | 135 | NSMutableSet *forbiddenLaunchSourcesForSafariServices = [NSMutableSet set]; 136 | for (NSString *key in settings) { 137 | if ([key hasPrefix:@"IsBlockedFromLaunchingSafari/"] && [settings[key] boolValue]) { 138 | NSString *appId = [key substringFromIndex:29]; 139 | [forbiddenLaunchSourcesForSafariServices addObject:appId]; 140 | } 141 | } 142 | gForbiddenLaunchSourcesForSafariServices = [forbiddenLaunchSourcesForSafariServices copy]; 143 | HBLogDebug(@"Forbidden Launch Sources for Safari Services: %@", forbiddenLaunchSourcesForSafariServices); 144 | 145 | NSMutableSet *customAllowedMappings = [NSMutableSet set]; 146 | for (NSString *key in settings) { 147 | if ([key hasPrefix:@"CustomBypassedApplications/"]) { 148 | NSString *srcId = [key substringFromIndex:27]; 149 | NSArray *destIds = settings[key]; 150 | if ([destIds isKindOfClass:[NSArray class]]) { 151 | for (NSString *destId in destIds) { 152 | [customAllowedMappings addObject:[NSString stringWithFormat:@"%@->%@", destId, srcId]]; 153 | } 154 | } 155 | } 156 | } 157 | gCustomAllowedMappings = [customAllowedMappings copy]; 158 | HBLogDebug(@"Custom Allowed Mappings: %@", customAllowedMappings); 159 | 160 | NSMutableSet *customForbiddenMappings = [NSMutableSet set]; 161 | for (NSString *key in settings) { 162 | if ([key hasPrefix:@"CustomBlockedApplications/"]) { 163 | NSString *srcId = [key substringFromIndex:26]; 164 | NSArray *destIds = settings[key]; 165 | if ([destIds isKindOfClass:[NSArray class]]) { 166 | for (NSString *destId in destIds) { 167 | [customForbiddenMappings addObject:[NSString stringWithFormat:@"%@->%@", srcId, destId]]; 168 | } 169 | } 170 | } 171 | } 172 | gCustomForbiddenMappings = [customForbiddenMappings copy]; 173 | HBLogDebug(@"Custom Forbidden Mappings: %@", customForbiddenMappings); 174 | 175 | NSMutableSet *useLenientModeSources = [NSMutableSet set]; 176 | for (NSString *key in settings) { 177 | if ([key hasPrefix:@"ShouldTeardownAutomatically/"] && [settings[key] boolValue]) { 178 | NSString *appId = [key substringFromIndex:28]; 179 | [useLenientModeSources addObject:appId]; 180 | } 181 | } 182 | gUseLenientModeSources = [useLenientModeSources copy]; 183 | HBLogDebug(@"Use Lenient Mode Sources: %@", useLenientModeSources); 184 | 185 | NSMutableSet *useHandledSimulationSources = [NSMutableSet set]; 186 | for (NSString *key in settings) { 187 | if ([key hasPrefix:@"ShouldSimulateSuccess/"] && [settings[key] boolValue]) { 188 | NSString *appId = [key substringFromIndex:22]; 189 | [useHandledSimulationSources addObject:appId]; 190 | } 191 | } 192 | gUseHandledSimulationSources = [useHandledSimulationSources copy]; 193 | HBLogDebug(@"Use Handled Simulation Sources: %@", useHandledSimulationSources); 194 | } 195 | 196 | static BOOL ShouldDeclineRequest(NSString *srcId, NSString *destId) { 197 | HBLogDebug(@"Checking if %@ should be allowed to launch %@", srcId, destId); 198 | 199 | if (!srcId || !destId) { 200 | HBLogDebug(@"> [ACCEPT] Invalid source or destination"); 201 | return NO; 202 | } 203 | 204 | if (!gEnabled) { 205 | HBLogDebug(@"> [ACCEPT] NoRedirect is disabled"); 206 | return NO; 207 | } 208 | 209 | if ([gUseLenientModeSources containsObject:srcId]) { 210 | HBLogDebug(@"> [ACCEPT] %@ is in lenient mode", srcId); 211 | 212 | if (gLastTransitionStamps[srcId]) { 213 | CFTimeInterval lastTransitionStamp = [gLastTransitionStamps[srcId] doubleValue]; 214 | CFTimeInterval nowStamp = CACurrentMediaTime(); 215 | CFTimeInterval lastInterval = fabs(nowStamp - lastTransitionStamp); 216 | if (lastInterval > 10.0) { 217 | HBLogDebug(@">> [ACCEPT] Last transition was %.3f seconds ago", lastInterval); 218 | return NO; 219 | } 220 | } 221 | } 222 | 223 | NSString *mapping = [NSString stringWithFormat:@"%@->%@", srcId, destId]; 224 | if ([gCustomAllowedMappings containsObject:mapping]) { 225 | HBLogDebug(@"> [ACCEPT] Custom mapping %@ is allowed", mapping); 226 | return NO; 227 | } 228 | 229 | if ([gForbiddenLaunchSources containsObject:srcId]) { 230 | HBLogDebug(@"> [REJECT] %@ is forbidden from launching others", srcId); 231 | return YES; 232 | } 233 | 234 | if ([gForbiddenLaunchDestinations containsObject:destId]) { 235 | HBLogDebug(@"> [REJECT] %@ is forbidden from being launched", destId); 236 | 237 | if ([srcId hasPrefix:@"com.apple."]) { 238 | BOOL isSafariViewService = [srcId isEqualToString:@"com.apple.mobilesafari"] || 239 | [srcId isEqualToString:@"com.apple.SafariViewService"]; 240 | if (!isSafariViewService) { 241 | HBLogDebug(@">> [ACCEPT] %@ is a system application except Safari View Service", srcId); 242 | return NO; 243 | } 244 | } 245 | 246 | return YES; 247 | } 248 | 249 | if (([destId isEqualToString:@"com.apple.AppStore"] || 250 | [destId isEqualToString:@"com.apple.ios.StoreKitUIService"]) && 251 | [gForbiddenLaunchSourcesForAppStore containsObject:srcId]) { 252 | HBLogDebug(@"> [REJECT] %@ is forbidden from launching App Store", srcId); 253 | return YES; 254 | } 255 | 256 | if (([destId isEqualToString:@"com.apple.mobilesafari"] || 257 | [destId isEqualToString:@"com.apple.SafariViewService"]) && 258 | [gForbiddenLaunchSourcesForSafariServices containsObject:srcId]) { 259 | HBLogDebug(@"> [REJECT] %@ is forbidden from launching Safari View Service", srcId); 260 | return YES; 261 | } 262 | 263 | if ([gCustomForbiddenMappings containsObject:mapping]) { 264 | HBLogDebug(@"> [REJECT] Custom mapping %@ is forbidden", mapping); 265 | return YES; 266 | } 267 | 268 | HBLogDebug(@"> [ACCEPT] Allowed"); 269 | return NO; 270 | } 271 | 272 | static void RecordRequest(NSString *srcId, NSString *destId, BOOL declined) { 273 | if (!srcId || !destId) { 274 | return; 275 | } 276 | 277 | if (!gRecordingEnabled) { 278 | return; 279 | } 280 | 281 | if ([srcId isEqualToString:@"com.apple.springboard"]) { 282 | return; 283 | } 284 | 285 | if ([destId isEqualToString:@"com.apple.SafariViewService"]) { 286 | destId = @"com.apple.mobilesafari"; 287 | } else if ([destId isEqualToString:@"com.apple.ios.StoreKitUIService"]) { 288 | destId = @"com.apple.AppStore"; 289 | } 290 | 291 | [NoRedirectRecord insertRecord:declined source:srcId target:destId]; 292 | } 293 | 294 | %group NoRedirectPrimary 295 | 296 | // %hook FBSystemService 297 | // 298 | // - (void)_reallyActivateApplication:(id)arg1 requestID:(id)arg2 options:(id)arg3 source:(id)arg4 originalSource:(id)arg5 isTrusted:(BOOL)arg6 sequenceNumber:(unsigned long long)arg7 cacheGUID:(id)arg8 ourSequenceNumber:(unsigned long long)arg9 ourCacheGUID:(id)arg10 withResult:(/*^block*/id)arg11 { 299 | // %log; %orig; 300 | // } 301 | // 302 | // %end 303 | 304 | %hook SBMainWorkspace 305 | 306 | - (BOOL)_executeTransitionRequest:(id)arg1 options:(unsigned long long)arg2 validator:(id)arg3 { 307 | HBLogDebug(@"_executeTransitionRequest: %@, options: %llu, validator: %@", arg1, (unsigned long long)arg2, arg3); 308 | 309 | BOOL transitionFinished = %orig; 310 | if (!transitionFinished) { 311 | return NO; 312 | } 313 | 314 | if (!gEnabled) { 315 | return transitionFinished; 316 | } 317 | 318 | if (![arg1 isKindOfClass:%c(SBMainWorkspaceTransitionRequest)]) { 319 | return transitionFinished; 320 | } 321 | 322 | SBWorkspaceTransitionRequest *request = (SBWorkspaceTransitionRequest *)arg1; 323 | SBApplicationSceneEntity *toEntity = request.toApplicationSceneEntities.anyObject; 324 | NSString *toAppId = toEntity.application.bundleIdentifier; 325 | if (!toAppId) { 326 | return transitionFinished; 327 | } 328 | 329 | if (!gLastTransitionStamps) { 330 | gLastTransitionStamps = [NSMutableDictionary dictionary]; 331 | } 332 | 333 | gLastTransitionStamps[toAppId] = @(CACurrentMediaTime()); 334 | HBLogDebug(@"Recorded transition to %@ at %.3f", toAppId, [gLastTransitionStamps[toAppId] doubleValue]); 335 | return transitionFinished; 336 | } 337 | 338 | - (BOOL)_canExecuteTransitionRequest:(id)arg1 forExecution:(BOOL)arg2 { 339 | if (!gEnabled) { 340 | return %orig; 341 | } 342 | 343 | HBLogDebug(@"Checking if transition request can be executed: %@", arg1); 344 | 345 | if (![arg1 isKindOfClass:%c(SBMainWorkspaceTransitionRequest)]) { 346 | return %orig; 347 | } 348 | 349 | BOOL isFromBreadcrumb = NO; 350 | SBWorkspaceTransitionRequest *request = (SBWorkspaceTransitionRequest *)arg1; 351 | NSString *eventLabel = request.eventLabel; 352 | if (eventLabel) { 353 | HBLogDebug(@"Event Label: %@", eventLabel); 354 | 355 | isFromBreadcrumb = [eventLabel containsString:@"ActivateFromBreadcrumb"]; 356 | BOOL isEligibleForDecline = isFromBreadcrumb || ([eventLabel containsString:@"OpenApplication"] && [eventLabel containsString:@"ForRequester"]); 357 | if (!isEligibleForDecline) { 358 | return %orig; 359 | } 360 | } 361 | 362 | NSString *fromAppId = nil; 363 | SBApplicationSceneEntity *fromEntity = request.fromApplicationSceneEntities.anyObject; 364 | if (fromEntity) { 365 | id fromAction = fromEntity.actions.anyObject; 366 | if (fromAction) { 367 | HBLogDebug(@"From Action: %@", fromAction); 368 | 369 | BOOL isEligibleForDecline = [fromAction isKindOfClass:%c(UIOpenURLAction)]; 370 | if (!isEligibleForDecline) { 371 | return %orig; 372 | } 373 | } 374 | 375 | fromAppId = fromEntity.application.bundleIdentifier; 376 | } else { 377 | NSString *fromProcessName = request.originatingProcess.name; 378 | if (isFromBreadcrumb || [fromProcessName isEqualToString:@"lsd"]) { 379 | SBLayoutElement *fromElement = [request.applicationContext.previousLayoutState elementWithRole:1]; 380 | fromAppId = fromElement.uniqueIdentifier; 381 | 382 | if ([fromAppId hasPrefix:@"sceneID:"]) { 383 | fromAppId = [fromAppId substringFromIndex:8]; 384 | } 385 | 386 | if ([fromAppId hasSuffix:@"-default"]) { 387 | fromAppId = [fromAppId substringToIndex:fromAppId.length - 8]; 388 | } else if (fromAppId.length > 37) { 389 | fromAppId = [fromAppId substringToIndex:fromAppId.length - 37]; 390 | } 391 | } 392 | } 393 | 394 | fromAppId = fromAppId ?: request.originatingProcess.bundleIdentifier; 395 | SBApplicationSceneEntity *toEntity = request.toApplicationSceneEntities.anyObject; 396 | NSString *toAppId = toEntity.application.bundleIdentifier; 397 | if (ShouldDeclineRequest(fromAppId, toAppId)) { 398 | RecordRequest(fromAppId, toAppId, YES); 399 | 400 | if ([gUseHandledSimulationSources containsObject:fromAppId]) { 401 | BOOL isStoreKitUI = [toAppId isEqualToString:@"com.apple.ios.StoreKitUIService"]; 402 | if (isStoreKitUI) { 403 | [request declineWithReason:@"No Redirect (Handled)"]; 404 | return NO; 405 | } 406 | 407 | BOOL isSafariUI = [toAppId isEqualToString:@"com.apple.SafariViewService"]; 408 | if (isSafariUI) { 409 | HBLogDebug(@"Redirecting to Safari View Services (Fallback)"); 410 | return %orig; 411 | } 412 | 413 | [request.applicationContext setBackground:YES]; 414 | return %orig; 415 | } 416 | 417 | [request declineWithReason:@"No Redirect"]; 418 | return NO; 419 | } 420 | 421 | RecordRequest(fromAppId, toAppId, NO); 422 | return %orig; 423 | } 424 | 425 | %end 426 | 427 | %end 428 | 429 | %group NoRedirectSafari 430 | 431 | %hook _SFBrowserContentViewController 432 | 433 | - (void)viewWillAppear:(BOOL)arg1 { 434 | %orig; 435 | 436 | NSString *fromAppId = [self _hostApplicationBundleIdentifier]; 437 | NSString *toAppId = @"com.apple.SafariViewService"; 438 | if (ShouldDeclineRequest(fromAppId, toAppId)) { 439 | if ([gUseHandledSimulationSources containsObject:fromAppId]) { 440 | HBLogDebug(@"Dismissed Safari View Services (Handled)"); 441 | [self _dismiss]; 442 | } 443 | } 444 | } 445 | 446 | %end 447 | 448 | %end 449 | 450 | %ctor { 451 | NSString *processName = [[NSProcessInfo processInfo] processName]; 452 | 453 | #if !TARGET_OS_SIMULATOR 454 | if ([processName isEqualToString:@"SafariViewService"]) { 455 | int ret; 456 | #if THEOS_PACKAGE_SCHEME_ROOTHIDE 457 | ret = libSandy_applyProfile("NoRedirectSafari_RootHide"); 458 | #else 459 | ret = libSandy_applyProfile("NoRedirectSafari"); 460 | #endif 461 | if (ret == kLibSandyErrorXPCFailure) { 462 | HBLogError(@"Failed to apply libSandy profile"); 463 | return; 464 | } 465 | gIsSafariViewService = YES; 466 | } 467 | #endif 468 | 469 | ReloadPrefs(); 470 | CFNotificationCenterAddObserver( 471 | CFNotificationCenterGetDarwinNotifyCenter(), 472 | NULL, 473 | (CFNotificationCallback)ReloadPrefs, 474 | CFSTR("com.82flex.noredirectprefs/saved"), 475 | NULL, 476 | CFNotificationSuspensionBehaviorCoalesce 477 | ); 478 | 479 | if ([processName isEqualToString:@"SpringBoard"]) { 480 | [NoRedirectRecord clearAllRecordsBeforeBoot]; 481 | %init(NoRedirectPrimary); 482 | } else if ([processName isEqualToString:@"SafariViewService"]) { 483 | %init(NoRedirectSafari); 484 | } 485 | 486 | HBLogWarn(@"NoRedirect initialized"); 487 | } -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/AltList.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ arm64, arm64e ] 3 | uuids: [ 'arm64: 5A5E5A01-3F7A-344A-884A-E7051F38DA03' ] 4 | platform: ios 5 | flags: [ flat_namespace, not_app_extension_safe ] 6 | install-name: "/Library/Frameworks/AltList.framework/AltList" 7 | current-version: 0 8 | compatibility-version: 0 9 | objc-constraint: retain_release 10 | exports: 11 | - archs: [ arm64, arm64e ] 12 | symbols: [ _safe_getExecutablePath, _tagArrayContainsTag ] 13 | objc-classes: [ _ATLApplicationListControllerBase, 14 | _ATLApplicationListMultiSelectionController, 15 | _ATLApplicationListSelectionController, 16 | _ATLApplicationListSubcontroller, 17 | _ATLApplicationListSubcontrollerController, 18 | _ATLApplicationSection, _ATLApplicationSelectionCell, 19 | _ATLApplicationSubtitleCell, 20 | _ATLApplicationSubtitleSwitchCell ] 21 | objc-ivars: [ _ATLApplicationListControllerBase._allSpecifiers, 22 | _ATLApplicationListControllerBase._altListBundle, 23 | _ATLApplicationListControllerBase._applicationSections, 24 | _ATLApplicationListControllerBase._iconLoadQueue, 25 | _ATLApplicationListControllerBase._isPopulated, 26 | _ATLApplicationListControllerBase._isReloadingSpecifiers, 27 | _ATLApplicationListControllerBase._placeholderAppIcon, 28 | _ATLApplicationListControllerBase._searchController, 29 | _ATLApplicationListControllerBase._searchKey, 30 | _ATLApplicationListControllerBase._specifiersByLetter, 31 | _ATLApplicationListMultiSelectionController._defaultApplicationSwitchValue, 32 | _ATLApplicationListMultiSelectionController._selectedApplications, 33 | _ATLApplicationListSelectionController._selectedApplicationID, 34 | _ATLApplicationSubtitleCell._customValueLabel ] 35 | undefineds: 36 | - archs: [ arm64, arm64e ] 37 | symbols: [ _NSClassFromString, _UIFontTextStyleBody, 38 | __Block_object_assign, __Block_object_dispose, 39 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 40 | __NSGetExecutablePath, __Unwind_Resume, 41 | ___CFConstantStringClassReference, ___kCFBooleanTrue, 42 | ___objc_personality_v0, ___stack_chk_fail, 43 | ___stack_chk_guard, __dispatch_main_q, 44 | __objc_empty_cache, _dispatch_async, 45 | _dispatch_get_global_queue, 46 | _dispatch_queue_attr_make_with_qos_class, 47 | _dispatch_queue_create, _objc_alloc, 48 | _objc_autoreleaseReturnValue, _objc_msgSend, 49 | _objc_msgSendSuper2, _objc_opt_class, 50 | _objc_opt_isKindOfClass, _objc_opt_new, 51 | _objc_opt_respondsToSelector, _objc_release, 52 | _objc_retain, _objc_retainAutoreleaseReturnValue, 53 | _objc_retainAutoreleasedReturnValue, 54 | _objc_storeStrong, 55 | _objc_unsafeClaimAutoreleasedReturnValue ] 56 | objc-classes: [ _LSApplicationProxy, _LSApplicationWorkspace, _NSArray, 57 | _NSBundle, _NSCharacterSet, _NSDictionary, _NSLocale, 58 | _NSMutableArray, _NSMutableDictionary, _NSMutableSet, 59 | _NSNumber, _NSObject, _NSPredicate, _NSSortDescriptor, 60 | _NSString, _PSListController, _PSSpecifier, 61 | _PSSwitchTableCell, _PSTableCell, _UIApplication, 62 | _UIColor, _UIFont, _UIImage, _UILabel, _UIScreen, 63 | _UISearchController ] 64 | objc-ivars: [ _PSListController._specifiers, _PSSpecifier.getter, 65 | _PSSpecifier.setter, _PSSpecifier.target ] 66 | ... 67 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationListControllerBase.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "ATLApplicationSection.h" 4 | 5 | @class LSApplicationProxy; 6 | 7 | @interface PSListController() 8 | - (BOOL)containsSpecifier:(PSSpecifier*)specifier; 9 | @end 10 | 11 | @protocol LSApplicationWorkspaceObserverProtocol 12 | @optional 13 | -(void)applicationsDidInstall:(id)arg1; 14 | -(void)applicationsDidUninstall:(id)arg1; 15 | @end 16 | 17 | @interface ATLApplicationListControllerBase : PSListController 18 | { 19 | dispatch_queue_t _iconLoadQueue; 20 | NSMutableArray* _allSpecifiers; 21 | NSMutableDictionary* _specifiersByLetter; 22 | NSArray* _applicationSections; 23 | UISearchController* _searchController; 24 | NSString* _searchKey; 25 | BOOL _isPopulated; 26 | BOOL _isReloadingSpecifiers; 27 | NSBundle* _altListBundle; 28 | UIImage* _placeholderAppIcon; 29 | } 30 | 31 | @property (nonatomic) BOOL useSearchBar; 32 | @property (nonatomic) BOOL hideSearchBarWhileScrolling; 33 | @property (nonatomic) BOOL includeIdentifiersInSearch; 34 | @property (nonatomic) BOOL highlightSearchText; 35 | @property (nonatomic) BOOL showIdentifiersAsSubtitle; 36 | @property (nonatomic) BOOL alphabeticIndexingEnabled; 37 | @property (nonatomic) BOOL hideAlphabeticSectionHeaders; 38 | @property (nonatomic) NSBundle* localizationBundle; 39 | 40 | - (instancetype)initWithSections:(NSArray*)applicationSections; 41 | 42 | - (void)_setUpSearchBar; 43 | - (void)_loadSectionsFromSpecifier; 44 | - (void)_populateSections; 45 | 46 | - (void)loadPreferences; 47 | - (void)prepareForPopulatingSections; 48 | - (NSString*)localizedStringForString:(NSString*)string; 49 | - (void)reloadApplications; 50 | 51 | - (BOOL)shouldHideApplicationSpecifiers; 52 | - (BOOL)shouldHideApplicationSpecifier:(PSSpecifier*)specifier; 53 | 54 | - (BOOL)shouldShowSubtitles; 55 | - (NSString*)subtitleForApplicationWithIdentifier:(NSString*)applicationID; 56 | - (NSString*)_subtitleForSpecifier:(PSSpecifier*)specifier; 57 | 58 | - (PSCellType)cellTypeForApplicationCells; 59 | - (Class)customCellClassForCellType:(PSCellType)cellType; 60 | - (Class)detailControllerClassForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy; 61 | - (SEL)getterForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy; 62 | - (SEL)setterForSpecifierOfApplicationProxy:(LSApplicationProxy*)applicationProxy; 63 | 64 | - (PSSpecifier*)createSpecifierForApplicationProxy:(LSApplicationProxy*)applicationProxy; 65 | - (NSArray*)createSpecifiersForApplicationSection:(ATLApplicationSection*)section; 66 | - (PSSpecifier*)createGroupSpecifierForApplicationSection:(ATLApplicationSection*)section; 67 | 68 | - (NSMutableArray*)specifiersGroupedByLetters; 69 | - (void)populateSpecifiersByLetter; 70 | 71 | - (PSSpecifier*)specifierForApplicationWithIdentifier:(NSString*)applicationID; 72 | - (NSIndexPath*)indexPathForApplicationWithIdentifier:(NSString*)applicationID; 73 | 74 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationListMultiSelectionController.h: -------------------------------------------------------------------------------- 1 | #import "ATLApplicationListControllerBase.h" 2 | 3 | @interface ATLApplicationListMultiSelectionController : ATLApplicationListControllerBase 4 | { 5 | NSMutableSet* _selectedApplications; 6 | BOOL _defaultApplicationSwitchValue; 7 | } 8 | 9 | - (void)setApplicationEnabled:(NSNumber*)enabledNum specifier:(PSSpecifier*)specifier; 10 | - (id)readApplicationEnabled:(PSSpecifier*)specifier; 11 | 12 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationListSelectionController.h: -------------------------------------------------------------------------------- 1 | #import "ATLApplicationListControllerBase.h" 2 | 3 | @interface ATLApplicationListSelectionController : ATLApplicationListControllerBase 4 | { 5 | NSString* _selectedApplicationID; 6 | } 7 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationListSubcontroller.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ATLApplicationListSubcontroller : PSListController 4 | @property (nonatomic) NSString* applicationID; 5 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationListSubcontrollerController.h: -------------------------------------------------------------------------------- 1 | #import "ATLApplicationListControllerBase.h" 2 | 3 | @interface ATLApplicationListSubcontrollerController : ATLApplicationListControllerBase 4 | @property (nonatomic) Class subcontrollerClass; 5 | 6 | - (NSString*)previewStringForApplicationWithIdentifier:(NSString*)applicationID; 7 | 8 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationSection.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef NS_ENUM(NSInteger, ApplicationSectionType) { 4 | SECTION_TYPE_ALL, 5 | SECTION_TYPE_SYSTEM, 6 | SECTION_TYPE_USER, 7 | SECTION_TYPE_HIDDEN, 8 | SECTION_TYPE_VISIBLE, 9 | SECTION_TYPE_CUSTOM 10 | }; 11 | 12 | #define kApplicationSectionTypeAll @"All" 13 | #define kApplicationSectionTypeSystem @"System" 14 | #define kApplicationSectionTypeUser @"User" 15 | #define kApplicationSectionTypeHidden @"Hidden" 16 | #define kApplicationSectionTypeVisible @"Visible" 17 | #define kApplicationSectionTypeCustom @"Custom" 18 | 19 | @interface ATLApplicationSection : NSObject 20 | @property (nonatomic) ApplicationSectionType sectionType; 21 | @property (nonatomic) NSPredicate* customPredicate; 22 | @property (nonatomic) NSString* sectionName; 23 | 24 | @property (nonatomic) NSArray* applicationsInSection; 25 | 26 | + (ApplicationSectionType)sectionTypeFromString:(NSString*)typeString; 27 | + (NSString*)stringFromSectionType:(ApplicationSectionType)sectionType; 28 | 29 | + (__kindof ATLApplicationSection*)applicationSectionWithDictionary:(NSDictionary*)sectionDictionary; 30 | - (instancetype)_initWithDictionary:(NSDictionary*)sectionDictionary; 31 | - (instancetype)initNonCustomSectionWithType:(ApplicationSectionType)sectionType; 32 | - (instancetype)initCustomSectionWithPredicate:(NSPredicate*)predicate sectionName:(NSString*)sectionName; 33 | - (NSArray*)sortDescriptorsForApplications; 34 | - (void)populateFromAllApplications:(NSArray*)allApplications; 35 | 36 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationSelectionCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ATLApplicationSelectionCell : PSTableCell 4 | 5 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationSubtitleCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface ATLApplicationSubtitleCell : PSTableCell 5 | { 6 | UILabel* _customValueLabel; 7 | } 8 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/ATLApplicationSubtitleSwitchCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface ATLApplicationSubtitleSwitchCell : PSSwitchTableCell 5 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Headers/AltList.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | AltList 9 | CFBundleIdentifier 10 | com.opa334.altlist 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | FMWK 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | NSPrincipalClass 22 | ATLApplicationListControllerBase 23 | 24 | 25 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/AltList.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module AltList { 2 | umbrella header "AltList.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_roothide/AltList.framework/AltList.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ arm64, arm64e ] 3 | uuids: [ 'arm64: 5A5E5A01-3F7A-344A-884A-E7051F38DA03' ] 4 | platform: ios 5 | flags: [ flat_namespace, not_app_extension_safe ] 6 | install-name: "@loader_path/.jbroot/Library/Frameworks/AltList.framework/AltList" 7 | current-version: 0 8 | compatibility-version: 0 9 | objc-constraint: retain_release 10 | exports: 11 | - archs: [ arm64, arm64e ] 12 | symbols: [ _safe_getExecutablePath, _tagArrayContainsTag ] 13 | objc-classes: [ _ATLApplicationListControllerBase, 14 | _ATLApplicationListMultiSelectionController, 15 | _ATLApplicationListSelectionController, 16 | _ATLApplicationListSubcontroller, 17 | _ATLApplicationListSubcontrollerController, 18 | _ATLApplicationSection, _ATLApplicationSelectionCell, 19 | _ATLApplicationSubtitleCell, 20 | _ATLApplicationSubtitleSwitchCell ] 21 | objc-ivars: [ _ATLApplicationListControllerBase._allSpecifiers, 22 | _ATLApplicationListControllerBase._altListBundle, 23 | _ATLApplicationListControllerBase._applicationSections, 24 | _ATLApplicationListControllerBase._iconLoadQueue, 25 | _ATLApplicationListControllerBase._isPopulated, 26 | _ATLApplicationListControllerBase._isReloadingSpecifiers, 27 | _ATLApplicationListControllerBase._placeholderAppIcon, 28 | _ATLApplicationListControllerBase._searchController, 29 | _ATLApplicationListControllerBase._searchKey, 30 | _ATLApplicationListControllerBase._specifiersByLetter, 31 | _ATLApplicationListMultiSelectionController._defaultApplicationSwitchValue, 32 | _ATLApplicationListMultiSelectionController._selectedApplications, 33 | _ATLApplicationListSelectionController._selectedApplicationID, 34 | _ATLApplicationSubtitleCell._customValueLabel ] 35 | undefineds: 36 | - archs: [ arm64, arm64e ] 37 | symbols: [ _NSClassFromString, _UIFontTextStyleBody, 38 | __Block_object_assign, __Block_object_dispose, 39 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 40 | __NSGetExecutablePath, __Unwind_Resume, 41 | ___CFConstantStringClassReference, ___kCFBooleanTrue, 42 | ___objc_personality_v0, ___stack_chk_fail, 43 | ___stack_chk_guard, __dispatch_main_q, 44 | __objc_empty_cache, _dispatch_async, 45 | _dispatch_get_global_queue, 46 | _dispatch_queue_attr_make_with_qos_class, 47 | _dispatch_queue_create, _objc_alloc, 48 | _objc_autoreleaseReturnValue, _objc_msgSend, 49 | _objc_msgSendSuper2, _objc_opt_class, 50 | _objc_opt_isKindOfClass, _objc_opt_new, 51 | _objc_opt_respondsToSelector, _objc_release, 52 | _objc_retain, _objc_retainAutoreleaseReturnValue, 53 | _objc_retainAutoreleasedReturnValue, 54 | _objc_storeStrong, 55 | _objc_unsafeClaimAutoreleasedReturnValue ] 56 | objc-classes: [ _LSApplicationProxy, _LSApplicationWorkspace, _NSArray, 57 | _NSBundle, _NSCharacterSet, _NSDictionary, _NSLocale, 58 | _NSMutableArray, _NSMutableDictionary, _NSMutableSet, 59 | _NSNumber, _NSObject, _NSPredicate, _NSSortDescriptor, 60 | _NSString, _PSListController, _PSSpecifier, 61 | _PSSwitchTableCell, _PSTableCell, _UIApplication, 62 | _UIColor, _UIFont, _UIImage, _UILabel, _UIScreen, 63 | _UISearchController ] 64 | objc-ivars: [ _PSListController._specifiers, _PSSpecifier.getter, 65 | _PSSpecifier.setter, _PSSpecifier.target ] 66 | ... 67 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_roothide/AltList.framework/Headers: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Headers -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_roothide/AltList.framework/Info.plist: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Info.plist -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_roothide/AltList.framework/Modules: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Modules -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_roothide/Preferences.framework/Preferences.tbd: -------------------------------------------------------------------------------- 1 | ../../Preferences.framework/Preferences.tbd -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_rootless/AltList.framework/AltList.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ arm64, arm64e ] 3 | uuids: [ 'arm64: 5A5E5A01-3F7A-344A-884A-E7051F38DA03' ] 4 | platform: ios 5 | flags: [ flat_namespace, not_app_extension_safe ] 6 | install-name: "@rpath/AltList.framework/AltList" 7 | current-version: 0 8 | compatibility-version: 0 9 | objc-constraint: retain_release 10 | exports: 11 | - archs: [ arm64, arm64e ] 12 | symbols: [ _safe_getExecutablePath, _tagArrayContainsTag ] 13 | objc-classes: [ _ATLApplicationListControllerBase, 14 | _ATLApplicationListMultiSelectionController, 15 | _ATLApplicationListSelectionController, 16 | _ATLApplicationListSubcontroller, 17 | _ATLApplicationListSubcontrollerController, 18 | _ATLApplicationSection, _ATLApplicationSelectionCell, 19 | _ATLApplicationSubtitleCell, 20 | _ATLApplicationSubtitleSwitchCell ] 21 | objc-ivars: [ _ATLApplicationListControllerBase._allSpecifiers, 22 | _ATLApplicationListControllerBase._altListBundle, 23 | _ATLApplicationListControllerBase._applicationSections, 24 | _ATLApplicationListControllerBase._iconLoadQueue, 25 | _ATLApplicationListControllerBase._isPopulated, 26 | _ATLApplicationListControllerBase._isReloadingSpecifiers, 27 | _ATLApplicationListControllerBase._placeholderAppIcon, 28 | _ATLApplicationListControllerBase._searchController, 29 | _ATLApplicationListControllerBase._searchKey, 30 | _ATLApplicationListControllerBase._specifiersByLetter, 31 | _ATLApplicationListMultiSelectionController._defaultApplicationSwitchValue, 32 | _ATLApplicationListMultiSelectionController._selectedApplications, 33 | _ATLApplicationListSelectionController._selectedApplicationID, 34 | _ATLApplicationSubtitleCell._customValueLabel ] 35 | undefineds: 36 | - archs: [ arm64, arm64e ] 37 | symbols: [ _NSClassFromString, _UIFontTextStyleBody, 38 | __Block_object_assign, __Block_object_dispose, 39 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 40 | __NSGetExecutablePath, __Unwind_Resume, 41 | ___CFConstantStringClassReference, ___kCFBooleanTrue, 42 | ___objc_personality_v0, ___stack_chk_fail, 43 | ___stack_chk_guard, __dispatch_main_q, 44 | __objc_empty_cache, _dispatch_async, 45 | _dispatch_get_global_queue, 46 | _dispatch_queue_attr_make_with_qos_class, 47 | _dispatch_queue_create, _objc_alloc, 48 | _objc_autoreleaseReturnValue, _objc_msgSend, 49 | _objc_msgSendSuper2, _objc_opt_class, 50 | _objc_opt_isKindOfClass, _objc_opt_new, 51 | _objc_opt_respondsToSelector, _objc_release, 52 | _objc_retain, _objc_retainAutoreleaseReturnValue, 53 | _objc_retainAutoreleasedReturnValue, 54 | _objc_storeStrong, 55 | _objc_unsafeClaimAutoreleasedReturnValue ] 56 | objc-classes: [ _LSApplicationProxy, _LSApplicationWorkspace, _NSArray, 57 | _NSBundle, _NSCharacterSet, _NSDictionary, _NSLocale, 58 | _NSMutableArray, _NSMutableDictionary, _NSMutableSet, 59 | _NSNumber, _NSObject, _NSPredicate, _NSSortDescriptor, 60 | _NSString, _PSListController, _PSSpecifier, 61 | _PSSwitchTableCell, _PSTableCell, _UIApplication, 62 | _UIColor, _UIFont, _UIImage, _UILabel, _UIScreen, 63 | _UISearchController ] 64 | objc-ivars: [ _PSListController._specifiers, _PSSpecifier.getter, 65 | _PSSpecifier.setter, _PSSpecifier.target ] 66 | ... 67 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_rootless/AltList.framework/Headers: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Headers -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_rootless/AltList.framework/Info.plist: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Info.plist -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_rootless/AltList.framework/Modules: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Modules -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_rootless/Preferences.framework/Preferences.tbd: -------------------------------------------------------------------------------- 1 | ../../Preferences.framework/Preferences.tbd -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_simulator/AltList.framework/AltList.tbd: -------------------------------------------------------------------------------- 1 | --- !tapi-tbd-v2 2 | archs: [ x86_64, arm64 ] 3 | uuids: [ 'arm64: 5A5E5A01-3F7A-344A-884A-E7051F38DA03' ] 4 | platform: ios 5 | flags: [ flat_namespace, not_app_extension_safe ] 6 | install-name: "@rpath/AltList.framework/AltList" 7 | current-version: 0 8 | compatibility-version: 0 9 | objc-constraint: retain_release 10 | exports: 11 | - archs: [ x86_64, arm64 ] 12 | symbols: [ _safe_getExecutablePath, _tagArrayContainsTag ] 13 | objc-classes: [ _ATLApplicationListControllerBase, 14 | _ATLApplicationListMultiSelectionController, 15 | _ATLApplicationListSelectionController, 16 | _ATLApplicationListSubcontroller, 17 | _ATLApplicationListSubcontrollerController, 18 | _ATLApplicationSection, _ATLApplicationSelectionCell, 19 | _ATLApplicationSubtitleCell, 20 | _ATLApplicationSubtitleSwitchCell ] 21 | objc-ivars: [ _ATLApplicationListControllerBase._allSpecifiers, 22 | _ATLApplicationListControllerBase._altListBundle, 23 | _ATLApplicationListControllerBase._applicationSections, 24 | _ATLApplicationListControllerBase._iconLoadQueue, 25 | _ATLApplicationListControllerBase._isPopulated, 26 | _ATLApplicationListControllerBase._isReloadingSpecifiers, 27 | _ATLApplicationListControllerBase._placeholderAppIcon, 28 | _ATLApplicationListControllerBase._searchController, 29 | _ATLApplicationListControllerBase._searchKey, 30 | _ATLApplicationListControllerBase._specifiersByLetter, 31 | _ATLApplicationListMultiSelectionController._defaultApplicationSwitchValue, 32 | _ATLApplicationListMultiSelectionController._selectedApplications, 33 | _ATLApplicationListSelectionController._selectedApplicationID, 34 | _ATLApplicationSubtitleCell._customValueLabel ] 35 | undefineds: 36 | - archs: [ x86_64, arm64 ] 37 | symbols: [ _NSClassFromString, _UIFontTextStyleBody, 38 | __Block_object_assign, __Block_object_dispose, 39 | __NSConcreteGlobalBlock, __NSConcreteStackBlock, 40 | __NSGetExecutablePath, __Unwind_Resume, 41 | ___CFConstantStringClassReference, ___kCFBooleanTrue, 42 | ___objc_personality_v0, ___stack_chk_fail, 43 | ___stack_chk_guard, __dispatch_main_q, 44 | __objc_empty_cache, _dispatch_async, 45 | _dispatch_get_global_queue, 46 | _dispatch_queue_attr_make_with_qos_class, 47 | _dispatch_queue_create, _objc_alloc, 48 | _objc_autoreleaseReturnValue, _objc_msgSend, 49 | _objc_msgSendSuper2, _objc_opt_class, 50 | _objc_opt_isKindOfClass, _objc_opt_new, 51 | _objc_opt_respondsToSelector, _objc_release, 52 | _objc_retain, _objc_retainAutoreleaseReturnValue, 53 | _objc_retainAutoreleasedReturnValue, 54 | _objc_storeStrong, 55 | _objc_unsafeClaimAutoreleasedReturnValue ] 56 | objc-classes: [ _LSApplicationProxy, _LSApplicationWorkspace, _NSArray, 57 | _NSBundle, _NSCharacterSet, _NSDictionary, _NSLocale, 58 | _NSMutableArray, _NSMutableDictionary, _NSMutableSet, 59 | _NSNumber, _NSObject, _NSPredicate, _NSSortDescriptor, 60 | _NSString, _PSListController, _PSSpecifier, 61 | _PSSwitchTableCell, _PSTableCell, _UIApplication, 62 | _UIColor, _UIFont, _UIImage, _UILabel, _UIScreen, 63 | _UISearchController ] 64 | objc-ivars: [ _PSListController._specifiers, _PSSpecifier.getter, 65 | _PSSpecifier.setter, _PSSpecifier.target ] 66 | ... 67 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_simulator/AltList.framework/Headers: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Headers -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_simulator/AltList.framework/Info.plist: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Info.plist -------------------------------------------------------------------------------- /NoRedirectPrefs/Frameworks/_simulator/AltList.framework/Modules: -------------------------------------------------------------------------------- 1 | ../../AltList.framework/Modules -------------------------------------------------------------------------------- /NoRedirectPrefs/LSApplicationProxy+AltList.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface LSApplicationProxy (AltList) 5 | - (BOOL)atl_isSystemApplication; 6 | - (BOOL)atl_isUserApplication; 7 | - (BOOL)atl_isHidden; 8 | - (NSString*)atl_fastDisplayName; 9 | - (NSString*)atl_nameToDisplay; 10 | @property (nonatomic,readonly) NSString* atl_bundleIdentifier; 11 | @end 12 | 13 | @interface LSApplicationWorkspace (AltList) 14 | - (NSArray*)atl_allInstalledApplications; 15 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(THEOS_DEVICE_SIMULATOR),1) 2 | TARGET := simulator:clang:latest:14.0 3 | INSTALL_TARGET_PROCESSES := Preferences 4 | ARCHS := arm64 x86_64 5 | else 6 | TARGET := iphone:clang:latest:14.0 7 | INSTALL_TARGET_PROCESSES := Preferences 8 | ARCHS := arm64 arm64e 9 | endif 10 | 11 | include $(THEOS)/makefiles/common.mk 12 | 13 | BUNDLE_NAME := NoRedirectPrefs 14 | 15 | NoRedirectPrefs_FILES += NoRedirectRootListController.m 16 | NoRedirectPrefs_FILES += NoRedirectAppListController.m 17 | NoRedirectPrefs_FILES += NoRedirectAppSpecificViewController.m 18 | NoRedirectPrefs_FILES += NoRedirectAppSelectionViewController.m 19 | NoRedirectPrefs_FILES += NoRedirectHistoryViewController.m 20 | NoRedirectPrefs_FILES += ../NoRedirectRecord.m 21 | 22 | ifeq ($(THEOS_PACKAGE_SCHEME),roothide) 23 | NoRedirectPrefs_FILES += ../libroot/dyn.c 24 | endif 25 | 26 | NoRedirectPrefs_CFLAGS += -fobjc-arc 27 | NoRedirectPrefs_CFLAGS += -I.. 28 | 29 | ifeq ($(THEOS_DEVICE_SIMULATOR),1) 30 | NoRedirectPrefs_CFLAGS += -FFrameworks/_simulator 31 | NoRedirectPrefs_LDFLAGS += -FFrameworks/_simulator 32 | NoRedirectPrefs_LDFLAGS += -rpath /opt/simject 33 | else 34 | ifeq ($(THEOS_PACKAGE_SCHEME),rootless) 35 | NoRedirectPrefs_CFLAGS += -FFrameworks/_rootless 36 | NoRedirectPrefs_LDFLAGS += -FFrameworks/_rootless 37 | else 38 | ifeq ($(THEOS_PACKAGE_SCHEME),roothide) 39 | NoRedirectPrefs_CFLAGS += -FFrameworks/_roothide 40 | NoRedirectPrefs_LDFLAGS += -FFrameworks/_roothide 41 | else 42 | NoRedirectPrefs_CFLAGS += -FFrameworks 43 | NoRedirectPrefs_LDFLAGS += -FFrameworks 44 | endif 45 | endif 46 | endif 47 | 48 | NoRedirectPrefs_FRAMEWORKS += UIKit 49 | NoRedirectPrefs_EXTRA_FRAMEWORKS += AltList 50 | NoRedirectPrefs_PRIVATE_FRAMEWORKS += CoreServices 51 | NoRedirectPrefs_PRIVATE_FRAMEWORKS += Preferences 52 | NoRedirectPrefs_INSTALL_PATH += /Library/PreferenceBundles 53 | 54 | include $(THEOS_MAKE_PATH)/bundle.mk -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface NoRedirectAppListController : ATLApplicationListSubcontrollerController 5 | @end 6 | -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppListController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #import "NoRedirectAppListController.h" 7 | 8 | @implementation NoRedirectAppListController 9 | 10 | - (NSString *)previewStringForApplicationWithIdentifier:(NSString *)applicationID { 11 | static NSUserDefaults *defaults = nil; 12 | if (!defaults) { 13 | defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.82flex.noredirectprefs"]; 14 | } 15 | 16 | BOOL hasBeenModified = NO; 17 | NSString *appSuffix = [NSString stringWithFormat:@"/%@", applicationID]; 18 | NSDictionary *settings = [defaults dictionaryRepresentation]; 19 | for (NSString *key in settings) { 20 | if ([key hasSuffix:appSuffix]) { 21 | id value = [defaults objectForKey:key]; 22 | if ([value isKindOfClass:[NSNumber class]] && [value boolValue]) { 23 | hasBeenModified = YES; 24 | break; 25 | } 26 | else if ([value isKindOfClass:[NSArray class]] && [value count] > 0) { 27 | hasBeenModified = YES; 28 | break; 29 | } 30 | } 31 | } 32 | 33 | if (hasBeenModified) { 34 | return NSLocalizedStringFromTableInBundle(@"Modified", @"App", [NSBundle bundleForClass:self.class], nil); 35 | } 36 | 37 | return nil; 38 | } 39 | 40 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppSelectionViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #define kNoRedirectKeyCustomBlockedApplications @"CustomBlockedApplications" 5 | #define kNoRedirectKeyCustomBypassedApplications @"CustomBypassedApplications" 6 | 7 | @interface NoRedirectAppSelectionViewController : ATLApplicationListMultiSelectionController 8 | @property(nonatomic, copy) NSString *applicationID; 9 | @property(nonatomic, copy) NSString *preferenceKey; 10 | @property(nonatomic, weak) PSListController *presentingParentController; 11 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppSelectionViewController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #import "NoRedirectAppSelectionViewController.h" 7 | 8 | @implementation NoRedirectAppSelectionViewController { 9 | PSSpecifier *_primarySpecifier; 10 | NSMutableArray *_selectedApplications; 11 | UIBarButtonItem *_cancelButton; 12 | UIBarButtonItem *_saveButton; 13 | BOOL _isChanged; 14 | } 15 | 16 | - (PSSpecifier *)primarySpecifier { 17 | if (!_primarySpecifier) { 18 | _primarySpecifier = [PSSpecifier preferenceSpecifierNamed:@"Selected Applications" 19 | target:self 20 | set:@selector(setPreferenceValue:specifier:) 21 | get:@selector(readPreferenceValue:) 22 | detail:nil 23 | cell:PSLinkListCell 24 | edit:nil]; 25 | [_primarySpecifier setProperty:[NSString stringWithFormat:@"%@/%@", self.preferenceKey, self.applicationID] 26 | forKey:@"key"]; 27 | [_primarySpecifier setProperty:@"com.82flex.noredirectprefs" forKey:@"defaults"]; 28 | [_primarySpecifier setProperty:@"com.82flex.noredirectprefs/saved" forKey:@"PostNotification"]; 29 | } 30 | return _primarySpecifier; 31 | } 32 | 33 | - (void)readSelectedApplications { 34 | _selectedApplications = [NSMutableArray arrayWithArray:([super readPreferenceValue:[self primarySpecifier]] ?: @[])]; 35 | } 36 | 37 | - (void)writeSelectedApplications { 38 | [super setPreferenceValue:(_selectedApplications ?: @[]) specifier:[self primarySpecifier]]; 39 | } 40 | 41 | - (void)setApplicationEnabled:(NSNumber *)enabledNum specifier:(PSSpecifier *)specifier { 42 | if (!specifier.identifier) { 43 | return; 44 | } 45 | if ([enabledNum boolValue]) { 46 | [_selectedApplications addObject:specifier.identifier]; 47 | } else { 48 | [_selectedApplications removeObject:specifier.identifier]; 49 | } 50 | _isChanged = YES; 51 | [self reloadSaveButton]; 52 | } 53 | 54 | - (id)readApplicationEnabled:(PSSpecifier *)specifier { 55 | return @([_selectedApplications containsObject:specifier.identifier]); 56 | } 57 | 58 | - (void)viewDidLoad { 59 | [super viewDidLoad]; 60 | 61 | _cancelButton = [[UIBarButtonItem alloc] 62 | initWithTitle:NSLocalizedStringFromTableInBundle(@"Cancel", @"App", [NSBundle bundleForClass:self.class], nil) 63 | style:UIBarButtonItemStylePlain 64 | target:self 65 | action:@selector(performDismissal:)]; 66 | self.navigationItem.leftBarButtonItem = _cancelButton; 67 | 68 | _saveButton = [[UIBarButtonItem alloc] 69 | initWithTitle:NSLocalizedStringFromTableInBundle(@"Save", @"App", [NSBundle bundleForClass:self.class], nil) 70 | style:UIBarButtonItemStyleDone 71 | target:self 72 | action:@selector(performSave:)]; 73 | _saveButton.enabled = NO; 74 | self.navigationItem.rightBarButtonItem = _saveButton; 75 | 76 | [self readSelectedApplications]; 77 | } 78 | 79 | - (void)performDismissal:(id)sender { 80 | [self dismissViewControllerAnimated:YES completion:nil]; 81 | } 82 | 83 | - (void)performSave:(id)sender { 84 | [self writeSelectedApplications]; 85 | [self.presentingParentController reloadSpecifiers]; 86 | [self dismissViewControllerAnimated:YES completion:nil]; 87 | } 88 | 89 | - (void)reloadSaveButton { 90 | [_saveButton setEnabled:_isChanged]; 91 | } 92 | 93 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppSpecificViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface NoRedirectAppSpecificViewController : ATLApplicationListControllerBase 5 | @property(nonatomic, copy) NSString *applicationID; 6 | @end 7 | -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectAppSpecificViewController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | 7 | #import "LSApplicationProxy+AltList.h" 8 | #import "NoRedirectAppSelectionViewController.h" 9 | #import "NoRedirectAppSpecificViewController.h" 10 | 11 | @implementation NoRedirectAppSpecificViewController { 12 | NSString *_applicationName; 13 | PSSpecifier *_blockedSpecifier; 14 | NSMutableArray *_blockedApplications; 15 | NSMutableArray *_blockedApplicationNames; 16 | PSSpecifier *_bypassedSpecifier; 17 | NSMutableArray *_bypassedApplications; 18 | NSMutableArray *_bypassedApplicationNames; 19 | } 20 | 21 | - (void)viewWillDisappear:(BOOL)animated { 22 | [super viewWillDisappear:animated]; 23 | PSListController *topVC = (PSListController *)self.navigationController.topViewController; 24 | if ([topVC respondsToSelector:@selector(reloadSpecifier:)]) { 25 | [topVC reloadSpecifier:[self specifier]]; 26 | } 27 | } 28 | 29 | - (NSString *)applicationName { 30 | if (!_applicationName) { 31 | LSApplicationProxy *appProxy = [LSApplicationProxy applicationProxyForIdentifier:self.applicationID]; 32 | _applicationName = appProxy.atl_nameToDisplay; 33 | } 34 | return _applicationName ?: self.specifier.name; 35 | } 36 | 37 | - (void)setSpecifier:(PSSpecifier *)specifier { 38 | [super setSpecifier:specifier]; 39 | 40 | NSString *appId = [specifier propertyForKey:@"applicationIdentifier"]; 41 | self.applicationID = appId; 42 | 43 | [self setTitle:[self applicationName]]; 44 | } 45 | 46 | - (NSMutableArray *)loadSpecifiersFromPlistName:(NSString *)plistName target:(id)target { 47 | NSMutableArray *specifiers = [super loadSpecifiersFromPlistName:plistName target:target]; 48 | if (!self.title || self.title.length == 0) { 49 | [self setTitle:[self applicationName]]; 50 | } 51 | return specifiers; 52 | } 53 | 54 | - (NSArray *)specifiers { 55 | if (!_specifiers) { 56 | NSMutableArray *specifiers = [self loadSpecifiersFromPlistName:[self plistName] target:self]; 57 | 58 | PSSpecifier *groupCustomBlocksSpecifier = nil; 59 | PSSpecifier *addCustomBlockSpecifier = nil; 60 | PSSpecifier *groupCustomBypassesSpecifier = nil; 61 | PSSpecifier *addCustonBypassSpecifier = nil; 62 | 63 | for (PSSpecifier *specifier in specifiers) { 64 | NSString *action = [specifier propertyForKey:@"action"]; 65 | NSString *key = [specifier propertyForKey:@"key"]; 66 | 67 | NSString *mixedKey = [NSString stringWithFormat:@"%@/%@", key, self.applicationID]; 68 | [specifier setProperty:mixedKey forKey:@"key"]; 69 | 70 | if ([action isEqualToString:@"addCustomBlock"]) { 71 | addCustomBlockSpecifier = specifier; 72 | } else if ([action isEqualToString:@"addCustomBypass"]) { 73 | addCustonBypassSpecifier = specifier; 74 | } else if ([key isEqualToString:@"GroupCustomBlocks"]) { 75 | groupCustomBlocksSpecifier = specifier; 76 | } else if ([key isEqualToString:@"GroupCustomBypasses"]) { 77 | groupCustomBypassesSpecifier = specifier; 78 | } 79 | } 80 | 81 | NSInteger blockInsertionPoint = [specifiers indexOfObject:addCustomBlockSpecifier]; 82 | NSInteger bypassInsertionPoint = [specifiers indexOfObject:addCustonBypassSpecifier]; 83 | 84 | [self readBlockedApplications]; 85 | [self readBypassedApplications]; 86 | 87 | _blockedApplicationNames = [NSMutableArray arrayWithCapacity:_blockedApplications.count]; 88 | _bypassedApplicationNames = [NSMutableArray arrayWithCapacity:_bypassedApplications.count]; 89 | 90 | NSMutableArray *blockedSpecifiers = [NSMutableArray array]; 91 | for (NSString *blockedApp in _blockedApplications) { 92 | LSApplicationProxy *appProxy = [LSApplicationProxy applicationProxyForIdentifier:blockedApp]; 93 | if (!appProxy) { 94 | continue; 95 | } 96 | 97 | PSSpecifier *appSpec = [self createSpecifierForApplicationProxy:appProxy]; 98 | if (!appSpec) { 99 | continue; 100 | } 101 | 102 | [blockedSpecifiers addObject:appSpec]; 103 | if (appSpec.name) { 104 | [_blockedApplicationNames addObject:appSpec.name]; 105 | } 106 | } 107 | [blockedSpecifiers sortUsingComparator:^NSComparisonResult(PSSpecifier *obj1, PSSpecifier *obj2) { 108 | return [obj1.name localizedStandardCompare:obj2.name]; 109 | }]; 110 | 111 | NSMutableArray *bypassedSpecifiers = [NSMutableArray array]; 112 | for (NSString *bypassedApp in _bypassedApplications) { 113 | LSApplicationProxy *appProxy = [LSApplicationProxy applicationProxyForIdentifier:bypassedApp]; 114 | if (!appProxy) { 115 | continue; 116 | } 117 | 118 | PSSpecifier *appSpec = [self createSpecifierForApplicationProxy:appProxy]; 119 | if (!appSpec) { 120 | continue; 121 | } 122 | 123 | [bypassedSpecifiers addObject:appSpec]; 124 | if (appSpec.name) { 125 | [_bypassedApplicationNames addObject:appSpec.name]; 126 | } 127 | } 128 | [bypassedSpecifiers sortUsingComparator:^NSComparisonResult(PSSpecifier *obj1, PSSpecifier *obj2) { 129 | return [obj1.name localizedStandardCompare:obj2.name]; 130 | }]; 131 | 132 | [groupCustomBlocksSpecifier setProperty:[self blockedFooterText] forKey:@"footerText"]; 133 | [groupCustomBypassesSpecifier setProperty:[self bypassedFooterText] forKey:@"footerText"]; 134 | 135 | if (blockedSpecifiers.count > 0) { 136 | addCustomBlockSpecifier.name = NSLocalizedStringFromTableInBundle( 137 | @"Edit Custom Block…", @"App", [NSBundle bundleForClass:self.class], nil); 138 | } 139 | 140 | if (bypassedSpecifiers.count > 0) { 141 | addCustonBypassSpecifier.name = NSLocalizedStringFromTableInBundle( 142 | @"Edit Custom Bypass…", @"App", [NSBundle bundleForClass:self.class], nil); 143 | } 144 | 145 | [specifiers insertObjects:bypassedSpecifiers 146 | atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(bypassInsertionPoint, 147 | bypassedSpecifiers.count)]]; 148 | [specifiers insertObjects:blockedSpecifiers 149 | atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(blockInsertionPoint, 150 | blockedSpecifiers.count)]]; 151 | 152 | _specifiers = specifiers; 153 | } 154 | return _specifiers; 155 | } 156 | 157 | - (PSSpecifier *)blockedSpecifier { 158 | if (!_blockedSpecifier) { 159 | _blockedSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Blocked Applications" 160 | target:self 161 | set:@selector(setPreferenceValue:specifier:) 162 | get:@selector(readPreferenceValue:) 163 | detail:nil 164 | cell:PSLinkListCell 165 | edit:nil]; 166 | [_blockedSpecifier setProperty:[NSString stringWithFormat:@"%@/%@", kNoRedirectKeyCustomBlockedApplications, 167 | self.applicationID] 168 | forKey:@"key"]; 169 | [_blockedSpecifier setProperty:@"com.82flex.noredirectprefs" forKey:@"defaults"]; 170 | } 171 | return _blockedSpecifier; 172 | } 173 | 174 | - (void)readBlockedApplications { 175 | _blockedApplications = [NSMutableArray arrayWithArray:([super readPreferenceValue:[self blockedSpecifier]] ?: @[])]; 176 | } 177 | 178 | - (PSSpecifier *)bypassedSpecifier { 179 | if (!_bypassedSpecifier) { 180 | _bypassedSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Bypassed Applications" 181 | target:self 182 | set:@selector(setPreferenceValue:specifier:) 183 | get:@selector(readPreferenceValue:) 184 | detail:nil 185 | cell:PSLinkListCell 186 | edit:nil]; 187 | [_bypassedSpecifier setProperty:[NSString stringWithFormat:@"%@/%@", kNoRedirectKeyCustomBypassedApplications, 188 | self.applicationID] 189 | forKey:@"key"]; 190 | [_bypassedSpecifier setProperty:@"com.82flex.noredirectprefs" forKey:@"defaults"]; 191 | } 192 | return _bypassedSpecifier; 193 | } 194 | 195 | - (void)readBypassedApplications { 196 | _bypassedApplications = 197 | [NSMutableArray arrayWithArray:([super readPreferenceValue:[self bypassedSpecifier]] ?: @[])]; 198 | } 199 | 200 | - (NSString *)plistName { 201 | return @"App"; 202 | } 203 | 204 | - (NSString *)blockedFooterText { 205 | NSString *what; 206 | if (_blockedApplicationNames.count == 1) { 207 | what = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@”", @"App", 208 | [NSBundle bundleForClass:self.class], nil), 209 | [_blockedApplicationNames firstObject]]; 210 | } else if (_blockedApplications.count == 2) { 211 | what = 212 | [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@” and “%@”", @"App", 213 | [NSBundle bundleForClass:self.class], nil), 214 | [_blockedApplicationNames firstObject], [_blockedApplicationNames lastObject]]; 215 | } else if (_blockedApplications.count > 2) { 216 | NSString *what2; 217 | if (_blockedApplications.count == 3) { 218 | what2 = [NSString 219 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu other application", @"App", 220 | [NSBundle bundleForClass:self.class], nil), 221 | _blockedApplications.count - 2]; 222 | } else { 223 | what2 = [NSString 224 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu other applications", @"App", 225 | [NSBundle bundleForClass:self.class], nil), 226 | _blockedApplications.count - 2]; 227 | } 228 | what = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@”, “%@” and %@", @"App", 229 | [NSBundle bundleForClass:self.class], nil), 230 | [_blockedApplicationNames firstObject], 231 | [_blockedApplicationNames objectAtIndex:1], what2]; 232 | } else { 233 | what = nil; 234 | } 235 | if (!what) { 236 | return @""; 237 | } 238 | return [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@” is blocked from launching %@.", @"App", 239 | [NSBundle bundleForClass:self.class], nil), 240 | _applicationName, what]; 241 | } 242 | 243 | - (NSString *)bypassedFooterText { 244 | NSString *what; 245 | if (_bypassedApplications.count == 1) { 246 | what = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@”", @"App", 247 | [NSBundle bundleForClass:self.class], nil), 248 | [_bypassedApplicationNames firstObject]]; 249 | } else if (_bypassedApplications.count == 2) { 250 | what = 251 | [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@” and “%@”", @"App", 252 | [NSBundle bundleForClass:self.class], nil), 253 | [_bypassedApplicationNames firstObject], [_bypassedApplicationNames lastObject]]; 254 | } else if (_bypassedApplications.count > 2) { 255 | NSString *what2; 256 | if (_bypassedApplications.count == 3) { 257 | what2 = [NSString 258 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu other application", @"App", 259 | [NSBundle bundleForClass:self.class], nil), 260 | _bypassedApplications.count - 2]; 261 | } else { 262 | what2 = [NSString 263 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%lu other applications", @"App", 264 | [NSBundle bundleForClass:self.class], nil), 265 | _bypassedApplications.count - 2]; 266 | } 267 | what = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"“%@”, “%@” and %@", @"App", 268 | [NSBundle bundleForClass:self.class], nil), 269 | [_bypassedApplicationNames firstObject], 270 | [_bypassedApplicationNames objectAtIndex:1], what2]; 271 | } else { 272 | what = nil; 273 | } 274 | if (!what) { 275 | return @""; 276 | } 277 | return [NSString 278 | stringWithFormat:NSLocalizedStringFromTableInBundle( 279 | @"“%@” is always allowed to be launched by %@. These rules have the highest priority.", 280 | @"App", [NSBundle bundleForClass:self.class], nil), 281 | _applicationName, what]; 282 | } 283 | 284 | - (void)addCustomBlock { 285 | [self customSelectionWithKey:kNoRedirectKeyCustomBlockedApplications]; 286 | } 287 | 288 | - (void)addCustomBypass { 289 | [self customSelectionWithKey:kNoRedirectKeyCustomBypassedApplications]; 290 | } 291 | 292 | - (void)customSelectionWithKey:(NSString *)prefKey { 293 | NoRedirectAppSelectionViewController *selectionCtrl = 294 | [[NoRedirectAppSelectionViewController alloc] initWithSections:@[ 295 | [ATLApplicationSection applicationSectionWithDictionary:@{ 296 | @"sectionType" : kApplicationSectionTypeUser, 297 | }], 298 | [ATLApplicationSection applicationSectionWithDictionary:@{ 299 | @"sectionType" : kApplicationSectionTypeSystem, 300 | }], 301 | ]]; 302 | 303 | selectionCtrl.applicationID = self.applicationID; 304 | selectionCtrl.showIdentifiersAsSubtitle = YES; 305 | selectionCtrl.useSearchBar = YES; 306 | selectionCtrl.hideSearchBarWhileScrolling = YES; 307 | selectionCtrl.includeIdentifiersInSearch = YES; 308 | if ([selectionCtrl respondsToSelector:@selector(highlightSearchText)]) { 309 | selectionCtrl.highlightSearchText = YES; 310 | } 311 | selectionCtrl.title = _applicationName; 312 | selectionCtrl.presentingParentController = self; 313 | selectionCtrl.preferenceKey = prefKey; 314 | 315 | UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:selectionCtrl]; 316 | [navCtrl setModalInPresentation:YES]; 317 | [self presentViewController:navCtrl animated:YES completion:nil]; 318 | } 319 | 320 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectHistoryViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface NoRedirectHistoryViewController : ATLApplicationListControllerBase 5 | @end 6 | -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectHistoryViewController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #import "LSApplicationProxy+AltList.h" 7 | #import "NoRedirectAppSpecificViewController.h" 8 | #import "NoRedirectHistoryViewController.h" 9 | #import "NoRedirectRecord.h" 10 | 11 | @interface PSSpecifier (Private) 12 | @property(nonatomic, retain) NSArray *values; 13 | @end 14 | 15 | @implementation NoRedirectHistoryViewController { 16 | UIBarButtonItem *_clearButton; 17 | PSSpecifier *_emptySpecifier; 18 | PSSpecifier *_statisticSpecifier; 19 | } 20 | 21 | - (BOOL)shouldShowSubtitles { 22 | return YES; 23 | } 24 | 25 | - (PSCellType)cellTypeForApplicationCells { 26 | return PSLinkListCell; 27 | } 28 | 29 | - (Class)detailControllerClassForSpecifierOfApplicationProxy:(LSApplicationProxy *)applicationProxy { 30 | return [NoRedirectAppSpecificViewController class]; 31 | } 32 | 33 | - (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier { 34 | [super setPreferenceValue:value specifier:specifier]; 35 | if (specifier == _statisticSpecifier) { 36 | [UIView transitionWithView:self.view 37 | duration:0.25 38 | options:UIViewAnimationOptionTransitionCrossDissolve 39 | animations:^{ 40 | [self reloadSpecifiers]; 41 | } 42 | completion:nil]; 43 | } 44 | } 45 | 46 | + (NSDateFormatter *)mediumDateFormatter { 47 | static NSDateFormatter *formatter; 48 | static dispatch_once_t onceToken; 49 | dispatch_once(&onceToken, ^{ 50 | formatter = [[NSDateFormatter alloc] init]; 51 | formatter.dateStyle = NSDateFormatterMediumStyle; 52 | formatter.timeStyle = NSDateFormatterNoStyle; 53 | }); 54 | return formatter; 55 | } 56 | 57 | - (PSSpecifier *)emptySpecifier { 58 | if (!_emptySpecifier) { 59 | _emptySpecifier = [PSSpecifier preferenceSpecifierNamed:@"" 60 | target:nil 61 | set:nil 62 | get:nil 63 | detail:nil 64 | cell:PSGroupCell 65 | edit:nil]; 66 | } 67 | return _emptySpecifier; 68 | } 69 | 70 | - (PSSpecifier *)statisticSpecifier { 71 | if (!_statisticSpecifier) { 72 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"" 73 | target:self 74 | set:@selector(setPreferenceValue:specifier:) 75 | get:@selector(readPreferenceValue:) 76 | detail:nil 77 | cell:PSSegmentCell 78 | edit:nil]; 79 | 80 | [specifier setIdentifier:@"StatisticsType"]; 81 | [specifier setProperty:@"StatisticsType" forKey:@"key"]; 82 | [specifier setProperty:@"com.82flex.noredirectprefs" forKey:@"defaults"]; 83 | [specifier setProperty:@YES forKey:@"enabled"]; 84 | 85 | specifier.values = @[ @0, @1 ]; 86 | specifier.titleDictionary = @{ 87 | @0 : 88 | NSLocalizedStringFromTableInBundle(@"By Date", @"History", [NSBundle bundleForClass:[self class]], nil), 89 | @1 : NSLocalizedStringFromTableInBundle(@"By Application", @"History", 90 | [NSBundle bundleForClass:[self class]], nil), 91 | }; 92 | 93 | [specifier setProperty:@0 forKey:@"default"]; 94 | 95 | _statisticSpecifier = specifier; 96 | } 97 | return _statisticSpecifier; 98 | } 99 | 100 | - (NSInteger)selectedStatisticsType { 101 | return [[self readPreferenceValue:[self statisticSpecifier]] integerValue]; 102 | } 103 | 104 | - (PSSpecifier *)createEmptySpecifier { 105 | PSSpecifier *specifier = [PSSpecifier 106 | preferenceSpecifierNamed:NSLocalizedStringFromTableInBundle(@"No history", @"History", 107 | [NSBundle bundleForClass:[self class]], nil) 108 | target:nil 109 | set:nil 110 | get:nil 111 | detail:nil 112 | cell:PSGroupCell 113 | edit:nil]; 114 | return specifier; 115 | } 116 | 117 | - (NSArray *)specifiers { 118 | if (!_specifiers) { 119 | NSMutableArray *specifiers = [NSMutableArray array]; 120 | 121 | NSInteger declinedCount = 0; 122 | NSInteger totalCount = 0; 123 | PSSpecifier *lastGroupSpecifier = nil; 124 | 125 | NSInteger selectedStatisticsType = [self selectedStatisticsType]; 126 | if (selectedStatisticsType == 0) { 127 | NSString *dateString = nil; 128 | NSMutableDictionary *cachedProxies = [NSMutableDictionary dictionary]; 129 | NSArray *records = [NoRedirectRecord allRecords]; 130 | for (NoRedirectRecord *record in records) { 131 | if (!record.source || !record.target) { 132 | continue; 133 | } 134 | 135 | LSApplicationProxy *srcProxy = cachedProxies[record.source]; 136 | if (!srcProxy) { 137 | srcProxy = [LSApplicationProxy applicationProxyForIdentifier:record.source]; 138 | if (srcProxy) { 139 | cachedProxies[record.source] = srcProxy; 140 | } 141 | } 142 | if (!srcProxy || srcProxy.atl_isHidden || !srcProxy.atl_nameToDisplay) { 143 | continue; 144 | } 145 | 146 | LSApplicationProxy *targetProxy = cachedProxies[record.target]; 147 | if (!targetProxy) { 148 | targetProxy = [LSApplicationProxy applicationProxyForIdentifier:record.target]; 149 | if (targetProxy) { 150 | cachedProxies[record.target] = targetProxy; 151 | } 152 | } 153 | if (!targetProxy || targetProxy.atl_isHidden || !targetProxy.atl_nameToDisplay) { 154 | continue; 155 | } 156 | 157 | PSSpecifier *specifier = [self createSpecifierForApplicationProxy:srcProxy]; 158 | if (!specifier) { 159 | continue; 160 | } 161 | 162 | specifier.name = 163 | [NSString stringWithFormat:@"%@ ❯ %@", srcProxy.atl_nameToDisplay, targetProxy.atl_nameToDisplay]; 164 | 165 | [specifier setProperty:record forKey:@"associatedRecord"]; 166 | [specifier setProperty:srcProxy.atl_nameToDisplay forKey:@"applicationName"]; 167 | 168 | NSString *newDateString = 169 | [[NoRedirectHistoryViewController mediumDateFormatter] stringFromDate:record.createdAt]; 170 | if (![dateString isEqualToString:newDateString]) { 171 | dateString = newDateString; 172 | 173 | PSSpecifier *dateSpecifier = [PSSpecifier preferenceSpecifierNamed:dateString 174 | target:nil 175 | set:nil 176 | get:nil 177 | detail:nil 178 | cell:PSGroupCell 179 | edit:nil]; 180 | 181 | [specifiers addObject:dateSpecifier]; 182 | 183 | lastGroupSpecifier = dateSpecifier; 184 | } 185 | 186 | specifier.identifier = [NSString stringWithFormat:@"%@-%@-%.0f", record.source, record.target, 187 | record.createdAt.timeIntervalSince1970]; 188 | 189 | [specifiers addObject:specifier]; 190 | 191 | if (record.declined) { 192 | declinedCount++; 193 | } 194 | 195 | totalCount++; 196 | } 197 | } else if (selectedStatisticsType == 1) { 198 | NSMutableDictionary *cachedProxies = [NSMutableDictionary dictionary]; 199 | NSMutableDictionary *requestsCountMapping = [NSMutableDictionary dictionary]; 200 | NSArray *records = [NoRedirectRecord allRecords]; 201 | for (NoRedirectRecord *record in records) { 202 | if (!record.source || !record.target) { 203 | continue; 204 | } 205 | 206 | LSApplicationProxy *srcProxy = cachedProxies[record.source]; 207 | if (!srcProxy) { 208 | srcProxy = [LSApplicationProxy applicationProxyForIdentifier:record.source]; 209 | if (srcProxy) { 210 | cachedProxies[record.source] = srcProxy; 211 | } 212 | } 213 | if (!srcProxy || srcProxy.atl_isHidden || !srcProxy.atl_nameToDisplay) { 214 | continue; 215 | } 216 | 217 | LSApplicationProxy *targetProxy = cachedProxies[record.target]; 218 | if (!targetProxy) { 219 | targetProxy = [LSApplicationProxy applicationProxyForIdentifier:record.target]; 220 | if (targetProxy) { 221 | cachedProxies[record.target] = targetProxy; 222 | } 223 | } 224 | if (!targetProxy || targetProxy.atl_isHidden || !targetProxy.atl_nameToDisplay) { 225 | continue; 226 | } 227 | 228 | NSInteger previousCount = [requestsCountMapping[record.source] integerValue]; 229 | requestsCountMapping[record.source] = @(previousCount + 1); 230 | 231 | if (record.declined) { 232 | declinedCount++; 233 | } 234 | 235 | totalCount++; 236 | } 237 | 238 | NSMutableArray *requestsProxies = [NSMutableArray array]; 239 | for (NSString *appId in requestsCountMapping) { 240 | LSApplicationProxy *proxy = cachedProxies[appId]; 241 | [requestsProxies addObject:proxy]; 242 | } 243 | [requestsProxies 244 | sortUsingComparator:^NSComparisonResult(LSApplicationProxy *obj1, LSApplicationProxy *obj2) { 245 | NSComparisonResult countResult = 246 | [requestsCountMapping[obj2.bundleIdentifier] compare:requestsCountMapping[obj1.bundleIdentifier]]; 247 | if (countResult != NSOrderedSame) { 248 | return countResult; 249 | } 250 | return [obj1.atl_nameToDisplay localizedStandardCompare:obj2.atl_nameToDisplay]; 251 | }]; 252 | 253 | NSMutableArray *groupedSpecifiers = [NSMutableArray array]; 254 | for (LSApplicationProxy *proxy in requestsProxies) { 255 | PSSpecifier *specifier = [self createSpecifierForApplicationProxy:proxy]; 256 | if (!specifier) { 257 | continue; 258 | } 259 | 260 | [specifier setProperty:requestsCountMapping[proxy.bundleIdentifier] forKey:@"associatedCount"]; 261 | [specifier setProperty:proxy.atl_nameToDisplay forKey:@"applicationName"]; 262 | [groupedSpecifiers addObject:specifier]; 263 | } 264 | 265 | if (groupedSpecifiers.count > 0) { 266 | PSSpecifier *emptySpecifier = [PSSpecifier preferenceSpecifierNamed:@"" 267 | target:nil 268 | set:nil 269 | get:nil 270 | detail:nil 271 | cell:PSGroupCell 272 | edit:nil]; 273 | 274 | lastGroupSpecifier = emptySpecifier; 275 | 276 | [specifiers addObject:emptySpecifier]; 277 | } 278 | 279 | [specifiers addObjectsFromArray:groupedSpecifiers]; 280 | } 281 | 282 | if (specifiers.count == 0) { 283 | PSSpecifier *emptySpecifier = [self createEmptySpecifier]; 284 | [specifiers addObject:emptySpecifier]; 285 | } else { 286 | [specifiers insertObjects:@[ [self emptySpecifier], [self statisticSpecifier] ] 287 | atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)]]; 288 | 289 | [lastGroupSpecifier setProperty:[self statisticContentWithDeclinedCount:declinedCount totalCount:totalCount] 290 | forKey:@"footerText"]; 291 | } 292 | 293 | _specifiers = specifiers; 294 | } 295 | return _specifiers; 296 | } 297 | 298 | - (NSString *)statisticContentWithDeclinedCount:(NSInteger)declinedCount totalCount:(NSInteger)totalCount { 299 | if (totalCount == 0) { 300 | return nil; 301 | } 302 | NSString *totalDescription = nil; 303 | if (totalCount == 1) { 304 | totalDescription = 305 | NSLocalizedStringFromTableInBundle(@"1 request", @"History", [NSBundle bundleForClass:[self class]], nil); 306 | } else { 307 | totalDescription = 308 | [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"%ld requests", @"History", 309 | [NSBundle bundleForClass:[self class]], nil), 310 | (long)totalCount]; 311 | } 312 | if (declinedCount > 0) { 313 | NSString *declinedDescription = nil; 314 | if (declinedCount == 1) { 315 | declinedDescription = NSLocalizedStringFromTableInBundle(@"1 request", @"History", 316 | [NSBundle bundleForClass:[self class]], nil); 317 | } else { 318 | declinedDescription = [NSString 319 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%ld requests", @"History", 320 | [NSBundle bundleForClass:[self class]], nil), 321 | (long)declinedCount]; 322 | } 323 | return [NSString 324 | stringWithFormat:NSLocalizedStringFromTableInBundle( 325 | @"No Redirect has recognized %@ and declined %@ for you since the last boot.", 326 | @"History", [NSBundle bundleForClass:[self class]], nil), 327 | totalDescription, declinedDescription]; 328 | } else { 329 | return [NSString stringWithFormat:NSLocalizedStringFromTableInBundle( 330 | @"No Redirect has recognized %@ for you since the last boot.", @"History", 331 | [NSBundle bundleForClass:[self class]], nil), 332 | totalDescription]; 333 | } 334 | } 335 | 336 | + (NSDateFormatter *)shortDateTimeFormatter { 337 | static NSDateFormatter *formatter; 338 | static dispatch_once_t onceToken; 339 | dispatch_once(&onceToken, ^{ 340 | formatter = [[NSDateFormatter alloc] init]; 341 | formatter.dateStyle = NSDateFormatterShortStyle; 342 | formatter.timeStyle = NSDateFormatterShortStyle; 343 | }); 344 | return formatter; 345 | } 346 | 347 | - (NSString *)_subtitleForSpecifier:(PSSpecifier *)specifier { 348 | NoRedirectRecord *record = [specifier propertyForKey:@"associatedRecord"]; 349 | if (record) { 350 | if (record.declined) { 351 | return [NSString 352 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"Declined on %@", @"History", 353 | [NSBundle bundleForClass:[self class]], nil), 354 | [[NoRedirectHistoryViewController shortDateTimeFormatter] 355 | stringFromDate:record.createdAt]]; 356 | } else { 357 | return [NSString 358 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"Redirected on %@", @"History", 359 | [NSBundle bundleForClass:[self class]], nil), 360 | [[NoRedirectHistoryViewController shortDateTimeFormatter] 361 | stringFromDate:record.createdAt]]; 362 | } 363 | } else { 364 | NSInteger associatedCount = [[specifier propertyForKey:@"associatedCount"] integerValue]; 365 | if (associatedCount == 0) { 366 | return nil; 367 | } 368 | if (associatedCount == 1) { 369 | return NSLocalizedStringFromTableInBundle(@"1 request", @"History", [NSBundle bundleForClass:[self class]], 370 | nil); 371 | } else { 372 | return [NSString 373 | stringWithFormat:NSLocalizedStringFromTableInBundle(@"%ld requests", @"History", 374 | [NSBundle bundleForClass:[self class]], nil), 375 | (long)associatedCount]; 376 | } 377 | } 378 | } 379 | 380 | - (void)viewDidLoad { 381 | [super viewDidLoad]; 382 | 383 | self.title = 384 | NSLocalizedStringFromTableInBundle(@"Redirect History", @"Root", [NSBundle bundleForClass:self.class], nil); 385 | 386 | _clearButton = [[UIBarButtonItem alloc] 387 | initWithTitle:NSLocalizedStringFromTableInBundle(@"Clear", @"History", [NSBundle bundleForClass:self.class], 388 | nil) 389 | style:UIBarButtonItemStylePlain 390 | target:self 391 | action:@selector(clearHistory)]; 392 | 393 | self.navigationItem.rightBarButtonItem = _clearButton; 394 | } 395 | 396 | - (void)clearHistory { 397 | UIAlertController *alert = 398 | [UIAlertController alertControllerWithTitle:nil 399 | message:NSLocalizedStringFromTableInBundle( 400 | @"Are you sure you want to clear the redirect history?", 401 | @"History", [NSBundle bundleForClass:self.class], nil) 402 | preferredStyle:UIAlertControllerStyleActionSheet]; 403 | [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTableInBundle( 404 | @"Clear", @"History", [NSBundle bundleForClass:self.class], nil) 405 | style:UIAlertActionStyleDestructive 406 | handler:^(UIAlertAction *action) { 407 | [self realClearHistory]; 408 | }]]; 409 | [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTableInBundle( 410 | @"Cancel", @"Root", [NSBundle bundleForClass:self.class], nil) 411 | style:UIAlertActionStyleCancel 412 | handler:nil]]; 413 | [self presentViewController:alert animated:YES completion:nil]; 414 | } 415 | 416 | - (void)realClearHistory { 417 | [NoRedirectRecord clearAllRecords]; 418 | [self updateSpecifiers:[self specifiers] withSpecifiers:@[ [self createEmptySpecifier] ]]; 419 | } 420 | 421 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 422 | PSSpecifier *specifier = [self specifierAtIndexPath:indexPath]; 423 | NSString *appId = [specifier propertyForKey:@"applicationIdentifier"]; 424 | if ([appId isEqualToString:@"com.apple.springboard"]) { 425 | NSString *appName = [specifier propertyForKey:@"applicationName"]; 426 | UIAlertController *alert = [UIAlertController 427 | alertControllerWithTitle:nil 428 | message:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle( 429 | @"Settings of “%@” cannot be modified.", @"History", 430 | [NSBundle bundleForClass:self.class], nil), 431 | appName] 432 | preferredStyle:UIAlertControllerStyleAlert]; 433 | [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTableInBundle( 434 | @"OK", @"Root", [NSBundle bundleForClass:self.class], nil) 435 | style:UIAlertActionStyleCancel 436 | handler:^(UIAlertAction *_Nonnull action) { 437 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 438 | }]]; 439 | [self presentViewController:alert animated:YES completion:nil]; 440 | return; 441 | } 442 | [super tableView:tableView didSelectRowAtIndexPath:indexPath]; 443 | } 444 | 445 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectRootListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NoRedirectRootListController : PSListController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /NoRedirectPrefs/NoRedirectRootListController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | #import "NoRedirectRootListController.h" 9 | 10 | void NoRedirectEnumerateProcessesUsingBlock(void (^enumerator)(pid_t pid, NSString *executablePath, BOOL *stop)) { 11 | static int kMaximumArgumentSize = 0; 12 | static dispatch_once_t onceToken; 13 | dispatch_once(&onceToken, ^{ 14 | size_t valSize = sizeof(kMaximumArgumentSize); 15 | if (sysctl((int[]){CTL_KERN, KERN_ARGMAX}, 2, &kMaximumArgumentSize, &valSize, NULL, 0) < 0) { 16 | perror("sysctl argument size"); 17 | kMaximumArgumentSize = 4096; 18 | } 19 | }); 20 | 21 | size_t procInfoLength = 0; 22 | if (sysctl((int[]){CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}, 3, NULL, &procInfoLength, NULL, 0) < 0) { 23 | return; 24 | } 25 | 26 | static struct kinfo_proc *procInfo = NULL; 27 | procInfo = (struct kinfo_proc *)realloc(procInfo, procInfoLength + 1); 28 | if (!procInfo) { 29 | return; 30 | } 31 | 32 | bzero(procInfo, procInfoLength + 1); 33 | if (sysctl((int[]){CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}, 3, procInfo, &procInfoLength, NULL, 0) < 0) { 34 | return; 35 | } 36 | 37 | static char *argBuffer = NULL; 38 | int procInfoCnt = (int)(procInfoLength / sizeof(struct kinfo_proc)); 39 | for (int i = 0; i < procInfoCnt; i++) { 40 | 41 | pid_t pid = procInfo[i].kp_proc.p_pid; 42 | if (pid <= 1) { 43 | continue; 44 | } 45 | 46 | size_t argSize = kMaximumArgumentSize; 47 | if (sysctl((int[]){CTL_KERN, KERN_PROCARGS2, pid, 0}, 3, NULL, &argSize, NULL, 0) < 0) { 48 | continue; 49 | } 50 | 51 | argBuffer = (char *)realloc(argBuffer, argSize + 1); 52 | if (!argBuffer) { 53 | continue; 54 | } 55 | 56 | bzero(argBuffer, argSize + 1); 57 | if (sysctl((int[]){CTL_KERN, KERN_PROCARGS2, pid, 0}, 3, argBuffer, &argSize, NULL, 0) < 0) { 58 | continue; 59 | } 60 | 61 | BOOL stop = NO; 62 | @autoreleasepool { 63 | enumerator(pid, [NSString stringWithUTF8String:(argBuffer + sizeof(int))], &stop); 64 | } 65 | 66 | if (stop) { 67 | break; 68 | } 69 | } 70 | } 71 | 72 | void NoRedirectKillAll(NSString *processName, BOOL softly) { 73 | NoRedirectEnumerateProcessesUsingBlock(^(pid_t pid, NSString *executablePath, BOOL *stop) { 74 | if ([executablePath.lastPathComponent isEqualToString:processName]) { 75 | if (softly) { 76 | kill(pid, SIGTERM); 77 | } else { 78 | kill(pid, SIGKILL); 79 | } 80 | } 81 | }); 82 | } 83 | 84 | void NoRedirectBatchKillAll(NSArray *processNames, BOOL softly) { 85 | NoRedirectEnumerateProcessesUsingBlock(^(pid_t pid, NSString *executablePath, BOOL *stop) { 86 | if ([processNames containsObject:executablePath.lastPathComponent]) { 87 | if (softly) { 88 | kill(pid, SIGTERM); 89 | } else { 90 | kill(pid, SIGKILL); 91 | } 92 | } 93 | }); 94 | } 95 | 96 | @interface LSPlugInKitProxy : NSObject 97 | @property(nonatomic, readonly, copy) NSString *pluginIdentifier; 98 | @end 99 | 100 | @interface LSApplicationProxy : NSObject 101 | @property(nonatomic, readonly) NSArray *plugInKitPlugins; 102 | + (LSApplicationProxy *)applicationProxyForIdentifier:(NSString *)bundleIdentifier; 103 | @end 104 | 105 | @implementation NoRedirectRootListController 106 | 107 | - (NSArray *)specifiers { 108 | if (!_specifiers) { 109 | _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self]; 110 | } 111 | return _specifiers; 112 | } 113 | 114 | - (void)respring { 115 | NoRedirectBatchKillAll(@[ @"SpringBoard" ], YES); 116 | } 117 | 118 | - (void)support { 119 | NSURL *url = [NSURL URLWithString:@"https://havoc.app/search/82Flex"]; 120 | if ([[UIApplication sharedApplication] canOpenURL:url]) { 121 | [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; 122 | } 123 | } 124 | 125 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 126 | if (indexPath.section == 2) { 127 | PSSpecifier *specifier = [self specifierAtIndexPath:indexPath]; 128 | NSString *key = [specifier propertyForKey:@"cell"]; 129 | if ([key isEqualToString:@"PSButtonCell"]) { 130 | UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 131 | NSNumber *isDestructiveValue = [specifier propertyForKey:@"isDestructive"]; 132 | BOOL isDestructive = [isDestructiveValue boolValue]; 133 | cell.textLabel.textColor = isDestructive ? [UIColor systemRedColor] : [UIColor systemBlueColor]; 134 | cell.textLabel.highlightedTextColor = isDestructive ? [UIColor systemRedColor] : [UIColor systemBlueColor]; 135 | return cell; 136 | } 137 | } 138 | return [super tableView:tableView cellForRowAtIndexPath:indexPath]; 139 | } 140 | 141 | - (void)resetAll { 142 | [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:@"com.82flex.noredirectprefs"]; 143 | notify_post("com.82flex.noredirectprefs/saved"); 144 | [self reloadSpecifierAtIndex:1 animated:YES]; 145 | } 146 | 147 | @end -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/App.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | label 11 | General 12 | 13 | 14 | cell 15 | PSSwitchCell 16 | default 17 | 18 | defaults 19 | com.82flex.noredirectprefs 20 | key 21 | IsBlockedFromLaunchingOthers 22 | label 23 | Block from Launching Others 24 | PostNotification 25 | com.82flex.noredirectprefs/saved 26 | 27 | 28 | cell 29 | PSSwitchCell 30 | default 31 | 32 | defaults 33 | com.82flex.noredirectprefs 34 | key 35 | IsBlockedFromBeingLaunched 36 | label 37 | Block from Being Launched 38 | PostNotification 39 | com.82flex.noredirectprefs/saved 40 | 41 | 42 | cell 43 | PSGroupCell 44 | label 45 | Cancellation 46 | footerText 47 | Pause all blocks automatically in 10 seconds each time when application become active. 48 | 49 | 50 | cell 51 | PSSwitchCell 52 | default 53 | 54 | defaults 55 | com.82flex.noredirectprefs 56 | key 57 | ShouldTeardownAutomatically 58 | label 59 | Delayed Cancellation 60 | PostNotification 61 | com.82flex.noredirectprefs/saved 62 | 63 | 64 | cell 65 | PSGroupCell 66 | label 67 | Simulation 68 | footerText 69 | Tell the caller that the redirect was handled successfully. This may cause the caller to stop trying other fallback methods to open the URL. 70 | 71 | 72 | cell 73 | PSSwitchCell 74 | default 75 | 76 | defaults 77 | com.82flex.noredirectprefs 78 | key 79 | ShouldSimulateSuccess 80 | label 81 | Simulate Handled Request 82 | PostNotification 83 | com.82flex.noredirectprefs/saved 84 | 85 | 86 | cell 87 | PSGroupCell 88 | label 89 | Common Blocks 90 | 91 | 92 | cell 93 | PSSwitchCell 94 | default 95 | 96 | defaults 97 | com.82flex.noredirectprefs 98 | key 99 | IsBlockedFromLaunchingAppStore 100 | label 101 | App Store 102 | PostNotification 103 | com.82flex.noredirectprefs/saved 104 | 105 | 106 | cell 107 | PSSwitchCell 108 | default 109 | 110 | defaults 111 | com.82flex.noredirectprefs 112 | key 113 | IsBlockedFromLaunchingSafari 114 | label 115 | Safari 116 | PostNotification 117 | com.82flex.noredirectprefs/saved 118 | 119 | 120 | cell 121 | PSGroupCell 122 | label 123 | Custom Blocks 124 | key 125 | GroupCustomBlocks 126 | 127 | 128 | cell 129 | PSButtonCell 130 | label 131 | Add Custom Block… 132 | action 133 | addCustomBlock 134 | 135 | 136 | cell 137 | PSGroupCell 138 | label 139 | Custom Bypasses 140 | key 141 | GroupCustomBypasses 142 | 143 | 144 | cell 145 | PSButtonCell 146 | label 147 | Add Custom Bypass… 148 | action 149 | addCustomBypass 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | NoRedirectPrefs 9 | CFBundleIdentifier 10 | com.82flex.noredirectprefs 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | NSPrincipalClass 22 | NoRedirectPrefsRootListController 23 | 24 | 25 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | label 11 | General 12 | footerText 13 | This tweak is designed to prevent redirections from Safari, Chrome, and other apps to the App Store, Safari, and other apps. 14 | 15 | 16 | cell 17 | PSSwitchCell 18 | default 19 | 20 | defaults 21 | com.82flex.noredirectprefs 22 | key 23 | IsEnabled 24 | label 25 | Enabled 26 | PostNotification 27 | com.82flex.noredirectprefs/saved 28 | 29 | 30 | cell 31 | PSLinkListCell 32 | detail 33 | NoRedirectAppListController 34 | subcontrollerClass 35 | NoRedirectAppSpecificViewController 36 | label 37 | Application Settings 38 | sections 39 | 40 | 41 | sectionType 42 | User 43 | 44 | 45 | sectionType 46 | System 47 | 48 | 49 | showIdentifiersAsSubtitle 50 | 51 | useSearchBar 52 | 53 | includeIdentifiersInSearch 54 | 55 | highlightSearchText 56 | 57 | 58 | 59 | cell 60 | PSGroupCell 61 | label 62 | History 63 | footerText 64 | These records will be cleared each time you reboot your device. 65 | 66 | 67 | cell 68 | PSSwitchCell 69 | default 70 | 71 | defaults 72 | com.82flex.noredirectprefs 73 | key 74 | IsRecordingEnabled 75 | label 76 | Allow Recording 77 | PostNotification 78 | com.82flex.noredirectprefs/saved 79 | 80 | 81 | cell 82 | PSLinkListCell 83 | detail 84 | NoRedirectHistoryViewController 85 | label 86 | Redirect History 87 | 88 | 89 | cell 90 | PSGroupCell 91 | label 92 | 93 | 94 | 95 | cell 96 | PSButtonCell 97 | label 98 | Reset All… 99 | action 100 | resetAll 101 | confirmation 102 | 103 | title 104 | Reset 105 | prompt 106 | Are you sure you want to reset all settings? 107 | okTitle 108 | Reset 109 | cancelTitle 110 | Cancel 111 | 112 | isDestructive 113 | 114 | 115 | 116 | cell 117 | PSGroupCell 118 | label 119 | 120 | footerText 121 | Please support our paid works, thank you! 122 | 123 | 124 | cell 125 | PSButtonCell 126 | label 127 | Made with ♥ by OwnGoal Studio 128 | action 129 | support 130 | 131 | 132 | title 133 | No Redirect 134 | 135 | 136 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/en.lproj/App.strings: -------------------------------------------------------------------------------- 1 | "%lu other application" = "%lu other application"; 2 | 3 | "%lu other applications" = "%lu other applications"; 4 | 5 | "Add Custom Block…" = "Add Custom Block…"; 6 | 7 | "Add Custom Bypass…" = "Add Custom Bypass…"; 8 | 9 | "Advanced" = "Advanced"; 10 | 11 | "App Store" = "App Store"; 12 | 13 | "Block Applications" = "Block Applications"; 14 | 15 | "Block from Being Launched" = "Block from Being Launched"; 16 | 17 | "Block from Launching Others" = "Block from Launching Others"; 18 | 19 | "Cancel" = "Cancel"; 20 | 21 | "Cancellation" = "Cancellation"; 22 | 23 | "Common Blocks" = "Common Blocks"; 24 | 25 | "Custom Blocks" = "Custom Blocks"; 26 | 27 | "Custom Bypasses" = "Custom Bypasses"; 28 | 29 | "Delayed Cancellation" = "Delayed Cancellation"; 30 | 31 | "Edit Custom Block…" = "Edit Custom Block…"; 32 | 33 | "Edit Custom Bypass…" = "Edit Custom Bypass…"; 34 | 35 | "General" = "General"; 36 | 37 | "Modified" = "Modified"; 38 | 39 | "Pause all blocks automatically in 10 seconds each time when application become active." = "Pause all blocks automatically in 10 seconds each time when application become active."; 40 | 41 | "Safari" = "Safari"; 42 | 43 | "Save" = "Save"; 44 | 45 | "Simulate Handled Request" = "Simulate Handled Request"; 46 | 47 | "Simulation" = "Simulation"; 48 | 49 | "Tell the caller that the redirect was handled successfully. This may cause the caller to stop trying other fallback methods to open the URL." = "Tell the caller that the redirect was handled successfully. This may cause the caller to stop trying other fallback methods to open the URL."; 50 | 51 | "“%@”" = "“%@”"; 52 | 53 | "“%@” and “%@”" = "“%@” and “%@”"; 54 | 55 | "“%@” is always allowed to be launched by %@. These rules have the highest priority." = "“%@” is always allowed to be launched by %@. These rules have the highest priority."; 56 | 57 | "“%@” is blocked from launching %@." = "“%@” is blocked from launching %@."; 58 | 59 | "“%@”, “%@” and %@" = "“%@”, “%@” and %@"; 60 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/en.lproj/History.strings: -------------------------------------------------------------------------------- 1 | "Are you sure you want to clear the redirect history?" = "Are you sure you want to clear the redirect history?"; 2 | 3 | "By Date" = "By Date"; 4 | 5 | "By Application" = "By Application"; 6 | 7 | "Clear" = "Clear"; 8 | 9 | "Declined on %@" = "Declined on %@"; 10 | 11 | "Redirected on %@" = "Redirected on %@"; 12 | 13 | "Settings of “%@” cannot be modified." = "Settings of “%@” cannot be modified."; 14 | 15 | "No history" = "No history"; 16 | 17 | "No Redirect has recognized %@ for you since the last boot." = "No Redirect has recognized %@ for you since the last boot."; 18 | 19 | "No Redirect has recognized %@ and declined %@ for you since the last boot." = "No Redirect has recognized %@ and declined %@ for you since the last boot."; 20 | 21 | "1 request" = "1 request"; 22 | 23 | "%ld requests" = "%ld requests"; 24 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | "CFBundleDisplayName" = "No Redirect"; 2 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/en.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | "Allow Recording" = "Allow Recording"; 2 | 3 | "Application Settings" = "Application Settings"; 4 | 5 | "Are you sure you want to reset all settings?" = "Are you sure you want to reset all settings?"; 6 | 7 | "Cancel" = "Cancel"; 8 | 9 | "Enabled" = "Enabled"; 10 | 11 | "General" = "General"; 12 | 13 | "History" = "History"; 14 | 15 | "Made with ♥ by OwnGoal Studio" = "Made with ♥ by OwnGoal Studio"; 16 | 17 | "No Redirect" = "No Redirect"; 18 | 19 | "OK" = "OK"; 20 | 21 | "Please support our paid works, thank you!" = "Please support our paid works, thank you!"; 22 | 23 | "Redirect History" = "Redirect History"; 24 | 25 | "Reset" = "Reset"; 26 | 27 | "Reset All" = "Reset All"; 28 | 29 | "Reset All…" = "Reset All…"; 30 | 31 | "These records will be cleared each time you reboot your device." = "These records will be cleared each time you reboot your device."; 32 | 33 | "This tweak is designed to prevent redirections from Safari, Chrome, and other apps to the App Store, Safari, and other apps." = "This tweak is designed to prevent redirections from Safari, Chrome, and other apps to the App Store, Safari, and other apps."; 34 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OwnGoalStudio/NoRedirect/90c13f87f5bcfe5eabc8d8e49896006158b4f172/NoRedirectPrefs/Resources/icon@2x.png -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OwnGoalStudio/NoRedirect/90c13f87f5bcfe5eabc8d8e49896006158b4f172/NoRedirectPrefs/Resources/icon@3x.png -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/zh-Hans.lproj/App.strings: -------------------------------------------------------------------------------- 1 | "%lu other application" = "其他 %lu 个应用程序"; 2 | 3 | "%lu other applications" = "其他 %lu 个应用程序"; 4 | 5 | "Add Custom Block…" = "添加自定义拦截项…"; 6 | 7 | "Add Custom Bypass…" = "添加自定义放行项…"; 8 | 9 | "Advanced" = "高级"; 10 | 11 | "App Store" = "App Store"; 12 | 13 | "Block Applications" = "拦截应用程序"; 14 | 15 | "Block from Being Launched" = "禁止被其他应用程序启动"; 16 | 17 | "Block from Launching Others" = "禁止启动其他应用程序"; 18 | 19 | "Cancel" = "取消"; 20 | 21 | "Cancellation" = "解除"; 22 | 23 | "Common Blocks" = "常用拦截"; 24 | 25 | "Custom Blocks" = "自定义拦截"; 26 | 27 | "Custom Bypasses" = "自定义放行"; 28 | 29 | "Delayed Cancellation" = "延迟解除"; 30 | 31 | "Edit Custom Block…" = "编辑自定义拦截项…"; 32 | 33 | "Edit Custom Bypass…" = "编辑自定义放行项…"; 34 | 35 | "General" = "通用"; 36 | 37 | "Modified" = "已修改"; 38 | 39 | "Pause all blocks automatically in 10 seconds each time when application become active." = "每次应用程序进入前台 10 秒后自动暂停所有拦截。"; 40 | 41 | "Safari" = "Safari 浏览器"; 42 | 43 | "Save" = "保存"; 44 | 45 | "Simulate Handled Request" = "模拟已处理请求"; 46 | 47 | "Simulation" = "模拟"; 48 | 49 | "Tell the caller that the redirect was handled successfully. This may cause the caller to stop trying other fallback methods to open the URL." = "告诉调用者重定向已成功处理。这可能导致调用者停止尝试其他备用方法来打开 URL。"; 50 | 51 | "“%@”" = "“%@”"; 52 | 53 | "“%@” and “%@”" = "“%@” 和 “%@”"; 54 | 55 | "“%@” is always allowed to be launched by %@. These rules have the highest priority." = "“%@” 总是允许被 %@ 启动。这些规则具备最高优先级。"; 56 | 57 | "“%@” is blocked from launching %@." = "“%@” 被禁止启动 %@。"; 58 | 59 | "“%@”, “%@” and %@" = "“%@”,“%@” 和 %@"; 60 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/zh-Hans.lproj/History.strings: -------------------------------------------------------------------------------- 1 | "Are you sure you want to clear the redirect history?" = "你确定要清除重定向历史记录吗?"; 2 | 3 | "By Date" = "按日期"; 4 | 5 | "By Application" = "按应用程序"; 6 | 7 | "Clear" = "清除"; 8 | 9 | "Declined on %@" = "拦截于 %@"; 10 | 11 | "Redirected on %@" = "重定向于 %@"; 12 | 13 | "Settings of “%@” cannot be modified." = "无法修改 “%@” 的设置。"; 14 | 15 | "No history" = "无历史记录"; 16 | 17 | "No Redirect has recognized %@ for you since the last boot." = "自上次启动以来,禁字诀已为你识别 %@。"; 18 | 19 | "No Redirect has recognized %@ and declined %@ for you since the last boot." = "自上次启动以来,禁字诀已为你识别 %@,并拦截其中的 %@。"; 20 | 21 | "1 request" = "1 个重定向请求"; 22 | 23 | "%ld requests" = "%ld 个重定向请求"; 24 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | "CFBundleDisplayName" = "禁字诀"; 2 | -------------------------------------------------------------------------------- /NoRedirectPrefs/Resources/zh-Hans.lproj/Root.strings: -------------------------------------------------------------------------------- 1 | "Allow Recording" = "允许记录"; 2 | 3 | "Application Settings" = "应用程序设置"; 4 | 5 | "Are you sure you want to reset all settings?" = "你确定要还原所有选项吗?"; 6 | 7 | "Cancel" = "取消"; 8 | 9 | "Enabled" = "启用"; 10 | 11 | "General" = "通用"; 12 | 13 | "History" = "历史记录"; 14 | 15 | "Made with ♥ by OwnGoal Studio" = "「乌龙工作室」倾情献制"; 16 | 17 | "No Redirect" = "禁字诀"; 18 | 19 | "OK" = "好"; 20 | 21 | "Please support our paid works, thank you!" = "请支持我们的其他付费作品,谢谢!"; 22 | 23 | "Redirect History" = "重定向历史记录"; 24 | 25 | "Reset" = "重置"; 26 | 27 | "Reset All" = "重置所有选项"; 28 | 29 | "Reset All…" = "重置所有选项…"; 30 | 31 | "These records will be cleared each time you reboot your device." = "每次重启设备时都会清理这些记录。"; 32 | 33 | "This tweak is designed to prevent redirections from Safari, Chrome, and other apps to the App Store, Safari, and other apps." = "此插件旨在阻止 Safari、Chrome 和其他应用程序之间的重定向。"; 34 | -------------------------------------------------------------------------------- /NoRedirectPrefs/control: -------------------------------------------------------------------------------- 1 | ../control -------------------------------------------------------------------------------- /NoRedirectPrefs/layout/Library/PreferenceLoader/Preferences/NoRedirectPrefs/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | NoRedirectPrefs 9 | cell 10 | PSLinkCell 11 | detail 12 | NoRedirectRootListController 13 | icon 14 | icon.png 15 | isController 16 | 17 | label 18 | No Redirect 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /NoRedirectRecord.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NoRedirectRecord : NSObject 4 | 5 | @property(nonatomic, assign, readonly) BOOL declined; 6 | @property(nonatomic, copy, readonly) NSString *source; 7 | @property(nonatomic, copy, readonly) NSString *target; 8 | @property(nonatomic, copy, readonly) NSDate *createdAt; 9 | 10 | - (instancetype)init NS_UNAVAILABLE; 11 | + (NSArray *)allRecords; 12 | + (void)insertRecord:(BOOL)declined source:(NSString *)sourceIdentifier target:(NSString *)targetIdentifier; 13 | + (void)clearAllRecordsBeforeBoot; 14 | + (void)clearAllRecords; 15 | 16 | @end -------------------------------------------------------------------------------- /NoRedirectRecord.m: -------------------------------------------------------------------------------- 1 | #import "NoRedirectRecord.h" 2 | 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | 9 | @implementation NoRedirectRecord 10 | 11 | @synthesize declined = _declined; 12 | @synthesize source = _source; 13 | @synthesize target = _target; 14 | @synthesize createdAt = _createdAt; 15 | 16 | + (sqlite3 *)sharedDatabase { 17 | return [self sharedDatabase:YES]; 18 | } 19 | 20 | + (sqlite3 *)sharedDatabase:(BOOL)createIfNotExists { 21 | static sqlite3 *db = NULL; 22 | static dispatch_once_t onceToken; 23 | dispatch_once(&onceToken, ^{ 24 | NSString *cachesPath = JBROOT_PATH_NSSTRING(@"/var/mobile/Library/Caches"); 25 | NSString *databasePath = [cachesPath stringByAppendingPathComponent:@"com.82flex.noredirect.db"]; 26 | if (!createIfNotExists && ![[NSFileManager defaultManager] fileExistsAtPath:databasePath]) { 27 | return; 28 | } 29 | if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) { 30 | char *error; 31 | if (sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, &error) != SQLITE_OK) { 32 | HBLogError(@"Failed to set WAL mode: %s", error); 33 | } 34 | if (sqlite3_exec(db, "PRAGMA synchronous=NORMAL;", NULL, NULL, &error) != SQLITE_OK) { 35 | HBLogError(@"Failed to set synchronous mode: %s", error); 36 | } 37 | if (sqlite3_exec(db, 38 | "CREATE TABLE IF NOT EXISTS records (id INTEGER PRIMARY KEY AUTOINCREMENT, declined " 39 | "INTEGER, source TEXT, target TEXT, created_at INTEGER);", 40 | NULL, NULL, &error) != SQLITE_OK) { 41 | HBLogError(@"Failed to create table: %s", error); 42 | } 43 | } else { 44 | HBLogError(@"Failed to open database: %s", sqlite3_errmsg(db)); 45 | } 46 | }); 47 | return db; 48 | } 49 | 50 | + (NSArray *)allRecords { 51 | NSMutableArray *records = [NSMutableArray array]; 52 | sqlite3 *db = [self sharedDatabase]; 53 | sqlite3_stmt *stmt; 54 | if (sqlite3_prepare_v2(db, "SELECT * FROM records ORDER BY id DESC;", -1, &stmt, NULL) == SQLITE_OK) { 55 | while (sqlite3_step(stmt) == SQLITE_ROW) { 56 | NoRedirectRecord *record = [[NoRedirectRecord alloc] init]; 57 | record->_declined = (BOOL)sqlite3_column_int(stmt, 1); 58 | const char *source = (const char *)sqlite3_column_text(stmt, 2); 59 | if (source) 60 | record->_source = [NSString stringWithUTF8String:source]; 61 | const char *target = (const char *)sqlite3_column_text(stmt, 3); 62 | if (target) 63 | record->_target = [NSString stringWithUTF8String:target]; 64 | record->_createdAt = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(stmt, 4)]; 65 | [records addObject:record]; 66 | } 67 | sqlite3_finalize(stmt); 68 | } 69 | return records; 70 | } 71 | 72 | + (void)insertRecord:(BOOL)declined source:(NSString *)sourceIdentifier target:(NSString *)targetIdentifier { 73 | sqlite3 *db = [self sharedDatabase]; 74 | sqlite3_stmt *stmt; 75 | if (sqlite3_prepare_v2(db, "INSERT INTO records (declined, source, target, created_at) VALUES (?, ?, ?, ?);", -1, 76 | &stmt, NULL) == SQLITE_OK) { 77 | sqlite3_bind_int(stmt, 1, declined); 78 | sqlite3_bind_text(stmt, 2, [sourceIdentifier UTF8String], -1, SQLITE_STATIC); 79 | sqlite3_bind_text(stmt, 3, [targetIdentifier UTF8String], -1, SQLITE_STATIC); 80 | sqlite3_bind_int(stmt, 4, (int)[[NSDate date] timeIntervalSince1970]); 81 | if (sqlite3_step(stmt) != SQLITE_DONE) { 82 | HBLogError(@"Failed to insert record: %s", sqlite3_errmsg(db)); 83 | } 84 | sqlite3_finalize(stmt); 85 | } else { 86 | HBLogError(@"Failed to prepare statement: %s", sqlite3_errmsg(db)); 87 | } 88 | } 89 | 90 | + (void)clearAllRecordsBeforeBoot { 91 | sqlite3 *db = [self sharedDatabase:NO]; 92 | if (!db) { 93 | return; 94 | } 95 | CFTimeInterval bootTime = CACurrentMediaTime(); 96 | sqlite3_stmt *stmt; 97 | if (sqlite3_prepare_v2(db, "DELETE FROM records WHERE created_at < ?;", -1, &stmt, NULL) == SQLITE_OK) { 98 | sqlite3_bind_int(stmt, 1, (int)bootTime); 99 | if (sqlite3_step(stmt) != SQLITE_DONE) { 100 | HBLogError(@"Failed to delete records: %s", sqlite3_errmsg(db)); 101 | } 102 | sqlite3_finalize(stmt); 103 | } else { 104 | HBLogError(@"Failed to prepare statement: %s", sqlite3_errmsg(db)); 105 | } 106 | } 107 | 108 | + (void)clearAllRecords { 109 | sqlite3 *db = [self sharedDatabase:NO]; 110 | if (!db) { 111 | return; 112 | } 113 | sqlite3_stmt *stmt; 114 | if (sqlite3_prepare_v2(db, "DELETE FROM records;", -1, &stmt, NULL) == SQLITE_OK) { 115 | if (sqlite3_step(stmt) != SQLITE_DONE) { 116 | HBLogError(@"Failed to delete records: %s", sqlite3_errmsg(db)); 117 | } 118 | sqlite3_finalize(stmt); 119 | } else { 120 | HBLogError(@"Failed to prepare statement: %s", sqlite3_errmsg(db)); 121 | } 122 | } 123 | 124 | @end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # No Redirect - 禁字诀 🈲 2 | 3 | A simple tweak that restricts application launching or being launched by other applications. 4 | 5 | 禁止指定 App “摇一摇”、“转一转” 等牛皮癣广告打开 App Store、Safari 或其他 App,并禁止其滥用 `SafariViewServices` 或 `StoreKitUIService`。 6 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.82flex.noredirect 2 | Name: No Redirect 3 | Version: 1.0 4 | Architecture: iphoneos-arm 5 | Description: Stop specified apps from redirecting to App Store, Safari or other apps. 6 | Maintainer: Lessica <82flex@gmail.com> 7 | Author: Lessica <82flex@gmail.com> 8 | Section: Tweaks 9 | Depends: firmware (>= 14.0), mobilesubstrate, preferenceloader, com.opa334.altlist, com.opa334.libsandy 10 | -------------------------------------------------------------------------------- /layout/Library/libSandy/NoRedirectSafari.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AllowedProcesses 6 | 7 | com.apple.SafariViewService 8 | 9 | Extensions 10 | 11 | 12 | type 13 | file 14 | extension_class 15 | com.apple.app-sandbox.read-write 16 | path 17 | /var/mobile/Library/Preferences/com.82flex.noredirectprefs.plist 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /layout/Library/libSandy/NoRedirectSafari_RootHide.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AllowedProcesses 6 | 7 | com.apple.SafariViewService 8 | 9 | Extensions 10 | 11 | 12 | type 13 | file 14 | extension_class 15 | com.apple.app-sandbox.read-write 16 | path 17 | /rootfs/var/mobile/Library/Preferences/com.82flex.noredirectprefs.plist 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /libroot/dyn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #if THEOS_PACKAGE_SCHEME_ROOTHIDE 12 | #include 13 | #endif 14 | 15 | static const char *(*dyn_get_root_prefix)(void) = NULL; 16 | static const char *(*dyn_get_jbroot_prefix)(void) = NULL; 17 | static const char *(*dyn_get_boot_uuid)(void) = NULL; 18 | static char *(*dyn_jbrootpath)(const char *path, char *resolvedPath) = NULL; 19 | static char *(*dyn_rootfspath)(const char *path, char *resolvedPath) = NULL; 20 | 21 | #if TARGET_OS_SIMULATOR 22 | 23 | static const char *libroot_get_root_prefix_fallback(void) 24 | { 25 | return IPHONE_SIMULATOR_ROOT; 26 | } 27 | 28 | static const char *libroot_get_jbroot_prefix_fallback(void) 29 | { 30 | return IPHONE_SIMULATOR_ROOT; 31 | } 32 | 33 | #else 34 | 35 | #if THEOS_PACKAGE_SCHEME_ROOTHIDE 36 | 37 | static const char *libroot_get_root_prefix_fallback(void) 38 | { 39 | char *resolved = (char *)rootfs("/"); 40 | int len = strlen(resolved); 41 | if (len > 1 && resolved[len - 1] == '/') { 42 | resolved[len - 1] = '\0'; 43 | } 44 | return resolved; 45 | } 46 | 47 | static const char *libroot_get_jbroot_prefix_fallback(void) 48 | { 49 | char *resolved = (char *)jbroot("/"); 50 | int len = strlen(resolved); 51 | if (len > 1 && resolved[len - 1] == '/') { 52 | resolved[len - 1] = '\0'; 53 | } 54 | return resolved; 55 | } 56 | 57 | #else 58 | 59 | #if IPHONEOS_ARM64 60 | 61 | static const char *libroot_get_root_prefix_fallback(void) 62 | { 63 | return ""; 64 | } 65 | 66 | static const char *libroot_get_jbroot_prefix_fallback(void) 67 | { 68 | return "/var/jb"; 69 | } 70 | 71 | #else 72 | 73 | static const char *libroot_get_root_prefix_fallback(void) 74 | { 75 | return ""; 76 | } 77 | 78 | static const char *libroot_get_jbroot_prefix_fallback(void) 79 | { 80 | if (access("/var/LIY", F_OK) == 0) { 81 | // Legacy support for XinaA15 1.x (For those two people still using it) 82 | // Technically this should be deprecated, but with the libroot solution it's not the hardest thing in the world to maintain 83 | // So I decided to leave it in 84 | return "/var/jb"; 85 | } 86 | else { 87 | return ""; 88 | } 89 | } 90 | 91 | #endif 92 | #endif 93 | #endif 94 | 95 | static const char *libroot_get_boot_uuid_fallback(void) 96 | { 97 | return "00000000-0000-0000-0000-000000000000"; 98 | } 99 | 100 | static char *libroot_rootfspath_fallback(const char *path, char *resolvedPath) 101 | { 102 | if (!path) return NULL; 103 | if (!resolvedPath) resolvedPath = malloc(PATH_MAX); 104 | 105 | const char *prefix = libroot_dyn_get_root_prefix(); 106 | const char *jbRootPrefix = libroot_dyn_get_jbroot_prefix(); 107 | size_t jbRootPrefixLen = strlen(jbRootPrefix); 108 | 109 | if (path[0] == '/') { 110 | // This function has two different purposes 111 | // If what we have is a subpath of the jailbreak root, strip the jailbreak root prefix 112 | // Else, add the rootfs prefix 113 | if (!strncmp(path, jbRootPrefix, jbRootPrefixLen)) { 114 | strlcpy(resolvedPath, &path[jbRootPrefixLen], PATH_MAX); 115 | } 116 | else { 117 | strlcpy(resolvedPath, prefix, PATH_MAX); 118 | strlcat(resolvedPath, path, PATH_MAX); 119 | } 120 | } 121 | else { 122 | // Don't modify relative paths 123 | strlcpy(resolvedPath, path, PATH_MAX); 124 | } 125 | 126 | return resolvedPath; 127 | } 128 | 129 | static char *libroot_jbrootpath_fallback(const char *path, char *resolvedPath) 130 | { 131 | if (!path) return NULL; 132 | if (!resolvedPath) resolvedPath = malloc(PATH_MAX); 133 | 134 | const char *prefix = libroot_dyn_get_jbroot_prefix(); 135 | bool skipRedirection = path[0] != '/'; // Don't redirect relative paths 136 | 137 | #ifndef IPHONEOS_ARM64 138 | // Special case 139 | // On XinaA15 v1: Don't redirect /var/mobile paths to /var/jb/var/mobile 140 | if (!skipRedirection) { 141 | if (access("/var/LIY", F_OK) == 0) { 142 | skipRedirection = strncmp(path, "/var/mobile", 11) == 0; 143 | } 144 | } 145 | #endif 146 | 147 | if (!skipRedirection) { 148 | strlcpy(resolvedPath, prefix, PATH_MAX); 149 | strlcat(resolvedPath, path, PATH_MAX); 150 | } 151 | else { 152 | strlcpy(resolvedPath, path, PATH_MAX); 153 | } 154 | 155 | return resolvedPath; 156 | } 157 | 158 | static void libroot_load(void) 159 | { 160 | static dispatch_once_t onceToken; 161 | dispatch_once (&onceToken, ^{ 162 | void *handle = dlopen("@rpath/libroot.dylib", RTLD_NOW); 163 | if (handle) { 164 | dyn_get_root_prefix = dlsym(handle, "libroot_get_root_prefix"); 165 | dyn_get_jbroot_prefix = dlsym(handle, "libroot_get_jbroot_prefix"); 166 | dyn_get_boot_uuid = dlsym(handle, "libroot_get_boot_uuid"); 167 | dyn_jbrootpath = dlsym(handle, "libroot_jbrootpath"); 168 | dyn_rootfspath = dlsym(handle, "libroot_rootfspath"); 169 | } 170 | if (!dyn_get_root_prefix) dyn_get_root_prefix = libroot_get_root_prefix_fallback; 171 | if (!dyn_get_jbroot_prefix) dyn_get_jbroot_prefix = libroot_get_jbroot_prefix_fallback; 172 | if (!dyn_get_boot_uuid) dyn_get_boot_uuid = libroot_get_boot_uuid_fallback; 173 | if (!dyn_jbrootpath) dyn_jbrootpath = libroot_jbrootpath_fallback; 174 | if (!dyn_rootfspath) dyn_rootfspath = libroot_rootfspath_fallback; 175 | }); 176 | } 177 | 178 | const char *libroot_dyn_get_root_prefix(void) 179 | { 180 | libroot_load(); 181 | return dyn_get_root_prefix(); 182 | } 183 | 184 | const char *libroot_dyn_get_jbroot_prefix(void) 185 | { 186 | libroot_load(); 187 | return dyn_get_jbroot_prefix(); 188 | } 189 | 190 | const char *libroot_dyn_get_boot_uuid(void) 191 | { 192 | libroot_load(); 193 | return dyn_get_boot_uuid(); 194 | } 195 | 196 | char *libroot_dyn_rootfspath(const char *path, char *resolvedPath) 197 | { 198 | libroot_load(); 199 | return dyn_rootfspath(path, resolvedPath); 200 | } 201 | 202 | char *libroot_dyn_jbrootpath(const char *path, char *resolvedPath) 203 | { 204 | libroot_load(); 205 | return dyn_jbrootpath(path, resolvedPath); 206 | } --------------------------------------------------------------------------------