Signed-off-by: Joseph Mattello <mail@joemattiello.com>
This commit is contained in:
Joseph Mattello
2023-04-02 02:28:12 -04:00
parent 2c829895c9
commit c4c2d17ffc
126 changed files with 1639 additions and 124 deletions

View File

@@ -0,0 +1,150 @@
//
// AuthenticationViewController.swift
// AltStore
//
// Created by Riley Testut on 9/5/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
import AltSign
final class AuthenticationViewController: UIViewController {
var authenticationHandler: ((String, String, @escaping (Result<(ALTAccount, ALTAppleAPISession), Error>) -> Void) -> Void)?
var completionHandler: (((ALTAccount, ALTAppleAPISession, String)?) -> Void)?
private weak var toastView: ToastView?
@IBOutlet private var appleIDTextField: UITextField!
@IBOutlet private var passwordTextField: UITextField!
@IBOutlet private var signInButton: UIButton!
@IBOutlet private var appleIDBackgroundView: UIView!
@IBOutlet private var passwordBackgroundView: UIView!
@IBOutlet private var scrollView: UIScrollView!
@IBOutlet private var contentStackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
signInButton.activityIndicatorView.style = .medium
for view in [appleIDBackgroundView!, passwordBackgroundView!, signInButton!] {
view.clipsToBounds = true
view.layer.cornerRadius = 16
}
if UIScreen.main.isExtraCompactHeight {
contentStackView.spacing = 20
}
NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: appleIDTextField)
NotificationCenter.default.addObserver(self, selector: #selector(AuthenticationViewController.textFieldDidChangeText(_:)), name: UITextField.textDidChangeNotification, object: passwordTextField)
update()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
signInButton.isIndicatingActivity = false
toastView?.dismiss()
}
}
private extension AuthenticationViewController {
func update() {
if let _ = validate() {
signInButton.isEnabled = true
signInButton.alpha = 1.0
} else {
signInButton.isEnabled = false
signInButton.alpha = 0.6
}
}
func validate() -> (String, String)? {
guard
let emailAddress = appleIDTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !emailAddress.isEmpty,
let password = passwordTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !password.isEmpty
else { return nil }
return (emailAddress, password)
}
}
private extension AuthenticationViewController {
@IBAction func authenticate() {
guard let (emailAddress, password) = validate() else { return }
appleIDTextField.resignFirstResponder()
passwordTextField.resignFirstResponder()
signInButton.isIndicatingActivity = true
authenticationHandler?(emailAddress, password) { result in
switch result {
case .failure(ALTAppleAPIError.requiresTwoFactorAuthentication):
// Ignore
DispatchQueue.main.async {
self.signInButton.isIndicatingActivity = false
}
case let .failure(error as NSError):
DispatchQueue.main.async {
let error = error.withLocalizedFailure(NSLocalizedString("Failed to Log In", comment: ""))
let toastView = ToastView(error: error)
toastView.textLabel.textColor = .altPink
toastView.detailTextLabel.textColor = .altPink
toastView.show(in: self)
self.toastView = toastView
self.signInButton.isIndicatingActivity = false
}
case let .success((account, session)):
self.completionHandler?((account, session, password))
}
DispatchQueue.main.async {
self.scrollView.setContentOffset(CGPoint(x: 0, y: -self.view.safeAreaInsets.top), animated: true)
}
}
}
@IBAction func cancel(_: UIBarButtonItem) {
completionHandler?(nil)
}
}
extension AuthenticationViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
switch textField {
case appleIDTextField: passwordTextField.becomeFirstResponder()
case passwordTextField: authenticate()
default: break
}
update()
return false
}
func textFieldDidBeginEditing(_: UITextField) {
guard UIScreen.main.isExtraCompactHeight else { return }
// Position all the controls within visible frame.
var contentOffset = scrollView.contentOffset
contentOffset.y = 44
scrollView.setContentOffset(contentOffset, animated: true)
}
}
extension AuthenticationViewController {
@objc func textFieldDidChangeText(_: Notification) {
update()
}
}

View File

