Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AltStore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
B3C395F7284F362400DA9E2F /* AppCenterAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F6284F362400DA9E2F /* AppCenterAnalytics */; };
B3C395F9284F362400DA9E2F /* AppCenterCrashes in Frameworks */ = {isa = PBXBuildFile; productRef = B3C395F8284F362400DA9E2F /* AppCenterCrashes */; };
B3EE16B62925E27D00B3B1F5 /* AnisetteManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */; };
B5847002294F7811002A854E /* AnisetteServerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5847001294F7811002A854E /* AnisetteServerViewController.swift */; };
BF02419622F2199300129732 /* RefreshAttemptsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */; };
BF08858322DE795100DE9F1E /* MyAppsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858222DE795100DE9F1E /* MyAppsViewController.swift */; };
BF08858522DE7EC800DE9F1E /* UpdateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */; };
Expand Down Expand Up @@ -540,6 +541,7 @@
B3C3960E284F4F9100DA9E2F /* AltStoreCore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltStoreCore.xcconfig; sourceTree = "<group>"; };
B3C3960F284F53E900DA9E2F /* AltBackup.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AltBackup.xcconfig; sourceTree = "<group>"; };
B3EE16B52925E27D00B3B1F5 /* AnisetteManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnisetteManager.swift; sourceTree = "<group>"; };
B5847001294F7811002A854E /* AnisetteServerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnisetteServerViewController.swift; sourceTree = "<group>"; };
BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshAttemptsViewController.swift; sourceTree = "<group>"; };
BF08858222DE795100DE9F1E /* MyAppsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsViewController.swift; sourceTree = "<group>"; };
BF08858422DE7EC800DE9F1E /* UpdateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCollectionViewCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1651,6 +1653,7 @@
BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */,
BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */,
BFF0B68D23219520007A79E1 /* PatreonViewController.swift */,
B5847001294F7811002A854E /* AnisetteServerViewController.swift */,
BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */,
BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */,
BFF0B695232242D3007A79E1 /* LicensesViewController.swift */,
Expand Down Expand Up @@ -2460,6 +2463,7 @@
BF41B806233423AE00C593A3 /* TabBarController.swift in Sources */,
BFE00A202503097F00EB4D0C /* INInteraction+AltStore.swift in Sources */,
BFDB6A0B22AAEDB7007EA6D6 /* Operation.swift in Sources */,
B5847002294F7811002A854E /* AnisetteServerViewController.swift in Sources */,
BF770E6722BD57C4002A40FE /* BackgroundTaskManager.swift in Sources */,
BF44EEFC246B4550002A52F2 /* RemoveAppOperation.swift in Sources */,
BF3D64B022E8D4B800E9056B /* AppContentViewControllerCells.swift in Sources */,
Expand Down
20 changes: 9 additions & 11 deletions AltStore/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ALTAnisetteURL</key>
<string>http://ani.sidestore.io/</string>
<key>ALTAppGroups</key>
<array>
<string>group.$(APP_GROUP_IDENTIFIER)</string>
<string>group.com.SideStore.SideStore</string>
</array>
<key>ALTDeviceID</key>
<string>00008101-000129D63698001E</string>
<key>ALTServerID</key>
<string>1F7D5B55-79CE-4546-A029-D4DDC4AF3B6D</string>
<key>ALTPairingFile</key>
<string>&lt;insert pairing file here&gt;</string>
<key>ALTAnisetteURL</key>
<string>https://sideloadly.io/anisette/irGb3Quww8zrhgqnzmrx</string>
<key>ALTServerID</key>
<string>1F7D5B55-79CE-4546-A029-D4DDC4AF3B6D</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDocumentTypes</key>
Expand Down Expand Up @@ -44,8 +44,6 @@
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleURLTypes</key>
Expand Down Expand Up @@ -93,6 +91,11 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSBonjourServices</key>
<array>
<string>_altserver._tcp</string>
Expand Down Expand Up @@ -133,11 +136,6 @@
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
119 changes: 105 additions & 14 deletions AltStore/Operations/FetchAnisetteDataOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,121 @@ final class FetchAnisetteDataOperation: ResultOperation<ALTAnisetteData>
return
}

