Initial commit

This commit is contained in:
Sven Weidauer 2021-11-01 21:56:37 +01:00
commit 74347fa8d6
4 changed files with 92 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

20
Package.swift Normal file
View file

@ -0,0 +1,20 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "SwiftHawk",
platforms: [
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6),
.iOS(.v13)
],
products: [
.library(name: "SwiftHawk", targets: ["SwiftHawk"]),
],
targets: [
.target(name: "SwiftHawk", dependencies: []),
]
)

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# SwiftHawk
[Hawk](https://github.com/mozilla/hawk) signature implementation for `URLRequest`

View file

@ -0,0 +1,62 @@
import Foundation
import CryptoKit
public struct HawkCredentials {
public var id: String
public var key: SymmetricKey
public init(id: String, key: SymmetricKey) {
self.id = id
self.key = key
}
public init(id: String, key: String) {
self.init(id: id, key: SymmetricKey(data: Data(key.utf8)))
}
}
public extension URLRequest {
mutating func sign<H: HashFunction>(credentials: HawkCredentials, hash: H.Type) {
guard let url = url else { return }
let nonce = makeNonce()
let timestamp = Int(Date().timeIntervalSince1970)
var path = url.path
if let query = url.query {
path += "?\(query)"
}
let string = "hawk.1.header\n\(timestamp)\n\(nonce)\n\(httpMethod?.uppercased() ?? "GET")\n\(path)\n\(url.host ?? "")\n\(port)\n\n\n"
var hash = HMAC<H>(key: credentials.key)
hash.update(data: Data(string.utf8))
let signature = Data(hash.finalize()).base64EncodedString(options: [])
let header = "Hawk id=\"\(credentials.id)\", ts=\"\(timestamp)\", nonce=\"\(nonce)\", mac=\"\(signature)\""
addValue(header, forHTTPHeaderField: "Authorization")
}
mutating func sign(credentials: HawkCredentials) {
self.sign(credentials: credentials, hash: SHA256.self)
}
var port: Int {
if let port = url?.port {
return port
}
switch url?.scheme {
case "http": return 80
case "https": return 443
default: return 0
}
}
func makeNonce() -> String {
SymmetricKey(size: .init(bitCount: 48)).withUnsafeBytes { ptr in
Data(ptr).base64EncodedString(options: [])
}
}
}