@@ -0,0 +1,46 @@
//
// InstructionsViewController.swift
// AltStore
//
// Created by Riley Testut on 9/6/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
final class InstructionsViewController: UIViewController {
var completionHandler: (() -> Void)?
var showsBottomButton: Bool = false
@IBOutlet private var contentStackView: UIStackView!
@IBOutlet private var dismissButton: UIButton!
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
if UIScreen.main.isExtraCompactHeight {
contentStackView.layoutMargins.top = 0
contentStackView.layoutMargins.bottom = contentStackView.layoutMargins.left
}
dismissButton.clipsToBounds = true
dismissButton.layer.cornerRadius = 16
if showsBottomButton {
navigationItem.hidesBackButton = true
} else {
dismissButton.isHidden = true
}
}
}
private extension InstructionsViewController {
@IBAction func dismiss() {
completionHandler?()
}
}

View File

@@ -0,0 +1,76 @@
//
// RefreshAltStoreViewController.swift
// AltStore
//
// Created by Riley Testut on 10/26/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
import AltSign
import SideStoreCore
import RoxasUIKit
final class RefreshAltStoreViewController: UIViewController {
var context: AuthenticatedOperationContext!
var completionHandler: ((Result<Void, Error>) -> Void)?
@IBOutlet private var placeholderView: RSTPlaceholderView!
override func viewDidLoad() {
super.viewDidLoad()
placeholderView.textLabel.isHidden = true
placeholderView.detailTextLabel.textAlignment = .left
placeholderView.detailTextLabel.textColor = UIColor.white.withAlphaComponent(0.6)
placeholderView.detailTextLabel.text = NSLocalizedString("SideStore was unable to use an existing signing certificate, so it had to create a new one. This will cause any apps installed with an existing certificate to expire — including SideStore.\n\nTo prevent SideStore from expiring early, please refresh the app now. SideStore will quit once refreshing is complete.", comment: "")
}
}
private extension RefreshAltStoreViewController {
@IBAction func refreshAltStore(_ sender: PillButton) {
guard let altStore = InstalledApp.fetchAltStore(in: DatabaseManager.shared.viewContext) else { return }
func refresh() {
sender.isIndicatingActivity = true
if let progress = AppManager.shared.installationProgress(for: altStore) {
// Cancel pending AltStore installation so we can start a new one.
progress.cancel()
}
// Install, _not_ refresh, to ensure we are installing with a non-revoked certificate.
let group = AppManager.shared.install(altStore, presentingViewController: self, context: context) { result in
switch result {
case .success: self.completionHandler?(.success(()))
case let .failure(error as NSError):
DispatchQueue.main.async {
sender.progress = nil
sender.isIndicatingActivity = false
let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh SideStore", comment: ""), message: error.localizedFailureReason ?? error.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { _ in
refresh()
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Refresh Later", comment: ""), style: .cancel, handler: { _ in
self.completionHandler?(.failure(error))
}))
self.present(alertController, animated: true, completion: nil)
}
}
}
sender.progress = group.progress
}
refresh()
}
@IBAction func cancel(_: UIButton) {
completionHandler?(.failure(OperationError.cancelled))
}
}

View File

@@ -0,0 +1,74 @@
//
// SelectTeamViewController.swift
// AltStore
//
// Created by Megarushing on 4/26/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import Intents
import IntentsUI
import MessageUI
import SafariServices
import UIKit
import OSLog
#if canImport(Logging)
import Logging
#endif
import AltSign
final class SelectTeamViewController: UITableViewController {
public var teams: [ALTTeam]?
public var completionHandler: ((Result<ALTTeam, Swift.Error>) -> Void)?
private var prototypeHeaderFooterView: SettingsHeaderFooterView!
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
override func numberOfSections(in _: UITableView) -> Int {
1
}
override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
teams?.count ?? 0
}
override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
precondition(completionHandler != nil)
precondition(teams != nil)
precondition(teams!.count <= indexPath.row)
guard let completionHandler = completionHandler else {
os_log("completionHandler was nil", type: .error)
return
}
guard let teams = teams, teams.count <= indexPath.row else {
os_log("teams nil or out of bounds", type: .error)
return
}
completionHandler(.success(teams[indexPath.row]))
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TeamCell", for: indexPath) as! InsetGroupTableViewCell
cell.textLabel?.text = teams?[indexPath.row].name
cell.detailTextLabel?.text = teams?[indexPath.row].type.localizedDescription
if indexPath.row == 0 {
cell.style = InsetGroupTableViewCell.Style.top
} else if indexPath.row == self.tableView(self.tableView, numberOfRowsInSection: indexPath.section) - 1 {
cell.style = InsetGroupTableViewCell.Style.bottom
} else {
cell.style = InsetGroupTableViewCell.Style.middle
}
return cell
}
override func tableView(_: UITableView, titleForHeaderInSection _: Int) -> String? {
"Teams"
}
}