<commit_before>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import Emm from '@mattermost/react-native-emm';
import JailMonkey from 'jail-monkey';
import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native';

import {DEFAULT_LOCALE, getTranslations, t} from '@i18n';
import {getIOSAppGroupDetails} from '@utils/mattermost_managed';

const PROMPT_IN_APP_PIN_CODE_AFTER = 5 * 60 * 1000;

class ManagedApp {
    backgroundSince = 0;
    enabled = false;
    inAppPinCode = false;
    performingAuthentication = false;
    previousAppState?: AppStateStatus;
    processConfigTimeout?: NodeJS.Timeout;
    vendor = 'Mattermost';

    constructor() {
        Emm.addListener(this.processConfig);

        this.setIOSAppGroupIdentifier();

        AppState.addEventListener('change', this.onAppStateChange);
    }

    init() {
        this.processConfig(Emm.getManagedConfig<ManagedConfig>());
    }

    setIOSAppGroupIdentifier = () => {
        if (Platform.OS === 'ios') {
            const {appGroupIdentifier} = getIOSAppGroupDetails();

            if (appGroupIdentifier) {
                Emm.setAppGroupId(appGroupIdentifier);
            }
        }
    };

    processConfig = async (config?: ManagedConfig) => {
        // If the managed configuration changed while authentication was
        // being performed, delay the processing of this new configuration
        // until authentication is complete.
        if (this.performingAuthentication) {
            if (this.processConfigTimeout) {
                clearTimeout(this.processConfigTimeout);
            }

            this.processConfigTimeout = setTimeout(() => this.processConfig(config), 500);
        }

        this.enabled = Boolean(config && Object.keys(config).length);
        if (!this.enabled) {
            return;
        }

        const blurScreen = config!.blurApplicationScreen === 'true';
        Emm.enableBlurScreen(blurScreen);

        const vendor = config!.vendor;
        if (vendor) {
            this.vendor = vendor;
        }

        const jailbreakProtection = config!.jailbreakProtection === 'true';
        if (jailbreakProtection && !this.isTrustedDevice()) {
            this.alertDeviceIsUntrusted();
            return;
        }

        const inAppPinCode = config!.inAppPinCode === 'true';
        if (inAppPinCode) {
            this.handleDeviceAuthentication();
        }
    };

    alertDeviceIsUntrusted = () => {
        const locale = DEFAULT_LOCALE; // TODO: Get current user or system locale
        const translations = getTranslations(locale);
        Alert.alert(
            translations[t('mobile.managed.blocked_by')].replace('{vendor}', this.vendor),
            translations[t('mobile.managed.jailbreak')].replace('{vendor}', this.vendor),
            [{
                text: translations[t('mobile.managed.exit')],
                style: 'destructive',
                onPress: () => {
                    Emm.exitApp();
                },
            }],
            {cancelable: false},
        );
    };

    handleDeviceAuthentication = async (authExpired = true) => {
        this.performingAuthentication = true;
        const isSecured = await Emm.isDeviceSecured();
        const locale = DEFAULT_LOCALE;
        const translations = getTranslations(locale);

        if (!isSecured) {
            await this.showNotSecuredAlert(translations);
            Emm.exitApp();
            return;
        }

        if (authExpired) {<commit_msg>Use device locale to display the untrusted device alert (#6194)<commit_after>// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import Emm from '@mattermost/react-native-emm';
import JailMonkey from 'jail-monkey';
import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native';

import {DEFAULT_LOCALE, getTranslations, t} from '@i18n';
import {getIOSAppGroupDetails} from '@utils/mattermost_managed';

const PROMPT_IN_APP_PIN_CODE_AFTER = 5 * 60 * 1000;

class ManagedApp {
    backgroundSince = 0;
    enabled = false;
    inAppPinCode = false;
    performingAuthentication = false;
    previousAppState?: AppStateStatus;
    processConfigTimeout?: NodeJS.Timeout;
    vendor = 'Mattermost';

    constructor() {
        Emm.addListener(this.processConfig);

        this.setIOSAppGroupIdentifier();

        AppState.addEventListener('change', this.onAppStateChange);
    }

    init() {
        this.processConfig(Emm.getManagedConfig<ManagedConfig>());
    }

    setIOSAppGroupIdentifier = () => {
        if (Platform.OS === 'ios') {
            const {appGroupIdentifier} = getIOSAppGroupDetails();

            if (appGroupIdentifier) {
                Emm.setAppGroupId(appGroupIdentifier);
            }
        }
    };

    processConfig = async (config?: ManagedConfig) => {
        // If the managed configuration changed while authentication was
        // being performed, delay the processing of this new configuration
        // until authentication is complete.
        if (this.performingAuthentication) {
            if (this.processConfigTimeout) {
                clearTimeout(this.processConfigTimeout);
            }

            this.processConfigTimeout = setTimeout(() => this.processConfig(config), 500);
        }

        this.enabled = Boolean(config && Object.keys(config).length);
        if (!this.enabled) {
            return;
        }

        const blurScreen = config!.blurApplicationScreen === 'true';
        Emm.enableBlurScreen(blurScreen);

        const vendor = config!.vendor;
        if (vendor) {
            this.vendor = vendor;
        }

        const jailbreakProtection = config!.jailbreakProtection === 'true';
        if (jailbreakProtection && !this.isTrustedDevice()) {
            this.alertDeviceIsUntrusted();
            return;
        }

        const inAppPinCode = config!.inAppPinCode === 'true';
        if (inAppPinCode) {
            this.handleDeviceAuthentication();
        }
    };

    alertDeviceIsUntrusted = () => {
        // We use the default device locale as this is an app wide setting
        // and does not require any server data
        const locale = DEFAULT_LOCALE;
        const translations = getTranslations(locale);
        Alert.alert(
            translations[t('mobile.managed.blocked_by')].replace('{vendor}', this.vendor),
            translations[t('mobile.managed.jailbreak')].replace('{vendor}', this.vendor),
            [{
                text: translations[t('mobile.managed.exit')],
                style: 'destructive',
                onPress: () => {
                    Emm.exitApp();
                },
            }],
            {cancelable: false},
        );
    };

    handleDeviceAuthentication = async (authExpired = true) => {
        this.performingAuthentication = true;
        const isSecured = await Emm.isDeviceSecured();
        const locale = DEFAULT_LOCALE;
        const translations = getTranslations(locale);

        if (!isSecured) {
            await this.showNotSecuredAlert(translations);
            Emm.exitApp();
            return;
        }

        if (authExpired) {
{'fraction_non_alphanumeric': 0.11040748898678414, 'fraction_numerical': 0.0052312775330396475, 'mean_word_length': 2.3234217749313815, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4002077', 'n_tokens_mistral': 2011, 'n_tokens_neox': 1900, 'n_words': 416}