mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
commit
3a8722c07d
9 changed files with 730 additions and 9 deletions
|
|
@ -22,11 +22,14 @@ XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md)
|
|||
- Just click a button to make a version active with `xcode-select`.
|
||||
- View release notes, OS compatibility, included SDKs and compilers from [Xcode Releases](https://xcodereleases.com).
|
||||
- Dark/Light Mode supported
|
||||
- Security Key Authentication supported
|
||||
|
||||
## Platforms/Runtimes
|
||||
|
||||
- Xcodes supports downloading the Apple runtimes via the app. Simply click on the Platform, and Xcodes will install automatically for you.
|
||||
|
||||
**Note: iOS 18+, tvOS 18+, watchOS 11+, visionOS 2+ requires that Xcode 16.1 Beta 3+ be installed and active.**
|
||||
|
||||
## Experiments
|
||||
|
||||
- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used.
|
||||
|
|
@ -160,7 +163,8 @@ popd
|
|||
# Attach the zip that was created in the Product directory to the release
|
||||
# Publish the release
|
||||
|
||||
# Update the [Homebrew Cask](https://github.com/RobotsAndPencils/homebrew-cask/blob/master/Casks/xcodes.rb).
|
||||
shasum -a 256 xcodes.zip
|
||||
# Update the [Homebrew Cask](https://github.com/XcodesOrg/homebrew-cask/blob/master/Casks/x/xcodes.rb).
|
||||
```
|
||||
</details>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
15F5B8902CCF09B900705E2F /* CryptoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15F5B88F2CCF09B900705E2F /* CryptoKit.framework */; };
|
||||
33027E342CA8C18800CB387C /* LibFido2Swift in Frameworks */ = {isa = PBXBuildFile; productRef = 334A932B2CA885A400A5E079 /* LibFido2Swift */; };
|
||||
3328073F2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3328073E2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift */; };
|
||||
332807412CA5EA820036F691 /* SignInSecurityKeyTouchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 332807402CA5EA820036F691 /* SignInSecurityKeyTouchView.swift */; };
|
||||
|
|
@ -122,6 +123,7 @@
|
|||
E84E4F522B323A5F003F3959 /* CornerRadiusModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84E4F512B323A5F003F3959 /* CornerRadiusModifier.swift */; };
|
||||
E84E4F542B333864003F3959 /* PlatformsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84E4F532B333864003F3959 /* PlatformsListView.swift */; };
|
||||
E84E4F572B335094003F3959 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = E84E4F562B335094003F3959 /* OrderedCollections */; };
|
||||
E862D43B2CC8B26F00BAA376 /* SRP in Frameworks */ = {isa = PBXBuildFile; productRef = E862D43A2CC8B26F00BAA376 /* SRP */; };
|
||||
E86671272B309D2F0048559A /* PlatformsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86671262B309D2F0048559A /* PlatformsView.swift */; };
|
||||
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87AB3C42939B65E00D72F43 /* Hardware.swift */; };
|
||||
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
|
||||
|
|
@ -195,6 +197,7 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
15F5B88F2CCF09B900705E2F /* CryptoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoKit.framework; path = System/Library/Frameworks/CryptoKit.framework; sourceTree = SDKROOT; };
|
||||
3328073E2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInSecurityKeyPinView.swift; sourceTree = "<group>"; };
|
||||
332807402CA5EA820036F691 /* SignInSecurityKeyTouchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInSecurityKeyTouchView.swift; sourceTree = "<group>"; };
|
||||
36741BFC291E4FDB00A85AAE /* DownloadPreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadPreferencePane.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -351,6 +354,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
15F5B8902CCF09B900705E2F /* CryptoKit.framework in Frameworks */,
|
||||
33027E342CA8C18800CB387C /* LibFido2Swift in Frameworks */,
|
||||
CABFA9E42592F08E00380FEE /* Version in Frameworks */,
|
||||
CABFA9FD2592F13300380FEE /* LegibleError in Frameworks */,
|
||||
|
|
@ -358,6 +362,7 @@
|
|||
CA9FF86D25951C6E00E47BAF /* XCModel in Frameworks */,
|
||||
CABFA9F82592F0F900380FEE /* KeychainAccess in Frameworks */,
|
||||
E83FDC442CBB649100679C6B /* Sparkle in Frameworks */,
|
||||
E862D43B2CC8B26F00BAA376 /* SRP in Frameworks */,
|
||||
CAA858CD25A3D8BC00ACF8C0 /* ErrorHandling in Frameworks */,
|
||||
E8C0EB1A291EF43E0081528A /* XcodesKit in Frameworks */,
|
||||
E8FD5727291EE4AC001E004C /* AsyncNetworkService in Frameworks */,
|
||||
|
|
@ -414,6 +419,7 @@
|
|||
CA538A12255A4F7C00E64DD7 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
15F5B88F2CCF09B900705E2F /* CryptoKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -723,6 +729,7 @@
|
|||
E84E4F562B335094003F3959 /* OrderedCollections */,
|
||||
E83FDC432CBB649100679C6B /* Sparkle */,
|
||||
334A932B2CA885A400A5E079 /* LibFido2Swift */,
|
||||
E862D43A2CC8B26F00BAA376 /* SRP */,
|
||||
);
|
||||
productName = XcodesMac;
|
||||
productReference = CAD2E79E2449574E00113D76 /* Xcodes.app */;
|
||||
|
|
@ -1646,6 +1653,10 @@
|
|||
package = E84E4F552B335094003F3959 /* XCRemoteSwiftPackageReference "swift-collections" */;
|
||||
productName = OrderedCollections;
|
||||
};
|
||||
E862D43A2CC8B26F00BAA376 /* SRP */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = SRP;
|
||||
};
|
||||
E8C0EB19291EF43E0081528A /* XcodesKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = XcodesKit;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@
|
|||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "big-num",
|
||||
"repositoryURL": "https://github.com/adam-fowler/big-num",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5c5511ad06aeb2b97d0868f7394e14a624bfb1c7",
|
||||
"version": "2.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CombineExpectations",
|
||||
"repositoryURL": "https://github.com/groue/CombineExpectations",
|
||||
|
|
@ -100,6 +109,24 @@
|
|||
"version": "1.0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-crypto",
|
||||
"repositoryURL": "https://github.com/apple/swift-crypto",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "ddb07e896a2a8af79512543b1c7eb9797f8898a5",
|
||||
"version": "1.1.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-srp",
|
||||
"repositoryURL": "https://github.com/xcodesOrg/swift-srp",
|
||||
"state": {
|
||||
"branch": "main",
|
||||
"revision": "543aa0122a0257b992f6c7d62d18a26e3dffb8fe",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftSoup",
|
||||
"repositoryURL": "https://github.com/scinfu/SwiftSoup",
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
// swift-tools-version:5.3
|
||||
// swift-tools-version:5.7
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "AppleAPI",
|
||||
platforms: [.macOS(.v10_15)],
|
||||
platforms: [.macOS(.v11)],
|
||||
products: [
|
||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||
.library(
|
||||
name: "AppleAPI",
|
||||
targets: ["AppleAPI"]),
|
||||
],
|
||||
dependencies: [],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/xcodesOrg/swift-srp", branch: "main")
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||
.target(
|
||||
name: "AppleAPI",
|
||||
dependencies: []),
|
||||
dependencies: [.product(name: "SRP", package: "swift-srp")]),
|
||||
.testTarget(
|
||||
name: "AppleAPITests",
|
||||
dependencies: ["AppleAPI"]),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import SRP
|
||||
import Crypto
|
||||
import CommonCrypto
|
||||
|
||||
|
||||
public class Client {
|
||||
private static let authTypes = ["sa", "hsa", "non-sa", "hsa2"]
|
||||
|
|
@ -8,9 +12,13 @@ public class Client {
|
|||
|
||||
// MARK: - Login
|
||||
|
||||
public func login(accountName: String, password: String) -> AnyPublisher<AuthenticationState, Swift.Error> {
|
||||
public func srpLogin(accountName: String, password: String) -> AnyPublisher<AuthenticationState, Swift.Error> {
|
||||
var serviceKey: String!
|
||||
|
||||
let client = SRPClient(configuration: SRPConfiguration<SHA256>(.N2048))
|
||||
let clientKeys = client.generateKeys()
|
||||
let a = clientKeys.public
|
||||
|
||||
return Current.network.dataTask(with: URLRequest.itcServiceKey)
|
||||
.map(\.data)
|
||||
.decode(type: ServiceKeyResponse.self, decoder: JSONDecoder())
|
||||
|
|
@ -24,11 +32,45 @@ public class Client {
|
|||
.map { return (serviceKey, $0)}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
.flatMap { (serviceKey, hashcash) -> AnyPublisher<URLSession.DataTaskPublisher.Output, Swift.Error> in
|
||||
.flatMap { (serviceKey, hashcash) -> AnyPublisher<(String, String, ServerSRPInitResponse), Swift.Error> in
|
||||
|
||||
return Current.network.dataTask(with: URLRequest.signIn(serviceKey: serviceKey, accountName: accountName, password: password, hashcash: hashcash))
|
||||
return Current.network.dataTask(with: URLRequest.SRPInit(serviceKey: serviceKey, a: Data(a.bytes).base64EncodedString(), accountName: accountName))
|
||||
.map(\.data)
|
||||
.decode(type: ServerSRPInitResponse.self, decoder: JSONDecoder())
|
||||
.map { return (serviceKey, hashcash, $0) }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
.flatMap { (serviceKey, hashcash, srpInit) -> AnyPublisher<URLSession.DataTaskPublisher.Output, Swift.Error> in
|
||||
guard let decodedB = Data(base64Encoded: srpInit.b) else {
|
||||
return Fail(error: AuthenticationError.srpInvalidPublicKey)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
guard let decodedSalt = Data(base64Encoded: srpInit.salt) else {
|
||||
return Fail(error: AuthenticationError.srpInvalidPublicKey)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
let iterations = srpInit.iteration
|
||||
|
||||
do {
|
||||
guard let encryptedPassword = self.pbkdf2(password: password, saltData: decodedSalt, keyByteCount: 32, prf: CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), rounds: iterations) else {
|
||||
return Fail(error: AuthenticationError.srpInvalidPublicKey)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
let sharedSecret = try client.calculateSharedSecret(password: encryptedPassword, salt: [UInt8](decodedSalt), clientKeys: clientKeys, serverPublicKey: .init([UInt8](decodedB)))
|
||||
|
||||
let m1 = client.calculateClientProof(username: accountName, salt: [UInt8](decodedSalt), clientPublicKey: a, serverPublicKey: .init([UInt8](decodedB)), sharedSecret: .init(sharedSecret.bytes))
|
||||
let m2 = client.calculateServerProof(clientPublicKey: a, clientProof: m1, sharedSecret: .init([UInt8](sharedSecret.bytes)))
|
||||
|
||||
return Current.network.dataTask(with: URLRequest.SRPComplete(serviceKey: serviceKey, hashcash: hashcash, accountName: accountName, c: srpInit.c, m1: Data(m1).base64EncodedString(), m2: Data(m2).base64EncodedString()))
|
||||
.mapError { $0 as Swift.Error }
|
||||
.eraseToAnyPublisher()
|
||||
} catch {
|
||||
return Fail(error: AuthenticationError.srpInvalidPublicKey)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
.flatMap { result -> AnyPublisher<AuthenticationState, Swift.Error> in
|
||||
let (data, response) = result
|
||||
|
|
@ -257,6 +299,44 @@ public class Client {
|
|||
.mapError { $0 as Error }
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func sha256(data : Data) -> Data {
|
||||
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
data.withUnsafeBytes {
|
||||
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
|
||||
}
|
||||
return Data(hash)
|
||||
}
|
||||
|
||||
private func pbkdf2(password: String, saltData: Data, keyByteCount: Int, prf: CCPseudoRandomAlgorithm, rounds: Int) -> Data? {
|
||||
guard let passwordData = password.data(using: .utf8) else { return nil }
|
||||
let hashedPasswordData = sha256(data: passwordData)
|
||||
|
||||
var derivedKeyData = Data(repeating: 0, count: keyByteCount)
|
||||
let derivedCount = derivedKeyData.count
|
||||
let derivationStatus: Int32 = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
|
||||
let keyBuffer: UnsafeMutablePointer<UInt8> =
|
||||
derivedKeyBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
|
||||
return saltData.withUnsafeBytes { saltBytes -> Int32 in
|
||||
let saltBuffer: UnsafePointer<UInt8> = saltBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
|
||||
return hashedPasswordData.withUnsafeBytes { hashedPasswordBytes -> Int32 in
|
||||
let passwordBuffer: UnsafePointer<UInt8> = hashedPasswordBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
|
||||
return CCKeyDerivationPBKDF(
|
||||
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||
passwordBuffer,
|
||||
hashedPasswordData.count,
|
||||
saltBuffer,
|
||||
saltData.count,
|
||||
prf,
|
||||
UInt32(rounds),
|
||||
keyBuffer,
|
||||
derivedCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
return derivationStatus == kCCSuccess ? derivedKeyData : nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Types
|
||||
|
|
@ -282,6 +362,7 @@ public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
|
|||
case notDeveloperAppleId
|
||||
case notAuthorized
|
||||
case invalidResult(resultString: String?)
|
||||
case srpInvalidPublicKey
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
|
|
@ -316,6 +397,8 @@ public enum AuthenticationError: Swift.Error, LocalizedError, Equatable {
|
|||
return "You are not authorized. Please Sign in with your Apple ID first."
|
||||
case let .invalidResult(resultString):
|
||||
return resultString ?? "If you continue to have problems, please submit a bug report in the Help menu."
|
||||
case .srpInvalidPublicKey:
|
||||
return "Invalid Key"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -495,3 +578,23 @@ public struct AppleProvider: Decodable, Equatable {
|
|||
public struct AppleUser: Decodable, Equatable {
|
||||
public let fullName: String
|
||||
}
|
||||
|
||||
public struct ServerSRPInitResponse: Decodable {
|
||||
let iteration: Int
|
||||
let salt: String
|
||||
let b: String
|
||||
let c: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
extension String {
|
||||
func base64ToU8Array() -> Data {
|
||||
return Data(base64Encoded: self) ?? Data()
|
||||
}
|
||||
}
|
||||
extension Data {
|
||||
func hexEncodedString() -> String {
|
||||
return map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ public extension URL {
|
|||
static let federate = URL(string: "https://idmsa.apple.com/appleauth/auth/federate")!
|
||||
static let olympusSession = URL(string: "https://appstoreconnect.apple.com/olympus/v1/session")!
|
||||
static let keyAuth = URL(string: "https://idmsa.apple.com/appleauth/auth/verify/security/key")!
|
||||
|
||||
static let srpInit = URL(string: "https://idmsa.apple.com/appleauth/auth/signin/init")!
|
||||
static let srpComplete = URL(string: "https://idmsa.apple.com/appleauth/auth/signin/complete?isRememberMeEnabled=false")!
|
||||
|
||||
}
|
||||
|
||||
public extension URLRequest {
|
||||
|
|
@ -150,4 +154,51 @@ public extension URLRequest {
|
|||
|
||||
return request
|
||||
}
|
||||
|
||||
static func SRPInit(serviceKey: String, a: String, accountName: String) -> URLRequest {
|
||||
struct ServerSRPInitRequest: Encodable {
|
||||
public let a: String
|
||||
public let accountName: String
|
||||
public let protocols: [SRPProtocol]
|
||||
}
|
||||
|
||||
var request = URLRequest(url: .srpInit)
|
||||
request.httpMethod = "POST"
|
||||
request.allHTTPHeaderFields = request.allHTTPHeaderFields ?? [:]
|
||||
request.allHTTPHeaderFields?["Accept"] = "application/json"
|
||||
request.allHTTPHeaderFields?["Content-Type"] = "application/json"
|
||||
request.allHTTPHeaderFields?["X-Requested-With"] = "XMLHttpRequest"
|
||||
request.allHTTPHeaderFields?["X-Apple-Widget-Key"] = serviceKey
|
||||
|
||||
request.httpBody = try? JSONEncoder().encode(ServerSRPInitRequest(a: a, accountName: accountName, protocols: [.s2k, .s2k_fo]))
|
||||
return request
|
||||
}
|
||||
|
||||
static func SRPComplete(serviceKey: String, hashcash: String, accountName: String, c: String, m1: String, m2: String) -> URLRequest {
|
||||
struct ServerSRPCompleteRequest: Encodable {
|
||||
let accountName: String
|
||||
let c: String
|
||||
let m1: String
|
||||
let m2: String
|
||||
let rememberMe: Bool
|
||||
}
|
||||
|
||||
var request = URLRequest(url: .srpComplete)
|
||||
request.httpMethod = "POST"
|
||||
request.allHTTPHeaderFields = request.allHTTPHeaderFields ?? [:]
|
||||
request.allHTTPHeaderFields?["Accept"] = "application/json"
|
||||
request.allHTTPHeaderFields?["Content-Type"] = "application/json"
|
||||
request.allHTTPHeaderFields?["X-Requested-With"] = "XMLHttpRequest"
|
||||
request.allHTTPHeaderFields?["X-Apple-Widget-Key"] = serviceKey
|
||||
request.allHTTPHeaderFields?["X-Apple-HC"] = hashcash
|
||||
|
||||
request.httpBody = try? JSONEncoder().encode(ServerSRPCompleteRequest(accountName: accountName, c: c, m1: m1, m2: m2, rememberMe: false))
|
||||
return request
|
||||
}
|
||||
}
|
||||
|
||||
public enum SRPProtocol: String, Codable {
|
||||
case s2k, s2k_fo
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ class AppState: ObservableObject {
|
|||
Current.defaults.set(username, forKey: "username")
|
||||
|
||||
isProcessingAuthRequest = true
|
||||
return client.login(accountName: username, password: password)
|
||||
return client.srpLogin(accountName: username, password: password)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.handleEvents(
|
||||
receiveOutput: { authenticationState in
|
||||
|
|
|
|||
|
|
@ -113,6 +113,241 @@ SOFTWARE.\
|
|||
\
|
||||
\
|
||||
|
||||
\fs34 big-num\
|
||||
\
|
||||
|
||||
\fs26 MIT License\
|
||||
\
|
||||
Copyright (c) 2019 Adam Fowler\
|
||||
\
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy\
|
||||
of this software and associated documentation files (the "Software"), to deal\
|
||||
in the Software without restriction, including without limitation the rights\
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\
|
||||
copies of the Software, and to permit persons to whom the Software is\
|
||||
furnished to do so, subject to the following conditions:\
|
||||
\
|
||||
The above copyright notice and this permission notice shall be included in all\
|
||||
copies or substantial portions of the Software.\
|
||||
\
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\
|
||||
SOFTWARE.\
|
||||
\
|
||||
\
|
||||
|
||||
\fs34 swift-crypto\
|
||||
\
|
||||
|
||||
\fs26 \
|
||||
Apache License\
|
||||
Version 2.0, January 2004\
|
||||
http://www.apache.org/licenses/\
|
||||
\
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\
|
||||
\
|
||||
1. Definitions.\
|
||||
\
|
||||
"License" shall mean the terms and conditions for use, reproduction,\
|
||||
and distribution as defined by Sections 1 through 9 of this document.\
|
||||
\
|
||||
"Licensor" shall mean the copyright owner or entity authorized by\
|
||||
the copyright owner that is granting the License.\
|
||||
\
|
||||
"Legal Entity" shall mean the union of the acting entity and all\
|
||||
other entities that control, are controlled by, or are under common\
|
||||
control with that entity. For the purposes of this definition,\
|
||||
"control" means (i) the power, direct or indirect, to cause the\
|
||||
direction or management of such entity, whether by contract or\
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the\
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.\
|
||||
\
|
||||
"You" (or "Your") shall mean an individual or Legal Entity\
|
||||
exercising permissions granted by this License.\
|
||||
\
|
||||
"Source" form shall mean the preferred form for making modifications,\
|
||||
including but not limited to software source code, documentation\
|
||||
source, and configuration files.\
|
||||
\
|
||||
"Object" form shall mean any form resulting from mechanical\
|
||||
transformation or translation of a Source form, including but\
|
||||
not limited to compiled object code, generated documentation,\
|
||||
and conversions to other media types.\
|
||||
\
|
||||
"Work" shall mean the work of authorship, whether in Source or\
|
||||
Object form, made available under the License, as indicated by a\
|
||||
copyright notice that is included in or attached to the work\
|
||||
(an example is provided in the Appendix below).\
|
||||
\
|
||||
"Derivative Works" shall mean any work, whether in Source or Object\
|
||||
form, that is based on (or derived from) the Work and for which the\
|
||||
editorial revisions, annotations, elaborations, or other modifications\
|
||||
represent, as a whole, an original work of authorship. For the purposes\
|
||||
of this License, Derivative Works shall not include works that remain\
|
||||
separable from, or merely link (or bind by name) to the interfaces of,\
|
||||
the Work and Derivative Works thereof.\
|
||||
\
|
||||
"Contribution" shall mean any work of authorship, including\
|
||||
the original version of the Work and any modifications or additions\
|
||||
to that Work or Derivative Works thereof, that is intentionally\
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner\
|
||||
or by an individual or Legal Entity authorized to submit on behalf of\
|
||||
the copyright owner. For the purposes of this definition, "submitted"\
|
||||
means any form of electronic, verbal, or written communication sent\
|
||||
to the Licensor or its representatives, including but not limited to\
|
||||
communication on electronic mailing lists, source code control systems,\
|
||||
and issue tracking systems that are managed by, or on behalf of, the\
|
||||
Licensor for the purpose of discussing and improving the Work, but\
|
||||
excluding communication that is conspicuously marked or otherwise\
|
||||
designated in writing by the copyright owner as "Not a Contribution."\
|
||||
\
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity\
|
||||
on behalf of whom a Contribution has been received by Licensor and\
|
||||
subsequently incorporated within the Work.\
|
||||
\
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of\
|
||||
this License, each Contributor hereby grants to You a perpetual,\
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable\
|
||||
copyright license to reproduce, prepare Derivative Works of,\
|
||||
publicly display, publicly perform, sublicense, and distribute the\
|
||||
Work and such Derivative Works in Source or Object form.\
|
||||
\
|
||||
3. Grant of Patent License. Subject to the terms and conditions of\
|
||||
this License, each Contributor hereby grants to You a perpetual,\
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable\
|
||||
(except as stated in this section) patent license to make, have made,\
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,\
|
||||
where such license applies only to those patent claims licensable\
|
||||
by such Contributor that are necessarily infringed by their\
|
||||
Contribution(s) alone or by combination of their Contribution(s)\
|
||||
with the Work to which such Contribution(s) was submitted. If You\
|
||||
institute patent litigation against any entity (including a\
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work\
|
||||
or a Contribution incorporated within the Work constitutes direct\
|
||||
or contributory patent infringement, then any patent licenses\
|
||||
granted to You under this License for that Work shall terminate\
|
||||
as of the date such litigation is filed.\
|
||||
\
|
||||
4. Redistribution. You may reproduce and distribute copies of the\
|
||||
Work or Derivative Works thereof in any medium, with or without\
|
||||
modifications, and in Source or Object form, provided that You\
|
||||
meet the following conditions:\
|
||||
\
|
||||
(a) You must give any other recipients of the Work or\
|
||||
Derivative Works a copy of this License; and\
|
||||
\
|
||||
(b) You must cause any modified files to carry prominent notices\
|
||||
stating that You changed the files; and\
|
||||
\
|
||||
(c) You must retain, in the Source form of any Derivative Works\
|
||||
that You distribute, all copyright, patent, trademark, and\
|
||||
attribution notices from the Source form of the Work,\
|
||||
excluding those notices that do not pertain to any part of\
|
||||
the Derivative Works; and\
|
||||
\
|
||||
(d) If the Work includes a "NOTICE" text file as part of its\
|
||||
distribution, then any Derivative Works that You distribute must\
|
||||
include a readable copy of the attribution notices contained\
|
||||
within such NOTICE file, excluding those notices that do not\
|
||||
pertain to any part of the Derivative Works, in at least one\
|
||||
of the following places: within a NOTICE text file distributed\
|
||||
as part of the Derivative Works; within the Source form or\
|
||||
documentation, if provided along with the Derivative Works; or,\
|
||||
within a display generated by the Derivative Works, if and\
|
||||
wherever such third-party notices normally appear. The contents\
|
||||
of the NOTICE file are for informational purposes only and\
|
||||
do not modify the License. You may add Your own attribution\
|
||||
notices within Derivative Works that You distribute, alongside\
|
||||
or as an addendum to the NOTICE text from the Work, provided\
|
||||
that such additional attribution notices cannot be construed\
|
||||
as modifying the License.\
|
||||
\
|
||||
You may add Your own copyright statement to Your modifications and\
|
||||
may provide additional or different license terms and conditions\
|
||||
for use, reproduction, or distribution of Your modifications, or\
|
||||
for any such Derivative Works as a whole, provided Your use,\
|
||||
reproduction, and distribution of the Work otherwise complies with\
|
||||
the conditions stated in this License.\
|
||||
\
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,\
|
||||
any Contribution intentionally submitted for inclusion in the Work\
|
||||
by You to the Licensor shall be under the terms and conditions of\
|
||||
this License, without any additional terms or conditions.\
|
||||
Notwithstanding the above, nothing herein shall supersede or modify\
|
||||
the terms of any separate license agreement you may have executed\
|
||||
with Licensor regarding such Contributions.\
|
||||
\
|
||||
6. Trademarks. This License does not grant permission to use the trade\
|
||||
names, trademarks, service marks, or product names of the Licensor,\
|
||||
except as required for reasonable and customary use in describing the\
|
||||
origin of the Work and reproducing the content of the NOTICE file.\
|
||||
\
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or\
|
||||
agreed to in writing, Licensor provides the Work (and each\
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,\
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\
|
||||
implied, including, without limitation, any warranties or conditions\
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the\
|
||||
appropriateness of using or redistributing the Work and assume any\
|
||||
risks associated with Your exercise of permissions under this License.\
|
||||
\
|
||||
8. Limitation of Liability. In no event and under no legal theory,\
|
||||
whether in tort (including negligence), contract, or otherwise,\
|
||||
unless required by applicable law (such as deliberate and grossly\
|
||||
negligent acts) or agreed to in writing, shall any Contributor be\
|
||||
liable to You for damages, including any direct, indirect, special,\
|
||||
incidental, or consequential damages of any character arising as a\
|
||||
result of this License or out of the use or inability to use the\
|
||||
Work (including but not limited to damages for loss of goodwill,\
|
||||
work stoppage, computer failure or malfunction, or any and all\
|
||||
other commercial damages or losses), even if such Contributor\
|
||||
has been advised of the possibility of such damages.\
|
||||
\
|
||||
9. Accepting Warranty or Additional Liability. While redistributing\
|
||||
the Work or Derivative Works thereof, You may choose to offer,\
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,\
|
||||
or other liability obligations and/or rights consistent with this\
|
||||
License. However, in accepting such obligations, You may act only\
|
||||
on Your own behalf and on Your sole responsibility, not on behalf\
|
||||
of any other Contributor, and only if You agree to indemnify,\
|
||||
defend, and hold each Contributor harmless for any liability\
|
||||
incurred by, or claims asserted against, such Contributor by reason\
|
||||
of your accepting any such warranty or additional liability.\
|
||||
\
|
||||
END OF TERMS AND CONDITIONS\
|
||||
\
|
||||
APPENDIX: How to apply the Apache License to your work.\
|
||||
\
|
||||
To apply the Apache License to your work, attach the following\
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"\
|
||||
replaced with your own identifying information. (Don't include\
|
||||
the brackets!) The text should be enclosed in the appropriate\
|
||||
comment syntax for the file format. We also recommend that a\
|
||||
file or class name and description of purpose be included on the\
|
||||
same "printed page" as the copyright notice for easier\
|
||||
identification within third-party archives.\
|
||||
\
|
||||
Copyright [yyyy] [name of copyright owner]\
|
||||
\
|
||||
Licensed under the Apache License, Version 2.0 (the "License");\
|
||||
you may not use this file except in compliance with the License.\
|
||||
You may obtain a copy of the License at\
|
||||
\
|
||||
http://www.apache.org/licenses/LICENSE-2.0\
|
||||
\
|
||||
Unless required by applicable law or agreed to in writing, software\
|
||||
distributed under the License is distributed on an "AS IS" BASIS,\
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
|
||||
See the License for the specific language governing permissions and\
|
||||
limitations under the License.\
|
||||
\
|
||||
\
|
||||
|
||||
\fs34 Path.swift\
|
||||
\
|
||||
|
||||
|
|
@ -579,6 +814,213 @@ For more information, please refer to <<http://unlicense.org/>>\
|
|||
\
|
||||
\
|
||||
|
||||
\fs34 swift-srp\
|
||||
\
|
||||
|
||||
\fs26 Apache License\
|
||||
Version 2.0, January 2004\
|
||||
http://www.apache.org/licenses/\
|
||||
\
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\
|
||||
\
|
||||
1. Definitions.\
|
||||
\
|
||||
"License" shall mean the terms and conditions for use, reproduction,\
|
||||
and distribution as defined by Sections 1 through 9 of this document.\
|
||||
\
|
||||
"Licensor" shall mean the copyright owner or entity authorized by\
|
||||
the copyright owner that is granting the License.\
|
||||
\
|
||||
"Legal Entity" shall mean the union of the acting entity and all\
|
||||
other entities that control, are controlled by, or are under common\
|
||||
control with that entity. For the purposes of this definition,\
|
||||
"control" means (i) the power, direct or indirect, to cause the\
|
||||
direction or management of such entity, whether by contract or\
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the\
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.\
|
||||
\
|
||||
"You" (or "Your") shall mean an individual or Legal Entity\
|
||||
exercising permissions granted by this License.\
|
||||
\
|
||||
"Source" form shall mean the preferred form for making modifications,\
|
||||
including but not limited to software source code, documentation\
|
||||
source, and configuration files.\
|
||||
\
|
||||
"Object" form shall mean any form resulting from mechanical\
|
||||
transformation or translation of a Source form, including but\
|
||||
not limited to compiled object code, generated documentation,\
|
||||
and conversions to other media types.\
|
||||
\
|
||||
"Work" shall mean the work of authorship, whether in Source or\
|
||||
Object form, made available under the License, as indicated by a\
|
||||
copyright notice that is included in or attached to the work\
|
||||
(an example is provided in the Appendix below).\
|
||||
\
|
||||
"Derivative Works" shall mean any work, whether in Source or Object\
|
||||
form, that is based on (or derived from) the Work and for which the\
|
||||
editorial revisions, annotations, elaborations, or other modifications\
|
||||
represent, as a whole, an original work of authorship. For the purposes\
|
||||
of this License, Derivative Works shall not include works that remain\
|
||||
separable from, or merely link (or bind by name) to the interfaces of,\
|
||||
the Work and Derivative Works thereof.\
|
||||
\
|
||||
"Contribution" shall mean any work of authorship, including\
|
||||
the original version of the Work and any modifications or additions\
|
||||
to that Work or Derivative Works thereof, that is intentionally\
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner\
|
||||
or by an individual or Legal Entity authorized to submit on behalf of\
|
||||
the copyright owner. For the purposes of this definition, "submitted"\
|
||||
means any form of electronic, verbal, or written communication sent\
|
||||
to the Licensor or its representatives, including but not limited to\
|
||||
communication on electronic mailing lists, source code control systems,\
|
||||
and issue tracking systems that are managed by, or on behalf of, the\
|
||||
Licensor for the purpose of discussing and improving the Work, but\
|
||||
excluding communication that is conspicuously marked or otherwise\
|
||||
designated in writing by the copyright owner as "Not a Contribution."\
|
||||
\
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity\
|
||||
on behalf of whom a Contribution has been received by Licensor and\
|
||||
subsequently incorporated within the Work.\
|
||||
\
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of\
|
||||
this License, each Contributor hereby grants to You a perpetual,\
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable\
|
||||
copyright license to reproduce, prepare Derivative Works of,\
|
||||
publicly display, publicly perform, sublicense, and distribute the\
|
||||
Work and such Derivative Works in Source or Object form.\
|
||||
\
|
||||
3. Grant of Patent License. Subject to the terms and conditions of\
|
||||
this License, each Contributor hereby grants to You a perpetual,\
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable\
|
||||
(except as stated in this section) patent license to make, have made,\
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,\
|
||||
where such license applies only to those patent claims licensable\
|
||||
by such Contributor that are necessarily infringed by their\
|
||||
Contribution(s) alone or by combination of their Contribution(s)\
|
||||
with the Work to which such Contribution(s) was submitted. If You\
|
||||
institute patent litigation against any entity (including a\
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work\
|
||||
or a Contribution incorporated within the Work constitutes direct\
|
||||
or contributory patent infringement, then any patent licenses\
|
||||
granted to You under this License for that Work shall terminate\
|
||||
as of the date such litigation is filed.\
|
||||
\
|
||||
4. Redistribution. You may reproduce and distribute copies of the\
|
||||
Work or Derivative Works thereof in any medium, with or without\
|
||||
modifications, and in Source or Object form, provided that You\
|
||||
meet the following conditions:\
|
||||
\
|
||||
(a) You must give any other recipients of the Work or\
|
||||
Derivative Works a copy of this License; and\
|
||||
\
|
||||
(b) You must cause any modified files to carry prominent notices\
|
||||
stating that You changed the files; and\
|
||||
\
|
||||
(c) You must retain, in the Source form of any Derivative Works\
|
||||
that You distribute, all copyright, patent, trademark, and\
|
||||
attribution notices from the Source form of the Work,\
|
||||
excluding those notices that do not pertain to any part of\
|
||||
the Derivative Works; and\
|
||||
\
|
||||
(d) If the Work includes a "NOTICE" text file as part of its\
|
||||
distribution, then any Derivative Works that You distribute must\
|
||||
include a readable copy of the attribution notices contained\
|
||||
within such NOTICE file, excluding those notices that do not\
|
||||
pertain to any part of the Derivative Works, in at least one\
|
||||
of the following places: within a NOTICE text file distributed\
|
||||
as part of the Derivative Works; within the Source form or\
|
||||
documentation, if provided along with the Derivative Works; or,\
|
||||
within a display generated by the Derivative Works, if and\
|
||||
wherever such third-party notices normally appear. The contents\
|
||||
of the NOTICE file are for informational purposes only and\
|
||||
do not modify the License. You may add Your own attribution\
|
||||
notices within Derivative Works that You distribute, alongside\
|
||||
or as an addendum to the NOTICE text from the Work, provided\
|
||||
that such additional attribution notices cannot be construed\
|
||||
as modifying the License.\
|
||||
\
|
||||
You may add Your own copyright statement to Your modifications and\
|
||||
may provide additional or different license terms and conditions\
|
||||
for use, reproduction, or distribution of Your modifications, or\
|
||||
for any such Derivative Works as a whole, provided Your use,\
|
||||
reproduction, and distribution of the Work otherwise complies with\
|
||||
the conditions stated in this License.\
|
||||
\
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,\
|
||||
any Contribution intentionally submitted for inclusion in the Work\
|
||||
by You to the Licensor shall be under the terms and conditions of\
|
||||
this License, without any additional terms or conditions.\
|
||||
Notwithstanding the above, nothing herein shall supersede or modify\
|
||||
the terms of any separate license agreement you may have executed\
|
||||
with Licensor regarding such Contributions.\
|
||||
\
|
||||
6. Trademarks. This License does not grant permission to use the trade\
|
||||
names, trademarks, service marks, or product names of the Licensor,\
|
||||
except as required for reasonable and customary use in describing the\
|
||||
origin of the Work and reproducing the content of the NOTICE file.\
|
||||
\
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or\
|
||||
agreed to in writing, Licensor provides the Work (and each\
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,\
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\
|
||||
implied, including, without limitation, any warranties or conditions\
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the\
|
||||
appropriateness of using or redistributing the Work and assume any\
|
||||
risks associated with Your exercise of permissions under this License.\
|
||||
\
|
||||
8. Limitation of Liability. In no event and under no legal theory,\
|
||||
whether in tort (including negligence), contract, or otherwise,\
|
||||
unless required by applicable law (such as deliberate and grossly\
|
||||
negligent acts) or agreed to in writing, shall any Contributor be\
|
||||
liable to You for damages, including any direct, indirect, special,\
|
||||
incidental, or consequential damages of any character arising as a\
|
||||
result of this License or out of the use or inability to use the\
|
||||
Work (including but not limited to damages for loss of goodwill,\
|
||||
work stoppage, computer failure or malfunction, or any and all\
|
||||
other commercial damages or losses), even if such Contributor\
|
||||
has been advised of the possibility of such damages.\
|
||||
\
|
||||
9. Accepting Warranty or Additional Liability. While redistributing\
|
||||
the Work or Derivative Works thereof, You may choose to offer,\
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,\
|
||||
or other liability obligations and/or rights consistent with this\
|
||||
License. However, in accepting such obligations, You may act only\
|
||||
on Your own behalf and on Your sole responsibility, not on behalf\
|
||||
of any other Contributor, and only if You agree to indemnify,\
|
||||
defend, and hold each Contributor harmless for any liability\
|
||||
incurred by, or claims asserted against, such Contributor by reason\
|
||||
of your accepting any such warranty or additional liability.\
|
||||
\
|
||||
END OF TERMS AND CONDITIONS\
|
||||
\
|
||||
APPENDIX: How to apply the Apache License to your work.\
|
||||
\
|
||||
To apply the Apache License to your work, attach the following\
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"\
|
||||
replaced with your own identifying information. (Don't include\
|
||||
the brackets!) The text should be enclosed in the appropriate\
|
||||
comment syntax for the file format. We also recommend that a\
|
||||
file or class name and description of purpose be included on the\
|
||||
same "printed page" as the copyright notice for easier\
|
||||
identification within third-party archives.\
|
||||
\
|
||||
Copyright [yyyy] [name of copyright owner]\
|
||||
\
|
||||
Licensed under the Apache License, Version 2.0 (the "License");\
|
||||
you may not use this file except in compliance with the License.\
|
||||
You may obtain a copy of the License at\
|
||||
\
|
||||
http://www.apache.org/licenses/LICENSE-2.0\
|
||||
\
|
||||
Unless required by applicable law or agreed to in writing, software\
|
||||
distributed under the License is distributed on an "AS IS" BASIS,\
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
|
||||
See the License for the specific language governing permissions and\
|
||||
limitations under the License.\
|
||||
\
|
||||
\
|
||||
|
||||
\fs34 DockProgress\
|
||||
\
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import Path
|
||||
import CryptoKit
|
||||
import Version
|
||||
@testable import Xcodes
|
||||
import XCTest
|
||||
import CommonCrypto
|
||||
import BigNum
|
||||
import SRP
|
||||
|
||||
class AppStateUpdateTests: XCTestCase {
|
||||
var subject: AppState!
|
||||
|
|
@ -258,4 +262,81 @@ class AppStateUpdateTests: XCTestCase {
|
|||
XCTAssertEqual(subject.allXcodes.map(\.version), [Version("12.4.0")!, Version("12.3.0-RC")!])
|
||||
XCTAssertEqual(subject.allXcodes.map(\.identicalBuilds), [[], []])
|
||||
}
|
||||
|
||||
func sha256(data : Data) -> Data {
|
||||
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
data.withUnsafeBytes {
|
||||
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
|
||||
}
|
||||
return Data(hash)
|
||||
}
|
||||
|
||||
func testSIRP() throws {
|
||||
/*
|
||||
Obtaind by running fastlane spaceauth --verbose -u anand.appleseed@example.com with some custom logging
|
||||
|
||||
Starting SIRP Apple ID login
|
||||
a: {"a":"VLEKLa+n2cyeYNWbECm45CuS4kCdCxodlTDGlW1FKaUyOrv/RbtN2sM0pVE12zI7k3VkocPC3rN5DZBIkahR6I8JHj/J97dtTvzsR+aNRWTYCT2HGP1PBI0QArp3eitAbFqTWI4+Zw+oOnV8+AYdH/wjbq7gOK4C4dvIHE+FzRwIlmguPb5qu2r47R9W3y1msVdoUGlFBOMOMb7Gyq7F0MaEIFH63lNzGomwq74mfss/cFqurd6fxU+Y7tdVTPZw1GWyBEPiXWpk8sNm2zE+S6zWo5tOsICprU75IC9galh1igfzN7VNe0SUFLNFTbFK+Bb1SFAOrAbBZOmyOG5uSQ==","accountName":"anand.appleseed@example.com","protocols":["s2k","s2k_fo"]}
|
||||
Received SIRP signin init response: {"iteration"=>20309, "salt"=>"fIjNflgqSJXACWwwvhDU+w==", "protocol"=>"s2k", "b"=>"PMbU75wwG6rDTySXn2ASWyfQuPoW5ham15SzIscpInwOPE2uk7sePsW4ra0dHcLDUMFQn/LgBggIKOo7YZ9hf1VReiAzXwSKSHdJHjHUURTC2eNpANGUPO1qzuXYgc/MP3MR+GipKHsz+KTLT+8wLjNaiCIHsL/7evJBMw9QqiwhyXlAIm5mGZfhdTVbGpLz2/QzrFmI6pUTrHpio6m1Q74DH3FBxxIeiIcuEdGdeVt9iUweowBRyf2woasTvSV1fbMQbl+lsWPwzt/a73+J30eOGFdSubqSVYh2pV0OLqRz7zPzJars12teCWUV+0WUIaxb14Mp7tlmqcTPuqZe9w==", "c"=>"d-533-eccbc4e9-9564-11ef-84a6-018111c8cc60:PRN"}
|
||||
encrypted_password: 40532b4de9353fc537dc62ee84eacebd7ecb5ec26efca98bd01b0380e302100f 32
|
||||
bb: 7672345903537871991962715758896796468138571329014139041563495295907370682045347022183702983061785424983278857706335295545994877883818377653653442007828499221881058994644619578239367613808278802931379172730746665773282250642455690715139985911303055104847971308813151718669484181874342088801251592138154023949370621963319928723678385968989085032385411532317797659749008135679504901238396934480214258070495365760319076978872181485178648397361564241555189629889320567561713407566532187413091018319494367244540399242523126294027225387432028960726767445027313453858210115810946641002311734776929442587065438110307439763191
|
||||
x: 726436461883978586175291668001486484510457416477927591386889224605776454162
|
||||
u: 49415306980415573732801389514223606278850554555635359953422678270536095422201
|
||||
private 23161374166158551996079451276150657702422963034121842124445818241826569345033578345120284496449280736328513302994568402583647660370960353252836732307301957364261384324957527103960720408713825427474127658415917826326829664923997096839970397226662116904369925262192683131695683487505523842260218490007066160096482662715246662018133837725691586205535995663334471723776536640973591229093933458552240634178864509015968350855952558520147559154646484379002445961375384929682566525908284011230815908584648931495968206840416022306138033496705677078512266958633477047047323620540878121579549170392075029336954975132431417099801
|
||||
S: 4f75b6ea99c2d7d121357cce80c75c8e1bf74a65e8f66f75f8f66a481301afb8bebf0e54a3fac4f8bfdd60c77d6e670c87968b341f62175e25eb1d4f496e4e6596e1a387f2840688a35002419b70115b7902a46544cc7b31eb4c909c0acaeb752835d1562a687c431421510ebc7535c007a2bd12a4f7696c8c96a75a491b1eb9189ade2bef23dd5b0bb962b4f03e7fba7f6ba6fe67ba34cc18647daf3e474876f85dac5a15eb51c99d1ed78783579ffd6c8b6911f72564d87dc8f76519c8fc1535b83743ed5f7d6b8461d7154ce2a874cbb45bf63018352b9b997fbafbd6b15eac2a544a801c0152470796f3b69a84a4a653e5186b30efeeb148ff3c32ab8e08
|
||||
K: c5207f707186a52f1adee41bf0a7bc41e51e6dffc25cdaeca8acb7de2710b20a
|
||||
hN: 65908899099613711898698321155848703477601840791750658211391687862255842366922
|
||||
hG: 23094592799618609623465742609366149076596436609130823198107630312273622653270
|
||||
hxor 73599884097654065452785151481733181870375477364472235597514429707329935690908
|
||||
response: {"accountName":"anand.appleseed@example.com","c":"d-533-eccbc4e9-9564-11ef-84a6-018111c8cc60:PRN","m1":"f/Bkq8gBTYxl7SyiRd4SXTyE/jM/g6E0mVyZIQDIsPg=","m2":"R2rgqC9cMAtWiXUImOrvs4oF+ccibf8KaFsZQ22WokM=","rememberMe":false}
|
||||
*/
|
||||
|
||||
let publicKey = Data(base64Encoded: "VLEKLa+n2cyeYNWbECm45CuS4kCdCxodlTDGlW1FKaUyOrv/RbtN2sM0pVE12zI7k3VkocPC3rN5DZBIkahR6I8JHj/J97dtTvzsR+aNRWTYCT2HGP1PBI0QArp3eitAbFqTWI4+Zw+oOnV8+AYdH/wjbq7gOK4C4dvIHE+FzRwIlmguPb5qu2r47R9W3y1msVdoUGlFBOMOMb7Gyq7F0MaEIFH63lNzGomwq74mfss/cFqurd6fxU+Y7tdVTPZw1GWyBEPiXWpk8sNm2zE+S6zWo5tOsICprU75IC9galh1igfzN7VNe0SUFLNFTbFK+Bb1SFAOrAbBZOmyOG5uSQ==".data(using: .utf8)!)
|
||||
|
||||
let clientKeys = SRPKeyPair(public: .init([UInt8](publicKey!)),
|
||||
private: .init(BigNum("23161374166158551996079451276150657702422963034121842124445818241826569345033578345120284496449280736328513302994568402583647660370960353252836732307301957364261384324957527103960720408713825427474127658415917826326829664923997096839970397226662116904369925262192683131695683487505523842260218490007066160096482662715246662018133837725691586205535995663334471723776536640973591229093933458552240634178864509015968350855952558520147559154646484379002445961375384929682566525908284011230815908584648931495968206840416022306138033496705677078512266958633477047047323620540878121579549170392075029336954975132431417099801")!))
|
||||
|
||||
let password = sha256(data: "example".data(using: .utf8)!)
|
||||
let salt = Data(base64Encoded: "fIjNflgqSJXACWwwvhDU+w==".data(using: .utf8)!)!
|
||||
let iterations: Int = 20309
|
||||
let derivedKeyLength: Int = 32
|
||||
var keyArray = Array<UInt8>(repeating: 0, count: derivedKeyLength)
|
||||
|
||||
let result:Int32 = keyArray.withUnsafeMutableBytes { keyBytes -> Int32 in
|
||||
let keyBuffer = UnsafeMutablePointer<UInt8>(keyBytes.baseAddress!.assumingMemoryBound(to: UInt8.self))
|
||||
return password.withUnsafeBytes { passwordDigestBytes -> Int32 in
|
||||
let passwordBuffer = UnsafePointer<UInt8>(passwordDigestBytes.baseAddress!.assumingMemoryBound(to: UInt8.self))
|
||||
return salt.withUnsafeBytes { saltBytes -> Int32 in
|
||||
let saltBuffer = UnsafePointer<UInt8>(saltBytes.baseAddress!.assumingMemoryBound(to: UInt8.self))
|
||||
return CCKeyDerivationPBKDF(
|
||||
CCPBKDFAlgorithm(kCCPBKDF2),
|
||||
passwordBuffer,
|
||||
password.count,
|
||||
saltBuffer,
|
||||
salt.count,
|
||||
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
|
||||
UInt32(iterations),
|
||||
keyBuffer,
|
||||
derivedKeyLength)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let expectedKey: [UInt8] = [0x40, 0x53, 0x2b, 0x4d, 0xe9, 0x35, 0x3f, 0xc5, 0x37, 0xdc, 0x62, 0xee, 0x84, 0xea, 0xce, 0xbd, 0x7e, 0xcb, 0x5e, 0xc2, 0x6e, 0xfc, 0xa9, 0x8b, 0xd0, 0x1b, 0x03, 0x80, 0xe3, 0x02, 0x10, 0x0f]
|
||||
|
||||
XCTAssertEqual(expectedKey, keyArray)
|
||||
|
||||
let decodedB = Data(base64Encoded: "PMbU75wwG6rDTySXn2ASWyfQuPoW5ham15SzIscpInwOPE2uk7sePsW4ra0dHcLDUMFQn/LgBggIKOo7YZ9hf1VReiAzXwSKSHdJHjHUURTC2eNpANGUPO1qzuXYgc/MP3MR+GipKHsz+KTLT+8wLjNaiCIHsL/7evJBMw9QqiwhyXlAIm5mGZfhdTVbGpLz2/QzrFmI6pUTrHpio6m1Q74DH3FBxxIeiIcuEdGdeVt9iUweowBRyf2woasTvSV1fbMQbl+lsWPwzt/a73+J30eOGFdSubqSVYh2pV0OLqRz7zPzJars12teCWUV+0WUIaxb14Mp7tlmqcTPuqZe9w==".data(using: .utf8)!)!
|
||||
|
||||
let client = SRPClient(configuration: SRPConfiguration<SHA256>(.N2048))
|
||||
let sharedSecret = try client.calculateSharedSecret(password: Data(keyArray), salt: [UInt8](salt), clientKeys: clientKeys, serverPublicKey: .init([UInt8](decodedB)))
|
||||
|
||||
let accountName = "anand.appleseed@example.com"
|
||||
let m1 = client.calculateClientProof(username: accountName, salt: [UInt8](salt), clientPublicKey: clientKeys.public, serverPublicKey: .init([UInt8](decodedB)), sharedSecret: .init(sharedSecret.bytes))
|
||||
let m2 = client.calculateServerProof(clientPublicKey: clientKeys.public, clientProof: m1, sharedSecret: .init([UInt8](sharedSecret.bytes)))
|
||||
|
||||
XCTAssertEqual(Data(m1).base64EncodedString(), "f/Bkq8gBTYxl7SyiRd4SXTyE/jM/g6E0mVyZIQDIsPg=")
|
||||
XCTAssertEqual(Data(m2).base64EncodedString(), "R2rgqC9cMAtWiXUImOrvs4oF+ccibf8KaFsZQ22WokM=")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue