Example #1
0
class CheckVmc:
    def __init__(self, vmc_file, user_agent, is_file=False):
        self.STORAGE_CERT_DIR = Config.STORAGE_CERT_DIR
        self.vmc_file = vmc_file
        self.Utils = Utils()
        self.vmc_response = {
            "status": False,
            "errors": [],
            "vmc_link": vmc_file
        }
        self.is_file = is_file
        self.user_agent = user_agent

    def download_pem_path(self, url):
        print('Beginning file download certificate with urllib')
        self.Utils.check_dir_folder(self.STORAGE_CERT_DIR)
        file_name_hash = str(uuid.uuid4())
        req = Request(url, headers={'User-Agent': self.user_agent})
        with urlopen(req) as response, open(
                self.STORAGE_CERT_DIR + file_name_hash + ".pem",
                'wb') as out_file:
            data = response.read()
            out_file.write(data)
        return self.STORAGE_CERT_DIR + file_name_hash + ".pem"

    def validate_vmc(self):
        try:
            end_entity_cert = None
            intermediates = []
            with open(self.vmc_file, 'rb') as f:
                for type_name, headers, der_bytes in pem.unarmor(
                        f.read(), multiple=True):
                    if end_entity_cert is None:
                        end_entity_cert = der_bytes
                    else:
                        intermediates.append(der_bytes)
            validator = CertificateValidator(end_entity_cert, intermediates)
            validated = validator.validate_usage(set(['digital_signature']))
            # print(intermediates)
        except errors.PathValidationError as PathValidationError:
            self.vmc_response["errors"].append("Error: " +
                                               str(PathValidationError))
            print(PathValidationError)
        except errors.RevokedError as RevokedError:
            self.vmc_response["errors"].append(
                "Error: Certificate Revoked.\n" + str(RevokedError))
            print(RevokedError)
        except errors.InvalidCertificateError as InvalidCertificateError:
            self.vmc_response["errors"].append(
                "Error: Certificate Is Invalid.\n" +
                str(InvalidCertificateError))
            print(InvalidCertificateError)
        except errors.PathBuildingError as PathBuildingError:
            self.vmc_response["errors"].append("Error: Cannot Build Path.\n" +
                                               str(PathBuildingError))
            print(PathBuildingError)
        except Exception as e:
            self.vmc_response["errors"].append(
                "Error: Validation Exception.\n" + str(e))
            print(e)

    # Check VMC extension
    def is_vmc_extension(self):
        if self.is_file:
            if self.vmc_file != None:
                return True
            else:
                print(self.vmc_file,
                      "Upload Vmc certificates has an Invalid Extension")
                return False
        else:
            if self.vmc_file.endswith('.pem') or self.vmc_file.endswith(
                    '.PEM'):
                return True
            else:
                self.vmc_response["errors"].append(
                    "Invalid file extension use. Only .pem files allowed")
                return False

    # Check vmc certificate
    def check_vmc(self):
        if self.vmc_file != "":
            if not self.is_file:
                self.vmc_file = self.download_pem_path(self.vmc_file)
            if self.is_vmc_extension():
                self.validate_vmc()
                if len(self.vmc_response['errors']) > 0:
                    self.vmc_response['status'] = False
                else:
                    self.vmc_response['status'] = True
        else:
            # Currently vmc certificate is optional
            self.vmc_response['status'] = "Option"
        return self.vmc_response
