AuthMenu.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import UIKit
  15. /// Firebase Auth supported identity providers and other methods of authentication
  16. enum AuthMenu: String {
  17. case settings = "Settings"
  18. case google = "google.com"
  19. case apple = "apple.com"
  20. case twitter = "twitter.com"
  21. case microsoft = "microsoft.com"
  22. case gitHub = "github.com"
  23. case yahoo = "yahoo.com"
  24. case facebook = "facebook.com"
  25. case gameCenter = "gc.apple.com"
  26. case emailPassword = "password"
  27. case passwordless = "emailLink"
  28. case phoneNumber = "phone"
  29. case anonymous
  30. case custom
  31. case initRecaptcha
  32. case customAuthDomain
  33. case getToken
  34. case getTokenForceRefresh
  35. case addAuthStateChangeListener
  36. case removeLastAuthStateChangeListener
  37. case addIdTokenChangeListener
  38. case removeLastIdTokenChangeListener
  39. case verifyClient
  40. case deleteApp
  41. case actionType
  42. case continueURL
  43. case requestVerifyEmail
  44. case requestPasswordReset
  45. case resetPassword
  46. case checkActionCode
  47. case applyActionCode
  48. case verifyPasswordResetCode
  49. // case phoneEnroll
  50. // case totpEnroll
  51. // case multifactorUnenroll
  52. // More intuitively named getter for `rawValue`.
  53. var id: String { rawValue }
  54. // The UI friendly name of the `AuthMenu`. Used for display.
  55. var name: String {
  56. switch self {
  57. case .settings:
  58. return "Settings"
  59. case .google:
  60. return "Google"
  61. case .apple:
  62. return "Apple"
  63. case .twitter:
  64. return "Twitter"
  65. case .microsoft:
  66. return "Microsoft"
  67. case .gitHub:
  68. return "GitHub"
  69. case .yahoo:
  70. return "Yahoo"
  71. case .facebook:
  72. return "Facebook"
  73. case .gameCenter:
  74. return "Game Center"
  75. case .emailPassword:
  76. return "Email & Password Login"
  77. case .passwordless:
  78. return "Email Link/Passwordless"
  79. case .phoneNumber:
  80. return "Phone Number"
  81. case .anonymous:
  82. return "Anonymous Authentication"
  83. case .custom:
  84. return "Custom Auth System"
  85. // Recpatcha
  86. case .initRecaptcha:
  87. return "Initialize reCAPTCHA Enterprise"
  88. // Custom Auth Domain
  89. case .customAuthDomain:
  90. return "Set Custom Auth Domain"
  91. // App Section
  92. case .getToken:
  93. return "Get Token"
  94. case .getTokenForceRefresh:
  95. return "Get Token Force Refresh"
  96. case .addAuthStateChangeListener:
  97. return "Add Auth State Change Listener"
  98. case .removeLastAuthStateChangeListener:
  99. return "Remove Last Auth State Change Listener"
  100. case .addIdTokenChangeListener:
  101. return "Add ID Token Change Listener"
  102. case .removeLastIdTokenChangeListener:
  103. return "Remove Last ID Token Change Listener"
  104. case .verifyClient:
  105. return "Verify Client"
  106. case .deleteApp:
  107. return "Delete App"
  108. // OOB
  109. case .actionType:
  110. return "Action Type"
  111. case .continueURL:
  112. return "Continue URL"
  113. case .requestVerifyEmail:
  114. return "Request Verify Email"
  115. case .requestPasswordReset:
  116. return "Request Password Reset"
  117. case .resetPassword:
  118. return "Reset Password"
  119. case .checkActionCode:
  120. return "Check Action Code"
  121. case .applyActionCode:
  122. return "Apply Action Code"
  123. case .verifyPasswordResetCode:
  124. return "Verify Password Reset Code"
  125. // // Multi factor
  126. // case .phoneEnroll:
  127. // return "Phone Enroll"
  128. // case .totpEnroll:
  129. // return "TOTP Enroll"
  130. // case .multifactorUnenroll:
  131. // return "Multifactor unenroll"
  132. }
  133. }
  134. // Failable initializer to create an `AuthMenu` from its corresponding `name` value.
  135. // - Parameter rawValue: String value representing `AuthMenu`'s name or type.
  136. init?(rawValue: String) {
  137. switch rawValue {
  138. case "Settings":
  139. self = .settings
  140. case "Google":
  141. self = .google
  142. case "Apple":
  143. self = .apple
  144. case "Twitter":
  145. self = .twitter
  146. case "Microsoft":
  147. self = .microsoft
  148. case "GitHub":
  149. self = .gitHub
  150. case "Yahoo":
  151. self = .yahoo
  152. case "Facebook":
  153. self = .facebook
  154. case "Game Center":
  155. self = .gameCenter
  156. case "Email & Password Login":
  157. self = .emailPassword
  158. case "Email Link/Passwordless":
  159. self = .passwordless
  160. case "Phone Number":
  161. self = .phoneNumber
  162. case "Anonymous Authentication":
  163. self = .anonymous
  164. case "Custom Auth System":
  165. self = .custom
  166. case "Initialize reCAPTCHA Enterprise":
  167. self = .initRecaptcha
  168. case "Set Custom Auth Domain":
  169. self = .customAuthDomain
  170. case "Get Token":
  171. self = .getToken
  172. case "Get Token Force Refresh":
  173. self = .getTokenForceRefresh
  174. case "Add Auth State Change Listener":
  175. self = .addAuthStateChangeListener
  176. case "Remove Last Auth State Change Listener":
  177. self = .removeLastAuthStateChangeListener
  178. case "Add ID Token Change Listener":
  179. self = .addIdTokenChangeListener
  180. case "Remove Last ID Token Change Listener":
  181. self = .removeLastIdTokenChangeListener
  182. case "Verify Client":
  183. self = .verifyClient
  184. case "Delete App":
  185. self = .deleteApp
  186. case "Action Type":
  187. self = .actionType
  188. case "Continue URL":
  189. self = .continueURL
  190. case "Request Verify Email":
  191. self = .requestVerifyEmail
  192. case "Request Password Reset":
  193. self = .requestPasswordReset
  194. case "Reset Password":
  195. self = .resetPassword
  196. case "Check Action Code":
  197. self = .checkActionCode
  198. case "Apply Action Code":
  199. self = .applyActionCode
  200. case "Verify Password Reset Code":
  201. self = .verifyPasswordResetCode
  202. // case "Phone Enroll":
  203. // self = .phoneEnroll
  204. // case "TOTP Enroll":
  205. // self = .totpEnroll
  206. // case "Multifactor unenroll":
  207. // self = .multifactorUnenroll
  208. default:
  209. return nil
  210. }
  211. }
  212. }
  213. enum ActionCodeRequestType: String {
  214. case email
  215. case `continue`
  216. case inApp
  217. var name: String {
  218. switch self {
  219. case .email:
  220. return "Email Only"
  221. case .inApp:
  222. return "In-App + Continue URL"
  223. case .continue:
  224. return "Continue URL"
  225. }
  226. }
  227. init?(rawValue: String) {
  228. switch rawValue {
  229. case "Email Only":
  230. self = .email
  231. case "In-App + Continue URL":
  232. self = .inApp
  233. case "Continue URL":
  234. self = .continue
  235. default:
  236. return nil
  237. }
  238. }
  239. }
  240. // MARK: DataSourceProvidable
  241. class AuthMenuData: DataSourceProvidable {
  242. private static var providers: [AuthMenu] {
  243. [.google, .apple, .twitter, .microsoft, .gitHub, .yahoo, .facebook, .gameCenter]
  244. }
  245. static var settingsSection: Section {
  246. let header = "Auth Settings"
  247. let item = Item(title: AuthMenu.settings.name, hasNestedContent: true)
  248. return Section(headerDescription: header, items: [item])
  249. }
  250. static var providerSection: Section {
  251. let providers = self.providers.map { Item(title: $0.name) }
  252. let header = "Identity Providers"
  253. let footer = "Choose a login flow from one of the identity providers above."
  254. return Section(headerDescription: header, footerDescription: footer, items: providers)
  255. }
  256. static var emailPasswordSection: Section {
  257. let image = UIImage(named: "firebaseIcon")
  258. let header = "Email and Password Login"
  259. let item = Item(title: AuthMenu.emailPassword.name, hasNestedContent: true, image: image)
  260. return Section(headerDescription: header, items: [item])
  261. }
  262. static var otherSection: Section {
  263. let lockSymbol = UIImage.systemImage("lock.slash.fill", tintColor: .systemOrange)
  264. let phoneSymbol = UIImage.systemImage("phone.fill", tintColor: .systemOrange)
  265. let anonSymbol = UIImage.systemImage("questionmark.circle.fill", tintColor: .systemOrange)
  266. let shieldSymbol = UIImage.systemImage("lock.shield.fill", tintColor: .systemOrange)
  267. let otherOptions = [
  268. Item(title: AuthMenu.passwordless.name, image: lockSymbol),
  269. Item(title: AuthMenu.phoneNumber.name, image: phoneSymbol),
  270. Item(title: AuthMenu.anonymous.name, image: anonSymbol),
  271. Item(title: AuthMenu.custom.name, image: shieldSymbol),
  272. ]
  273. let header = "Other Authentication Methods"
  274. return Section(headerDescription: header, items: otherOptions)
  275. }
  276. static var recaptchaSection: Section {
  277. let image = UIImage(named: "firebaseIcon")
  278. let header = "Initialize reCAPTCHA Enterprise"
  279. let item = Item(title: AuthMenu.initRecaptcha.name, hasNestedContent: false, image: image)
  280. return Section(headerDescription: header, items: [item])
  281. }
  282. static var customAuthDomainSection: Section {
  283. let image = UIImage(named: "firebaseIcon")
  284. let header = "Custom Auth Domain"
  285. let item = Item(title: AuthMenu.customAuthDomain.name, hasNestedContent: false, image: image)
  286. return Section(headerDescription: header, items: [item])
  287. }
  288. static var appSection: Section {
  289. let header = "APP"
  290. let items: [Item] = [
  291. Item(title: AuthMenu.getToken.name),
  292. Item(title: AuthMenu.getTokenForceRefresh.name),
  293. Item(title: AuthMenu.addAuthStateChangeListener.name),
  294. Item(title: AuthMenu.removeLastAuthStateChangeListener.name),
  295. Item(title: AuthMenu.addIdTokenChangeListener.name),
  296. Item(title: AuthMenu.removeLastIdTokenChangeListener.name),
  297. Item(title: AuthMenu.verifyClient.name),
  298. Item(title: AuthMenu.deleteApp.name),
  299. ]
  300. return Section(headerDescription: header, items: items)
  301. }
  302. static var oobSection: Section {
  303. let header = "OOB"
  304. let items: [Item] = [
  305. Item(title: AuthMenu.actionType.name, detailTitle: ActionCodeRequestType.inApp.name),
  306. Item(title: AuthMenu.continueURL.name, detailTitle: "--", isEditable: true),
  307. Item(title: AuthMenu.requestVerifyEmail.name),
  308. Item(title: AuthMenu.requestPasswordReset.name),
  309. Item(title: AuthMenu.resetPassword.name),
  310. Item(title: AuthMenu.checkActionCode.name),
  311. Item(title: AuthMenu.applyActionCode.name),
  312. Item(title: AuthMenu.verifyPasswordResetCode.name),
  313. ]
  314. return Section(headerDescription: header, items: items)
  315. }
  316. //static var multifactorSection: MultiFactorMenuData.
  317. static var sections: [Section] =
  318. [settingsSection, providerSection, emailPasswordSection, otherSection, recaptchaSection,
  319. customAuthDomainSection, appSection, oobSection, MultiFactorMenuData.multifactorSection]
  320. static var authLinkSections: [Section] {
  321. let allItems = AuthMenuData.sections.flatMap { $0.items }
  322. let header = "Manage linking between providers"
  323. let footer =
  324. "Select an unchecked row to link the currently signed in user to that auth provider. To unlink the user from a linked provider, select its corresponding row marked with a checkmark."
  325. return [Section(headerDescription: header, footerDescription: footer, items: allItems)]
  326. }
  327. var sections: [Section] = AuthMenuData.sections
  328. }