def is_valid_token(token):
    """Check that the user has a valid token."""
    # Set auth object
    auth = Auth(token)

    try:
        # Make request
        result = auth.test()

    except Error as err:
        # Check for auth errors
        stf.report_event(str(err), {
            'token': token
        })
        return False

    # Check for further errors
    if not result.successful:
        stf.report_event('token_invalid', {
            'token': token,
            'result': result.__dict__
        })
        return False

    # Return successful
    return True
Example #2
0
def get_token(code, scope="user"):
    """Request a token from the Slack API."""
    # Set OAuth access object
    oauth = OAuth()

    # Setup return URL
    return_url = "{0}_url".format(scope)

    try:
        # Attempt to make request
        result = oauth.access(
            client_id=PROJECT_INFO["client_id"],
            client_secret=PROJECT_INFO["client_secret"],
            redirect_uri=PROJECT_INFO[return_url],
            code=code,
        )

    except Error as err:
        report_event("oauth_error", {"code": code, "return_url": return_url, "error": str(err)})
        abort(400)

    if not result.successful:
        report_event("oauth_unsuccessful", {"code": code, "return_url": return_url, "result": result.__dict__})
        abort(400)

    # Return token
    return result.body["access_token"]
def send_flip(token, table, args):
    """Post the flip as the authenticated user in Slack."""
    # Set up chat object
    chat = Chat(token)

    try:
        # Attempt to post message
        chat.post_message(
            args['channel_id'],
            table,
            username=args['user_id'],
            as_user=True
        )

    except Error as err:
        stf.report_event(str(err), {
            'token': token,
            'table': table,
            'args': args
        })

        # Report if we got any errors
        return '{0} encountered an error: {1}'.format(
            stf.PROJECT_INFO['name_full'],
            str(err)
        )

    # Return successful
    return
Example #4
0
def store_user(token, info):
    """Store a validated user in the database."""
    # Check if user exists
    user = DB.session.query(Users).filter(Users.id == info['user_id']).filter(
        Users.team == info['team_id']).first()

    if user is None:
        # Create new user
        new_user = Users(info['user_id'])
        new_user.team = info['team_id']
        new_user.token = token

        # Store new user
        report_event('user_added', {'token': token, 'info': info})
        DB.session.add(new_user)

    else:
        # Update user token
        report_event('user_updated', {'token': token, 'info': info})
        user.token = token

    # Update DB
    DB.session.commit()

    return
Example #5
0
def validate_return(args, scope="user"):
    """Wrapper function for data validation functions."""
    # Make sure we have args
    if not args["state"] or not args["code"]:
        report_event("missing_args", args)
        abort(400)

    # Validate state
    validate_state(args["state"])

    # Get access token
    token = get_token(args["code"], scope)

    # Validate token and get info
    token_info = validate_token(token)

    # Set up storage methods
    store_methods = {"user": store_user, "team": store_team}

    # Store token data
    store_methods[scope](token, token_info)

    # Set success url
    redirect_url = "{0}?success=1".format(PROJECT_INFO["base_url"])

    # Return successful
    return redirect_url
Example #6
0
def validate_return(args, scope='user'):
    """Wrapper function for data validation functions."""
    # Make sure we have args
    if not args['state'] or not args['code']:
        report_event('missing_args', args)
        abort(400)

    # Validate state
    validate_state(args['state'])

    # Get access token
    token = get_token(args['code'], scope)

    # Validate token and get info
    token_info = validate_token(token)

    # Set up storage methods
    store_methods = {'user': store_user, 'team': store_team}

    # Store token data
    store_methods[scope](token, token_info)

    # Set success url
    redirect_url = '{0}?success=1'.format(PROJECT_INFO['base_url'])

    # Return successful
    return redirect_url
