AuthMenu.swift 12 KB

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