from datetime import datetime, timedelta from app import app from data.database import db_for_update, User, ServiceKey, ServiceKeyApproval from data.model import ServiceKeyDoesNotExist, ServiceKeyAlreadyApproved, db_transaction from data.model.notification import create_notification UNAPPROVED_TTL = timedelta(seconds=app.config['UNAPPROVED_SERVICE_KEY_TTL_SEC']) def _gc_expired(service): expired_keys = ((ServiceKey.service == service) & (ServiceKey.expiration_date <= datetime.utcnow())) stale_unapproved_keys = ((ServiceKey.service >> service) & (ServiceKey.approval >> None) & (ServiceKey.created_date + UNAPPROVED_TTL) >= datetime.utcnow()) ServiceKey.delete().where(expired_keys | stale_unapproved_keys).execute() # TODO ACTION_LOGS for keys def upsert_service_key(name, kid, service, jwk, metadata, expiration_date): _gc_expired(service) try: with db_transaction(): key = db_for_update(ServiceKey.select().where(ServiceKey.kid == kid)).get() key.name = name key.metadata.update(metadata) key.expiration_date = expiration_date key.save() except ServiceKey.DoesNotExist: sk = ServiceKey.create(name=name, kid=kid, service=service, jwk=jwk, metadata=metadata, expiration_date=expiration_date) superusers = User.select().where(User.username << app.config['SUPER_USERS']) for superuser in superusers: # TODO(jzelinskie): create notification type in the database migration create_notification('service_key_submitted', superuser, { 'name': name, 'kid': kid, 'service': service, 'jwk': jwk, 'metadata': metadata, 'created_date': sk.created_date, 'expiration_date': expiration_date, }) def get_service_keys(service, kid=None): _gc_expired(service) query = ServiceKey.select().where(ServiceKey.service == service, ~(ServiceKey.approval >> None)) if kid: query.where(ServiceKey.kid == kid) return query def delete_service_key(service, kid): _gc_expired(service) try: ServiceKey.delete().where(ServiceKey.service == service, ServiceKey.kid == kid).execute() except ServiceKey.DoesNotExist: raise ServiceKeyDoesNotExist() def approve_service_key(service, kid, approver, approval_type): try: with db_transaction(): key = db_for_update(ServiceKey.select().where(ServiceKey.service == service, ServiceKey.kid == kid)).get() if key.approval is not None: raise ServiceKeyAlreadyApproved approval = ServiceKeyApproval.create(approver=approver, approval_type=approval_type) key.approval = approval key.save() except ServiceKey.DoesNotExist: raise ServiceKeyDoesNotExist