Example #2
0
class CheckSvg:
    def __init__(self, svg_file, user_agent, is_file=False):
        self.RNG_SCHEMA_FILE = Config.RNG_SCHEMA_FILE
        self.STORAGE_SVG_DIR = Config.STORAGE_SVG_DIR
        self.svg_file = svg_file
        self.Utils = Utils()
        self.svg_image_path = None
        self.svg_response = {
            "status": False,
            "errors": [],
            "svg_link": svg_file
        }
        self.is_file = is_file
        self.user_agent = user_agent

    # Donwnload SVG
    def download_svg_path(self, url):
        print('Beginning SVG file download with requests')
        try:
            self.Utils.check_dir_folder(self.STORAGE_SVG_DIR)
            file_name_hash = str(uuid.uuid4())

            session = requests.Session()
            session.max_redirects = 3
            response = session.get(url,
                                   headers={'User-Agent': self.user_agent})
            if response:
                self.svg_image_path = self.STORAGE_SVG_DIR + file_name_hash + ".svg"
                with open(self.STORAGE_SVG_DIR + file_name_hash + ".svg",
                          'wb+') as out_file:
                    out_file.write(response.content)
                print("Generated file: " + self.STORAGE_SVG_DIR +
                      file_name_hash + ".svg")
                return self.STORAGE_SVG_DIR + file_name_hash + ".svg"
            else:
                response.raise_for_status()
                return False

        except HTTPError as http_err:
            self.svg_response['errors'].append({
                "short_error":
                "Http Error",
                "error_details":
                "An error occurred while fetching the BIMI SVG Image. " +
                str(http_err) + "."
            })
            print(f'HTTP error : {http_err}, occurred while fetching image')
            return False

        except requests.exceptions.TooManyRedirects as red_err:
            self.svg_response['errors'].append({
                "short_error":
                "Too many redirects",
                "error_details":
                "The svg URL redirected too many times, please remove the redirections, or atleast reduce them to 3 or less."
            })
            print(
                f'HTTP error : More than 3 redirects while fetching the svg image'
            )
            return False

        except Exception as e:
            print(e)
            self.svg_response["errors"].append({
                "short_error":
                "Something went wrong while downloading the SVG Image",
                "error_details":
                "The SVG file referenced by the URL in the BIMI record is unreachable by this validator."
            })
            return False

    # CHECK SVG Extension
    def is_svg_extension(self):
        print('Checking Svg extension')
        if self.is_file:
            if self.svg_file != None:
                return True
            else:
                print(self.svg_file,
                      "Upload SVG Image has an Invalid Extension")
                return False
        else:
            if self.svg_file.endswith('.svg') or self.svg_file.endswith(
                    '.SVG'):
                return True
            else:
                return False

    # Check if xml file has an SVG tag
    def is_svg_xml(self):
        print('Checking If this is an XML file')
        tag = None
        with open(self.svg_file, "r") as f:
            try:
                for event, el in et.iterparse(f, ('start', )):
                    tag = el.tag
                    break
            except et.ParseError:
                pass
        return tag == '{http://www.w3.org/2000/svg}svg'

    # SVG check function
    def check_svg(self):
        if self.svg_file != "":
            if self.is_svg_extension():
                if not self.is_file:
                    self.svg_file = self.download_svg_path(self.svg_file)
                    if not self.svg_file:
                        self.svg_response['status'] = False
                        return self.svg_response
                if self.svg_file:
                    if self.is_svg_xml():
                        self.check_svg_schema()
                        self.svg_image_path = self.svg_file
                        if len(self.svg_response['errors']) > 0:
                            self.svg_response['status'] = False
                        else:
                            self.svg_response['status'] = True
                    else:
                        self.svg_response['errors'].append({
                            "short_error":
                            "Invalid SVG",
                            "error_details":
                            "The SVG image in your BIMI record has no SVG tag"
                        })
                else:
                    self.svg_response['errors'].append({
                        "short_error":
                        "File extraction error",
                        "error_details":
                        "There was an issue with downloading the SVG. Either the SVG image file doesn't exist or the link is unreachable / blocked."
                    })
            else:
                self.svg_response['errors'].append({
                    "short_error":
                    "Extension Error",
                    "error_details":
                    "Invalid File extension"
                })
        else:
            self.svg_response['errors'].append({
                "short_error":
                "No SVG Image Found",
                "error_details":
                "We have found a blank/empty SVG file Or no SVG link in you BIMI record. Please check your BIMI record for this."
            })

        return self.svg_response

    # SVG check according to Relax Ng, rng file schema
    def check_svg_schema(self):
        try:
            result = subprocess.run(
                ['pyjing', "-c", self.RNG_SCHEMA_FILE, self.svg_file],
                stdout=subprocess.PIPE)
            # print(result.stdout)
            error_string = result.stdout.decode()
            if error_string:
                if error_string.find("error:") != -1:
                    err = error_string.split("\n")
                    for i in range(len(err)):
                        # print(err[i])
                        if err[i]:
                            clear_error_string = self.Utils.clear_response_single_string(
                                err[i].split('.svg:')[1])
                            error_str = self.Utils.strip_svg_plugin_errors(
                                self.STORAGE_SVG_DIR, clear_error_string,
                                ", Check Line ")
                            self.svg_response['errors'].append({
                                "short_error":
                                error_str,
                                "error_details":
                                clear_error_string
                            })
                    self.svg_response['status'] = False
            else:
                self.svg_response['status'] = True
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print(str(e))
Example #3
0
import logging as logger
from Config import Config
from datetime import date
from utils.Utils import Utils
log_level = Config.LOGGING_LEVEL
log_file_path = Config.LOG_FILE_PATH + str(
    date.today()) + "_" + Config.LOG_FILE_NAME
