main
1# frozen_string_literal: true
2
3module Xml
4 module Kit
5 module Templatable
6 # Can be used to disable embeding a signature.
7 # By default a signature will be embedded if a signing
8 # certificate is available.
9 attr_accessor :embed_signature
10
11 # Used to enable/disable encrypting the document.
12 attr_accessor :encrypt
13
14 # The [Xml::Kit::KeyPair] to use for generating a signature.
15 attr_accessor :signing_key_pair
16
17 # The [Xml::Kit::Certificate] that contains the public key to use for encrypting the document.
18 attr_accessor :encryption_certificate
19
20 # Allows you to specify the digest method algorithm. (Default: SHA256)
21 # A list of digest methods can be found in [Xml::Kit::Signature].
22 attr_accessor :digest_method
23
24 # Allows you to specify the signature method algorithm. (Default: SHA256)
25 # A list of signature methods can be found in [Xml::Kit::Signature].
26 attr_accessor :signature_method
27
28 # Returns the generated XML document with an XML Digital Signature and XML Encryption.
29 def to_xml(xml: ::Builder::XmlMarkup.new, pretty: false)
30 result = signatures.complete(render(self, xml: xml))
31 pretty ? Nokogiri::XML(result).to_xml(indent: 2) : result
32 end
33
34 # Generates an {#Xml::Kit::EncryptedKey} section. https://www.w3.org/TR/xmlenc-core1/#sec-EncryptedKey
35 #
36 # @since 0.3.0
37 # @param xml [Builder::XmlMarkup] the xml builder instance
38 # @param id [String] the id of EncryptedKey element
39 def encrypt_key_for(xml:, id:, key_info: nil)
40 ::Xml::Kit::EncryptedKey.new(
41 id: id,
42 asymmetric_cipher: asymmetric_cipher,
43 symmetric_cipher: symmetric_cipher,
44 key_info: key_info
45 ).to_xml(xml: xml)
46 end
47
48 # @deprecated Use {#encrypt_data_for} instead of this
49 def encryption_for(*args, &block)
50 ::Xml::Kit.deprecate(
51 'encryption_for is deprecated. Use encrypt_data_for instead.'
52 )
53 encrypt_data_for(*args, &block)
54 end
55
56 # Generates an {#Xml::Kit::EncryptedData} section. https://www.w3.org/TR/xmlenc-core1/#sec-EncryptedData
57 #
58 # @since 0.3.0
59 # @param xml [Builder::XmlMarkup] the xml builder instance
60 # @param key_info [Xml::Kit::KeyInfo] the key info to render in the EncryptedData
61 def encrypt_data_for(xml:, key_info: nil)
62 return yield xml unless encrypt?
63
64 temp = ::Builder::XmlMarkup.new
65 yield temp
66 ::Xml::Kit::EncryptedData.new(
67 signatures.complete(temp.target!),
68 symmetric_cipher: symmetric_cipher,
69 asymmetric_cipher: asymmetric_cipher,
70 key_info: key_info
71 ).to_xml(xml: xml)
72 end
73
74 # Provides a default RSA asymmetric cipher. Can be overridden to provide custom ciphers.
75 #
76 # @abstract
77 # @since 0.3.0
78 def asymmetric_cipher(algorithm: Crypto::RsaCipher::ALGORITHM)
79 raise Xml::Kit::Error, 'encryption_certificate is not specified.' unless encryption_certificate
80
81 @asymmetric_cipher ||= Crypto.cipher_for(
82 algorithm,
83 encryption_certificate.public_key
84 )
85 end
86
87 # Provides a default aes256-cbc symmetric cipher. Can be overridden to provide custom ciphers.
88 #
89 # @abstract
90 # @since 0.3.0
91 def symmetric_cipher
92 @symmetric_cipher ||= Crypto::SymmetricCipher.new
93 end
94
95 def render(model, options)
96 ::Xml::Kit::Template.new(model).to_xml(options)
97 end
98
99 def signature_for(reference_id:, xml:)
100 return unless sign?
101
102 signatures.build(reference_id).to_xml(xml: xml)
103 end
104
105 # Allows you to specify which key pair to use for generating an XML digital signature.
106 #
107 # @param key_pair [Xml::Kit::KeyPair] the key pair to use for signing.
108 def sign_with(key_pair, signature_method: :SHA256, digest_method: :SHA256)
109 self.signing_key_pair = key_pair
110 self.embed_signature = true
111 self.signature_method = signature_method
112 self.digest_method = digest_method
113 signatures.sign_with(key_pair)
114 end
115
116 # Allows you to specify which public key to use for generating an XML encrypted element.
117 #
118 # @param certificate [Xml::Kit::Certificate] the certificate containing the public key to use for encryption.
119 def encrypt_with(certificate)
120 self.encrypt = true
121 self.encryption_certificate = certificate
122 end
123
124 private
125
126 def sign?
127 embed_signature
128 end
129
130 # @!visibility private
131 def signatures
132 @signatures ||= ::Xml::Kit::Signatures.new(
133 key_pair: signing_key_pair,
134 digest_method: digest_method || :SHA256,
135 signature_method: signature_method || :SHA256
136 )
137 end
138
139 # @!visibility private
140 def encrypt?
141 encrypt && encryption_certificate
142 end
143 end
144 end
145end