Skip to content

Commit

Permalink
Add support for supplying 2FA code in non-interactive sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
majd committed Jun 27, 2021
1 parent 972f0b2 commit 5a4d2f5
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,24 @@ To download a copy of the ipa file, use the `download` command.
```
OVERVIEW: Download (encrypted) iOS app packages from the App Store.
USAGE: ipatool download --bundle-identifier <bundle-identifier> [--email <email>] [--password <password>] [--country <country>] [--device-family <device-family>] [--log-level <log-level>]
USAGE: ipatool download --bundle-identifier <bundle-identifier> [--email <email>] [--password <password>] [--auth-code <auth-code>] [--country <country>] [--device-family <device-family>] [--log-level <log-level>]
OPTIONS:
-b, --bundle-identifier <bundle-identifier>
The bundle identifier of the target iOS app.
-e, --email <email> The email address for the Apple ID.
-p, --password <password>
The password for the Apple ID.
-c, --country <country> The two-letter (ISO 3166-1 alpha-2) country code for
the iTunes Store. (default: US)
--auth-code <auth-code> The 2FA code for the Apple ID.
-c, --country <country> The two-letter (ISO 3166-1 alpha-2) country code for the iTunes Store. (default: US)
-d, --device-family <device-family>
The device family to limit the search query to.
(default: iPhone)
The device family to limit the search query to. (default: iPhone)
--log-level <log-level> The log level. (default: info)
--version Show the version.
-h, --help Show help information.
```

**Note:** You can specify the Apple ID email address and username as arguments when using the tool or by setting them as environment variables (`IPATOOL_EMAIL` and `IPATOOL_PASSWORD`). If you do not specify this information using either of those methods, the tool will prompt for user input in an interactive session.
**Note:** You can specify the Apple ID email address and username as arguments when using the tool or by setting them as environment variables (`IPATOOL_EMAIL` and `IPATOOL_PASSWORD`). If you do not specify this information using either of those methods, the tool will prompt for user input in an interactive session. Similarly, you can supply the 2FA code interactively or using the environment variable `IPATOOL_2FA_CODE`.

## Common Knowledge

Expand Down
22 changes: 18 additions & 4 deletions Source/Commands/Download.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct Download: ParsableCommand {
@Option(name: [.short, .customLong("password")], help: "The password for the Apple ID.")
private var passwordArgument: String?

@Option(name: [.customLong("auth-code")], help: "The 2FA code for the Apple ID.")
private var authCodeArgument: String?

@Option(name: [.short, .long], help: "The two-letter (ISO 3166-1 alpha-2) country code for the iTunes Store.")
private var country: String = "US"

Expand Down Expand Up @@ -84,7 +87,20 @@ extension Download {
_exit(1)
}
}


mutating func authCode() -> String {
if let authCode = authCodeArgument {
return authCode
} else if let authCode = ProcessInfo.processInfo.environment["IPATOOL_2FA_CODE"] {
return authCode
} else if let authCode = String(validatingUTF8: UnsafePointer<CChar>(getpass(logger.compile("Enter 2FA code: ", level: .warning)))) {
return authCode
} else {
logger.log("A 2FA auth-code is required.", level: .error)
_exit(1)
}
}

mutating func authenticate(email: String, password: String) -> StoreResponse.Account {
logger.log("Creating HTTP client...", level: .debug)
let httpClient = HTTPClient(urlSession: URLSession.shared)
Expand All @@ -98,10 +114,8 @@ extension Download {
} catch {
switch error {
case StoreResponse.Error.codeRequired:
let code = String(validatingUTF8: UnsafePointer<CChar>(getpass(logger.compile("Enter 2FA code: ", level: .warning))))

do {
return try storeClient.authenticate(email: email, password: password, code: code)
return try storeClient.authenticate(email: email, password: password, code: authCode())
} catch {
logger.log("\(error)", level: .debug)

Expand Down

0 comments on commit 5a4d2f5

Please sign in to comment.