Utils = Utils()
Utils.check_dir_folder(Config.LOG_FILE_PATH)

if log_level == "INFO":
    log_level = logger.INFO
elif log_level == "DEBUG":
    log_level = logger.DEBUG
elif log_level == "WARNING":
    log_level = logger.WARN
else:
    log_level = logger.INFO

logger.basicConfig(
    filename=log_file_path,
    filemode='a',
    format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
    datefmt='%m/%d/%Y %H:%M:%S',
    level=log_level)
Example #4
0
class CheckSvg:
    def __init__(self, svg_file, user_agent, is_file=False):
        self.RNG_SCHEMA_FILE = Config.RNG_SCHEMA_FILE
        self.STORAGE_SVG_DIR = Config.STORAGE_SVG_DIR
        self.svg_file = svg_file
        self.Utils = Utils()
        self.svg_response = {
            "status": False,
            "errors": [],
            "svg_link": svg_file
        }
        self.is_file = is_file
        self.user_agent = user_agent

    # Donwnload SVG
    def download_svg_path(self, url):
        print('Beginning file download with urllib2')
        try:
            self.Utils.check_dir_folder(self.STORAGE_SVG_DIR)
            file_name_hash = str(uuid.uuid4())
            req = Request(url, headers={'User-Agent': self.user_agent})
            with urlopen(req) as response, open(
                    self.STORAGE_SVG_DIR + file_name_hash + ".svg",
                    'wb') as out_file:
                data = response.read()
                out_file.write(data)
            return self.STORAGE_SVG_DIR + file_name_hash + ".svg"
        except Exception as e:
            print(e)
            self.svg_response['errors'].append({
                "short_error":
                str(e),
                "error_details":
                clear_error_string
            })
            return

    # CHECK SVG Extension
    def is_svg_extension(self):
        if self.is_file:
            if self.svg_file != None:
                return True
            else:
                print(self.svg_file,
                      "Upload SVG Image has an Invalid Extension")
                return False
        else:
            if self.svg_file.endswith('.svg') or self.svg_file.endswith(
                    '.SVG'):
                return True
            else:
                return False

    # Check if xml file has an SVG tag
    def is_svg_xml(self):
        tag = None
        with open(self.svg_file, "r") as f:
            try:
                for event, el in et.iterparse(f, ('start', )):
                    tag = el.tag
                    break
            except et.ParseError:
                pass
        return tag == '{http://www.w3.org/2000/svg}svg'

    # SVG check function
    def check_svg(self):
        if self.svg_file != "":
            if self.is_svg_extension():
                if not self.is_file:
                    self.svg_file = self.download_svg_path(self.svg_file)
                if self.is_svg_xml():
                    self.check_svg_schema()
                    if len(self.svg_response['errors']) > 0:
                        self.svg_response['status'] = False
                    else:
                        self.svg_response['status'] = True
                else:
                    self.svg_response['errors'].append({
                        "short_error":
                        "Invalid SVG",
                        "error_details":
                        "The SVG image in your BIMI record has no SVG tag"
                    })
            else:
                self.svg_response['errors'].append({
                    "short_error":
                    "Extension Error",
                    "error_details":
                    "Invalid File extension"
                })
        else:
            self.svg_response['errors'].append({
                "short_error":
                "No SVG Image Found",
                "error_details":
                "We have found a blank/empty SVG file Or no SVG link in you BIMI record. Please check your BIMI record for this."
            })

        return self.svg_response

    # SVG check according to Relax Ng, rng file schema
    def check_svg_schema(self):
        try:
            result = subprocess.run(
                ['pyjing', "-c", self.RNG_SCHEMA_FILE, self.svg_file],
                stdout=subprocess.PIPE)
            # print(result.stdout)
            error_string = result.stdout.decode()
            if error_string:
                if error_string.find("error:") != -1:
                    err = error_string.split("error:")
                    for i in range(1, len(err) - 1):
                        clear_error_string = self.Utils.clear_response_single_string(
                            err[i])
                        error_str = self.Utils.strip_svg_plugin_errors(
                            self.STORAGE_SVG_DIR, clear_error_string,
                            ", Check Line ")
                        self.svg_response['errors'].append({
                            "short_error":
                            error_str,
                            "error_details":
                            clear_error_string
                        })
                    self.svg_response['status'] = False
            else:
                self.svg_response['status'] = True
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            print(str(e))
Example #5
0
class CheckVmc:
    def __init__(self, vmc_file, user_agent, svg_link='', is_file=False):
        self.STORAGE_CERT_DIR = Config.STORAGE_CERT_DIR
        self.vmc_file = vmc_file
        self.Utils = Utils()
        self.vmc_response = {
            "status": False,
            "errors": [],
            "vmc_link": vmc_file
        }
        self.is_file = is_file
        self.user_agent = user_agent
        self.parsed_vmc = None
        self.svg_link = svg_link
        self.pem_file_path = None

    def download_pem_path(self, url):
        try:
            print('Beginning VMC file download certificate')
            self.Utils.check_dir_folder(self.STORAGE_CERT_DIR)
            file_name_hash = str(uuid.uuid4())

            session = requests.Session()
            session.max_redirects = 3
            response = session.get(url,
                                   headers={'User-Agent': self.user_agent})
            if response:
                self.pem_file_path = self.STORAGE_CERT_DIR + file_name_hash + ".pem"
                with open(self.STORAGE_CERT_DIR + file_name_hash + ".pem",
                          'wb+') as out_file:
                    out_file.write(response.content)
                return self.STORAGE_CERT_DIR + file_name_hash + ".pem"
            else:
                response.raise_for_status()
                return False
        except HTTPError as http_err:
            self.vmc_response['errors'].append(
                "An error occurred while fetching the Certificate from the provided Url. "
                + str(http_err) + ".")
            print(
                f'HTTP error : {http_err} occurred while fetching the Certificate'
            )
            return False
        except requests.exceptions.TooManyRedirects as red_err:
            self.vmc_response['errors'].append(
                "The cetificate URL redirected too many times, please remove the redirections, or atleast reduce them to 3 or less."
            )
            print(
                f'HTTP error : {red_err}. More than 3 redirects while fetching the svg image'
            )
            return False
        except Exception as e:
            print(e)
            return False

    def validate_vmc(self):
        try:
            end_entity_cert = None
            intermediates = []
            with open(self.vmc_file, 'rb') as f:
                readfile = f.read()
                # Create parsed data for expiry and embedded svg check
                self.parsed_vmc = self.parse_vmc_cert(readfile)
                for type_name, headers, der_bytes in pem.unarmor(
                        readfile, multiple=True):
                    if end_entity_cert is None:
                        end_entity_cert = der_bytes
                    else:
                        intermediates.append(der_bytes)

            validator = CertificateValidator(end_entity_cert, intermediates)
            validated = validator.validate_usage(
                set(['digital_signature'])
                # ,extended_key_usage=set(["server_auth", "client_auth"])
            )
            if validated:
                print("Certificate Validated")

        except errors.PathValidationError as PathValidationError:
            self.vmc_response["errors"].append("Warning: " +
                                               str(PathValidationError))
            print(PathValidationError)
        except errors.RevokedError as RevokedError:
            self.vmc_response["errors"].append(
                "Warning: Certificate Revoked.\n" + str(RevokedError))
            print(RevokedError)
        except errors.InvalidCertificateError as InvalidCertificateError:
            self.vmc_response["errors"].append(
                "Warning: Certificate Is Invalid.\n" +
                str(InvalidCertificateError))
            print(InvalidCertificateError)
        except errors.PathBuildingError as PathBuildingError:
            # self.vmc_response["errors"].append("Warning: Cannot Build Path.\n"+str(PathBuildingError))
            print(PathBuildingError)
        except Exception as e:
            self.vmc_response["errors"].append(
                "Warning: Validation Exception.\n" + str(e))
            print(e)

    # Extract SVG image from VMC cert file
    def get_svg_from_cert(self):
        cert_svg = None
        for i in self.parsed_vmc.extensions:
            if hasattr(i.value, 'value') and 'svg' in str(i.value.value):
                data = (base64.b64decode(
                    str(i.value.value).split("data:image/svg+xml;base64,")[1]))
                svg = (gzip.decompress(data).decode())
                cert_svg = svg.strip()
                cert_svg = "".join(svg.split())
        return cert_svg

    # naive comapsion SVG in PEM with BIMI SVG
    def compare_pem_svg(self):
        cert_svg = self.get_svg_from_cert()
        if cert_svg:
            with open(self.svg_link, encoding='utf-8') as svg_file:
                # Remove indentation / tabs / newline
                svg = "".join((svg_file.read()).split())
                if svg.lower() == cert_svg.lower():
                    pass
                else:
                    self.vmc_response["errors"].append(
                        "The SVG image provided in the BIMI record doesn't match the SVG image provided in the pem file. Please make sure that they are the same.\n"
                    )
        else:
            self.vmc_response["errors"].append(
                "There's no embedded SVG Logotype Image as defined in svg logotype RFC 3709. \n"
            )

    # Check VMC extension
    def is_vmc_extension(self):
        if self.is_file:
            if self.vmc_file != None:
                return True
            else:
                print(self.vmc_file,
                      "Uploaded Vmc certificates has an Invalid Extension")
                return False
        else:
            if self.vmc_file.endswith('.pem') or self.vmc_file.endswith(
                    '.PEM'):
                return True
            else:
                self.vmc_response["errors"].append(
                    "Invalid file extension used. Only .pem files allowed")
                return False

    # Parse VMC certificate
    def parse_vmc_cert(self, pem_data):
        return x509.load_pem_x509_certificate(pem_data, default_backend())

    # Check certificate expiry
    def cert_validity(self):
        current_date_time = datetime.utcnow()
        print(current_date_time)
        print(self.parsed_vmc.not_valid_before)
        print(self.parsed_vmc.not_valid_after)
        if self.parsed_vmc.not_valid_before > current_date_time:
            print("VMC certificate not yet active")
            self.vmc_response["errors"].append(
                "The VMC certificate used is not yet active, and being used prior to the active date: "
                +
                self.parsed_vmc.not_valid_before.strftime("%m/%d/%Y, %H:%M:%S")
            )
            return False
        elif self.parsed_vmc.not_valid_after < current_date_time:
            print("VMC certificate expired")
            self.vmc_response["errors"].append(
                "The VMC certificate used is expired by date: " +
                self.parsed_vmc.not_valid_after.strftime("%m/%d/%Y, %H:%M:%S"))
            return False
        return True

    # Check VMC certificate
    def check_vmc(self):
        if self.vmc_file != "":
            if not self.is_file:
                self.vmc_file = self.download_pem_path(self.vmc_file)
                if not self.vmc_file:
                    self.vmc_response['status'] = False
                    return self.vmc_response
            else:
                self.pem_file_path = self.vmc_file

            if self.is_vmc_extension():
                # Read stored file and validate with certvalidator
                self.validate_vmc()
                # Check certificate expiry
                self.cert_validity()
                # Compare SVG in BIMI and SVG in PEM cert
                self.compare_pem_svg()
                if len(self.vmc_response['errors']) > 0:
                    self.vmc_response['status'] = False
                else:
                    self.vmc_response['status'] = True
        else:
            # Currently vmc certificate is optional
            self.vmc_response['status'] = "Option"
        return self.vmc_response