rubrik 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a28dfceafc9ceb57e6b2a30f82b6e8ca237c8ce3381a05d6793568154775c43a
4
- data.tar.gz: 1a0a6f8b8079396583cdf27fae2638a9f24c16f0483c830d54a805dc707982f5
3
+ metadata.gz: 1092e4bfdff7f05272eab8cf226a09b54737f368c24e883370002a399036ce4a
4
+ data.tar.gz: 818072d3ea9003599a9ec5fb49af2df99f3f43045e9aa6a81a1e62e8f2c11fd3
5
5
  SHA512:
6
- metadata.gz: 4b294ed919bade9e09eef834afb47a17f65928b40099a9add84f079df46102e852a7289c7fbacbb745b67929ae14098fc002ebd2b12987a921e4461b5996a406
7
- data.tar.gz: 283e213a97967fb54d4c2b21f2ab009e96c434a93b26f3ff34ee4f75cfdcd925bd5cbc633bcb22844822ed4eb2e36efa4158f33b40f633b5ade6af7c9d97d30a
6
+ metadata.gz: 173091b0ab44b398a10260e267de6ff92fe8083d2668dabe86e79bdb93547151ad9b73e08296c955e3e604ebba4b1f9f74fc44ae91ef661839883cd96f71fe9d
7
+ data.tar.gz: 60a0c1647190a473703ac1ae1cf1e5d407bc59e4f599b1de6d3111c3dd7105fa8077ec7955fed5df1c5c088dc9a515e7b5b3bd1987a0d42dc2835f5ca8585313
data/README.md CHANGED
@@ -22,6 +22,7 @@ This gem is under development and may be subjected to breaking changes.
22
22
 
23
23
  ### PDF Features
24
24
  - [x] Modify PDFs with incremental updates (doesn't modify the documents, only append signature appearance)
25
+ - [ ] Encryption Support
25
26
  - [ ] Signature appearance (stamp)
26
27
  - [ ] External (offline) signatures
27
28
 
@@ -15,14 +15,14 @@ module Rubrik
15
15
  serialized_objs = obj.flatten.map { |e| SerializeObject[e] }
16
16
  "<<#{serialized_objs.join(" ")}>>"
17
17
  when Symbol
18
- "/#{obj}"
18
+ serialize_symbol(obj)
19
19
  when Array
20
20
  serialized_objs = obj.map { |e| SerializeObject[e] }
21
21
  "[#{serialized_objs.join(" ")}]"
22
22
  when PDF::Reader::Reference
23
23
  "#{obj.id} #{obj.gen} R"
24
24
  when String
25
- "(#{obj})"
25
+ serialize_string(obj)
26
26
  when TrueClass
27
27
  "true"
28
28
  when FalseClass
@@ -48,6 +48,43 @@ module Rubrik
48
48
  end
49
49
 
50
50
  alias call []
51
+
52
+ private
53
+
54
+ STRING_ESCAPE_MAP = {
55
+ "\n" => "\\\n",
56
+ "\r" => "\\\r",
57
+ "\t" => "\\\t",
58
+ "\b" => "\\\b",
59
+ "\f" => "\\\f",
60
+ "\\" => "\\\\",
61
+ "(" => "\\(",
62
+ ")" => "\\)"
63
+ }.freeze
64
+
65
+ sig {params(string: String).returns(String)}
66
+ def serialize_string(string)
67
+ "(#{string.gsub(/[\n\r\t\b\f\\()]/n, STRING_ESCAPE_MAP)})"
68
+ end
69
+
70
+ DELIMITERS = "()<>[]{}/%".bytes.freeze
71
+ REGULAR_CHARACTERS =
72
+ "!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".bytes.freeze
73
+
74
+
75
+ NAME_ESCAPE_CHARACTERS = (0..255).to_a - REGULAR_CHARACTERS + DELIMITERS + "#".bytes
76
+ NAME_ESCAPE_CHARACTERS.freeze
77
+
78
+ NAME_ESCAPE_MAP = NAME_ESCAPE_CHARACTERS.each_with_object({}) do |char, escape_map|
79
+ escape_map[char.chr] = "##{char.to_s(16).rjust(2, "0")}"
80
+ end.freeze
81
+
82
+ NAME_ESCAPE_REGEX = /[#{Regexp.escape(NAME_ESCAPE_CHARACTERS.map(&:chr).join)}]/
83
+
84
+ sig {params(symbol: Symbol).returns(String)}
85
+ def serialize_symbol(symbol)
86
+ "/#{symbol.to_s.b.gsub(NAME_ESCAPE_REGEX, NAME_ESCAPE_MAP)}"
87
+ end
51
88
  end
52
89
  end
53
90
  end
@@ -76,12 +76,30 @@ module Rubrik
76
76
  }
77
77
  }
