Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Linux support #121

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ on:

jobs:
build:
runs-on: macos-12
name: Lint & Build swift on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-12]
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
Expand Down
18 changes: 13 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@

import PackageDescription

// Currently, CommonCrypto and CryptoKit are not available under Linux.
// If CommonCrypto is not available, swift-crypto should be used.

#if canImport(CommonCrypto)
let dependencies: [Package.Dependency] = []
let tDependencies: [Target.Dependency] = []
#else // for Linux
let dependencies: [Package.Dependency] = [.package(url: "https://github.com/apple/swift-crypto.git", from: "2.0.0")]
let tDependencies: [Target.Dependency] = [.product(name: "Crypto", package: "swift-crypto")]
#endif

let package = Package(
name: "TwitterAPIKit",
platforms: [
Expand All @@ -17,16 +28,13 @@ let package = Package(
name: "TwitterAPIKit",
targets: ["TwitterAPIKit"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
dependencies: dependencies,
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: "TwitterAPIKit",
dependencies: []),
dependencies: tDependencies),
.testTarget(
name: "TwitterAPIKitTests",
dependencies: ["TwitterAPIKit"]),
Expand Down
25 changes: 0 additions & 25 deletions Sources/TwitterAPIKit/Extensions/Data.swift
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
import CommonCrypto
import Foundation

extension Data {
func hmac(key: Data) -> Data {

// Thanks: https://github.com/jernejstrasner/SwiftCrypto

let digestLen = Int(CC_SHA1_DIGEST_LENGTH)
return withUnsafeBytes { bytes -> Data in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: digestLen)
defer {
result.deallocate()
}

key.withUnsafeBytes { body in
CCHmac(
CCHmacAlgorithm(kCCHmacAlgSHA1),
body.baseAddress,
key.count, bytes.baseAddress,
count,
result
)
}

return Data(bytes: result, count: digestLen)
}
}

func split(separator: Data, omittingEmptySubsequences: Bool = true) -> [Data] {
var current = startIndex
Expand Down
44 changes: 44 additions & 0 deletions Sources/TwitterAPIKit/Extensions/HMAC.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Foundation

#if canImport(CommonCrypto)
import CommonCrypto

extension Data {
fileprivate func hmac(key: Data) -> Data {

// Thanks: https://github.com/jernejstrasner/SwiftCrypto

let digestLen = Int(CC_SHA1_DIGEST_LENGTH)
return withUnsafeBytes { bytes -> Data in
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: digestLen)
defer {
result.deallocate()
}

key.withUnsafeBytes { body in
CCHmac(
CCHmacAlgorithm(kCCHmacAlgSHA1),
body.baseAddress,
key.count, bytes.baseAddress,
count,
result
)
}

return Data(bytes: result, count: digestLen)
}
}
}

func createHMACSHA1(key: Data, message: Data) -> Data {
return message.hmac(key: key)
}

#elseif canImport(Crypto) // for Linux
import Crypto
func createHMACSHA1(key: Data, message: Data) -> Data {
return Data(HMAC<Insecure.SHA1>.authenticationCode(for: message, using: SymmetricKey(data: key)))
}
#else
#error("Crypto is not available in this environment.")
#endif
3 changes: 1 addition & 2 deletions Sources/TwitterAPIKit/OAuthHelper.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import CommonCrypto
import Foundation

private let oauthVersion = "1.0"
Expand Down Expand Up @@ -69,6 +68,6 @@ private func oauthSignature(

let key = signingKey.data(using: .utf8)!
let msg = signatureBaseString.data(using: .utf8)!
let sha1 = msg.hmac(key: key)
let sha1 = createHMACSHA1(key: key, message: msg)
return sha1.base64EncodedString(options: [])
}
4 changes: 4 additions & 0 deletions Sources/TwitterAPIKit/TwitterAPIKit.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import Foundation

#if canImport(FoundationNetworking)
@_exported import FoundationNetworking
#endif

public enum TwitterBaseURLType {
case twitter
case api
Expand Down
10 changes: 7 additions & 3 deletions Sources/TwitterAPIKit/TwitterAPIResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,12 @@ extension String {
}

fileprivate var unescapingUnicodeCharacters: String {
let mutableString = NSMutableString(string: self)
CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true)
return mutableString as String
#if os(Linux)
return self
#else
let mutableString = NSMutableString(string: self)
CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true)
return mutableString as String
#endif
}
}