nokogiri-xmlsec-instructure 0.10.3 → 0.12.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/ext/nokogiri_ext_xmlsec/extconf.rb +8 -16
  3. data/ext/nokogiri_ext_xmlsec/nokogiri_decrypt_with_key.c +5 -0
  4. data/ext/nokogiri_ext_xmlsec/nokogiri_encrypt_with_key.c +17 -0
  5. data/ext/nokogiri_ext_xmlsec/nokogiri_sign.c +19 -2
  6. data/ext/nokogiri_ext_xmlsec/options.c +44 -1
  7. data/ext/nokogiri_ext_xmlsec/options.h +6 -4
  8. data/lib/nokogiri-xmlsec.rb +3 -1
  9. data/lib/xmlsec/version.rb +3 -1
  10. data/lib/xmlsec.rb +99 -88
  11. metadata +10 -167
  12. data/.github/workflows/push.yml +0 -40
  13. data/.gitignore +0 -23
  14. data/.rspec +0 -2
  15. data/.tool-versions +0 -1
  16. data/Appraisals +0 -9
  17. data/Gemfile +0 -4
  18. data/Guardfile +0 -13
  19. data/LICENSE.txt +0 -22
  20. data/README.md +0 -132
  21. data/Rakefile +0 -30
  22. data/gemfiles/nokogiri_12.5.gemfile +0 -7
  23. data/gemfiles/nokogiri_13.10.gemfile +0 -7
  24. data/nokogiri-xmlsec-instructure.gemspec +0 -41
  25. data/spec/fixtures/cert/server.crt +0 -14
  26. data/spec/fixtures/cert/server.csr +0 -11
  27. data/spec/fixtures/cert/server.key.decrypted +0 -15
  28. data/spec/fixtures/cert/server.key.encrypted +0 -18
  29. data/spec/fixtures/hate.xml +0 -7
  30. data/spec/fixtures/pwned.xml +0 -1
  31. data/spec/fixtures/rsa.pem +0 -15
  32. data/spec/fixtures/rsa.pub +0 -6
  33. data/spec/fixtures/sign2-doc.xml +0 -6
  34. data/spec/fixtures/sign2-result.xml +0 -25
  35. data/spec/fixtures/sign3-result.xml +0 -39
  36. data/spec/lib/nokogiri/xml/document/encryption_and_decryption_spec.rb +0 -55
  37. data/spec/lib/nokogiri/xml/document/signing_and_verifying_spec.rb +0 -122
  38. data/spec/lib/nokogiri/xml/document/unsafe_xml_spec.rb +0 -61
  39. data/spec/spec_helper.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d80bf299c2e7900122535982dfde8b7b6ab67ea53528b0b055c3758b9b9753f
4
- data.tar.gz: 379cbbff6fc67ac23cf9d604d15aea36f79e58418b034dcf5e5b45db3c86a739
3
+ metadata.gz: 9b9e1360203a6f2ce84bc88abe8d731d657a88a02642d5cc26827f3dac53c6da
4
+ data.tar.gz: 1d5fa5d3e4570b50716268d2cd65a7159a0170466babb829042169c71c1e20b0
5
5
  SHA512:
6
- metadata.gz: e87ccfb10dfc8d9afe6964c58f4a56179fde5faa0ab007fb8bb5b62a038d6bc609d7f96efc09fbc394d3e51af568f3134133d87d5a843d6a456fe949dca464c2
7
- data.tar.gz: 705acc4113dc8380a29c3ef001a19eceda6a128e9c08441a3ebd9f135452f5d0a22419d8cfdd64f2002841132687f10f84af09fe998d19f701aeff5d4860e21a
6
+ metadata.gz: 97d2d274344a10a9be1fe7c7c354882ff1d1d1a56ba38cd28c4ba8f2e1f6e64c4aa4f8ac143361fda0187b1ef69ee2ac8cdec0688164c67a83567aab7a1286be
7
+ data.tar.gz: 477f5c98388d76e02cbdaf913ff21328c3ed397fd5797c363d7dfc5d9641f25657eea0bf0b027ac599d0620976c8e72f12de5c19aa3a0fcb77bc01bf69ff3de9
@@ -1,22 +1,14 @@
1
- require 'mkmf'
2
- require 'nokogiri'
1
+ # frozen_string_literal: true
3
2
 