78
78
 
79
- modified_page = objects.fetch(first_page_reference).dup
80
- (modified_page[:Annots] ||= []) << signature_field_id
79
+ first_page = objects.fetch(first_page_reference)
80
+ annots = first_page[:Annots]
81
81
 
82
- modified_objects << {id: first_page_reference, value: modified_page}
82
+ if annots.is_a?(PDF::Reader::Reference)
83
+ new_annots = objects.fetch(annots).dup
84
+ new_annots << signature_field_id
83
85
 
84
- (interactive_form[:Fields] ||= []) << signature_field_id
86
+ modified_objects << {id: annots, value: new_annots}
87
+ else
88
+ new_first_page = first_page.dup
89
+ (new_first_page[:Annots] ||= []) << signature_field_id
90
+
91
+ modified_objects << {id: first_page_reference, value: new_first_page}
92
+ end
93
+
94
+ fields_entry = interactive_form[:Fields]
95
+ if fields_entry.is_a?(PDF::Reader::Reference)
96
+ new_fields_array = objects.fetch(fields_entry).dup
97
+ new_fields_array << signature_field_id
98
+
99
+ modified_objects << {id: fields_entry, value: new_fields_array}
100
+ else
101
+ (interactive_form[:Fields] ||= []) << signature_field_id
102
+ end
85
103
 
86
104
  signature_value_id
87
105
  end
@@ -108,11 +126,22 @@ module Rubrik
108
126
  root_ref = objects.trailer[:Root]
109
127
  root = T.let(objects.fetch(root_ref), T::Hash[Symbol, T.untyped])
110
128
 
111
- if root.key?(:AcroForm)
129
+ interactive_form_value = root[:AcroForm]
130
+ case interactive_form_value
131
+ when PDF::Reader::Reference
112
132
  form_id = root[:AcroForm]
113
133
 
114
134
  modified_objects << {id: form_id, value: objects.fetch(form_id).dup}
115
- else
135
+ when Hash
136
+ interactive_form_id = assign_new_object_id!
137
+
138
+ modified_objects << {id: interactive_form_id, value: interactive_form_value.dup}
139
+
140
+ new_root = root.dup
141
+ new_root[:AcroForm] = interactive_form_id
142
+
143
+ modified_objects << {id: root_ref, value: new_root}
144
+ when NilClass
116
145
  interactive_form_id = assign_new_object_id!
117
146
  modified_objects << {id: interactive_form_id, value: {Fields: []}}
118
147
 
@@ -121,6 +150,10 @@ module Rubrik
121
150
  updated_root[:AcroForm] = interactive_form_id
122
151
 
123
152
  modified_objects << {id: root_ref, value: updated_root}
153
+ else
154
+ raise Error.new(
155
+ "Expected dictionary, reference or nil but got " \
156
+ "#{interactive_form_value.class} on AcroForm entry.")
124
157
  end
125
158
 
126
159
  interactive_form[:SigFlags] = 3 # dont modify, append only
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubrik
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubrik
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomás Coêlho
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-22 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pdf-reader