def index(file_id): # Verify if the provided userfile exists. file_path = join(current_app.config['APPDATA_FOLDER'], file_id) if not exists(file_path): return render_template('error.html', msg='File not found') # Get an instance of PadesSignatureExplorer class, used to open/validate PDF # signatures. sig_explorer = PadesSignatureExplorer(get_rest_pki_client()) # Specify that we want to validate the signatures in the file, not only # inspect them. sig_explorer.validate = True # Set the PDF file. sig_explorer.signature_file_path = file_path # Specify the parameters for the signature validation: # Accept any PAdES signature as long as the signer has an ICP-Brasil # certificate. sig_explorer.default_signature_policy_id = \ StandardSignaturePolicies.PADES_BASIC # Specify the security context to be used to determine trust in the # certificate chain. We have encapsulated the security context on utils.py. sig_explorer.security_context_id = get_security_context_id() # Call the open() method, which returns the signature file's information. signature = sig_explorer.open() # Render the information (see file templates/open_pades_rest/index.html for # more information on the information returned) return render_template('open_pades_rest/index.html', signature=signature)
def full(): """ This function initiates a XML element signature using REST PKI and renders the signature page. The full XML signature is recommended in cases which there is a need to sign the whole XML file. """ try: # Get an instance of the FullXmlSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = FullXmlSignatureStarter(get_restpki_client()) # Set the XML to be signed, a sample XML Document. signature_starter.set_xml_to_sign(get_sample_xml_document_path()) # Set the location on which to insert the signature node. If the # location is not specified, the signature will appended to the root # element (which is most usual with enveloped signatures). nsm = NamespaceManager() nsm.add_namespace('ls', 'http://www.lacunasoftware.com/sample') signature_starter.set_signature_element_location( '//ls:signaturePlaceholder', XmlInsertionOptions.APPEND_CHILD, nsm) # Set the signature policy. signature_starter.signature_policy = \ StandardSignaturePolicies.XADES_BES # Set the security context to be used to determine trust in the # certificate chain. We have encapsulated the security context choice on # util.py. signature_starter.security_context = get_security_context_id() # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js javascript) and also to complete the signature after # the form is submitted (see method pades_signature_action()). This # should not be mistaken with the API access token. result = signature_starter.start_with_webpki() # The token acquired above can only be used for a single signature # attempt. In order to retry the signature it is necessary to get a new # token. This can be a problem if the user uses the back button of the # browser, since the browser might show a cached page that we rendered # previously, with a now stale token. To prevent this from happen, we # force page expiration through HTTP headers to prevent caching of the # page. response = make_response( render_template('xml_signature/full.html', token=result.token)) response.headers = get_expired_page_headers() return response except Exception as e: return render_template('error.html', msg=e)
def element(): """ This function initiates a XML element signature using REST PKI and renders the signature page. The XML element signature is recommended in cases which there is a need to sign a specific element of a XML. """ # Instantiate the XmlElementSignatureStarter class, responsible for # receiving the signature elements and start the signature process. try: signature_starter = XmlElementSignatureStarter(get_restpki_client()) # Set the XML to be signed, a sample XML Document. signature_starter.set_xml_to_sign(get_sample_nfe_path()) # Set the ID of the element to be signed. signature_starter.to_sign_element_id = \ 'NFe35141214314050000662550010001084271182362300' # Set the signature policy. signature_starter.signature_policy = \ StandardSignaturePolicies.NFE_PADRAO_NACIONAL # Set a security context to be used to determine trust in the # certificate chain. We have encapsulated the security context choice on # util.py. signature_starter.security_context = get_security_context_id() # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js javascript) and also to complete the signature after # the form is submitted (see method action()). This should not be # mistaken with the API access token. result = signature_starter.start_with_webpki() # The token acquired above can only be used for a single signature # attempt. In order to retry the signature it is necessary to get a new # token. This can be a problem if the user uses the back button of the # browser, since the browser might show a cached page that we rendered # previously, with a now stale token. We force page expiration through # HTTP headers to prevent caching of the page. response = make_response( render_template('xml_signature/element.html', token=result.token)) response.headers = get_expired_page_headers() return response except Exception as e: return render_template('error.html', msg=e)
def start(file_id=None): """ This function is called asynchonously via AJAX by the batch signature page for each document being signed. It receives the ID of the document and initiates a CAdES signature using REST PKI and returns a JSON with the token, which identifies this signature process, to be used in the next signature steps (see batch-signature-form.js). """ # Get an instantiate of the CadesSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = CadesSignatureStarter(get_restpki_client()) # Set the document to be signed based on its ID. signature_starter.set_file_to_sign_path(get_sample_batch_doc_path(file_id)) # Set the signature policy. signature_starter.signature_policy = \ StandardSignaturePolicies.PKI_BRAZIL_CADES_ADR_BASICA # Set a security context. We have encapsulated the security context # choice on util.py. signature_starter.security_context = get_security_context_id() # Optionally, set whether the content should be encapsulated in the # resulting CMS. If this parameter is ommitted, the following rules # apply: # - If no CmsToCoSign is given, the resulting CMS will include the # content. # - If a CmsToCoSign is given, the resulting CMS will include the # content if and only if the CmsToCoSign also includes the content. # signature_starter.encapsulate_content = True # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js) and also to complete the signature after # the form is submitted (see method action()). This should not be # mistaken with the API access token. result = signature_starter.start_with_webpki() # Return a JSON with the token obtained from REST PKI (the page will use # jQuery to decode this value). return jsonify(result.token)
def index(code): # On printer_version_pades_express, we stored the unformatted version of the # verification code (without hyphens), but used the formatted version (with # hyphens) on the printer-friendly PDF. Now, we remove the hyphens before # looking it up. verification_code = parse_verification_code(code) # Get document associated with verification code. file_id = lookup_verification_code(verification_code) if file_id is None: # Invalid code given! # Small delay to slow down brute-force attacks (if you want to be extra # careful you might want to add a CAPTCHA to the process) sleep(2) # Return "Not Found" page. return render_template('error.html', msg='File not found') # Locate document from storage. file_path = join(current_app.config['APPDATA_FOLDER'], file_id) # Get an instance of PadesSignatureExplorer class, used to open/validate PDF # signatures. sig_explorer = PadesSignatureExplorer(get_rest_pki_client()) # Specify that we want to validate the signatures in the file, not only # inspect them. sig_explorer.validate = True # Set the PDF file. sig_explorer.signature_file_path = file_path # Specify the parameters for the signature validation: # Accept any PAdES signature as long as the signer has an ICP-Brasil # certificate. sig_explorer.default_signature_policy_id = \ StandardSignaturePolicies.PADES_BASIC # Specify the security context to be used to determine trust in the # certificate chain. We have encapsulated the security context on utils.py. sig_explorer.security_context_id = get_security_context_id() # Call the open() method, which returns the signature file's information. signature = sig_explorer.open() # Render the signature opening page. return render_template('check_pades_rest/index.html', signature=signature, file_id=file_id)
def start(file_id=None): """ This function is called asynchonously via AJAX by the batch signature page for each document being signed. It receives the ID of the document and initiates a PAdES signature using REST PKI and returns a JSON with the token, which identifies this signature process, to be used in the next signature steps (see batch-signature-form.js). """ # Get an instantiate of the PadesSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = PadesSignatureStarter(get_restpki_client()) # Set the document to be signed based on its ID. signature_starter.set_pdf_to_sign(get_sample_batch_doc_path(file_id)) # Set the signature policy. signature_starter.signature_policy = \ StandardSignaturePolicies.PADES_BASIC # Set a security context to determine trust in the certificate chain. We # have encapsulated the security context choice on util.py. signature_starter.security_context = get_security_context_id() # Set the visual representation for the signature. We have encapsulated # this code (on util-pades.py) to be used on various PAdES examples. signature_starter.visual_representation = \ PadesVisualElementsRestPki.get_visual_representation() # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js) and also to complete the signature after # the form is submitted (see method action()). This should not be # mistaken with the API access token. result = signature_starter.start_with_webpki() # Return a JSON with the token obtained from REST PKI (the page will use # jQuery to decode this value). return jsonify(result.token)
def index(): """ This view function initiates an authentication with REST PKI and renders the authentication page. """ try: # Get an instance of the Authentication class. auth = get_restpki_client().get_authentication() # Call the start_with_webpki() method, which initiates the # authentication. This yields the "token", a 22-character case-sensitive # URL-safe string, which represents this authentication process. We'll # use this value to call the signWithRestPki() method on the Web PKI # component (see signature-form.js) and also to call the # complete_with_webpki() method on the route /authentication/action. # This should not be mistaken with the API access token. We have # encapsulated the security context choice on util.py. token = auth.start_with_webpki(get_security_context_id()) # The token acquired above can only be used for a single # authentication. In order to retry authenticating it is necessary to # get a new token. This can be a problem if the user uses the back # button of the browser, since the browser might show a cached page that # we rendered previously, with a now stale token. To prevent this from # happening, we force page expiration through HTTP headers to prevent # caching of the page. response = make_response( render_template('authentication/index.html', token=token)) response.headers = get_expired_page_headers() return response except Exception as e: return render_template('error.html', msg=e)
def index(file_to_sign=None, file_to_cosign=None): """ This function initiates a CAdES signature using REST PKI and renders the signature page. All CAdES signature examples converge to this action, but with different URL arguments: 1. Signature with a server file : no arguments filled 2. Signature with a file uploaded by the user : "******" filled 3. Co-signature of a previously signed CMS : "cmsfile" filled """ try: # Get an instantiate of the CadesSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = CadesSignatureStarter(get_restpki_client()) if file_to_cosign is not None: # If the URL argument "cmsfile" is filled, the user has asked to # co-sign a previously signed CMS. We'll set the path to the CMS to # be co-signed, which was previously saved in the "app-data" folder # by the action() step. Note two important things: # # 1. The CMS to be co-signed must be set using the method # "set_cms_to_cosign", not the method "set_file_to_sign". # # 2. Since we're creating CMSs with encapsulated content (see call # to encapsulated_content property below), we don't need to set # the content to be signed, REST PKI will get the content from # the CMS being co-signed. # signature_starter.set_cms_to_cosign_path( '%s/%s' % (current_app.config['APPDATA_FOLDER'], file_to_cosign)) else: # If the URL argument "userfile" is filled, it means the user was # redirected here by "upload" view (signature with file uploaded by # user). We'll set the path of the file to be signed, which was # saved in the app_data folder by "upload" view. signature_starter.set_file_to_sign_path( '%s/%s' % (current_app.config['APPDATA_FOLDER'], file_to_sign)) # Set the signature policy. signature_starter.signature_policy =\ StandardSignaturePolicies.PKI_BRAZIL_CADES_ADR_BASICA # Set a security context to be used to determine trust in the # certificate chain. We have encapsulated the security context choice on # util.py. signature_starter.security_context = get_security_context_id() # Optionally, set whether the content should be encapsulated in the # resulting CMS. If this parameter is ommitted, the following rules # apply: # # - If no CmsToCoSign is given, the resulting CMS will include the # content. # - If a CmsToCoSign is given, the resulting CMS will include the # content if and only if the CmsToCoSign also includes the content. # signature_starter.encapsulate_content = True # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js) and also to complete the signature after # the form is submitted (see method action()). This should not be # mistaken with the API access token. result = signature_starter.start_with_webpki() # The token acquired above can only be used for a single signature # attempt. In order to retry the signature it is necessary to get a # new token. This can be a problem if the user uses the back button of # the browser, since the browser might show a cached page that we # rendered previously, with a now stale token. To prevent this from # happening, we call the method get_expired_page_headers(). To prevent # this from happen, we force page expiration through HTTP headers to # prevent caching of the page. response = make_response( render_template('cades_signature_restpki/index.html', token=result.token)) get_expired_page_headers(response.headers) return response except Exception as e: return render_template('error.html', msg=e)
def generate_printer_friendly_version(pdf_path, verification_code): client = get_rest_pki_client() # The verification code is generated without hyphens to save storage space # and avoid copy-and-paste problems. On the PDF generation, we use the # "formatted" version, with hyphens (which will later be discarded on the # verification page) formatted_verification_code = format_verification_code(verification_code) # Build the verification link from the constant "VERIFICATION_LINK_FORMAT" # (see above) and the formatted verification code. verification_link = VERIFICATION_LINK_FORMAT % formatted_verification_code # 1. Upload the PDF. blob_token = client.upload_file_from_path(pdf_path) # 2. Inspect signatures on the uploaded PDF # Get and instance of the PadesSignatureExplorer class, used to # open/validate PDF signatures. sig_explorer = PadesSignatureExplorer(client) # Specify that we want to validate the signatures in the file, not only # inspect them. sig_explorer.validate = True # Set the PDF file to be inspected. sig_explorer.signature_file_blob_token = blob_token # Specify the parameters for the signature validation: # Accept any PAdES signature as long as the signer has an ICP-Brasil # certificate. sig_explorer.default_signature_policy_id = \ StandardSignaturePolicies.PADES_BASIC # Specify the security context to be used to determine trust in the # certificate chain. We have encapsulated the security context on utils.py. sig_explorer.security_context_id = get_security_context_id() # Call the open() method, which returns the signature file's information. signature = sig_explorer.open() # 3. Create PDF with the verification information from uploaded PDF. # Get an instance of the PdfMarker class, used to apply marks on the PDF. pdf_marker = PdfMarker(client) # Specify the file to be marked. pdf_marker.file_blob_token = blob_token # Build string with joined names of signers (see method get_display_name # below) signer_names_list = [] for signer in signature.signers: signer_names_list.append(get_display_name(signer.certificate)) signer_names = join_strings_pt(signer_names_list) all_pages_message = "This document was digitally signed by %s.\n" \ "To check the signatures, visit %s at %s and inform this code %s." % (signer_names, VERIFICATION_SITE_NAME_WITH_ARTICLE, VERIFICATION_SITE, formatted_verification_code) # PdfHelper is a class from the PKI Express's "fluent API" that helps # creating elements and parameters for the PdfMarker. pdf = PdfHelper() # ICP-Brasil logo on bottom-right corner of every page (except on the page # which will be created at the end of the document) pdf_marker.marks.append(pdf.mark().on_all_pages().on_container( pdf.container().width(1.0).anchor_right(1.0).height(1.0).anchor_bottom( 1.0)).add_element( pdf.image_element().with_opacity(75).with_image_content( get_icp_brasil_logo_content(), "image/png"))) # Summary on bottom margin of every page (except on the page which will be # created at the end of the document) pdf_marker.marks.append(pdf.mark().on_all_pages().on_container( pdf.container().height(2.0).anchor_bottom().var_width().margins( 1.5, 3.5)).add_element(pdf.text_element().with_opacity( 75).add_section_from_text(all_pages_message))) # Summary on right margin of every page (except on the page which will be # created at the end of the document), rotated 90 degrees counterclockwise # (text goes up). pdf_marker.marks.append(pdf.mark().on_all_pages().on_container( pdf.container().width(2.0).anchor_right().var_height().margins( 1.5, 3.5)).add_element( pdf.text_element().rotate_90_counter_clockwise().with_opacity( 75).add_section_from_text(all_pages_message))) # Create a "manifest" mark on a new page added on the end of the document. # We'll add several elements to this mark. manifest_mark = pdf.mark()\ .on_new_page()\ .on_container( pdf.container() .var_width_and_height() .margins(2.54, 2.54)) # We'll keep track of our "vertical offset" as we add elements to the mark. vertical_offset = 0 element_height = 3 # ICP-Brasil logo on the upper-left corner. Using elementHeight as width # because the image is a square. manifest_mark.add_element(pdf.image_element().on_container( pdf.container().height(element_height).anchor_top(vertical_offset). width(element_height).anchor_left()).with_image_content( get_icp_brasil_logo_content(), "image/png")) # QR Code with the verification link on the upper-right corner. Using # elementHeight as width because the image is a square. manifest_mark.add_element(pdf.qr_code_element().on_container( pdf.container().height(element_height).anchor_top( vertical_offset).width(element_height).anchor_right( )).with_qr_code_data(verification_link).draw_quiet_zones()) manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top( vertical_offset * 0.2).full_width()).align_text_center().add_section( pdf.text_section().with_font_size( NORMAL_FONT_SIZE * 1.6).with_text('SIGNATURE\nCHECK'))) vertical_offset += element_height # Vertical padding. vertical_offset += 1.7 # Header with verification code. element_height = 2 manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top( vertical_offset).full_width()).align_text_center().add_section( pdf.text_section().with_font_size( NORMAL_FONT_SIZE * 1.2).with_text( "Verification code: %s" % formatted_verification_code))) vertical_offset += element_height # Paragraph saving "this document was signed by the following signers etc" # and mentioning the timezone of the date/times below. element_height = 2.5 manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top( vertical_offset).full_width() ).add_section(pdf.text_section( ).with_font_size(NORMAL_FONT_SIZE).with_text( "This document was digitally signed by the following signers on the indicated dates (%s):" % TIME_ZONE_DISPLAY_NAME))) vertical_offset += element_height # Iterate signers. for signer in signature.signers: element_height = 1.5 # Green "check" or red "X" icon depending on result of validation for # this signer. manifest_mark.add_element(pdf.image_element().on_container( pdf.container().height(0.5).anchor_top(vertical_offset + 0.2). width(0.5).anchor_left()).with_image_content( get_validation_result_icon(signer.validation_results.is_valid), 'image/png')) # Description of signer (see method get_signer_description() below). manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top(vertical_offset). var_width().margins(0.8, 0.0)).add_section( pdf.text_section().with_font_size(NORMAL_FONT_SIZE).with_text( get_signer_description(signer)))) vertical_offset += element_height # Some vertical padding for last signer. vertical_offset += 1.0 # Paragraph with link to verification site and citing both the verification # code above and the verification link below. element_height = 2.5 manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top( vertical_offset).full_width()).add_section( pdf.text_section().with_font_size(NORMAL_FONT_SIZE).with_text( "In order to check the signatures, visit %s at " % VERIFICATION_SITE_NAME_WITH_ARTICLE) ).add_section( pdf.text_section().with_font_size(NORMAL_FONT_SIZE).with_color( Color.BLUE).with_text(VERIFICATION_SITE) ).add_section( pdf.text_section().with_font_size(NORMAL_FONT_SIZE).with_text( ' and inform the code above or access the link below:'))) vertical_offset += element_height # Verification link. element_height = 1.5 manifest_mark.add_element(pdf.text_element().on_container( pdf.container().height(element_height).anchor_top(vertical_offset). full_width()).add_section( pdf.text_section().with_font_size(NORMAL_FONT_SIZE).with_color( Color.BLUE).with_text(verification_link)).align_text_center()) # Add marks. pdf_marker.marks.append(manifest_mark) # Apply marks. result = pdf_marker.apply() # Return content of the printer-friendly version. return result.open()
def index(userfile=None): """ This function initiates a PAdES signature using REST PKI and renders the signature page. Both PAdES signature examples, with a server file and with a file uploaded by the user, converge to this function. The difference is that, when the file is uploaded by the user, the function is called with a URL argument named "userfile". """ try: # Get an instantiate of the PadesSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = PadesSignatureStarter(get_restpki_client()) # If the URL argument "userfile" is filled, it means the user was # redirected here by "upload" view (signature with file uploaded by # user). We'll set the path of the file to be signed, which was saved # in the app_data folder by "upload" view. if userfile is not None: signature_starter.set_pdf_to_sign( '%s/%s' % (current_app.config['APPDATA_FOLDER'], userfile)) else: signature_starter.set_pdf_to_sign(get_sample_doc_path()) # Set the signature policy. signature_starter.signature_policy =\ StandardSignaturePolicies.PADES_BASIC # Set a security context to be used to determine trust in the # certificate chain. We have encapsulated the security context choice on # util.py. signature_starter.security_context = get_security_context_id() # Set the visual representation for the signature. We have encapsulated # this code (on util-pades.py) to be used on various PAdES examples. signature_starter.visual_representation = get_visual_representation() # Call the start_with_webpki() method, which initiates the signature. # This yields the token, a 43-character case-sensitive URL-safe string, # which identifies this signature process. We'll use this value to call # the signWithRestPki() method on the Web PKI component (see # signature-form.js javascript) and also to complete the signature after # the form is submitted (see method pades_signature_action()). This # should not be mistaken with the API access token. result = signature_starter.start_with_webpki() # The token acquired above can only be used for a single signature # attempt. In order to retry the signature it is necessary to get a new # token. This can be a problem if the user uses the back button of the # browser, since the browser might show a cached page that we rendered # previously, with a now stale token. To prevent this from happen, we # force page expiration through HTTP headers to prevent caching of the # page. response = make_response(render_template('pades_signature/index.html', token=result.token, userfile=userfile)) response.headers = get_expired_page_headers() return response except Exception as e: return render_template('error.html', msg=e)