This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/api/appspecifictokens.py
2019-11-12 11:09:47 -05:00

133 lines
4 KiB
Python

""" Manages app specific tokens for the current user. """
import logging
import math
from datetime import timedelta
from flask import request
import features
from app import app
from auth.auth_context import get_authenticated_user
from data import model
from endpoints.api import (ApiResource, nickname, resource, validate_json_request,
log_action, require_user_admin, require_fresh_login,
path_param, NotFound, format_date, show_if, query_param, parse_args,
truthy_bool)
from util.timedeltastring import convert_to_timedelta
logger = logging.getLogger(__name__)
def token_view(token, include_code=False):
data = {
'uuid': token.uuid,
'title': token.title,
'last_accessed': format_date(token.last_accessed),
'created': format_date(token.created),
'expiration': format_date(token.expiration),
}
if include_code:
data.update({
'token_code': model.appspecifictoken.get_full_token_string(token),
})
return data
# The default window to use when looking up tokens that will be expiring.
_DEFAULT_TOKEN_EXPIRATION_WINDOW = '4w'
@resource('/v1/user/apptoken')
@show_if(features.APP_SPECIFIC_TOKENS)
class AppTokens(ApiResource):
""" Lists all app specific tokens for a user """
schemas = {
'NewToken': {
'type': 'object',
'required': [
'title',
],
'properties': {
'title': {
'type': 'string',
'description': 'The user-defined title for the token',
},
}
},
}
@require_user_admin
@nickname('listAppTokens')
@parse_args()
@query_param('expiring', 'If true, only returns those tokens expiring soon', type=truthy_bool)
def get(self, parsed_args):
""" Lists the app specific tokens for the user. """
expiring = parsed_args['expiring']
if expiring:
expiration = app.config.get('APP_SPECIFIC_TOKEN_EXPIRATION')
token_expiration = convert_to_timedelta(expiration or _DEFAULT_TOKEN_EXPIRATION_WINDOW)
seconds = math.ceil(token_expiration.total_seconds() * 0.1) or 1
soon = timedelta(seconds=seconds)
tokens = model.appspecifictoken.get_expiring_tokens(get_authenticated_user(), soon)
else:
tokens = model.appspecifictoken.list_tokens(get_authenticated_user())
return {
'tokens': [token_view(token, include_code=False) for token in tokens],
'only_expiring': expiring,
}
@require_user_admin
@require_fresh_login
@nickname('createAppToken')
@validate_json_request('NewToken')
def post(self):
""" Create a new app specific token for user. """
title = request.get_json()['title']
token = model.appspecifictoken.create_token(get_authenticated_user(), title)
log_action('create_app_specific_token', get_authenticated_user().username,
{'app_specific_token_title': token.title,
'app_specific_token': token.uuid})
return {
'token': token_view(token, include_code=True),
}
@resource('/v1/user/apptoken/<token_uuid>')
@show_if(features.APP_SPECIFIC_TOKENS)
@path_param('token_uuid', 'The uuid of the app specific token')
class AppToken(ApiResource):
""" Provides operations on an app specific token """
@require_user_admin
@require_fresh_login
@nickname('getAppToken')
def get(self, token_uuid):
""" Returns a specific app token for the user. """
token = model.appspecifictoken.get_token_by_uuid(token_uuid, owner=get_authenticated_user())
if token is None:
raise NotFound()
return {
'token': token_view(token, include_code=True),
}
@require_user_admin
@require_fresh_login
@nickname('revokeAppToken')
def delete(self, token_uuid):
""" Revokes a specific app token for the user. """
token = model.appspecifictoken.revoke_token_by_uuid(token_uuid, owner=get_authenticated_user())
if token is None:
raise NotFound()
log_action('revoke_app_specific_token', get_authenticated_user().username,
{'app_specific_token_title': token.title,
'app_specific_token': token.uuid})
return '', 204