Example #7
0
def send_flip(token, table, args):
    """Post the flip as the authenticated user in Slack."""
    # Set up chat object
    chat = Chat(token)

    try:
        # Attempt to post message
        chat.post_message(args['channel_id'],
                          table,
                          username=args['user_id'],
                          as_user=True)

    except Error as err:
        stf.report_event(str(err), {
            'token': token,
            'table': table,
            'args': args
        })

        # Report if we got any errors
        return '{app} encountered an error: {error}'.format(
            app=stf.PROJECT_INFO['name_full'], error=str(err))

    # Return without errors
    return None
Example #8
0
def get_token(code, scope='user'):
    """Request a token from the Slack API."""
    # Set OAuth access object
    oauth = OAuth()

    # Setup return URL
    return_url = '{0}_url'.format(scope)

    try:
        # Attempt to make request
        result = oauth.access(client_id=PROJECT_INFO['client_id'],
                              client_secret=PROJECT_INFO['client_secret'],
                              redirect_uri=PROJECT_INFO[return_url],
                              code=code)

    except Error as err:
        report_event('oauth_error', {
            'code': code,
            'return_url': return_url,
            'error': str(err)
        })
        abort(400)

    if not result.successful:
        report_event('oauth_unsuccessful', {
            'code': code,
            'return_url': return_url,
            'result': result.__dict__
        })
        abort(400)

    # Return token
    return result.body['access_token']
Example #9
0
def hmmm():
    report_event('post_request', request.form.to_dict())
    if PROJECT_INFO['debug']:
        print("************", file=stderr)
        print(request, file=stderr)
        print("************", file=stderr)

    return flipper.flip(request.form.to_dict())
Example #10
0
def home():
    """Render app homepage template."""
    if request.method == 'POST':
        report_event('post_request', request.form.to_dict())
        return flipper.flip(request.form.to_dict())

    else:
        return render_template('index.html',
                               project=PROJECT_INFO,
                               allowed_types=ALLOWED_TYPES,
                               allowed_commands=ALLOWED_COMMANDS)
Example #11
0
def home():
    """Render app homepage template."""
    if request.method == 'POST':
        report_event('post_request', request.form.to_dict())
        return flipper.flip(request.form.to_dict())

    else:
        return render_template(
            'index.html',
            project=PROJECT_INFO,
            allowed_types=ALLOWED_TYPES,
            allowed_commands=ALLOWED_COMMANDS
        )
Example #12
0
    def __call__(self, parser, namespace, values, option_string=None):
        """Validate flip arguments and stores them to namespace."""
        flip_type = values[0].lower()
        flip_word = None

        # Check for help
        if flip_type in ['help', 'list', 'version']:
            parser.print_help(flip_type)
            return

        # Check that the type is valid
        if (flip_type not in stf.ALLOWED_TYPES and
                flip_type not in stf.WORD_TYPES and
                flip_type not in stf.RESTORE_TYPES):
            stf.report_event('flip_invalid', {
                'flip': flip_type
            })
            parser.error(
                'Flip type "{0}" is not known'.format(
                    flip_type.encode('utf-8')
                )
            )

        if flip_type in stf.WORD_TYPES or flip_type in stf.RESTORE_TYPES:

            if len(values) >= 2:
                # Set word value
                flip_word = ' '.join(values[1:len(values)])

            else:
                # Check for flip that requires words
                if flip_type == 'word':
                    stf.report_event('flip_missing_word', {
                        'flip': flip_type
                    })
                    parser.error(
                        'Flip type "{0}" requires words to flip'.format(
                            flip_type.encode('utf-8')
                        )
                    )

        # Set values
        setattr(namespace, 'flip_type', flip_type)
        setattr(namespace, 'flip_word', flip_word)

        return
Example #13
0
def validate_token(token):
    """Validate token and retrieves info from Slack API."""
    # Set auth object
    auth = Auth(token)

    try:
        # Make request
        result = auth.test()

    except Error as err:
        report_event(str(err), {"token": token})
        abort(400)

    # Check for errors
    if not result.successful:
        report_event("token_invalid", {"token": token, "result": result.__dict__})
        abort(400)

    # Return user info
    return result.body
