Class: CertSign::A1Signer
- Inherits:
-
Object
- Object
- CertSign::A1Signer
- Defined in:
- lib/cert_sign/a1_signer.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(key:, cert:, chain: []) ⇒ A1Signer
constructor
A new instance of A1Signer.
-
#sign_pdf(input_path:, output_path:, visible:, reason: nil, location: nil, contact: nil, signature_type: nil, tsa_url: nil, **_ignored) ⇒ Object
Agora aceita as keywords :signature_type e :tsa_url (e ignora quaisquer outras) visible: { page:, x_pct:, y_pct:, width_pt:, height_pt:, text: }.
Constructor Details
#initialize(key:, cert:, chain: []) ⇒ A1Signer
Returns a new instance of A1Signer.
6 7 8 9 10 |
# File 'lib/cert_sign/a1_signer.rb', line 6 def initialize(key:, cert:, chain: []) @key = key @cert = cert @chain = chain end |
Class Method Details
.from_p12(path:, password:) ⇒ Object
12 13 14 15 |
# File 'lib/cert_sign/a1_signer.rb', line 12 def self.from_p12(path:, password:) p12 = OpenSSL::PKCS12.new(File.binread(path), password) new(key: p12.key, cert: p12.certificate, chain: (p12.ca_certs || [])) end |
Instance Method Details
#sign_pdf(input_path:, output_path:, visible:, reason: nil, location: nil, contact: nil, signature_type: nil, tsa_url: nil, **_ignored) ⇒ Object
Agora aceita as keywords :signature_type e :tsa_url (e ignora quaisquer outras) visible: { page:, x_pct:, y_pct:, width_pt:, height_pt:, text: }
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/cert_sign/a1_signer.rb', line 19 def sign_pdf(input_path:, output_path:, visible:, reason: nil, location: nil, contact: nil, signature_type: nil, tsa_url: nil, **_ignored) doc = HexaPDF::Document.open(input_path) # AcroForm, campo e widget na página desejada form = doc.acro_form(create: true) page_index = (visible[:page].to_i - 1).clamp(0, doc.pages.count - 1) rect = CertSign::Coordinates.rect_from_percent( doc, page_index: page_index, x_pct: visible[:x_pct].to_f, y_pct: visible[:y_pct].to_f, width_pt: visible[:width_pt].to_f, height_pt: visible[:height_pt].to_f ) sig_field = form.create_signature_field("Signature#{Time.now.to_i}") = sig_field.(doc.pages[page_index], Rect: rect) # === Carimbo visual da assinatura === w = rect[2] - rect[0] h = rect[3] - rect[1] pad = 6 #cn = @cert.subject.to_a.assoc('CN')&..to_s cn = @cert.subject.to_s[/CN=([^\/]+)/, 1] title = (visible[:text].presence || "Assinado digitalmente").to_s now = Time.now.getlocal.strftime("%d/%m/%Y %H:%M:%S") canvas = .create_appearance.canvas # fundo + borda canvas.save_graphics_state do canvas.line_width(0.8) canvas.stroke_color(0.25) canvas.fill_color(0.96) canvas.rectangle(0, 0, w, h).fill_stroke end # título y = h - pad - 11 canvas.fill_color(0) canvas.font("Helvetica", variant: :bold, size: 10) canvas.text(title, at: [pad, y]) y -= 14 # linhas canvas.font("Helvetica", size: 9) [ ("Por: #{cn}" unless cn.empty?), "Data: #{now}", "Motivo: #{(reason || CertSign.config.default_reason)}", ("Local: #{(location || CertSign.config.default_location)}" if location || CertSign.config.default_location) ].compact.each do |line| break if y < pad + 9 canvas.text(line, at: [pad, y]) y -= 12 end # === fim do carimbo === # Timestamp handler (opcional) ts_handler = nil if tsa_url.to_s.strip != "" # Em HexaPDF 1.x o helper é exposto via document ts_handler = doc.signatures.signing_handler(name: :timestamp, tsa_url: tsa_url) rescue nil end # Chamada de assinatura (HexaPDF 1.4+) # signature_type pode ser :pades (quando quiser PAdES) ou nil (CMS padrão) doc.sign( output_path, signature: sig_field, reason: reason || CertSign.config.default_reason, location: location || CertSign.config.default_location, contact_info: contact || CertSign.config.default_contact, certificate: @cert, key: @key, certificate_chain: @chain, signature_type: (signature_type&.to_sym), timestamp_handler: ts_handler ) end |