#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
This file is part of cpe package.
This module is used to the treatment of identifiers
of IT platforms (hardware, operating systems or applications of system)
in accordance with Well-Formed Name (WFN) of version 2.3 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 cpe import CPE
from cpe2_3 import CPE2_3
from comp.cpecomp import CPEComponent
from comp.cpecomp_logical import CPEComponentLogical
from comp.cpecomp2_3_wfn import CPEComponent2_3_WFN
from comp.cpecomp_undefined import CPEComponentUndefined
from comp.cpecomp_anyvalue import CPEComponentAnyValue
from comp.cpecomp_notapplicable import CPEComponentNotApplicable
[docs]class CPE2_3_WFN(CPE2_3):
"""
Implementation of WFN of version 2.3 of CPE specification.
A CPE Name is a percent-encoded WFN with each name
starting with the prefix 'wfn:'.
Each platform can be broken down into many distinct parts.
A CPE Name specifies a simple part and is used to identify
any platform that matches the description of that part.
The distinct parts are:
- Hardware part: the physical platform supporting the IT system.
- Operating system part: the operating system controls and manages the
IT hardware.
- Application part: software systems, services, servers, and packages
installed on the system.
CPE Name syntax: wfn:[a1=v1, a2=v2, …, an=vn]
Only the following attributes SHALL be permitted in a WFN
attribute-value pair:
a. part
b. vendor
c. product
d. version
e. update
f. edition
g. language
h. sw_edition
i. target_sw
j. target_hw
k. other
"""
###############
# CONSTANTS #
###############
#: Style of CPE Name
STYLE = CPE2_3.STYLE_WFN
#: Prefix of CPE Name with WFN style
CPE_PREFIX = "wfn:["
#: Suffix of CPE Name with WFN style
CPE_SUFFIX = "]"
####################
# OBJECT METHODS #
####################
[docs] def __new__(cls, cpe_str, *args, **kwargs):
"""
Create a new CPE Name of version 2.3 with WFN style.
:param string cpe_str: CPE Name string
:returns: CPE object of version 2.3 of CPE specification with
WFN style.
:rtype: CPE2_3_WFN
"""
return dict.__new__(cls)
def _parse(self):
"""
Checks if the CPE Name is valid.
:returns: None
:exception: ValueError - bad-formed CPE Name
"""
# Check prefix and initial bracket of WFN
if self._str[0:5] != CPE2_3_WFN.CPE_PREFIX:
errmsg = "Bad-formed CPE Name: WFN prefix not found"
raise ValueError(errmsg)
# Check final backet
if self._str[-1:] != "]":
errmsg = "Bad-formed CPE Name: final bracket of WFN not found"
raise ValueError(errmsg)
content = self._str[5:-1]
if content != "":
# Dictionary with pairs attribute-value
components = dict()
# Split WFN in components
list_component = content.split(CPEComponent2_3_WFN.SEPARATOR_COMP)
# Adds the defined components
for e in list_component:
# Whitespace not valid in component names and values
if e.find(" ") != -1:
msg = "Bad-formed CPE Name: WFN with too many whitespaces"
raise ValueError(msg)
# Split pair attribute-value
pair = e.split(CPEComponent2_3_WFN.SEPARATOR_PAIR)
att_name = pair[0]
att_value = pair[1]
# Check valid attribute name
if att_name not in CPEComponent.CPE_COMP_KEYS_EXTENDED:
msg = "Bad-formed CPE Name: invalid attribute name '{0}'".format(
att_name)
raise ValueError(msg)
if att_name in components:
# Duplicate attribute
msg = "Bad-formed CPE Name: attribute '{0}' repeated".format(
att_name)
raise ValueError(msg)
if not (att_value.startswith('"') and
att_value.endswith('"')):
# Logical value
strUpper = att_value.upper()
if strUpper == CPEComponent2_3_WFN.VALUE_ANY:
comp = CPEComponentAnyValue()
elif strUpper == CPEComponent2_3_WFN.VALUE_NA:
comp = CPEComponentNotApplicable()
else:
msg = "Invalid logical value '{0}'".format(att_value)
raise ValueError(msg)
elif att_value.startswith('"') and att_value.endswith('"'):
# String value
comp = CPEComponent2_3_WFN(att_value, att_name)
else:
# Bad value
msg = "Bad-formed CPE Name: invalid value '{0}'".format(
att_value)
raise ValueError(msg)
components[att_name] = comp
# Adds the undefined components
for ck in CPEComponent.CPE_COMP_KEYS_EXTENDED:
if ck not in components:
components[ck] = CPEComponentUndefined()
# #######################
# Storage of CPE Name #
# #######################
part_comp = components[CPEComponent.ATT_PART]
if isinstance(part_comp, CPEComponentLogical):
elements = []
elements.append(components)
self[CPE.KEY_UNDEFINED] = elements
else:
# Create internal structure of CPE Name in parts:
# one of them is filled with identified components,
# the rest are empty
part_value = part_comp.get_value()
# Del double quotes of value
system = part_value[1:-1]
if system in CPEComponent.SYSTEM_VALUES:
self._create_cpe_parts(system, components)
else:
self._create_cpe_parts(CPEComponent.VALUE_PART_UNDEFINED,
components)
# Fills the empty parts of internal structure of CPE Name
for pk in CPE.CPE_PART_KEYS:
if pk not in self.keys():
self[pk] = []
[docs] def get_attribute_values(self, att_name):
"""
Returns the values of attribute "att_name" of CPE Name.
By default a only element in each part.
:param string att_name: Attribute name to get
:returns: List of attribute values
:rtype: list
:exception: ValueError - invalid attribute name
"""
lc = []
if not CPEComponent.is_valid_attribute(att_name):
errmsg = "Invalid attribute name '{0}'".format(att_name)
raise ValueError(errmsg)
for pk in CPE.CPE_PART_KEYS:
elements = self.get(pk)
for elem in elements:
comp = elem.get(att_name)
if (isinstance(comp, CPEComponentAnyValue) or
isinstance(comp, CPEComponentUndefined)):
value = CPEComponent2_3_WFN.VALUE_ANY
elif isinstance(comp, CPEComponentNotApplicable):
value = CPEComponent2_3_WFN.VALUE_NA
else:
value = comp.get_value()
lc.append(value)
return lc
if __name__ == "__main__":
import doctest
doctest.testmod()
doctest.testfile("tests/testfile_cpe2_3_wfn.txt")