nokogiri-xmlsec-me-harder 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +123 -0
- data/Rakefile +30 -0
- data/ext/nokogiri_ext_xmlsec/common.h +13 -0
- data/ext/nokogiri_ext_xmlsec/extconf.rb +27 -0
- data/ext/nokogiri_ext_xmlsec/init.c +76 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_decrypt_with_key.c +82 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_encrypt_with_key.c +169 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_helpers_set_attribute_id.c +76 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_init.c +32 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_sign_certificate.c +186 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_sign_rsa.c +167 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_certificates.c +138 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_named_keys.c +133 -0
- data/ext/nokogiri_ext_xmlsec/nokogiri_verify_signature_rsa.c +76 -0
- data/ext/nokogiri_ext_xmlsec/options.c +166 -0
- data/ext/nokogiri_ext_xmlsec/options.h +36 -0
- data/ext/nokogiri_ext_xmlsec/shutdown.c +12 -0
- data/ext/nokogiri_ext_xmlsec/util.c +139 -0
- data/ext/nokogiri_ext_xmlsec/util.h +42 -0
- data/ext/nokogiri_ext_xmlsec/xmlsecrb.h +44 -0
- data/lib/nokogiri-xmlsec.rb +1 -0
- data/lib/xmlsec.rb +104 -0
- data/lib/xmlsec/version.rb +3 -0
- data/nokogiri-xmlsec-me-harder.gemspec +39 -0
- data/spec/fixtures/cert/server.crt +14 -0
- data/spec/fixtures/cert/server.csr +11 -0
- data/spec/fixtures/cert/server.key.decrypted +15 -0
- data/spec/fixtures/cert/server.key.encrypted +18 -0
- data/spec/fixtures/hate.xml +7 -0
- data/spec/fixtures/pwned.xml +1 -0
- data/spec/fixtures/rsa.pem +15 -0
- data/spec/fixtures/rsa.pub +6 -0
- data/spec/fixtures/sign2-doc.xml +6 -0
- data/spec/fixtures/sign2-result.xml +25 -0
- data/spec/fixtures/sign3-result.xml +38 -0
- data/spec/lib/nokogiri/xml/document/encryption_and_decryption_spec.rb +34 -0
- data/spec/lib/nokogiri/xml/document/signing_and_verifying_spec.rb +123 -0
- data/spec/lib/nokogiri/xml/document/unsafe_xml_spec.rb +61 -0
- data/spec/spec_helper.rb +10 -0
- metadata +213 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
#ifndef NOKOGIRI_EXT_XMLSEC_OPTIONS_H
|
2
|
+
#define NOKOGIRI_EXT_XMLSEC_OPTIONS_H
|
3
|
+
|
4
|
+
#include "common.h"
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
#include <xmlsec/crypto.h>
|
8
|
+
|
9
|
+
typedef struct {
|
10
|
+
// From :block_encryption
|
11
|
+
xmlSecTransformId block_encryption;
|
12
|
+
const char* key_type;
|
13
|
+
int key_bits;
|
14
|
+
|
15
|
+
// From :key_transport
|
16
|
+
xmlSecTransformId key_transport;
|
17
|
+
} XmlEncOptions;
|
18
|
+
|
19
|
+
// Supported algorithms taken from #5.1 of
|
20
|
+
// http://www.w3.org/TR/xmlenc-core
|
21
|
+
//
|
22
|
+
// For options, only use the URL fragment (stuff post #)
|
23
|
+
// since that's unique enough and it removes a lot of typing.
|
24
|
+
BOOL GetXmlEncOptions(VALUE rb_opts, XmlEncOptions* options,
|
25
|
+
VALUE* rb_exception_result,
|
26
|
+
const char** exception_message);
|
27
|
+
|
28
|
+
// XML DSIG helpers.
|
29
|
+
xmlSecTransformId GetSignatureMethod(VALUE rb_method,
|
30
|
+
VALUE* rb_exception_result,
|
31
|
+
const char** exception_message);
|
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
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#include "xmlsecrb.h"
|
2
|
+
|
3
|
+
/* not actually called anywhere right now, but here for posterity */
|
4
|
+
void Shutdown_xmlsecrb() {
|
5
|
+
xmlSecCryptoShutdown();
|
6
|
+
xmlSecCryptoAppShutdown();
|
7
|
+
xmlSecShutdown();
|
8
|
+
xsltCleanupGlobals();
|
9
|
+
#ifndef XMLSEC_NO_XSLT
|
10
|
+
xsltCleanupGlobals();
|
11
|
+
#endif /* XMLSEC_NO_XSLT */
|
12
|
+
}
|
@@ -0,0 +1,139 @@
|
|
1
|
+
#include "util.h"
|
2
|
+
|
3
|
+
#include <xmlsec/errors.h>
|
4
|
+
|
5
|
+
xmlSecKeysMngrPtr createKeyManagerWithSingleKey(
|
6
|
+
char* keyStr,
|
7
|
+
unsigned int keyLength,
|
8
|
+
char *keyName,
|
9
|
+
VALUE* rb_exception_result_out,
|
10
|
+
const char** exception_message_out) {
|
11
|
+
VALUE rb_exception_result = Qnil;
|
12
|
+
const char* exception_message = NULL;
|
13
|
+
xmlSecKeysMngrPtr mngr = NULL;
|
14
|
+
xmlSecKeyPtr key = NULL;
|
15
|
+
|
16
|
+
/* create and initialize keys manager, we use a simple list based
|
17
|
+
* keys manager, implement your own xmlSecKeysStore klass if you need
|
18
|
+
* something more sophisticated
|
19
|
+
*/
|
20
|
+
mngr = xmlSecKeysMngrCreate();
|
21
|
+
if(mngr == NULL) {
|
22
|
+
rb_exception_result = rb_eDecryptionError;
|
23
|
+
exception_message = "failed to create keys manager.";
|
24
|
+
goto done;
|
25
|
+
}
|
26
|
+
if(xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
|
27
|
+
rb_exception_result = rb_eDecryptionError;
|
28
|
+
exception_message = "failed to initialize keys manager.";
|
29
|
+
goto done;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* load private RSA key */
|
33
|
+
key = xmlSecCryptoAppKeyLoadMemory((xmlSecByte *)keyStr,
|
34
|
+
keyLength,
|
35
|
+
xmlSecKeyDataFormatPem,
|
36
|
+
NULL, // the key file password
|
37
|
+
NULL, // the key password callback
|
38
|
+
NULL);// the user context for password callback
|
39
|
+
if(key == NULL) {
|
40
|
+
rb_exception_result = rb_eDecryptionError;
|
41
|
+
exception_message = "failed to load rsa key";
|
42
|
+
goto done;
|
43
|
+
}
|
44
|
+
|
45
|
+
if(xmlSecKeySetName(key, BAD_CAST keyName) < 0) {
|
46
|
+
rb_exception_result = rb_eDecryptionError;
|
47
|
+
exception_message = "failed to set key name";
|
48
|
+
goto done;
|
49
|
+
}
|
50
|
+
|
51
|
+
/* add key to keys manager, from now on keys manager is responsible
|
52
|
+
* for destroying key
|
53
|
+
*/
|
54
|
+
if(xmlSecCryptoAppDefaultKeysMngrAdoptKey(mngr, key) < 0) {
|
55
|
+
rb_exception_result = rb_eDecryptionError;
|
56
|
+
exception_message = "failed to add key to keys manager";
|
57
|
+
goto done;
|
58
|
+
}
|
59
|
+
|
60
|
+
done:
|
61
|
+
if(rb_exception_result != Qnil) {
|
62
|
+
if (key) {
|
63
|
+
xmlSecKeyDestroy(key);
|
64
|
+
}
|
65
|
+
|
66
|
+
if (mngr) {
|
67
|
+
xmlSecKeysMngrDestroy(mngr);
|
68
|
+
mngr = NULL;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
*rb_exception_result_out = rb_exception_result;
|
73
|
+
*exception_message_out = exception_message;
|
74
|
+
return mngr;
|
75
|
+
}
|
76
|
+
|
77
|
+
xmlSecDSigCtxPtr createDSigContext(xmlSecKeysMngrPtr keyManager) {
|
78
|
+
xmlSecDSigCtxPtr dsigCtx = xmlSecDSigCtxCreate(keyManager);
|
79
|
+
if (!dsigCtx) {
|
80
|
+
return NULL;
|
81
|
+
}
|
82
|
+
|
83
|
+
// Restrict ReferenceUris to same document or empty to avoid XXE attacks.
|
84
|
+
dsigCtx->enabledReferenceUris = xmlSecTransformUriTypeEmpty |
|
85
|
+
xmlSecTransformUriTypeSameDocument;
|
86
|
+
|
87
|
+
return dsigCtx;
|
88
|
+
}
|
89
|
+
|
90
|
+
#define ERROR_STACK_SIZE 4096
|
91
|
+
static char g_errorStack[ERROR_STACK_SIZE];
|
92
|
+
static size_t g_errorStackPos;
|
93
|
+
|
94
|
+
char* getXmlSecLastError() {
|
95
|
+
return g_errorStack;
|
96
|
+
}
|
97
|
+
|
98
|
+
int hasXmlSecLastError() {
|
99
|
+
return g_errorStack[0] != '\0';
|
100
|
+
}
|
101
|
+
|
102
|
+
void resetXmlSecError() {
|
103
|
+
g_errorStack[0] = '\0';
|
104
|
+
g_errorStackPos = 0;
|
105
|
+
}
|
106
|
+
|
107
|
+
void storeErrorCallback(const char *file,
|
108
|
+
int line,
|
109
|
+
const char *func,
|
110
|
+
const char *errorObject,
|
111
|
+
const char *errorSubject,
|
112
|
+
int reason,
|
113
|
+
const char *msg) {
|
114
|
+
int i = 0;
|
115
|
+
const char* error_msg = NULL;
|
116
|
+
int amt = 0;
|
117
|
+
if (g_errorStackPos >= ERROR_STACK_SIZE) {
|
118
|
+
// Just bail. Earlier errors are more interesting usually anyway.
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
|
122
|
+
for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) {
|
123
|
+
if(xmlSecErrorsGetCode(i) == reason) {
|
124
|
+
error_msg = xmlSecErrorsGetMsg(i);
|
125
|
+
break;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
amt = snprintf(
|
130
|
+
&g_errorStack[g_errorStackPos],
|
131
|
+
ERROR_STACK_SIZE - g_errorStackPos,
|
132
|
+
"func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n",
|
133
|
+
func, file, line, errorObject, errorSubject, reason,
|
134
|
+
error_msg ? error_msg : "", msg);
|
135
|
+
|
136
|
+
if (amt > 0) {
|
137
|
+
g_errorStackPos += amt;
|
138
|
+
}
|
139
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#ifndef NOKOGIRI_EXT_XMLSEC_UTIL_H
|
2
|
+
#define NOKOGIRI_EXT_XMLSEC_UTIL_H
|
3
|
+
|
4
|
+
#include "xmlsecrb.h"
|
5
|
+
|
6
|
+
// Constructs a xmlSecKeysMngr and adds the given named key to the manager.
|
7
|
+
//
|
8
|
+
// Caller takes ownership. Free with xmlSecKeysMngrDestroy().
|
9
|
+
xmlSecKeysMngrPtr createKeyManagerWithSingleKey(
|
10
|
+
char* keyStr,
|
11
|
+
unsigned int keyLength,
|
12
|
+
char *keyName,
|
13
|
+
VALUE* rb_exception_result_out,
|
14
|
+
const char** exception_message_out);
|
15
|
+
|
16
|
+
// Creates a xmlSecDSigCtx with defaults locked down to prevent XXE.
|
17
|
+
//
|
18
|
+
// Caller takes ownership of the context. Free with xmlSecDSigCtxDestroy().
|
19
|
+
xmlSecDSigCtxPtr createDSigContext(xmlSecKeysMngrPtr keyManager);
|
20
|
+
|
21
|
+
// Retrieves the recorded error strings from libxmlsec1. Ensure resetXmlSecError()
|
22
|
+
// is called at the start of the range of error collection.
|
23
|
+
char* getXmlSecLastError();
|
24
|
+
|
25
|
+
// Reset the recording of errors. After this getXmlSecLastError() will return
|
26
|
+
// an empty string. Call at the start of a logical interaction with libxmlsec.
|
27
|
+
void resetXmlSecError();
|
28
|
+
|
29
|
+
// Return false if there are no errors. If false, getXmlSecLastError() will
|
30
|
+
// return an empty string.
|
31
|
+
int hasXmlSecLastError();
|
32
|
+
|
33
|
+
// Error reporting hooks to redirect Xmlsec1 library errors away from stdout.
|
34
|
+
void storeErrorCallback(const char *file,
|
35
|
+
int line,
|
36
|
+
const char *func,
|
37
|
+
const char *errorObject,
|
38
|
+
const char *errorSubject,
|
39
|
+
int reason,
|
40
|
+
const char *msg);
|
41
|
+
|
42
|
+
#endif // NOKOGIRI_EXT_XMLSEC_UTIL_H
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#ifndef NOKOGIRI_EXT_XMLSEC_XMLSECRB_H
|
2
|
+
#define NOKOGIRI_EXT_XMLSEC_XMLSECRB_H
|
3
|
+
|
4
|
+
#include "common.h"
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#include <libxml/tree.h>
|
9
|
+
#include <libxml/xmlmemory.h>
|
10
|
+
#include <libxml/parser.h>
|
11
|
+
#include <libxml/xmlstring.h>
|
12
|
+
|
13
|
+
#include <libxslt/xslt.h>
|
14
|
+
|
15
|
+
#include <xmlsec/xmlsec.h>
|
16
|
+
#include <xmlsec/xmltree.h>
|
17
|
+
#include <xmlsec/xmldsig.h>
|
18
|
+
#include <xmlsec/xmlenc.h>
|
19
|
+
#include <xmlsec/templates.h>
|
20
|
+
#include <xmlsec/crypto.h>
|
21
|
+
|
22
|
+
// TODO(awong): Support non-gcc and non-clang compilers.
|
23
|
+
#define EXTENSION_EXPORT __attribute__((visibility("default")))
|
24
|
+
|
25
|
+
VALUE sign_with_key(VALUE self, VALUE rb_opts);
|
26
|
+
VALUE sign_with_certificate(VALUE self, VALUE rb_opts);
|
27
|
+
VALUE verify_signature_with_rsa_key(VALUE self, VALUE rb_rsa_key);
|
28
|
+
VALUE verify_signature_with_named_keys(VALUE self, VALUE rb_keys);
|
29
|
+
VALUE verify_signature_with_certificates(VALUE self, VALUE rb_certs);
|
30
|
+
VALUE encrypt_with_key(VALUE self, VALUE rb_rsa_key_name, VALUE rb_rsa_key,
|
31
|
+
VALUE rb_opts);
|
32
|
+
VALUE decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key);
|
33
|
+
VALUE set_id_attribute(VALUE self, VALUE rb_attr_name);
|
34
|
+
|
35
|
+
void Init_Nokogiri_ext(void);
|
36
|
+
|
37
|
+
extern VALUE rb_cNokogiri_XML_Document;
|
38
|
+
extern VALUE rb_eSigningError;
|
39
|
+
extern VALUE rb_eVerificationError;
|
40
|
+
extern VALUE rb_eKeystoreError;
|
41
|
+
extern VALUE rb_eEncryptionError;
|
42
|
+
extern VALUE rb_eDecryptionError;
|
43
|
+
|
44
|
+
#endif // NOKOGIRI_EXT_XMLSEC_XMLSECRB_H
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'xmlsec'
|
data/lib/xmlsec.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require "xmlsec/version"
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'nokogiri_ext_xmlsec'
|
4
|
+
|
5
|
+
class Nokogiri::XML::Document
|
6
|
+
# Signs this document, and then returns it.
|
7
|
+
#
|
8
|
+
# Examples:
|
9
|
+
#
|
10
|
+
# doc.sign! key: 'rsa-private-key'
|
11
|
+
# doc.sign! key: 'rsa-private-key', name: 'key-name'
|
12
|
+
# doc.sign! cert: 'x509 certificate', key: 'cert private key'
|
13
|
+
# doc.sign! cert: 'x509 certificate', key: 'cert private key',
|
14
|
+
# name: 'key-name'
|
15
|
+
def sign! opts
|
16
|
+
if opts.has_key? :cert
|
17
|
+
raise "need a private :key" unless opts[:key]
|
18
|
+
sign_with_certificate opts
|
19
|
+
elsif opts[:key]
|
20
|
+
sign_with_key opts
|
21
|
+
else
|
22
|
+
raise "No private :key was given"
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
# Verifies the signature on the current document.
|
28
|
+
#
|
29
|
+
# Returns `true` if the signature is valid, `false` otherwise.
|
30
|
+
#
|
31
|
+
# Examples:
|
32
|
+
#
|
33
|
+
# # Try to validate with the given public or private key
|
34
|
+
# doc.verify_with key: 'rsa-key'
|
35
|
+
#
|
36
|
+
# # Try to validate with a set of keys. It will try to match
|
37
|
+
# # based on the contents of the `KeyName` element.
|
38
|
+
# doc.verify_with({
|
39
|
+
# 'key-name' => 'x509 certificate',
|
40
|
+
# 'another-key-name' => 'rsa-public-key'
|
41
|
+
# })
|
42
|
+
#
|
43
|
+
# # Try to validate with a trusted certificate
|
44
|
+
# doc.verify_with(x509: 'certificate')
|
45
|
+
#
|
46
|
+
# # Try to validate with a set of certificates, any one of which
|
47
|
+
# # can match
|
48
|
+
# doc.verify_with(x509: ['cert1', 'cert2'])
|
49
|
+
#
|
50
|
+
# You can also use `:cert` or `:certificate` or `:certs` or
|
51
|
+
# `:certificates` as aliases for `:x509`.
|
52
|
+
#
|
53
|
+
def verify_with opts_or_keys
|
54
|
+
if (certs = opts_or_keys[:cert]) ||
|
55
|
+
(certs = opts_or_keys[:certs])
|
56
|
+
certs = [certs] unless certs.kind_of?(Array)
|
57
|
+
verify_with_certificates certs
|
58
|
+
elsif opts_or_keys[:key]
|
59
|
+
verify_with_rsa_key opts_or_keys[:key]
|
60
|
+
else
|
61
|
+
verify_with_named_keys opts_or_keys
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Attempts to verify the signature of this document using only certificates
|
66
|
+
# installed on the system. This is equivalent to calling
|
67
|
+
# `verify_with certificates: []` (that is, an empty array).
|
68
|
+
#
|
69
|
+
def verify_signature
|
70
|
+
verify_with_certificates []
|
71
|
+
end
|
72
|
+
|
73
|
+
# Encrypts the current document, then returns it.
|
74
|
+
#
|
75
|
+
# Examples:
|
76
|
+
#
|
77
|
+
# # encrypt with a public key and optional key name
|
78
|
+
# doc.encrypt! key: 'public-key', name: 'name'
|
79
|
+
#
|
80
|
+
def encrypt! opts
|
81
|
+
if opts[:key]
|
82
|
+
encrypt_with_key opts[:name].to_s, opts[:key], opts.select { |key, _| key != :key && key != :name }
|
83
|
+
else
|
84
|
+
raise "public :key is required for encryption"
|
85
|
+
end
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
# Decrypts the current document, then returns it.
|
90
|
+
#
|
91
|
+
# Examples:
|
92
|
+
#
|
93
|
+
# # decrypt with a specific private key
|
94
|
+
# doc.decrypt! key: 'private-key'
|
95
|
+
#
|
96
|
+
def decrypt! opts
|
97
|
+
if opts[:key]
|
98
|
+
decrypt_with_key opts[:name].to_s, opts[:key]
|
99
|
+
else
|
100
|
+
raise 'inadequate options specified for decryption'
|
101
|
+
end
|
102
|
+
self
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'xmlsec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "nokogiri-xmlsec-me-harder"
|
8
|
+
spec.version = Xmlsec::VERSION
|
9
|
+
spec.authors = ["Albert J. Wong"]
|
10
|
+
spec.email = ["awong.dev@gmail.com"]
|
11
|
+
spec.description = %q{Adds support to Ruby for encrypting, decrypting,
|
12
|
+
signing and validating the signatures of XML documents, according to the
|
13
|
+
[XML Encryption Syntax and Processing](http://www.w3.org/TR/xmlenc-core/)
|
14
|
+
standard, by wrapping around the [xmlsec](http://www.aleksey.com/xmlsec) C
|
15
|
+
library and adding relevant methods to `Nokogiri::XML::Document`.
|
16
|
+
Implementation is based off nokogiri-xmlsec by
|
17
|
+
"Colin MacKenzie IV" <inisterchipmunk@gmail.com> with heavy modifications
|
18
|
+
and some API changes.}
|
19
|
+
spec.summary = %q{Wrapper around http://www.aleksey.com/xmlsec to
|
20
|
+
support XML encryption, decryption, signing and signature validation in
|
21
|
+
Ruby}
|
22
|
+
spec.homepage = "https://github.com/omb-awong/xmlsec"
|
23
|
+
spec.license = "MIT"
|
24
|
+
|
25
|
+
spec.files = `git ls-files`.split($/)
|
26
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
27
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
spec.extensions = %w{ext/nokogiri_ext_xmlsec/extconf.rb}
|
30
|
+
|
31
|
+
spec.add_dependency 'nokogiri'
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
34
|
+
spec.add_development_dependency "rake"
|
35
|
+
spec.add_development_dependency "rake-compiler"
|
36
|
+
spec.add_development_dependency "rspec"
|
37
|
+
spec.add_development_dependency "guard-rspec"
|
38
|
+
spec.add_development_dependency "guard-rake"
|
39
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICLzCCAZgCCQCVuhhQ38rw0TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJV
|
3
|
+
UzEQMA4GA1UECAwHR2VvcmdpYTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
|
4
|
+
dHkgTHRkMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTAgFw0xMzA1MjUxODQwMDRa
|
5
|
+
GA8zMDEyMDkyNTE4NDAwNFowWzELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0dlb3Jn
|
6
|
+
aWExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEXMBUGA1UEAwwO
|
7
|
+
d3d3Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALE4oSql
|
8
|
+
eymfHtzOeY86WyvfsjZmaz2XnIo9dzZsK71yMEKkgvXQnnYy9pK0NaYcG0B0hcii
|
9
|
+
3fqGBiHMkZY2BOGWwCC/wOmJCzLq9q6caPWUs71Zko+h59LaqV93vzDmZaXYfFoQ
|
10
|
+
gSVEWpEpCSo560x0mSuLnJYdQQzZ/L6xvxZ1AgMBAAEwDQYJKoZIhvcNAQEFBQAD
|
11
|
+
gYEATyK/RlfpohUVimgFkycTF2hyusjctseXoZDCctgg/STMsL8iA0P9YB6k91GC
|
12
|
+
kWpwevuiwarD1MfSUV6goPINFkIBvfK+5R9lpHaTqqs615z8T9R5VJgaLcFe3tWd
|
13
|
+
7oq3V2q5Nl6MrZfXj2N07qe6/9zfdauxYO26vAEKCvIkbMo=
|
14
|
+
-----END CERTIFICATE-----
|