barbican/barbican/plugin/util/mime_types.py

155 lines
5.5 KiB
Python

# Copyright (c) 2013-2014 Rackspace, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Barbican defined mime-types
"""
from barbican.common import utils
# Supported content types
# Note: These types may be provided by clients.
PLAIN_TEXT = ['text/plain',
'text/plain;charset=utf-8',
'text/plain; charset=utf-8']
PLAIN_TEXT_CHARSETS = ['utf-8']
BINARY = ['application/octet-stream',
'application/pkcs8']
SUPPORTED = PLAIN_TEXT + BINARY
# Normalizes client types to internal types.
INTERNAL_CTYPES = {'text/plain': 'text/plain',
'text/plain;charset=utf-8': 'text/plain',
'text/plain; charset=utf-8': 'text/plain',
'application/octet-stream': 'application/octet-stream',
'application/pkcs8': 'application/pkcs8',
'application/aes': 'application/aes'}
# Maps mime-types used to specify secret data formats to the types that can
# be requested for secrets via GET calls.
# Note: Raw client types are converted into the 'INTERNAL_CTYPES' types
# which are then used as the keys to the 'CTYPES_MAPPINGS' below.
CTYPES_PLAIN = {'default': 'text/plain'}
CTYPES_BINARY = {'default': 'application/octet-stream'}
CTYPES_PKCS8 = {'default': 'application/pkcs8'}
CTYPES_AES = {'default': 'application/aes'}
CTYPES_MAPPINGS = {'text/plain': CTYPES_PLAIN,
'application/octet-stream': CTYPES_BINARY,
'application/pkcs8': CTYPES_PKCS8,
'application/aes': CTYPES_AES}
# Supported encodings
ENCODINGS = ['base64']
# Maps normalized content-types to supported encoding(s)
CTYPES_TO_ENCODINGS = {'text/plain': None,
'application/octet-stream': ['base64', 'binary'],
'application/pkcs8': ['base64', 'binary'],
'application/aes': None}
def normalize_content_type(mime_type):
"""Normalize the supplied content-type to an internal form."""
stripped = list(map(lambda x: x.strip(), mime_type.split(';')))
mime = stripped[0].lower()
if len(stripped) > 1:
# mime type includes charset
charset_type = stripped[1].lower()
if '=' not in charset_type:
# charset is malformed
return mime_type
else:
charset = list(map(lambda x: x.strip(),
charset_type.split('=')))[1]
if charset not in PLAIN_TEXT_CHARSETS:
# unsupported charset
return mime_type
return INTERNAL_CTYPES.get(mime, mime_type)
def is_supported(mime_type):
normalized_type = normalize_content_type(mime_type)
return normalized_type in SUPPORTED
def is_base64_encoding_supported(mime_type):
if is_supported(mime_type):
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[mime_type]]
return encodings and ('base64' in encodings)
return False
def is_content_type_with_encoding_supported(content_type, content_encoding):
if not is_supported(content_type):
return False
normalized_type = normalize_content_type(content_type)
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[normalized_type]]
if encodings:
return content_encoding in encodings
else:
return content_encoding is None
def get_supported_encodings(content_type):
normalized_type = normalize_content_type(content_type)
return CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[normalized_type]]
def is_base64_processing_needed(content_type, content_encoding):
content_encodings = utils.get_accepted_encodings_direct(content_encoding)
if content_encodings:
if 'base64' not in content_encodings:
return False
if is_supported(content_type):
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES[content_type]]
return encodings and 'base64' in encodings
return False
def use_binary_content_as_is(content_type, content_encoding):
"""Checks if headers are valid to allow binary content as-is."""
content_encodings = utils.get_accepted_encodings_direct(content_encoding)
if content_encodings:
if 'binary' not in content_encodings:
return False
if is_supported(content_type):
encodings = CTYPES_TO_ENCODINGS[INTERNAL_CTYPES.get(content_type)]
return encodings and 'binary' in encodings
return INTERNAL_CTYPES.get(content_type) in BINARY
def augment_fields_with_content_types(secret):
"""Add content-types and encodings information to a Secret's fields.
Generate a dict of content types based on the data associated
with the specified secret.
:param secret: The models.Secret instance to add 'content_types' to.
"""
fields = secret.to_dict_fields()
if not secret.secret_store_metadata:
return fields
content_type = secret.secret_store_metadata.get('content_type')
if content_type and content_type.value in CTYPES_MAPPINGS:
fields.update(
{'content_types': CTYPES_MAPPINGS[content_type.value]}
)
return fields