Example #14
0
def store_team(token, info):
    """Store a validated team in the database."""
    # Check if team exists
    team = Teams.query.get(info['team_id'])

    if team is None:
        # Create new team
        new_team = Teams(team_id=info['team_id'], token=token)

        # Store new team
        report_event('team_added', {'token': token, 'info': info})
        DB.session.add(new_team)

    else:
        # Update team token
        report_event('team_updated', {'token': token, 'info': info})
        team.token = token

    # Update DB
    DB.session.commit()
Example #15
0
def validate_state(state):
    """Validate state token returned by authentication."""
    try:
        # Attempt to decode state
        state_token = GENERATOR.loads(
            state, max_age=timedelta(minutes=60).total_seconds())

    except SignatureExpired:
        # Token has expired
        report_event('token_expired', {'state': state})
        abort(400)

    except BadSignature:
        # Token is not authorized
        report_event('token_not_authorized', {'state': state})
        abort(401)

    if state_token != PROJECT_INFO['client_id']:
        # Token is not authorized
        report_event('token_not_valid', {
            'state': state,
            'state_token': state_token
        })
        abort(401)

    # Return success
    return
Example #16
0
def flip(args):
    """Wrapper function for flip functions."""
    # Reset global error traker
    global ERRORS
    ERRORS = []

    # Make sure this is a valid slash command
    if args['command'] not in stf.ALLOWED_COMMANDS:
        stf.report_event('command_not_allowed', args)
        return '"{0}" is not an allowed command'.format(args['command'])

    else:
        # Set global command value to access later
        global COMMAND
        COMMAND = args['command']

    # Check to see if user has authenticated with the app
    token = check_user(args)

    # If the user or token is not valid, let them know
    if token is None or not is_valid_token(token):
        stf.report_event('auth_error', {'args': args, 'token': token})
        return AUTH_ERROR

    # If there's no input, use the default flip
    if not args['text']:
        flip_type = 'classic'
        flip_word = None

    else:
        # Set up text args for parser
        text_args = args['text'].split()

        # Get parser
        parser = get_parser()

        # Parse args
        result = parser.parse_args(text_args)

        # Report any errors from parser
        if len(ERRORS) > 0:
            stf.report_event('parser_errors', {'errors': ERRORS})
            return ERRORS[0]

        # Set values
        flip_type = result.flip_type
        flip_word = result.flip_word

    # Get requested flip
    table = do_flip(flip_type, flip_word)

    # Post flip as user
    err = send_flip(token, table, args)

    # If there were problems posting, report it
    if err is not None:
        return err

    # Return successful
    return ('', 204)
Example #17
0
def store_team(token, info):
    """Store a validated team in the database."""
    # Check if team exists
    team = Teams.query.get(info["team_id"])

    if team is None:
        # Create new team
        new_team = Teams(info["team_id"])
        new_team.token = token

        # Store new team
        report_event("team_added", {"token": token, "info": info})
        DB.session.add(new_team)

    else:
        # Update team token
        report_event("team_updated", {"token": token, "info": info})
        team.token = token

    # Update DB
    DB.session.commit()

    return
Example #18
0
def validate_token(token):
    """Validate token and retrieves info from Slack API."""
    # Set auth object
    auth = Auth(token)

    try:
        # Make request
        result = auth.test()

    except Error as err:
        report_event(str(err), {'token': token})
        abort(400)

    # Check for errors
    if not result.successful:
        report_event('token_invalid', {
            'token': token,
            'result': result.__dict__
        })
        abort(400)

    # Return user info
    return result.body
