"""Signed URLs Utility.""" import datetime import json from botocore.signers import CloudFrontSigner from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding from flask import g from asset_transcoder import config from asset_transcoder.constants import urls from asset_transcoder.utils.exceptions import OwsError key = None def _get_private_key(): global key if not key: key = serialization.load_pem_private_key( config.CLOUDFRONT_PRIVATE_KEY, password=None, backend=default_backend() ) return key def _rsa_signer(message): signing_key = _get_private_key() return signing_key.sign(message, padding.PKCS1v15(), hashes.SHA1()) def _sign_url(url, signer, policy): policy['Statement'][0]['Resource'] = url policy_json = json.dumps(policy, separators=(',', ':')) return signer.generate_presigned_url(url, policy=policy_json) def _get_policy_object(policy, duration): expire_date = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=duration) expires_at = int(expire_date.timestamp()) condition = { 'DateLessThan': { 'AWS:EpochTime': expires_at } } if policy == urls.SIGNED_URL_WITH_IP: condition['IpAddress'] = { 'AWS:SourceIp': g.client_ip } return { 'Statement': [ { 'Resource': None, 'Condition': condition } ] } def sign_urls(assets, policy, duration): """Generate signed urls for a list of assets with asset finals. Args: assets (list): List of asset_upload objects policy (str): Constant indicating how to sign the urls. duration (int): Number of minutes the signed urls are valid for. Returns: datetime.datetime: converted object """ if policy == urls.UNSIGNED_URL: return assets if not config.CLOUDFRONT_PRIVATE_KEY: raise OwsError.internal_server_error('Cloudfront private key is not set') key_id = config.CLOUDFRONT_KEY_PAIR_ID if not key_id: raise OwsError.internal_server_error('Cloudfront key id not set') signing_policy = _get_policy_object(policy, duration) cloudfront_signer = CloudFrontSigner(key_id, _rsa_signer) for asset in assets: for asset_final in asset['asset_finals']: asset_final['url'] = _sign_url(asset_final['url'], cloudfront_signer, signing_policy) return assets