# encoding: utf-8
#
# Copyright 2017 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
bootstrapping

Created by Greg Neagle on 2017-08-31.

Functions supporting bootstrapping mode
"""

import os

# PyLint cannot properly find names inside Cocoa libraries, so issues bogus
# No name 'Foo' in module 'Bar' warnings. Disable them.
# pylint: disable=E0611
from Foundation import CFPreferencesAppSynchronize
from Foundation import CFPreferencesCopyValue
from Foundation import CFPreferencesSetValue
from Foundation import kCFPreferencesAnyUser
from Foundation import kCFPreferencesCurrentHost
# pylint: enable=E0611

from . import constants


class SetupError(Exception):
    '''Error to raise when we can not set up bootstrapping'''
    pass


def disable_fde_autologin():
    '''Disables autologin to the unlocking user's account on a FileVault-
    encrypted machines.'''
    
    # See https://support.apple.com/en-us/HT202842
    # We attempt to store the original value of com.apple.loginwindow
    # DisableFDEAutoLogin so if the local admin has set it to True for #reasons
    # we don't inadvertently clear it when clearing bootstrap mode

    # is OriginalDisableFDEAutoLogin already set? If so, bootstrap mode was
    # already enabled, and never properly cleared. Don't stomp on it.
    original_value = CFPreferencesCopyValue(
        'OriginalDisableFDEAutoLogin', 'com.apple.loginwindow',
        kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    if not original_value:
        # get the current value of DisableFDEAutoLogin if any
        original_value = CFPreferencesCopyValue(
            'DisableFDEAutoLogin', 'com.apple.loginwindow',
            kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
        if not original_value:
            # we need a way to record the original value was not set,
            # and we can't store None...
            original_value = '<not set>'
        # store it so we can restore it later
        CFPreferencesSetValue(
            'OriginalDisableFDEAutoLogin', original_value,
            'com.apple.loginwindow',
            kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    # set com.apple.loginwindow DisableFDEAutoLogin to True
    CFPreferencesSetValue(
        'DisableFDEAutoLogin', True, 'com.apple.loginwindow',
        kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    CFPreferencesAppSynchronize('com.apple.loginwindow')


def reset_fde_autologin():
    '''Resets the state of com.apple.loginwindow DisableFDEAutoLogin to its
    value before we set it to True'''
    # get the previous value of DisableFDEAutoLogin if any
    original_value = CFPreferencesCopyValue(
        'OriginalDisableFDEAutoLogin', 'com.apple.loginwindow',
        kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    if original_value == '<not set>':
        original_value = None
    # reset DisableFDEAutoLogin to original value (if original_value is None,
    # the key gets deleted)
    CFPreferencesSetValue(
        'DisableFDEAutoLogin', original_value, 'com.apple.loginwindow',
        kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    # delete the OriginalDisableFDEAutoLogin key
    CFPreferencesSetValue(
        'OriginalDisableFDEAutoLogin', None, 'com.apple.loginwindow',
        kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
    CFPreferencesAppSynchronize('com.apple.loginwindow')


def set_bootstrap_mode():
    '''Set up bootstrap mode'''
    # turn off auto login of FV unlocking user
    disable_fde_autologin()
    # create CHECKANDINSTALLATSTARTUPFLAG file
    try:
        open(constants.CHECKANDINSTALLATSTARTUPFLAG, 'w').close()
    except (OSError, IOError), err:
        reset_fde_autologin()
        raise SetupError(
            'Could not create bootstrapping flag file: %s', err)


def clear_bootstrap_mode():
    '''Clear bootstrap mode'''
    reset_fde_autologin()
    if os.path.exists(constants.CHECKANDINSTALLATSTARTUPFLAG):
        try:
            os.unlink(constants.CHECKANDINSTALLATSTARTUPFLAG)
        except OSError, err:
            raise SetupError(
                'Could not remove bootstrapping flag file: %s', err)
