Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/boto/cloudfront/distribution.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.7/site-packages/boto/cloudfront/distribution.py Sat May 02 07:14:21 2020 -0400 @@ -0,0 +1,757 @@ +# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, dis- +# tribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the fol- +# lowing conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import uuid +import base64 +import time +from boto.compat import six, json +from boto.cloudfront.identity import OriginAccessIdentity +from boto.cloudfront.object import Object, StreamingObject +from boto.cloudfront.signers import ActiveTrustedSigners, TrustedSigners +from boto.cloudfront.logging import LoggingInfo +from boto.cloudfront.origin import S3Origin, CustomOrigin +from boto.s3.acl import ACL + +class DistributionConfig(object): + + def __init__(self, connection=None, origin=None, enabled=False, + caller_reference='', cnames=None, comment='', + trusted_signers=None, default_root_object=None, + logging=None): + """ + :param origin: Origin information to associate with the + distribution. If your distribution will use + an Amazon S3 origin, then this should be an + S3Origin object. If your distribution will use + a custom origin (non Amazon S3), then this + should be a CustomOrigin object. + :type origin: :class:`boto.cloudfront.origin.S3Origin` or + :class:`boto.cloudfront.origin.CustomOrigin` + + :param enabled: Whether the distribution is enabled to accept + end user requests for content. + :type enabled: bool + + :param caller_reference: A unique number that ensures the + request can't be replayed. If no + caller_reference is provided, boto + will generate a type 4 UUID for use + as the caller reference. + :type enabled: str + + :param cnames: A CNAME alias you want to associate with this + distribution. You can have up to 10 CNAME aliases + per distribution. + :type enabled: array of str + + :param comment: Any comments you want to include about the + distribution. + :type comment: str + + :param trusted_signers: Specifies any AWS accounts you want to + permit to create signed URLs for private + content. If you want the distribution to + use signed URLs, this should contain a + TrustedSigners object; if you want the + distribution to use basic URLs, leave + this None. + :type trusted_signers: :class`boto.cloudfront.signers.TrustedSigners` + + :param default_root_object: Designates a default root object. + Only include a DefaultRootObject value + if you are going to assign a default + root object for the distribution. + :type comment: str + + :param logging: Controls whether access logs are written for the + distribution. If you want to turn on access logs, + this should contain a LoggingInfo object; otherwise + it should contain None. + :type logging: :class`boto.cloudfront.logging.LoggingInfo` + + """ + self.connection = connection + self.origin = origin + self.enabled = enabled + if caller_reference: + self.caller_reference = caller_reference + else: + self.caller_reference = str(uuid.uuid4()) + self.cnames = [] + if cnames: + self.cnames = cnames + self.comment = comment + self.trusted_signers = trusted_signers + self.logging = logging + self.default_root_object = default_root_object + + def __repr__(self): + return "DistributionConfig:%s" % self.origin + + def to_xml(self): + s = '<?xml version="1.0" encoding="UTF-8"?>\n' + s += '<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">\n' + if self.origin: + s += self.origin.to_xml() + s += ' <CallerReference>%s</CallerReference>\n' % self.caller_reference + for cname in self.cnames: + s += ' <CNAME>%s</CNAME>\n' % cname + if self.comment: + s += ' <Comment>%s</Comment>\n' % self.comment + s += ' <Enabled>' + if self.enabled: + s += 'true' + else: + s += 'false' + s += '</Enabled>\n' + if self.trusted_signers: + s += '<TrustedSigners>\n' + for signer in self.trusted_signers: + if signer == 'Self': + s += ' <Self></Self>\n' + else: + s += ' <AwsAccountNumber>%s</AwsAccountNumber>\n' % signer + s += '</TrustedSigners>\n' + if self.logging: + s += '<Logging>\n' + s += ' <Bucket>%s</Bucket>\n' % self.logging.bucket + s += ' <Prefix>%s</Prefix>\n' % self.logging.prefix + s += '</Logging>\n' + if self.default_root_object: + dro = self.default_root_object + s += '<DefaultRootObject>%s</DefaultRootObject>\n' % dro + s += '</DistributionConfig>\n' + return s + + def startElement(self, name, attrs, connection): + if name == 'TrustedSigners': + self.trusted_signers = TrustedSigners() + return self.trusted_signers + elif name == 'Logging': + self.logging = LoggingInfo() + return self.logging + elif name == 'S3Origin': + self.origin = S3Origin() + return self.origin + elif name == 'CustomOrigin': + self.origin = CustomOrigin() + return self.origin + else: + return None + + def endElement(self, name, value, connection): + if name == 'CNAME': + self.cnames.append(value) + elif name == 'Comment': + self.comment = value + elif name == 'Enabled': + if value.lower() == 'true': + self.enabled = True + else: + self.enabled = False + elif name == 'CallerReference': + self.caller_reference = value + elif name == 'DefaultRootObject': + self.default_root_object = value + else: + setattr(self, name, value) + +class StreamingDistributionConfig(DistributionConfig): + + def __init__(self, connection=None, origin='', enabled=False, + caller_reference='', cnames=None, comment='', + trusted_signers=None, logging=None): + super(StreamingDistributionConfig, self).__init__(connection=connection, + origin=origin, enabled=enabled, + caller_reference=caller_reference, + cnames=cnames, comment=comment, + trusted_signers=trusted_signers, + logging=logging) + def to_xml(self): + s = '<?xml version="1.0" encoding="UTF-8"?>\n' + s += '<StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">\n' + if self.origin: + s += self.origin.to_xml() + s += ' <CallerReference>%s</CallerReference>\n' % self.caller_reference + for cname in self.cnames: + s += ' <CNAME>%s</CNAME>\n' % cname + if self.comment: + s += ' <Comment>%s</Comment>\n' % self.comment + s += ' <Enabled>' + if self.enabled: + s += 'true' + else: + s += 'false' + s += '</Enabled>\n' + if self.trusted_signers: + s += '<TrustedSigners>\n' + for signer in self.trusted_signers: + if signer == 'Self': + s += ' <Self/>\n' + else: + s += ' <AwsAccountNumber>%s</AwsAccountNumber>\n' % signer + s += '</TrustedSigners>\n' + if self.logging: + s += '<Logging>\n' + s += ' <Bucket>%s</Bucket>\n' % self.logging.bucket + s += ' <Prefix>%s</Prefix>\n' % self.logging.prefix + s += '</Logging>\n' + s += '</StreamingDistributionConfig>\n' + return s + +class DistributionSummary(object): + + def __init__(self, connection=None, domain_name='', id='', + last_modified_time=None, status='', origin=None, + cname='', comment='', enabled=False): + self.connection = connection + self.domain_name = domain_name + self.id = id + self.last_modified_time = last_modified_time + self.status = status + self.origin = origin + self.enabled = enabled + self.cnames = [] + if cname: + self.cnames.append(cname) + self.comment = comment + self.trusted_signers = None + self.etag = None + self.streaming = False + + def __repr__(self): + return "DistributionSummary:%s" % self.domain_name + + def startElement(self, name, attrs, connection): + if name == 'TrustedSigners': + self.trusted_signers = TrustedSigners() + return self.trusted_signers + elif name == 'S3Origin': + self.origin = S3Origin() + return self.origin + elif name == 'CustomOrigin': + self.origin = CustomOrigin() + return self.origin + return None + + def endElement(self, name, value, connection): + if name == 'Id': + self.id = value + elif name == 'Status': + self.status = value + elif name == 'LastModifiedTime': + self.last_modified_time = value + elif name == 'DomainName': + self.domain_name = value + elif name == 'Origin': + self.origin = value + elif name == 'CNAME': + self.cnames.append(value) + elif name == 'Comment': + self.comment = value + elif name == 'Enabled': + if value.lower() == 'true': + self.enabled = True + else: + self.enabled = False + elif name == 'StreamingDistributionSummary': + self.streaming = True + else: + setattr(self, name, value) + + def get_distribution(self): + return self.connection.get_distribution_info(self.id) + +class StreamingDistributionSummary(DistributionSummary): + + def get_distribution(self): + return self.connection.get_streaming_distribution_info(self.id) + +class Distribution(object): + + def __init__(self, connection=None, config=None, domain_name='', + id='', last_modified_time=None, status=''): + self.connection = connection + self.config = config + self.domain_name = domain_name + self.id = id + self.last_modified_time = last_modified_time + self.status = status + self.in_progress_invalidation_batches = 0 + self.active_signers = None + self.etag = None + self._bucket = None + self._object_class = Object + + def __repr__(self): + return "Distribution:%s" % self.domain_name + + def startElement(self, name, attrs, connection): + if name == 'DistributionConfig': + self.config = DistributionConfig() + return self.config + elif name == 'ActiveTrustedSigners': + self.active_signers = ActiveTrustedSigners() + return self.active_signers + else: + return None + + def endElement(self, name, value, connection): + if name == 'Id': + self.id = value + elif name == 'LastModifiedTime': + self.last_modified_time = value + elif name == 'Status': + self.status = value + elif name == 'InProgressInvalidationBatches': + self.in_progress_invalidation_batches = int(value) + elif name == 'DomainName': + self.domain_name = value + else: + setattr(self, name, value) + + def update(self, enabled=None, cnames=None, comment=None): + """ + Update the configuration of the Distribution. The only values + of the DistributionConfig that can be directly updated are: + + * CNAMES + * Comment + * Whether the Distribution is enabled or not + + Any changes to the ``trusted_signers`` or ``origin`` properties of + this distribution's current config object will also be included in + the update. Therefore, to set the origin access identity for this + distribution, set ``Distribution.config.origin.origin_access_identity`` + before calling this update method. + + :type enabled: bool + :param enabled: Whether the Distribution is active or not. + + :type cnames: list of str + :param cnames: The DNS CNAME's associated with this + Distribution. Maximum of 10 values. + + :type comment: str or unicode + :param comment: The comment associated with the Distribution. + + """ + new_config = DistributionConfig(self.connection, self.config.origin, + self.config.enabled, self.config.caller_reference, + self.config.cnames, self.config.comment, + self.config.trusted_signers, + self.config.default_root_object) + if enabled is not None: + new_config.enabled = enabled + if cnames is not None: + new_config.cnames = cnames + if comment is not None: + new_config.comment = comment + self.etag = self.connection.set_distribution_config(self.id, self.etag, new_config) + self.config = new_config + self._object_class = Object + + def enable(self): + """ + Activate the Distribution. A convenience wrapper around + the update method. + """ + self.update(enabled=True) + + def disable(self): + """ + Deactivate the Distribution. A convenience wrapper around + the update method. + """ + self.update(enabled=False) + + def delete(self): + """ + Delete this CloudFront Distribution. The content + associated with the Distribution is not deleted from + the underlying Origin bucket in S3. + """ + self.connection.delete_distribution(self.id, self.etag) + + def _get_bucket(self): + if isinstance(self.config.origin, S3Origin): + if not self._bucket: + bucket_dns_name = self.config.origin.dns_name + bucket_name = bucket_dns_name.replace('.s3.amazonaws.com', '') + from boto.s3.connection import S3Connection + s3 = S3Connection(self.connection.aws_access_key_id, + self.connection.aws_secret_access_key, + proxy=self.connection.proxy, + proxy_port=self.connection.proxy_port, + proxy_user=self.connection.proxy_user, + proxy_pass=self.connection.proxy_pass) + self._bucket = s3.get_bucket(bucket_name) + self._bucket.distribution = self + self._bucket.set_key_class(self._object_class) + return self._bucket + else: + raise NotImplementedError('Unable to get_objects on CustomOrigin') + + def get_objects(self): + """ + Return a list of all content objects in this distribution. + + :rtype: list of :class:`boto.cloudfront.object.Object` + :return: The content objects + """ + bucket = self._get_bucket() + objs = [] + for key in bucket: + objs.append(key) + return objs + + def set_permissions(self, object, replace=False): + """ + Sets the S3 ACL grants for the given object to the appropriate + value based on the type of Distribution. If the Distribution + is serving private content the ACL will be set to include the + Origin Access Identity associated with the Distribution. If + the Distribution is serving public content the content will + be set up with "public-read". + + :type object: :class:`boto.cloudfront.object.Object` + :param enabled: The Object whose ACL is being set + + :type replace: bool + :param replace: If False, the Origin Access Identity will be + appended to the existing ACL for the object. + If True, the ACL for the object will be + completely replaced with one that grants + READ permission to the Origin Access Identity. + + """ + if isinstance(self.config.origin, S3Origin): + if self.config.origin.origin_access_identity: + id = self.config.origin.origin_access_identity.split('/')[-1] + oai = self.connection.get_origin_access_identity_info(id) + policy = object.get_acl() + if replace: + policy.acl = ACL() + policy.acl.add_user_grant('READ', oai.s3_user_id) + object.set_acl(policy) + else: + object.set_canned_acl('public-read') + + def set_permissions_all(self, replace=False): + """ + Sets the S3 ACL grants for all objects in the Distribution + to the appropriate value based on the type of Distribution. + + :type replace: bool + :param replace: If False, the Origin Access Identity will be + appended to the existing ACL for the object. + If True, the ACL for the object will be + completely replaced with one that grants + READ permission to the Origin Access Identity. + + """ + bucket = self._get_bucket() + for key in bucket: + self.set_permissions(key, replace) + + def add_object(self, name, content, headers=None, replace=True): + """ + Adds a new content object to the Distribution. The content + for the object will be copied to a new Key in the S3 Bucket + and the permissions will be set appropriately for the type + of Distribution. + + :type name: str or unicode + :param name: The name or key of the new object. + + :type content: file-like object + :param content: A file-like object that contains the content + for the new object. + + :type headers: dict + :param headers: A dictionary containing additional headers + you would like associated with the new + object in S3. + + :rtype: :class:`boto.cloudfront.object.Object` + :return: The newly created object. + """ + if self.config.origin.origin_access_identity: + policy = 'private' + else: + policy = 'public-read' + bucket = self._get_bucket() + object = bucket.new_key(name) + object.set_contents_from_file(content, headers=headers, policy=policy) + if self.config.origin.origin_access_identity: + self.set_permissions(object, replace) + return object + + def create_signed_url(self, url, keypair_id, + expire_time=None, valid_after_time=None, + ip_address=None, policy_url=None, + private_key_file=None, private_key_string=None): + """ + Creates a signed CloudFront URL that is only valid within the specified + parameters. + + :type url: str + :param url: The URL of the protected object. + + :type keypair_id: str + :param keypair_id: The keypair ID of the Amazon KeyPair used to sign + theURL. This ID MUST correspond to the private key + specified with private_key_file or private_key_string. + + :type expire_time: int + :param expire_time: The expiry time of the URL. If provided, the URL + will expire after the time has passed. If not provided the URL will + never expire. Format is a unix epoch. + Use int(time.time() + duration_in_sec). + + :type valid_after_time: int + :param valid_after_time: If provided, the URL will not be valid until + after valid_after_time. Format is a unix epoch. + Use int(time.time() + secs_until_valid). + + :type ip_address: str + :param ip_address: If provided, only allows access from the specified + IP address. Use '192.168.0.10' for a single IP or + use '192.168.0.0/24' CIDR notation for a subnet. + + :type policy_url: str + :param policy_url: If provided, allows the signature to contain + wildcard globs in the URL. For example, you could + provide: 'http://example.com/media/\*' and the policy + and signature would allow access to all contents of + the media subdirectory. If not specified, only + allow access to the exact url provided in 'url'. + + :type private_key_file: str or file object. + :param private_key_file: If provided, contains the filename of the + private key file used for signing or an open + file object containing the private key + contents. Only one of private_key_file or + private_key_string can be provided. + + :type private_key_string: str + :param private_key_string: If provided, contains the private key string + used for signing. Only one of private_key_file or + private_key_string can be provided. + + :rtype: str + :return: The signed URL. + """ + # Get the required parameters + params = self._create_signing_params( + url=url, keypair_id=keypair_id, expire_time=expire_time, + valid_after_time=valid_after_time, ip_address=ip_address, + policy_url=policy_url, private_key_file=private_key_file, + private_key_string=private_key_string) + + #combine these into a full url + if "?" in url: + sep = "&" + else: + sep = "?" + signed_url_params = [] + for key in ["Expires", "Policy", "Signature", "Key-Pair-Id"]: + if key in params: + param = "%s=%s" % (key, params[key]) + signed_url_params.append(param) + signed_url = url + sep + "&".join(signed_url_params) + return signed_url + + def _create_signing_params(self, url, keypair_id, + expire_time=None, valid_after_time=None, + ip_address=None, policy_url=None, + private_key_file=None, private_key_string=None): + """ + Creates the required URL parameters for a signed URL. + """ + params = {} + # Check if we can use a canned policy + if expire_time and not valid_after_time and not ip_address and not policy_url: + # we manually construct this policy string to ensure formatting + # matches signature + policy = self._canned_policy(url, expire_time) + params["Expires"] = str(expire_time) + else: + # If no policy_url is specified, default to the full url. + if policy_url is None: + policy_url = url + # Can't use canned policy + policy = self._custom_policy(policy_url, expires=expire_time, + valid_after=valid_after_time, + ip_address=ip_address) + + encoded_policy = self._url_base64_encode(policy) + params["Policy"] = encoded_policy + #sign the policy + signature = self._sign_string(policy, private_key_file, private_key_string) + #now base64 encode the signature (URL safe as well) + encoded_signature = self._url_base64_encode(signature) + params["Signature"] = encoded_signature + params["Key-Pair-Id"] = keypair_id + return params + + @staticmethod + def _canned_policy(resource, expires): + """ + Creates a canned policy string. + """ + policy = ('{"Statement":[{"Resource":"%(resource)s",' + '"Condition":{"DateLessThan":{"AWS:EpochTime":' + '%(expires)s}}}]}' % locals()) + return policy + + @staticmethod + def _custom_policy(resource, expires=None, valid_after=None, ip_address=None): + """ + Creates a custom policy string based on the supplied parameters. + """ + condition = {} + # SEE: http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RestrictingAccessPrivateContent.html#CustomPolicy + # The 'DateLessThan' property is required. + if not expires: + # Defaults to ONE day + expires = int(time.time()) + 86400 + condition["DateLessThan"] = {"AWS:EpochTime": expires} + if valid_after: + condition["DateGreaterThan"] = {"AWS:EpochTime": valid_after} + if ip_address: + if '/' not in ip_address: + ip_address += "/32" + condition["IpAddress"] = {"AWS:SourceIp": ip_address} + policy = {"Statement": [{ + "Resource": resource, + "Condition": condition}]} + return json.dumps(policy, separators=(",", ":")) + + @staticmethod + def _sign_string(message, private_key_file=None, private_key_string=None): + """ + Signs a string for use with Amazon CloudFront. + Requires the rsa library be installed. + """ + try: + import rsa + except ImportError: + raise NotImplementedError("Boto depends on the python rsa " + "library to generate signed URLs for " + "CloudFront") + # Make sure only one of private_key_file and private_key_string is set + if private_key_file and private_key_string: + raise ValueError("Only specify the private_key_file or the private_key_string not both") + if not private_key_file and not private_key_string: + raise ValueError("You must specify one of private_key_file or private_key_string") + # If private_key_file is a file name, open it and read it + if private_key_string is None: + if isinstance(private_key_file, six.string_types): + with open(private_key_file, 'r') as file_handle: + private_key_string = file_handle.read() + # Otherwise, treat it like a file + else: + private_key_string = private_key_file.read() + + # Sign it! + private_key = rsa.PrivateKey.load_pkcs1(private_key_string) + signature = rsa.sign(str(message), private_key, 'SHA-1') + return signature + + @staticmethod + def _url_base64_encode(msg): + """ + Base64 encodes a string using the URL-safe characters specified by + Amazon. + """ + msg_base64 = base64.b64encode(msg) + msg_base64 = msg_base64.replace('+', '-') + msg_base64 = msg_base64.replace('=', '_') + msg_base64 = msg_base64.replace('/', '~') + return msg_base64 + +class StreamingDistribution(Distribution): + + def __init__(self, connection=None, config=None, domain_name='', + id='', last_modified_time=None, status=''): + super(StreamingDistribution, self).__init__(connection, config, + domain_name, id, last_modified_time, status) + self._object_class = StreamingObject + + def startElement(self, name, attrs, connection): + if name == 'StreamingDistributionConfig': + self.config = StreamingDistributionConfig() + return self.config + else: + return super(StreamingDistribution, self).startElement(name, attrs, + connection) + + def update(self, enabled=None, cnames=None, comment=None): + """ + Update the configuration of the StreamingDistribution. The only values + of the StreamingDistributionConfig that can be directly updated are: + + * CNAMES + * Comment + * Whether the Distribution is enabled or not + + Any changes to the ``trusted_signers`` or ``origin`` properties of + this distribution's current config object will also be included in + the update. Therefore, to set the origin access identity for this + distribution, set + ``StreamingDistribution.config.origin.origin_access_identity`` + before calling this update method. + + :type enabled: bool + :param enabled: Whether the StreamingDistribution is active or not. + + :type cnames: list of str + :param cnames: The DNS CNAME's associated with this + Distribution. Maximum of 10 values. + + :type comment: str or unicode + :param comment: The comment associated with the Distribution. + + """ + new_config = StreamingDistributionConfig(self.connection, + self.config.origin, + self.config.enabled, + self.config.caller_reference, + self.config.cnames, + self.config.comment, + self.config.trusted_signers) + if enabled is not None: + new_config.enabled = enabled + if cnames is not None: + new_config.cnames = cnames + if comment is not None: + new_config.comment = comment + self.etag = self.connection.set_streaming_distribution_config(self.id, + self.etag, + new_config) + self.config = new_config + self._object_class = StreamingObject + + def delete(self): + self.connection.delete_streaming_distribution(self.id, self.etag) + +