#!python
# -*- coding: utf-8 -*-
# 2017-01-13 Cornelius Kölbel <cornelius.koelbel@netknights.it>
#
# Copyright (c) 2017, Cornelius Kölbel
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

__doc__ = """
This script searches tokens that have not been used for a while.
To do so, it checks for the tokeninfo field "last_auth".
If the last authentication is to old, the script can delete, disable or mark
these tokens.

You can call the script like this:

    edumfa-get-unused-tokens list 10h|7d|2y
    edumfa-get-unused-tokens disable 10h|7d|2y
    edumfa-get-unused-tokens delete 10h|7d|2y
    edumfa-get-unused-tokens mark 10h|7d|2y --description="new
    value"

"""
__version__ = "0.1"

from edumfa.lib.token import get_tokens, remove_token, enable_token
from edumfa.lib.policy import ACTION
from edumfa.app import create_app
import click
from flask.cli import FlaskGroup
from flask import current_app as app

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])


def create_prod_app():
    return create_app("production", silent=True, script=True)


@click.group(cls=FlaskGroup, add_default_commands=False, create_app=create_prod_app, context_settings=CONTEXT_SETTINGS,
             epilog='Check out our docs at https://edumfa.readthedocs.io/ for more details')
def cli():
    pass

def _get_tokenlist(age):
    tlist = []
    tokenobj_list = get_tokens()
    for token_obj in tokenobj_list:
        if not token_obj.check_last_auth_newer(age):
            tlist.append(token_obj)
    return tlist

@cli.command()
@click.argument('age')
def list(age):
    """
    finds all tokens, where the last_auth is too old.
    """
    # Oh bad performance, we have to look at *ALL* tokens!
    tlist = _get_tokenlist(age)
    click.echo("Token serial\tLast authentication")
    click.echo("="*42)
    for token_obj in tlist:
        click.echo("{0!s}\t{1!s}".format(token_obj.token.serial,
                                    token_obj.get_tokeninfo(ACTION.LASTAUTH)))

@cli.command()
@click.argument('age')
@click.option('-d', '--description', help='The description that will be set.')
@click.option('-t', '--tokeninfo',
                help='The tokeninfo that will be set. It needs a key and a '
                     'value and should be specified like key=value.')
def mark(age, description=None, tokeninfo=None):
    """
    Find unused tokens and mark them either by setting the description or by
    setting a tokeninfo.

    Tokeninfo parameter needs to be provided like key=value.
    """
    tlist = _get_tokenlist(age)
    for token_obj in tlist:
        if description:
            click.echo("Setting description for token {0!s}: {1!s}".format(
                token_obj.token.serial, description))
            token_obj.set_description(description)
            token_obj.save()
        if tokeninfo:
            key, value = tokeninfo.split("=")
            click.echo("Setting tokeninfo for token {0!s}: {1!s}={2!s}".format(
                token_obj.token.serial, key, value))
            token_obj.add_tokeninfo(key, value)
            token_obj.save()

@cli.command()
@click.argument('age')
def delete(age):
    """
    Find unused tokens and delete them.
    """
    tlist = _get_tokenlist(age)
    for token_obj in tlist:
        serial = token_obj.token.serial
        remove_token(serial)
        click.echo("Token {0!s} deleted.".format(serial))

@cli.command()
@click.argument('age')
def disable(age):
    """
    Find unused tokens and delete them.
    """
    tlist = _get_tokenlist(age)
    for token_obj in tlist:
        serial = token_obj.token.serial
        enable_token(serial, enable=False)
        click.echo("Token {0!s} disabled.".format(serial))

if __name__ == '__main__':
    cli()

