Skip to content

Commit

Permalink
Merge pull request #27 from Vaultio/refactorSecurity
Browse files Browse the repository at this point in the history
 Major refactor to KeyManager + Addition of BIP32 support.
  • Loading branch information
pr0zac authored Sep 6, 2018
2 parents 71f077a + 40e010f commit 16ed0ee
Show file tree
Hide file tree
Showing 36 changed files with 2,165 additions and 708 deletions.
446 changes: 223 additions & 223 deletions EtherKit/ABI.swift

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions EtherKit/EtherKitError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum EtherKitError: Error {
case decryptionFailed
case keyNotFound
case signatureFailed
case keyDerivationFailed
}

public enum JSONRPCFailureReason {
Expand Down
80 changes: 43 additions & 37 deletions EtherKit/EtherQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,57 +204,63 @@ public final class EtherQuery {

// MARK: Mutative Requests

public func send(
using manager: EtherKeyManager,
from: Address,
public func send<T: PrivateKeyType>(
using key: T,
to: Address,
value: UInt256,
data: GeneralData? = nil,
queue: DispatchQueue = DispatchQueue.global(qos: .default),
completion: @escaping (Result<Hash, EtherKitError>) -> Void
) {
request(
networkVersion(),
transactionCount(from, blockNumber: .pending),
gasPrice()
) {
key.unlocked(queue: queue) {
switch $0 {
case let .failure(error):
completion(.failure(error))
case let .success(items):
let (network, nonce, networkGasPrice) = items
let rawTransaction = SendTransaction(
to: to,
value: value,
gasLimit: EtherQuery.DefaultGasLimit,
gasPrice: networkGasPrice,
nonce: nonce,
data: data ?? GeneralData(data: Data())
)

self.requestGasEstimate(for: rawTransaction, from: from) {
case .failure:
completion(.failure(EtherKitError.keyManagerFailed(reason: .keyNotFound)))
return
case let .success(unlockedKey):
self.request(
self.networkVersion(),
self.transactionCount(unlockedKey.publicKey.address, blockNumber: .pending),
self.gasPrice()
) {
switch $0 {
case let .failure(error):
completion(.failure(error))
case let .success(gasLimit):

let finalTransaction = SendTransaction(
to: rawTransaction.to,
value: rawTransaction.value,
gasLimit: gasLimit,
gasPrice: rawTransaction.gasPrice,
nonce: rawTransaction.nonce,
data: rawTransaction.data
case let .success(items):
let (network, nonce, networkGasPrice) = items
let rawTransaction = SendTransaction(
to: to,
value: value,
gasLimit: EtherQuery.DefaultGasLimit,
gasPrice: networkGasPrice,
nonce: nonce,
data: data ?? GeneralData(data: Data())
)

finalTransaction.sign(using: manager, with: from, network: network) {
self.requestGasEstimate(for: rawTransaction, from: unlockedKey.publicKey.address) {
switch $0 {
case let .failure(error):
completion(.failure(error))
case let .success(signature):
let request = SendRawTransactionRequest(SendRawTransactionRequest.Parameters(
data: RLPData.encode(from: finalTransaction.toRLPValue() + signature.toRLPValue())
))
self.request(request) { completion($0) }
case let .success(gasLimit):

let finalTransaction = SendTransaction(
to: rawTransaction.to,
value: rawTransaction.value,
gasLimit: gasLimit,
gasPrice: rawTransaction.gasPrice,
nonce: rawTransaction.nonce,
data: rawTransaction.data
)

finalTransaction.sign(using: unlockedKey, network: network).bimap(
success: { signature in
let request = SendRawTransactionRequest(SendRawTransactionRequest.Parameters(
data: RLPData.encode(from: finalTransaction.toRLPValue() + signature.toRLPValue())
))
self.request(request) { completion($0) }
},
failure: { $0 }
)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions EtherKit/Extensions/Array+Chunks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import Foundation
// https://stackoverflow.com/questions/26395766/swift-what-is-the-right-way-to-split-up-a-string-resulting-in-a-string-wi/38156873#38156873
extension Array {
func chunks(_ chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
Array(self[$0..<Swift.min($0 + chunkSize, self.count)])
return stride(from: 0, to: count, by: chunkSize).map {
Array(self[$0 ..< Swift.min($0 + chunkSize, self.count)])
}
}
}
14 changes: 0 additions & 14 deletions EtherKit/Extensions/Data+BitConversion.swift

This file was deleted.

12 changes: 0 additions & 12 deletions EtherKit/Extensions/Data+Conversions.swift

This file was deleted.

24 changes: 24 additions & 0 deletions EtherKit/Extensions/Data+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Data+Extensions.swift
// EtherKit
//
// Created by Cole Potrocky on 4/26/18.
//

import CryptoSwift

extension Data {
public var bits: [Bit] {
return bytes.flatMap { $0.bits() }
}

public var paddedHexString: String {
return reduce("0x") { "\($0)\(String(format: "%02x", $1))" }
}

public static func randomBytes(count: Int) -> Data {
var bytes = Data(count: count)
_ = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, count, $0) }
return bytes
}
}
32 changes: 32 additions & 0 deletions EtherKit/Extensions/Int+Bytes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Int+Bytes.swift
// EtherKit
//
// Created by Cole Potrocky on 8/13/18.
//

import Foundation

// Adapted from:
// https://stackoverflow.com/questions/29970204/split-uint32-into-uint8-in-swift
protocol ByteConvertibleType: BinaryInteger {
var bytes: Data { get }
}

extension ByteConvertibleType {
var bytes: Data {
var num = self

let size = MemoryLayout<Self>.size
let ptr = withUnsafePointer(to: &num) {
$0.withMemoryRebound(to: UInt8.self, capacity: size) {
UnsafeBufferPointer(start: $0, count: size)
}
}

return Data(bytes: [UInt8](ptr))
}
}

extension UInt16: ByteConvertibleType {}
extension UInt32: ByteConvertibleType {}
30 changes: 30 additions & 0 deletions EtherKit/KeyManager/Device.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Device.swift
// EtherKit
//
// Created by Cole Potrocky on 8/8/18.
//

import LocalAuthentication

public enum Device {
public static var hasSecureEnclave: Bool {
return !isSimulator && hasBiometricSupport
}

public static var isSimulator: Bool {
return TARGET_OS_SIMULATOR == 1
}

public static var hasBiometricSupport: Bool {
var error: NSError?
var hasBiometricSupport = LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
guard error == nil else {
guard #available(iOS 11, *) else {
return error?.code != LAError.touchIDNotAvailable.rawValue
}
return error?.code != LAError.biometryNotAvailable.rawValue
}
return hasBiometricSupport
}
}
Loading

0 comments on commit 16ed0ee

Please sign in to comment.