Skip to content

Commit

Permalink
Add simple success and failure tests for 2FA login
Browse files Browse the repository at this point in the history
  • Loading branch information
interstateone committed Oct 14, 2020
1 parent f226ee1 commit 48516cc
Show file tree
Hide file tree
Showing 12 changed files with 447 additions and 3 deletions.
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
"version": "1.0.1"
}
},
{
"package": "OHHTTPStubs",
"repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs",
"state": {
"branch": null,
"revision": "e92b5a5746ef16add2a1424f1fc19529d9a75cde",
"version": "9.0.0"
}
},
{
"package": "Path.swift",
"repositoryURL": "https://github.com/mxcl/Path.swift.git",
Expand Down
8 changes: 6 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ let package = Package(
.package(name: "PMKFoundation", url: "https://github.com/PromiseKit/Foundation.git", .upToNextMinor(from: "3.3.1")),
.package(url: "https://github.com/scinfu/SwiftSoup.git", .upToNextMinor(from: "2.0.0")),
.package(url: "https://github.com/mxcl/LegibleError.git", .upToNextMinor(from: "1.0.1")),
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", .upToNextMinor(from: "3.2.0"))
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", .upToNextMinor(from: "3.2.0")),
.package(url: "https://github.com/AliSoftware/OHHTTPStubs", .upToNextMinor(from: "9.0.0")),
],
targets: [
.target(
Expand Down Expand Up @@ -47,6 +48,9 @@ let package = Package(
]),
.testTarget(
name: "AppleAPITests",
dependencies: ["AppleAPI"]),
dependencies: ["AppleAPI", .product(name: "OHHTTPStubsSwift", package: "OHHTTPStubs")],
resources: [
.copy("Fixtures"),
]),
]
)
2 changes: 1 addition & 1 deletion Sources/AppleAPI/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class Client {

public init() {}

public enum Error: Swift.Error, LocalizedError {
public enum Error: Swift.Error, LocalizedError, Equatable {
case invalidSession
case invalidUsernameOrPassword(username: String)
case unexpectedSignInResponse(statusCode: Int, message: String?)
Expand Down
89 changes: 89 additions & 0 deletions Tests/AppleAPITests/AppleAPITests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import XCTest
import OHHTTPStubs
import OHHTTPStubsSwift
import PromiseKit
import PMKFoundation
@testable import AppleAPI
Expand All @@ -12,4 +14,91 @@ final class AppleAPITests: XCTestCase {

override func setUp() {
}

override func tearDown() {
HTTPStubs.removeAllStubs()
super.tearDown()
}

func test_Login_2FA_Succeeds() {
stub(condition: isAbsoluteURLString(URL.itcServiceKey.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "ITCServiceKey", ofType: "json", inDirectory: "Fixtures/Login_2FA_Succeeds")!,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.signIn.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "SignIn", ofType: "json", inDirectory: "Fixtures/Login_2FA_Succeeds")!,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.authOptions.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "AuthOptions", ofType: "json", inDirectory: "Fixtures/Login_2FA_Succeeds")!,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.submitSecurityCode.absoluteString)) { _ in
HTTPStubsResponse(data: Data(), statusCode: 204, headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.trust.absoluteString)) { _ in
HTTPStubsResponse(data: Data(), statusCode: 204, headers: nil)
}
stub(condition: isAbsoluteURLString(URL.olympusSession.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "OlympusSession", ofType: "json", inDirectory: "Fixtures/Login_2FA_Succeeds")!,
headers: ["Content-Type": "application/json"])
}

let expectation = self.expectation(description: "promise fulfills")

let client = Client()
client.login(accountName: "[email protected]", password: "ABC123")
.tap { result in
guard case .fulfilled = result else {
XCTFail("login rejected")
return
}
expectation.fulfill()
}
.cauterize()

wait(for: [expectation], timeout: 1.0)
}

func test_Login_2FA_IncorrectPassword() {
stub(condition: isAbsoluteURLString(URL.itcServiceKey.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "ITCServiceKey", ofType: "json", inDirectory: "Fixtures/Login_2FA_IncorrectPassword")!,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.signIn.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "SignIn", ofType: "json", inDirectory: "Fixtures/Login_2FA_IncorrectPassword")!,
status: 401,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.authOptions.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "AuthOptions", ofType: "json", inDirectory: "Fixtures/Login_2FA_IncorrectPassword")!,
headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.submitSecurityCode.absoluteString)) { _ in
HTTPStubsResponse(data: Data(), statusCode: 204, headers: ["Content-Type": "application/json"])
}
stub(condition: isAbsoluteURLString(URL.trust.absoluteString)) { _ in
HTTPStubsResponse(data: Data(), statusCode: 204, headers: nil)
}
stub(condition: isAbsoluteURLString(URL.olympusSession.absoluteString)) { _ in
fixture(filePath: Bundle.module.path(forResource: "OlympusSession", ofType: "json", inDirectory: "Fixtures/Login_2FA_IncorrectPassword")!,
headers: ["Content-Type": "application/json"])
}

let expectation = self.expectation(description: "promise rejects")

let client = Client()
client.login(accountName: "[email protected]", password: "ABC123")
.tap { result in
guard case .rejected(let error as AppleAPI.Client.Error) = result else {
XCTFail("login fulfilled, but should have rejected with .invalidUsernameOrPassword error")
return
}
XCTAssertEqual(error, AppleAPI.Client.Error.invalidUsernameOrPassword(username: "[email protected]"))
expectation.fulfill()
}
.cauterize()

wait(for: [expectation], timeout: 1.0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"trustedPhoneNumbers" : [ {
"obfuscatedNumber" : "(•••) •••-••00",
"pushMode" : "sms",
"numberWithDialCode" : "+1 (•••) •••-••00",
"id" : 1
} ],
"securityCode" : {
"length" : 6,
"tooManyCodesSent" : false,
"tooManyCodesValidated" : false,
"securityCodeLocked" : false,
"securityCodeCooldown" : false
},
"authenticationType" : "hsa2",
"recoveryUrl" : "https://iforgot.apple.com/phone/add?prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"cantUsePhoneNumberUrl" : "https://iforgot.apple.com/iforgot/phone/add?context=cantuse&prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"recoveryWebUrl" : "https://iforgot.apple.com/password/verify/appleid?prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"repairPhoneNumberUrl" : "https://gsa.apple.com/appleid/account/manage/repair/verify/phone",
"repairPhoneNumberWebUrl" : "https://appleid.apple.com/widget/account/repair?#!repair",
"aboutTwoFactorAuthenticationUrl" : "https://support.apple.com/kb/HT204921",
"autoVerified" : false,
"showAutoVerificationUI" : false,
"managedAccount" : false,
"trustedPhoneNumber" : {
"obfuscatedNumber" : "(•••) •••-••00",
"pushMode" : "sms",
"numberWithDialCode" : "+1 (•••) •••-••00",
"id" : 1
},
"hsa2Account" : true,
"restrictedAccount" : false,
"supportsRecovery" : true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"authServiceUrl" : "https://idmsa.apple.com/appleauth",
"authServiceKey" : "NNNNN"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
"user" : {
"fullName" : "Test User",
"firstName" : "Test",
"lastName" : "User",
"emailAddress" : "[email protected]",
"prsId" : "000000000"
},
"provider" : {
"providerId" : 00000,
"name" : "Test User",
"contentTypes" : [ "SOFTWARE" ],
"subType" : "INDIVIDUAL",
"pla" : [ {
"id" : "1BC01216-52D4-43DC-8555-195F4454C348",
"version" : "5014",
"types" : [ "contractContentTypeDisplay.iOSFreeApps", "contractContentTypeDisplay.MacOSXFreeApplications" ],
"contractCountryOfOrigins" : [ "CAN" ]
} ]
},
"theme" : "APPSTORE_CONNECT",
"availableProviders" : [ {
"providerId" : 000000,
"name" : "Test User",
"contentTypes" : [ "SOFTWARE" ],
"subType" : "INDIVIDUAL"
} ],
"backingType" : "ITC",
"backingTypes" : [ "ITC" ],
"roles" : [ "ADMIN", "LEGAL" ],
"unverifiedRoles" : [ ],
"featureFlags" : [ "showWwdrUserRoles", "adpRad", "apiKeys" ],
"agreeToTerms" : true,
"termsSignatures" : [ "ASC", "RAD" ],
"modules" : [ {
"key" : "Apps",
"name" : "ITC.HomePage.Apps.IconText",
"localizedName" : "My Apps",
"url" : "https://appstoreconnect.apple.com/apps",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "AppAnalytics",
"name" : "ITC.HomePage.AppAnalytics.IconText",
"localizedName" : "App Analytics",
"url" : "https://analytics.itunes.apple.com/",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "SalesTrends",
"name" : "ITC.HomePage.SalesTrends.IconText",
"localizedName" : "Sales and Trends",
"url" : "https://appstoreconnect.apple.com/trends",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "FinancialReports",
"name" : "ITC.HomePage.FinancialReports.IconText",
"localizedName" : "Payments and Financial Reports",
"url" : "https://appstoreconnect.apple.com/itc/payments_and_financial_reports",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "Account",
"name" : "ITC.HomePage.Account.IconText",
"localizedName" : "Users and Access",
"url" : "https://appstoreconnect.apple.com/access/users",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "ContractsTaxBanking",
"name" : "ITC.HomePage.ContractsTaxBanking.IconText",
"localizedName" : "Agreements, Tax, and Banking",
"url" : "https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/da/jumpTo?page=contracts",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
}, {
"key" : "Resources",
"name" : "ITC.HomePage.Resources.IconText",
"localizedName" : "Resources and Help",
"url" : "https://developer.apple.com/app-store-connect/",
"iconUrl" : "https://appstoreconnect.apple.com/static/img/ico_homepage/themed/apps/[email protected]",
"down" : false,
"visible" : true,
"hasNotifications" : false
} ],
"helpLinks" : [ {
"key" : "AllAsc",
"url" : "https://help.apple.com/app-store-connect/",
"localizedText" : "App Store Connect Resources"
}, {
"key" : "Xcode",
"url" : "https://help.apple.com/xcode/mac/current/",
"localizedText" : "Xcode Help"
}, {
"key" : "SupportContact",
"url" : "https://developer.apple.com/support/",
"localizedText" : "Support and Contact"
} ],
"userProfile" : [ {
"key" : "signIn",
"url" : "https://appstoreconnect.apple.com/login",
"localizedText" : "Sign In"
}, {
"key" : "personalDetails",
"url" : "https://appstoreconnect.apple.com/access/users/07E3E586-44B1-48D3-BF8D-430F754F1BAA/settings",
"localizedText" : "Edit Profile"
}, {
"key" : "signOut",
"url" : "https://appstoreconnect.apple.com/logout",
"localizedText" : "Sign Out"
} ],
"pccDto" : null,
"publicUserId" : "07E3E586-44B1-48D3-BF8D-430F754F1BAA",
"ofacState" : null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"serviceErrors" : [ {
"code" : "-20101",
"message" : "Your Apple ID or password was incorrect.",
"suppressDismissal" : false
} ]
}
34 changes: 34 additions & 0 deletions Tests/AppleAPITests/Fixtures/Login_2FA_Succeeds/AuthOptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"trustedPhoneNumbers" : [ {
"obfuscatedNumber" : "(•••) •••-••00",
"pushMode" : "sms",
"numberWithDialCode" : "+1 (•••) •••-••00",
"id" : 1
} ],
"securityCode" : {
"length" : 6,
"tooManyCodesSent" : false,
"tooManyCodesValidated" : false,
"securityCodeLocked" : false,
"securityCodeCooldown" : false
},
"authenticationType" : "hsa2",
"recoveryUrl" : "https://iforgot.apple.com/phone/add?prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"cantUsePhoneNumberUrl" : "https://iforgot.apple.com/iforgot/phone/add?context=cantuse&prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"recoveryWebUrl" : "https://iforgot.apple.com/password/verify/appleid?prs_account_nm=test%40example.com&autoSubmitAccount=true&appId=142",
"repairPhoneNumberUrl" : "https://gsa.apple.com/appleid/account/manage/repair/verify/phone",
"repairPhoneNumberWebUrl" : "https://appleid.apple.com/widget/account/repair?#!repair",
"aboutTwoFactorAuthenticationUrl" : "https://support.apple.com/kb/HT204921",
"autoVerified" : false,
"showAutoVerificationUI" : false,
"managedAccount" : false,
"trustedPhoneNumber" : {
"obfuscatedNumber" : "(•••) •••-••00",
"pushMode" : "sms",
"numberWithDialCode" : "+1 (•••) •••-••00",
"id" : 1
},
"hsa2Account" : true,
"restrictedAccount" : false,
"supportsRecovery" : true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"authServiceUrl" : "https://idmsa.apple.com/appleauth",
"authServiceKey" : "NNNNN"
}
Loading

0 comments on commit 48516cc

Please sign in to comment.