Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion .dotfiles
Submodule .dotfiles updated 0 files
33 changes: 33 additions & 0 deletions .github/workflows/all-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Run `TwitterAPIKit` Tests

on:
pull_request:
paths:
- '*.swift'

jobs:
linux-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: swift-actions/setup-swift@v2
with:
swift-version: 5

- name: Run Unit Tests
uses: GetAutomaApp/opensource-actions/swifttesting@main
with:
compose: "false"
working-directory: "."

macos-tests:
runs-on: [macOS, self-hosted]
steps:
- uses: actions/checkout@v4

- name: Run Unit Tests
uses: GetAutomaApp/opensource-actions/swifttesting@main
with:
compose: "false"
working-directory: "."
47 changes: 0 additions & 47 deletions .github/workflows/swift.yml

This file was deleted.

1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

25 changes: 0 additions & 25 deletions Package.resolved

This file was deleted.

13 changes: 7 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

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] = []
internal let dependencies: [Package.Dependency] = []
internal let tDependencies: [Target.Dependency] = []
#else // for Linux
let dependencies: [Package.Dependency] = [.package(url: "https://github.com/apple/swift-crypto.git", from: "3.8.0")]
let tDependencies: [Target.Dependency] = [.product(name: "Crypto", package: "swift-crypto")]
internal let dependencies: [Package.Dependency] = [
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.8.0")
]
internal let tDependencies: [Target.Dependency] = [.product(name: "Crypto", package: "swift-crypto")]
#endif

