This repository was archived by the owner on Feb 23, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 168
Auth mobile #783
Merged
Merged
Auth mobile #783
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
fdf9f2b
Refactor PIN and auth actions
tanx e605d57
Refactor pin mobile view
tanx 4ccf00d
Refactor set pin mobile view
tanx c52b469
Refactor set pin confirm mobile view
tanx 19d2d83
Wire up pin views
tanx 8172c78
Fix pin input in storybook
tanx ba2a643
Wire up auth-mobile module to be more testable
tanx 687b105
Fix wallet action tests
tanx 1c10839
Write auth-mobile unit tests
tanx 791430d
Fix typos in mobile/main.js
tanx 90f52ce
Remove npm audit from travis build
tanx e6ecda7
Add copy to mobile wait screen
tanx 1f861d6
Fix typo in main.js
tanx 65ed187
Fix new pin error message
tanx 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
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
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
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,202 @@ | ||
| /** | ||
| * @fileOverview action to handle mobile specific authentication | ||
| * using PINs, TouchID, and KeyStore storage. | ||
| */ | ||
|
|
||
| import { PIN_LENGTH } from '../config'; | ||
|
|
||
| const PIN = 'DevicePin'; | ||
| const PASS = 'WalletPassword'; | ||
|
|
||
| class AuthAction { | ||
| constructor(store, wallet, nav, SecureStore, Fingerprint, Alert) { | ||
| this._store = store; | ||
| this._wallet = wallet; | ||
| this._nav = nav; | ||
| this._SecureStore = SecureStore; | ||
| this._Fingerprint = Fingerprint; | ||
| this._Alert = Alert; | ||
| } | ||
|
|
||
| // | ||
| // PIN actions | ||
| // | ||
|
|
||
| /** | ||
| * Initialize the set pin view by resetting input values | ||
| * and then navigating to the view. | ||
| * @return {undefined} | ||
| */ | ||
| initSetPin() { | ||
| this._store.auth.newPin = ''; | ||
| this._store.auth.pinVerify = ''; | ||
| this._nav.goSetPin(); | ||
| } | ||
|
|
||
| /** | ||
| * Initialize the pin view by resetting input values | ||
| * and then navigating to the view. | ||
| * @return {undefined} | ||
| */ | ||
| initPin() { | ||
| this._store.auth.pin = ''; | ||
| this._nav.goPin(); | ||
| } | ||
|
|
||
| /** | ||
| * Append a digit input to the pin parameter. | ||
| * @param {string} options.digit The digit to append to the pin | ||
| * @param {string} options.param The pin parameter name | ||
| * @return {undefined} | ||
| */ | ||
| pushPinDigit({ digit, param }) { | ||
| const { auth } = this._store; | ||
| if (auth[param].length < PIN_LENGTH) { | ||
| auth[param] += digit; | ||
| } | ||
| if (auth[param].length < PIN_LENGTH) { | ||
| return; | ||
| } | ||
| if (param === 'newPin') { | ||
| this._nav.goSetPinConfirm(); | ||
| } else if (param === 'pinVerify') { | ||
| this.checkNewPin(); | ||
| } else if (param === 'pin') { | ||
| this.checkPin(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Remove the last digit from the pin parameter. | ||
| * @param {string} options.param The pin parameter name | ||
| * @return {undefined} | ||
| */ | ||
| popPinDigit({ param }) { | ||
| const { auth } = this._store; | ||
| if (auth[param]) { | ||
| auth[param] = auth[param].slice(0, -1); | ||
| } else if (param === 'pinVerify') { | ||
| this.initSetPin(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Check the PIN that was chosen by the user was entered | ||
| * correctly twice to make sure that there was no typo. | ||
| * If everything is ok, store the pin in the keystore and | ||
| * unlock the wallet. | ||
| * @return {Promise<undefined>} | ||
| */ | ||
| async checkNewPin() { | ||
| const { newPin, pinVerify } = this._store.auth; | ||
| if (newPin.length !== PIN_LENGTH || newPin !== pinVerify) { | ||
| this._alert("PINs don't match", () => this.initSetPin()); | ||
| return; | ||
| } | ||
| await this._setToKeyStore(PIN, newPin); | ||
| await this._generateWalletPassword(); | ||
| } | ||
|
|
||
| /** | ||
| * Check the PIN that was entered by the user in the unlock | ||
| * screen matches the pin stored in the keystore and unlock | ||
| * the wallet. | ||
| * @return {Promise<undefined>} | ||
| */ | ||
| async checkPin() { | ||
| const { pin } = this._store.auth; | ||
| const storedPin = await this._getFromKeyStore(PIN); | ||
| if (pin !== storedPin) { | ||
| this._alert('Incorrect PIN', () => this.initPin()); | ||
| return; | ||
| } | ||
| await this._unlockWallet(); | ||
| } | ||
|
|
||
| // | ||
| // TouchID & KeyStore Authentication | ||
| // | ||
|
|
||
| /** | ||
| * Try authenticating the user using either via TouchID/FaceID on iOS | ||
| * or a fingerprint reader on Android. | ||
| * @return {Promise<undefined>} | ||
| */ | ||
| async tryFingerprint() { | ||
| const hasHardware = await this._Fingerprint.hasHardwareAsync(); | ||
| if (!hasHardware) { | ||
| return; | ||
| } | ||
| const msg = 'Unlock your Wallet'; | ||
| const { success } = await this._Fingerprint.authenticateAsync(msg); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can confirm that fingerprint auth works on Android!!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. Did you get that iOS device yet? |
||
| if (!success) { | ||
| return; | ||
| } | ||
| await this._unlockWallet(); | ||
| } | ||
|
|
||
| /** | ||
| * A new wallet password is generated and stored in the keystore | ||
| * during device setup. This password is not intended to be displayed | ||
| * to the user but is unlocked at the application layer via TouchID | ||
| * or PIN (which is stored in the keystore). | ||
| * @return {Promise<undefined>} | ||
| */ | ||
| async _generateWalletPassword() { | ||
| const newPass = this._totallyNotSecureRandomPassword(); | ||
| await this._setToKeyStore(PASS, newPass); | ||
| this._store.wallet.newPassword = newPass; | ||
| this._store.wallet.passwordVerify = newPass; | ||
| await this._wallet.checkNewPassword(); | ||
| } | ||
|
|
||
| /** | ||
| * Unlock the wallet using a randomly generated password that is | ||
| * stored in the keystore. This password is not intended to be displayed | ||
| * to the user but rather unlocked at the application layer. | ||
| * @return {Promise<undefined>} | ||
| */ | ||
| async _unlockWallet() { | ||
| const storedPass = await this._getFromKeyStore(PASS); | ||
| this._store.wallet.password = storedPass; | ||
| await this._wallet.checkPassword(); | ||
| } | ||
|
|
||
| _getFromKeyStore(key) { | ||
| const options = { | ||
| keychainAccessible: this._SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, | ||
| }; | ||
| return this._SecureStore.getItemAsync(key, options); | ||
| } | ||
|
|
||
| _setToKeyStore(key, value) { | ||
| const options = { | ||
| keychainAccessible: this._SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, | ||
| }; | ||
| return this._SecureStore.setItemAsync(key, value, options); | ||
| } | ||
|
|
||
| _alert(title, callback) { | ||
| this._Alert.alert(title, '', [{ text: 'TRY AGAIN', onPress: callback }]); | ||
| } | ||
|
|
||
| /** | ||
| * NOT SECURE ... DO NOT USE IN PRODUCTION !!! | ||
| * | ||
| * Just a stop gap during development until we have a secure native | ||
| * PRNG: https://github.com/lightninglabs/lightning-app/issues/777 | ||
| * | ||
| * Generate a hex encoded 256 bit entropy wallet password (which will | ||
| * be stretched using a KDF in lnd). | ||
| * @return {string} A hex string containing some random bytes | ||
| */ | ||
| _totallyNotSecureRandomPassword() { | ||
| const bytes = new Uint8Array(32); | ||
| for (let i = 0; i < bytes.length; i++) { | ||
| bytes[i] = Math.floor(256 * Math.random()); | ||
| } | ||
| return Buffer.from(bytes.buffer).toString('hex'); | ||
| } | ||
| } | ||
|
|
||
| export default AuthAction; | ||
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a plan to add copy so the user knows that they can use their fingerprint/faceID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the device supports it the native OS UI will already display copy...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, not on Android. I just tried it and it worked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok cool. I try to write the code so that it at least runs on Android, but I think we can ignore Android specific issues and focus on iOS for now.