From 4b9df44dac7d25a66efc29fef35b1b8967d524f6 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Wed, 6 Jan 2021 21:30:31 -0600 Subject: [PATCH] Add migrate certificates --- CHANGELOG.md | 4 ++- source/app/conf.py.example | 14 +++----- source/app/controllers/pacs/cfdi_cert.py | 35 +++++++++++++++++++ .../pacs/comerciodigital/comercio.py | 2 -- source/app/controllers/util.py | 20 ----------- source/app/models/main.py | 31 ++++++++++++++++ 6 files changed, 73 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3e42af..febadb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,9 @@ con su respectiva contraseña, te quedarás sin poder timbrar. menú "Emisor" ficha "Otros Datos", usuario y token de timbrado. 1. Agregar nuevo requerimiento `pip install xmlsec` 1. Actualizar `git pull origin master` -1. Entrar a `source/app/controllers/pacs` y copiar `conf.py.example` a `conf.py` +1. Entrar a `source/app/controllers/pacs/comerciodigital` y copiar `conf.py.example` a `conf.py` +1. Entrar a `source/app/controllers/pacs/finkok` y copiar `conf.py.example` a `conf.py` +1. Agregar la variable `TOKEN` al archivo `source/app/conf.py` 1. Reiniciar el servicio: `sudo systemctl restart empresalibre` 1. Sube de nuevo tus certificados en el menú "Emisor" ficha "Certificado". 1. Ve al menú "Opciones", ficha "Otros". diff --git a/source/app/conf.py.example b/source/app/conf.py.example index b8257e8..802b6f3 100644 --- a/source/app/conf.py.example +++ b/source/app/conf.py.example @@ -13,13 +13,7 @@ TITLE_APP = 'Empresa Libre' #~ Establece una ruta accesible para el servidor web LOG_PATH = '/var/log/empresalibre/empresa-libre.log' -# ~ Establece los valores para sincronizar los backups de la base de datos -# ~ por ejemplo -# ~ SEAFILE_SERVER = { - # ~ 'URL': 'https://tu_servidor_seafile', - # ~ 'USER': 'tu_usuario', - # ~ 'PASS': 'tu_contraseña', - # ~ 'REPO': 'id_repo', -# ~ } - -SEAFILE_SERVER = {} +# ~ Establece un token personalizado para encriptar las claves +# ~ from secrets import token_hex +# ~ token_hex(32) +TOKEN = '' diff --git a/source/app/controllers/pacs/cfdi_cert.py b/source/app/controllers/pacs/cfdi_cert.py index b309f2d..642e13d 100644 --- a/source/app/controllers/pacs/cfdi_cert.py +++ b/source/app/controllers/pacs/cfdi_cert.py @@ -4,6 +4,7 @@ import argparse import base64 import datetime import getpass +import subprocess from pathlib import Path import xmlsec @@ -211,6 +212,40 @@ class SATCertificate(object): def error(self): return self._error + @classmethod + def save_cert(cls, obj): + import hashlib + + cer = x509.load_pem_x509_certificate(obj.cer_pem.encode(), default_backend()) + cer_der = cer.public_bytes(serialization.Encoding.DER) + token = hashlib.md5(obj.rfc.encode()).hexdigest() + path = Path(f'/tmp/{obj.rfc}.key') + path.write_text(obj.key_enc) + args = f'openssl rsa -inform PEM -outform PEM -in "{str(path)}" -passin pass:{token}' + pem = subprocess.check_output(args, shell=True).decode() + key = serialization.load_pem_private_key(pem.encode(), password=None) + + digest = hashes.Hash(hashes.SHA512(), default_backend()) + digest.update(obj.rfc.encode()) + digest.update(obj.serie.encode()) + digest.update(TOKEN.encode()) + p = digest.finalize() + + key_enc = key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.BestAvailableEncryption(p) + ) + + cert = SATCertificate(cer_der, key_enc) + obj.key_enc = cert.key_enc + obj.cer = cert.cer + obj.serie = cert.serial_number + obj.desde = cert.not_before + obj.hasta = cert.not_after + obj.save() + return + def main(args): # ~ contra = getpass.getpass('Introduce la contraseña del archivo KEY: ') diff --git a/source/app/controllers/pacs/comerciodigital/comercio.py b/source/app/controllers/pacs/comerciodigital/comercio.py index 365b47e..185a7f8 100644 --- a/source/app/controllers/pacs/comerciodigital/comercio.py +++ b/source/app/controllers/pacs/comerciodigital/comercio.py @@ -78,8 +78,6 @@ class PACComercioDigital(object): def __init__(self): self.error = '' - # ~ self.cfdi_uuid = '' - # ~ self.date_stamped = '' def _error(self, msg): self.error = str(msg) diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index af95d32..6b383d7 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -460,26 +460,6 @@ def _get_uuid_fecha(xml): return node.attrib['UUID'], node.attrib['FechaTimbrado'] -def _ecodex_timbra_xml(xml): - from .pac import Ecodex as PAC - from .configpac import ecodex - - auth, url = ecodex(DEBUG) - - pac = PAC(auth, url) - xml = pac.timbra_xml(xml) - if xml: - data = {'ok': True, 'error': ''} - data['xml'] = xml - uuid, fecha = _get_uuid_fecha(xml) - data['uuid'] = uuid - data['fecha'] = fecha - return data - - msg = pac.error - return {'ok': False, 'error': msg} - - def get_sat(xml): from .pac import get_status_sat return get_status_sat(xml) diff --git a/source/app/models/main.py b/source/app/models/main.py index 1679bea..3cbc0ea 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -10492,6 +10492,29 @@ def _change_pass(rfc): return +def _export_cert(): + rfc = input('Introduce el RFC: ').strip().upper() + if not rfc: + msg = 'El RFC es requerido' + log.error(msg) + return + + args = util.get_con(rfc) + if not args: + return + + conectar(args) + log.info('Exportando certificados...') + + obj = Certificado.get(Certificado.es_fiel==False) + cert = utils.SATCertificate + cert.save_cert(obj) + + desconectar() + log.info('Proceso terminado correctamente...') + return + + def _process_command_line_arguments(): parser = argparse.ArgumentParser( description='Empresa Libre') @@ -10516,6 +10539,9 @@ def _process_command_line_arguments(): parser.add_argument('-ed', '--export-documents', dest='export_documents', action='store_true', default=False, required=False) + parser.add_argument('-ec', '--export-cert', dest='export_cert', + action='store_true', default=False, required=False) + parser.add_argument('-r', '--rfc', dest='rfc', default='') return parser.parse_args() @@ -10555,6 +10581,11 @@ def main(args): if args.export_documents: _export_documents() + return + + if args.export_cert: + _export_cert() + return return