// // account.swift // 74 桌 // // Created by yunli on 2023/5/20. // import Alamofire import SwiftUI struct Constant { var cookiesDefaultsKey: String } let Constants: Constant = .init(cookiesDefaultsKey: "JSESSIONID") class CookieHandler { static let shared: CookieHandler = .init() let defaults = UserDefaults.standard let cookieStorage = HTTPCookieStorage.shared func getCookie(forURL url: String) -> [HTTPCookie] { let computedUrl = URL(string: url) let cookies = cookieStorage.cookies(for: computedUrl!) ?? [] return cookies } func getAllCookie() -> [HTTPCookie] { let cookies = cookieStorage.cookies ?? [] return cookies } func delCookie() {} } struct Login: Encodable { let user: String let pwd: String let cook: String } struct UserInfo: Encodable { var name: String var o: String } class LoginHandler { static let sharedInstance = LoginHandler() func getCookie(name: String) -> [HTTPCookie] { return CookieHandler().getCookie(forURL: "https://debug.sdsz.icu:81/").filter { cookie -> Bool in cookie.name == name } } func getAllCookie(name: String) -> [HTTPCookie] { return CookieHandler().getAllCookie().filter { cookie -> Bool in cookie.name == name } } func fetchLoginCookie(action: @escaping (_: String) -> Void) { if let cookie = getCookie(name: "JSESSIONID").first { HTTPCookieStorage.shared.deleteCookie(cookie) print(cookie) } let url = "https://debug.sdsz.icu:81/sso/login" AF.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).response { _ in if let cookie = self.getCookie(name: "JSESSIONID").first { action(cookie.value) } } } } class FetchHandler { static let sharedInstance = FetchHandler() func matches(url: String) -> Bool { do { return try url.matches(of: Regex(#"(^\[\]$|param":"|"workRests"||DOCTYPE|in\?username=|requestParams|\"newmessage\"|Sorry, Page Not Found|北师大实验中学--登录|404 Not Found|502 Bad Gateway)"#)).count != 0 } catch { return true } } func getUrl(url: String) -> String { var ret: String = url ret = ret .replacing("dd.sdsz.com.cn", with: "debug.sdsz.icu:81") .replacing(/^http:/, with: "https:") .replacing("service=http%3A%2F%2Fdebug.sdsz.icu:81", with: "service=http%3A%2F%2Fdd.sdsz.com.cn") print("URL: \(ret)") return ret } func workFetch(url: String, action: @escaping (_: String) -> Void) { if matches(url: url) { action(url) } else { AF.request(getUrl(url: url), method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseString { res in if let resv = res.value { self.workFetch(url: resv, action: action) } } } } func fetchAny(url: String, action: @escaping (_: String) -> Void) { let urlFull = "https://debug.sdsz.icu:81/\(url)" workFetch(url: urlFull, action: action) } } func doLogin(user: String, password: String, action: @escaping (_: Int) -> Void) { LoginHandler().fetchLoginCookie { (cookie: String) in let login = Login(user: user, pwd: password, cook: cookie) print(login) AF.request("https://debug.sdsz.icu/andlogin", method: .post, parameters: login, encoder: JSONParameterEncoder.default, headers: nil).responseString { res in print("\(res)") if res.value == "success" { action(1) } else { action(0) } } } } struct DecodableType: Decodable { let url: String } func getUserInfo(action: @escaping (_: UserInfo) -> Void) { FetchHandler().fetchAny(url: "bxn-portal/portal/osforstudent/index") { res in var userInfo: UserInfo = .init(name: "", o: "") if let name = res.firstMatch(of: /userFullName" value="(.*?)"/) { userInfo.name = "\(name.1)" } if let name = res.firstMatch(of: /userId" value="(.*?)"/) { userInfo.o = "\(name.1)" } action(userInfo) } } struct loginView: View { @State var username: String = "" @State var password: String = "" @State var btnText: String = "登录" @State var btnColor: Color = .blue @State var inProgress: Bool = false @FocusState private var isFocused: Bool @Binding var isLoggedIn: Int @Binding var userInfo: UserInfo var body: some View { VStack { Form { List { HStack { Image(systemName: "person.fill").foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7)) TextField(text: $username, prompt: Text("数字校园号")) { Text("数字校园号") }.focused($isFocused) .keyboardType(.numberPad) } HStack { Image(systemName: "key.fill").foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7)) SecureField(text: $password, prompt: Text("密码")) { Text("密码") }.focused($isFocused) } }.onTapGesture { isFocused = false } HStack { Spacer() Button(action: { inProgress = true doLogin(user: username, password: password) { (ret: Int) in isLoggedIn = ret inProgress = false if ret == 0 { btnText = "登录失败" btnColor = .red } else { getUserInfo { res in userInfo = res } } } }) { HStack { Text(btnText) if inProgress { ProgressView() } else { Image(systemName: "chevron.right") } } }.foregroundColor(btnColor).buttonStyle(.bordered) } } } } } struct accountView: View { @State var username: String = "" @State var password: String = "" @FocusState private var isFocused: Bool @Binding var isLoggedIn: Int @Binding var userInfo: UserInfo func delAllCookie(name: String) { for cookie in LoginHandler().getAllCookie(name: name) { print(cookie) HTTPCookieStorage.shared.deleteCookie(cookie) } } var body: some View { VStack { Form { Section(header: Text("基本信息")) { HStack { Text("姓名") Spacer() Text(userInfo.name) } HStack { Text("内部 ID") Spacer() Text(userInfo.o) } } Section { Button(action: { isLoggedIn = 0 delAllCookie(name: "CASTGC") delAllCookie(name: "JSESSIONID") }) { VStack { Text("退出").foregroundColor(.red) } } } } Spacer() } } } struct accountView_Previews: PreviewProvider { @State static var isLoggedIn = 0 @State static var userInfo: UserInfo = .init(name: "", o: "") static var previews: some View { loginView(isLoggedIn: $isLoggedIn, userInfo: $userInfo) } }