-
Notifications
You must be signed in to change notification settings - Fork 0
docs(TwoFactorAuth): Add 2FA doc for integration in a new app #642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
LouisCAD
wants to merge
4
commits into
main
Choose a base branch
from
2fa-doc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
6068246
docs(TwoFactorAuth): Add 2FA doc for integration in a new app
LouisCAD ab09da5
chore(TwoFactorAuth): Update the doc
LouisCAD 2432472
docs(TwoFactorAuth): Fix example snippet
LouisCAD 584c87d
docs(TwoFactorAuth): Update doc to clarify no user db support
LouisCAD File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| # 2-factor authentication | ||
|
|
||
| ## How to integrate into a new app (Part One, polling-only) | ||
|
|
||
| This enables the feature, that tries to retrieve any ongoing login challenge when the app is brought to the foreground. | ||
| It does NOT include notifications support, which is an extra (Part Two). | ||
|
|
||
| ### 1. Add the dependencies | ||
|
|
||
| Depend on these 2FA related libraries: | ||
|
|
||
| ```kotlin | ||
| implementation(core.infomaniak.core.twofactorauth.back.withuserdb) | ||
| implementation(core.infomaniak.core.twofactorauth.front) | ||
| ``` | ||
|
|
||
| ### 2. Define the TwoFactorAuthManager singleton | ||
|
|
||
| #### A. With the user db dependency | ||
|
|
||
| Example with top-level declaration: | ||
|
|
||
| ```kotlin | ||
| /** | ||
| * Singleton for incoming 2FA (two-factor authentication) challenges. | ||
| * | ||
| * Not a ViewModel because the state needs to be scoped for the entire app. | ||
| */ | ||
| val twoFactorAuthManager = TwoFactorAuthManager { userId -> AccountUtils.getHttpClient(userId) } | ||
| ``` | ||
|
|
||
| Example with annotation based dependency injection: | ||
|
|
||
| ```kotlin | ||
| @Provides | ||
| @Singleton | ||
| fun provideTwoFactorAuthManager(accountUtils: AccountUtils): TwoFactorAuthManager { | ||
| return TwoFactorAuthManager { userId -> accountUtils.getHttpClient(userId) } | ||
| } | ||
| ``` | ||
|
|
||
| #### B. With NO dependency on the user db (not fully supported) | ||
|
|
||
| If you can't or don't want to depend on the user database dependency, there is a way. | ||
|
|
||
| **⚠️⚠️ NOTE: ⚠️⚠️** | ||
|
|
||
| Currently, the notifications part doesn't work without the user db, because so far, all our apps are using the user db, | ||
| including apps that initially were not projected to do so. | ||
|
|
||
| Technically, it is possible to make a user-db free version of the `notifications.registration` module, but it'll be | ||
| done only if needed by an app. | ||
|
|
||
| ##### How to | ||
|
|
||
| 1. Drop the `.withuserdb` in the dependency | ||
|
|
||
| ```kotlin | ||
| -implementation(core.infomaniak.core.twofactorauth.back.withuserdb) | ||
| +implementation(core.infomaniak.core.twofactorauth.back) | ||
| ``` | ||
|
|
||
| 2. Provide the required extra parameters. | ||
|
|
||
| Example: | ||
|
|
||
| ```kotlin | ||
| val twoFactorAuthManager = TwoFactorAuthManager( | ||
| coroutineScope = coroutineScope, | ||
| userIds = someStorage.connectedUsers.map { users -> | ||
| users.map(mutableSetOf()) { it.id } | ||
| }.distinctUntilChanged(), | ||
| getAccountInfo = { | ||
| val info = getUserAccountInfoById(it) | ||
| ConnectionAttemptInfo.TargetAccount( | ||
| avatarUrl = info.avatar, | ||
| fullName = info.displayName, | ||
| initials = info.computeInitials(), | ||
| email = info.email, | ||
| id = it.toLong(), | ||
| ) | ||
| }, | ||
| getConnectedHttpClient = { userId -> getHttpClientForUser(userId) } | ||
| ) | ||
| ``` | ||
|
|
||
| ### 3. Add the overlay where needed | ||
|
|
||
| For each Activity in the app (including login screen for multi-account apps): | ||
|
|
||
| Add `TwoFactorAuthApprovalAutoManagedBottomSheet(twoFactorAuthManager)` at the root of the content. | ||
|
|
||
| Example: | ||
|
|
||
| ```kotlin | ||
| class MainActivity : ComponentActivity() { | ||
|
|
||
| @Inject | ||
| lateinit var twoFactorAuthManager: TwoFactorAuthManager // If using annotation based DI lib. | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| setContent { | ||
| TwoFactorAuthApprovalAutoManagedBottomSheet( | ||
| twoFactorAuthManager = twoFactorAuthManager, // References the member var, or the singleton. | ||
| isInDarkTheme = isSystemInDarkTheme() | ||
| ) | ||
| Whatever() | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| If the Activity is NOT using Compose, or if you don't know (e.g. in a `BaseActivity` class), the `addComposableOverlay` | ||
| function was made just for that, just make sure it's called after `setContentView` or `setContent`. | ||
|
|
||
| Example: | ||
|
|
||
| ```kotlin | ||
| class MainActivity : ComponentActivity() { | ||
|
|
||
| @Inject | ||
| lateinit var twoFactorAuthManager: TwoFactorAuthManager // If using annotation based DI lib. | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| setContentView(whatever) | ||
| addComposableOverlay { | ||
| TwoFactorAuthApprovalAutoManagedBottomSheet( | ||
| twoFactorAuthManager = twoFactorAuthManager, // References the member var, or the singleton. | ||
| isInDarkTheme = isSystemInDarkTheme() | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| At this point, you can expect the feature to be working (albeit without notifications). | ||
|
|
||
| ## How to integrate into a new app (Part Two, notifications support) | ||
|
|
||
| **⚠️⚠️ NOTE: ⚠️⚠️** | ||
|
|
||
| Unless specified otherwise, the **code below is to be put into Google Play Services dedicated source sets**. | ||
|
|
||
| For example, if the host app is published to F-Droid + the Google Play Store and has 2 product flavors named "fdroid" and "standard", where "standard" contains Google Play Services dependent code, by default, the code below should be located into `app-module/src/standard/kotlin`, where `app-module` is the target app or library module. | ||
|
|
||
| ### 1. Add the right dependency in the right configuration | ||
|
|
||
| Add this dependency in the host app's Gradle build file: | ||
|
|
||
| ```kotlin | ||
| "standardImplementation"(core.infomaniak.core.notifications.registration) | ||
| ``` | ||
|
|
||
| Here, "standard" matches the product flavor that includes Firebase/Google Play Services dependencies. | ||
|
LouisCAD marked this conversation as resolved.
|
||
|
|
||
| ### 2. Ensure notification token and topics will be synced | ||
|
|
||
| First, create the `RegisterUserDeviceWorker` class (if it doesn't exist already). It needs to subclass `AbstractNotificationsRegistrationWorker`. | ||
|
|
||
| You can find the Mail app example here: https://github.com/Infomaniak/android-kMail/blob/e272d5b5ff5f4b1eb1f11784537a3d624c063e80/app/src/standard/java/com/infomaniak/mail/firebase/RegisterUserDeviceWorker.kt | ||
|
|
||
| Follow other changes from this PR in the Mail, or the kDrive app: | ||
| https://github.com/Infomaniak/android-kDrive/pull/1872/changes | ||
| https://github.com/Infomaniak/android-kMail/pull/2698/changes | ||
|
|
||
| Here's the list of changes you need to add from the example PRs above: | ||
| 1. Ensure `TwoFactorAuthNotifications.channel()` is created/submitted to Android's NotificationManager. | ||
| 2. Ensure `NotificationsRegistrationManager` is added in `userDataCleanableList` at the beginning of the app process for the Play Services app variant. | ||
| 3. Ensure the user addition and removal functions to call `resetForUser` in elements registered `userDataCleanableList` (already done if added Cross-app login first). | ||
| 4. Ensure `NotificationsRegistrationManager.scheduleWorkerOnUpdate` is called in an app process wide coroutine, right from the app process start. | ||
| 5. Ensure the `Application` subclass is declared properly in the manifest for the Play Services dependent product flavor | ||
| 6. In the `FirebaseMessagingService` subclass (create it and declare it in the manifest if needed), make sure the `onNewToken` and `onMessageReceived` functions are implemented properly to forward the new tokens to `NotificationsRegistrationManager`, and matching notifications (the ones with `TwoFactorAuthNotifications.TYPE` in key `"type"`), forwarded to `twoFactorAuthManager.onApprovalChallengePushed(…)`. | ||
| 7. Ensure any other push notification topics are properly integrated for `RegisterUserDeviceWorker` and `NotificationsRegistrationManager.scheduleWorkerOnUpdate`. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.