mirror of
https://github.com/mas-cli/mas
synced 2024-11-22 11:33:13 +00:00
Migrate ISStoreAccount
from Grand Central Dispatch to PromiseKit.
Partial #562 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
This commit is contained in:
parent
aceb4c3ddb
commit
c01f7c541e
6 changed files with 72 additions and 66 deletions
|
@ -11,6 +11,7 @@
|
|||
--disable blankLinesAroundMark
|
||||
--disable consecutiveSpaces
|
||||
--disable hoistPatternLet
|
||||
--disable hoistTry
|
||||
--disable indent
|
||||
--disable trailingCommas
|
||||
|
||||
|
|
|
@ -7,85 +7,81 @@
|
|||
//
|
||||
|
||||
import CommerceKit
|
||||
import PromiseKit
|
||||
import StoreFoundation
|
||||
|
||||
extension ISStoreAccount: StoreAccount {
|
||||
static var primaryAccount: ISStoreAccount? {
|
||||
static var primaryAccount: Promise<ISStoreAccount> {
|
||||
if #available(macOS 10.13, *) {
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
|
||||
var account: ISStoreAccount?
|
||||
ISServiceProxy.genericShared().accountService.primaryAccount { storeAccount in
|
||||
account = storeAccount
|
||||
group.leave()
|
||||
}
|
||||
|
||||
_ = group.wait(timeout: .now() + 30)
|
||||
|
||||
return account
|
||||
return race(
|
||||
Promise<ISStoreAccount> { seal in
|
||||
ISServiceProxy.genericShared().accountService.primaryAccount { storeAccount in
|
||||
seal.fulfill(storeAccount)
|
||||
}
|
||||
},
|
||||
after(seconds: 30).then {
|
||||
Promise(error: MASError.notSignedIn)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return CKAccountStore.shared().primaryAccount
|
||||
return .value(CKAccountStore.shared().primaryAccount)
|
||||
}
|
||||
}
|
||||
|
||||
static func signIn(username: String, password: String, systemDialog: Bool = false) throws -> ISStoreAccount {
|
||||
static func signIn(username: String, password: String, systemDialog: Bool) -> Promise<ISStoreAccount> {
|
||||
if #available(macOS 10.13, *) {
|
||||
// Signing in is no longer possible as of High Sierra.
|
||||
// https://github.com/mas-cli/mas/issues/164
|
||||
throw MASError.notSupported
|
||||
return Promise(error: MASError.notSupported)
|
||||
} else {
|
||||
if let account = primaryAccount, account.isSignedIn {
|
||||
throw MASError.alreadySignedIn(asAccountId: account.identifier)
|
||||
}
|
||||
return
|
||||
primaryAccount
|
||||
.then { account -> Promise<ISStoreAccount> in
|
||||
if account.isSignedIn {
|
||||
return Promise(error: MASError.alreadySignedIn(asAccountId: account.identifier))
|
||||
}
|
||||
|
||||
let password =
|
||||
password.isEmpty && !systemDialog
|
||||
? String(validatingUTF8: getpass("Password: "))!
|
||||
: password
|
||||
let password =
|
||||
password.isEmpty && !systemDialog
|
||||
? String(validatingUTF8: getpass("Password: "))!
|
||||
: password
|
||||
|
||||
guard !password.isEmpty || systemDialog else {
|
||||
throw MASError.noPasswordProvided
|
||||
}
|
||||
guard !password.isEmpty || systemDialog else {
|
||||
return Promise(error: MASError.noPasswordProvided)
|
||||
}
|
||||
|
||||
let accountService = ISServiceProxy.genericShared().accountService
|
||||
accountService.setStoreClient(ISStoreClient(storeClientType: 0))
|
||||
let context = ISAuthenticationContext(accountID: 0)
|
||||
context.appleIDOverride = username
|
||||
|
||||
let context = ISAuthenticationContext(accountID: 0)
|
||||
context.appleIDOverride = username
|
||||
if !systemDialog {
|
||||
context.demoMode = true
|
||||
context.demoAccountName = username
|
||||
context.demoAccountPassword = password
|
||||
context.demoAutologinMode = true
|
||||
}
|
||||
let signInPromise =
|
||||
Promise<ISStoreAccount> { seal in
|
||||
let accountService = ISServiceProxy.genericShared().accountService
|
||||
accountService.setStoreClient(ISStoreClient(storeClientType: 0))
|
||||
accountService.signIn(with: context) { success, storeAccount, error in
|
||||
if success, let storeAccount {
|
||||
seal.fulfill(storeAccount)
|
||||
} else {
|
||||
seal.reject(MASError.signInFailed(error: error as NSError?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
if systemDialog {
|
||||
return signInPromise
|
||||
} else {
|
||||
context.demoMode = true
|
||||
context.demoAccountName = username
|
||||
context.demoAccountPassword = password
|
||||
context.demoAutologinMode = true
|
||||
|
||||
var storeAccount: ISStoreAccount?
|
||||
var maserror: MASError?
|
||||
// Only works on macOS Sierra and below
|
||||
accountService.signIn(with: context) { success, account, error in
|
||||
if success, let account {
|
||||
storeAccount = account
|
||||
} else {
|
||||
maserror = .signInFailed(error: error as NSError?)
|
||||
return race(
|
||||
signInPromise,
|
||||
after(seconds: 30).then {
|
||||
Promise(error: MASError.signInFailed(error: nil))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
group.leave()
|
||||
}
|
||||
|
||||
if systemDialog {
|
||||
group.wait()
|
||||
} else {
|
||||
_ = group.wait(timeout: .now() + 30)
|
||||
}
|
||||
|
||||
if let storeAccount {
|
||||
return storeAccount
|
||||
}
|
||||
|
||||
throw maserror ?? MASError.signInFailed(error: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ extension SSPurchase {
|
|||
// Monterey obscures the user's App Store account information, but allows
|
||||
// redownloads without passing the account to SSPurchase.
|
||||
// https://github.com/mas-cli/mas/issues/417
|
||||
if let storeAccount = ISStoreAccount.primaryAccount {
|
||||
if let storeAccount = try? ISStoreAccount.primaryAccount.wait() {
|
||||
accountIdentifier = storeAccount.dsID
|
||||
appleID = storeAccount.identifier
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ public struct AccountCommand: CommandProtocol {
|
|||
return .failure(.notSupported)
|
||||
}
|
||||
|
||||
if let account = ISStoreAccount.primaryAccount {
|
||||
print(account.identifier)
|
||||
} else {
|
||||
return .failure(.notSignedIn)
|
||||
do {
|
||||
print(try ISStoreAccount.primaryAccount.wait().identifier)
|
||||
return .success(())
|
||||
} catch {
|
||||
return .failure(error as? MASError ?? .failed(error: error as NSError))
|
||||
}
|
||||
return .success(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ public struct SignInCommand: CommandProtocol {
|
|||
password: options.password,
|
||||
systemDialog: options.dialog
|
||||
)
|
||||
.wait()
|
||||
return .success(())
|
||||
} catch {
|
||||
return .failure(error as? MASError ?? .signInFailed(error: error as NSError))
|
||||
|
|
|
@ -11,6 +11,8 @@ import Foundation
|
|||
public enum MASError: Error, Equatable {
|
||||
case notSupported
|
||||
|
||||
case failed(error: NSError?)
|
||||
|
||||
case notSignedIn
|
||||
case noPasswordProvided
|
||||
case signInFailed(error: NSError?)
|
||||
|
@ -46,6 +48,12 @@ extension MASError: CustomStringConvertible {
|
|||
For more information see: \
|
||||
https://github.com/mas-cli/mas#%EF%B8%8F-known-issues
|
||||
"""
|
||||
case .failed(let error):
|
||||
if let error {
|
||||
return "Failed: \(error.localizedDescription)"
|
||||
} else {
|
||||
return "Failed"
|
||||
}
|
||||
case .signInFailed(let error):
|
||||
if let error {
|
||||
return "Sign in failed: \(error.localizedDescription)"
|
||||
|
|
Loading…
Reference in a new issue