Class: Sphragis::PdfSigner

Inherits:
Object
  • Object
show all
Defined in:
lib/sphragis/pdf_signer.rb

Defined Under Namespace

Classes: SigningError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pdf_path, signature_options = {}) ⇒ PdfSigner

Initialize with PDF path and optional signature placement

Parameters:

  • pdf_path (String)

    Path to the PDF file

  • signature_options (Hash) (defaults to: {})

    Options for signature placement

    • x: X coordinate (default: 400)
    • y: Y coordinate (default: 50)
    • width: Signature width (default: 150)
    • height: Signature height (default: 50)
    • page: Page number to sign (default: last page)
    • reason: Signing reason (default: "Document approval")
    • location: Signing location (default: nil)
    • provider: Signature provider (:fortify, :harica, :itsme) (default: configured default)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/sphragis/pdf_signer.rb', line 22

def initialize(pdf_path, signature_options = {})
  @pdf_path = pdf_path
  @signature_options = default_signature_options.merge(signature_options)

  # Create provider based on options or use default.
  # OTP and placement params are forwarded to the provider so that
  # cloud providers (e.g. Harica) receive everything they need at sign time.
  provider_name  = @signature_options.delete(:provider) || ProviderFactory.default_provider
  provider_extra = {
    otp:      @signature_options.delete(:otp),
    x:        @signature_options[:x],
    y:        @signature_options[:y],
    width:    @signature_options[:width],
    height:   @signature_options[:height],
    page:     @signature_options[:page],
    reason:   @signature_options[:reason],
    location: @signature_options[:location]
  }.compact
  @provider = ProviderFactory.create(provider_name, provider_extra)

  validate_pdf!
end

Instance Attribute Details

#pdf_pathObject (readonly)

Returns the value of attribute pdf_path.



9
10
11
# File 'lib/sphragis/pdf_signer.rb', line 9

def pdf_path
  @pdf_path
end

#providerObject (readonly)

Returns the value of attribute provider.



9
10
11
# File 'lib/sphragis/pdf_signer.rb', line 9

def provider
  @provider
end

#signature_optionsObject (readonly)

Returns the value of attribute signature_options.



9
10
11
# File 'lib/sphragis/pdf_signer.rb', line 9

def signature_options
  @signature_options
end

Instance Method Details

#pdf_infoObject

Get PDF metadata



71
72
73
74
75
76
77
78
79
# File 'lib/sphragis/pdf_signer.rb', line 71

def pdf_info
  reader = PDF::Reader.new(pdf_path)
  {
    page_count: reader.page_count,
    pdf_version: reader.pdf_version,
    info: reader.info,
    metadata: reader.
  }
end

#signString

Sign the PDF document

Returns:

  • (String)

    Path to the signed PDF



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/sphragis/pdf_signer.rb', line 47

def sign
  raise SigningError, "PDF file does not exist: #{pdf_path}" unless File.exist?(pdf_path)

  @provider.connect

  output_path = pdf_path.sub(/\.pdf$/i, "_signed.pdf")

  if @provider.respond_to?(:sign_bytes)
    sign_locally(output_path)
  else
    # Cloud provider (e.g. Harica) returns a fully signed PDF.
    signature = @provider.sign(File.binread(pdf_path))
    File.binwrite(output_path, signature[:signed_pdf_bytes])
  end

  @provider.disconnect

  output_path
rescue StandardError => e
  @provider&.disconnect
  raise SigningError, "Failed to sign PDF: #{e.message}"
end

#validate_placement(page_number = nil) ⇒ Object

Validate signature placement on a specific page

Raises:



82
83
84
85
86
87
88
89
# File 'lib/sphragis/pdf_signer.rb', line 82

def validate_placement(page_number = nil)
  page = page_number || signature_options[:page] || pdf_info[:page_count]
  info = pdf_info

  raise SigningError, "Invalid page number: #{page}" if page > info[:page_count] || page < 1

  true
end