AuthMenu.swift 11 KB

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