|
| 1 | +import CommonCrypto |
| 2 | +import Foundation |
| 3 | + |
| 4 | +private let OAUTH_VERSION = "1.0" |
| 5 | +private let OAUTH_SIGNATURE_METHOD = "HMAC-SHA1" |
| 6 | + |
| 7 | +func authorizationHeader( |
| 8 | + for method: HTTPMethod, |
| 9 | + url: URL, |
| 10 | + parameters: [String: Any], |
| 11 | + isMediaUpload: Bool, |
| 12 | + consumerKey: String, |
| 13 | + consumerSecret: String, |
| 14 | + oauthToken: String?, |
| 15 | + oauthTokenSecret: String? |
| 16 | +) -> String { |
| 17 | + var authorizationParameters = [String: Any]() |
| 18 | + authorizationParameters["oauth_version"] = OAUTH_VERSION |
| 19 | + authorizationParameters["oauth_signature_method"] = OAUTH_SIGNATURE_METHOD |
| 20 | + authorizationParameters["oauth_consumer_key"] = consumerKey |
| 21 | + authorizationParameters["oauth_timestamp"] = String(Int(Date().timeIntervalSince1970)) |
| 22 | + authorizationParameters["oauth_nonce"] = UUID().uuidString |
| 23 | + |
| 24 | + if let oauthToken = oauthToken { |
| 25 | + authorizationParameters["oauth_token"] = oauthToken |
| 26 | + } |
| 27 | + |
| 28 | + for (key, value) in parameters where key.hasPrefix("oauth_") { |
| 29 | + authorizationParameters.updateValue(value, forKey: key) |
| 30 | + } |
| 31 | + |
| 32 | + let combinedParameters = authorizationParameters.merging(parameters) { $1 } |
| 33 | + |
| 34 | + let finalParameters = isMediaUpload ? authorizationParameters : combinedParameters |
| 35 | + |
| 36 | + authorizationParameters["oauth_signature"] = oauthSignature( |
| 37 | + for: method, url: url, parameters: finalParameters, consumerSecret: consumerSecret, |
| 38 | + oauthTokenSecret: oauthTokenSecret) |
| 39 | + |
| 40 | + let authorizationParameterComponents = authorizationParameters.urlEncodedQueryString.components( |
| 41 | + separatedBy: "&" |
| 42 | + ).sorted() |
| 43 | + |
| 44 | + var headerComponents = [String]() |
| 45 | + for component in authorizationParameterComponents { |
| 46 | + let subcomponent = component.components(separatedBy: "=") |
| 47 | + if subcomponent.count == 2 { |
| 48 | + headerComponents.append("\(subcomponent[0])=\"\(subcomponent[1])\"") |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + return "OAuth " + headerComponents.joined(separator: ", ") |
| 53 | +} |
| 54 | + |
| 55 | +private func oauthSignature( |
| 56 | + for method: HTTPMethod, |
| 57 | + url: URL, |
| 58 | + parameters: [String: Any], |
| 59 | + consumerSecret: String, |
| 60 | + oauthTokenSecret: String? |
| 61 | +) -> String { |
| 62 | + let tokenSecret = oauthTokenSecret?.urlEncodedString ?? "" |
| 63 | + let encodedConsumerSecret = consumerSecret.urlEncodedString |
| 64 | + let signingKey = "\(encodedConsumerSecret)&\(tokenSecret)" |
| 65 | + let parameterComponents = parameters.urlEncodedQueryString.components(separatedBy: "&").sorted() |
| 66 | + let parameterString = parameterComponents.joined(separator: "&") |
| 67 | + let encodedParameterString = parameterString.urlEncodedString |
| 68 | + let encodedURL = url.absoluteString.urlEncodedString |
| 69 | + let signatureBaseString = "\(method.rawValue)&\(encodedURL)&\(encodedParameterString)" |
| 70 | + |
| 71 | + let key = signingKey.data(using: .utf8)! |
| 72 | + let msg = signatureBaseString.data(using: .utf8)! |
| 73 | + let sha1 = msg.hmac(key: key) |
| 74 | + return sha1.base64EncodedString(options: []) |
| 75 | +} |
0 commit comments