nm_datafile 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -5
- data/changelog.md +9 -11
- data/lib/nm_datafile.rb +5 -16
- data/lib/nm_datafile/blowfish.rb +22 -0
- data/lib/nm_datafile/crypto.rb +12 -11
- data/lib/nm_datafile/data_loading.rb +13 -11
- data/lib/nm_datafile/debug.rb +5 -3
- data/lib/nm_datafile/file_encoding.rb +3 -20
- data/lib/nm_datafile/nm_datafile.rb +11 -6
- data/lib/nm_datafile/schema.rb +11 -11
- data/lib/nm_datafile/version.rb +1 -1
- data/spec/data/nmd_binary_string_w_2s_2li_2a_1ubws_1ep.zip +0 -0
- data/spec/nm_datafile_spec.rb +66 -8
- metadata +3 -3
- data/lib/nm_datafile/b_f.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f642327532de8791b0c770ac2b7913cda8ebc20
|
4
|
+
data.tar.gz: 9d4cbcce8067f1dade4d236ef32c28ac95e1170b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11f77b2b9617260f53c8aff8598ad150f825e3b9797ff68b2d1f077e0e9bd0f582a96b8793fb9ac11ca111828008de7b530a563096cc85e27dff85afa316a6c0
|
7
|
+
data.tar.gz: 8f6772c1df00df26f5daa60373012d894298eb2eba438071fed08bdd6b066565e25dddb4d850783cfb3be1d4ccaa5e0a4dc915d72bcbb5dac05ea3ae0a98a580
|
data/README.md
CHANGED
@@ -35,8 +35,7 @@ Or install it yourself as:
|
|
35
35
|
|
36
36
|
## Usage
|
37
37
|
|
38
|
-
First define a file Schema.
|
39
|
-
For instance, if you wanted a file type called 'shippable_file' and you wanted it to have many records of 'sales', 'line_items', etc,
|
38
|
+
First define a file Schema. For instance, if you wanted a file type called 'shippable_file' and you wanted it to have many records of 'sales', 'line_items', etc,
|
40
39
|
and you wanted your file to have a string of data named 'ready_for_shipment_batch', then you would define it like so.
|
41
40
|
|
42
41
|
$nm_datafile_schemas = {
|
@@ -48,11 +47,48 @@ and you wanted your file to have a string of data named 'ready_for_shipment_batc
|
|
48
47
|
}
|
49
48
|
}
|
50
49
|
|
51
|
-
|
50
|
+
First define a schema for your NmDatafile. For instance, if you wanted a file called 'data_file' and you just wanted a "strings" attribute where you can store an array of encrypted strings, then you could set the below schema.
|
52
51
|
|
53
|
-
|
52
|
+
NmDatafile::SCHEMA = {
|
53
|
+
schemas: {
|
54
|
+
:data_file => {
|
55
|
+
data_collections: [:strings], # name the data that is input into the NMDatafile as an array
|
56
|
+
data_objects: [:file_owners_name]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
54
60
|
|
55
|
-
|
61
|
+
That's actually the default schema, so you don't need to set it, it's located in lib/nm_datafile/schema.rb, fyi :)
|
62
|
+
|
63
|
+
Now that you've got a schema set up, you can start using your data and easily serialize data into an encrypted file format.
|
64
|
+
|
65
|
+
nmd = NmDatafile.new(:data_file)
|
66
|
+
nmd.strings #=> []
|
67
|
+
nmd.strings << "hi"
|
68
|
+
nmd.file_owners_name = "dsj"
|
69
|
+
nmd.save_to_string # This is a binary string for programmers, you can write it to a file
|
70
|
+
nmd.save_to_file('/tmp/file.zip') # this saves your strings to a file
|
71
|
+
|
72
|
+
Ok, you've done all that, but your data is visible as that it's a zip file. So to turn sneaky mode on, you'll want to
|
73
|
+
|
74
|
+
NmDatafile.Load('/tmp/secret_file')
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
# Testing Note
|
79
|
+
|
80
|
+
Some cyphers are hardcoded in the tests... so if you make changes to the crypto algo, your tests will fail until you fix this...
|
81
|
+
|
82
|
+
|
83
|
+
# TODO
|
84
|
+
|
85
|
+
* Finish algo so it uses front door keys... encryption needs to be encrypted with the front door key
|
86
|
+
* Make it so the rails app sets up the schema file the proper way
|
87
|
+
* Specify encryption type in file schema? (symmetric vs asymmetric)
|
88
|
+
* Allow exporting data as a stenographic cat.jpg file.
|
89
|
+
* Better API for adding a new schema, and better default
|
90
|
+
* Bring in tests
|
91
|
+
* Allow PGP to be used to encrypt the file
|
56
92
|
|
57
93
|
|
58
94
|
## Contributing
|
data/changelog.md
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
### TODO:
|
2
2
|
|
3
3
|
* Fix the way there's an nm_datafile class... :(
|
4
|
-
* Define the
|
4
|
+
* Define the methods as static methods to make more clear where everything is
|
5
5
|
|
6
|
+
|
7
|
+
### 0.1.0
|
8
|
+
|
9
|
+
* Changed the syntax to accept a symmetric_key
|
10
|
+
* Fixed bug where fast_decrypt_string_with_pass doesn't implement any kind of password for encryption/ decryption...
|
11
|
+
* Fixed bug in the BF module by replacing it with better code
|
6
12
|
* Handle $FrontDoorKey
|
7
|
-
|
8
|
-
|
9
|
-
- it should also raise an exception if that instance variable isn't set
|
10
|
-
- Crypto::clean_decrypt_string is only used from within the gem!
|
11
|
-
- data_loading.rb
|
12
|
-
- nm_datafile.rb
|
13
|
-
|
14
|
-
- It's hard to tell what's an instance method and what's a class method
|
15
|
-
with all the mixin usage...
|
16
|
-
|
13
|
+
|
14
|
+
|
17
15
|
|
18
16
|
### 0.0.2
|
19
17
|
|
data/lib/nm_datafile.rb
CHANGED
@@ -2,35 +2,24 @@ require 'json'
|
|
2
2
|
require 'yaml'
|
3
3
|
require 'zip'
|
4
4
|
|
5
|
-
# require 'factory_girl'
|
6
|
-
# require 'pry'; binding.pry
|
7
|
-
# require File.expand_path('../../spec/factories/sales.rb', __FILE__)
|
8
|
-
|
9
5
|
require 'nm_datafile/version'
|
10
6
|
require 'nm_datafile/schema'
|
11
|
-
require 'nm_datafile/
|
7
|
+
require 'nm_datafile/blowfish'
|
12
8
|
require 'nm_datafile/data_loading'
|
13
9
|
require 'nm_datafile/crypto'
|
14
10
|
require 'nm_datafile/nm_datafile'
|
15
11
|
|
16
12
|
|
17
|
-
|
18
13
|
module NmDatafile
|
19
|
-
FRONT_DOOR_KEY = "$FrontDoorKey" # Write to NmDatafile::FRONT_DOOR_KEY to set a symetric key
|
20
|
-
@@symmetric_key = "$FrontDoorKey"
|
21
|
-
|
22
14
|
extend DataLoading
|
23
15
|
extend Crypto
|
16
|
+
extend FileEncoding
|
24
17
|
|
25
|
-
|
26
|
-
|
18
|
+
#config = {file_type: file_type, symmetric_key: symmetric_key}
|
19
|
+
def self.new(config, *args)
|
20
|
+
NmDatafile.new(config, *args)
|
27
21
|
end
|
28
22
|
|
29
|
-
def self.set_symmetric_key(val)
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
23
|
end
|
35
24
|
|
36
25
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# http://philtoland.com/post/807114394/simple-blowfish-encryption-with-ruby#notes
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
|
5
|
+
module NmDatafile
|
6
|
+
|
7
|
+
module Blowfish
|
8
|
+
def self.cipher(mode, key, data)
|
9
|
+
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(mode)
|
10
|
+
cipher.key = Digest::SHA256.digest(key)
|
11
|
+
cipher.update(data) << cipher.final
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.encrypt(key, data)
|
15
|
+
cipher(:encrypt, key, data)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.decrypt(key, text)
|
19
|
+
cipher(:decrypt, key, text)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/nm_datafile/crypto.rb
CHANGED
@@ -22,10 +22,9 @@ module NmDatafile
|
|
22
22
|
|
23
23
|
# TODu: rename to decode_string_as_password_protected
|
24
24
|
def decode_string_as_password_protected(password, decryptable_portion)
|
25
|
-
|
26
|
-
bf = BF.new(password, true)
|
25
|
+
clear_text = Blowfish.decrypt(password, decryptable_portion)
|
27
26
|
|
28
|
-
|
27
|
+
clear_text
|
29
28
|
end
|
30
29
|
|
31
30
|
|
@@ -78,17 +77,17 @@ module NmDatafile
|
|
78
77
|
|
79
78
|
# This method needs to be available on the
|
80
79
|
# NmDatafile module
|
81
|
-
def clean_decrypt_string(string)
|
82
|
-
|
83
|
-
# decode_password_protected_string(@@unsecure_pass, string)
|
84
|
-
unsecure_pass = ::NmDatafile::FRONT_DOOR_KEY
|
85
|
-
fast_decrypt_string_with_pass(unsecure_pass, string)
|
80
|
+
def clean_decrypt_string(string, symmetric_key)
|
81
|
+
fast_decrypt_string_with_pass(symmetric_key, string)
|
86
82
|
end
|
87
83
|
|
88
|
-
|
84
|
+
def clean_encrypt_string(string, symmetric_key)
|
85
|
+
fast_encrypt_string_with_pass(symmetric_key, string)
|
86
|
+
end
|
89
87
|
|
90
88
|
def fast_encrypt_string_with_pass(pass, string)
|
91
|
-
|
89
|
+
passworded_string = encode_string_as_password_protected(string, pass)
|
90
|
+
encoded_as_base64 = Base64.encode64(passworded_string)
|
92
91
|
rearranged = rearrangement(encoded_as_base64)
|
93
92
|
obfs = obfuscated_ending(rearranged)
|
94
93
|
Base64.encode64(obfs)
|
@@ -98,9 +97,11 @@ module NmDatafile
|
|
98
97
|
obfs = Base64.decode64(string)
|
99
98
|
rearranged = obfuscated_ending_undo(obfs)
|
100
99
|
encoded_as_base64 = rearrangement_undo(rearranged)
|
101
|
-
Base64.decode64(encoded_as_base64)
|
100
|
+
passworded_string = Base64.decode64(encoded_as_base64)
|
101
|
+
clear_text_string = decode_password_protected_string(pass, passworded_string)
|
102
102
|
end
|
103
103
|
|
104
|
+
|
104
105
|
def rearrangement(s)
|
105
106
|
s = the_last_three_chars(s) + the_string_minus_the_last_three_chars(s)
|
106
107
|
end
|
@@ -4,17 +4,20 @@ module NmDatafile
|
|
4
4
|
|
5
5
|
# (m) Load: loads a file into memory as an NmDatafile
|
6
6
|
# TODO: Make lowercase
|
7
|
-
def Load(file_path)
|
7
|
+
def Load(file_path, symmetric_key)
|
8
8
|
zip_data = File.read(file_path)
|
9
|
-
|
9
|
+
load_binary_data(zip_data, symmetric_key)
|
10
10
|
end
|
11
11
|
|
12
12
|
# TODO: Make lowercase
|
13
|
-
def
|
14
|
-
hash = extract_entities_from_binary_data(binary_data)
|
13
|
+
def load_binary_data(binary_data, symmetric_key)
|
14
|
+
hash = extract_entities_from_binary_data(binary_data, symmetric_key)
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
config = { file_type: determine_file_type(hash[:attributes]),
|
17
|
+
symmetric_key: symmetric_key
|
18
|
+
}
|
19
|
+
|
20
|
+
nmd = NmDatafile.new( config )
|
18
21
|
|
19
22
|
nmd.load_attributes(hash[:attributes]) unless hash[:attributes].nil?
|
20
23
|
nmd.load_encryption(hash[:encryption])
|
@@ -28,15 +31,14 @@ module NmDatafile
|
|
28
31
|
end
|
29
32
|
|
30
33
|
|
31
|
-
def determine_password(hash)
|
34
|
+
def determine_password(hash, symmetric_key)
|
32
35
|
d = YAML::load hash[:encryption]
|
33
|
-
|
34
|
-
::NmDatafile.clean_decrypt_string(d["password"])
|
36
|
+
::NmDatafile.clean_decrypt_string(d["password"], symmetric_key)
|
35
37
|
end
|
36
38
|
|
37
39
|
# This method peers through a zip binary data blob and returns a hash consisting of
|
38
40
|
# { file_name1: file_data1, etc }
|
39
|
-
def extract_entities_from_binary_data(binary_data)
|
41
|
+
def extract_entities_from_binary_data(binary_data, symmetric_key)
|
40
42
|
binary_data_io = StringIO.new(binary_data)
|
41
43
|
|
42
44
|
hash = {}
|
@@ -46,7 +48,7 @@ module NmDatafile
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
password = self.determine_password(hash)
|
51
|
+
password = self.determine_password(hash, symmetric_key)
|
50
52
|
|
51
53
|
decrypt_encryptable_data!(password, hash)
|
52
54
|
hash
|
data/lib/nm_datafile/debug.rb
CHANGED
@@ -20,6 +20,8 @@ module NmDatafile
|
|
20
20
|
|
21
21
|
# creates an address_completion file based on the contents of the current shippable_file object
|
22
22
|
def simulate_address_completion_response(n_shipped)
|
23
|
+
symmetric_key = @symmetric_key
|
24
|
+
|
23
25
|
raise "can't make an address_completion_response unless it's a shippable_file" if @file_type != :shippable_file
|
24
26
|
setup_object_for_schema # TODu: I put this in, there was a bug in the test where it needs to be run... does it not run on init somehow?
|
25
27
|
|
@@ -32,10 +34,10 @@ module NmDatafile
|
|
32
34
|
erroneous_addresses << { "id" => sale["id"] }
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
simulated_response = [shipped_sales, erroneous_addresses, ready_for_shipment_batch]
|
37
|
-
|
38
|
-
nmd_address_completion = NmDatafile.new(
|
39
|
+
config = { file_type: :address_completion_file, symmetric_key: symmetric_key}
|
40
|
+
nmd_address_completion = NmDatafile.new(config, *simulated_response)
|
39
41
|
end
|
40
42
|
|
41
43
|
def generate_upload_params(action = "upload_shippable_file")
|
@@ -51,21 +51,15 @@ module NmDatafile
|
|
51
51
|
binary_output = `#{alt}`
|
52
52
|
end
|
53
53
|
|
54
|
+
# TODu: rename to encode_password_protected_string
|
54
55
|
def encode_string_as_password_protected(encryptable_portion, pass = nil)
|
55
|
-
#require 'b_f'
|
56
|
-
|
57
56
|
pish = @password
|
58
57
|
pish = pass unless pass.nil?
|
59
58
|
raise "error, password given was too long, must be 56 or less chars" if pish.length > 56
|
60
59
|
|
61
|
-
|
60
|
+
encrypted = Blowfish.encrypt(pish, encryptable_portion)
|
62
61
|
|
63
|
-
encrypted
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
def decode_password_protected_string(password, decryptable_portion)
|
68
|
-
::NmDatafile.decode_password_protected_string(password, decryptable_portion)
|
62
|
+
encrypted
|
69
63
|
end
|
70
64
|
|
71
65
|
def obfuscate_file_format
|
@@ -77,16 +71,5 @@ module NmDatafile
|
|
77
71
|
end
|
78
72
|
|
79
73
|
|
80
|
-
def clean_encrypt_string(string)
|
81
|
-
# Base64.encode64(encode_string_as_password_protected(string, @@unsecure_pass))
|
82
|
-
::NmDatafile.fast_encrypt_string_with_pass(::NmDatafile::FRONT_DOOR_KEY, string)
|
83
|
-
end
|
84
|
-
|
85
|
-
# This redirects to the mixin used by Crypto
|
86
|
-
# ughhh.....
|
87
|
-
def clean_decrypt_string(string)
|
88
|
-
::NmDatafile.clean_decrypt_string(string)
|
89
|
-
end
|
90
|
-
|
91
74
|
end
|
92
75
|
end
|
@@ -91,13 +91,15 @@ module NmDatafile
|
|
91
91
|
# (m)
|
92
92
|
# aNonyMousDatafile
|
93
93
|
class NmDatafile
|
94
|
-
@@schemas = ::NmDatafile::SCHEMA[:schemas] # TODO: move to initialize
|
95
94
|
@@clear_text_path = "clear_text_protected_nmd" # used for using system calls to decrypt and encrypt using a zip password
|
96
|
-
|
95
|
+
|
96
|
+
attr_reader :file_type, :password, :symmetric_key
|
97
|
+
attr_accessor :schemas
|
97
98
|
|
98
99
|
# include Crypto
|
99
100
|
include Debug
|
100
101
|
include FileEncoding
|
102
|
+
include Crypto
|
101
103
|
|
102
104
|
###############################
|
103
105
|
# Loading and Dumping Methods #
|
@@ -105,7 +107,10 @@ module NmDatafile
|
|
105
107
|
|
106
108
|
# notice migration to loading.rb
|
107
109
|
|
108
|
-
def initialize(
|
110
|
+
def initialize(config, *args)
|
111
|
+
file_type = config[:file_type]
|
112
|
+
@symmetric_key = config[:symmetric_key]
|
113
|
+
@schemas = ::NmDatafile::SCHEMA[:schemas]
|
109
114
|
set_file_type(file_type)
|
110
115
|
|
111
116
|
load_data(args)
|
@@ -122,7 +127,7 @@ module NmDatafile
|
|
122
127
|
def load_encryption(encryption_data)
|
123
128
|
d = YAML::load encryption_data
|
124
129
|
@integrity_hash = d["integrity_hash"] unless d["integrity_hash"].nil?
|
125
|
-
@password = clean_decrypt_string(d["password"]) unless d["password"].nil?
|
130
|
+
@password = ::NmDatafile.clean_decrypt_string(d["password"], @symmetric_key) unless d["password"].nil?
|
126
131
|
end
|
127
132
|
|
128
133
|
# (m) load_data: loads array of data into memory as an NmDatafile object
|
@@ -199,7 +204,7 @@ module NmDatafile
|
|
199
204
|
|
200
205
|
def build_encryption
|
201
206
|
hash = { integrity_hash: integrity_hash,
|
202
|
-
password: clean_encrypt_string(@password)
|
207
|
+
password: clean_encrypt_string(@password, @symmetric_key)
|
203
208
|
}.to_json
|
204
209
|
end
|
205
210
|
|
@@ -216,7 +221,7 @@ module NmDatafile
|
|
216
221
|
#######################
|
217
222
|
|
218
223
|
def schema
|
219
|
-
|
224
|
+
@schemas[@file_type]
|
220
225
|
end
|
221
226
|
|
222
227
|
def data_collection_names
|
data/lib/nm_datafile/schema.rb
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# something more generic
|
3
3
|
module NmDatafile
|
4
4
|
SCHEMA = { schemas:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
{ :shippable_file => {
|
6
|
+
data_collections: [:sales, :line_items, :discounts, :addresses, :ubws, :encryption_pairs], # name the data that is input into the NMDatafile as an array
|
7
|
+
data_objects: [:ready_for_shipment_batch]
|
8
|
+
},
|
9
|
+
|
10
|
+
:address_completion_file => {
|
11
|
+
data_collections: [:sales, :erroneous_sales],
|
12
|
+
data_objects: [:ready_for_shipment_batch]
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
16
|
end
|
data/lib/nm_datafile/version.rb
CHANGED
Binary file
|
data/spec/nm_datafile_spec.rb
CHANGED
@@ -6,13 +6,36 @@ describe "nm_datafile" do
|
|
6
6
|
#@sample_data = get_sample_data
|
7
7
|
@sales = [{"address_id"=>1, "created_at"=>"2015-03-08T03:54:51Z", "currency_used"=>"BTC"}]
|
8
8
|
@sample_data = [ @sales ]
|
9
|
-
|
9
|
+
# binary_nmd_info:
|
10
|
+
# decrypted password should be: "@(OfMLpCe@pV(GGLuEvj(Tup$BaFodP3!6^5%5pTW"
|
11
|
+
#
|
12
|
+
# if you change the encryption algo, recreate this file with the help of the first test
|
13
|
+
@binary_nmd_path = 'spec/data/nmd_binary_string_w_2s_2li_2a_1ubws_1ep.zip'
|
14
|
+
|
15
|
+
@symmetric_key = "this_is_a_keythis_is_a_keythis_is_a_keythis_is_a_key"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be able to create an nmd_file out of complicated data hashes and save it" do
|
19
|
+
sales = [{"address_id"=>1, "created_at"=>"2015-03-23T01:55:04Z", "currency_used"=>"BTC", "delivery_acknowledged"=>nil, "id"=>1, "original_id"=>nil, "prepped"=>true, "ready_for_shipment_batch_id"=>1, "receipt_confirmed"=>"2015-03-23T01:55:04Z", "sale_amount"=>"4500000.0", "shipped"=>nil, "shipping_amount"=>0.0, "total_amount"=>"4500000.0", "updated_at"=>"2015-03-23T01:55:04Z", "user_id"=>1, "utilized_bitcoin_wallet_id"=>1}, {"address_id"=>5, "created_at"=>"2015-03-23T01:55:04Z", "currency_used"=>"BTC", "delivery_acknowledged"=>nil, "id"=>2, "original_id"=>nil, "prepped"=>true, "ready_for_shipment_batch_id"=>1, "receipt_confirmed"=>"2015-03-23T01:55:04Z", "sale_amount"=>"4500000.0", "shipped"=>nil, "shipping_amount"=>0.0, "total_amount"=>"4500000.0", "updated_at"=>"2015-03-23T01:55:04Z", "user_id"=>2, "utilized_bitcoin_wallet_id"=>1}]
|
20
|
+
line_items = [{"created_at"=>"2015-03-23T01:55:04Z", "currency_used"=>"BTC", "description"=>nil, "discount"=>nil, "discounted_amount"=>nil, "discounted_item_id"=>nil, "id"=>1, "original_id"=>nil, "price"=>"4500000.0", "price_after_product_discounts"=>nil, "price_extend"=>"4500000.0", "product_sku"=>"0001", "qty"=>1, "sale_id"=>1, "shipping_cost"=>"0.0", "shipping_cost_btc"=>0, "shipping_cost_usd"=>"0.0", "updated_at"=>"2015-03-23T01:55:04Z"}, {"created_at"=>"2015-03-23T01:55:04Z", "currency_used"=>"BTC", "description"=>nil, "discount"=>nil, "discounted_amount"=>nil, "discounted_item_id"=>nil, "id"=>2, "original_id"=>nil, "price"=>"4500000.0", "price_after_product_discounts"=>nil, "price_extend"=>"4500000.0", "product_sku"=>"0001", "qty"=>1, "sale_id"=>2, "shipping_cost"=>"0.0", "shipping_cost_btc"=>0, "shipping_cost_usd"=>"0.0", "updated_at"=>"2015-03-23T01:55:04Z"}]
|
21
|
+
discounts = []
|
22
|
+
addresses = [{"address1"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAkkLLYWOzmHDrknH9NWLjTz7cmMN6Da7Oqz57WFQS\n3vdFb/72BrdpHnzZRmZNIWBH4Vj7sUcKv0X2Q+WL45qQSELEdOawpgGVvS9A\nXrqzAJxbTBKTpyqszqfD/Q8pTMnCIXo0S1zJERBpqLvxQF2rO+sytMn6x9xZ\n2ZFKWtpSfcYxR89itnCK3tCBNHH9hJG+ej/oFsXwJgddVuSnRRSPPW6Ea/W2\n9G4xuOVnDwpfOLGj7wfP6+AlMuJCGTN6Urd18eGyFiYP+WaPvk51yS4jkzOi\nkqRbRLTIvsEiK2KcVyEd6F/NxqTLD7Nw5ADxHyVZzOiNPJKTmwf7diaP8mdm\nyqQzC8c5mfPzWhop3DYJXzL2Y4Mgk7qxR08RKIewTR/SWLtlRnFOwT+itBQN\nN4nD1x19T0Wp\n=dsyQ\n-----END PGP MESSAGE-----\n", "address2"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf6AloPtxXYB+OGv+MnFgQofqs6CEMbKoSf45c+hk6c\nZMpqr9/R/ZK6I7Nbla/FCbKmAtttZ0T6I1GAS/6ivFDJ8J7Y7bhag2tueP86\ntMfyTL6j6VQGOEu7AoMrx58vk76bC2DYG8BAw42y6lHifz8X9IJAzrccyjT4\nHzYmUmoM2sma3qHuN1PZp24qZJqHEOGr8XhpTzaDXuIp00P3+X0NVoLzaZUS\ncgxObRImRzHyRSzSHKRnnbTKHg7SKn43J2lpkJV07bqP8HLNTGYG1YzUigjp\nPydGX0l1sLjo4I3KTmBetjs5s4sJTH3QqqYq/Dfqfch5/MqE92LrNlxzCtgc\ncKQwpTllOo0smnSBLrTnixgEy0mfhUlmVjasEoG9DxD0yinJR+9TeCeskPQk\nKdXI8L/O\n=Mx2r\n-----END PGP MESSAGE-----\n", "apt"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf/QWtqnGOuYOQqhdv9rot0N8altMdgso71Deub2YqH\nyVSrrLhzpvT6mPmNJXHOuS0AtamnNjeMbiJRmkf3m6l56BMYlz904GIbG3Zr\nzzJcr8A+N30afhMO/kmZZfK5mjLfKHiyPA71HN5Kd3J8N9aWYwj9HDm3tCSB\ndsOvcZ5QXkXwzIj+jtOV1201PvwMyShmTgZqCM7c0OwR/sFKBOhx33tcZKWx\nW+k0jbfZJb0RUv95jPuQIeS180O5BRWSUC2tOXaCkgT9u6pC41sRjTZnuH+3\nv/DIhV7uyf46f00sCcwpxPedtrchydh+Daww7sPpdQpRKWtk19a+iIIo8Rvt\n7KQkA0Y5WuvhTQbdfq8deJzUwqUKJtGVGPcps1PMeIMe6ZTLi0ru\n=Gmsg\n-----END PGP MESSAGE-----", "city"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAqPKhl8LbI8Fs+zasPS3a61CWCS8Aus7UgR8Bf3Eu\n4UBPOA7B3U4YQXhMoxMYGl/JN0C6IctjkP6PwyKXvNTgpKG1WKuki8/hKKZg\njPLhiDwZeFggzCTqC0GxublCrQOPZjHNUufShCY5D1g/iTKTO3VCuilUDyBj\nt3ExgO8k/SgdfbzzrKNe3TktJTOFMOenwr0QQg51B3XrBLih5/ssHWVnrs06\nmBlC6jucHY/tuPIAiQj7xJBpncUHJZbqbvkm0xsb8QFFzSoNyCV+3rekpil5\nYlbb9i3Vtr7BIwEowHvqjKaubEy58bxk7F+P5XrLj+yabV9vzUH1xeqFkEwY\n3KQq1wOGUHMqR9hmZZfkT70jIo3/+7Wxd8g+RZnH6Sh0jQ6E8i4wTtVgjoCV\n\n=ZHnk\n-----END PGP MESSAGE-----\n", "code_name"=>"My House 5", "country"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgArZZDnWPNSpRwVLfzAuhcOXN0CpX8X70ZeN7pUkUS\nQomf5LpvQ+31dVgCdOpkcf/NgL5fnr7CaJLQ7ovC3f9tz+oxirfRT/SueGL5\nhDqQIPE23y0UPoLeNBh8krzhz72o9fQAa3fHG50KCgJpizyUHXaOxo8i8+eA\nkzcGTaL12jeTrDSxoy8xGj/xZyS/m1HbcJ7ZdVSChZt72xe/Cj4epgC1SD4b\nvm7Ki90EOcY8NylRBeR8/yFKsY3YSE+kF7snD94N2M2O9or+wgT61iXZMYf0\ntKeK1woU4C+SnBIo+H+Aa6X4s3OGiFH0GyTxfr+C0r4FzSTO1LcioIq5m6GS\nWqQiVhyzg6XScDqB3Je7CGEEjA6oFzOmQmn3Rsa2ZnYNHaqP6g==\n=RvKD\n-----END PGP MESSAGE-----\n", "created_at"=>"2015-03-23T01:55:04Z", "encryption_pair_id"=>1, "erroneous"=>false, "first_name"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf/UTM9RsZfkWBG3PzkHzm6GtCBmjXAwbHeSg00rKIe\nMdikzxnm464wG1sM0WDJeQCVQGzGIAkxfvOPU4rnfhq6x/NJpI7WuC4X1uJw\niyxiZnpT/A2PEYdlWbUZQWeeadEgAMdI+yiPJ/SHbQrmWDwLEhpKtwCqjMYi\nhtJt1W1l+lhAMdGvXh6nIVyQWiqm9+pQrEvewWIAKsxcFk2OGKSfMRRtivWl\nECNCI8z8h0WdIythAVHTJ8CzmEszYuMWRG7LUMhUs3IHNAtCWkoRojISY1/4\nKqSqQlhpMwJmYGebPhGiAarpmjtltZA/Dy7ERFfctoLxjE7BkRK7HXnq13XW\n4qQk0lyBxx/TadYmlCzDu/B6riOUsbCHJQiwQPpv9+D/CPdK9NWI\n=Awa8\n-----END PGP MESSAGE-----\n", "id"=>1, "last_name"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf+O6lcxOYNW9a4E46TUfcYm4dSoUeEMXKjdk9RmWvj\no49h2EOWbjR+LoyAYFah9GF8ydBwkrI47dyeokZDJq9lnHQrZdO3BEPzEfd3\nxZ7bPAH7kVennN4kkon/uh5cnwQdFcIQufkUWPePIOTM37GVEMwiUWSAk6Tv\nsd/hC11UraLgJV/iQ1PKYrQ1k9JFab4qYMNg3vdJCS2i5EmVUldlhxhw2odq\nU0e03FM0zjA6oe7/zoci7tYRsvMbDIr7gnNk75s4xKHmA73879uiEgCUXisd\nEJtAiCoAi357VJvIGM9p/rLAzBiL3Q8K3LWKWVzjvPp5tIIQZMAF50FF/f9u\nA6Qjh6R1leS5aGd6NwEzd6udN4hM+ORUDMUrKNgjGcFhzwFnTrE=\n=bbtQ\n-----END PGP MESSAGE-----\n", "original_id"=>nil, "phone"=>nil, "state"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAwSy1/X1hRxDkEgX0WTe8EWKCyacxW2J4jvv5/kDM\nZBpOLi78KCCVokrp2hmdkTzM0aJQl45/dkImVOYOpXb9ulnCJXbmpyF6398d\nvbGTvjtLXQSaJ41LbCGxu32L1bCQsrBUIORqqL/+C9gdqrMmYItWDXwN2do5\nWfVhJShOJEWULSUrhYOC40BuRLKNrv2ruk48bh7Mdn7DQbaBa0jT4iV6flK7\nmFvZfAULPOM40UBJ9aCF/GQGBR7lPM3SiaUHfi3rWQihjpUEmHE1l/ui7FWw\n+FiaKvKWhvECAIo5iV9V/sUPGj3Zw5JEDFX9J4GS6zry2G9/sU1Ka7nOQx3F\nOqQnazqWUIMO9WCMZRV/6gnw7rbOr897ikGXvOdoMY4scVb8dz8bbLT9\n=s04T\n-----END PGP MESSAGE-----\n", "updated_at"=>"2015-03-23T01:55:04Z", "user_id"=>1, "zip"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAqyLtfr8yy9aRSNCKy9UTNVhVFFs1ABozP2QUUKVJ\nfA/oUeAntTmeFz1Ga7HC1g8iyefE1G/Y2PEaHCSj1JFqczOJS13XgRYO45AK\nd9dTLLjl+qElVx78M06mIoXUaeSuaex0X/3qNXauCIeGJpaBf9xMLMlYbxH8\nzW3Q1j15VnQz6MFuwoYNXfABc2ekLve076UvUCxbn0G598VmCHHCD28u+Oec\nsuuxebOcjQWbFNsLoGTpKS+OecilkQ98H1cPkLD7qZHluGWP+0WCOCkg1Ttq\nvW+ibdmGW30fq/1EKprJchayANgGdMd/ynbduG0Nn0pGYUk+y5WBucMDINGS\nZKQlHHtkqVBbH14dmx81aGg2gblp6PVaa/fmFw/2FP385ARJ1mRT3w==\n=PlFx\n-----END PGP MESSAGE-----\n"}, {"address1"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAkkLLYWOzmHDrknH9NWLjTz7cmMN6Da7Oqz57WFQS\n3vdFb/72BrdpHnzZRmZNIWBH4Vj7sUcKv0X2Q+WL45qQSELEdOawpgGVvS9A\nXrqzAJxbTBKTpyqszqfD/Q8pTMnCIXo0S1zJERBpqLvxQF2rO+sytMn6x9xZ\n2ZFKWtpSfcYxR89itnCK3tCBNHH9hJG+ej/oFsXwJgddVuSnRRSPPW6Ea/W2\n9G4xuOVnDwpfOLGj7wfP6+AlMuJCGTN6Urd18eGyFiYP+WaPvk51yS4jkzOi\nkqRbRLTIvsEiK2KcVyEd6F/NxqTLD7Nw5ADxHyVZzOiNPJKTmwf7diaP8mdm\nyqQzC8c5mfPzWhop3DYJXzL2Y4Mgk7qxR08RKIewTR/SWLtlRnFOwT+itBQN\nN4nD1x19T0Wp\n=dsyQ\n-----END PGP MESSAGE-----\n", "address2"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf6AloPtxXYB+OGv+MnFgQofqs6CEMbKoSf45c+hk6c\nZMpqr9/R/ZK6I7Nbla/FCbKmAtttZ0T6I1GAS/6ivFDJ8J7Y7bhag2tueP86\ntMfyTL6j6VQGOEu7AoMrx58vk76bC2DYG8BAw42y6lHifz8X9IJAzrccyjT4\nHzYmUmoM2sma3qHuN1PZp24qZJqHEOGr8XhpTzaDXuIp00P3+X0NVoLzaZUS\ncgxObRImRzHyRSzSHKRnnbTKHg7SKn43J2lpkJV07bqP8HLNTGYG1YzUigjp\nPydGX0l1sLjo4I3KTmBetjs5s4sJTH3QqqYq/Dfqfch5/MqE92LrNlxzCtgc\ncKQwpTllOo0smnSBLrTnixgEy0mfhUlmVjasEoG9DxD0yinJR+9TeCeskPQk\nKdXI8L/O\n=Mx2r\n-----END PGP MESSAGE-----\n", "apt"=>"", "city"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAqPKhl8LbI8Fs+zasPS3a61CWCS8Aus7UgR8Bf3Eu\n4UBPOA7B3U4YQXhMoxMYGl/JN0C6IctjkP6PwyKXvNTgpKG1WKuki8/hKKZg\njPLhiDwZeFggzCTqC0GxublCrQOPZjHNUufShCY5D1g/iTKTO3VCuilUDyBj\nt3ExgO8k/SgdfbzzrKNe3TktJTOFMOenwr0QQg51B3XrBLih5/ssHWVnrs06\nmBlC6jucHY/tuPIAiQj7xJBpncUHJZbqbvkm0xsb8QFFzSoNyCV+3rekpil5\nYlbb9i3Vtr7BIwEowHvqjKaubEy58bxk7F+P5XrLj+yabV9vzUH1xeqFkEwY\n3KQq1wOGUHMqR9hmZZfkT70jIo3/+7Wxd8g+RZnH6Sh0jQ6E8i4wTtVgjoCV\n\n=ZHnk\n-----END PGP MESSAGE-----\n", "code_name"=>"My House 9", "country"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgArZZDnWPNSpRwVLfzAuhcOXN0CpX8X70ZeN7pUkUS\nQomf5LpvQ+31dVgCdOpkcf/NgL5fnr7CaJLQ7ovC3f9tz+oxirfRT/SueGL5\nhDqQIPE23y0UPoLeNBh8krzhz72o9fQAa3fHG50KCgJpizyUHXaOxo8i8+eA\nkzcGTaL12jeTrDSxoy8xGj/xZyS/m1HbcJ7ZdVSChZt72xe/Cj4epgC1SD4b\nvm7Ki90EOcY8NylRBeR8/yFKsY3YSE+kF7snD94N2M2O9or+wgT61iXZMYf0\ntKeK1woU4C+SnBIo+H+Aa6X4s3OGiFH0GyTxfr+C0r4FzSTO1LcioIq5m6GS\nWqQiVhyzg6XScDqB3Je7CGEEjA6oFzOmQmn3Rsa2ZnYNHaqP6g==\n=RvKD\n-----END PGP MESSAGE-----\n", "created_at"=>"2015-03-23T01:55:04Z", "encryption_pair_id"=>1, "erroneous"=>false, "first_name"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf/UTM9RsZfkWBG3PzkHzm6GtCBmjXAwbHeSg00rKIe\nMdikzxnm464wG1sM0WDJeQCVQGzGIAkxfvOPU4rnfhq6x/NJpI7WuC4X1uJw\niyxiZnpT/A2PEYdlWbUZQWeeadEgAMdI+yiPJ/SHbQrmWDwLEhpKtwCqjMYi\nhtJt1W1l+lhAMdGvXh6nIVyQWiqm9+pQrEvewWIAKsxcFk2OGKSfMRRtivWl\nECNCI8z8h0WdIythAVHTJ8CzmEszYuMWRG7LUMhUs3IHNAtCWkoRojISY1/4\nKqSqQlhpMwJmYGebPhGiAarpmjtltZA/Dy7ERFfctoLxjE7BkRK7HXnq13XW\n4qQk0lyBxx/TadYmlCzDu/B6riOUsbCHJQiwQPpv9+D/CPdK9NWI\n=Awa8\n-----END PGP MESSAGE-----\n", "id"=>5, "last_name"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQf+O6lcxOYNW9a4E46TUfcYm4dSoUeEMXKjdk9RmWvj\no49h2EOWbjR+LoyAYFah9GF8ydBwkrI47dyeokZDJq9lnHQrZdO3BEPzEfd3\nxZ7bPAH7kVennN4kkon/uh5cnwQdFcIQufkUWPePIOTM37GVEMwiUWSAk6Tv\nsd/hC11UraLgJV/iQ1PKYrQ1k9JFab4qYMNg3vdJCS2i5EmVUldlhxhw2odq\nU0e03FM0zjA6oe7/zoci7tYRsvMbDIr7gnNk75s4xKHmA73879uiEgCUXisd\nEJtAiCoAi357VJvIGM9p/rLAzBiL3Q8K3LWKWVzjvPp5tIIQZMAF50FF/f9u\nA6Qjh6R1leS5aGd6NwEzd6udN4hM+ORUDMUrKNgjGcFhzwFnTrE=\n=bbtQ\n-----END PGP MESSAGE-----\n", "original_id"=>nil, "phone"=>nil, "state"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAwSy1/X1hRxDkEgX0WTe8EWKCyacxW2J4jvv5/kDM\nZBpOLi78KCCVokrp2hmdkTzM0aJQl45/dkImVOYOpXb9ulnCJXbmpyF6398d\nvbGTvjtLXQSaJ41LbCGxu32L1bCQsrBUIORqqL/+C9gdqrMmYItWDXwN2do5\nWfVhJShOJEWULSUrhYOC40BuRLKNrv2ruk48bh7Mdn7DQbaBa0jT4iV6flK7\nmFvZfAULPOM40UBJ9aCF/GQGBR7lPM3SiaUHfi3rWQihjpUEmHE1l/ui7FWw\n+FiaKvKWhvECAIo5iV9V/sUPGj3Zw5JEDFX9J4GS6zry2G9/sU1Ka7nOQx3F\nOqQnazqWUIMO9WCMZRV/6gnw7rbOr897ikGXvOdoMY4scVb8dz8bbLT9\n=s04T\n-----END PGP MESSAGE-----\n", "updated_at"=>"2015-03-23T01:55:04Z", "user_id"=>2, "zip"=>"-----BEGIN PGP MESSAGE-----\nVersion: haneWIN JavascriptPG v2.0\n\nhQEMAxi+vIcfDgArAQgAqyLtfr8yy9aRSNCKy9UTNVhVFFs1ABozP2QUUKVJ\nfA/oUeAntTmeFz1Ga7HC1g8iyefE1G/Y2PEaHCSj1JFqczOJS13XgRYO45AK\nd9dTLLjl+qElVx78M06mIoXUaeSuaex0X/3qNXauCIeGJpaBf9xMLMlYbxH8\nzW3Q1j15VnQz6MFuwoYNXfABc2ekLve076UvUCxbn0G598VmCHHCD28u+Oec\nsuuxebOcjQWbFNsLoGTpKS+OecilkQ98H1cPkLD7qZHluGWP+0WCOCkg1Ttq\nvW+ibdmGW30fq/1EKprJchayANgGdMd/ynbduG0Nn0pGYUk+y5WBucMDINGS\nZKQlHHtkqVBbH14dmx81aGg2gblp6PVaa/fmFw/2FP385ARJ1mRT3w==\n=PlFx\n-----END PGP MESSAGE-----\n"}]
|
23
|
+
ubws = [{"created_at"=>"2015-03-23T01:55:04Z", "id"=>1, "original_id"=>nil, "updated_at"=>"2015-03-23T01:55:04Z", "wallet_address"=>"1FWNSL4HZy7pW2zRHanR2t72nvw7VdLVuB"}]
|
24
|
+
encryption_pairs = [{"created_at"=>"2015-03-23T01:55:04Z", "id"=>1, "original_id"=>nil, "private_key"=>nil, "public_key"=>"-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1.4.12 (GNU/Linux)\n\nmQENBFLm15sBCADGEjoJw/ATyPYC+3er/XiZsCCht6t1Kr8p6fXVI9h7cyvoTulM\n31iug8kFvIr/dggNtEVYjnzuk6ervf2mit5uw3wgs8BBDGOj7BLg6kfuEUjsRaRO\nlCNKKneuscCBvyDbilsnc9jOdc7Nz4wpa8nwLh9iM6GqcM90pClaGYsDAYSFL7Kz\nHiTkBeDeo6pQS2p7G7p+Fg498OrpvythBtwhNiVL01X8f2zaGhlkTaDThJm5qofG\nlal552FitRtJuwu6Tim2Fef2jqJoEb0Hxc4o59/kKm+hqYlW0p5qleKm/hNWDSp1\nFA4VlUP7IPqPa5mzrIIrpRhDRZaIkdGAqWchABEBAAG0EWFiY2RlIChhKSA8YUBi\nLmM+iQE4BBMBAgAiBQJS5tebAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRAdhYud6iaPu+yoB/4lyX2WTLFQWKCYavU4OzSiRSwSg33LAa/hj9as4jDUErg0\nIPl2dm3QMpf57jny1stqEDAVBQ3eyff5LqmJnhf6YyfroyfCMuTbY4woNyaY2IC0\nXJlBdMlUAOoWcHZCfl4ud97vW+XfRky/uZsmjUBh5DymL2f0fVFxwIeXl/k0hOti\n0FY6l7EGl0I9MQp5dPdqJonsAv1KnjdclsqmLDu7cFWHNF+BHCTb3xkDs0kqShvs\nA8o8HrD/9kUxdRSVdO+VQrZaimI6XdNWHzI4pEYQHQtnZ0IA1aOyzcqWpyTSlyy8\n1QzyNAvXQ4gzrpqRwdrdqUjuEwUTJoLKRSyYQ8yCuQENBFLm15sBCADI6MESgCQH\nf2JIjsHk2owRMpEhjyr25pEktjTpf8zLy5LYwHgwZXwpc6zDnwMBV6PcaPI6ZTRF\nGfwY4GsL9DBLefbiZuvYghYi++cevG11V87XhoRx8u8FGPukjRyKs4gCTrHW2g9q\n8IES46GZalCkC4x8WDM68yWutO/22ie7eALjMU+Ju9lbrwUI4/uy6a9dQJLMPdXN\ncYnWQO/q/CpkcngnoKEjreJ9FszrdSFtd+cBoItknsX668Euf4IIPwCW/KUfGZMm\n/Js/3pZRQpqq+OryuKcB03YsMd5E/JE+DySUo19rPeA2xwXLlW5goA9JL0YCvqW/\ntmEwvwDoVlW5ABEBAAGJAR8EGAECAAkFAlLm15sCGwwACgkQHYWLneomj7tfowgA\ngKRy023Oa6rYKwEZlQRWc7gL27Z8V9vCFgBaMM4cNFqrKqY97VezZ6ldjYqd6AGJ\nGWbrG8SqVZ4ZyoksyWnweMYKqoRGIcX7LEuL97mc6W7bB5MRGL9zQRIxu0/KHVik\nVZ8PL3f4j4XdPuF0gRLPBIDOOZVGqf86NpnKLx1XEIaS/z3OqxyWkRR47oOquqpd\nNd4Gn1hDZlTgiSsaSf6aFdS6O2eDLaseZ2l0WgrWoUMjD5bzmKgpmaJAJ+CcfuvB\nP1O44KOH9l+pRzKCbr6nlfd8rbQ4kehjIaGchdehvLFv9WQWMH9uDkKgIu3BGGkp\nJ1TdTyeCX++qX0MtJ79GDw==\n=ToNu\n-----END PGP PUBLIC KEY BLOCK-----\n", "test_value"=>nil, "tested"=>nil, "updated_at"=>"2015-03-23T01:55:04Z"}]
|
25
|
+
rfsb = {"acf_integrity_hash"=>nil, "batch_stamp"=>"2015-03-23_01.55.042", "created_at"=>"2015-03-23T01:55:04Z", "id"=>1, "original_id"=>nil, "sale_id"=>nil, "sf_integrity_hash"=>"c39c2be15b918842604261d8daf9ef1535842a7d558d0b6f2114a9404dd453d8", "updated_at"=>"2015-03-23T01:55:04Z"}
|
26
|
+
|
27
|
+
config = {file_type: :shippable_file, symmetric_key: @symmetric_key}
|
28
|
+
nm_data = NmDatafile.new(config, sales, line_items, discounts, addresses, ubws, encryption_pairs, rfsb)
|
29
|
+
nm_data.sales.count.should eq 2
|
30
|
+
|
31
|
+
# uncomment to update file
|
32
|
+
#nm_data.save_to_file(@binary_nmd_path)
|
10
33
|
end
|
11
34
|
|
12
35
|
it "should be able to load data from a binary string" do
|
13
36
|
nmd_binary_string = File.read(@binary_nmd_path)
|
14
37
|
|
15
|
-
nmd_file = NmDatafile::
|
38
|
+
nmd_file = NmDatafile::load_binary_data nmd_binary_string, @symmetric_key
|
16
39
|
|
17
40
|
sales = nmd_file.sales
|
18
41
|
line_items = nmd_file.line_items
|
@@ -22,7 +45,8 @@ describe "nm_datafile" do
|
|
22
45
|
encryption_pairs = nmd_file.encryption_pairs
|
23
46
|
rfsb = nmd_file.ready_for_shipment_batch
|
24
47
|
|
25
|
-
|
48
|
+
config = {file_type: :shippable_file, symmetric_key: @symmetric_key}
|
49
|
+
nm_data = NmDatafile.new(config, sales, line_items, discounts, addresses, ubws, encryption_pairs, rfsb)
|
26
50
|
|
27
51
|
nm_data.sales.count.should eq 2
|
28
52
|
nm_data.ready_for_shipment_batch["batch_stamp"].should eq rfsb["batch_stamp"]
|
@@ -30,26 +54,60 @@ describe "nm_datafile" do
|
|
30
54
|
|
31
55
|
it "should be able to load data from a path to a zip" do
|
32
56
|
|
33
|
-
nmd_string_loaded = NmDatafile::
|
57
|
+
nmd_string_loaded = NmDatafile::load_binary_data File.read(@binary_nmd_path), @symmetric_key
|
34
58
|
|
35
|
-
nmd_path_loaded = NmDatafile::Load @binary_nmd_path
|
59
|
+
nmd_path_loaded = NmDatafile::Load @binary_nmd_path, @symmetric_key
|
36
60
|
|
37
61
|
nmd_string_loaded.sales.should eq nmd_path_loaded.sales
|
38
62
|
end
|
39
63
|
|
40
64
|
it "should be able to save data as a zip string" do
|
41
|
-
|
65
|
+
config = {file_type: :shippable_file, symmetric_key: @symmetric_key}
|
66
|
+
nmd_shippable = NmDatafile.new(config, *@sample_data)
|
42
67
|
|
43
|
-
nmd = NmDatafile::
|
68
|
+
nmd = NmDatafile::load_binary_data nmd_shippable.save_to_string, @symmetric_key
|
44
69
|
|
45
70
|
nmd.sales.should eq @sample_data.first
|
46
71
|
end
|
47
72
|
|
48
73
|
it "should be able to load in the attributes" do
|
49
|
-
nmd = NmDatafile::Load @binary_nmd_path
|
74
|
+
nmd = NmDatafile::Load @binary_nmd_path, @symmetric_key
|
50
75
|
|
51
76
|
nmd.file_type.should eq :shippable_file
|
52
77
|
end
|
78
|
+
|
79
|
+
it "fast_encrypt_string_with_pass and fast_decrypt_string_with_pass reverse" do
|
80
|
+
original_string = "hello"
|
81
|
+
|
82
|
+
pass = @symmetric_key
|
83
|
+
|
84
|
+
encrypted_string = NmDatafile::fast_encrypt_string_with_pass(pass, original_string)
|
85
|
+
|
86
|
+
clear_text = NmDatafile::fast_decrypt_string_with_pass(pass, encrypted_string)
|
87
|
+
|
88
|
+
clear_text.should eq original_string
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should test simulate_address_completion_response(n_shipped)" do
|
92
|
+
nmd_file = NmDatafile::Load @binary_nmd_path, @symmetric_key
|
93
|
+
|
94
|
+
x = nmd_file.simulate_address_completion_response(5)
|
95
|
+
|
96
|
+
x.sales.count.should eq 2
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should test generate_upload_params" do
|
100
|
+
nmd_file = NmDatafile::Load @binary_nmd_path, @symmetric_key
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should fail when the wrong symmetric key is used" do
|
104
|
+
encrypted = ::NmDatafile.clean_encrypt_string("encrypt this string please", "this_is_a_keythi")
|
105
|
+
|
106
|
+
expect {
|
107
|
+
clear_text = ::NmDatafile.clean_decrypt_string(encrypted, "this_is_a_keythasdf")
|
108
|
+
}.to raise_error
|
109
|
+
end
|
110
|
+
|
53
111
|
|
54
112
|
|
55
113
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nm_datafile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dsj
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -97,7 +97,7 @@ files:
|
|
97
97
|
- Rakefile
|
98
98
|
- changelog.md
|
99
99
|
- lib/nm_datafile.rb
|
100
|
-
- lib/nm_datafile/
|
100
|
+
- lib/nm_datafile/blowfish.rb
|
101
101
|
- lib/nm_datafile/crypto.rb
|
102
102
|
- lib/nm_datafile/data_loading.rb
|
103
103
|
- lib/nm_datafile/debug.rb
|
data/lib/nm_datafile/b_f.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
# https://gist.github.com/nono/2995118
|
2
|
-
|
3
|
-
require "openssl"
|
4
|
-
|
5
|
-
module NmDatafile
|
6
|
-
|
7
|
-
class BF < Struct.new(:key, :pad_with_spaces)
|
8
|
-
def encrypt(str)
|
9
|
-
cipher = OpenSSL::Cipher.new('bf-ecb').encrypt
|
10
|
-
if pad_with_spaces
|
11
|
-
str += " " until str.bytesize % 8 == 0
|
12
|
-
cipher.padding = 0
|
13
|
-
end
|
14
|
-
cipher.key = key
|
15
|
-
binary_data = cipher.update(str) << cipher.final
|
16
|
-
hex_encoded = binary_data.unpack('H*').first
|
17
|
-
end
|
18
|
-
|
19
|
-
def decrypt(hex_encoded)
|
20
|
-
cipher = OpenSSL::Cipher.new('bf-ecb').decrypt
|
21
|
-
cipher.padding = 0 if pad_with_spaces
|
22
|
-
cipher.key = key
|
23
|
-
binary_data = [hex_encoded].pack('H*')
|
24
|
-
str = cipher.update(binary_data) << cipher.final
|
25
|
-
str.force_encoding(Encoding::UTF_8)
|
26
|
-
str
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|