Source code for cpe.comp.cpecomp1_1

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This file is part of cpe package.

This module allows to store the value of the components of a CPE name
of version 1.1 of CPE (Common Platform Enumeration) specification.

Copyright (C) 2013  Alejandro Galindo García, Roberto Abdelkader Martínez Pérez

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

For any problems using the cpe package, or general questions and
feedback about it, please contact:

- Alejandro Galindo García: galindo.garcia.alejandro@gmail.com
- Roberto Abdelkader Martínez Pérez: robertomartinezp@gmail.com
"""

from cpecomp_simple import CPEComponentSimple
from cpecomp_undefined import CPEComponentUndefined
from cpecomp_empty import CPEComponentEmpty

import re


[docs]class CPEComponent1_1(CPEComponentSimple): """ Represents a component of version 1.1 of CPE specification. TEST: simple value >>> value = "microsoft" >>> comp = CPEComponent1_1(value, CPEComponentSimple.ATT_VENDOR) """ ############### # CONSTANTS # ############### #: Escape component separator _ESCAPE_SEPARATOR = "\\!" #: Pattern used in regular expression of the value of a component _STRING = "\w\.\-,\(\)@\#" #: Separator of components of CPE name with URI style SEPARATOR_COMP = ":" #: Characters of version 1.1 of CPE name to convert #: to standard value (WFN value) NON_STANDARD_VALUES = [".", "-", ",", "(", ")", "@", "#"] # Logical values in string format #: Logical value associated with a undefined component of CPE Name VALUE_UNDEFINED = None #: Logical value associated with a component without value set VALUE_EMPTY = "" #################### # OBJECT METHODS # ####################
[docs] def __contains__(self, item): """ Returns True if item is included in set of values of self. Comparatives in name matching of version 1.1 of CPE: | c = self._standard_value | d = item._standard_value | IF c is empty THEN match True. | ELSE IF c is a singleton AND c = d THEN match True. | ELSE IF c has form ~v AND v != d THEN match True. | ELSE IF c has form v1!v2!..!vn AND v = d for some v THEN match True. | ENDIF. :param CPEComponent item: component to find in self :returns: True if item is included in set of self :rtype: boolean TEST: two different simple values >>> comp1 = CPEComponent1_1('5.0', CPEComponentSimple.ATT_VERSION) >>> comp2 = CPEComponent1_1('9.0', CPEComponentSimple.ATT_VERSION) >>> comp1 in comp2 False """ if ((self == item) or isinstance(self, CPEComponentUndefined) or isinstance(self, CPEComponentEmpty)): return True dataset = self._standard_value dataitem = item._standard_value # len(self) == 1, check NOT operation if len(dataset) == 1: valset = dataset[0] if ((valset != dataitem) and self._is_negated and (not item._is_negated) and len(dataitem) == 1): return True else: return False # len(self) > 1, check OR operation eqNegated = self._is_negated == item._is_negated for elem in dataset: if ([elem] == dataitem) and eqNegated: return True return False
[docs] def __repr__(self): """ Returns a unambiguous representation of CPE component. :returns: Representation of CPE component as string :rtype: string """ value = self.get_value() result = [] if self._is_negated: value = value.replace("~", "") result.append("NOT ") result.append(self.__class__.__name__) result.append("(") result.append(value) result.append(")") return "".join(result)
def _decode(self): """ Convert the encoded value of component to standard value (WFN value). """ s = self._encoded_value elements = s.replace('~', '').split('!') dec_elements = [] for elem in elements: result = [] idx = 0 while (idx < len(elem)): # Get the idx'th character of s c = elem[idx] if (c in CPEComponent1_1.NON_STANDARD_VALUES): # Escape character result.append("\\") result.append(c) else: # Do nothing result.append(c) idx += 1 dec_elements.append("".join(result)) self._standard_value = dec_elements def _is_valid_value(self): """ Return True if the value of component in generic attribute is valid, and otherwise False. :returns: True if value is valid, False otherwise :rtype: boolean """ comp_str = self._encoded_value value_pattern = [] value_pattern.append("^((") value_pattern.append("~[") value_pattern.append(CPEComponent1_1._STRING) value_pattern.append("]+") value_pattern.append(")|(") value_pattern.append("[") value_pattern.append(CPEComponent1_1._STRING) value_pattern.append("]+(![") value_pattern.append(CPEComponent1_1._STRING) value_pattern.append("]+)*") value_pattern.append("))$") value_rxc = re.compile("".join(value_pattern)) return value_rxc.match(comp_str) is not None
[docs] def as_fs(self): r""" Returns the value of compoment encoded as formatted string. Inspect each character in value of component. Certain nonalpha characters pass thru without escaping into the result, but most retain escaping. :returns: Formatted string associated with the component :rtype: string TEST: >>> val = 'xp!vista' >>> comp1 = CPEComponent1_1(val, CPEComponentSimple.ATT_VERSION) >>> comp1.as_fs() 'xp\\!vista' """ result = [] for s in self._standard_value: idx = 0 while (idx < len(s)): c = s[idx] # get the idx'th character of s if c != "\\": # unquoted characters pass thru unharmed result.append(c) else: # Escaped characters are examined nextchr = s[idx + 1] if ((nextchr == ".") or (nextchr == "-") or (nextchr == "_")): # the period, hyphen and underscore pass unharmed result.append(nextchr) idx += 1 else: # all others retain escaping result.append("\\") result.append(nextchr) idx += 2 continue idx += 1 result.append(CPEComponent1_1._ESCAPE_SEPARATOR) return "".join(result[0:-1])
[docs] def as_uri_2_3(self): """ Returns the value of compoment encoded as URI string. Scans an input string s and applies the following transformations: - Pass alphanumeric characters thru untouched - Percent-encode quoted non-alphanumerics as needed - Unquoted special characters are mapped to their special forms. :returns: URI string :rtype: string TEST: >>> val = '#nvidi@' >>> comp1 = CPEComponent1_1(val, CPEComponentSimple.ATT_VENDOR) >>> comp1.as_uri_2_3() '%23nvidi%40' """ separator = CPEComponentSimple._pct_encode_uri("!") result = [] for s in self._standard_value: idx = 0 while (idx < len(s)): thischar = s[idx] # get the idx'th character of s # alphanumerics (incl. underscore) pass untouched if (CPEComponentSimple._is_alphanum(thischar)): result.append(thischar) idx += 1 continue # escape character if (thischar == "\\"): idx += 1 nxtchar = s[idx] result.append(CPEComponentSimple._pct_encode_uri(nxtchar)) idx += 1 continue idx += 1 result.append(separator) return "".join(result[0:-1])
[docs] def as_wfn(self): r""" Returns the value of compoment encoded as Well-Formed Name (WFN) string. :returns: WFN string :rtype: string TEST: >>> val = 'xp!vista' >>> comp1 = CPEComponent1_1(val, CPEComponentSimple.ATT_VERSION) >>> comp1.as_wfn() 'xp\\!vista' """ result = [] for s in self._standard_value: result.append(s) result.append(CPEComponent1_1._ESCAPE_SEPARATOR) return "".join(result[0:-1])
[docs] def set_value(self, comp_str, comp_att): """ Set the value of component. By default, the component has a simple value. :param string comp_att: attribute associated with value of component :returns: None :exception: ValueError - incorrect value of component TEST: >>> val = 'xp!vista' >>> val2 = 'sp2' >>> att = CPEComponentSimple.ATT_VERSION >>> comp1 = CPEComponent1_1(val, att) >>> comp1.set_value(val2, att) >>> comp1.get_value() 'sp2' """ super(CPEComponent1_1, self).set_value(comp_str, comp_att) self._is_negated = comp_str.startswith('~')
if __name__ == "__main__": import doctest doctest.testmod() doctest.testfile("../tests/testfile_cpecomp1_1.txt")