зеркало из https://github.com/github/SoftU2F.git
similar refactor for responses
This commit is contained in:
Родитель
cd25a91f00
Коммит
4e183bfb94
|
@ -50,13 +50,21 @@ public struct AuthenticationRequest: RawConvertible {
|
||||||
self.header = CommandHeader(ins: .Authenticate, p1: control.rawValue, dataLength: body.count)
|
self.header = CommandHeader(ins: .Authenticate, p1: control.rawValue, dataLength: body.count)
|
||||||
self.trailer = CommandTrailer(noBody: false)
|
self.trailer = CommandTrailer(noBody: false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AuthenticationRequest: Command {
|
||||||
|
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
||||||
|
self.header = header
|
||||||
|
self.body = body
|
||||||
|
self.trailer = trailer
|
||||||
|
}
|
||||||
|
|
||||||
func validateBody() throws {
|
func validateBody() throws {
|
||||||
// Make sure it's at least long enough to have key-handle length.
|
// Make sure it's at least long enough to have key-handle length.
|
||||||
if body.count < U2F_CHAL_SIZE + U2F_APPID_SIZE + 1 {
|
if body.count < U2F_CHAL_SIZE + U2F_APPID_SIZE + 1 {
|
||||||
throw ResponseStatus.WrongLength
|
throw ResponseStatus.WrongLength
|
||||||
}
|
}
|
||||||
|
|
||||||
if body.count != U2F_CHAL_SIZE + U2F_APPID_SIZE + 1 + keyHandleLength {
|
if body.count != U2F_CHAL_SIZE + U2F_APPID_SIZE + 1 + keyHandleLength {
|
||||||
throw ResponseStatus.WrongLength
|
throw ResponseStatus.WrongLength
|
||||||
}
|
}
|
||||||
|
@ -66,11 +74,3 @@ public struct AuthenticationRequest: RawConvertible {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AuthenticationRequest: CommandProtocol {
|
|
||||||
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
|
||||||
self.header = header
|
|
||||||
self.body = body
|
|
||||||
self.trailer = trailer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,52 +8,55 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct AuthenticationResponse: MessageProtocol {
|
public struct AuthenticationResponse: RawConvertible {
|
||||||
public let userPresence: UInt8
|
let body: Data
|
||||||
public let counter: UInt32
|
let trailer: ResponseStatus
|
||||||
public let signature: Data
|
|
||||||
public let status: ResponseStatus
|
public var userPresence: UInt8 {
|
||||||
|
return body[0]
|
||||||
|
}
|
||||||
|
|
||||||
public var raw: Data {
|
public var counter: UInt32 {
|
||||||
|
let lowerBound = MemoryLayout<UInt8>.size
|
||||||
|
let upperBound = lowerBound + MemoryLayout<UInt32>.size
|
||||||
|
let data = body.subdata(in: lowerBound..<upperBound)
|
||||||
|
|
||||||
|
return data.withUnsafeBytes { (ptr: UnsafePointer<UInt32>) -> UInt32 in
|
||||||
|
return ptr.pointee.bigEndian
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var signature: Data {
|
||||||
|
let lowerBound = MemoryLayout<UInt8>.size + MemoryLayout<UInt32>.size
|
||||||
|
let upperBound = body.count
|
||||||
|
return body.subdata(in: lowerBound..<upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(userPresence: UInt8, counter: UInt32, signature: Data) {
|
||||||
let writer = DataWriter()
|
let writer = DataWriter()
|
||||||
|
|
||||||
writer.write(userPresence)
|
writer.write(userPresence)
|
||||||
writer.write(counter)
|
writer.write(counter)
|
||||||
writer.writeData(signature)
|
writer.writeData(signature)
|
||||||
writer.write(status)
|
|
||||||
|
body = writer.buffer
|
||||||
return writer.buffer
|
trailer = .NoError
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public init(raw: Data) throws {
|
|
||||||
let reader = DataReader(data: raw)
|
extension AuthenticationResponse: Response {
|
||||||
|
init(body: Data, trailer: ResponseStatus) {
|
||||||
do {
|
self.body = body
|
||||||
userPresence = try reader.read()
|
self.trailer = trailer
|
||||||
counter = try reader.read()
|
}
|
||||||
signature = try reader.readData(reader.remaining - 2)
|
|
||||||
status = try reader.read()
|
func validateBody() throws {
|
||||||
} catch DataReaderError.End {
|
// TODO: minimum signature size?
|
||||||
throw ResponseStatus.WrongLength
|
if body.count < MemoryLayout<UInt8>.size + MemoryLayout<UInt32>.size + 1 {
|
||||||
}
|
throw ResponseError.BadSize
|
||||||
|
}
|
||||||
if reader.remaining > 0 {
|
|
||||||
throw ResponseStatus.WrongLength
|
if trailer != .NoError {
|
||||||
}
|
throw ResponseError.BadStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(userPresence u: UInt8, counter c: UInt32, signature s: Data) {
|
|
||||||
userPresence = u
|
|
||||||
counter = c
|
|
||||||
signature = s
|
|
||||||
status = .NoError
|
|
||||||
}
|
|
||||||
|
|
||||||
public func debug() {
|
|
||||||
print("AuthenticationResponse:")
|
|
||||||
print(String(format: " User presence: 0x%02x", userPresence))
|
|
||||||
print(String(format: " Counter: 0x%08x", counter))
|
|
||||||
print( " Signature: \(signature.base64EncodedString())")
|
|
||||||
print( " Status: \(status)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// CommandProtocol.swift
|
// Command.swift
|
||||||
// SoftU2FTool
|
// SoftU2FTool
|
||||||
//
|
//
|
||||||
// Created by Benjamin P Toews on 2/7/17.
|
// Created by Benjamin P Toews on 2/7/17.
|
||||||
|
@ -14,7 +14,7 @@ public func commandType(raw: Data) throws -> CommandCode {
|
||||||
return header.ins
|
return header.ins
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol CommandProtocol {
|
protocol Command {
|
||||||
var header: CommandHeader { get }
|
var header: CommandHeader { get }
|
||||||
var body: Data { get }
|
var body: Data { get }
|
||||||
var trailer: CommandTrailer { get }
|
var trailer: CommandTrailer { get }
|
||||||
|
@ -25,7 +25,7 @@ protocol CommandProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement RawConvertible
|
// Implement RawConvertible
|
||||||
extension CommandProtocol {
|
extension Command {
|
||||||
public var raw: Data {
|
public var raw: Data {
|
||||||
let writer = DataWriter()
|
let writer = DataWriter()
|
||||||
writer.writeData(header.raw)
|
writer.writeData(header.raw)
|
|
@ -16,20 +16,6 @@ let U2F_EC_POINT_SIZE = ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
|
||||||
|
|
||||||
let MaxResponseSize = Int(UInt16.max) + 1
|
let MaxResponseSize = Int(UInt16.max) + 1
|
||||||
|
|
||||||
// ISO7816-4
|
|
||||||
public enum ResponseStatus: UInt16, EndianEnumProtocol, Error {
|
|
||||||
public typealias RawValue = UInt16
|
|
||||||
|
|
||||||
case NoError = 0x9000
|
|
||||||
case WrongData = 0x6A80
|
|
||||||
case ConditionsNotSatisfied = 0x6985
|
|
||||||
case CommandNotAllowed = 0x6986
|
|
||||||
case InsNotSupported = 0x6D00
|
|
||||||
case WrongLength = 0x6700
|
|
||||||
case ClassNotSupported = 0x6E00
|
|
||||||
case OtherError = 0x6F00 // "No precise diagnosis"
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CommandClass: UInt8 {
|
public enum CommandClass: UInt8 {
|
||||||
case Reserved = 0x00
|
case Reserved = 0x00
|
||||||
}
|
}
|
||||||
|
@ -49,3 +35,17 @@ public enum Control: UInt8 {
|
||||||
// Used internally.
|
// Used internally.
|
||||||
case Invalid = 0xFF
|
case Invalid = 0xFF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ISO7816-4
|
||||||
|
public enum ResponseStatus: UInt16, EndianEnumProtocol, Error {
|
||||||
|
public typealias RawValue = UInt16
|
||||||
|
|
||||||
|
case NoError = 0x9000
|
||||||
|
case WrongData = 0x6A80
|
||||||
|
case ConditionsNotSatisfied = 0x6985
|
||||||
|
case CommandNotAllowed = 0x6986
|
||||||
|
case InsNotSupported = 0x6D00
|
||||||
|
case WrongLength = 0x6700
|
||||||
|
case ClassNotSupported = 0x6E00
|
||||||
|
case OtherError = 0x6F00 // "No precise diagnosis"
|
||||||
|
}
|
||||||
|
|
|
@ -8,32 +8,25 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct ErrorResponse: MessageProtocol {
|
public struct ErrorResponse: RawConvertible {
|
||||||
public let status: ResponseStatus
|
let body: Data
|
||||||
|
let trailer: ResponseStatus
|
||||||
public var raw: Data {
|
|
||||||
let writer = DataWriter()
|
|
||||||
|
|
||||||
writer.write(status)
|
|
||||||
|
|
||||||
return writer.buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(status s: ResponseStatus) {
|
public init(status s: ResponseStatus) {
|
||||||
status = s
|
body = Data()
|
||||||
}
|
trailer = s
|
||||||
|
}
|
||||||
public init(raw: Data) throws {
|
}
|
||||||
let reader = DataReader(data: raw)
|
|
||||||
status = try reader.read()
|
extension ErrorResponse: Response {
|
||||||
|
init(body: Data, trailer: ResponseStatus) {
|
||||||
if reader.remaining > 0 {
|
self.body = body
|
||||||
throw ResponseStatus.WrongLength
|
self.trailer = trailer
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func validateBody() throws {
|
||||||
public func debug() {
|
if body.count != 0 {
|
||||||
print("Error Response:")
|
throw ResponseError.BadSize
|
||||||
print(" Status: \(status)")
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
//
|
|
||||||
// APDUMessage.swift
|
|
||||||
// SecurityKeyBLE
|
|
||||||
//
|
|
||||||
// Created by Benjamin P Toews on 9/12/16.
|
|
||||||
// Copyright © 2017 GitHub. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public protocol MessageProtocol {
|
|
||||||
var raw: Data { get }
|
|
||||||
init(raw: Data) throws
|
|
||||||
|
|
||||||
func debug()
|
|
||||||
}
|
|
|
@ -34,6 +34,14 @@ public struct RegisterRequest: RawConvertible {
|
||||||
self.header = CommandHeader(ins: .Register, dataLength: body.count)
|
self.header = CommandHeader(ins: .Register, dataLength: body.count)
|
||||||
self.trailer = CommandTrailer(noBody: false)
|
self.trailer = CommandTrailer(noBody: false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension RegisterRequest: Command {
|
||||||
|
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
||||||
|
self.header = header
|
||||||
|
self.body = body
|
||||||
|
self.trailer = trailer
|
||||||
|
}
|
||||||
|
|
||||||
func validateBody() throws {
|
func validateBody() throws {
|
||||||
if body.count != U2F_CHAL_SIZE + U2F_APPID_SIZE {
|
if body.count != U2F_CHAL_SIZE + U2F_APPID_SIZE {
|
||||||
|
@ -41,11 +49,3 @@ public struct RegisterRequest: RawConvertible {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RegisterRequest: CommandProtocol {
|
|
||||||
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
|
||||||
self.header = header
|
|
||||||
self.body = body
|
|
||||||
self.trailer = trailer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,81 +9,120 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SelfSignedCertificate
|
import SelfSignedCertificate
|
||||||
|
|
||||||
public struct RegisterResponse: MessageProtocol {
|
public struct RegisterResponse: RawConvertible {
|
||||||
// Parse a DER formatted X509 certificate from the beginning of a datum and return its length.
|
let body: Data
|
||||||
static func certLength(fromData d: Data) throws -> Int {
|
let trailer: ResponseStatus
|
||||||
var size: Int = 0
|
|
||||||
if SelfSignedCertificate.parseX509(d, consumed: &size) {
|
public var publicKey: Data {
|
||||||
return size
|
return body.subdata(in: publicKeyRange)
|
||||||
} else {
|
}
|
||||||
throw ResponseStatus.OtherError
|
|
||||||
}
|
var keyHandleLength: Int {
|
||||||
|
return Int(body.subdata(in: keyHandleLengthRange)[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
public let publicKey: Data
|
public var keyHandle: Data {
|
||||||
public let keyHandle: Data
|
return body.subdata(in: keyHandleRange)
|
||||||
public let certificate: Data
|
}
|
||||||
public let signature: Data
|
|
||||||
public let status: ResponseStatus
|
public var certificate: Data {
|
||||||
|
return body.subdata(in: certificateRange)
|
||||||
|
}
|
||||||
|
|
||||||
public var raw: Data {
|
public var signature: Data {
|
||||||
|
return body.subdata(in: signatureRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
var publicKeyRange: Range<Int> {
|
||||||
|
let lowerBound = 0
|
||||||
|
let upperBound = lowerBound + U2F_EC_POINT_SIZE
|
||||||
|
return lowerBound..<upperBound
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyHandleLengthRange: Range<Int> {
|
||||||
|
let lowerBound = publicKeyRange.upperBound
|
||||||
|
let upperBound = lowerBound + MemoryLayout<UInt8>.size
|
||||||
|
return lowerBound..<upperBound
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyHandleRange: Range<Int> {
|
||||||
|
let lowerBound = keyHandleLengthRange.upperBound
|
||||||
|
let upperBound = lowerBound + keyHandleLength
|
||||||
|
return lowerBound..<upperBound
|
||||||
|
}
|
||||||
|
|
||||||
|
var certificateSize: Int {
|
||||||
|
let remainingRange: Range<Int> = keyHandleRange.upperBound..<body.count
|
||||||
|
let remaining = body.subdata(in: remainingRange)
|
||||||
|
var size: Int = 0
|
||||||
|
|
||||||
|
if SelfSignedCertificate.parseX509(remaining, consumed: &size) {
|
||||||
|
return size
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var certificateRange: Range<Int> {
|
||||||
|
let lowerBound = keyHandleRange.upperBound
|
||||||
|
let upperBound = lowerBound + certificateSize
|
||||||
|
return lowerBound..<upperBound
|
||||||
|
}
|
||||||
|
|
||||||
|
var signatureRange: Range<Int> {
|
||||||
|
let lowerBound = certificateRange.upperBound
|
||||||
|
let upperBound = body.count
|
||||||
|
return lowerBound..<upperBound
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(publicKey: Data, keyHandle: Data, certificate: Data, signature: Data) {
|
||||||
let writer = DataWriter()
|
let writer = DataWriter()
|
||||||
|
|
||||||
writer.write(UInt8(0x05))
|
|
||||||
writer.writeData(publicKey)
|
writer.writeData(publicKey)
|
||||||
writer.write(UInt8(keyHandle.count))
|
writer.write(UInt8(keyHandle.count))
|
||||||
writer.writeData(keyHandle)
|
writer.writeData(keyHandle)
|
||||||
writer.writeData(certificate)
|
writer.writeData(certificate)
|
||||||
writer.writeData(signature)
|
writer.writeData(signature)
|
||||||
writer.write(status)
|
|
||||||
|
|
||||||
return writer.buffer
|
body = writer.buffer
|
||||||
}
|
trailer = .NoError
|
||||||
|
}
|
||||||
public init(raw: Data) throws {
|
}
|
||||||
let reader = DataReader(data: raw)
|
|
||||||
|
extension RegisterResponse: Response {
|
||||||
do {
|
init(body: Data, trailer: ResponseStatus) {
|
||||||
// reserved byte
|
self.body = body
|
||||||
let _: UInt8 = try reader.read()
|
self.trailer = trailer
|
||||||
|
}
|
||||||
publicKey = try reader.readData(U2F_EC_POINT_SIZE)
|
|
||||||
|
func validateBody() throws {
|
||||||
let khLen: UInt8 = try reader.read()
|
// Check that we at least have key-handle length.
|
||||||
keyHandle = try reader.readData(Int(khLen))
|
var min = U2F_EC_POINT_SIZE + MemoryLayout<UInt8>.size
|
||||||
|
if body.count < min {
|
||||||
// peek at cert to figure out its length
|
throw ResponseError.BadSize
|
||||||
let certLen = try RegisterResponse.certLength(fromData: reader.rest)
|
}
|
||||||
certificate = try reader.readData(certLen)
|
|
||||||
|
|
||||||
signature = try reader.readData(reader.remaining - 2)
|
// Check that we at least have one byte of cert.
|
||||||
|
// TODO: minimum cert size?
|
||||||
status = try reader.read()
|
min += keyHandleLength + 1
|
||||||
} catch DataReaderError.End {
|
if body.count < min {
|
||||||
throw ResponseStatus.WrongLength
|
throw ResponseError.BadSize
|
||||||
}
|
}
|
||||||
|
|
||||||
if reader.remaining > 0 {
|
// Check that cert is parsable.
|
||||||
throw ResponseStatus.WrongLength
|
if certificateSize == 0 {
|
||||||
}
|
throw ResponseError.BadCertificate
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(publicKey pk: Data, keyHandle kh: Data, certificate cert: Data, signature sig: Data) {
|
// Check that we at least have one byte of signature.
|
||||||
publicKey = pk
|
// TODO: minimum signature size?
|
||||||
keyHandle = kh
|
min += certificateSize + 1
|
||||||
certificate = cert
|
if body.count < min {
|
||||||
signature = sig
|
throw ResponseError.BadSize
|
||||||
status = .NoError
|
}
|
||||||
}
|
|
||||||
|
if trailer != .NoError {
|
||||||
public func debug() {
|
throw ResponseError.BadStatus
|
||||||
print("Registration Response:")
|
}
|
||||||
print( " Reserved: 0x05")
|
|
||||||
print( " Public key: \(publicKey.base64EncodedString())")
|
|
||||||
print(String(format: " KH Len: 0x%02x", keyHandle.count))
|
|
||||||
print( " Key Handle: \(keyHandle.base64EncodedString())")
|
|
||||||
print( " Certificate: \(certificate.base64EncodedString())")
|
|
||||||
print( " Signature: \(signature.base64EncodedString())")
|
|
||||||
print( " Status: \(status)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// Response.swift
|
||||||
|
// SoftU2FTool
|
||||||
|
//
|
||||||
|
// Created by Benjamin P Toews on 2/7/17.
|
||||||
|
// Copyright © 2017 GitHub. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ResponseError: Error {
|
||||||
|
case BadSize
|
||||||
|
case BadStatus
|
||||||
|
case BadCertificate
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Response {
|
||||||
|
var body: Data { get }
|
||||||
|
var trailer: ResponseStatus { get }
|
||||||
|
|
||||||
|
init(body: Data, trailer: ResponseStatus)
|
||||||
|
|
||||||
|
func validateBody() throws
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement RawConvertible
|
||||||
|
extension Response {
|
||||||
|
public var raw: Data {
|
||||||
|
let writer = DataWriter()
|
||||||
|
writer.writeData(body)
|
||||||
|
writer.write(trailer)
|
||||||
|
|
||||||
|
return writer.buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(raw: Data) throws {
|
||||||
|
let reader = DataReader(data: raw)
|
||||||
|
let body = try reader.readData(reader.remaining - 2)
|
||||||
|
let trailer: ResponseStatus = try reader.read()
|
||||||
|
|
||||||
|
self.init(body: body, trailer: trailer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing with libu2f-host
|
||||||
|
public init(raw: Data, bodyOnly: Bool) throws {
|
||||||
|
if bodyOnly {
|
||||||
|
self.init(body: raw, trailer: .NoError)
|
||||||
|
} else {
|
||||||
|
try self.init(raw: raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,12 +13,6 @@ public struct VersionRequest: RawConvertible {
|
||||||
let body: Data
|
let body: Data
|
||||||
let trailer: CommandTrailer
|
let trailer: CommandTrailer
|
||||||
|
|
||||||
func validateBody() throws {
|
|
||||||
if body.count > 0 {
|
|
||||||
throw ResponseStatus.WrongLength
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.header = CommandHeader(ins: .Version, dataLength: 0)
|
self.header = CommandHeader(ins: .Version, dataLength: 0)
|
||||||
self.body = Data()
|
self.body = Data()
|
||||||
|
@ -26,10 +20,16 @@ public struct VersionRequest: RawConvertible {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VersionRequest: CommandProtocol {
|
extension VersionRequest: Command {
|
||||||
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
init(header: CommandHeader, body: Data, trailer: CommandTrailer) {
|
||||||
self.header = header
|
self.header = header
|
||||||
self.body = body
|
self.body = body
|
||||||
self.trailer = trailer
|
self.trailer = trailer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateBody() throws {
|
||||||
|
if body.count > 0 {
|
||||||
|
throw ResponseStatus.WrongLength
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,44 +8,33 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct VersionResponse: MessageProtocol {
|
public struct VersionResponse: RawConvertible {
|
||||||
public let version: String
|
let body: Data
|
||||||
public let status: ResponseStatus
|
let trailer: ResponseStatus
|
||||||
|
|
||||||
public var raw: Data {
|
public var version: String {
|
||||||
let writer = DataWriter()
|
return String(data: body, encoding: .utf8) ?? ""
|
||||||
|
|
||||||
writer.writeData(version.data(using: .utf8)!)
|
|
||||||
writer.write(status)
|
|
||||||
|
|
||||||
return writer.buffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(version v: String) {
|
public init(version: String) {
|
||||||
version = v
|
body = version.data(using: .utf8)!
|
||||||
status = .NoError
|
trailer = .NoError
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public init(raw: Data) throws {
|
|
||||||
let reader = DataReader(data: raw)
|
extension VersionResponse: Response {
|
||||||
|
init(body: Data, trailer: ResponseStatus) {
|
||||||
let vData = try reader.readData(reader.remaining - 2)
|
self.body = body
|
||||||
if let v = String(data: vData, encoding: .utf8) {
|
self.trailer = trailer
|
||||||
version = v
|
}
|
||||||
} else {
|
|
||||||
throw ResponseStatus.WrongLength
|
func validateBody() throws {
|
||||||
}
|
if version.lengthOfBytes(using: .utf8) < 1 {
|
||||||
|
throw ResponseError.BadSize
|
||||||
status = try reader.read()
|
}
|
||||||
|
|
||||||
if reader.remaining > 0 {
|
if trailer != .NoError {
|
||||||
throw ResponseStatus.WrongLength
|
throw ResponseError.BadStatus
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public func debug() {
|
|
||||||
print("Version Response:")
|
|
||||||
print(" Version: \(version)")
|
|
||||||
print(" Status: \(status)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ResponseTests: XCTestCase {
|
||||||
XCTAssertEqual(r2.keyHandle, r.keyHandle)
|
XCTAssertEqual(r2.keyHandle, r.keyHandle)
|
||||||
XCTAssertEqual(r2.certificate, r.certificate)
|
XCTAssertEqual(r2.certificate, r.certificate)
|
||||||
XCTAssertEqual(r2.signature, r.signature)
|
XCTAssertEqual(r2.signature, r.signature)
|
||||||
XCTAssertEqual(r2.status, r.status)
|
XCTAssertEqual(r2.trailer, r.trailer)
|
||||||
XCTAssertEqual(r.raw, r2.raw)
|
XCTAssertEqual(r.raw, r2.raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class ResponseTests: XCTestCase {
|
||||||
let r2 = try VersionResponse(raw: r.raw)
|
let r2 = try VersionResponse(raw: r.raw)
|
||||||
|
|
||||||
XCTAssertEqual(r.version, r2.version)
|
XCTAssertEqual(r.version, r2.version)
|
||||||
XCTAssertEqual(r.status, r2.status)
|
XCTAssertEqual(r.trailer, r2.trailer)
|
||||||
XCTAssertEqual(r.raw, r2.raw)
|
XCTAssertEqual(r.raw, r2.raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class ResponseTests: XCTestCase {
|
||||||
let r = ErrorResponse(status: .ConditionsNotSatisfied)
|
let r = ErrorResponse(status: .ConditionsNotSatisfied)
|
||||||
let r2 = try ErrorResponse(raw: r.raw)
|
let r2 = try ErrorResponse(raw: r.raw)
|
||||||
|
|
||||||
XCTAssertEqual(r.status, r2.status)
|
XCTAssertEqual(r.trailer, r2.trailer)
|
||||||
XCTAssertEqual(r.raw, r2.raw)
|
XCTAssertEqual(r.raw, r2.raw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
F738F5171E4A2CF6005680A2 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */; };
|
F738F5171E4A2CF6005680A2 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */; };
|
||||||
F738F5201E4A2DDD005680A2 /* CommandHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */; };
|
F738F5201E4A2DDD005680A2 /* CommandHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */; };
|
||||||
F738F5211E4A2DDD005680A2 /* CommandTrailer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */; };
|
F738F5211E4A2DDD005680A2 /* CommandTrailer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */; };
|
||||||
F738F5221E4A2DDD005680A2 /* MessageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51D1E4A2DDD005680A2 /* MessageProtocol.swift */; };
|
|
||||||
F738F5281E4A2E57005680A2 /* DataReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5251E4A2E57005680A2 /* DataReader.swift */; };
|
F738F5281E4A2E57005680A2 /* DataReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5251E4A2E57005680A2 /* DataReader.swift */; };
|
||||||
F738F5291E4A2E57005680A2 /* DataWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5261E4A2E57005680A2 /* DataWriter.swift */; };
|
F738F5291E4A2E57005680A2 /* DataWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5261E4A2E57005680A2 /* DataWriter.swift */; };
|
||||||
F738F52A1E4A2E57005680A2 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5271E4A2E57005680A2 /* Endian.swift */; };
|
F738F52A1E4A2E57005680A2 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5271E4A2E57005680A2 /* Endian.swift */; };
|
||||||
|
@ -51,7 +50,6 @@
|
||||||
F738F5411E4A2ED6005680A2 /* ResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F53D1E4A2ED6005680A2 /* ResponseTests.swift */; };
|
F738F5411E4A2ED6005680A2 /* ResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F53D1E4A2ED6005680A2 /* ResponseTests.swift */; };
|
||||||
F738F5431E4A2F91005680A2 /* CommandHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */; };
|
F738F5431E4A2F91005680A2 /* CommandHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */; };
|
||||||
F738F5441E4A2F91005680A2 /* CommandTrailer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */; };
|
F738F5441E4A2F91005680A2 /* CommandTrailer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */; };
|
||||||
F738F5451E4A2F91005680A2 /* MessageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F51D1E4A2DDD005680A2 /* MessageProtocol.swift */; };
|
|
||||||
F738F5481E4A2F91005680A2 /* AuthenticationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5041E4A2CF6005680A2 /* AuthenticationRequest.swift */; };
|
F738F5481E4A2F91005680A2 /* AuthenticationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5041E4A2CF6005680A2 /* AuthenticationRequest.swift */; };
|
||||||
F738F5491E4A2F91005680A2 /* AuthenticationResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5051E4A2CF6005680A2 /* AuthenticationResponse.swift */; };
|
F738F5491E4A2F91005680A2 /* AuthenticationResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5051E4A2CF6005680A2 /* AuthenticationResponse.swift */; };
|
||||||
F738F54A1E4A2F91005680A2 /* ErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5061E4A2CF6005680A2 /* ErrorResponse.swift */; };
|
F738F54A1E4A2F91005680A2 /* ErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5061E4A2CF6005680A2 /* ErrorResponse.swift */; };
|
||||||
|
@ -77,15 +75,17 @@
|
||||||
F738F5871E4A3C09005680A2 /* DataReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5851E4A3C09005680A2 /* DataReaderTests.swift */; };
|
F738F5871E4A3C09005680A2 /* DataReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5851E4A3C09005680A2 /* DataReaderTests.swift */; };
|
||||||
F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5861E4A3C09005680A2 /* DataWriterTests.swift */; };
|
F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5861E4A3C09005680A2 /* DataWriterTests.swift */; };
|
||||||
F738F58A1E4A3C21005680A2 /* TestUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5891E4A3C21005680A2 /* TestUtil.swift */; };
|
F738F58A1E4A3C21005680A2 /* TestUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5891E4A3C21005680A2 /* TestUtil.swift */; };
|
||||||
F7B5DBAD1E4A5CED00E5ABD4 /* CommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAC1E4A5CED00E5ABD4 /* CommandProtocol.swift */; };
|
F7B5DBAD1E4A5CED00E5ABD4 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAC1E4A5CED00E5ABD4 /* Command.swift */; };
|
||||||
F7B5DBAF1E4A815700E5ABD4 /* RawConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */; };
|
F7B5DBAF1E4A815700E5ABD4 /* RawConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */; };
|
||||||
F7B5DBB01E4A827000E5ABD4 /* RawConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */; };
|
F7B5DBB01E4A827000E5ABD4 /* RawConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */; };
|
||||||
F7B5DBB11E4A827400E5ABD4 /* CommandProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAC1E4A5CED00E5ABD4 /* CommandProtocol.swift */; };
|
F7B5DBB11E4A827400E5ABD4 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBAC1E4A5CED00E5ABD4 /* Command.swift */; };
|
||||||
F7B5DBB31E4A82EB00E5ABD4 /* MessagePart.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */; };
|
F7B5DBB31E4A82EB00E5ABD4 /* MessagePart.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */; };
|
||||||
F7B5DBB41E4A83D900E5ABD4 /* MessagePart.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */; };
|
F7B5DBB41E4A83D900E5ABD4 /* MessagePart.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */; };
|
||||||
F7B5DBC11E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBD1E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift */; };
|
F7B5DBC11E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBD1E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift */; };
|
||||||
F7B5DBC21E4A85EB00E5ABD4 /* RegisterRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBE1E4A85EB00E5ABD4 /* RegisterRequestTests.swift */; };
|
F7B5DBC21E4A85EB00E5ABD4 /* RegisterRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBE1E4A85EB00E5ABD4 /* RegisterRequestTests.swift */; };
|
||||||
F7B5DBC31E4A85EB00E5ABD4 /* VersionRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBF1E4A85EB00E5ABD4 /* VersionRequestTests.swift */; };
|
F7B5DBC31E4A85EB00E5ABD4 /* VersionRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBBF1E4A85EB00E5ABD4 /* VersionRequestTests.swift */; };
|
||||||
|
F7B5DBC91E4A8CF000E5ABD4 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBC81E4A8CF000E5ABD4 /* Response.swift */; };
|
||||||
|
F7B5DBCA1E4A8CF000E5ABD4 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B5DBC81E4A8CF000E5ABD4 /* Response.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -226,7 +226,6 @@
|
||||||
F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = "<group>"; };
|
F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = "<group>"; };
|
||||||
F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandHeader.swift; sourceTree = "<group>"; };
|
F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandHeader.swift; sourceTree = "<group>"; };
|
||||||
F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandTrailer.swift; sourceTree = "<group>"; };
|
F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandTrailer.swift; sourceTree = "<group>"; };
|
||||||
F738F51D1E4A2DDD005680A2 /* MessageProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageProtocol.swift; sourceTree = "<group>"; };
|
|
||||||
F738F5251E4A2E57005680A2 /* DataReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReader.swift; path = Data/DataReader.swift; sourceTree = "<group>"; };
|
F738F5251E4A2E57005680A2 /* DataReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReader.swift; path = Data/DataReader.swift; sourceTree = "<group>"; };
|
||||||
F738F5261E4A2E57005680A2 /* DataWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriter.swift; path = Data/DataWriter.swift; sourceTree = "<group>"; };
|
F738F5261E4A2E57005680A2 /* DataWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriter.swift; path = Data/DataWriter.swift; sourceTree = "<group>"; };
|
||||||
F738F5271E4A2E57005680A2 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Endian.swift; path = Data/Endian.swift; sourceTree = "<group>"; };
|
F738F5271E4A2E57005680A2 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Endian.swift; path = Data/Endian.swift; sourceTree = "<group>"; };
|
||||||
|
@ -248,12 +247,13 @@
|
||||||
F738F5851E4A3C09005680A2 /* DataReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReaderTests.swift; path = DataTests/DataReaderTests.swift; sourceTree = "<group>"; };
|
F738F5851E4A3C09005680A2 /* DataReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReaderTests.swift; path = DataTests/DataReaderTests.swift; sourceTree = "<group>"; };
|
||||||
F738F5861E4A3C09005680A2 /* DataWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriterTests.swift; path = DataTests/DataWriterTests.swift; sourceTree = "<group>"; };
|
F738F5861E4A3C09005680A2 /* DataWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriterTests.swift; path = DataTests/DataWriterTests.swift; sourceTree = "<group>"; };
|
||||||
F738F5891E4A3C21005680A2 /* TestUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = "<group>"; };
|
F738F5891E4A3C21005680A2 /* TestUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBAC1E4A5CED00E5ABD4 /* CommandProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandProtocol.swift; sourceTree = "<group>"; };
|
F7B5DBAC1E4A5CED00E5ABD4 /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawConvertible.swift; sourceTree = "<group>"; };
|
F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawConvertible.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePart.swift; sourceTree = "<group>"; };
|
F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePart.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBBD1E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationRequestTests.swift; sourceTree = "<group>"; };
|
F7B5DBBD1E4A85EB00E5ABD4 /* AuthenticationRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationRequestTests.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBBE1E4A85EB00E5ABD4 /* RegisterRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegisterRequestTests.swift; sourceTree = "<group>"; };
|
F7B5DBBE1E4A85EB00E5ABD4 /* RegisterRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegisterRequestTests.swift; sourceTree = "<group>"; };
|
||||||
F7B5DBBF1E4A85EB00E5ABD4 /* VersionRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionRequestTests.swift; sourceTree = "<group>"; };
|
F7B5DBBF1E4A85EB00E5ABD4 /* VersionRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionRequestTests.swift; sourceTree = "<group>"; };
|
||||||
|
F7B5DBC81E4A8CF000E5ABD4 /* Response.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -404,17 +404,17 @@
|
||||||
F738F5521E4A2FF0005680A2 /* Constants.swift */,
|
F738F5521E4A2FF0005680A2 /* Constants.swift */,
|
||||||
F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */,
|
F7B5DBAE1E4A815700E5ABD4 /* RawConvertible.swift */,
|
||||||
F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */,
|
F7B5DBB21E4A82EB00E5ABD4 /* MessagePart.swift */,
|
||||||
F7B5DBAC1E4A5CED00E5ABD4 /* CommandProtocol.swift */,
|
F7B5DBAC1E4A5CED00E5ABD4 /* Command.swift */,
|
||||||
F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */,
|
F738F51B1E4A2DDD005680A2 /* CommandHeader.swift */,
|
||||||
F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */,
|
F738F51C1E4A2DDD005680A2 /* CommandTrailer.swift */,
|
||||||
F738F51D1E4A2DDD005680A2 /* MessageProtocol.swift */,
|
F7B5DBC81E4A8CF000E5ABD4 /* Response.swift */,
|
||||||
F738F5041E4A2CF6005680A2 /* AuthenticationRequest.swift */,
|
F738F5041E4A2CF6005680A2 /* AuthenticationRequest.swift */,
|
||||||
F738F5051E4A2CF6005680A2 /* AuthenticationResponse.swift */,
|
F738F5051E4A2CF6005680A2 /* AuthenticationResponse.swift */,
|
||||||
F738F5061E4A2CF6005680A2 /* ErrorResponse.swift */,
|
|
||||||
F738F5071E4A2CF6005680A2 /* RegisterRequest.swift */,
|
F738F5071E4A2CF6005680A2 /* RegisterRequest.swift */,
|
||||||
F738F5081E4A2CF6005680A2 /* RegisterResponse.swift */,
|
F738F5081E4A2CF6005680A2 /* RegisterResponse.swift */,
|
||||||
F738F5091E4A2CF6005680A2 /* VersionRequest.swift */,
|
F738F5091E4A2CF6005680A2 /* VersionRequest.swift */,
|
||||||
F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */,
|
F738F50A1E4A2CF6005680A2 /* VersionResponse.swift */,
|
||||||
|
F738F5061E4A2CF6005680A2 /* ErrorResponse.swift */,
|
||||||
F738F4F31E4A2CCC005680A2 /* APDU.h */,
|
F738F4F31E4A2CCC005680A2 /* APDU.h */,
|
||||||
F738F4F41E4A2CCC005680A2 /* Info.plist */,
|
F738F4F41E4A2CCC005680A2 /* Info.plist */,
|
||||||
);
|
);
|
||||||
|
@ -808,8 +808,9 @@
|
||||||
files = (
|
files = (
|
||||||
F738F5281E4A2E57005680A2 /* DataReader.swift in Sources */,
|
F738F5281E4A2E57005680A2 /* DataReader.swift in Sources */,
|
||||||
F738F5531E4A2FF0005680A2 /* Constants.swift in Sources */,
|
F738F5531E4A2FF0005680A2 /* Constants.swift in Sources */,
|
||||||
F7B5DBAD1E4A5CED00E5ABD4 /* CommandProtocol.swift in Sources */,
|
F7B5DBAD1E4A5CED00E5ABD4 /* Command.swift in Sources */,
|
||||||
F7B5DBB31E4A82EB00E5ABD4 /* MessagePart.swift in Sources */,
|
F7B5DBB31E4A82EB00E5ABD4 /* MessagePart.swift in Sources */,
|
||||||
|
F7B5DBC91E4A8CF000E5ABD4 /* Response.swift in Sources */,
|
||||||
F738F5151E4A2CF6005680A2 /* RegisterResponse.swift in Sources */,
|
F738F5151E4A2CF6005680A2 /* RegisterResponse.swift in Sources */,
|
||||||
F738F5201E4A2DDD005680A2 /* CommandHeader.swift in Sources */,
|
F738F5201E4A2DDD005680A2 /* CommandHeader.swift in Sources */,
|
||||||
F738F5141E4A2CF6005680A2 /* RegisterRequest.swift in Sources */,
|
F738F5141E4A2CF6005680A2 /* RegisterRequest.swift in Sources */,
|
||||||
|
@ -819,7 +820,6 @@
|
||||||
F738F5111E4A2CF6005680A2 /* AuthenticationRequest.swift in Sources */,
|
F738F5111E4A2CF6005680A2 /* AuthenticationRequest.swift in Sources */,
|
||||||
F738F5291E4A2E57005680A2 /* DataWriter.swift in Sources */,
|
F738F5291E4A2E57005680A2 /* DataWriter.swift in Sources */,
|
||||||
F738F5171E4A2CF6005680A2 /* VersionResponse.swift in Sources */,
|
F738F5171E4A2CF6005680A2 /* VersionResponse.swift in Sources */,
|
||||||
F738F5221E4A2DDD005680A2 /* MessageProtocol.swift in Sources */,
|
|
||||||
F738F5131E4A2CF6005680A2 /* ErrorResponse.swift in Sources */,
|
F738F5131E4A2CF6005680A2 /* ErrorResponse.swift in Sources */,
|
||||||
F738F5121E4A2CF6005680A2 /* AuthenticationResponse.swift in Sources */,
|
F738F5121E4A2CF6005680A2 /* AuthenticationResponse.swift in Sources */,
|
||||||
F738F5161E4A2CF6005680A2 /* VersionRequest.swift in Sources */,
|
F738F5161E4A2CF6005680A2 /* VersionRequest.swift in Sources */,
|
||||||
|
@ -839,14 +839,14 @@
|
||||||
F7B5DBB01E4A827000E5ABD4 /* RawConvertible.swift in Sources */,
|
F7B5DBB01E4A827000E5ABD4 /* RawConvertible.swift in Sources */,
|
||||||
F7B5DBB41E4A83D900E5ABD4 /* MessagePart.swift in Sources */,
|
F7B5DBB41E4A83D900E5ABD4 /* MessagePart.swift in Sources */,
|
||||||
F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */,
|
F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */,
|
||||||
F7B5DBB11E4A827400E5ABD4 /* CommandProtocol.swift in Sources */,
|
F7B5DBB11E4A827400E5ABD4 /* Command.swift in Sources */,
|
||||||
F738F5411E4A2ED6005680A2 /* ResponseTests.swift in Sources */,
|
F738F5411E4A2ED6005680A2 /* ResponseTests.swift in Sources */,
|
||||||
F738F5431E4A2F91005680A2 /* CommandHeader.swift in Sources */,
|
F738F5431E4A2F91005680A2 /* CommandHeader.swift in Sources */,
|
||||||
F738F5441E4A2F91005680A2 /* CommandTrailer.swift in Sources */,
|
F738F5441E4A2F91005680A2 /* CommandTrailer.swift in Sources */,
|
||||||
|
F7B5DBCA1E4A8CF000E5ABD4 /* Response.swift in Sources */,
|
||||||
F738F5541E4A2FF0005680A2 /* Constants.swift in Sources */,
|
F738F5541E4A2FF0005680A2 /* Constants.swift in Sources */,
|
||||||
F738F5401E4A2ED6005680A2 /* CommandTrailerTests.swift in Sources */,
|
F738F5401E4A2ED6005680A2 /* CommandTrailerTests.swift in Sources */,
|
||||||
F7B5DBC31E4A85EB00E5ABD4 /* VersionRequestTests.swift in Sources */,
|
F7B5DBC31E4A85EB00E5ABD4 /* VersionRequestTests.swift in Sources */,
|
||||||
F738F5451E4A2F91005680A2 /* MessageProtocol.swift in Sources */,
|
|
||||||
F738F5501E4A2F9E005680A2 /* DataWriter.swift in Sources */,
|
F738F5501E4A2F9E005680A2 /* DataWriter.swift in Sources */,
|
||||||
F738F5491E4A2F91005680A2 /* AuthenticationResponse.swift in Sources */,
|
F738F5491E4A2F91005680A2 /* AuthenticationResponse.swift in Sources */,
|
||||||
F738F5481E4A2F91005680A2 /* AuthenticationRequest.swift in Sources */,
|
F738F5481E4A2F91005680A2 /* AuthenticationRequest.swift in Sources */,
|
||||||
|
|
|
@ -46,45 +46,33 @@ class U2FAuthenticator {
|
||||||
func installMsgHandler() {
|
func installMsgHandler() {
|
||||||
u2fhid.handle(.Msg) { (_ msg: softu2f_hid_message) -> Bool in
|
u2fhid.handle(.Msg) { (_ msg: softu2f_hid_message) -> Bool in
|
||||||
let data = msg.data.takeUnretainedValue() as Data
|
let data = msg.data.takeUnretainedValue() as Data
|
||||||
let cmd: APDU.Command
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
cmd = try APDU.Command(raw: data)
|
let ins = try APDU.commandType(raw: data)
|
||||||
|
|
||||||
|
switch ins {
|
||||||
|
case .Register:
|
||||||
|
try self.handleRegisterRequest(data, cid: msg.cid)
|
||||||
|
case .Authenticate:
|
||||||
|
try self.handleAuthenticationRequest(data, cid: msg.cid)
|
||||||
|
case .Version:
|
||||||
|
try self.handleVersionRequest(data, cid: msg.cid)
|
||||||
|
default:
|
||||||
|
self.sendError(status: .InsNotSupported, cid: msg.cid)
|
||||||
|
}
|
||||||
} catch let err as APDU.ResponseStatus {
|
} catch let err as APDU.ResponseStatus {
|
||||||
self.sendError(status: err, cid: msg.cid)
|
self.sendError(status: err, cid: msg.cid)
|
||||||
return true
|
|
||||||
} catch {
|
} catch {
|
||||||
self.sendError(status: .OtherError, cid: msg.cid)
|
self.sendError(status: .OtherError, cid: msg.cid)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print("↓↓↓↓↓ Received message ↓↓↓↓↓")
|
|
||||||
cmd.debug()
|
|
||||||
print("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n")
|
|
||||||
|
|
||||||
if let req = cmd.registerRequest {
|
|
||||||
self.handleRegisterRequest(req, cid: msg.cid)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if let req = cmd.authenticationRequest {
|
|
||||||
if let control = APDU.Control(rawValue: cmd.header.p1) {
|
|
||||||
self.handleAuthenticationRequest(req, control: control, cid: msg.cid)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let req = cmd.versionRequest {
|
|
||||||
self.handleVersionRequest(req, cid: msg.cid)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
self.sendError(status: .OtherError, cid: msg.cid)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRegisterRequest(_ req: APDU.RegisterRequest, cid: UInt32) {
|
func handleRegisterRequest(_ raw: Data, cid: UInt32) throws {
|
||||||
|
let req = try APDU.RegisterRequest(raw: raw)
|
||||||
|
|
||||||
let facet = KnownFacets[req.applicationParameter]
|
let facet = KnownFacets[req.applicationParameter]
|
||||||
let notification = UserPresence.Notification.Register(facet: facet)
|
let notification = UserPresence.Notification.Register(facet: facet)
|
||||||
|
|
||||||
|
@ -127,13 +115,15 @@ class U2FAuthenticator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAuthenticationRequest(_ req: APDU.AuthenticationRequest, control: APDU.Control, cid: UInt32) {
|
func handleAuthenticationRequest(_ raw: Data, cid: UInt32) throws {
|
||||||
|
let req = try APDU.AuthenticationRequest(raw: raw)
|
||||||
|
|
||||||
guard let reg = U2FRegistration(keyHandle: req.keyHandle, applicationParameter: req.applicationParameter) else {
|
guard let reg = U2FRegistration(keyHandle: req.keyHandle, applicationParameter: req.applicationParameter) else {
|
||||||
sendError(status: .WrongData, cid: cid)
|
sendError(status: .WrongData, cid: cid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if control == .CheckOnly {
|
if req.control == .CheckOnly {
|
||||||
// success -> error response. It's weird...
|
// success -> error response. It's weird...
|
||||||
sendError(status: .ConditionsNotSatisfied, cid: cid)
|
sendError(status: .ConditionsNotSatisfied, cid: cid)
|
||||||
return
|
return
|
||||||
|
@ -170,7 +160,8 @@ class U2FAuthenticator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleVersionRequest(_ req: APDU.VersionRequest, cid: UInt32) {
|
func handleVersionRequest(_ raw: Data, cid: UInt32) throws {
|
||||||
|
let _ = try APDU.VersionRequest(raw: raw)
|
||||||
let resp = APDU.VersionResponse(version: "U2F_V2")
|
let resp = APDU.VersionResponse(version: "U2F_V2")
|
||||||
sendMsg(msg: resp, cid: cid)
|
sendMsg(msg: resp, cid: cid)
|
||||||
}
|
}
|
||||||
|
@ -180,14 +171,7 @@ class U2FAuthenticator {
|
||||||
sendMsg(msg: resp, cid: cid)
|
sendMsg(msg: resp, cid: cid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendMsg(msg: APDU.MessageProtocol, cid: UInt32) {
|
func sendMsg(msg: APDU.RawConvertible, cid: UInt32) {
|
||||||
if u2fhid.sendMsg(cid: cid, data: msg.raw) {
|
let _ = u2fhid.sendMsg(cid: cid, data: msg.raw)
|
||||||
print("↓↓↓↓↓ Sent message ↓↓↓↓↓")
|
|
||||||
} else {
|
|
||||||
print("↓↓↓↓↓ Error sending message ↓↓↓↓↓")
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.debug()
|
|
||||||
print("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,83 +7,84 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
import APDU
|
||||||
|
|
||||||
@testable import SoftU2FTool
|
@testable import SoftU2FTool
|
||||||
//class IntegrationTests: SoftU2FTestCase {
|
class IntegrationTests: SoftU2FTestCase {
|
||||||
// override func tearDown() {
|
override func tearDown() {
|
||||||
// let _ = U2FRegistration.deleteAll()
|
let _ = U2FRegistration.deleteAll()
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// func testRegister() throws {
|
func testRegister() throws {
|
||||||
// var rc = u2fh_global_init(u2fh_initflags(rawValue: 0))
|
var rc = u2fh_global_init(u2fh_initflags(rawValue: 0))
|
||||||
//// var rc = u2fh_global_init(U2FH_DEBUG)
|
// var rc = u2fh_global_init(U2FH_DEBUG)
|
||||||
// XCTAssertEqual(rc.name, U2FH_OK.name)
|
XCTAssertEqual(rc.name, U2FH_OK.name)
|
||||||
// defer { u2fh_global_done() }
|
defer { u2fh_global_done() }
|
||||||
//
|
|
||||||
//
|
|
||||||
// var devs: OpaquePointer? = nil
|
var devs: OpaquePointer? = nil
|
||||||
// rc = u2fh_devs_init(&devs)
|
rc = u2fh_devs_init(&devs)
|
||||||
// XCTAssertEqual(rc.name, U2FH_OK.name)
|
XCTAssertEqual(rc.name, U2FH_OK.name)
|
||||||
// XCTAssertNotNil(devs)
|
XCTAssertNotNil(devs)
|
||||||
// defer { u2fh_devs_done(devs) }
|
defer { u2fh_devs_done(devs) }
|
||||||
//
|
|
||||||
// var maxIdx = UInt32(0xFFFFFFFF)
|
var maxIdx = UInt32(0xFFFFFFFF)
|
||||||
// while u2fh_devs_discover(devs, &maxIdx) == U2FH_NO_U2F_DEVICE {
|
while u2fh_devs_discover(devs, &maxIdx) == U2FH_NO_U2F_DEVICE {
|
||||||
// u2fh_devs_done(devs)
|
u2fh_devs_done(devs)
|
||||||
// sleep(1)
|
sleep(1)
|
||||||
//
|
|
||||||
// rc = u2fh_devs_init(&devs)
|
rc = u2fh_devs_init(&devs)
|
||||||
// XCTAssertEqual(rc.name, U2FH_OK.name)
|
XCTAssertEqual(rc.name, U2FH_OK.name)
|
||||||
// XCTAssertNotNil(devs)
|
XCTAssertNotNil(devs)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// XCTAssertEqual(rc.name, U2FH_OK.name)
|
XCTAssertEqual(rc.name, U2FH_OK.name)
|
||||||
// XCTAssertEqual(maxIdx, 0)
|
XCTAssertEqual(maxIdx, 0)
|
||||||
//
|
|
||||||
// let appId = "https://github.com/u2f/trusted_facets"
|
let appId = "https://github.com/u2f/trusted_facets"
|
||||||
// let challenge = "VA-qf-tVVQVuPmNI4U2_ShZNYgvaaHnMPp_EnL2dNWY"
|
let challenge = "VA-qf-tVVQVuPmNI4U2_ShZNYgvaaHnMPp_EnL2dNWY"
|
||||||
// let challengeParamBytes = try JSONSerialization.data(withJSONObject: ["challenge": challenge, "version": "U2F_V2", "appId": appId])
|
let challengeParamBytes = try JSONSerialization.data(withJSONObject: ["challenge": challenge, "version": "U2F_V2", "appId": appId])
|
||||||
// let challengeParam = String(bytes: challengeParamBytes, encoding: .utf8)!
|
let challengeParam = String(bytes: challengeParamBytes, encoding: .utf8)!
|
||||||
// var respPtr: UnsafeMutablePointer<Int8>? = nil
|
var respPtr: UnsafeMutablePointer<Int8>? = nil
|
||||||
//
|
|
||||||
// rc = u2fh_register(devs, challengeParam, appId, &respPtr, U2FH_REQUEST_USER_PRESENCE)
|
rc = u2fh_register(devs, challengeParam, appId, &respPtr, U2FH_REQUEST_USER_PRESENCE)
|
||||||
// XCTAssertEqual(rc.name, U2FH_OK.name)
|
XCTAssertEqual(rc.name, U2FH_OK.name)
|
||||||
//
|
|
||||||
// if respPtr == nil {
|
if respPtr == nil {
|
||||||
// XCTFail("Expected registration response")
|
XCTFail("Expected registration response")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// let respStr = String(cString: respPtr!)
|
let respStr = String(cString: respPtr!)
|
||||||
//
|
|
||||||
// guard let respData = respStr.data(using: .utf8) else {
|
guard let respData = respStr.data(using: .utf8) else {
|
||||||
// XCTFail("Expected response to utf8 encoded")
|
XCTFail("Expected response to utf8 encoded")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// let respJSON = try JSONSerialization.jsonObject(with: respData, options: JSONSerialization.ReadingOptions.init(rawValue: 0))
|
let respJSON = try JSONSerialization.jsonObject(with: respData, options: JSONSerialization.ReadingOptions.init(rawValue: 0))
|
||||||
//
|
|
||||||
// guard let respDict = respJSON as? [String: String] else {
|
guard let respDict = respJSON as? [String: String] else {
|
||||||
// XCTFail("Expected response to be dictionary")
|
XCTFail("Expected response to be dictionary")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// guard let regDataStr = respDict["registrationData"] else {
|
guard let regDataStr = respDict["registrationData"] else {
|
||||||
// XCTFail("Expected response dictionary to include registrationData member")
|
XCTFail("Expected response dictionary to include registrationData member")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// guard let regData = WebSafeBase64.decode(regDataStr) else {
|
guard let regData = WebSafeBase64.decode(regDataStr) else {
|
||||||
// XCTFail("Expected response registrationData member to be b64 encoded")
|
XCTFail("Expected response registrationData member to be b64 encoded")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // TODO: this fails because we include the APDU trailer in the RegisterResponse....
|
// TODO: this fails because we include the APDU trailer in the RegisterResponse....
|
||||||
// let regResp = try RegisterResponse(raw: regData)
|
let regResp = try APDU.RegisterResponse(raw: regData, bodyOnly: true)
|
||||||
//
|
|
||||||
// guard let _ = U2FRegistration(keyHandle: regResp.keyHandle, applicationParameter: randData()) else {
|
guard let _ = U2FRegistration(keyHandle: regResp.keyHandle, applicationParameter: randData()) else {
|
||||||
// XCTFail("Expected key handle from response to match registration")
|
XCTFail("Expected key handle from response to match registration")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
|
@ -10,39 +10,38 @@ import XCTest
|
||||||
@testable import SoftU2FTool
|
@testable import SoftU2FTool
|
||||||
|
|
||||||
func tupleDigestEqual(_ a: SHA256.TupleDigest, _ b: SHA256.TupleDigest) -> Bool {
|
func tupleDigestEqual(_ a: SHA256.TupleDigest, _ b: SHA256.TupleDigest) -> Bool {
|
||||||
return
|
return a.0 == b.0 &&
|
||||||
a.0 == b.0 &&
|
a.1 == b.1 &&
|
||||||
a.1 == b.1 &&
|
a.2 == b.2 &&
|
||||||
a.2 == b.2 &&
|
a.3 == b.3 &&
|
||||||
a.3 == b.3 &&
|
a.4 == b.4 &&
|
||||||
a.4 == b.4 &&
|
a.5 == b.5 &&
|
||||||
a.5 == b.5 &&
|
a.6 == b.6 &&
|
||||||
a.6 == b.6 &&
|
a.7 == b.7 &&
|
||||||
a.7 == b.7 &&
|
a.8 == b.8 &&
|
||||||
a.8 == b.8 &&
|
a.9 == b.9 &&
|
||||||
a.9 == b.9 &&
|
a.10 == b.10 &&
|
||||||
a.10 == b.10 &&
|
a.11 == b.11 &&
|
||||||
a.11 == b.11 &&
|
a.12 == b.12 &&
|
||||||
a.12 == b.12 &&
|
a.13 == b.13 &&
|
||||||
a.13 == b.13 &&
|
a.14 == b.14 &&
|
||||||
a.14 == b.14 &&
|
a.15 == b.15 &&
|
||||||
a.15 == b.15 &&
|
a.16 == b.16 &&
|
||||||
a.16 == b.16 &&
|
a.17 == b.17 &&
|
||||||
a.17 == b.17 &&
|
a.18 == b.18 &&
|
||||||
a.18 == b.18 &&
|
a.19 == b.19 &&
|
||||||
a.19 == b.19 &&
|
a.20 == b.20 &&
|
||||||
a.20 == b.20 &&
|
a.21 == b.21 &&
|
||||||
a.21 == b.21 &&
|
a.22 == b.22 &&
|
||||||
a.22 == b.22 &&
|
a.23 == b.23 &&
|
||||||
a.23 == b.23 &&
|
a.24 == b.24 &&
|
||||||
a.24 == b.24 &&
|
a.25 == b.25 &&
|
||||||
a.25 == b.25 &&
|
a.26 == b.26 &&
|
||||||
a.26 == b.26 &&
|
a.27 == b.27 &&
|
||||||
a.27 == b.27 &&
|
a.28 == b.28 &&
|
||||||
a.28 == b.28 &&
|
a.29 == b.29 &&
|
||||||
a.29 == b.29 &&
|
a.30 == b.30 &&
|
||||||
a.30 == b.30 &&
|
a.31 == b.31
|
||||||
a.31 == b.31
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func randData(maxLen: Int = 4096) -> Data {
|
func randData(maxLen: Int = 4096) -> Data {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче