All variables are now in snake case: API change.
This commit is contained in:
parent
1030f44ee3
commit
5649bee23e
|
@ -45,11 +45,10 @@ from .exceptions import (AssetsChecksumDoesNotMatch,
|
|||
P7MFileDoesNotHaveACoherentCryptographicalSignature,
|
||||
P7MFileNotAuthentic, XMLFileNotConformingToSchema)
|
||||
|
||||
|
||||
#######
|
||||
# API #
|
||||
#######
|
||||
|
||||
|
||||
def is_xml_file_conforming_to_schema(xml_file: str,
|
||||
xml_schema_file: str) -> bool:
|
||||
r"""Check that the XML file follows its schema.
|
||||
|
@ -470,44 +469,44 @@ def write_configuration_file(configuration_file: str):
|
|||
:raises: a configparser or a built-in exception.
|
||||
"""
|
||||
config = dict()
|
||||
config['metadata file'] = {
|
||||
'XML namespace':
|
||||
const.XML['metadata file']['namespaces']['default'],
|
||||
'XML invoice checksum tag':
|
||||
const.XML['metadata file']['tags']['invoice checksum'],
|
||||
'XML invoice filename tag':
|
||||
const.XML['metadata file']['tags']['invoice filename'],
|
||||
'XML system id tag':
|
||||
const.XML['metadata file']['tags']['system id']
|
||||
config['metadata_file'] = {
|
||||
'xml_namespace':
|
||||
const.xml['metadata_file']['namespaces']['default'],
|
||||
'xml_invoice_checksum_tag':
|
||||
const.xml['metadata_file']['tags']['invoice_checksum'],
|
||||
'xml_invoice_filename_tag':
|
||||
const.xml['metadata_file']['tags']['invoice_filename'],
|
||||
'xml_system_id_tag':
|
||||
const.xml['metadata_file']['tags']['system_id']
|
||||
}
|
||||
config['trusted list file'] = {
|
||||
'XML namespace': const.XML['trusted list file']['namespaces']['default'],
|
||||
'XML certificate tag': const.XML['trusted list file']['tags']['certificate'],
|
||||
'download': const.Downloads['trusted list file']['default'],
|
||||
config['trusted_list_file'] = {
|
||||
'xml_namespace': const.xml['trusted_list_file']['namespaces']['default'],
|
||||
'xml_certificate_tag': const.xml['trusted_list_file']['tags']['certificate'],
|
||||
'download': const.downloads['trusted_list_file']['default'],
|
||||
}
|
||||
config['invoice file'] = {
|
||||
'XML namespace':
|
||||
const.XML['invoice file']['namespaces']['default'],
|
||||
'XML attachment tag':
|
||||
const.XML['invoice file']['tags']['attachment'],
|
||||
'XML attachment filename tag':
|
||||
const.XML['invoice file']['tags']['attachment filename'],
|
||||
'XML attachment XPath':
|
||||
const.XML['invoice file']['XPath']['attachment'],
|
||||
'text encoding':
|
||||
const.XML['invoice file']['proprieties']['text encoding'],
|
||||
'XSD download':
|
||||
const.Downloads['invoice file']['XSD']['default'],
|
||||
'W3C XSD download':
|
||||
const.Downloads['invoice file']['XSD']['W3C Schema for XML Signatures'],
|
||||
'XSLT ordinaria download':
|
||||
const.Downloads['invoice file']['XSLT']['ordinaria'],
|
||||
'XSLT PA download':
|
||||
const.Downloads['invoice file']['XSLT']['PA'],
|
||||
'attachment extension whitelist':
|
||||
const.File['invoice']['attachment']['extension whitelist'],
|
||||
'attachment filetype whitelist':
|
||||
const.File['invoice']['attachment']['filetype whitelist']
|
||||
config['invoice_file'] = {
|
||||
'xml_namespace':
|
||||
const.xml['invoice_file']['namespaces']['default'],
|
||||
'xml_attachment_tag':
|
||||
const.xml['invoice_file']['tags']['attachment'],
|
||||
'xml_attachment_filename_tag':
|
||||
const.xml['invoice_file']['tags']['attachment_filename'],
|
||||
'xml_attachment_xpath':
|
||||
const.xml['invoice_file']['xpath']['attachment'],
|
||||
'text_encoding':
|
||||
const.xml['invoice_file']['proprieties']['text_encoding'],
|
||||
'xsd_download':
|
||||
const.downloads['invoice_file']['xsd']['default'],
|
||||
'w3c_xsd_download':
|
||||
const.downloads['invoice_file']['xsd']['w3c_schema_for_xml_signatures'],
|
||||
'xslt_ordinaria_download':
|
||||
const.downloads['invoice_file']['xslt']['ordinaria'],
|
||||
'xslt_pa_download':
|
||||
const.downloads['invoice_file']['xslt']['pa'],
|
||||
'attachment_extension_whitelist':
|
||||
const.file['invoice']['attachment']['extension_whitelist'],
|
||||
'attachment_filetype_whitelist':
|
||||
const.file['invoice']['attachment']['filetype_whitelist']
|
||||
}
|
||||
|
||||
with open(configuration_file, 'w') as configfile:
|
||||
|
@ -537,136 +536,136 @@ def assert_data_structure(source: str, file_type: str, data: dict):
|
|||
|
||||
if 'patched' not in data:
|
||||
raise ValueError
|
||||
if 'configuration file' not in data:
|
||||
if 'configuration_file' not in data:
|
||||
raise ValueError
|
||||
if 'write default configuration file' not in data:
|
||||
if 'write_default_configuration_file' not in data:
|
||||
raise ValueError
|
||||
if 'ignore assets checksum' not in data:
|
||||
if 'ignore_assets_checksum' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['patched'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['configuration file'], str):
|
||||
if not isinstance(data['configuration_file'], str):
|
||||
raise TypeError
|
||||
if not isinstance(data['write default configuration file'], bool):
|
||||
if not isinstance(data['write_default_configuration_file'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['ignore assets checksum'], bool):
|
||||
if not isinstance(data['ignore_assets_checksum'], bool):
|
||||
raise TypeError
|
||||
|
||||
if source == 'invoice':
|
||||
if 'extract attachments' not in data:
|
||||
if 'extract_attachments' not in data:
|
||||
raise ValueError
|
||||
if 'invoice xslt type' not in data:
|
||||
if 'invoice_xslt_type' not in data:
|
||||
raise ValueError
|
||||
if 'no invoice xml validation' not in data:
|
||||
if 'no_invoice_xml_validation' not in data:
|
||||
raise ValueError
|
||||
if 'force invoice schema file download' not in data:
|
||||
if 'force_invoice_schema_file_download' not in data:
|
||||
raise ValueError
|
||||
if 'generate html output' not in data:
|
||||
if 'generate_html_output' not in data:
|
||||
raise ValueError
|
||||
if 'invoice filename' not in data:
|
||||
if 'invoice_filename' not in data:
|
||||
raise ValueError
|
||||
if 'no checksum check' not in data:
|
||||
if 'no_checksum_check' not in data:
|
||||
raise ValueError
|
||||
if 'force invoice xml stylesheet file download' not in data:
|
||||
if 'force_invoice_xml_stylesheet_file_download' not in data:
|
||||
raise ValueError
|
||||
if 'ignore attachment extension whitelist' not in data:
|
||||
if 'ignore_attachment_extension_whitelist' not in data:
|
||||
raise ValueError
|
||||
if 'ignore attachment filetype whitelist' not in data:
|
||||
if 'ignore_attachment_filetype_whitelist' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['extract attachments'], bool):
|
||||
if not isinstance(data['extract_attachments'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['invoice xslt type'], str):
|
||||
if not isinstance(data['invoice_xslt_type'], str):
|
||||
raise TypeError
|
||||
if not isinstance(data['no invoice xml validation'], bool):
|
||||
if not isinstance(data['no_invoice_xml_validation'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['force invoice schema file download'], bool):
|
||||
if not isinstance(data['force_invoice_schema_file_download'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['generate html output'], bool):
|
||||
if not isinstance(data['generate_html_output'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['invoice filename'], str):
|
||||
if not isinstance(data['invoice_filename'], str):
|
||||
raise TypeError
|
||||
if not isinstance(data['no checksum check'], bool):
|
||||
if not isinstance(data['no_checksum_check'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['force invoice xml stylesheet file download'],
|
||||
if not isinstance(data['force_invoice_xml_stylesheet_file_download'],
|
||||
bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['ignore attachment extension whitelist'], bool):
|
||||
if not isinstance(data['ignore_attachment_extension_whitelist'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['ignore attachment filetype whitelist'], bool):
|
||||
if not isinstance(data['ignore_attachment_filetype_whitelist'], bool):
|
||||
raise TypeError
|
||||
if data['patched']:
|
||||
if 'metadata file' not in data:
|
||||
if 'metadata_file' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['metadata file'], str):
|
||||
if not isinstance(data['metadata_file'], str):
|
||||
raise TypeError
|
||||
else:
|
||||
if 'metadata files' not in data:
|
||||
if 'metadata_files' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['metadata files'], list):
|
||||
if not isinstance(data['metadata_files'], list):
|
||||
raise TypeError
|
||||
for m in data['metadata files']:
|
||||
for m in data['metadata_files']:
|
||||
if not isinstance(m, str):
|
||||
raise TypeError
|
||||
|
||||
if file_type == 'p7m':
|
||||
if 'ignore signature check' not in data:
|
||||
if 'ignore_signature_check' not in data:
|
||||
raise ValueError
|
||||
if 'ignore signers certificate check' not in data:
|
||||
if 'ignore_signers_certificate_check' not in data:
|
||||
raise ValueError
|
||||
if 'force trusted list file download' not in data:
|
||||
if 'force_trusted_list_file_download' not in data:
|
||||
raise ValueError
|
||||
if 'keep original file' not in data:
|
||||
if 'keep_original_file' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['ignore signature check'], bool):
|
||||
if not isinstance(data['ignore_signature_check'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['ignore signers certificate check'], bool):
|
||||
if not isinstance(data['ignore_signers_certificate_check'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['force trusted list file download'], bool):
|
||||
if not isinstance(data['force_trusted_list_file_download'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['keep original file'], bool):
|
||||
if not isinstance(data['keep_original_file'], bool):
|
||||
raise TypeError
|
||||
ok = True
|
||||
elif file_type == 'plain':
|
||||
ok = True
|
||||
elif source == 'generic':
|
||||
if file_type == 'p7m':
|
||||
if 'ignore signature check' not in data:
|
||||
if 'ignore_signature_check' not in data:
|
||||
raise ValueError
|
||||
if 'ignore signers certificate check' not in data:
|
||||
if 'ignore_signers_certificate_check' not in data:
|
||||
raise ValueError
|
||||
if 'force trusted list file download' not in data:
|
||||
if 'force_trusted_list_file_download' not in data:
|
||||
raise ValueError
|
||||
if 'keep original file' not in data:
|
||||
if 'keep_original_file' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['ignore signature check'], bool):
|
||||
if not isinstance(data['ignore_signature_check'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['ignore signers certificate check'], bool):
|
||||
if not isinstance(data['ignore_signers_certificate_check'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['force trusted list file download'], bool):
|
||||
if not isinstance(data['force_trusted_list_file_download'], bool):
|
||||
raise TypeError
|
||||
if not isinstance(data['keep original file'], bool):
|
||||
if not isinstance(data['keep_original_file'], bool):
|
||||
raise TypeError
|
||||
if data['patched']:
|
||||
if 'p7m file' not in data:
|
||||
if 'p7m_file' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['p7m file'], str):
|
||||
if not isinstance(data['p7m_file'], str):
|
||||
raise TypeError
|
||||
else:
|
||||
if 'p7m files' not in data:
|
||||
if 'p7m_files' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['p7m files'], list):
|
||||
if not isinstance(data['p7m_files'], list):
|
||||
raise TypeError
|
||||
for p in data['p7m files']:
|
||||
for p in data['p7m_files']:
|
||||
if not isinstance(p, str):
|
||||
raise TypeError
|
||||
ok = True
|
||||
elif source == 'NOOP':
|
||||
if file_type == 'NOOP':
|
||||
if 'write default configuration file' not in data:
|
||||
if 'write_default_configuration_file' not in data:
|
||||
raise ValueError
|
||||
if not isinstance(data['write default configuration file'], bool):
|
||||
if not isinstance(data['write_default_configuration_file'], bool):
|
||||
raise TypeError
|
||||
if not data['write default configuration file']:
|
||||
if not data['write_default_configuration_file']:
|
||||
raise ValueError
|
||||
ok = True
|
||||
|
||||
|
@ -686,7 +685,7 @@ def asset_checksum_matches(file: str) -> bool:
|
|||
m = hashlib.sha512()
|
||||
matches = False
|
||||
m.update(open(file, 'rb').read())
|
||||
if m.hexdigest() == const.Checksum[pathlib.Path(file).name]:
|
||||
if m.hexdigest() == const.checksum[pathlib.Path(file).name]:
|
||||
matches = True
|
||||
|
||||
return matches
|
||||
|
@ -715,59 +714,59 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
|
||||
project_name = 'fattura_elettronica_reader'
|
||||
create_appdirs(project_name)
|
||||
configuration_file = data['configuration file']
|
||||
configuration_file = data['configuration_file']
|
||||
if configuration_file == str():
|
||||
configuration_file = define_appdirs_user_config_dir_file_path(
|
||||
project_name, const.Paths['configuration file'])
|
||||
if not pathlib.Path(configuration_file).is_file() or data['write default configuration file']:
|
||||
project_name, const.paths['configuration_file'])
|
||||
if not pathlib.Path(configuration_file).is_file() or data['write_default_configuration_file']:
|
||||
write_configuration_file(configuration_file)
|
||||
|
||||
pathlib.Path(data['destination directory']).mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
pathlib.Path(data['destination_directory']).mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
|
||||
if source != 'NOOP' and file_type != 'NOOP':
|
||||
config = yaml.load(open(configuration_file, 'r'), Loader=yaml.SafeLoader)
|
||||
|
||||
# Define all the paths for the static elements.
|
||||
trusted_list_file = define_appdirs_user_data_dir_file_path(
|
||||
project_name, const.Paths['trusted list file'])
|
||||
project_name, const.paths['trusted_list_file'])
|
||||
ca_certificate_pem_file = define_appdirs_user_data_dir_file_path(
|
||||
project_name, const.Paths['CA certificate pem file'])
|
||||
project_name, const.paths['ca_certificate_pem_file'])
|
||||
w3c_schema_file_for_xml_signatures = define_appdirs_user_data_dir_file_path(
|
||||
project_name,
|
||||
const.Paths['invoice file']['XSD']['W3C Schema for XML Signatures'])
|
||||
const.paths['invoice_file']['xsd']['w3c_schema_for_xml_signatures'])
|
||||
|
||||
if source == 'invoice':
|
||||
invoice_schema_file = define_appdirs_user_data_dir_file_path(
|
||||
project_name, const.Paths['invoice file']['XSD']['default'])
|
||||
project_name, const.paths['invoice_file']['xsd']['default'])
|
||||
invoice_xslt_file = define_appdirs_user_data_dir_file_path(
|
||||
project_name,
|
||||
const.Paths['invoice file']['XSLT'][data['invoice xslt type']])
|
||||
const.paths['invoice_file']['xslt'][data['invoice_xslt_type']])
|
||||
|
||||
# See also:
|
||||
# https://www.fatturapa.gov.it/export/fatturazione/sdi/messaggi/v1.0/MT_v1.0.xsl
|
||||
metadata_root = parse_xml_file(data['metadata file'])
|
||||
if data['invoice filename'] == str():
|
||||
metadata_root = parse_xml_file(data['metadata_file'])
|
||||
if data['invoice_filename'] == str():
|
||||
invoice_filename = get_invoice_filename(
|
||||
metadata_root,
|
||||
config['metadata file']['XML invoice filename tag'],
|
||||
dict(default=config['metadata file']['XML namespace']))
|
||||
config['metadata_file']['xml_invoice_filename_tag'],
|
||||
dict(default=config['metadata_file']['xml_namespace']))
|
||||
if invoice_filename is None:
|
||||
raise MissingTagInMetadataFile
|
||||
else:
|
||||
invoice_filename = data['invoice filename']
|
||||
invoice_filename = data['invoice_filename']
|
||||
|
||||
# Assume the invoice file is in the same directory of the metadata file.
|
||||
if not pathlib.Path(invoice_filename).is_file():
|
||||
invoice_filename = str(
|
||||
pathlib.Path(
|
||||
pathlib.Path(data['metadata file']).parent,
|
||||
pathlib.Path(data['metadata_file']).parent,
|
||||
pathlib.Path(invoice_filename)))
|
||||
|
||||
if not data['no checksum check']:
|
||||
if not data['no_checksum_check']:
|
||||
checksum_matches, checksum = invoice_file_checksum_matches(
|
||||
metadata_root, invoice_filename,
|
||||
config['metadata file']['XML invoice checksum tag'],
|
||||
dict(default=config['metadata file']['XML namespace']))
|
||||
config['metadata_file']['xml_invoice_checksum_tag'],
|
||||
dict(default=config['metadata_file']['xml_namespace']))
|
||||
if checksum is None:
|
||||
raise MissingTagInMetadataFile
|
||||
if not checksum_matches:
|
||||
|
@ -775,7 +774,7 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
|
||||
file_to_consider = invoice_filename
|
||||
elif source == 'generic':
|
||||
file_to_consider = data['p7m file']
|
||||
file_to_consider = data['p7m_file']
|
||||
|
||||
# Apparently, invoices must be signed for 'PA' and not necessarly for
|
||||
# 'B2B' and other cases. I could not find official documentation
|
||||
|
@ -786,49 +785,49 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
if not is_p7m_file_signed(file_to_consider):
|
||||
raise P7MFileDoesNotHaveACoherentCryptographicalSignature
|
||||
|
||||
if data['force trusted list file download'] or not pathlib.Path(
|
||||
if data['force_trusted_list_file_download'] or not pathlib.Path(
|
||||
trusted_list_file).is_file():
|
||||
get_remote_file(trusted_list_file,
|
||||
config['trusted list file']['download'])
|
||||
config['trusted_list_file']['download'])
|
||||
|
||||
if not data['ignore assets checksum']:
|
||||
if not data['ignore_assets_checksum']:
|
||||
if not asset_checksum_matches(trusted_list_file):
|
||||
raise AssetsChecksumDoesNotMatch("Run the program with the '--ignore-assets-checksum' option, contact the developer or open a pull request. Have a look at " + const.Docs['assets url'])
|
||||
raise AssetsChecksumDoesNotMatch("Run the program with the '--ignore-assets-checksum' option, contact the developer or open a pull request. Have a look at " + const.docs['assets url'])
|
||||
|
||||
trusted_list_xml_root = parse_xml_file(trusted_list_file)
|
||||
|
||||
get_ca_certificates(trusted_list_xml_root, ca_certificate_pem_file,
|
||||
config['trusted list file']['XML namespace'],
|
||||
config['trusted list file']['XML certificate tag'])
|
||||
config['trusted_list_file']['xml_namespace'],
|
||||
config['trusted_list_file']['xml_certificate_tag'])
|
||||
|
||||
if (not (source == 'invoice' and file_type == 'plain')) or (
|
||||
source == 'invoice'
|
||||
and file_type == 'p7m') or (source == 'generic'
|
||||
and file_type == 'p7m'):
|
||||
if not is_p7m_file_authentic(file_to_consider, ca_certificate_pem_file,
|
||||
data['ignore signature check'],
|
||||
data['ignore signers certificate check']):
|
||||
data['ignore_signature_check'],
|
||||
data['ignore_signers_certificate_check']):
|
||||
raise P7MFileNotAuthentic
|
||||
|
||||
if source == 'invoice' or ('no invoice xml validation' in data and
|
||||
(not data['no invoice xml validation'])):
|
||||
if source == 'invoice' or ('no_invoice_xml_validation' in data and
|
||||
(not data['no_invoice_xml_validation'])):
|
||||
# This W3C file should not change any time soon so we can avoid the force download option.
|
||||
if not pathlib.Path(w3c_schema_file_for_xml_signatures).is_file():
|
||||
get_remote_file(w3c_schema_file_for_xml_signatures,
|
||||
config['invoice file']['W3C XSD download'])
|
||||
config['invoice_file']['W3C XSD download'])
|
||||
|
||||
if data['force invoice schema file download'] or not pathlib.Path(
|
||||
if data['force_invoice_schema_file_download'] or not pathlib.Path(
|
||||
invoice_schema_file).is_file():
|
||||
get_remote_file(invoice_schema_file,
|
||||
config['invoice file']['XSD download'])
|
||||
config['invoice_file']['XSD download'])
|
||||
|
||||
patch_invoice_schema_file(
|
||||
invoice_schema_file,
|
||||
const.Patch['invoice file']['XSD']['line'][0]['offending'],
|
||||
const.Patch['invoice file']['XSD']['line'][0]['fix'])
|
||||
const.patch['invoice_file']['xsd']['line'][0]['offending'],
|
||||
const.patch['invoice_file']['xsd']['line'][0]['fix'])
|
||||
|
||||
# Verify the checksum of the patched file.
|
||||
if not data['ignore assets checksum']:
|
||||
if not data['ignore_assets_checksum']:
|
||||
if not asset_checksum_matches(invoice_schema_file):
|
||||
raise AssetsChecksumDoesNotMatch("Run the program with the '--ignore-assets-checksum' option, contact the developer or open a pull request. Have a look at https://frnmst.github.io/fattura-elettronica-reader/assets.html")
|
||||
|
||||
|
@ -869,7 +868,7 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
raise CannotExtractOriginalP7MFile
|
||||
|
||||
if source == 'invoice':
|
||||
if not data['no invoice xml validation']:
|
||||
if not data['no_invoice_xml_validation']:
|
||||
if not is_xml_file_conforming_to_schema(
|
||||
str(
|
||||
pathlib.Path(tmpdirname,
|
||||
|
@ -882,29 +881,29 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
pathlib.Path(tmpdirname,
|
||||
file_to_consider_original_relative)))
|
||||
|
||||
if data['extract attachments']:
|
||||
if data['extract_attachments']:
|
||||
extract_attachments_from_invoice_file(
|
||||
invoice_root,
|
||||
config['invoice file']['XML attachment XPath'],
|
||||
config['invoice file']['XML attachment tag'],
|
||||
config['invoice file']['XML attachment filename tag'],
|
||||
config['invoice file']['text encoding'],
|
||||
data['ignore attachment extension whitelist'],
|
||||
data['ignore attachment filetype whitelist'],
|
||||
config['invoice file']['attachment extension whitelist'],
|
||||
config['invoice file']['attachment filetype whitelist'],
|
||||
data['destination directory'])
|
||||
config['invoice_file']['xml_attachment_xpath'],
|
||||
config['invoice_file']['xml_attachment_tag'],
|
||||
config['invoice_file']['xml_attachment_filename_tag'],
|
||||
config['invoice_file']['text_encoding'],
|
||||
data['ignore_attachment_extension_whitelist'],
|
||||
data['ignore_attachment_filetype_whitelist'],
|
||||
config['invoice_file']['attachment_extension_whitelist'],
|
||||
config['invoice_file']['attachment_filetype_whitelist'],
|
||||
data['destination_directory'])
|
||||
|
||||
if data['generate html output']:
|
||||
if data['force invoice xml stylesheet file download'] or not pathlib.Path(
|
||||
if data['generate_html_output']:
|
||||
if data['force_invoice_xml_stylesheet_file_download'] or not pathlib.Path(
|
||||
invoice_xslt_file).is_file():
|
||||
get_remote_file(
|
||||
invoice_xslt_file,
|
||||
config['invoice file']['XSLT ' +
|
||||
data['invoice xslt type'] +
|
||||
' download'])
|
||||
config['invoice_file']['xslt_' +
|
||||
data['invoice_xslt_type'] +
|
||||
'_download'])
|
||||
|
||||
if not data['ignore assets checksum']:
|
||||
if not data['ignore_assets_checksum']:
|
||||
if not asset_checksum_matches(invoice_xslt_file):
|
||||
raise AssetsChecksumDoesNotMatch("Run the program with the '--ignore-assets-checksum' option, contact the developer or open a pull request. Have a look at https://frnmst.github.io/fattura-elettronica-reader/assets.html")
|
||||
|
||||
|
@ -913,18 +912,18 @@ def pipeline(source: str, file_type: str, data: dict):
|
|||
|
||||
get_invoice_as_html(invoice_root, invoice_xslt_root,
|
||||
html_output,
|
||||
config['invoice file']['text encoding'],
|
||||
data['destination directory'])
|
||||
config['invoice_file']['text_encoding'],
|
||||
data['destination_directory'])
|
||||
|
||||
if (source == 'invoice'
|
||||
and file_type == 'p7m') or (source == 'generic'
|
||||
and file_type == 'p7m'):
|
||||
if data['keep original file']:
|
||||
if data['keep_original_file']:
|
||||
shutil.move(
|
||||
str(
|
||||
pathlib.Path(tmpdirname,
|
||||
file_to_consider_original_relative)),
|
||||
str(pathlib.Path(data['destination directory'], file_to_consider_original_relative)))
|
||||
str(pathlib.Path(data['destination_directory'], file_to_consider_original_relative)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# cli.py
|
||||
#
|
||||
# Copyright (c) 2018 Enio Carboni - Italy
|
||||
# Copyright (C) 2019-2020 Franco Masotti (franco \D\o\T masotti {-A-T-} tutanota \D\o\T com)
|
||||
# Copyright (C) 2019-2022 Franco Masotti (franco \D\o\T masotti {-A-T-} tutanota \D\o\T com)
|
||||
#
|
||||
# This file is part of fattura-elettronica-reader.
|
||||
#
|
||||
|
@ -50,85 +50,85 @@ class CliToApi():
|
|||
common_data = {
|
||||
'patched':
|
||||
False,
|
||||
'configuration file':
|
||||
'configuration_file':
|
||||
args.configuration_file,
|
||||
'write default configuration file':
|
||||
'write_default_configuration_file':
|
||||
args.write_default_configuration_file,
|
||||
'ignore assets checksum':
|
||||
'ignore_assets_checksum':
|
||||
args.ignore_assets_checksum,
|
||||
'destination directory':
|
||||
'destination_directory':
|
||||
args.destination_directory,
|
||||
}
|
||||
|
||||
# Prepare the data structure.
|
||||
if args.source == 'invoice':
|
||||
data = {
|
||||
'extract attachments':
|
||||
'extract_attachments':
|
||||
args.extract_attachments,
|
||||
'metadata files':
|
||||
'metadata_files':
|
||||
args.metadata_file,
|
||||
'invoice xslt type':
|
||||
'invoice_xslt_type':
|
||||
args.invoice_xslt_type,
|
||||
'no invoice xml validation':
|
||||
'no_invoice_xml_validation':
|
||||
args.no_invoice_xml_validation,
|
||||
'force invoice schema file download':
|
||||
'force_invoice_schema_file_download':
|
||||
args.force_invoice_schema_file_download,
|
||||
'generate html output':
|
||||
'generate_html_output':
|
||||
args.generate_html_output,
|
||||
'invoice filename':
|
||||
'invoice_filename':
|
||||
args.invoice_filename,
|
||||
'no checksum check':
|
||||
'no_checksum_check':
|
||||
args.no_checksum_check,
|
||||
'force invoice xml stylesheet file download':
|
||||
'force_invoice_xml_stylesheet_file_download':
|
||||
args.force_invoice_xml_stylesheet_file_download,
|
||||
'ignore attachment extension whitelist':
|
||||
'ignore_attachment_extension_whitelist':
|
||||
args.ignore_attachment_extension_whitelist,
|
||||
'ignore attachment filetype whitelist':
|
||||
'ignore_attachment_filetype_whitelist':
|
||||
args.ignore_attachment_filetype_whitelist,
|
||||
}
|
||||
if args.file_type == 'p7m':
|
||||
data['ignore signature check'] = args.ignore_signature_check
|
||||
data['ignore_signature_check'] = args.ignore_signature_check
|
||||
data[
|
||||
'ignore signers certificate check'] = args.ignore_signers_certificate_check
|
||||
'ignore_signers_certificate_check'] = args.ignore_signers_certificate_check
|
||||
data[
|
||||
'force trusted list file download'] = args.force_trusted_list_file_download
|
||||
data['keep original file'] = args.keep_original_file
|
||||
'force_trusted_list_file_download'] = args.force_trusted_list_file_download
|
||||
data['keep_original_file'] = args.keep_original_file
|
||||
elif args.file_type == 'plain':
|
||||
pass
|
||||
elif args.source == 'generic':
|
||||
if args.file_type == 'p7m':
|
||||
data = {
|
||||
'p7m files': args.p7m_file,
|
||||
'ignore signature check': args.ignore_signature_check,
|
||||
'ignore signers certificate check':
|
||||
'p7m_files': args.p7m_file,
|
||||
'ignore_signature_check': args.ignore_signature_check,
|
||||
'ignore_signers_certificate_check':
|
||||
args.ignore_signers_certificate_check,
|
||||
'force trusted list file download':
|
||||
'force_trusted_list_file_download':
|
||||
args.force_trusted_list_file_download,
|
||||
'keep original file': args.keep_original_file,
|
||||
'keep_original_file': args.keep_original_file,
|
||||
}
|
||||
else:
|
||||
data = {'write default configuration file': True}
|
||||
data = {'write_default_configuration_file': True}
|
||||
|
||||
# Merge the dicts.
|
||||
data = {**common_data, **data}
|
||||
|
||||
if args.source == 'invoice':
|
||||
iterator = data['metadata files']
|
||||
iterator = data['metadata_files']
|
||||
elif args.source == 'generic':
|
||||
iterator = data['p7m files']
|
||||
iterator = data['p7m_files']
|
||||
else:
|
||||
# Write the config file and quit.
|
||||
iterator = ['config file']
|
||||
iterator = ['config_file']
|
||||
|
||||
for i in iterator:
|
||||
# Patch data with single files.
|
||||
data['patched'] = True
|
||||
if args.source == 'invoice':
|
||||
data['metadata file'] = i
|
||||
data['metadata_file'] = i
|
||||
source = args.source
|
||||
file_type = args.file_type
|
||||
elif args.source == 'generic':
|
||||
data['p7m file'] = i
|
||||
data['p7m_file'] = i
|
||||
source = args.source
|
||||
file_type = args.file_type
|
||||
else:
|
||||
|
@ -265,7 +265,7 @@ class CliInterface():
|
|||
invoice_p7m_parser.add_argument('-o',
|
||||
'--keep-original-file',
|
||||
action='store_true',
|
||||
help='keep the original file')
|
||||
help='extract the plain XML file')
|
||||
|
||||
invoice_p7m_parser.add_argument('metadata_file',
|
||||
nargs='+',
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# constants.py
|
||||
#
|
||||
# Copyright (c) 2018 Enio Carboni - Italy
|
||||
# Copyright (C) 2019-2021 Franco Masotti (franco \D\o\T masotti {-A-T-} tutanota \D\o\T com)
|
||||
# Copyright (C) 2019-2022 Franco Masotti (franco \D\o\T masotti {-A-T-} tutanota \D\o\T com)
|
||||
#
|
||||
# This file is part of fattura-elettronica-reader.
|
||||
#
|
||||
|
@ -24,75 +24,75 @@
|
|||
from pathlib import Path
|
||||
|
||||
common_defaults = dict()
|
||||
common_defaults = {'home directory': Path.home()}
|
||||
common_defaults = {'home_directory': Path.home()}
|
||||
|
||||
XML = dict()
|
||||
XML['metadata file'] = dict()
|
||||
XML['trusted list file'] = dict()
|
||||
XML['invoice file'] = dict()
|
||||
xml = dict()
|
||||
xml['metadata_file'] = dict()
|
||||
xml['trusted_list_file'] = dict()
|
||||
xml['invoice_file'] = dict()
|
||||
|
||||
XML['metadata file']['namespaces'] = {
|
||||
xml['metadata_file']['namespaces'] = {
|
||||
'default':
|
||||
'http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fattura/messaggi/v1.0'
|
||||
}
|
||||
|
||||
XML['metadata file']['tags'] = {
|
||||
'invoice checksum': 'Hash',
|
||||
'invoice filename': 'NomeFile',
|
||||
'system id': 'IdentificativoSdI'
|
||||
xml['metadata_file']['tags'] = {
|
||||
'invoice_checksum': 'Hash',
|
||||
'invoice_filename': 'NomeFile',
|
||||
'system_id': 'IdentificativoSdI'
|
||||
}
|
||||
|
||||
XML['trusted list file']['namespaces'] = {
|
||||
xml['trusted_list_file']['namespaces'] = {
|
||||
'default': 'http://uri.etsi.org/02231/v2#'
|
||||
}
|
||||
|
||||
XML['trusted list file']['tags'] = {'certificate': 'X509Certificate'}
|
||||
xml['trusted_list_file']['tags'] = {'certificate': 'X509Certificate'}
|
||||
|
||||
XML['invoice file']['namespaces'] = {
|
||||
xml['invoice_file']['namespaces'] = {
|
||||
'default': 'http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2'
|
||||
}
|
||||
|
||||
XML['invoice file']['tags'] = {
|
||||
xml['invoice_file']['tags'] = {
|
||||
'attachment': 'Attachment',
|
||||
'attachment filename': 'NomeAttachment'
|
||||
'attachment_filename': 'NomeAttachment'
|
||||
}
|
||||
|
||||
XML['invoice file']['XPath'] = {
|
||||
xml['invoice_file']['xpath'] = {
|
||||
'attachment': './FatturaElettronicaBody/Allegati'
|
||||
}
|
||||
|
||||
# See:
|
||||
# https://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.2.1/Schema_del_file_xml_FatturaPA_versione_1.2.1.xsd
|
||||
XML['invoice file']['proprieties'] = {'text encoding': 'UTF-8'}
|
||||
xml['invoice_file']['proprieties'] = {'text_encoding': 'UTF-8'}
|
||||
|
||||
# Download urls.
|
||||
Downloads = dict()
|
||||
downloads = dict()
|
||||
|
||||
Downloads['invoice file'] = dict()
|
||||
Downloads['invoice file']['XSLT'] = {
|
||||
downloads['invoice_file'] = dict()
|
||||
downloads['invoice_file']['xslt'] = {
|
||||
# Pubblica Amministrazione.
|
||||
'PA':
|
||||
'pa':
|
||||
'https://www.fatturapa.gov.it/export/documenti/fatturapa/v1.2.1/Foglio_di_stile_fatturaPA_v1.2.1.xsl',
|
||||
'ordinaria':
|
||||
'https://www.fatturapa.gov.it/export/documenti/fatturapa/v1.2.1/Foglio_di_stile_fatturaordinaria_v1.2.1.xsl'
|
||||
}
|
||||
Downloads['invoice file']['XSD'] = {
|
||||
downloads['invoice_file']['xsd'] = {
|
||||
'default':
|
||||
'https://www.fatturapa.gov.it/export/documenti/fatturapa/v1.2.1/Schema_del_file_xml_FatturaPA_versione_1.2.1a.xsd',
|
||||
'W3C Schema for XML Signatures':
|
||||
'w3c_schema_for_xml_signatures':
|
||||
'https://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd'
|
||||
}
|
||||
|
||||
Downloads['trusted list file'] = {
|
||||
downloads['trusted_list_file'] = {
|
||||
'default': 'https://eidas.agid.gov.it/TL/TSL-IT.xml'
|
||||
}
|
||||
|
||||
# File Patches.
|
||||
Patch = dict()
|
||||
Patch['invoice file'] = dict()
|
||||
Patch['invoice file']['XSD'] = dict()
|
||||
Patch['invoice file']['XSD']['line'] = dict()
|
||||
Patch['invoice file']['XSD']['line'][0] = {
|
||||
# file patches.
|
||||
patch = dict()
|
||||
patch['invoice_file'] = dict()
|
||||
patch['invoice_file']['xsd'] = dict()
|
||||
patch['invoice_file']['xsd']['line'] = dict()
|
||||
patch['invoice_file']['xsd']['line'][0] = {
|
||||
'offending':
|
||||
2 * ' ' +
|
||||
'<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd" />\n',
|
||||
|
@ -102,51 +102,51 @@ Patch['invoice file']['XSD']['line'][0] = {
|
|||
}
|
||||
|
||||
# Relative paths.
|
||||
Paths = dict()
|
||||
Paths['trusted list file'] = 'trusted_list.xml'
|
||||
Paths['CA certificate pem file'] = 'CA.pem'
|
||||
Paths['invoice file'] = dict()
|
||||
paths = dict()
|
||||
paths['trusted_list_file'] = 'trusted_list.xml'
|
||||
paths['ca_certificate_pem_file'] = 'CA.pem'
|
||||
paths['invoice_file'] = dict()
|
||||
# Invoice stylesheet files.
|
||||
Paths['invoice file']['XSLT'] = {
|
||||
'PA': 'invoice_stylesheet_PA.xslt',
|
||||
paths['invoice_file']['xslt'] = {
|
||||
'pa': 'invoice_stylesheet_PA.xslt',
|
||||
'ordinaria': 'invoice_stylesheet_ordinaria.xslt'
|
||||
}
|
||||
# Invoice schema files.
|
||||
Paths['invoice file']['XSD'] = {
|
||||
# Invoice schema files (xsd).
|
||||
paths['invoice_file']['xsd'] = {
|
||||
'default': 'invoice_schema.xsd',
|
||||
'W3C Schema for XML Signatures': 'xmldsig-core-schema.xsd'
|
||||
'w3c_schema_for_xml_signatures': 'xmldsig-core-schema.xsd'
|
||||
}
|
||||
Paths['configuration file'] = 'fattura_elettronica_reader.conf'
|
||||
paths['configuration_file'] = 'fattura_elettronica_reader.conf'
|
||||
|
||||
# Stuff related generically to files.
|
||||
File = dict()
|
||||
File['invoice'] = dict()
|
||||
File['invoice']['attachment'] = {
|
||||
'extension whitelist': ['PDF', 'pdf'],
|
||||
file = dict()
|
||||
file['invoice'] = dict()
|
||||
file['invoice']['attachment'] = {
|
||||
'extension_whitelist': ['PDF', 'pdf'],
|
||||
# Uses mimes.
|
||||
'filetype whitelist': ['application/pdf']
|
||||
'filetype_whitelist': ['application/pdf']
|
||||
}
|
||||
|
||||
#############
|
||||
# Checksums #
|
||||
# checksums #
|
||||
#############
|
||||
# SHA-512 checksum of the assets.
|
||||
Checksum = dict()
|
||||
Checksum[Paths['invoice file']['XSLT']['PA']] = 'd1ca406c6bb174aa351eae4d6ca162b459e00ab3993d87f977c118c0edfe4201c8aec54c7498f324285a56677885cb11bba5de02ae0c9e46b63ab679eb7aa4a2'
|
||||
Checksum[Paths['invoice file']['XSLT']['ordinaria']] = '2c315cbb04126e98192c0afa585fe3b264ed4fada044504cf9ad77f2272e26106916239e86238dc250f15f5b22a33383e2e690ae28a5f5eb7a8a3b84d3f393b3'
|
||||
checksum = dict()
|
||||
checksum[paths['invoice_file']['xslt']['pa']] = 'd1ca406c6bb174aa351eae4d6ca162b459e00ab3993d87f977c118c0edfe4201c8aec54c7498f324285a56677885cb11bba5de02ae0c9e46b63ab679eb7aa4a2'
|
||||
checksum[paths['invoice_file']['xslt']['ordinaria']] = '2c315cbb04126e98192c0afa585fe3b264ed4fada044504cf9ad77f2272e26106916239e86238dc250f15f5b22a33383e2e690ae28a5f5eb7a8a3b84d3f393b3'
|
||||
|
||||
# Checksum of the patched schema file, not of the original one which is
|
||||
# checksum of the patched schema file, not of the original one which is
|
||||
# 2a7c3f2913ee390c167e41ae5618c303b481f548f9b2a8d60dddc36804ddd3ebf7cb5003e5cc6996480c67d085b82b438aff7cc0f74d7c104225449785cb575b
|
||||
#
|
||||
# The XML schema file for FatturaPA version 1.2.1 needs to be patched. fattura_elettronica_reader
|
||||
# The xml schema file for FatturaPA version 1.2.1 needs to be patched. fattura_elettronica_reader
|
||||
# runs the SHA-512 checksum on the patched version of that file which corresponds to:
|
||||
Checksum[Paths['invoice file']['XSD']['default']] = 'a1b02818f81ac91f35358260dd12e1bf4480e1545bb457caffa0d434200a1bd05bedd88df2d897969485a989dda78922850ebe978b92524778a37cb0afacba27'
|
||||
checksum[paths['invoice_file']['xsd']['default']] = 'a1b02818f81ac91f35358260dd12e1bf4480e1545bb457caffa0d434200a1bd05bedd88df2d897969485a989dda78922850ebe978b92524778a37cb0afacba27'
|
||||
|
||||
# TSL-IT.xml
|
||||
Checksum[Paths['trusted list file']] = 'd6b8c13a5574fb34f658f1122c3c4cd72fd7f9b59f51b3ab9e3972e6aebc19ab432de4706b4473d467f4bd6966fe49296389b3f9164ba593cac9c81843a83155'
|
||||
checksum[paths['trusted_list_file']] = 'd6b8c13a5574fb34f658f1122c3c4cd72fd7f9b59f51b3ab9e3972e6aebc19ab432de4706b4473d467f4bd6966fe49296389b3f9164ba593cac9c81843a83155'
|
||||
|
||||
Docs = dict()
|
||||
Docs['assets url'] = 'https://docs.franco.net.eu.org/fattura-elettronica-reader/assets.html'
|
||||
docs = dict()
|
||||
docs['assets_url'] = 'https://docs.franco.net.eu.org/fattura-elettronica-reader/assets.html'
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
|
|
Loading…
Reference in New Issue