account.swift 8.2 KB

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