Example #19
0
    def __call__(self, parser, namespace, values, option_string=None):
        """Validate flip arguments and stores them to namespace."""
        flip_type = values[0].lower()
        flip_word = None

        # Check for help
        if flip_type in ['help', 'list', 'version']:
            parser.print_help(flip_type)
            return

        # Check that the type is valid
        if (flip_type not in stf.ALLOWED_TYPES
                and flip_type not in stf.WORD_TYPES
                and flip_type not in stf.RESTORE_TYPES):
            stf.report_event('flip_invalid', {'flip': flip_type})
            parser.error(
                'Flip type "{type}" is not known'.format(type=flip_type))

        if flip_type in stf.WORD_TYPES or flip_type in stf.RESTORE_TYPES:

            if len(values) >= 2:
                # Set word value
                flip_word = ' '.join(values[1:len(values)])

            else:
                # Check for flip that requires words
                if flip_type == 'word':
                    stf.report_event('flip_missing_word', {'flip': flip_type})
                    parser.error(
                        'Flip type "{type}" requires words to flip'.format(
                            type=flip_type))

        # Set values
        setattr(namespace, 'flip_type', flip_type)
        setattr(namespace, 'flip_word', flip_word)

        return
Example #20
0
def store_user(token, info):
    """Store a validated user in the database."""
    # Check if user exists
    user = DB.session.query(Users).filter(Users.id == info["user_id"]).filter(Users.team == info["team_id"]).first()

    if user is None:
        # Create new user
        new_user = Users(info["user_id"])
        new_user.team = info["team_id"]
        new_user.token = token

        # Store new user
        report_event("user_added", {"token": token, "info": info})
        DB.session.add(new_user)

    else:
        # Update user token
        report_event("user_updated", {"token": token, "info": info})
        user.token = token

    # Update DB
    DB.session.commit()

    return
Example #21
0
def is_valid_token(token):
    """Check that the user has a valid token."""
    # Set auth object
    auth = Auth(token)

    try:
        # Make request
        result = auth.test()

    except Error as err:
        # Check for auth errors
        stf.report_event(str(err), {'token': token})
        return False

    # Check for further errors
    if not result.successful:
        stf.report_event('token_invalid', {
            'token': token,
            'result': result.__dict__
        })
        return False

    # Return successful
    return True
Example #22
0
def validate_state(state):
    """Validate state token returned by authentication."""
    try:
        # Attempt to decode state
        state_token = GENERATOR.loads(state, max_age=timedelta(minutes=60).total_seconds())

    except SignatureExpired:
        # Token has expired
        report_event("token_expired", {"state": state})
        abort(400)

    except BadSignature:
        # Token is not authorized
        report_event("token_not_authorized", {"state": state})
        abort(401)

    if state_token != PROJECT_INFO["client_id"]:
        # Token is not authorized
        report_event("token_not_valid", {"state": state, "state_token": state_token})
        abort(401)

    # Return success
    return
Example #23
0
def flip(args):
    """Wrapper function for flip functions."""
    # Reset global error traker
    global ERRORS
    ERRORS = []

    # Make sure this is a valid slash command
    if args['command'] not in stf.ALLOWED_COMMANDS:
        stf.report_event('command_not_allowed', args)
        return '"{0}" is not an allowed command'.format(args['command'])

    else:
        # Set global command value to access later
        global COMMAND
        COMMAND = args['command']

    # Check to see if user has authenticated with the app
    token = check_user(args)

    # If the user or token is not valid, let them know
    if token is None or not is_valid_token(token):
        stf.report_event('auth_error', {
            'args': args,
            'token': token
        })
        return AUTH_ERROR

    # If there's no input, use the default flip
    if not args['text']:
        flip_type = 'classic'
        flip_word = None

    else:
        # Set up text args for parser
        text_args = args['text'].split()

        # Get parser
        parser = get_parser()

        # Parse args
        result = parser.parse_args(text_args)

        # Report any errors from parser
        if len(ERRORS) > 0:
            stf.report_event('parser_errors', {
                'errors': ERRORS
            })
            return ERRORS[0]

        # Set values
        flip_type = result.flip_type
        flip_word = result.flip_word

    # Get requested flip
    table = do_flip(flip_type, flip_word)

    # Post flip as user
    err = send_flip(token, table, args)

    # If there were problems posting, report it
    if err is not None:
        return err

    # Return successful
    return ('', 204)