rest_pki 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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +6 -1
- data/lib/rest_pki.rb +32 -0
- data/lib/rest_pki/cades_signature.rb +52 -0
- data/lib/rest_pki/color.rb +37 -0
- data/lib/rest_pki/digest_algorithm.rb +158 -0
- data/lib/rest_pki/digest_algorithm_and_value.rb +29 -0
- data/lib/rest_pki/oids.rb +163 -0
- data/lib/rest_pki/pades_measurement_units.rb +6 -0
- data/lib/rest_pki/pades_page_orientation.rb +7 -0
- data/lib/rest_pki/pades_paper_size.rb +17 -0
- data/lib/rest_pki/pades_signature_explorer.rb +17 -0
- data/lib/rest_pki/pades_signer_info.rb +11 -0
- data/lib/rest_pki/pades_size.rb +17 -0
- data/lib/rest_pki/pades_visual_rectangle.rb +25 -0
- data/lib/rest_pki/page_optimization.rb +34 -0
- data/lib/rest_pki/pdf_container_definition.rb +266 -0
- data/lib/rest_pki/pdf_helper.rb +29 -0
- data/lib/rest_pki/pdf_mark.rb +81 -0
- data/lib/rest_pki/pdf_mark_element.rb +54 -0
- data/lib/rest_pki/pdf_mark_element_type.rb +7 -0
- data/lib/rest_pki/pdf_mark_image.rb +25 -0
- data/lib/rest_pki/pdf_mark_image_element.rb +33 -0
- data/lib/rest_pki/pdf_mark_page_options.rb +8 -0
- data/lib/rest_pki/pdf_mark_qr_code_element.rb +32 -0
- data/lib/rest_pki/pdf_mark_text_element.rb +47 -0
- data/lib/rest_pki/pdf_marker.rb +61 -0
- data/lib/rest_pki/pdf_text_section.rb +57 -0
- data/lib/rest_pki/pdf_text_style.rb +7 -0
- data/lib/rest_pki/pk_algorithms.rb +173 -0
- data/lib/rest_pki/pk_certificate.rb +99 -0
- data/lib/rest_pki/resource_content_or_reference.rb +25 -0
- data/lib/rest_pki/resources/pades_explorer_model.rb +12 -0
- data/lib/rest_pki/resources/pdf_marker_model.rb +12 -0
- data/lib/rest_pki/signature_algorithm_and_value.rb +11 -0
- data/lib/rest_pki/signature_explorer.rb +48 -0
- data/lib/rest_pki/signature_policy_identifier.rb +10 -0
- data/lib/rest_pki/validation_item.rb +2 -2
- data/lib/rest_pki/validation_results.rb +11 -11
- data/lib/rest_pki/version.rb +1 -1
- metadata +37 -3
@@ -0,0 +1,54 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfMarkElement
|
3
|
+
attr_accessor :element_type, :relative_container, :rotation, :opacity
|
4
|
+
|
5
|
+
def initialize(element_type, relative_container = nil)
|
6
|
+
@element_type = element_type
|
7
|
+
@relative_container = relative_container
|
8
|
+
@rotation = 0
|
9
|
+
@opacity = 100
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_model
|
13
|
+
{
|
14
|
+
elementType: @element_type,
|
15
|
+
relativeContainer: @relative_container,
|
16
|
+
rotation: @rotation,
|
17
|
+
opacity: @opacity,
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
#region FluentApi
|
22
|
+
def on_container(relative_container)
|
23
|
+
@relative_container = relative_container
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_rotation(rotation)
|
28
|
+
@rotation = rotation
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def rotate90_clockwise
|
33
|
+
@rotation = 270
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def rotate90_counter_clockwise
|
38
|
+
@rotation = 90
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def rotate180
|
43
|
+
@rotation = 180
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_opacity(opacity)
|
48
|
+
@opacity = opacity
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
#endregion
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfMarkImage
|
3
|
+
attr_accessor :resource
|
4
|
+
|
5
|
+
def initialize(image_content=nil, mime_type=nil)
|
6
|
+
@resource = ResourceContentOrReference.new
|
7
|
+
unless image_content.nil?
|
8
|
+
@resource.content = image_content
|
9
|
+
end
|
10
|
+
|
11
|
+
unless mime_type.nil?
|
12
|
+
@resource.mime_type = mime_type
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_model
|
17
|
+
if @resource.content.nil? && @resource.url.nil?
|
18
|
+
raise 'The image content was not set, neither its URL'
|
19
|
+
end
|
20
|
+
{
|
21
|
+
resource: @resource.to_model
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfMarkImageElement < PdfMarkElement
|
3
|
+
attr_accessor :image
|
4
|
+
|
5
|
+
def initialize(relative_container = nil, image = nil)
|
6
|
+
super(PdfMarkElementType::IMAGE, relative_container)
|
7
|
+
@image = image
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_model
|
11
|
+
model = super
|
12
|
+
unless @image.nil?
|
13
|
+
model['image'] = @image.to_model
|
14
|
+
end
|
15
|
+
model
|
16
|
+
end
|
17
|
+
|
18
|
+
#region FluentApi
|
19
|
+
|
20
|
+
def with_mark_image(image)
|
21
|
+
@image = image
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_image(image_content, mime_type)
|
26
|
+
@image = PdfMarkImage.new(image_content, mime_type)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
#endregion
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfMarkQRCodeElement < PdfMarkElement
|
3
|
+
attr_accessor :qr_code_data, :draw_quiet_zone
|
4
|
+
|
5
|
+
def initialize(relative_container = nil, qr_code_data = nil)
|
6
|
+
super(PdfMarkElementType::QR_CODE, relative_container)
|
7
|
+
@qr_code_data = qr_code_data
|
8
|
+
@draw_quiet_zone = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_model
|
12
|
+
model = super
|
13
|
+
model['qrCodeData'] = @qr_code_data
|
14
|
+
model['qrCodeDataDrawQuietZones'] = @draw_quiet_zone
|
15
|
+
model
|
16
|
+
end
|
17
|
+
|
18
|
+
#region FluentApi
|
19
|
+
|
20
|
+
def with_qr_code_data(qr_code_data)
|
21
|
+
@qr_code_data = qr_code_data
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def draw_quiet_zone
|
26
|
+
@draw_quiet_zone = true
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
#endregion
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfMarkTextElement < PdfMarkElement
|
3
|
+
attr_accessor :text_sections, :align
|
4
|
+
|
5
|
+
def initialize(relative_container=nil, text_sections=[])
|
6
|
+
super(PdfMarkElementType::TEXT, relative_container)
|
7
|
+
@text_sections = text_sections
|
8
|
+
@align = 'Left'
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_model
|
12
|
+
model = super
|
13
|
+
model['textSections'] = @text_sections.map { |s| s.to_model }
|
14
|
+
model['align'] = @align
|
15
|
+
model
|
16
|
+
end
|
17
|
+
|
18
|
+
#region FluentApi
|
19
|
+
|
20
|
+
def align_text_left
|
21
|
+
@align = 'Left'
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def align_text_right
|
26
|
+
@align = 'Right'
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def align_text_center
|
31
|
+
@align = 'Center'
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_section(section)
|
36
|
+
@text_sections.push(section)
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_section_with_text(text)
|
41
|
+
@text_sections.push(PdfTextSection.new(text))
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
#endregion
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'base64'
|
2
|
+
module RestPki
|
3
|
+
class PdfMarker
|
4
|
+
attr_accessor :marks, :measurement_units, :page_optimization, :abort_if_signed
|
5
|
+
attr_reader :file_content
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
@marks = []
|
10
|
+
@measurement_units = PadesMeasurementUnits::CENTIMETERS
|
11
|
+
@page_optimization = nil
|
12
|
+
@abort_if_signed = nil
|
13
|
+
@file_content = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_file_from_path(path)
|
17
|
+
File.open(path, 'rb') do |f|
|
18
|
+
@file_content = f.read
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# region set_file
|
23
|
+
|
24
|
+
def set_file_from_content_raw(content_raw)
|
25
|
+
@file_content = content_raw
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_file_from_content_base64(content_base64)
|
29
|
+
content = nil
|
30
|
+
unless content_base64.nil?
|
31
|
+
content = Base64.decode64(content_base64)
|
32
|
+
end
|
33
|
+
@file_content = content
|
34
|
+
end
|
35
|
+
|
36
|
+
# endregion
|
37
|
+
|
38
|
+
def apply
|
39
|
+
if @file_content.nil?
|
40
|
+
raise 'No file was provided'
|
41
|
+
end
|
42
|
+
|
43
|
+
marks = @marks.map { |m| m.to_model }
|
44
|
+
page_optimization = nil
|
45
|
+
unless @page_optimization.nil?
|
46
|
+
page_optimization = @page_optimization.to_model
|
47
|
+
end
|
48
|
+
request = {
|
49
|
+
marks: marks,
|
50
|
+
measurementUnits: @measurement_units,
|
51
|
+
pageOptimization: page_optimization,
|
52
|
+
abortIfSigned: abort_if_signed
|
53
|
+
}
|
54
|
+
request['file'] = {
|
55
|
+
content: Base64.encode64(@file_content)
|
56
|
+
}
|
57
|
+
model = @client.post('Api/Pdf/AddMarks', request, 'pdf_marker_model')
|
58
|
+
model.file_content
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RestPki
|
2
|
+
class PdfTextSection
|
3
|
+
attr_accessor :text, :color, :font_size, :style
|
4
|
+
|
5
|
+
def initialize(text=nil, color=nil, font_size=nil)
|
6
|
+
if color.nil?
|
7
|
+
color = Color.from_rgb_string('#000000') # White
|
8
|
+
end
|
9
|
+
@style = PdfTextStyle::NORMAL
|
10
|
+
@text = text
|
11
|
+
@color = color
|
12
|
+
@font_size = font_size
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_model
|
16
|
+
color = nil
|
17
|
+
unless @color.nil?
|
18
|
+
color = @color
|
19
|
+
end
|
20
|
+
{
|
21
|
+
style: @style,
|
22
|
+
text: @text,
|
23
|
+
color: color,
|
24
|
+
fontSize: @font_size,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
#region FluentApi
|
29
|
+
|
30
|
+
def with_font_size(font_size)
|
31
|
+
@font_size = font_size
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_text(text)
|
36
|
+
@text = text
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def bold
|
41
|
+
@style = PdfTextStyle::BOLD
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def italic
|
46
|
+
@style = PdfTextStyle::ITALIC
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def with_color(color)
|
51
|
+
@color = color
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
#endregion
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module RestPki
|
2
|
+
|
3
|
+
class SignatureAlgorithm
|
4
|
+
attr_reader :name, :oid, :xml_uri, :digest_algorithm, :pk_algorithm
|
5
|
+
def initialize(name, oid, xml_uri, digest_algorithm, pk_algorithm)
|
6
|
+
@name = name
|
7
|
+
@oid = oid
|
8
|
+
@xml_uri = xml_uri
|
9
|
+
@digest_algorithm = digest_algorithm
|
10
|
+
@pk_algorithm = pk_algorithm
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.MD5_WITH_RSA; RSASignatureAlgorithm.new(DigestAlgorithm.MD5) end
|
14
|
+
def self.SHA1_WITH_RSA; RSASignatureAlgorithm.new(DigestAlgorithm.SHA1) end
|
15
|
+
def self.SHA256_WITH_RSA; RSASignatureAlgorithm.new(DigestAlgorithm.SHA256) end
|
16
|
+
def self.SHA384_WITH_RSA; RSASignatureAlgorithm.new(DigestAlgorithm.SHA384) end
|
17
|
+
def self.SHA512_WITH_RSA; RSASignatureAlgorithm.new(DigestAlgorithm.SHA512) end
|
18
|
+
|
19
|
+
def self.algorithms
|
20
|
+
[
|
21
|
+
SignatureAlgorithm.MD5_WITH_RSA,
|
22
|
+
SignatureAlgorithm.SHA1_WITH_RSA,
|
23
|
+
SignatureAlgorithm.SHA256_WITH_RSA,
|
24
|
+
SignatureAlgorithm.SHA384_WITH_RSA,
|
25
|
+
SignatureAlgorithm.SHA512_WITH_RSA
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.safe_algorithms
|
30
|
+
[
|
31
|
+
SignatureAlgorithm.SHA256_WITH_RSA,
|
32
|
+
SignatureAlgorithm.SHA384_WITH_RSA,
|
33
|
+
SignatureAlgorithm.SHA512_WITH_RSA
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.get_instance_by_name(name)
|
38
|
+
begin
|
39
|
+
sig = SignatureAlgorithm._algorithms.find{ |s| s.name == name}
|
40
|
+
rescue => exception
|
41
|
+
raise "Unrecognized digest algorithm name: #{name}"
|
42
|
+
end
|
43
|
+
sig
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_instance_by_oid(oid)
|
47
|
+
begin
|
48
|
+
sig = SignatureAlgorithm._algorithms.find{ |s| s.oid == oid}
|
49
|
+
rescue => exception
|
50
|
+
raise "Unrecognized digest algorithm oid: #{oid}"
|
51
|
+
end
|
52
|
+
sig
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.get_instance_by_xml_uri(xml_uri)
|
56
|
+
begin
|
57
|
+
sig = SignatureAlgorithm._algorithms.find{ |s| s.xml_uri == xml_uri}
|
58
|
+
rescue => exception
|
59
|
+
raise "Unrecognized digest algorithm XML URI: #{xml_uri}"
|
60
|
+
end
|
61
|
+
sig
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.get_instance_by_api_model(model)
|
65
|
+
algorithm = model['algorithm']
|
66
|
+
case algorithm
|
67
|
+
when 'MD5WithRSA'
|
68
|
+
return SignatureAlgorithm.MD5_WITH_RSA
|
69
|
+
when 'SHA1WithRSA'
|
70
|
+
return SignatureAlgorithm.SHA1_WITH_RSA
|
71
|
+
when 'SHA256WithRSA'
|
72
|
+
return SignatureAlgorithm.SHA256_WITH_RSA
|
73
|
+
when 'SHA384WithRSA'
|
74
|
+
return SignatureAlgorithm.SHA384_WITH_RSA
|
75
|
+
when 'SHA512WithRSA'
|
76
|
+
return SignatureAlgorithm.SHA512_WITH_RSA
|
77
|
+
else
|
78
|
+
raise "Unsupported signature algorithm: #{algorithm}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
class RSASignatureAlgorithm < SignatureAlgorithm
|
83
|
+
def initialize(digest_algorithm)
|
84
|
+
name = "#{digest_algorithm.name} with RSA"
|
85
|
+
pk_algorithm = PKAlgorithm.RSA
|
86
|
+
oid = nil
|
87
|
+
xml_uri = nil
|
88
|
+
case digest_algorithm
|
89
|
+
when DigestAlgorithm.MD5
|
90
|
+
oid = Oids.oids["MD5_WITH_RSA"]
|
91
|
+
xml_uri = 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5'
|
92
|
+
when DigestAlgorithm.SHA1
|
93
|
+
oid = Oids.oids["SHA1_WITH_RSA"]
|
94
|
+
xml_uri = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
|
95
|
+
when DigestAlgorithm.SHA256
|
96
|
+
oid = Oids.oids["SHA256_WITH_RSA"]
|
97
|
+
xml_uri = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
|
98
|
+
when DigestAlgorithm.SHA384
|
99
|
+
oid = Oids.oids["SHA384_WITH_RSA"]
|
100
|
+
xml_uri = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
|
101
|
+
when DigestAlgorithm.SHA512
|
102
|
+
oid = Oids.oids["SHA512_WITH_RSA"]
|
103
|
+
xml_uri = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
|
104
|
+
else
|
105
|
+
raise "Unsupported digest algorithm: #{digest_algorithm}"
|
106
|
+
end
|
107
|
+
|
108
|
+
super(name, oid, xml_uri, digest_algorithm, pk_algorithm)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
class PKAlgorithm
|
112
|
+
attr_reader :name, :oid
|
113
|
+
def initialize(name, oid)
|
114
|
+
@name = name
|
115
|
+
@oid = oid
|
116
|
+
end
|
117
|
+
|
118
|
+
def ==(comparison_object)
|
119
|
+
if comparison_object.equal?(self)
|
120
|
+
return true
|
121
|
+
end
|
122
|
+
unless comparison_object.instance_of?(self.class)
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
self.oid == comparison_object.oid
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.RSA; RSAPKAlgorithm.new end
|
129
|
+
|
130
|
+
def self._algorithms
|
131
|
+
[PKAlgorithm.RSA]
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.get_instance_by_name(name)
|
135
|
+
begin
|
136
|
+
alg = PKAlgorithm.algorithms.find{|a| a.name == name}
|
137
|
+
rescue => exception
|
138
|
+
raise "Unrecognized private key algorithm name: #{name}"
|
139
|
+
end
|
140
|
+
alg
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.get_instance_by_oid(oid)
|
144
|
+
begin
|
145
|
+
alg = PKAlgorithm.algorithms.find{|a| a.name == oid}
|
146
|
+
rescue => exception
|
147
|
+
raise "Unrecognized private key algorithm oid: #{oid}"
|
148
|
+
end
|
149
|
+
alg
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.get_instance_by_api_model(algorithm)
|
153
|
+
case algorithm
|
154
|
+
when 'RSA'
|
155
|
+
return PKAlgorithm.RSA
|
156
|
+
else
|
157
|
+
raise "Unsupported private key algorithms #{algorithm}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
class RSAPKAlgorithm < PKAlgorithm
|
163
|
+
def initialize
|
164
|
+
name = 'RSA'
|
165
|
+
oid = Oids.oids["RSA"]
|
166
|
+
super(name, oid)
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.get_signature_algorithm(digest_algorithm)
|
170
|
+
RSASignatureAlgorithm.new(digest_algorithm)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|