Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: fix Weibo UniversalLink OAuth #210

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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: 3 additions & 3 deletions Sources/MonkeyKing/MonkeyKing+Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -492,15 +492,15 @@ extension MonkeyKing {
["transferObject": NSKeyedArchiver.archivedData(withRootObject: dict)],
["app": appData],
]
UIPasteboard.general.items = messageData


guard let url = weiboSchemeLink(uuidString: uuidString) else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}
UIPasteboard.general.items = messageData

if account.universalLink != nil,
let ulURL = weiboUniversalLink(query: url.query) {
let ulURL = weiboUniversalLink(query: url.query, authItems: [:]) {
shared.openURL(ulURL, options: [.universalLinksOnly: true]) { succeed in
if !succeed {
fallbackToScheme(url: url, completionHandler: completionHandler)
Expand Down
189 changes: 98 additions & 91 deletions Sources/MonkeyKing/MonkeyKing+OAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import UIKit

extension MonkeyKing {

public class func oauth(for platform: SupportedPlatform, scope: String? = nil, requestToken: String? = nil, dataString: String? = nil, completionHandler: @escaping OAuthCompletionHandler) {
guard platform.isAppInstalled || platform.canWebOAuth else {
completionHandler(.failure(.noApp))
Expand All @@ -12,45 +12,45 @@ extension MonkeyKing {
completionHandler(.failure(.noAccount))
return
}

iblacksun marked this conversation as resolved.
Show resolved Hide resolved
shared.oauthCompletionHandler = completionHandler
shared.payCompletionHandler = nil
shared.deliverCompletionHandler = nil
shared.openSchemeCompletionHandler = nil

switch account {
case .alipay(let appID):

guard let dataStr = dataString else {
completionHandler(.failure(.apiRequest(.missingParameter)))
return
}

let appUrlScheme = "apoauth" + appID
let resultDic: [String: String] = ["fromAppUrlScheme": appUrlScheme, "requestType": "SafePay", "dataString": dataStr]

guard var resultStr = resultDic.toString else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

resultStr = resultStr.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: " ", with: "")
resultStr = resultStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? resultStr
resultStr = "alipay://alipayclient/?" + resultStr

guard let url = URL(string: resultStr) else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

shared.openURL(url) { flag in
if flag { return }
completionHandler(.failure(.sdk(.invalidURLScheme)))
}

case .weChat(let appID, _, _, let universalLink):
let scope = scope ?? "snsapi_userinfo"

if !platform.isAppInstalled {
// SMS OAuth
// uid??
Expand All @@ -65,7 +65,7 @@ extension MonkeyKing {
]
return urlComponents
}

var urlComponents = defaultURLComponents()
var wxUrlOptions = [UIApplication.OpenExternalURLOptionsKey : Any]()

Expand All @@ -76,16 +76,16 @@ extension MonkeyKing {
URLQueryItem(name: "scope", value: scope),
URLQueryItem(name: "state", value: "Weixinauth"), // Weixinauth instead?
])

shared.setPasteboard(of: appID, with: [
"universalLink": universalLink,
"isAuthResend": false,
"command": "0"
])

wxUrlOptions[.universalLinksOnly] = true
}

handleWeChatAuth(
urlComponents,
defaultURLComponents(),
Expand All @@ -110,17 +110,17 @@ extension MonkeyKing {
]
let data = NSKeyedArchiver.archivedData(withRootObject: dic)
UIPasteboard.general.setData(data, forPasteboardType: "com.tencent.tencent\(appID)")

var urlComponents = URLComponents(string: "mqqOpensdkSSoLogin://SSoLogin/tencent\(appID)/com.tencent.tencent\(appID)")
urlComponents?.queryItems = [
URLQueryItem(name: "generalpastboard", value: "1"),
]

guard let url = urlComponents?.url else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

shared.openURL(url) { flag in
if flag { return }
completionHandler(.failure(.sdk(.invalidURLScheme)))
Expand All @@ -132,59 +132,66 @@ extension MonkeyKing {
addWebView(withURLString: accessTokenAPI)
case .weibo(let appID, _, let redirectURL, _):
let scope = scope ?? "all"
guard !platform.isAppInstalled else {
let uuidString = UUID().uuidString
let transferObjectData = NSKeyedArchiver.archivedData(
withRootObject: [
"__class": "WBAuthorizeRequest",
"redirectURI": redirectURL,
"requestID": uuidString,
"scope": scope,
]
)
let userInfoData = NSKeyedArchiver.archivedData(
withRootObject: [
"mykey": "as you like",
"SSO_From": "SendMessageToWeiboViewController",
]
)
let appData = NSKeyedArchiver.archivedData(
withRootObject: [
"appKey": appID,
"bundleID": Bundle.main.monkeyking_bundleID ?? "",
"name": Bundle.main.monkeyking_displayName ?? "",
"universalLink": account.universalLink ?? "",
]
)
let authItems: [[String: Any]] = [
["transferObject": transferObjectData],
["userInfo": userInfoData],
["app": appData],
]
UIPasteboard.general.items = authItems

guard let url = weiboSchemeLink(uuidString: uuidString) else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

if account.universalLink != nil,
#available(iOS 10.0, *),
let ulURL = weiboUniversalLink(query: url.query) {
shared.openURL(ulURL, options: [.universalLinksOnly: true]) { succeed in
if !succeed {
fallbackToScheme(url: url, completionHandler: completionHandler)
}
}
} else {
guard platform.isAppInstalled else {
// Web OAuth
let accessTokenAPI = "https://api.weibo.com/oauth2/authorize?client_id=\(appID)&response_type=code&redirect_uri=\(redirectURL)&scope=\(scope)"
addWebView(withURLString: accessTokenAPI)
return
}
let uuidString = UUID().uuidString
let transferObject: [String: String] = [
"__class": "WBAuthorizeRequest",
"redirectURI": redirectURL,
"requestID": uuidString,
"scope": scope,
]
let transferObjectData = NSKeyedArchiver.archivedData(withRootObject: transferObject)

let userInfo: [String: String] = [
"mykey": "as you like",
"SSO_From": "SendMessageToWeiboViewController",
"sdkVersion": "3.3.4",
"startTime": Date().description
]
let userInfoData = NSKeyedArchiver.archivedData(withRootObject: userInfo)

let app: [String: String] = [
"appKey": appID,
"requestID": uuidString,
"bundleID": Bundle.main.monkeyking_bundleID ?? "",
"name": Bundle.main.monkeyking_displayName ?? "",
"uLink": account.universalLink ?? ""
]
let appData = NSKeyedArchiver.archivedData(withRootObject: app)

let pasteboardItems: [[String: Any]] = [
["transferObject": transferObjectData],
["userInfo": userInfoData],
["app": appData],
]
let authItems: [String: Any] = [
"sdkiOS16AppAttachment": app,
"sdkiOS16attachment": ["transferObject": transferObject, "userInfo": userInfo]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个新的 authItems 的兼容性如何?(针对不同 iOS 版本或不同微博版本)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为 MonkeyKing 之前 Weibo OAuth 是无效的,所以这个 MR 主要是解决这个问题,分享我没测试过。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增的 authItems 我仅在 iOS 15、16 下配合最新 Weibo App 验证过,其他 iOS 系统及 Weibo 版本未验证

]
guard let url = weiboSchemeLink(uuidString: uuidString) else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}
UIPasteboard.general.items = pasteboardItems

guard #available(iOS 10.0, *), account.universalLink != nil,
let ulURL = weiboUniversalLink(query: url.query, authItems: authItems) else {
UIPasteboard.general.items = pasteboardItems
fallbackToScheme(url: url, completionHandler: completionHandler)
return
}
shared.openURL(ulURL, options: [.universalLinksOnly: true]) { succeed in
if !succeed {
UIPasteboard.general.items = pasteboardItems
fallbackToScheme(url: url, completionHandler: completionHandler)
}

return
}
// Web OAuth
let accessTokenAPI = "https://api.weibo.com/oauth2/authorize?client_id=\(appID)&response_type=code&redirect_uri=\(redirectURL)&scope=\(scope)"
addWebView(withURLString: accessTokenAPI)

case .pocket(let appID):
guard let startIndex = appID.range(of: "-")?.lowerBound else {
return
Expand All @@ -198,12 +205,12 @@ extension MonkeyKing {
URLQueryItem(name: "request_token", value: requestToken),
URLQueryItem(name: "redirect_uri", value: redirectURLString),
]

guard let url = urlComponents?.url else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

shared.openURL(url) { flag in
if flag { return }
completionHandler(.failure(.sdk(.invalidURLScheme)))
Expand All @@ -224,20 +231,20 @@ extension MonkeyKing {
_ default: URLComponents?,
_ wxUrlOptions: [UIApplication.OpenExternalURLOptionsKey : Any],
completionHandler: @escaping OAuthCompletionHandler) {
guard let url = urlComponents?.url else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}
shared.openURL(url, options: wxUrlOptions) { flag in
if flag { return }
if wxUrlOptions.isEmpty {
completionHandler(.failure(.sdk(.invalidURLScheme)))
guard let url = urlComponents?.url else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}
handleWeChatAuth(`default`, nil, [:], completionHandler: completionHandler)
shared.openURL(url, options: wxUrlOptions) { flag in
if flag { return }
if wxUrlOptions.isEmpty {
completionHandler(.failure(.sdk(.invalidURLScheme)))
return
}
handleWeChatAuth(`default`, nil, [:], completionHandler: completionHandler)
}
}
}


private class func fallbackToScheme(url: URL, completionHandler: @escaping OAuthCompletionHandler) {
shared.openURL(url) { succeed in
if succeed {
Expand All @@ -246,12 +253,12 @@ extension MonkeyKing {
completionHandler(.failure(.sdk(.invalidURLScheme)))
}
}

public class func weChatOAuthForCode(scope: String? = nil,
state: String? = nil,
completionHandler: @escaping OAuthFromWeChatCodeCompletionHandler) {
let platform = SupportedPlatform.weChat

iblacksun marked this conversation as resolved.
Show resolved Hide resolved
guard platform.isAppInstalled || platform.canWebOAuth else {
completionHandler(.failure(.noApp))
return
Expand All @@ -260,37 +267,37 @@ extension MonkeyKing {
completionHandler(.failure(.noAccount))
return
}

shared.oauthFromWeChatCodeCompletionHandler = completionHandler

if case .weChat(let appID, _, _, let universalLink) = account {
let scope = scope ?? "snsapi_userinfo"
let state = state ?? "Weixinauth"

let items = [
URLQueryItem(name: "scope", value: scope),
URLQueryItem(name: "state", value: state),
]

guard let url = shared.wechatUniversalLink(of: "auth", items: items),
let universalLink = universalLink else {
completionHandler(.failure(.sdk(.urlEncodeFailed)))
return
}

shared.setPasteboard(of: appID, with: [
"universalLink": universalLink,
"isAuthResend": false,
"command": "0"
])

shared.openURL(url) { flag in
if flag { return }
completionHandler(.failure(.sdk(.invalidURLScheme)))
}
}
}

// Twitter Authenticate
// https://dev.twitter.com/web/sign-in/implementing
private func twitterAuthenticate(appID: String, appKey: String, redirectURL: String) {
Expand All @@ -299,7 +306,7 @@ extension MonkeyKing {
let oauthHeader = ["Authorization": oauthString]
Networking.shared.request(requestTokenAPI, method: .post, parameters: nil, encoding: .url, headers: oauthHeader) { responseData, _, _ in
if let responseData = responseData,
let requestToken = (responseData["oauth_token"] as? String) {
let requestToken = (responseData["oauth_token"] as? String) {
let loginURL = "https://api.twitter.com/oauth/authenticate?oauth_token=\(requestToken)"
MonkeyKing.addWebView(withURLString: loginURL)
}
Expand Down
Loading