account.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //
  2. // account.swift
  3. // 74 桌
  4. //
  5. // Created by yunli on 2023/5/20.
  6. //
  7. import Alamofire
  8. import SwiftUI
  9. struct Constant {
  10. var cookiesDefaultsKey: String
  11. }
  12. let Constants: Constant = .init(cookiesDefaultsKey: "JSESSIONID")
  13. class CookieHandler {
  14. static let shared: CookieHandler = .init()
  15. let defaults = UserDefaults.standard
  16. let cookieStorage = HTTPCookieStorage.shared
  17. func getCookie(forURL url: String) -> [HTTPCookie] {
  18. let computedUrl = URL(string: url)
  19. let cookies = cookieStorage.cookies(for: computedUrl!) ?? []
  20. return cookies
  21. }
  22. func backupCookies(forURL url: String) {
  23. var cookieDict = [String: AnyObject]()
  24. for cookie in getCookie(forURL: url) {
  25. cookieDict[cookie.name] = cookie.properties as AnyObject?
  26. }
  27. defaults.set(cookieDict, forKey: Constants.cookiesDefaultsKey)
  28. }
  29. func restoreCookies() {
  30. if let cookieDictionary = defaults.dictionary(forKey: Constants.cookiesDefaultsKey) {
  31. for (_, cookieProperties) in cookieDictionary {
  32. if let cookie = HTTPCookie(properties: cookieProperties as! [HTTPCookiePropertyKey: Any]) {
  33. cookieStorage.setCookie(cookie)
  34. }
  35. }
  36. }
  37. }
  38. }
  39. struct Login: Encodable {
  40. let user: String
  41. let pwd: String
  42. let cook: String
  43. }
  44. struct UserInfo: Encodable {
  45. var name: String
  46. var o: String
  47. }
  48. class LoginHandler {
  49. static let sharedInstance = LoginHandler()
  50. func getCookie(name: String) -> HTTPCookie? {
  51. if let cookie = CookieHandler().getCookie(forURL: "https://debug.sdsz.icu:81/").filter({ cookie -> Bool in
  52. cookie.name == name
  53. }).first {
  54. return cookie
  55. }
  56. return nil
  57. }
  58. func fetchLoginCookie(action: @escaping (_: String) -> Void) {
  59. if let cookie = getCookie(name: "JSESSIONID") {
  60. HTTPCookieStorage.shared.deleteCookie(cookie)
  61. print(cookie)
  62. }
  63. let url = "https://debug.sdsz.icu:81/sso/login"
  64. AF.request(url, method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).response { _ in
  65. if let cookie = self.getCookie(name: "JSESSIONID") {
  66. action(cookie.value)
  67. }
  68. }
  69. }
  70. }
  71. class FetchHandler {
  72. static let sharedInstance = FetchHandler()
  73. func matches(url: String) -> Bool {
  74. do {
  75. return try url.matches(of: Regex(#"(^\[\]$|param":"|"workRests"|<tr>|DOCTYPE|in\?username=|requestParams|\"newmessage\"|Sorry, Page Not Found|北师大实验中学--登录|404 Not Found|502 Bad Gateway)"#)).count != 0
  76. } catch {
  77. return true
  78. }
  79. }
  80. func getUrl(url: String) -> String {
  81. var ret: String = url
  82. print("PRE: \(ret)")
  83. ret = ret
  84. .replacing("dd.sdsz.com.cn", with: "debug.sdsz.icu:81")
  85. .replacing(/^http:/, with: "https:")
  86. .replacing("service=http%3A%2F%2Fdebug.sdsz.icu:81", with: "service=http%3A%2F%2Fdd.sdsz.com.cn")
  87. print("AFTER: \(ret)")
  88. return ret
  89. }
  90. func workFetch(url: String, action: @escaping (_: String) -> Void) {
  91. if matches(url: url) {
  92. action(url)
  93. } else {
  94. AF.request(getUrl(url: url), method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseString { res in
  95. print(res)
  96. if let resv = res.value {
  97. self.workFetch(url: resv, action: action)
  98. }
  99. }
  100. }
  101. }
  102. func fetchAny(url: String, action: @escaping (_: String) -> Void) {
  103. let urlFull = "https://debug.sdsz.icu:81/\(url)"
  104. workFetch(url: urlFull, action: action)
  105. }
  106. }
  107. func doLogin(user: String, password: String, action: @escaping (_: Int) -> Void) {
  108. LoginHandler().fetchLoginCookie { (cookie: String) in
  109. let login = Login(user: user, pwd: password, cook: cookie)
  110. print(login)
  111. AF.request("https://debug.sdsz.icu/andlogin", method: .post, parameters: login, encoder: JSONParameterEncoder.default, headers: nil).responseString { res in
  112. print("\(res)")
  113. if res.value == "success" {
  114. action(1)
  115. } else {
  116. action(0)
  117. }
  118. }
  119. }
  120. }
  121. struct DecodableType: Decodable { let url: String }
  122. func getUserInfo(action: @escaping (_: UserInfo) -> Void) {
  123. FetchHandler().fetchAny(url: "bxn-portal/portal/osforstudent/index") { res in
  124. var userInfo: UserInfo = .init(name: "", o: "")
  125. if let name = res.firstMatch(of: /userFullName" value="(.*?)"/) {
  126. userInfo.name = "\(name.1)"
  127. }
  128. if let name = res.firstMatch(of: /userId" value="(.*?)"/) {
  129. userInfo.o = "\(name.1)"
  130. }
  131. action(userInfo)
  132. }
  133. }
  134. struct loginView: View {
  135. @State var username: String = ""
  136. @State var password: String = ""
  137. @State var btnText: String = "登录"
  138. @State var btnColor: Color = .blue
  139. @State var inProgress: Bool = false
  140. @FocusState private var isFocused: Bool
  141. @Binding var isLoggedIn: Int
  142. @Binding var userInfo: UserInfo
  143. var body: some View {
  144. VStack {
  145. Form {
  146. List {
  147. HStack {
  148. Image(systemName: "person.fill").foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7))
  149. TextField(text: $username, prompt: Text("数字校园号")) {
  150. Text("数字校园号")
  151. }.focused($isFocused)
  152. .keyboardType(.numberPad)
  153. }
  154. HStack {
  155. Image(systemName: "key.fill").foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7))
  156. SecureField(text: $password, prompt: Text("密码")) {
  157. Text("密码")
  158. }.focused($isFocused)
  159. }
  160. }.onTapGesture {
  161. isFocused = false
  162. }
  163. HStack {
  164. Spacer()
  165. Button(action: {
  166. inProgress = true
  167. doLogin(user: username, password: password) { (ret: Int) in
  168. isLoggedIn = ret
  169. inProgress = false
  170. if ret == 0 {
  171. btnText = "登录失败"
  172. btnColor = .red
  173. } else {
  174. getUserInfo { res in
  175. userInfo = res
  176. }
  177. }
  178. }
  179. }) {
  180. HStack {
  181. Text(btnText)
  182. if inProgress {
  183. ProgressView()
  184. } else {
  185. Image(systemName: "chevron.right")
  186. }
  187. }
  188. }.foregroundColor(btnColor).buttonStyle(.bordered)
  189. }
  190. }
  191. }
  192. }
  193. }
  194. struct accountView: View {
  195. @State var username: String = ""
  196. @State var password: String = ""
  197. @FocusState private var isFocused: Bool
  198. @Binding var isLoggedIn: Int
  199. @Binding var userInfo: UserInfo
  200. var body: some View {
  201. VStack {
  202. Form {
  203. Section(header: Text("基本信息")) {
  204. HStack {
  205. Text("姓名")
  206. Spacer()
  207. Text(userInfo.name)
  208. }
  209. HStack {
  210. Text("内部 ID")
  211. Spacer()
  212. Text(userInfo.o)
  213. }
  214. }
  215. Section {
  216. Button(action: {
  217. isLoggedIn = 0
  218. if let cookie = LoginHandler().getCookie(name: "CASTGC") {
  219. HTTPCookieStorage.shared.deleteCookie(cookie)
  220. print(cookie)
  221. }
  222. }) {
  223. VStack {
  224. Text("退出").foregroundColor(.red)
  225. }
  226. }
  227. }
  228. }
  229. Spacer()
  230. }
  231. }
  232. }
  233. struct accountView_Previews: PreviewProvider {
  234. @State static var isLoggedIn = 0
  235. @State static var userInfo: UserInfo = .init(name: "", o: "")
  236. static var previews: some View {
  237. loginView(isLoggedIn: $isLoggedIn, userInfo: $userInfo)
  238. }
  239. }