let url = AnisetteManager.currentURL
DLOG("Anisette URL: %@", url.absoluteString)
do {
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("adi.pb")
print("ADI Path: \(documentsPath)")

if !fm.fileExists(atPath: documentsPath.absoluteString) {
self.fetchADIFile(session: URLSession.shared)
}

let url = AnisetteManager.currentURL
DLOG("Anisette URL: %@", url.absoluteString)

let session = URLSession.shared

var postData = Data()

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=ebd46b494f8b3f6926db4f30a3f371ae", forHTTPHeaderField: "Content-Type")

// Get the raw data from the file.
let rawData: Data = try Data(contentsOf: documentsPath)
DLOG("adi.pb exists")
postData.append("--ebd46b494f8b3f6926db4f30a3f371ae\r\n".data(using: .utf8)!)
postData.append("Content-Disposition: form-data; name=\"adi.pb\"; filename=\"adi.pb\"\r\n\r\n".data(using: .utf8)!)
for byte in rawData {
postData.append(byte)
}
postData.append("\r\n--ebd46b494f8b3f6926db4f30a3f371ae\r\n".data(using: .utf8)!)
let task = session.uploadTask(with: request, from: postData, completionHandler: { data, response, error in
if let data = data {
do {
print(data)
// make sure this JSON is in the format we expect
// convert data to json
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: String] {
// try to read out a dictionary
//for some reason serial number isn't needed but it doesn't work unless it has a value
let formattedJSON: [String: String] = ["machineID": json["X-Apple-I-MD-M"]!, "oneTimePassword": json["X-Apple-I-MD"]!, "localUserID": json["X-Apple-I-MD-LU"]!, "routingInfo": json["X-Apple-I-MD-RINFO"]!, "deviceUniqueIdentifier": json["X-Mme-Device-Id"]!, "deviceDescription": json["X-MMe-Client-Info"]!, "date": json["X-Apple-I-Client-Time"]!, "locale": json["X-Apple-Locale"]!, "timeZone": json["X-Apple-I-TimeZone"]!, "deviceSerialNumber": "1"]

if let anisette = ALTAnisetteData(json: formattedJSON) {
self.finish(.success(anisette))
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
self.finish(.failure(error))
}
}
})
task.resume()
} catch let error as NSError {
self.fetchADIFile(session: URLSession.shared)
return self.finish(.failure(error))

}
}

