Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

🐛 Allow redownloads on macOS 12 Monterey #428

Merged
merged 5 commits into from
Nov 4, 2021
Merged
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
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ $ mas lucky twitter

> Please note that this command will not allow you to install (or even purchase) an app for the first time:
use the `purchase` command in that case.
> ⛔ The `purchase` command is not supported as of macOS 10.15 Catalina. Please see [Known Issues](#%EF%B8%8F-known-issues).

```bash
$ mas purchase 768053424
Expand Down Expand Up @@ -148,6 +149,8 @@ Xcode (8.0)

### 🚏📥 Sign-in

> ⛔ The `signin` command is not supported as of macOS 10.13 High Sierra. Please see [Known Issues](#%EF%B8%8F-known-issues).

To #to the Mac App Store for the first time run `mas signin`.

```bash
Expand All @@ -156,11 +159,8 @@ $ mas signin mas@example.com
Password:
```

> ⚠️ Due to breaking changes in the underlying API that mas uses to interact with the Mac App Store,
> the `signin` command has been temporarily disabled on macOS 10.13+ ⛔.
> For more information on this issue, see [#164](https://github.com/mas-cli/mas/issues/164).

If you experience issues signing in this way, you can ask to signin using a graphical dialog (provided by Mac App Store application):
If you experience issues signing in this way, you can ask to # using a graphical dialog
(provided by Mac App Store application):

```bash
$ mas signin --dialog mas@example.com
Expand All @@ -182,6 +182,22 @@ Use `mas signout` to sign out from the Mac App Store.
then your Mac App Store apps will be included in the Brewfile created. See the [homebrew-bundle]
docs for more details.

## ⚠️ Known Issues

Over time, Apple has changed the APIs used by `mas` to manage App Store apps, limiting its capabilities. Please #
or purchase apps using the App Store app instead. Subsequent redownloads can be performed with `mas install`.

- ⛔️ The `signin` command is not supported as of macOS 10.13 High Sierra. [#164](https://github.com/mas-cli/mas/issues/164)
- ⛔️ The `purchase` command is not supported as of macOS 10.15 Catalina. [#289](https://github.com/mas-cli/mas/issues/289)
- ⛔️ The `account` command is not supported as of macOS 12 Monterey. [#417](https://github.com/mas-cli/mas/issues/417)

The versions `mas` sees from the app bundles on your Mac don't always match the versions reported by the App Store for
the same app bundles. This leads to some confusion when the `outdated` and `upgrade` commands differ in behavior from
what is shown as outdated in the App Store app. Further confusing matters, there is often some delay due to CDN
propagatioon and caching between the time a new app version is released to the App Store, and the time it appears
available in the App Store app or via the `mas` command. These issues cause symptoms like
[#384](https://github.com/mas-cli/mas/issues/384) and [#387](https://github.com/mas-cli/mas/issues/387).

## 💥 When something doesn't work

If you see this error, it's probably because you haven't installed the app through the App Store yet.
Expand Down
18 changes: 13 additions & 5 deletions Sources/MasKit/AppStore/Downloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,20 @@ private func downloadWithRetries(
/// Only works for free apps. Defaults to false.
/// - Returns: A promise the completes when the download is complete.
private func download(_ appID: UInt64, purchase: Bool = false) -> Promise<Void> {
guard let account = ISStoreAccount.primaryAccount else {
return Promise(error: MASError.notSignedIn)
}
var storeAccount: ISStoreAccount?
if #available(macOS 12, *) {
// Monterey obscured the user's account information, but still allows
// redownloads without passing it to SSPurchase.
// https://github.com/mas-cli/mas/issues/417
} else {
guard let account = ISStoreAccount.primaryAccount else {
return Promise(error: MASError.notSignedIn)
}

guard let storeAccount = account as? ISStoreAccount else {
fatalError("Unable to cast StoreAccount to ISStoreAccount")
storeAccount = account as? ISStoreAccount
guard storeAccount != nil else {
fatalError("Unable to cast StoreAccount to ISStoreAccount")
}
}

return Promise<SSPurchase> { seal in
Expand Down
9 changes: 6 additions & 3 deletions Sources/MasKit/AppStore/SSPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ typealias SSPurchaseCompletion =
(_ purchase: SSPurchase?, _ completed: Bool, _ error: Error?, _ response: SSPurchaseResponse?) -> Void

extension SSPurchase {
convenience init(adamId: UInt64, account: ISStoreAccount, purchase: Bool = false) {
convenience init(adamId: UInt64, account: ISStoreAccount?, purchase: Bool = false) {
self.init()

var parameters: [String: Any] = [
Expand All @@ -40,8 +40,11 @@ extension SSPurchase {
.joined(separator: "&")

itemIdentifier = adamId
accountIdentifier = account.dsID
appleID = account.identifier

if let account = account {
accountIdentifier = account.dsID
appleID = account.identifier
}

// Not sure if this is needed, but lets use it here.
if purchase {
Expand Down
6 changes: 6 additions & 0 deletions Sources/MasKit/Commands/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ public struct AccountCommand: CommandProtocol {

/// Runs the command.
public func run(_: Options) -> Result<Void, MASError> {
if #available(macOS 12, *) {
// Account information is no longer available as of Monterey.
// https://github.com/mas-cli/mas/issues/417
return .failure(.notSupported)
}

if let account = ISStoreAccount.primaryAccount {
print(String(describing: account.identifier))
} else {
Expand Down
6 changes: 6 additions & 0 deletions Sources/MasKit/Commands/Purchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public struct PurchaseCommand: CommandProtocol {

/// Runs the command.
public func run(_ options: Options) -> Result<Void, MASError> {
if #available(macOS 10.15, *) {
// Purchases are no longer possible as of Catalina.
// https://github.com/mas-cli/mas/issues/289
return .failure(.notSupported)
}

// Try to download applications with given identifiers and collect results
let appIds = options.appIds.filter { appId in
if let product = appLibrary.installedApp(forId: appId) {
Expand Down
4 changes: 3 additions & 1 deletion Sources/MasKit/Commands/SignIn.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public struct SignInCommand: CommandProtocol {
/// Runs the command.
public func run(_ options: Options) -> Result<Void, MASError> {
if #available(macOS 10.13, *) {
return .failure(.signInDisabled)
// Signing in is no longer possible as of High Sierra.
// https://github.com/mas-cli/mas/issues/164
return .failure(.notSupported)
}

guard ISStoreAccount.primaryAccount == nil else {
Expand Down
12 changes: 6 additions & 6 deletions Sources/MasKit/Errors/MASError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
import Foundation

public enum MASError: Error, Equatable {
case notSupported

case notSignedIn
case signInDisabled
case signInFailed(error: NSError?)
case alreadySignedIn

Expand Down Expand Up @@ -38,12 +39,11 @@ extension MASError: CustomStringConvertible {
case .notSignedIn:
return "Not signed in"

case .signInDisabled:
case .notSupported:
return """
The 'signin' command has been disabled on this macOS version. \
Please #to the Mac App Store app manually.
For more info see: \
https://github.com/mas-cli/mas/issues/164
This command is not supported on this macOS version due to changes in macOS. \
For more information see: \
https://github.com/mas-cli/mas#known-issues
"""

case .signInFailed(let error):
Expand Down
9 changes: 0 additions & 9 deletions Sources/mas/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,10 @@
//

import Commandant
import Foundation
import MasKit

MasKit.initialize()

let monterey = OperatingSystemVersion(majorVersion: 12, minorVersion: 0, patchVersion: 0)
if ProcessInfo.processInfo.isOperatingSystemAtLeast(monterey) {
printWarning(
"mas is not yet functional on macOS Monterey (12) due to changes in macOS frameworks. "
+ "To track progress or to *contribute* to fixing this issue, please see: "
+ "https://github.com/mas-cli/mas/issues/417")
}

let registry = CommandRegistry<MASError>()
let helpCommand = HelpCommand(registry: registry)

Expand Down