metafusion-crypto 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/metafusion/crypto.rb +10 -0
- data/lib/metafusion/crypto/base.rb +132 -0
- data/lib/metafusion/crypto/meta.rb +57 -0
- data/lib/metafusion/crypto/version.rb +19 -0
- data/spec/metafusion/crypto/base_spec.rb +113 -0
- data/spec/metafusion/crypto/meta_spec.rb +90 -0
- data/spec/metafusion/crypto/version_spec.rb +19 -0
- metadata +53 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
# Cryptography helper module <tt>Metafusion::Crypto</tt> as well as
|
2
|
+
# <tt>Metafusion::Crypto::PrivateKey</tt> and
|
3
|
+
# <tt>Metafusion::Crypto::DigitalSignature</tt> classes.
|
4
|
+
|
5
|
+
require 'openssl'
|
6
|
+
require 'digest/sha1'
|
7
|
+
|
8
|
+
# Module that contains Cryptography helper methods and the
|
9
|
+
# <tt>Metafusion::Crypto::Key</tt> class to be utilized in
|
10
|
+
# public key encryption.
|
11
|
+
module Metafusion::Crypto
|
12
|
+
|
13
|
+
# Generate private and public keys
|
14
|
+
# 1. <tt>private_file</tt> - file name of private key to generate (default = "rsa_key")
|
15
|
+
# 2. <tt>public_file</tt> - file name of public key to generate (default = "#{private_key}.pub")
|
16
|
+
# 3. <tt>bits</tt> - number of bits for key (default = 1024)
|
17
|
+
# 4. <tt>clean</tt> - specifies if existing key files should
|
18
|
+
# zapped and replaced by newly generated keys (default = true)
|
19
|
+
#
|
20
|
+
# Returns the private key generated.
|
21
|
+
#
|
22
|
+
# Usage:
|
23
|
+
# priv_key = Metafusion::Crypto.generate_key_pair
|
24
|
+
def self.generate_key_pair(private_file = "rsa_key",
|
25
|
+
public_file = "#{private_file}.pub",
|
26
|
+
bits = 512, clean = true)
|
27
|
+
if clean
|
28
|
+
File.delete(private_file) if File.exists?(private_file)
|
29
|
+
File.delete(public_file) if File.exists?(public_file)
|
30
|
+
end
|
31
|
+
private_key = OpenSSL::PKey::RSA.new(bits)
|
32
|
+
File.open(private_file, "w+") do |fp|
|
33
|
+
fp << private_key.to_s
|
34
|
+
end
|
35
|
+
File.open(public_file, "w+") do |fp|
|
36
|
+
fp << private_key.public_key.to_s
|
37
|
+
end
|
38
|
+
private_key
|
39
|
+
end
|
40
|
+
|
41
|
+
# <tt>Metafusion::Crypto::DigitalSignature</tt> provides easier
|
42
|
+
# a more streamlined API to create digital signatures without
|
43
|
+
# needing to know what that entails.
|
44
|
+
#
|
45
|
+
# Usage:
|
46
|
+
# include Metafusion::Crypto
|
47
|
+
# sig = DigitalSignature.from_file('rsa_key.pub', 'rsa_key')
|
48
|
+
# original_text = "my clear text message"
|
49
|
+
# crypted_text = sig.encrypt(original_text)
|
50
|
+
# plain_text = sig.decrypt(crypted_text)
|
51
|
+
# puts "It worked - let's celebrate!" if original_text == plain_text
|
52
|
+
class DigitalSignature
|
53
|
+
# Class methods
|
54
|
+
class << self
|
55
|
+
# Loads and constructs key from file <tt>private_filename</tt> given.
|
56
|
+
def from_keys(public_filename = "rsa_key.pub",
|
57
|
+
private_filename = nil)
|
58
|
+
return self.new(File.read(public_filename)) unless private_filename
|
59
|
+
self.new(File.read(public_filename), File.read(private_filename))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Constructor that takes the private and public key data.
|
64
|
+
# Only the <tt>public_data</tt> is required since not all
|
65
|
+
# <tt>DigitalSignature</tt> class clients will have access
|
66
|
+
# to the private key.
|
67
|
+
def initialize(public_data, private_data = nil)
|
68
|
+
@private_key = OpenSSL::PKey::RSA.new(private_data) if private_data
|
69
|
+
@public_key = OpenSSL::PKey::RSA.new(public_data)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Encrypts given <tt>text</tt> using key instance. This assumes
|
73
|
+
# that private key data was provided at instantiation step.
|
74
|
+
def encrypt(text)
|
75
|
+
Base64.encode64(@private_key.send("private_encrypt", text)) if @private_key
|
76
|
+
end
|
77
|
+
|
78
|
+
# Decrypts given <tt>text</tt> using key instance.
|
79
|
+
def decrypt(text)
|
80
|
+
@public_key.send("public_decrypt", Base64.decode64(text))
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
attr_accessor :private_key, :public_key
|
85
|
+
end
|
86
|
+
|
87
|
+
# <tt>Metafusion::Crypto::PrivateKey</tt> provides class that wraps
|
88
|
+
# the boilerplate private key encryption API from the Ruby
|
89
|
+
# standard library OpenSSL implementation.
|
90
|
+
#
|
91
|
+
# Usage:
|
92
|
+
# include Metafusion::Crypto
|
93
|
+
# pkey = PrivateKey.new('mypassphrase')
|
94
|
+
# original_text = 'Yo yo yo. What up dog?'
|
95
|
+
# crypted_text = pkey.encrypt(original_text)
|
96
|
+
# plain_text = pkey.decrypt(crypted_text)
|
97
|
+
# puts "Let's roll and celebrate - it worked" if original_text == plain_text
|
98
|
+
class PrivateKey
|
99
|
+
# Class methods
|
100
|
+
class << self
|
101
|
+
# Read in private key from file
|
102
|
+
def from_file(key_file = 'rsa_key')
|
103
|
+
return self.new(File.read(key_file))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Creates <tt>PrivateKey</tt> instance given
|
108
|
+
# <tt>raw_passphrase</tt> and <tt>cipher</tt>.
|
109
|
+
# The default cipher is AES-256-CBC.
|
110
|
+
def initialize(raw_passphrase, cipher = "aes-256-cbc")
|
111
|
+
@encrypt_cipher = OpenSSL::Cipher::Cipher.new(cipher)
|
112
|
+
@decrypt_cipher = OpenSSL::Cipher::Cipher.new(cipher)
|
113
|
+
@key = Digest::SHA1.hexdigest(raw_passphrase)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Encrypts given <tt>text</tt> using key instance
|
117
|
+
def encrypt(text)
|
118
|
+
@encrypt_cipher.encrypt(@key)
|
119
|
+
s = @encrypt_cipher.update(text)
|
120
|
+
s << @encrypt_cipher.final
|
121
|
+
Base64.encode64(s)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Decrypts given <tt>text</tt> using key instance
|
125
|
+
def decrypt(text)
|
126
|
+
@decrypt_cipher.decrypt(@key)
|
127
|
+
s = @decrypt_cipher.update(Base64.decode64(text))
|
128
|
+
s << @decrypt_cipher.final
|
129
|
+
s
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# meta.rb contains <tt>Metafusion::Crypto::Meta</tt> and related classes that
|
2
|
+
# help define the metadata of the <tt>Metafusion::Crypto4R</tt> project.
|
3
|
+
|
4
|
+
require('rubygems')
|
5
|
+
require('erb')
|
6
|
+
|
7
|
+
class Metafusion::Crypto::Meta #:nodoc:
|
8
|
+
attr_accessor :root_dir
|
9
|
+
attr_reader :gem_spec, :project_files, :spec_files
|
10
|
+
|
11
|
+
# Initializer for Metafusion::Crypto::Meta class. Takes <tt>root_dir</tt> as parameter.
|
12
|
+
def initialize(root_dir)
|
13
|
+
@root_dir = root_dir
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns package information defined in <tt>root_dir</tt>/pkg-info.yml
|
17
|
+
def pkg_info
|
18
|
+
yaml_file = File.join(@root_dir, 'pkg-info.yml')
|
19
|
+
ryaml = ERB.new(File.read(yaml_file), 0)
|
20
|
+
s = ryaml.result(binding)
|
21
|
+
YAML.load(s)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns RubyGems spec information
|
25
|
+
def spec_info
|
26
|
+
self.pkg_info['spec'] if self.pkg_info
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns list of project files
|
30
|
+
def project_files
|
31
|
+
@project_files ||= Dir.glob(File.join(@root_dir, 'lib/**/*.rb'))
|
32
|
+
@project_files
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns list of specification files
|
36
|
+
def spec_files
|
37
|
+
@spec_files ||= Dir.glob(File.join(@root_dir, 'spec/**/*_spec.rb'))
|
38
|
+
@spec_files
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns RubyGem specification for Metafusion::Crypto project
|
42
|
+
def gem_spec
|
43
|
+
@gem_spec ||= Gem::Specification.new do |spec|
|
44
|
+
self.spec_info.each do |key, val|
|
45
|
+
# if val.is_a?(Hash)
|
46
|
+
# puts val.inspect
|
47
|
+
# val.each do |k, v|
|
48
|
+
# spec.send(key, k, v)
|
49
|
+
# end
|
50
|
+
# else
|
51
|
+
spec.send("#{key}=", val)
|
52
|
+
# end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@gem_spec
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# version.rb contains <tt>Metafusion::Crypto::Version</tt> that provides helper
|
2
|
+
# methods related to versioning of the <tt>Metafusion::Crypto4R</tt> project.
|
3
|
+
|
4
|
+
module Metafusion::Crypto::Version #:nodoc:
|
5
|
+
MAJOR = 0
|
6
|
+
MINOR = 1
|
7
|
+
REVISION = 0
|
8
|
+
class << self
|
9
|
+
# Returns X.Y.Z formatted version string
|
10
|
+
def to_version
|
11
|
+
"#{MAJOR}.#{MINOR}.#{REVISION}"
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns X-Y-Z formatted version name
|
15
|
+
def to_name
|
16
|
+
"#{MAJOR}_#{MINOR}_#{REVISION}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
2
|
+
|
3
|
+
PRIVATE_KEY = 'rsa_key'
|
4
|
+
PUBLIC_KEY = 'rsa_key.pub'
|
5
|
+
|
6
|
+
def remove_rsa_keys(priv = PRIVATE_KEY, pub = PUBLIC_KEY)
|
7
|
+
File.delete(priv) if File.exists?(priv)
|
8
|
+
File.delete(pub) if File.exists?(pub)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Metafusion::Crypto, ".generate_key_pair" do
|
12
|
+
before(:each) do
|
13
|
+
remove_rsa_keys
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should create a private and public RSA key pair" do
|
17
|
+
Metafusion::Crypto.generate_key_pair
|
18
|
+
File.exists?(PRIVATE_KEY).should be_true
|
19
|
+
File.exists?(PUBLIC_KEY).should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
after(:each) do
|
23
|
+
remove_rsa_keys
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe Metafusion::Crypto::DigitalSignature do
|
28
|
+
before(:each) do
|
29
|
+
# ensure the keys are generated
|
30
|
+
Metafusion::Crypto.generate_key_pair
|
31
|
+
@private_key = "private key"
|
32
|
+
@public_key = "public key"
|
33
|
+
File.stub!(:read).and_return(@public_key, @private_key)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create instance from from_keys class method" do
|
37
|
+
Metafusion::Crypto::DigitalSignature.should_receive(:new).with(@public_key,@private_key)
|
38
|
+
Metafusion::Crypto::DigitalSignature.from_keys(PUBLIC_KEY, PRIVATE_KEY)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should create instance from from_keys class method using private key data when only public key provided" do
|
42
|
+
Metafusion::Crypto::DigitalSignature.should_receive(:new).with(@public_key)
|
43
|
+
Metafusion::Crypto::DigitalSignature.from_keys(PUBLIC_KEY)
|
44
|
+
end
|
45
|
+
|
46
|
+
after(:each) do
|
47
|
+
remove_rsa_keys
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Metafusion::Crypto::DigitalSignature do
|
52
|
+
before(:each) do
|
53
|
+
@original_text = "Charlotte Bronte rules"
|
54
|
+
Metafusion::Crypto.generate_key_pair
|
55
|
+
@digital_signature = Metafusion::Crypto::DigitalSignature.from_keys('rsa_key.pub', 'rsa_key')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should encrypt/decrypt round-trip back to original text" do
|
59
|
+
crypted_text = @digital_signature.encrypt(@original_text)
|
60
|
+
decrypted_text = @digital_signature.decrypt(crypted_text)
|
61
|
+
decrypted_text.should eql(@original_text)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should encrypt original text to a 90 character base64 string" do
|
65
|
+
crypted_text = @digital_signature.encrypt(@original_text)
|
66
|
+
crypted_text.size.should be(90)
|
67
|
+
end
|
68
|
+
|
69
|
+
after(:each) do
|
70
|
+
remove_rsa_keys
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe Metafusion::Crypto::PrivateKey do
|
75
|
+
before(:each) do
|
76
|
+
@original_text = "Was Jane Eyre the ultimate feminist?"
|
77
|
+
@private_key = Metafusion::Crypto::PrivateKey.new("currerbell1847")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should encrypt/decrypt round-trip back to original text" do
|
81
|
+
crypted_text = @private_key.encrypt(@original_text)
|
82
|
+
decrypted_text = @private_key.decrypt(crypted_text)
|
83
|
+
decrypted_text.should eql(@original_text)
|
84
|
+
end
|
85
|
+
|
86
|
+
after(:each) do
|
87
|
+
remove_rsa_keys
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe Metafusion::Crypto::PrivateKey, ".from_file" do
|
92
|
+
before(:each) do
|
93
|
+
@file_name = "key_file"
|
94
|
+
@key_content = "the key goes here"
|
95
|
+
File.stub!(:read).and_return(@key_content)
|
96
|
+
@pkey = mock(Metafusion::Crypto::PrivateKey)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should create new instance of PrivateKey with contents of key file supplied" do
|
100
|
+
Metafusion::Crypto::PrivateKey.should_receive(:new).with(@key_content).and_return(@pkey)
|
101
|
+
Metafusion::Crypto::PrivateKey.from_file(@file_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should read contents of file given" do
|
105
|
+
File.should_receive(:read).with(@file_name).and_return("")
|
106
|
+
Metafusion::Crypto::PrivateKey.from_file(@file_name)
|
107
|
+
end
|
108
|
+
|
109
|
+
after(:each) do
|
110
|
+
@pkey = nil
|
111
|
+
@file_name = nil
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
2
|
+
|
3
|
+
def glob_files(*path_elements)
|
4
|
+
Dir.glob(File.join(*path_elements))
|
5
|
+
end
|
6
|
+
|
7
|
+
def load_erb_yaml(path, context)
|
8
|
+
ryaml = ERB.new(File.read(path), 0)
|
9
|
+
YAML.load(ryaml.result(context))
|
10
|
+
end
|
11
|
+
|
12
|
+
module ERBMetaMixin
|
13
|
+
# Needed to make the YAML load work...
|
14
|
+
def project_files
|
15
|
+
glob_files(@root_dir, 'lib', '**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
# Needed to make the YAML load work...
|
19
|
+
def spec_files
|
20
|
+
glob_files(@root_dir, 'spec', '**/*_spec.rb')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "Metafusion::Crypto::Meta cache policy" do
|
25
|
+
include ERBMetaMixin
|
26
|
+
before(:each) do
|
27
|
+
@root_dir = project_root_dir
|
28
|
+
@meta = Metafusion::Crypto::Meta.new(@root_dir)
|
29
|
+
@expected_pkg_info = load_erb_yaml(File.join(@root_dir, 'pkg-info.yml'), binding)
|
30
|
+
@expected_project_files = project_files
|
31
|
+
@expected_spec_files = spec_files
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should store value returned from project_files in @project_files after first glob" do
|
35
|
+
@meta.instance_eval("@project_files").should eql(nil)
|
36
|
+
@meta.project_files
|
37
|
+
@meta.instance_eval("@project_files").should eql(@expected_project_files)
|
38
|
+
@meta.project_files
|
39
|
+
@meta.instance_eval("@project_files").should eql(@expected_project_files)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should store value returned from spec_files in @spec_files after first glob" do
|
43
|
+
@meta.instance_eval("@spec_files").should eql(nil)
|
44
|
+
@meta.spec_files
|
45
|
+
@meta.instance_eval("@spec_files").should eql(@expected_spec_files)
|
46
|
+
@meta.spec_files
|
47
|
+
@meta.instance_eval("@spec_files").should eql(@expected_spec_files)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "Metafusion::Crypto::Meta" do
|
52
|
+
include ERBMetaMixin
|
53
|
+
before(:each) do
|
54
|
+
@root_dir = project_root_dir
|
55
|
+
@meta = Metafusion::Crypto::Meta.new(@root_dir)
|
56
|
+
@expected_yaml_hash = load_erb_yaml(File.join(@root_dir, 'pkg-info.yml'), binding)
|
57
|
+
@expected_project_files = project_files
|
58
|
+
@expected_spec_files = spec_files
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should load and return YAML file into Hash object upon #pkg_info call" do
|
62
|
+
yaml_hash = @meta.pkg_info
|
63
|
+
yaml_hash.should.eql? @expected_yaml_hash
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should return the embedded hash responding to key 'spec' of #pkg_info call upon #spec_info call" do
|
67
|
+
yaml_hash = @meta.spec_info
|
68
|
+
yaml_hash.should.eql? @expected_yaml_hash['spec']
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return list of files matching ROOT_DIR/lib/**/*.rb upon #project_files call" do
|
72
|
+
project_files = @meta.project_files
|
73
|
+
project_files.should.eql? @expected_project_files
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return list of files matching ROOT_DIR/spec/**/*.rb upon #spec_files call" do
|
77
|
+
spec_files = @meta.spec_files
|
78
|
+
spec_files.should.eql? @expected_spec_files
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return Gem specification based on YAML file contents and #project_files and #spec_files return values" do
|
82
|
+
spec = @meta.gem_spec
|
83
|
+
expected_spec_hash = @expected_yaml_hash['spec']
|
84
|
+
expected_spec_hash.each do |key, val|
|
85
|
+
unless val.is_a?(Hash)
|
86
|
+
spec.send(key).to_s.should eql(expected_spec_hash[key].to_s)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
2
|
+
|
3
|
+
VERSION_LIST = [Metafusion::Crypto::Version::MAJOR, Metafusion::Crypto::Version::MINOR, Metafusion::Crypto::Version::REVISION]
|
4
|
+
|
5
|
+
EXPECTED_VERSION = VERSION_LIST.join('.')
|
6
|
+
EXPECTED_NAME = VERSION_LIST.join('_')
|
7
|
+
|
8
|
+
describe Metafusion::Crypto::Version, ".to_version" do
|
9
|
+
it "should return #{EXPECTED_VERSION}" do
|
10
|
+
Metafusion::Crypto::Version.to_version.should eql(EXPECTED_VERSION)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Metafusion::Crypto::Version, ".to_name" do
|
15
|
+
it "should return #{EXPECTED_NAME}" do
|
16
|
+
Metafusion::Crypto::Version.to_name.should eql(EXPECTED_NAME)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: metafusion-crypto
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-09-30 00:00:00 -05:00
|
8
|
+
summary: Provides private key and digital signature encryption mechanisms for application developers that do not want to worry about the details.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: metafusion@googlegroups.com
|
12
|
+
homepage: http://metafusion.rubyforge.org
|
13
|
+
rubyforge_project: metafusion
|
14
|
+
description:
|
15
|
+
autorequire: metafusion/crypto
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.2
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Susan Potter
|
31
|
+
files:
|
32
|
+
- lib/metafusion/crypto.rb
|
33
|
+
- lib/metafusion/crypto/base.rb
|
34
|
+
- lib/metafusion/crypto/version.rb
|
35
|
+
- lib/metafusion/crypto/meta.rb
|
36
|
+
- spec/metafusion/crypto/base_spec.rb
|
37
|
+
- spec/metafusion/crypto/version_spec.rb
|
38
|
+
- spec/metafusion/crypto/meta_spec.rb
|
39
|
+
test_files: []
|
40
|
+
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
executables: []
|
46
|
+
|
47
|
+
extensions: []
|
48
|
+
|
49
|
+
requirements:
|
50
|
+
- Ruby 1.8.4+
|
51
|
+
- jcode (for unicode support)
|
52
|
+
dependencies: []
|
53
|
+
|