func fetchADIFile(session: URLSession) {

let task = URLSession.shared.dataTask(with: url) { data, response, error in
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("adi.pb")

print("ADI URL: \(AnisetteManager.currentURL.appendingPathComponent("adi_file").absoluteString)")

let task = URLSession.shared.dataTask(with: AnisetteManager.currentURL.appendingPathComponent("adi_file")) { data, response, error in
guard let data = data, error == nil else { return }

do {
// make sure this JSON is in the format we expect
// convert data to json
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: String] {
// try to read out a dictionary
//for some reason serial number isn't needed but it doesn't work unless it has a value
let formattedJSON: [String: String] = ["machineID": json["X-Apple-I-MD-M"]!, "oneTimePassword": json["X-Apple-I-MD"]!, "localUserID": json["X-Apple-I-MD-LU"]!, "routingInfo": json["X-Apple-I-MD-RINFO"]!, "deviceUniqueIdentifier": json["X-Mme-Device-Id"]!, "deviceDescription": json["X-MMe-Client-Info"]!, "date": json["X-Apple-I-Client-Time"]!, "locale": json["X-Apple-Locale"]!, "timeZone": json["X-Apple-I-TimeZone"]!, "deviceSerialNumber": "1"]

if let anisette = ALTAnisetteData(json: formattedJSON) {
DLOG("Anisette used: %@", formattedJSON)
self.finish(.success(anisette))
DLOG("Found anisette data instead of adi.pb file, fallback initiated")

if let trustedURL = UserDefaults.shared.trustedServerURL {
print(trustedURL)
print(AnisetteManager.currentURLString)
if trustedURL == AnisetteManager.currentURLString {
return self.finish(.success(anisette))
}
}

let alert = UIAlertController(title: "WARNING!", message: "We've detected you are using an older anisette server, using this server has a higher likelihood of locking your account, do you still want to continue?", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertAction.Style.destructive, handler: {action in
DLOG("Using older anisette method")
UserDefaults.shared.trustedServerURL = AnisetteManager.currentURLString
return self.finish(.success(anisette))
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: {action in
DLOG("Cancelled the fallback operation")
return
}))

let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first

DispatchQueue.main.async {
if let presentingController = keyWindow?.rootViewController?.presentedViewController {
presentingController.present(alert, animated: true)
} else {
keyWindow?.rootViewController?.present(alert, animated: true)
}
}
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
self.finish(.failure(error))
} catch _ as NSError {
do {
try data.write(to: documentsPath)
DLOG("Wrote adi.pb file")
return
} catch let error as NSError {
DLOG("ADI Write Error: %@", error.domain)
return self.finish(.failure(error))
}

}

}

task.resume()
Expand Down
1 change: 1 addition & 0 deletions AltStore/Operations/InstallAppOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ private extension InstallAppOperation
}
catch
{
self.didCleanUp = false
print("Failed to remove temporary directory.", error)
}
}
Expand Down
21 changes: 21 additions & 0 deletions AltStore/Settings/AnisetteManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,29 @@

import Foundation

struct PublicAnisetteServer {
let label: String
let urlString: String
}

public struct AnisetteManager {

static var publicServers: [PublicAnisetteServer] {
// TODO: Pull these servers from somewhere, also let users edit list
return [
PublicAnisetteServer(label: "Jawshoedan", urlString: "https://anisette.jawshoeadan.me"),
PublicAnisetteServer(label: "Buh", urlString: "http://191.101.206.188:6969"),
PublicAnisetteServer(label: "Macley (US)", urlString: "http://us1.sternserv.tech"),
PublicAnisetteServer(label: "Macley (DE)", urlString: "http://de1.sternserv.tech"),
PublicAnisetteServer(label: "DrPudding", urlString: "https://sign.rheaa.xyz"),
PublicAnisetteServer(label: "jkcoxson (AltServer)", urlString: "http://jkcoxson.com:2095"),
PublicAnisetteServer(label: "jkcoxson (Provision)", urlString: "http://jkcoxson.com:2052"),
PublicAnisetteServer(label: "Sideloadly", urlString: "https://sideloadly.io/anisette/irGb3Quww8zrhgqnzmrx"),
PublicAnisetteServer(label: "Nythepegasus", urlString: "http://45.33.29.114"),
PublicAnisetteServer(label: "crystall1nedev", urlString: "https://anisette.crystall1ne.software/")
]
}

/// User defined URL from Settings/UserDefaults
static var userURL: String? {
var urlString: String?
Expand Down
71 changes: 71 additions & 0 deletions AltStore/Settings/AnisetteServerViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// AnisetteServerViewController.swift
// SideStore
//
// Created by Nicholas Yoder on 12/18/22.
// Copyright © 2022 SideStore. All rights reserved.
//

import UIKit

import AltStoreCore
import Roxas



class AnisetteServerViewController: UITableViewController
{
@IBOutlet var anisetteServers: UIButton!
override func viewDidLoad()
{
super.viewDidLoad()

// self.prepareServers()
}

override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
}

func prepareServers() -> UIMenu {
var menuItems: [UIAction] = []
for server in AnisetteManager.publicServers {
let action = UIAction(title: server.label, identifier: UIAction.Identifier(server.urlString), handler: { (_) in })
if action.title == "Sideloadly" {
action.attributes = .destructive
}
menuItems.append(action)
}
var anisetteMenu: UIMenu {
return UIMenu(title: "Anisette Servers", image: nil, identifier: nil, options: [], children: menuItems)
}

return anisetteMenu
}
}

extension AnisetteServerViewController
{
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
self.tableView.deselectRow(at: indexPath, animated: true)
if indexPath[1] == 0 {
// reset adi.pb
let toast = ToastView(text: "Deleted adi.pb file!", detailText: "You will need to verify your 2FA!")
toast.show(in: self)
let fm = FileManager.default
let documentsPath = fm.documentsDirectory.appendingPathComponent("adi.pb")
print("ADI Path: \(documentsPath)")

if fm.fileExists(atPath: documentsPath.path) {
do {
try fm.removeItem(at: documentsPath.absoluteURL)
print("DELETED ADI")
} catch let error as NSError {
print("REMOVE ERROR: \(error.domain)")
}
}
}
}
}
Loading