diff --git a/app/init/emm_provider.js b/app/init/emm_provider.js index 36bcde4f1..6974e46bb 100644 --- a/app/init/emm_provider.js +++ b/app/init/emm_provider.js @@ -134,7 +134,7 @@ class EMMProvider { }; showNotSecuredAlert = (translations) => { - return new Promise((resolve) => { + return new Promise(async (resolve) => { const options = []; if (Platform.OS === 'android') { @@ -152,9 +152,22 @@ class EMMProvider { style: 'cancel', }); + let message; + if (Platform.OS === 'ios') { + const {supportsFaceId} = await mattermostManaged.supportsFaceId(); + + if (supportsFaceId) { + message = translations[t('mobile.managed.not_secured.ios')]; + } else { + message = translations[t('mobile.managed.not_secured.ios.touchId')]; + } + } else { + message = translations[t('mobile.managed.not_secured.android')]; + } + Alert.alert( translations[t('mobile.managed.blocked_by')].replace('{vendor}', this.vendor), - Platform.OS === 'ios' ? translations[t('mobile.managed.not_secured.ios')] : translations[t('mobile.managed.not_secured.android')], + message, options, {cancelable: false, onDismiss: resolve}, ); diff --git a/app/mattermost_managed/mattermost-managed.android.js b/app/mattermost_managed/mattermost-managed.android.js index 778396a9f..2c2e24176 100644 --- a/app/mattermost_managed/mattermost-managed.android.js +++ b/app/mattermost_managed/mattermost-managed.android.js @@ -66,5 +66,6 @@ export default { return JailMonkey.trustFall(); }, + supportsFaceId: async () => false, quitApp: MattermostManaged.quitApp, }; diff --git a/app/mattermost_managed/mattermost-managed.ios.js b/app/mattermost_managed/mattermost-managed.ios.js index 8073f9a26..b27fea6da 100644 --- a/app/mattermost_managed/mattermost-managed.ios.js +++ b/app/mattermost_managed/mattermost-managed.ios.js @@ -68,5 +68,6 @@ export default { return JailMonkey.trustFall(); }, + supportsFaceId: MattermostManaged.supportsFaceId, quitApp: MattermostManaged.quitApp, }; diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 0cb0bc216..6641d7481 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -279,6 +279,7 @@ "mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}, please exit the app.", "mobile.managed.not_secured.android": "This device must be secured with a screen lock to use Mattermost.", "mobile.managed.not_secured.ios": "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Face ID & Passcode.", + "mobile.managed.not_secured.ios.touchId": "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Touch ID & Passcode.", "mobile.managed.secured_by": "Secured by {vendor}", "mobile.managed.settings": "Go to settings", "mobile.markdown.code.copy_code": "Copy Code", diff --git a/ios/Mattermost/MattermostManaged.m b/ios/Mattermost/MattermostManaged.m index a96f94d2f..d8124a1ee 100644 --- a/ios/Mattermost/MattermostManaged.m +++ b/ios/Mattermost/MattermostManaged.m @@ -7,6 +7,7 @@ // #import "MattermostManaged.h" +#import #import @implementation MattermostManaged { @@ -167,4 +168,17 @@ RCT_EXPORT_METHOD(quitApp) exit(0); } +RCT_EXPORT_METHOD(supportsFaceId:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + LAContext *context = [[LAContext alloc] init]; + NSError *error; + + // context.biometryType is initialized when canEvaluatePolicy, regardless of the error or return value + [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]; + + resolve(@{ + @"supportsFaceId": @(context.biometryType == LABiometryTypeFaceID && @available(iOS 11.0, *)) + }); +} + @end diff --git a/ios/MattermostShare/ShareViewController.swift b/ios/MattermostShare/ShareViewController.swift index 151a71757..9ac1a1f30 100644 --- a/ios/MattermostShare/ShareViewController.swift +++ b/ios/MattermostShare/ShareViewController.swift @@ -47,9 +47,16 @@ class ShareViewController: SLComposeServiceViewController { var error: NSError? if !context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) { if let error = error, error.code == kLAErrorPasscodeNotSet { + var message = "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Touch ID & Passcode." + if #available(iOS 11.0, *) { + if (context.biometryType == LABiometryType.faceID) { + message = "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Face ID & Passcode." + } + } + self.showErrorMessage( title: "", - message: "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Face ID & Passcode.", + message: message, VC: self ) } else {