4
- def barf message = 'dependencies not met'
5
- raise message
6
- end
3
+ require "mkmf"
4
+ require "nokogiri"
7
5
 
8
- barf unless have_header('ruby.h')
6
+ abort unless pkg_config("xmlsec1")
7
+ append_cflags("-fvisibility=hidden")
9
8
 
10
- pkg_config('xmlsec1')
11
- $CFLAGS << " " + `xmlsec1-config --cflags`.strip
12
- $CFLAGS << " -fvisibility=hidden"
13
-
14
- $CFLAGS << Dir[Gem.loaded_specs['nokogiri'].full_gem_path + "/ext/*"].map { |dir| " -I#{dir}"}.join("")
15
-
16
- puts "Cflags: #{$CFLAGS}"
17
- $libs = `xmlsec1-config --libs`.strip
9
+ abort unless find_header("nokogiri.h", *Dir["#{Gem.loaded_specs["nokogiri"].full_gem_path}/ext/*"])
18
10
 
19
11
  # We reference symbols out of nokogiri but don't link directly against it
20
- $LDFLAGS << ' -Wl,-undefined,dynamic_lookup'
12
+ append_ldflags(["-Wl", "-undefined,dynamic_lookup"])
21
13
 
22
- create_makefile('nokogiri_ext_xmlsec')
14
+ create_makefile("nokogiri_ext_xmlsec")
@@ -39,6 +39,11 @@ VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
39
39
  // don't let xmlsec free the node we're looking at out from under us
40
40
  encCtx->flags |= XMLSEC_ENC_RETURN_REPLACED_NODE;
41
41
 
42
+ #ifdef XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH
43
+ // Enable lax key search, since xmlsec 1.3.0
44
+ encCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH;
45
+ #endif
46
+
42
47
  // decrypt the data
43
48
  if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
44
49
  rb_exception_result = rb_eDecryptionError;
@@ -115,6 +115,11 @@ VALUE encrypt_with_key(VALUE self, VALUE rb_rsa_key_name, VALUE rb_rsa_key,
115
115
  goto done;
116
116
  }
117
117
 
118
+ #ifdef XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH
119
+ // Enable lax key search, since xmlsec 1.3.0
120
+ encCtx->keyInfoWriteCtx.flags |= XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH;
121
+ #endif
122
+
118
123
  // Generate the symmetric key.
119
124
  encCtx->encKey = xmlSecKeyGenerateByName(BAD_CAST options.key_type, options.key_bits,
120
125
  xmlSecKeyDataTypeSession);
@@ -137,6 +142,10 @@ VALUE encrypt_with_key(VALUE self, VALUE rb_rsa_key_name, VALUE rb_rsa_key,
137
142
  }
138
143
  }
139
144
 
145
+ // We don't want xmlsec to free the node we're looking at out from under us,
146
+ // since it's still referenced from a Ruby object.
147
+ encCtx->flags |= XMLSEC_ENC_RETURN_REPLACED_NODE;
148
+
140
149
  // Set key name.
