Feature: support authorization for API
This commit is contained in:
parent
6835bd6224
commit
ec25648ebd
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user