pdfrb 0.7.13 → 0.7.15
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 +4 -4
- data/lib/pdfrb/digital_signature/verification.rb +1 -1
- data/lib/pdfrb/document/encryption.rb +205 -0
- data/lib/pdfrb/document.rb +3 -0
- data/lib/pdfrb/encryption/standard_security_handler.rb +5 -1
- data/lib/pdfrb/model/type/thumbnail.rb +43 -0
- data/lib/pdfrb/model/type/timespan.rb +35 -0
- data/lib/pdfrb/model/type/user_property.rb +36 -0
- data/lib/pdfrb/model/type/viewport.rb +39 -0
- data/lib/pdfrb/model/type/vri.rb +75 -0
- data/lib/pdfrb/model/type.rb +15 -0
- data/lib/pdfrb/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0117148def4f7bc7280fa9727a6ce26fcafa9cb8f6e31cb32a480cb9548ac99e'
|
|
4
|
+
data.tar.gz: a7bf629aabbef013625f56e4c719f97a4fa6bc2823c158d4d7f37ea9c6ff8379
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7d17104eaf145c31e843f94e622dd181b965f18aa4e3aba4adb80bedbdb500855984c603ef2ce60fa4abec31d1e4a07841d96397a71452147a6bff19c122b94
|
|
7
|
+
data.tar.gz: e3513e197dff0e244f97adff17e332ff74b75509054449c32a779e8926bf1fbb91f9965b8a5757f78dbeb54f5e09741260b4139aef31f79cb0caaa25ca878b17
|
|
@@ -89,7 +89,7 @@ module Pdfrb
|
|
|
89
89
|
trusted?: !trusted_certs.empty? && valid,
|
|
90
90
|
error: valid ? nil : "signature verification failed",
|
|
91
91
|
)
|
|
92
|
-
rescue OpenSSL::PKCS7::PKCS7Error => e
|
|
92
|
+
rescue OpenSSL::PKCS7::PKCS7Error, ArgumentError => e
|
|
93
93
|
VerificationResult.new(valid?: false,
|
|
94
94
|
byte_range_ok?: true,
|
|
95
95
|
cert_chain: [],
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest/md5"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
module Pdfrb
|
|
7
|
+
class Document
|
|
8
|
+
# Encryption facade. Exposes a clean API for encrypting a
|
|
9
|
+
# document (builds the /Encrypt dict, wires the security handler
|
|
10
|
+
# into the writer config) and for checking encryption status.
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# doc.encryption.encrypt!(
|
|
14
|
+
# user_password: "reader",
|
|
15
|
+
# owner_password: "owner",
|
|
16
|
+
# bits: 128,
|
|
17
|
+
# permissions: %i[print copy]
|
|
18
|
+
# )
|
|
19
|
+
# doc.write("encrypted.pdf")
|
|
20
|
+
class Encryption
|
|
21
|
+
PERMISSION_FLAGS = {
|
|
22
|
+
print: 1 << 2,
|
|
23
|
+
modify: 1 << 3,
|
|
24
|
+
copy: 1 << 4,
|
|
25
|
+
annotate: 1 << 5,
|
|
26
|
+
fill: 1 << 8,
|
|
27
|
+
extract: 1 << 9,
|
|
28
|
+
assemble: 1 << 10,
|
|
29
|
+
print_hq: 1 << 11,
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
32
|
+
attr_reader :document
|
|
33
|
+
|
|
34
|
+
def initialize(document)
|
|
35
|
+
@document = document
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Encrypt this document with a user + owner password.
|
|
39
|
+
#
|
|
40
|
+
# @param user_password [String] the password readers need to open.
|
|
41
|
+
# @param owner_password [String] the password that grants full
|
|
42
|
+
# permissions (defaults to user_password).
|
|
43
|
+
# @param bits [Integer] key length: 40, 128 (AES-128), or
|
|
44
|
+
# 256 (AES-256 R6).
|
|
45
|
+
# @param permissions [Array<Symbol>] granted permissions from
|
|
46
|
+
# PERMISSION_FLAGS keys; any not listed are denied.
|
|
47
|
+
# @return [Pdfrb::Model::Cos::Dictionary] the /Encrypt dict.
|
|
48
|
+
def encrypt!(user_password:, owner_password: nil, bits: 128,
|
|
49
|
+
permissions: PERMISSION_FLAGS.keys)
|
|
50
|
+
case bits
|
|
51
|
+
when 256 then encrypt_v5(user_password, owner_password || user_password, permissions)
|
|
52
|
+
when 128 then encrypt_rc4(user_password, owner_password || user_password,
|
|
53
|
+
permissions, v: 4, r: 4, length: 128)
|
|
54
|
+
when 40 then encrypt_rc4(user_password, owner_password || user_password,
|
|
55
|
+
permissions, v: 2, r: 3, length: 40)
|
|
56
|
+
else
|
|
57
|
+
raise Pdfrb::EncryptionError,
|
|
58
|
+
"unsupported key length: #{bits} (use 40, 128, or 256)"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Whether the document has an /Encrypt dict in the trailer.
|
|
63
|
+
def encrypted?
|
|
64
|
+
trailer = document.trailer
|
|
65
|
+
!trailer.nil? && !trailer[:Encrypt].nil?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Remove /Encrypt from the trailer (decrypt use case). Returns
|
|
69
|
+
# self for chaining; use encrypted? to check the result.
|
|
70
|
+
def decrypt!
|
|
71
|
+
trailer = document.trailer
|
|
72
|
+
if trailer && trailer[:Encrypt]
|
|
73
|
+
if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
74
|
+
trailer.value.delete(:Encrypt)
|
|
75
|
+
else
|
|
76
|
+
trailer.delete(:Encrypt)
|
|
77
|
+
end
|
|
78
|
+
document.config["encryption.handler"] = nil
|
|
79
|
+
document.config["encryption.password"] = nil
|
|
80
|
+
end
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Compute the /P integer: all bits set minus the denied ones.
|
|
85
|
+
def self.permission_bits(granted)
|
|
86
|
+
base = -1
|
|
87
|
+
PERMISSION_FLAGS.each do |name, bit|
|
|
88
|
+
base &= ~bit unless granted.include?(name)
|
|
89
|
+
end
|
|
90
|
+
base
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def ensure_id!
|
|
96
|
+
id0 = Digest::MD5.hexdigest(Time.now.to_s + rand.to_s)[0, 16]
|
|
97
|
+
trailer = document.trailer
|
|
98
|
+
if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
99
|
+
trailer.value[:ID] = [id0.b, id0.b]
|
|
100
|
+
else
|
|
101
|
+
trailer[:ID] = [id0.b, id0.b]
|
|
102
|
+
end
|
|
103
|
+
id0.b
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# RC4-based encryption for V2/V4 (40-bit or 128-bit).
|
|
107
|
+
def encrypt_rc4(user_pw, owner_pw, permissions, v:, r:, length:)
|
|
108
|
+
p_bits = self.class.permission_bits(permissions)
|
|
109
|
+
id0 = ensure_id!
|
|
110
|
+
|
|
111
|
+
o_entry = compute_o_entry(user_pw, owner_pw, r, length)
|
|
112
|
+
key = Pdfrb::Encryption::PasswordVerification.derive_key_rc4(
|
|
113
|
+
password: user_pw, o_entry: o_entry.b, p_flags: p_bits,
|
|
114
|
+
id0: id0, revision: r, key_length_bits: length,
|
|
115
|
+
encrypt_metadata: true
|
|
116
|
+
)
|
|
117
|
+
u_entry =
|
|
118
|
+
if r == 2
|
|
119
|
+
Pdfrb::Encryption::PasswordVerification.build_u_r2(key)
|
|
120
|
+
else
|
|
121
|
+
Pdfrb::Encryption::PasswordVerification.build_u_r3plus(
|
|
122
|
+
file_key: key, id0: id0, revision: r
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
register({ Filter: :Standard, V: v, R: r, Length: length,
|
|
127
|
+
P: p_bits, O: o_entry, U: u_entry },
|
|
128
|
+
user_password: user_pw)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# AES-256 R6 encryption for V5.
|
|
132
|
+
def encrypt_v5(user_pw, owner_pw, permissions)
|
|
133
|
+
p_bits = self.class.permission_bits(permissions)
|
|
134
|
+
id0 = ensure_id!
|
|
135
|
+
|
|
136
|
+
handler = Pdfrb::Encryption::StandardSecurityHandler.for_v5(
|
|
137
|
+
user_password: user_pw, owner_password: owner_pw,
|
|
138
|
+
permissions: p_bits, id: id0
|
|
139
|
+
)
|
|
140
|
+
dict = handler.encrypt_dict
|
|
141
|
+
register({ Filter: :Standard, V: dict[:V], R: dict[:R],
|
|
142
|
+
Length: dict[:Length], P: p_bits,
|
|
143
|
+
O: dict[:O], U: dict[:U], UE: dict[:UE],
|
|
144
|
+
OE: dict[:OE], Perms: dict[:Perms] },
|
|
145
|
+
user_password: user_pw,
|
|
146
|
+
prebuilt_handler: handler)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Compute the /O entry per Algorithm 3 (owner password hash).
|
|
150
|
+
def compute_o_entry(user_pw, owner_pw, revision, length_bits)
|
|
151
|
+
require "digest/md5"
|
|
152
|
+
pv = Pdfrb::Encryption::PasswordVerification
|
|
153
|
+
padded = pv.pad_password(owner_pw)
|
|
154
|
+
digest = Digest::MD5.digest(padded)
|
|
155
|
+
if revision >= 3
|
|
156
|
+
50.times do
|
|
157
|
+
digest = if length_bits >= 128
|
|
158
|
+
Digest::MD5.digest(digest[0, length_bits / 8])
|
|
159
|
+
else
|
|
160
|
+
Digest::MD5.digest(digest[0, 5])
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
rc4 = Pdfrb::Encryption::RC4Impl.new(digest[0, length_bits / 8])
|
|
165
|
+
o = rc4.process(pv.pad_password(user_pw))
|
|
166
|
+
if revision >= 3
|
|
167
|
+
19.downto(1) do |i|
|
|
168
|
+
key = digest[0, length_bits / 8].bytes.map { |b| b ^ i }.pack("C*")
|
|
169
|
+
o = Pdfrb::Encryption::RC4Impl.new(key).process(o)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
o
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Register the encrypt dict in the trailer + wire the handler.
|
|
176
|
+
def register(encrypt_hash, user_password:, prebuilt_handler: nil)
|
|
177
|
+
dict = document.add(encrypt_hash,
|
|
178
|
+
type: Pdfrb::Model::Type::EncryptionStandard)
|
|
179
|
+
ref = Pdfrb::Model::Reference.new(dict.oid, dict.gen)
|
|
180
|
+
trailer = document.trailer
|
|
181
|
+
if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
182
|
+
trailer.value[:Encrypt] = ref
|
|
183
|
+
else
|
|
184
|
+
trailer[:Encrypt] = ref
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
handler = prebuilt_handler || begin
|
|
188
|
+
h = Pdfrb::Encryption::StandardSecurityHandler.new(
|
|
189
|
+
{ Encrypt: encrypt_hash,
|
|
190
|
+
ID: if trailer.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
191
|
+
trailer.value[:ID]
|
|
192
|
+
else
|
|
193
|
+
trailer[:ID]
|
|
194
|
+
end }
|
|
195
|
+
)
|
|
196
|
+
h.verify_user_password?(user_password)
|
|
197
|
+
h
|
|
198
|
+
end
|
|
199
|
+
document.config["encryption.handler"] = handler
|
|
200
|
+
document.config["encryption.password"] = user_password
|
|
201
|
+
dict
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
data/lib/pdfrb/document.rb
CHANGED
|
@@ -31,6 +31,7 @@ module Pdfrb
|
|
|
31
31
|
autoload :Info, "pdfrb/document/info"
|
|
32
32
|
autoload :PageLabels, "pdfrb/document/page_labels"
|
|
33
33
|
autoload :Stamps, "pdfrb/document/stamps"
|
|
34
|
+
autoload :Encryption, "pdfrb/document/encryption"
|
|
34
35
|
|
|
35
36
|
def initialize(io: nil, config: {})
|
|
36
37
|
Pdfrb::Model::Type.eager_load!
|
|
@@ -163,6 +164,8 @@ module Pdfrb
|
|
|
163
164
|
|
|
164
165
|
def stamps; @stamps ||= Document::Stamps.new(self); end
|
|
165
166
|
|
|
167
|
+
def encryption; @encryption ||= Document::Encryption.new(self); end
|
|
168
|
+
|
|
166
169
|
def info; @info ||= Document::Info.new(self); end
|
|
167
170
|
|
|
168
171
|
def display; @display ||= Document::Display.new(self); end
|
|
@@ -219,7 +219,11 @@ module Pdfrb
|
|
|
219
219
|
hash = md5.digest
|
|
220
220
|
|
|
221
221
|
rc4 = RC4Impl.new(key)
|
|
222
|
-
|
|
222
|
+
19.downto(1) do |i|
|
|
223
|
+
xored_key = key.bytes.map { |b| b ^ i }.pack("C*")
|
|
224
|
+
rc4 = RC4Impl.new(xored_key)
|
|
225
|
+
hash = rc4.process(hash)
|
|
226
|
+
end
|
|
223
227
|
|
|
224
228
|
hash[0, 16]
|
|
225
229
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Thumbnail image stream (ISO 32000-2 §12.3.4). A small image
|
|
7
|
+
# XObject rendered at reduced resolution for use in viewer
|
|
8
|
+
# navigation panels. Attached to a page via the /Thumb key.
|
|
9
|
+
class Thumbnail < Pdfrb::Model::Cos::Stream
|
|
10
|
+
arlington_object "Thumbnail"
|
|
11
|
+
|
|
12
|
+
# /Width — required.
|
|
13
|
+
def width
|
|
14
|
+
value[:Width]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# /Height — required.
|
|
18
|
+
def height
|
|
19
|
+
value[:Height]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# /ColorSpace — required unless /ImageMask true.
|
|
23
|
+
def color_space
|
|
24
|
+
value[:ColorSpace]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# /BitsPerComponent — required.
|
|
28
|
+
def bits_per_component
|
|
29
|
+
value[:BitsPerComponent]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# /Filter — optional; a named filter or array of filters.
|
|
33
|
+
def filter
|
|
34
|
+
value[:Filter]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def dimensions
|
|
38
|
+
[width, height]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Timespan (ISO 32000-2 §12.7.11, PDF 1.5+). A duration with
|
|
7
|
+
# a unit, used in RichMedia timing, 3D animation, and
|
|
8
|
+
# JavaScript-embedded timelines.
|
|
9
|
+
class Timespan < Pdfrb::Model::Cos::Dictionary
|
|
10
|
+
arlington_object "Timespan"
|
|
11
|
+
|
|
12
|
+
# /Type — optional, fixed "Timespan".
|
|
13
|
+
def type
|
|
14
|
+
value[:Type]&.to_sym
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# /S — required, fixed "S" (seconds).
|
|
18
|
+
def subtype
|
|
19
|
+
value[:S]&.to_sym
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# /V — required, the numeric duration in seconds.
|
|
23
|
+
def duration
|
|
24
|
+
value[:V]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Convenience: duration in milliseconds.
|
|
28
|
+
def milliseconds
|
|
29
|
+
v = duration
|
|
30
|
+
v ? v.to_f * 1000 : nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# UserProperty (ISO 32000-2 §14.7.5). A single property in the
|
|
7
|
+
# /P array of a user property list attached to structure
|
|
8
|
+
# elements for custom metadata.
|
|
9
|
+
class UserProperty < Pdfrb::Model::Cos::Dictionary
|
|
10
|
+
arlington_object "UserProperty"
|
|
11
|
+
|
|
12
|
+
# /N — required, the property name.
|
|
13
|
+
def name
|
|
14
|
+
value[:N]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# /V — required, the property value (any COS type).
|
|
18
|
+
def property_value
|
|
19
|
+
value[:V]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# /F — optional, a text string with the intended format of
|
|
23
|
+
# the value.
|
|
24
|
+
def format
|
|
25
|
+
value[:F]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# /H — optional, whether the property is hidden from the
|
|
29
|
+
# user (default false).
|
|
30
|
+
def hidden?
|
|
31
|
+
value[:H] == true
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# Viewport (ISO 32000-2 §12.7.11, PDF 1.6+). Defines a
|
|
7
|
+
# rectangular region of a page intended for separate display,
|
|
8
|
+
# used for magnifier rectangles, measurement regions, and
|
|
9
|
+
# zoom targets.
|
|
10
|
+
class Viewport < Pdfrb::Model::Cos::Dictionary
|
|
11
|
+
arlington_object "Viewport"
|
|
12
|
+
|
|
13
|
+
# /Type — optional, fixed "Viewport".
|
|
14
|
+
def type
|
|
15
|
+
value[:Type]&.to_sym
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# /BBox — required, the viewport rectangle.
|
|
19
|
+
def bbox
|
|
20
|
+
value[:BBox]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# /Name — optional, human-readable viewport name.
|
|
24
|
+
def name
|
|
25
|
+
value[:Name]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# /Measure — optional indirect Measure dict (RL for rulers,
|
|
29
|
+
# GEO for geospatial since PDF 2.0).
|
|
30
|
+
def measure(document = nil)
|
|
31
|
+
ref = value[:Measure]
|
|
32
|
+
return nil unless ref && document
|
|
33
|
+
|
|
34
|
+
ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Model
|
|
5
|
+
module Type
|
|
6
|
+
# VRI (Validation Related Information) dictionary per ETSI EN
|
|
7
|
+
# 319 142-1 (PAdES) §B.5. Lives in /DSS /VRI map, keyed by the
|
|
8
|
+
# hex-encoded SHA-1 of the signature it validates. Holds the
|
|
9
|
+
# certificates, CRLs, and OCSP responses relevant to one
|
|
10
|
+
# signature.
|
|
11
|
+
class Vri < Pdfrb::Model::Cos::Dictionary
|
|
12
|
+
arlington_object "VRI"
|
|
13
|
+
|
|
14
|
+
# /Type — optional, fixed "VRI".
|
|
15
|
+
def type
|
|
16
|
+
value[:Type]&.to_sym
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# /Cert — array of indirect streams, each a DER-encoded
|
|
20
|
+
# X.509 certificate relevant to the signature.
|
|
21
|
+
def certificates(document = nil)
|
|
22
|
+
refs = value[:Cert]
|
|
23
|
+
return [] unless refs
|
|
24
|
+
|
|
25
|
+
resolve_refs(refs, document)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# /CRL — array of indirect streams, each a DER-encoded
|
|
29
|
+
# certificate revocation list.
|
|
30
|
+
def crls(document = nil)
|
|
31
|
+
refs = value[:CRL]
|
|
32
|
+
return [] unless refs
|
|
33
|
+
|
|
34
|
+
resolve_refs(refs, document)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# /OCSP — array of indirect streams, each a DER-encoded
|
|
38
|
+
# OCSP response.
|
|
39
|
+
def ocsp_responses(document = nil)
|
|
40
|
+
refs = value[:OCSP]
|
|
41
|
+
return [] unless refs
|
|
42
|
+
|
|
43
|
+
resolve_refs(refs, document)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# /TU — optional string-text with a human-readable timestamp.
|
|
47
|
+
def timestamp_text
|
|
48
|
+
value[:TU]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# /TS — optional indirect stream with a timestamp token.
|
|
52
|
+
def timestamp_token(document = nil)
|
|
53
|
+
ref = value[:TS]
|
|
54
|
+
return nil unless ref && document
|
|
55
|
+
|
|
56
|
+
ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def resolve_refs(refs, document)
|
|
62
|
+
return [] unless document
|
|
63
|
+
|
|
64
|
+
arr = refs.is_a?(Pdfrb::Model::PdfArray) ? refs.value : refs
|
|
65
|
+
arr = [arr] unless arr.is_a?(::Array)
|
|
66
|
+
arr.filter_map do |r|
|
|
67
|
+
next r unless r.is_a?(Pdfrb::Model::Reference)
|
|
68
|
+
|
|
69
|
+
document.object(r)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
data/lib/pdfrb/model/type.rb
CHANGED
|
@@ -356,6 +356,21 @@ module Pdfrb
|
|
|
356
356
|
|
|
357
357
|
# Page-piece dictionary (s14.5).
|
|
358
358
|
autoload :PagePieceInfo, "pdfrb/model/type/page_piece_info"
|
|
359
|
+
|
|
360
|
+
# PAdES validation-related information (ETSI EN 319 142-1).
|
|
361
|
+
autoload :Vri, "pdfrb/model/type/vri"
|
|
362
|
+
|
|
363
|
+
# Page thumbnails (s12.3.4).
|
|
364
|
+
autoload :Thumbnail, "pdfrb/model/type/thumbnail"
|
|
365
|
+
|
|
366
|
+
# Timespan (s12.7.11, PDF 1.5+).
|
|
367
|
+
autoload :Timespan, "pdfrb/model/type/timespan"
|
|
368
|
+
|
|
369
|
+
# Viewport (s12.7.11, PDF 1.6+).
|
|
370
|
+
autoload :Viewport, "pdfrb/model/type/viewport"
|
|
371
|
+
|
|
372
|
+
# User property (s14.7.5).
|
|
373
|
+
autoload :UserProperty, "pdfrb/model/type/user_property"
|
|
359
374
|
end
|
|
360
375
|
end
|
|
361
376
|
end
|
data/lib/pdfrb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pdfrb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -817,6 +817,7 @@ files:
|
|
|
817
817
|
- lib/pdfrb/document/colors.rb
|
|
818
818
|
- lib/pdfrb/document/destinations.rb
|
|
819
819
|
- lib/pdfrb/document/display.rb
|
|
820
|
+
- lib/pdfrb/document/encryption.rb
|
|
820
821
|
- lib/pdfrb/document/files.rb
|
|
821
822
|
- lib/pdfrb/document/fonts.rb
|
|
822
823
|
- lib/pdfrb/document/form.rb
|
|
@@ -1149,14 +1150,19 @@ files:
|
|
|
1149
1150
|
- lib/pdfrb/model/type/three_d_stream.rb
|
|
1150
1151
|
- lib/pdfrb/model/type/three_d_units.rb
|
|
1151
1152
|
- lib/pdfrb/model/type/three_d_view.rb
|
|
1153
|
+
- lib/pdfrb/model/type/thumbnail.rb
|
|
1154
|
+
- lib/pdfrb/model/type/timespan.rb
|
|
1152
1155
|
- lib/pdfrb/model/type/to_unicode_cmap_stream.rb
|
|
1153
1156
|
- lib/pdfrb/model/type/transition.rb
|
|
1154
1157
|
- lib/pdfrb/model/type/underline_annotation.rb
|
|
1155
1158
|
- lib/pdfrb/model/type/ur_transform_parameters.rb
|
|
1156
1159
|
- lib/pdfrb/model/type/uri_dict.rb
|
|
1157
1160
|
- lib/pdfrb/model/type/url_alias.rb
|
|
1161
|
+
- lib/pdfrb/model/type/user_property.rb
|
|
1158
1162
|
- lib/pdfrb/model/type/variable_text_field.rb
|
|
1159
1163
|
- lib/pdfrb/model/type/viewer_preferences.rb
|
|
1164
|
+
- lib/pdfrb/model/type/viewport.rb
|
|
1165
|
+
- lib/pdfrb/model/type/vri.rb
|
|
1160
1166
|
- lib/pdfrb/model/type/watermark_annotation.rb
|
|
1161
1167
|
- lib/pdfrb/model/type/widget_annotation.rb
|
|
1162
1168
|
- lib/pdfrb/model/type/widget_appearance.rb
|