def action(): # Get the token for this signature. (rendered in a hidden input field, see # xml-signature/index.html template) token = request.form['token'] # Instantiate the XmlSignatureFinisher class, responsible for completing # the signature process. signature_finisher = XmlSignatureFinisher(get_rest_pki_client()) # Set the token. signature_finisher.token = token # Call the finish() method, which finalizes the signature process and # returns the signed XML. result = signature_finisher.finish() # Get information about the certificate used by the user to sign the file. # This method must only be called after calling the finish() method. signer_cert = result.certificate # At this point, you'd typically store the signed PDF on your database. For # demonstration purposes, we'll store the XML on a temporary folder publicly # accessible and render a link to it. create_app_data() # Guarantees that "app data" folder exists. filename = '%s.xml' % (str(uuid.uuid4())) result.write_to_file(join(current_app.config['APPDATA_FOLDER'], filename)) return render_template('xml_signature_rest/complete.html', signed_xml=filename, signer_cert=signer_cert)
def complete(token=None): """ This function is called asynchornously via AJAX by the batch signature page for each document being signed. It receives the tokne, that identifies the signature process. We'll call REST PKI to complete this signature and return a JSON with the saved filename so that the page can render a link to it. """ # Get an intance of the PadesSignatureFinisher class, responsible for # completing the signature process. signature_finisher = PadesSignatureFinisher(get_rest_pki_client()) # Set the token. signature_finisher.token = token # Call the finish() method, which finalizes the signature process.The # return value is the signed PDF content. result = signature_finisher.finish() # At this point, you'd typically store the signed PDF on your database. # For demonstration purposes, we'll store the PDF on a temporary folder # publicly accessible and render a link to it. create_app_data() # Guarantees that "app data" folder exists. filename = '%s.pdf' % (str(uuid.uuid4())) result.write_to_file( os.path.join(current_app.config['APPDATA_FOLDER'], filename)) return jsonify(filename)
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 get_visual_representation(): """ This function is called by PAdES samples. It contains an example of signature visual representation. This is only in a separate function in order to organize the various examples. """ # Create a visual representation. visual_representation = { 'text': { # For a full list of the supported tags, see: # https://docs.lacunasoftware.com/articles/rest-pki/pades-tags.html 'text': 'Signed by {{name}} ({{national_id}})', 'fontSize': 13.0, # Specify that the signing time should also be rendered. 'includeSigningTime': True, # Optionally set the horizontal alignment of the text ('Left' or # 'Right'), if not set the default is 'Left'. 'horizontalAlign': 'Left', # Optionally set the container within the signature rectangle on # which to place the text. By default, the text can occupy the # entire rectangle (how much of the rectangle the text will # actually fill depends on the length and font size). Below, we # specify that the text should respect a right margin of 1.5 cm. 'container': { 'left': 0.2, 'top': 0.2, 'right': 0.2, 'bottom': 0.2 } }, 'image': { # We'll use as background the image static/PdfStamp.png 'resource': { 'content': b64encode(get_pdf_stamp_content()), 'mimeType': 'image/png' }, # Align the image to the right horizontally. 'horizontalAlign': 'Right', # Align the image to the center vertically. 'verticalAlign': 'Center' }, } # Position of the visual representation. We get the footnote position # preset and customize it. visual_positioning = \ PadesVisualPositioningPresets.get_footnote(get_rest_pki_client()) visual_positioning['auto']['container']['height'] = 4.94 visual_positioning['auto']['signatureRectangleSize']['width'] = 8.0 visual_positioning['auto']['signatureRectangleSize']['height'] = 4.94 visual_representation['position'] = visual_positioning return visual_representation
def action(): """ This view function receives the form submission from the template authentication/index.html. We'll call REST PKI to validate the authentication. """ try: # Get the token for this authentication (rendered in a hidden input # field, see authentication/index.html template). token = request.form['token'] # Get an instance of the Authentication class. auth = get_rest_pki_client().get_authentication() # Call the complete_with_webpki() method with the token, which finalizes # the authentication process. The call yields a ValidationResults # object, which denotes whether the authentication was successful or not # (we'll use it to render the page accordingly, see below). result = auth.complete_with_webpki(token) vr = result.validation_results if not vr.is_valid: # If the authentication as not successful, we render a page showing # what went wrong vr_html = str(vr) vr_html = vr_html.replace('\n', '<br/>') vr_html = vr_html.replace('\t', ' ') return render_template('authentication_rest/failed.html', vr_html=vr_html) # At this point, you have assurance that the certificate is valid # according to the SecurityContext specified on the method # start_with_webpki() and that the user is indeed the certificate's # subject. Now, you'd typically query your database for a user that # matches one of the certificate's fields, such as # user_cert.emailAddress or user_cert.pki_brazil.cpf (the actual # field to be used as key depends on your application's business # logic) and set the user as authenticated with whatever web # security framework your application uses. For demonstration # purposes, we'll just render the user's certificate information. user_cert = result.certificate return render_template('authentication_rest/success.html', user_cert=user_cert) except Exception as e: return render_template('error.html', msg=e)
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 index(): # Get an instance of the FullXmlSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = FullXmlSignatureStarter(get_rest_pki_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_rest/index.html', token=result.token)) get_expired_page_headers(response.headers) return response
def action(): """ This function receives the form submission from the template cades-signature/index.html. We'll call REST PKI to complete the signature. """ try: # Get the token for this signature. (rendered in a hidden input field, # see pades-signature/index.html template) token = request.form['token'] # Get an intance of the PadesSignatureFinisher class, responsible for # completing the signature process. signature_finisher = PadesSignatureFinisher(get_rest_pki_client()) # Set the token. signature_finisher.token = token # Call the finish() method, which finalizes the signature process. The # return value is the signed PDF content. result = signature_finisher.finish() # Get information about the certificate used by the user to sign the # file. This method must only be called after calling the finish() # method. signer_cert = result.certificate # At this point, you'd typically store the signed PDF on your database. # For demonstration purposes, we'll store the PDF on a temporary folder # publicly accessible and render a link to it. create_app_data() # Guarantees that "app data" folder exists. filename = '%s.pdf' % (str(uuid.uuid4())) result.write_to_file( os.path.join(current_app.config['APPDATA_FOLDER'], filename)) return render_template('pades_signature_rest/complete.html', signer_cert=signer_cert, signed_pdf=filename) except Exception as e: return render_template('error.html', msg=e)
def start(file_id=None): """ This function is called asynchronously 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_rest_pki_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 = \ PadesVisualElementsRest.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(): # Instantiate the XmlElementSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = XmlElementSignatureStarter(get_rest_pki_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_nfe_signature_rest/index.html', token=result.token)) get_expired_page_headers(response.headers) return response
def complete(token): # Get an instance of the CadesSignatureFinisher class, responsible for # completing the signature process. signature_finisher = CadesSignatureFinisher(get_rest_pki_client()) # Set the token. signature_finisher.token = token # Call the finish() method, which finalizes the signature process.The # return value is the CMS content. result = signature_finisher.finish() # At this point, you'd typically store the signed PDF on your database. # For demonstration purposes, we'll store the CMS on a temporary folder # publicly accessible and render a link to it. create_app_data() # Guarantees that "app data" folder exists. filename = '%s.p7s' % (str(uuid.uuid4())) result.write_to_file(join(current_app.config['APPDATA_FOLDER'], filename)) return jsonify(filename)
def start(file_id): # Get an instantiate of the CadesSignatureStarter class, responsible for # receiving the signature elements and start the signature process. signature_starter = CadesSignatureStarter(get_rest_pki_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(): """ This view function initiates an authentication with REST PKI and renders the authentication page. """ try: # Get an instance of the Authentication class. auth = get_rest_pki_client().get_authentication() # Call the start_with_web_pki() 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_web_pki() 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_web_pki(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_rest/index.html', token=token)) get_expired_page_headers(response.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_rest_pki_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_rest/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(file_to_sign=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_rest_pki_client()) # Set the PDF to be signed. signature_starter.set_pdf_to_sign( '%s/%s' % (current_app.config['APPDATA_FOLDER'], file_to_sign)) # 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 = \ PadesVisualElementsRest.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_rest/index.html', token=result.token)) get_expired_page_headers(response.headers) return response except Exception as e: return render_template('error.html', msg=e)