<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation
import SnapKit
import SwiftKeychainWrapper

enum AuthenticationState {
    case notAuthenticating
    case presenting
}

class SensitiveViewController: UIViewController {
    var promptingForTouchID: Bool = false
    var backgroundedBlur: UIImageView?
    var authState: AuthenticationState = .notAuthenticating

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(checkIfUserRequiresValidation), name: UIApplication.willEnterForegroundNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(checkIfUserRequiresValidation), name: UIApplication.didBecomeActiveNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(blurContents), name: UIApplication.willResignActiveNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(hideLogins), name: UIApplication.didEnterBackgroundNotification, object: nil)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        NotificationCenter.default.removeObserver(self)
    }

    @objc func checkIfUserRequiresValidation() {
        guard authState != .presenting else {
            return
        }

        presentedViewController?.dismiss(animated: false, completion: nil)
        guard let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo(), authInfo.requiresValidation() else {
            removeBackgroundedBlur()
            return
        }

        promptingForTouchID = true
        AppAuthenticator.presentAuthenticationUsingInfo(authInfo,
            touchIDReason: AuthenticationStrings.loginsTouchReason,
            success: {
                self.promptingForTouchID = false
                self.authState = .notAuthenticating
                self.removeBackgroundedBlur()
            },
            cancel: {
                self.promptingForTouchID = false
                self.authState = .notAuthenticating
                _ = self.navigationController?.popToRootViewController(animated: true)
            },
            fallback: {
                self.promptingForTouchID = false
                AppAuthenticator.presentPasscodeAuthentication(self.navigationController).uponQueue(.main) { isOk in
                    if isOk {
                        self.removeBackgroundedBlur()
                        self.navigationController?.dismiss(animated: true, completion: nil)
                        self.authState = .notAuthenticating
                    } else {
                        _ = self.navigationController?.popToRootViewController(animated: false)
                        self.authState = .notAuthenticating
                    }
                }
            }
        )
        authState = .presenting
    }

    @objc func hideLogins() {
        _ = self.navigationController?.popToRootViewController(animated: true)
    }

    @objc func blurContents() {
        if backgroundedBlur == nil {
            backgroundedBlur = addBlurredContent()
        }
    }

    func removeBackgroundedBlur() {
        if !promptingForTouchID {
            backgroundedBlur?.removeFromSuperview()
            backgroundedBlur = nil
        }
    }

    fileprivate func addBlurredContent() -> UIImageView? {<commit_msg>Bug 1562486 - missing dismiss() (#5324)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import Foundation
import SnapKit
import SwiftKeychainWrapper

enum AuthenticationState {
    case notAuthenticating
    case presenting
}

class SensitiveViewController: UIViewController {
    var promptingForTouchID: Bool = false
    var backgroundedBlur: UIImageView?
    var authState: AuthenticationState = .notAuthenticating

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(checkIfUserRequiresValidation), name: UIApplication.willEnterForegroundNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(checkIfUserRequiresValidation), name: UIApplication.didBecomeActiveNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(blurContents), name: UIApplication.willResignActiveNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(hideLogins), name: UIApplication.didEnterBackgroundNotification, object: nil)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        NotificationCenter.default.removeObserver(self)
    }

    @objc func checkIfUserRequiresValidation() {
        guard authState != .presenting else {
            return
        }

        presentedViewController?.dismiss(animated: false, completion: nil)
        guard let authInfo = KeychainWrapper.sharedAppContainerKeychain.authenticationInfo(), authInfo.requiresValidation() else {
            removeBackgroundedBlur()
            return
        }

        promptingForTouchID = true
        AppAuthenticator.presentAuthenticationUsingInfo(authInfo,
            touchIDReason: AuthenticationStrings.loginsTouchReason,
            success: {
                self.promptingForTouchID = false
                self.authState = .notAuthenticating
                self.removeBackgroundedBlur()
            },
            cancel: {
                self.view.alpha = 0
                self.promptingForTouchID = false
                self.authState = .notAuthenticating
                _ = self.navigationController?.popToRootViewController(animated: false)
                self.dismiss(animated: false)
            },
            fallback: {
                self.promptingForTouchID = false
                AppAuthenticator.presentPasscodeAuthentication(self.navigationController).uponQueue(.main) { isOk in
                    if isOk {
                        self.removeBackgroundedBlur()
                        self.navigationController?.dismiss(animated: true, completion: nil)
                        self.authState = .notAuthenticating
                    } else {
                        // On cancel, the login list can appear for a split-second, set the view to transparent to avoid this.
                        self.view.alpha = 0
                        _ = self.navigationController?.popToRootViewController(animated: false)
                        self.dismiss(animated: false)
                        self.authState = .notAuthenticating
                    }
                }
            }
        )
        authState = .presenting
    }

    @objc func hideLogins() {
        _ = self.navigationController?.popToRootViewController(animated: true)
    }

    @objc func blurContents() {
        if backgroundedBlur == nil {
            backgroundedBlur = addBlurredContent()
        }
    }

    func removeBackgroundedBlur() {
        if !promptingForTouchID {
            backgroundedBlur?.removeFromSuperview()
            backgroundedBlur = nil
        }
    }

    fileprivate func addBlurredContent() -> UIImageView? {
{'fraction_non_alphanumeric': 0.07142857142857142, 'fraction_numerical': 0.002737226277372263, 'mean_word_length': 2.3891342756183747, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '3020421', 'n_tokens_mistral': 1954, 'n_tokens_neox': 1822, 'n_words': 408}