141
150
  if(keyName) {
142
151
  if(xmlSecKeySetName(encCtx->encKey, (xmlSecByte *)keyName) < 0) {
@@ -180,6 +189,14 @@ done:
180
189
 
181
190
  /* cleanup */
182
191
  if(encCtx != NULL) {
192
+ // the replaced node is orphaned, but not freed; let Nokogiri
193
+ // own it now
194
+ if (encCtx->replacedNodeList != NULL) {
195
+ noko_xml_document_pin_node(encCtx->replacedNodeList);
196
+ // no really, please don't free it
197
+ encCtx->replacedNodeList = NULL;
198
+ }
199
+
183
200
  xmlSecEncCtxDestroy(encCtx);
184
201
  }
185
202
 
@@ -14,6 +14,9 @@
14
14
  // taken from http://www.w3.org/TR/xmldsig-core
15
15
  // :digest_alg - Algorithm identified by the URL fragment. Supported algorithms
16
16
  // taken from http://www.w3.org/TR/xmldsig-core
17
+ // :canon_alg - Algorithm identified by the URL fragment. Supported algorithms
18
+ // taken from http://www.w3.org/TR/xmldsig-core/#sec-c14nAlg
19
+ // Default is ExclC14N (exclusive canonicalization).
17
20
  // :name - [optional] String with name of the rsa key.
18
21
  // :uri - [optional] The URI attribute for the <Reference> node in the
19
22
  // signature.
@@ -45,6 +48,7 @@ VALUE sign(VALUE self, VALUE rb_opts) {
45
48
  VALUE rb_cert = rb_hash_aref(rb_opts, ID2SYM(rb_intern("cert")));
46
49
  VALUE rb_signature_alg = rb_hash_aref(rb_opts, ID2SYM(rb_intern("signature_alg")));
47
50
  VALUE rb_digest_alg = rb_hash_aref(rb_opts, ID2SYM(rb_intern("digest_alg")));
51
+ VALUE rb_canon_alg = rb_hash_aref(rb_opts, ID2SYM(rb_intern("canon_alg")));
48
52
  VALUE rb_uri = rb_hash_aref(rb_opts, ID2SYM(rb_intern("uri")));
49
53
  VALUE rb_key_name = rb_hash_aref(rb_opts, ID2SYM(rb_intern("name")));
50
54
  VALUE rb_store_references = rb_hash_aref(rb_opts, ID2SYM(rb_intern("store_references")));
@@ -71,6 +75,9 @@ VALUE sign(VALUE self, VALUE rb_opts) {
71
75
  Check_Type(rb_uri, T_STRING);
72
76
  refUri = StringValueCStr(rb_uri);
73
77
  }
78
+ if (!NIL_P(rb_canon_alg)){
79
+ Check_Type(rb_canon_alg, T_STRING);
80
+ }
74
81
  switch (TYPE(rb_store_references)) {
75
82
  case T_TRUE:
76
83
  store_references = 1;
@@ -83,6 +90,15 @@ VALUE sign(VALUE self, VALUE rb_opts) {
83
90
  break;
84
91
  }
85
92
 
93
+ xmlSecTransformId canon_algorithm = xmlSecTransformExclC14NId; // default
94
+ if (!NIL_P(rb_canon_alg)){
95
+ canon_algorithm = GetCanonicalizationMethod(rb_canon_alg,
96
+ &rb_exception_result, &exception_message);
97
+ if (canon_algorithm == xmlSecTransformIdUnknown){
98
+ goto done;
99
+ }
100
+ }
101
+
86
102
  xmlSecTransformId signature_algorithm = GetSignatureMethod(rb_signature_alg,
87
103
  &rb_exception_result, &exception_message);
88
104
  if (signature_algorithm == xmlSecTransformIdUnknown) {
@@ -93,7 +109,7 @@ VALUE sign(VALUE self, VALUE rb_opts) {
93
109
  Noko_Node_Get_Struct(self, xmlNode, envelopeNode);
94
110
  doc = envelopeNode->doc;
95
111
  // create signature template for enveloped signature.
96
- signNode = xmlSecTmplSignatureCreate(doc, xmlSecTransformExclC14NId,
112
+ signNode = xmlSecTmplSignatureCreate(doc, canon_algorithm,
97
113
  signature_algorithm, NULL);
98
114
  if (signNode == NULL) {
99
115
  rb_exception_result = rb_eSigningError;
@@ -111,6 +127,7 @@ VALUE sign(VALUE self, VALUE rb_opts) {
111
127
  // Propagate exception.
112
128
  goto done;
113
129
  }
130
+
114
131
  refNode = xmlSecTmplSignatureAddReference(signNode, digest_algorithm,
115
132
  NULL, (const xmlChar *)refUri, NULL);
116
133
  if(refNode == NULL) {
@@ -126,7 +143,7 @@ VALUE sign(VALUE self, VALUE rb_opts) {
126
143
  goto done;
127
144
  }
128
145
 
129
- if(xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformExclC14NId) == NULL) {
146
+ if(xmlSecTmplReferenceAddTransform(refNode, canon_algorithm) == NULL){
130
147
  rb_exception_result = rb_eSigningError;
131
148
  exception_message = "failed to add canonicalization transform to reference";
132
149
  goto done;
@@ -15,8 +15,11 @@ static const char RSA_OAEP_MGF1P[] = "rsa-oaep-mgf1p";
15
15
  // Block Encryption Strings.
16
16
  static const char TRIPLEDES_CBC[] = "tripledes-cbc";
17
17
  static const char AES128_CBC[] = "aes128-cbc";
18
- static const char AES256_CBC[] = "aes256-cbc";
19
18
  static const char AES192_CBC[] = "aes192-cbc";
19
+ static const char AES256_CBC[] = "aes256-cbc";
20
+ static const char GCM128_CBC[] = "aes128-gcm";
21
+ static const char GCM192_CBC[] = "aes192-gcm";
22
+ static const char GCM256_CBC[] = "aes256-gcm";
20
23
 
21
24
  // Supported signature algorithms taken from #6 of
22
25
  // http://www.w3.org/TR/xmldsig-core1/
@@ -44,6 +47,13 @@ static const char DIGEST_SHA256[] = "sha256";
44
47
  static const char DIGEST_SHA384[] = "sha384";
45
48
  static const char DIGEST_SHA512[] = "sha512";
46
49
 
50
+ // Canonicalization algorithms
51
+ // http://www.w3.org/TR/xmldsig-core1/#sec-Canonicalization
52
+ static const char C14N[] = "c14n";
53
+ static const char C14N_WITH_COMMENTS[] = "c14n-with-comments";
54
+ static const char EXCL_C14N[] = "exc-c14n";
55
+ static const char EXCL_C14N_WITH_COMMENTS[] = "exc-c14n-with-comments";
56
+
47
57
  BOOL GetXmlEncOptions(VALUE rb_opts,
48
58
  XmlEncOptions* options,
49
59
  VALUE* rb_exception_result,
@@ -82,6 +92,18 @@ BOOL GetXmlEncOptions(VALUE rb_opts,
82
92
  options->block_encryption = xmlSecTransformDes3CbcId;
83
93
  options->key_type = "des";
84
94
  options->key_bits = 192;
95
+ } else if (strncmp(GCM256_CBC, blockEncryptionValue, blockEncryptionLen) == 0) {
96
+ options->block_encryption = xmlSecTransformAes256GcmId;
97
+ options->key_type = "aes";
98
+ options->key_bits = 256;
99
+ } else if (strncmp(GCM128_CBC, blockEncryptionValue, blockEncryptionLen) == 0) {
100
+ options->block_encryption = xmlSecTransformAes128GcmId;
101
+ options->key_type = "aes";
102
+ options->key_bits = 128;
103
+ } else if (strncmp(GCM192_CBC, blockEncryptionValue, blockEncryptionLen) == 0) {
104
+ options->block_encryption = xmlSecTransformAes192GcmId;
105
+ options->key_type = "aes";
106
+ options->key_bits = 192;
85
107
  } else {
86
108
  *rb_exception_result = rb_eArgError;
87
109
  *exception_message = "Unknown :block_encryption value";
@@ -164,3 +186,24 @@ xmlSecTransformId GetDigestMethod(VALUE rb_digest_alg,
164
186
  *exception_message = "Unknown :digest_algorithm";
165
187
  return xmlSecTransformIdUnknown;
166
188
  }
189
+
190
+ xmlSecTransformId GetCanonicalizationMethod(VALUE rb_canon_alg,
191
+ VALUE *rb_exception_result,
192
+ const char **exception_message){
193
+ const char *canonAlgorithm = RSTRING_PTR(rb_canon_alg);
194
+ unsigned int canonAlgorithmLength = RSTRING_LEN(rb_canon_alg);
195
+
196
+ if (strncmp(C14N, canonAlgorithm, canonAlgorithmLength) == 0){
197
+ return xmlSecTransformInclC14NId;
198
+ }else if (strncmp(C14N_WITH_COMMENTS, canonAlgorithm, canonAlgorithmLength) == 0){
199
+ return xmlSecTransformInclC14NWithCommentsId;
200
+ }else if (strncmp(EXCL_C14N, canonAlgorithm, canonAlgorithmLength) == 0){
201
+ return xmlSecTransformExclC14NId;
202
+ } else if (strncmp(EXCL_C14N_WITH_COMMENTS, canonAlgorithm, canonAlgorithmLength) == 0){
203
+ return xmlSecTransformExclC14NWithCommentsId;
204
+ }
205
+
206
+ *rb_exception_result = rb_eArgError;
207
+ *exception_message = "Unknown :canon_alg";
208
+ return xmlSecTransformIdUnknown;
209
+ }
@@ -30,7 +30,9 @@ xmlSecTransformId GetSignatureMethod(VALUE rb_method,
30
30
  VALUE* rb_exception_result,
31
31
  const char** exception_message);
32
32
  xmlSecTransformId GetDigestMethod(VALUE rb_digest_method,
33
- VALUE* rb_exception_result,
34
- const char** exception_message);
35
-
36
- #endif // NOKOGIRI_EXT_XMLSEC_OPTIONS_H
33
+ VALUE *rb_exception_result,
34
+ const char **exception_message);
35
+ xmlSecTransformId GetCanonicalizationMethod(VALUE rb_canonicalization_method,
36
+ VALUE *rb_exception_result,
37
+ const char **exception_message);
38
+ #endif // NOKOGIRI_EXT_XMLSEC_OPTIONS_H
@@ -1 +1,3 @@
1
- require 'xmlsec'
1
+ # frozen_string_literal: true
2
+
3
+ require "xmlsec"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Xmlsec
2
- VERSION = '0.10.3'
4
+ VERSION = "0.12.0"
3
5
  end
data/lib/xmlsec.rb CHANGED
@@ -1,103 +1,114 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "xmlsec/version"
2
- require 'nokogiri'
3
- require 'nokogiri_ext_xmlsec'
4
+ require "nokogiri"
5
+ require "nokogiri_ext_xmlsec"
4
6
 
5
- class Nokogiri::XML::Document
6
- def sign! opts
7
- root.sign! opts
8
- self
9
- end
7
+ module Nokogiri
8
+ module XML
9
+ class Document
10
+ def sign!(opts)
11
+ root.sign! opts
12
+ self
13
+ end
10
14
 
11
- # Verifies the signature on the current document.
12
- #
13
- # Returns `true` if the signature is valid, `false` otherwise.
14
- #
15
- # Examples:
16
- #
17
- # # Try to validate with the given public or private key
18
- # doc.verify_with key: 'rsa-key'
19
- #
20
- # # Try to validate with a set of keys. It will try to match
21
- # # based on the contents of the `KeyName` element.
22
- # doc.verify_with({
23
- # 'key-name' => 'x509 certificate',
24
- # 'another-key-name' => 'rsa-public-key'
25
- # })
26
- #
27
- # # Try to validate with a trusted certificate
28
- # doc.verify_with(cert: 'certificate')
29
- #
30
- # # Try to validate with a set of certificates, any one of which
31
- # # can match
32
- # doc.verify_with(certs: ['cert1', 'cert2'])
33
- #
34
- # # Validate the signature, checking the certificate validity as of
35
- # # a certain time (anything that's convertible to an integer, such as a Time)
36
- # doc.verify_with(cert: 'certificate', verification_time: message_creation_timestamp)
37
- #
38
- # # Validate the signature, but don't validate that the certificate is valid,
39
- # # or has a full trust chain
40
- # doc.verify_with(cert: 'certificate', verify_certificates: false)
41
- #
42
- def verify_with opts_or_keys
43
- first_signature = root.at_xpath("//ds:Signature", 'ds' => "http://www.w3.org/2000/09/xmldsig#")
44
- raise XMLSec::VerificationError("start node not found") unless first_signature
15
+ # Verifies the signature on the current document.
16
+ #
17
+ # Returns `true` if the signature is valid, `false` otherwise.
18
+ #
19
+ # Examples:
20
+ #
21
+ # # Try to validate with the given public or private key
22
+ # doc.verify_with key: 'rsa-key'
23
+ #
24
+ # # Try to validate with a set of keys. It will try to match
25
+ # # based on the contents of the `KeyName` element.
26
+ # doc.verify_with({
27
+ # 'key-name' => 'x509 certificate',
28
+ # 'another-key-name' => 'rsa-public-key'
29
+ # })
30
+ #
31
+ # # Try to validate with a trusted certificate
32
+ # doc.verify_with(cert: 'certificate')
33
+ #
34
+ # # Try to validate with a set of certificates, any one of which
35
+ # # can match
36
+ # doc.verify_with(certs: ['cert1', 'cert2'])
37
+ #
38
+ # # Validate the signature, checking the certificate validity as of
39
+ # # a certain time (anything that's convertible to an integer, such as a Time)
40
+ # doc.verify_with(cert: 'certificate', verification_time: message_creation_timestamp)
41
+ #
42
+ # # Validate the signature, but don't validate that the certificate is valid,
43
+ # # or has a full trust chain
44
+ # doc.verify_with(cert: 'certificate', verify_certificates: false)
45
+ #
46
+ def verify_with(opts_or_keys)
47
+ first_signature = root.at_xpath("//ds:Signature", "ds" => "http://www.w3.org/2000/09/xmldsig#")
48
+ raise XMLSec::VerificationError("start node not found") unless first_signature
45
49
 
46
- first_signature.verify_with(opts_or_keys)
47
- end
50
+ first_signature.verify_with(opts_or_keys)
51
+ end
48
52
 
49
- # Attempts to verify the signature of this document using only certificates
50
- # installed on the system. This is equivalent to calling
51
- # `verify_with certificates: []` (that is, an empty array).
52
- #
53
- def verify_signature
54
- verify_with(certs: [])
55
- end
53
+ # Attempts to verify the signature of this document using only certificates
54
+ # installed on the system. This is equivalent to calling
55
+ # `verify_with certificates: []` (that is, an empty array).
56
+ #
57
+ def verify_signature
58
+ verify_with(certs: [])
59
+ end
56
60
 
57
- # Encrypts the current document, then returns it.
58
- #
59
- # Examples:
60
- #
61
- # # encrypt with a public key and optional key name
62
- # doc.encrypt! key: 'public-key', name: 'name'
63
- #
64
- def encrypt!(key:, name: nil, **opts)
65
- root.encrypt_with(key: key, name: name, **opts)
66
- self
67
- end
61
+ # Encrypts the current document, then returns it.
62
+ #
63
+ # Examples:
64
+ #
65
+ # # encrypt with a public key and optional key name
66
+ # doc.encrypt! key: 'public-key', name: 'name'
67
+ #
68
+ def encrypt!(key:, name: nil, **)
69
+ root.encrypt_with(key:, name:, **)
70
+ self
71
+ end
68
72
 
69
- # Decrypts the current document, then returns it.
70
- #
71
- # Examples:
72
- #
73
- # # decrypt with a specific private key
74
- # doc.decrypt! key: 'private-key'
75
- # # pass the key as an OpenSSL PKey object
76
- # doc.decrypt! key: OpenSSL::PKey.read('private-key')
77
- #
78
- def decrypt! opts
79
- first_encrypted_node = root.at_xpath("//xenc:EncryptedData", 'xenc' => "http://www.w3.org/2001/04/xmlenc#")
80
- raise XMLSec::DecryptionError("start node not found") unless first_encrypted_node
73
+ # Decrypts the current document, then returns it.
74
+ #
75
+ # Examples:
76
+ #
77
+ # # decrypt with a specific private key
78
+ # doc.decrypt! key: 'private-key'
79
+ # # pass the key as an OpenSSL PKey object
80
+ # doc.decrypt! key: OpenSSL::PKey.read('private-key')
81
+ #
82
+ def decrypt!(opts)
83
+ first_encrypted_node = root.at_xpath("//xenc:EncryptedData", "xenc" => "http://www.w3.org/2001/04/xmlenc#")
84
+ raise XMLSec::DecryptionError("start node not found") unless first_encrypted_node
81
85
 
82
- first_encrypted_node.decrypt_with opts
83
- self
86
+ first_encrypted_node.decrypt_with opts
87
+ self
88
+ end
89
+ end
84
90
  end
85
91
  end
86
92
 
87
- class Nokogiri::XML::Node
88
- def encrypt_with(key:, name: nil, **opts)
89
- raise ArgumentError("public :key is required for encryption") unless key
90
- encrypt_with_key(name, key, opts)
91
- end
93
+ module Nokogiri
94
+ module XML
95
+ class Node
96
+ def encrypt_with(key:, name: nil, **opts)
97
+ raise ArgumentError("public :key is required for encryption") unless key
98
+
99
+ encrypt_with_key(name, key, opts)
100
+ end
92
101
 
93
- def decrypt_with(opts)
94
- raise 'inadequate options specified for decryption' unless opts[:key]
102
+ def decrypt_with(opts)
103
+ raise "inadequate options specified for decryption" unless opts[:key]
95
104
 
96
- parent = self.parent
97
- previous = self.previous
98
- key = opts[:key]
99
- key = key.to_pem if key.respond_to?(:to_pem)
100
- decrypt_with_key(opts[:name].to_s, key)
101
- previous ? previous.next : parent.children.first
105
+ parent = self.parent
106
+ previous = self.previous
107
+ key = opts[:key]
108
+ key = key.to_pem if key.respond_to?(:to_pem)
109
+ decrypt_with_key(opts[:name].to_s, key)
110
+ previous ? previous.next : parent.children.first
111
+ end
112
+ end
102
113
  end
103
114
  end