Feature: support authorization for API

This commit is contained in:
yicheng 2018-10-19 14:25:52 +08:00
parent 6835bd6224
commit ec25648ebd
2 changed files with 112 additions and 83 deletions

View File

@ -18,16 +18,35 @@ class ApiRequest{
configuration.timeoutIntervalForRequest = 604800
configuration.timeoutIntervalForResource = 604800
alamoFireManager = Alamofire.SessionManager(configuration: configuration)
}
private static func authHeader() -> HTTPHeaders? {
let secret = ConfigManager.shared.apiSecret
return (secret != nil) ? ["Authorization":"Bearer \(secret ?? "")"] : nil;
}
private static func req(
_ url: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default)
-> DataRequest {
return request(ConfigManager.apiUrl + url,
method: method,
parameters: parameters,
encoding:encoding,
headers: authHeader())
}
var trafficReq:DataRequest? = nil
var logReq:DataRequest? = nil
var alamoFireManager:SessionManager!
static func requestConfig(completeHandler:@escaping ((ClashConfig)->())){
request(ConfigManager.apiUrl + "/configs", method: .get).responseData{
req("/configs").responseData{
res in
guard let data = res.result.value else {return}
let config = ClashConfig.fromData(data)
@ -35,6 +54,86 @@ class ApiRequest{
}
}
static func requestConfigUpdate(callback:@escaping ((String?)->())){
req("/configs", method: .put).responseJSON { (res) in
if let errMSg = updateAllConfig() {
let err = String(cString: errMSg)
callback(err == "" ? nil : err)
} else {
callback("unknown error")
}
}
}
static func updateOutBoundMode(mode:ClashProxyMode, callback:@escaping ((Bool)->())) {
req("/configs", method: .put, parameters: ["mode":mode.rawValue], encoding: JSONEncoding.default)
.responseJSON{ response in
switch response.result {
case .success(_):
callback(true)
case .failure(_):
callback(false)
}
}
}
static func requestProxyGroupList(completeHandler:@escaping (([String:[String:Any]])->())){
req("/proxies").responseJSON{
res in
guard let data = res.result.value as? [String:[String:[String:Any]]] else {return}
completeHandler(data["proxies"]!)
}
}
static func updateAllowLan(allow:Bool,completeHandler:@escaping (()->())) {
req("/configs",
method: .put,
parameters: ["allow-lan":allow],
encoding: JSONEncoding.default).response{
_ in
completeHandler()
}
}
static func updateProxyGroup(group:String,selectProxy:String,callback:@escaping ((Bool)->())) {
let groupEncoded = group.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
req("/proxies/\(groupEncoded)",
method: .put,
parameters: ["name":selectProxy],
encoding: JSONEncoding.default)
.responseJSON { (response) in
callback(response.response?.statusCode == 204)
}
}
static func getAllProxyList(callback:@escaping (([String])->())) {
requestProxyGroupList { (groups) in
let lists:[String] = groups["GLOBAL"]?["all"] as? [String] ?? []
var proxyList = [String]()
for proxy in lists {
if ["Shadowsocks","Vmess"] .contains(groups[proxy]?["type"] as? String ?? ""){
proxyList.append(proxy)
}
}
callback(proxyList)
}
}
static func getProxyDelay(proxyName:String,callback:@escaping ((Int)->())) {
let proxyNameEncoded = proxyName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
req("/proxies/\(proxyNameEncoded)/delay"
, method: .get
, parameters: ["timeout":5000,"url":"http://www.gstatic.com/generate_204"])
.responseJSON { (res) in let json = JSON(res.result.value ?? [])
callback(json["delay"].int ?? Int.max)
}
}
}
// Stream Apis
extension ApiRequest {
func requestTrafficInfo(retryTimes:Int = 0, callback:@escaping ((Int,Int)->()) ){
trafficReq?.cancel()
var retry = retryTimes
@ -45,11 +144,12 @@ class ApiRequest{
trafficReq =
alamoFireManager
.request(ConfigManager.apiUrl + "/traffic")
.request(ConfigManager.apiUrl + "/traffic",
headers:ApiRequest.authHeader())
.stream {(data) in
retry = 0
if let jsonData = try? JSONSerialization.jsonObject(with: data) as? [String:Int] {
callback(jsonData!["up"] ?? 0, jsonData!["down"] ?? 0)
callback(jsonData?["up"] ?? 0, jsonData?["down"] ?? 0)
}
}.response { res in
guard let err = res.error else {return}
@ -73,7 +173,8 @@ class ApiRequest{
logReq =
alamoFireManager
.request(ConfigManager.apiUrl + "/logs?level=\(ConfigManager.selectLoggingApiLevel.rawValue)")
.request(ConfigManager.apiUrl + "/logs?level=\(ConfigManager.selectLoggingApiLevel.rawValue)",
headers:ApiRequest.authHeader())
.stream {(data) in
retry = 0
if let jsonData = try? JSONSerialization.jsonObject(with: data) as? [String:String] {
@ -94,81 +195,4 @@ class ApiRequest{
}
}
static func requestConfigUpdate(callback:@escaping ((String?)->())){
request(ConfigManager.apiUrl + "/configs", method: .put).responseJSON { (res) in
if res.response?.statusCode == 204 {
callback(nil)
} else {
if let errMSg = updateAllConfig() {
let err = String(cString: errMSg)
callback(err == "" ? nil : err)
} else {
callback("unknown error")
}
}
}
}
static func updateOutBoundMode(mode:ClashProxyMode, callback:@escaping ((Bool)->())) {
request(ConfigManager.apiUrl + "/configs", method: .put, parameters: ["mode":mode.rawValue], encoding: JSONEncoding.default)
.responseJSON{ response in
switch response.result {
case .success(_):
callback(true)
case .failure(_):
callback(false)
}
}
}
static func requestProxyGroupList(completeHandler:@escaping (([String:[String:Any]])->())){
request(ConfigManager.apiUrl + "/proxies", method: .get).responseJSON{
res in
guard let data = res.result.value as? [String:[String:[String:Any]]] else {return}
completeHandler(data["proxies"]!)
}
}
static func updateAllowLan(allow:Bool,completeHandler:@escaping (()->())) {
request(ConfigManager.apiUrl + "/configs",
method: .put,
parameters: ["allow-lan":allow],
encoding: JSONEncoding.default).response{
_ in
completeHandler()
}
}
static func updateProxyGroup(group:String,selectProxy:String,callback:@escaping ((Bool)->())) {
let groupEncoded = group.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
request(ConfigManager.apiUrl + "/proxies/\(groupEncoded)", method: .put, parameters: ["name":selectProxy], encoding: JSONEncoding.default).responseJSON { (response) in
callback(response.response?.statusCode == 204)
}
}
static func getAllProxyList(callback:@escaping (([String])->())) {
requestProxyGroupList { (groups) in
let lists:[String] = groups["GLOBAL"]?["all"] as? [String] ?? []
var proxyList = [String]()
for proxy in lists {
if ["Shadowsocks","Vmess"] .contains(groups[proxy]?["type"] as? String ?? ""){
proxyList.append(proxy)
}
}
callback(proxyList)
}
}
static func getProxyDelay(proxyName:String,callback:@escaping ((Int)->())) {
let proxyNameEncoded = proxyName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
request(ConfigManager.apiUrl + "/proxies/\(proxyNameEncoded)/delay"
, method: .get
, parameters: ["timeout":5000,"url":"http://www.gstatic.com/generate_204"])
.responseJSON { (res) in let json = JSON(res.result.value ?? [])
callback(json["delay"].int ?? Int.max)
}
}
}

View File

@ -16,8 +16,10 @@ class ConfigManager {
static let shared = ConfigManager()
private let disposeBag = DisposeBag()
var apiPort = "8080"
var apiSecret:String? = nil
private init(){
refreshApiPort()
refreshApiInfo()
setupNetworkNotifier()
}
@ -58,6 +60,7 @@ class ConfigManager {
}
}
static var selectedProxyMap:[String:String] {
get{
let map = UserDefaults.standard.dictionary(forKey: "selectedProxyMap") as? [String:String] ?? ["Proxy":"ProxyAuto"]
@ -95,8 +98,9 @@ class ConfigManager {
}
}
func refreshApiPort(){
func refreshApiInfo(){
apiPort = "7892"
apiSecret = nil;
if let yamlStr = try? String(contentsOfFile: kConfigFilePath),
var yaml = (try? Yams.load(yaml: yamlStr)) as? [String:Any] {
if let controller = yaml["external-controller"] as? String,
@ -106,6 +110,7 @@ class ConfigManager {
yaml["external-controller"] = apiPort
ConfigFileFactory.saveToClashConfigFile(config: yaml)
}
apiSecret = yaml["secret"] as? String
} else {
_ = ConfigFileFactory.replaceConfigWithSampleConfig()
}