let package = Package(
internal let package = Package(
name: "TwitterAPIKit",
platforms: [
.macOS(.v10_14),
Expand Down
2 changes: 2 additions & 0 deletions Sources/TwitterAPIKit/APIv1/Media/MediaAPIv1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Foundation

// swiftlint:disable function_body_length closure_body_length
open class MediaAPIv1: TwitterAPIBase {
/// For more details, see:
/// https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/
Expand Down Expand Up @@ -232,3 +233,4 @@ open class MediaAPIv1: TwitterAPIBase {
// De-init Logic Here
}
}
// swiftlint:enable function_body_length closure_body_length
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ open class UploadMediaAppendRequestV1: TwitterAPIRequest {
.multipartFormData
}

open var parameters: [String: Any] {
[
"command": command,
"media_id": mediaID,
"media": media,
"segment_index": segmentIndex,
"filename": filename,
"mime_type": mimeType
open var parameters: [String: MultipartFormDataPart] {
return [
"command": .value(name: "command", value: command),
"media_id": .value(name: "media_id", value: mediaID),
"media": .data(name: "media", value: media, filename: filename, mimeType: mimeType),
"segment_index": .value(name: "segment_index", value: segmentIndex),
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,41 @@ import Foundation
/// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/
/// post-and-engage/api-reference/get-statuses-retweeters-ids
open class GetRetweetersRequestV1: TwitterAPIRequest {
// Status ID
public let tweetID: String
public let count: Int?
public let cursor: String?
public let stringifyIDs: Bool?

public var method: HTTPMethod {
.get
return .get
}

public var path: String {
"/1.1/statuses/retweeters/ids.json"

return "/1.1/statuses/retweeters/ids.json"
}

open var parameters: [String: Any] {
var parameters = [String: Any]()
parameters["id"] = tweetID
cursor.map { parameters["cursor"] = $0 }
stringifyIDs.map { parameters["stringify_ids"] = $0 }
return parameters

var params = [String: Any]()

params["id"] = tweetID
count.map { params["count"] = $0 }
cursor.map { params["cursor"] = $0 }
stringifyIDs.map { params["stringify_ids"] = $0 }

return params
}

public init(
tweetID: String,
count: Int? = .none,
cursor: String? = .none,
stringifyIDs: Bool? = .none
) {
self.tweetID = tweetID
self.count = count
self.cursor = cursor
self.stringifyIDs = stringifyIDs
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/TwitterAPIKit/Extensions/HMAC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import Foundation
#if canImport(CommonCrypto)
import CommonCrypto

internal protocol HMAC {
// Stub Logic for `swiftlint file_name`
}

fileprivate extension Data {
func hmac(key: Data) -> Data {
// Thanks: https://github.com/jernejstrasner/SwiftCrypto
Expand Down Expand Up @@ -40,7 +44,7 @@ import Foundation
/// - key: The key to use for signing
/// - message: The message to sign
/// - Returns: The HMAC-SHA1 signature as Data
func createHMACSHA1(key: Data, message: Data) -> Data {
public func createHMACSHA1(key: Data, message: Data) -> Data {
message.hmac(key: key)
}

Expand All @@ -52,7 +56,7 @@ import Foundation
/// - key: The key to use for signing
/// - message: The message to sign
/// - Returns: The HMAC-SHA1 signature as Data
func createHMACSHA1(key: Data, message: Data) -> Data {
public func createHMACSHA1(key: Data, message: Data) -> Data {
Data(HMAC<Insecure.SHA1>.authenticationCode(for: message, using: SymmetricKey(data: key)))
}
#else
Expand Down
7 changes: 2 additions & 5 deletions Sources/TwitterAPIKit/OAuthHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
private let oauthVersion = "1.0"
private let oauthSignatureMethod = "HMAC-SHA1"

// swiftlint:disable function_parameter_count
// swiftlint:disable function_parameter_count function_body_length
/// Generates an OAuth authorization header for a given HTTP method, URL, and parameters.
/// - Parameters:
/// - method: The HTTP method to use.
Expand All @@ -35,22 +35,18 @@ public func authorizationHeader(
oauthTimestamp: String? = .none,
oauthNonce: String? = .none
) -> String {
// swiftlint:enable function_parameter_count
var authorizationParameters = [String: Any]()
authorizationParameters["oauth_version"] = oauthVersion
authorizationParameters["oauth_signature_method"] = oauthSignatureMethod
authorizationParameters["oauth_consumer_key"] = consumerKey
authorizationParameters["oauth_timestamp"] = oauthTimestamp ?? String(Int(Date().timeIntervalSince1970))
authorizationParameters["oauth_nonce"] = oauthNonce ?? UUID().uuidString

if let oauthToken {
authorizationParameters["oauth_token"] = oauthToken
}

for (key, value) in parameters where key.hasPrefix("oauth_") {
authorizationParameters.updateValue(value, forKey: key)
}

let combinedParameters = authorizationParameters.merging(parameters) { $1 }

authorizationParameters["oauth_signature"] = oauthSignature(
Expand All @@ -76,6 +72,7 @@ public func authorizationHeader(

return "OAuth " + headerComponents.joined(separator: ", ")
}
// swiftlint:enable function_parameter_count function_body_length

private func oauthSignature(
for method: HTTPMethod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class TwitterAPISessionDelegatedJSONTask: TwitterAPISessionJSONTask, Twit
taskQueue.resume()
}

// swiftlint:disable:next function_body_length
private func getResponse() -> TwitterAPIResponse<Data> {
guard completed, let data else {
fatalError("Request not completed yet.")
Expand Down
36 changes: 24 additions & 12 deletions Sources/TwitterAPIKit/TwitterAPIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,18 +134,7 @@ public extension TwitterAPIClient {
forceRefresh: Bool = false,
_ block: @escaping (Result<RefreshOAuth20TokenResultValue, TwitterAPIKitError>) -> Void
) {
guard case let .oauth20(token) = apiAuth else {
block(.failure(.refreshOAuth20TokenFailed(reason: .invalidAuthenticationMethod(apiAuth))))
return
}

guard let refreshToken = token.refreshToken else {
block(.failure(.refreshOAuth20TokenFailed(reason: .refreshTokenIsMissing)))
return
}

if !forceRefresh, !token.expired {
block(.success((token: token, refreshed: false)))
guard let (refreshToken, token) = handleBlockGuards(forceRefresh: forceRefresh, block) else {
return
}

Expand Down Expand Up @@ -177,6 +166,29 @@ public extension TwitterAPIClient {
self.refreshOAuth20TokenClient = nil
}
}

/// Handles Block Guards for `refreshOAuth20Token`
func handleBlockGuards(
forceRefresh: Bool = false,
_ block: @escaping (Result<RefreshOAuth20TokenResultValue, TwitterAPIKitError>) -> Void
) -> (String, TwitterAuthenticationMethod.OAuth20)? {
guard case let .oauth20(token) = apiAuth else {
block(.failure(.refreshOAuth20TokenFailed(reason: .invalidAuthenticationMethod(apiAuth))))
return nil
}

guard let refreshToken = token.refreshToken else {
block(.failure(.refreshOAuth20TokenFailed(reason: .refreshTokenIsMissing)))
return nil
}

if !forceRefresh, !token.expired {
block(.success((token: token, refreshed: false)))
return nil
}

return (refreshToken, token)
}
}

/// Base class for Twitter API clients.
Expand Down
2 changes: 2 additions & 0 deletions Sources/TwitterAPIKit/TwitterAPIRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ public extension TwitterAPIRequest {
}
}

// swiftlint:disable function_body_length
public extension TwitterAPIRequest {
/// Builds a URL request for the given environment.
/// - Parameters:
Expand Down Expand Up @@ -289,6 +290,7 @@ public extension TwitterAPIRequest {
return body
}
}
// swiftlint:enable function_body_length

private extension TwitterAPIEnvironment {
func baseURL(for type: TwitterBaseURLType) -> URL {
Expand Down
1 change: 1 addition & 0 deletions Sources/TwitterAPIKit/TwitterAPISession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ open class TwitterAPISession {
}
}

// swiftlint:disable:next function_body_length
private func tryBuildURLRequest(_ request: TwitterAPIRequest) throws -> URLRequest {
var urlRequest = try request.buildRequest(environment: environment)

Expand Down
Loading
Loading