rubrik 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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