garcun 0.0.2

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +17 -0
  3. data/.gitignore +197 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +22 -0
  6. data/LICENSE +201 -0
  7. data/README.md +521 -0
  8. data/Rakefile +47 -0
  9. data/garcun.gemspec +83 -0
  10. data/lib/garcon.rb +290 -0
  11. data/lib/garcon/chef/chef_helpers.rb +343 -0
  12. data/lib/garcon/chef/coerce/coercer.rb +134 -0
  13. data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
  14. data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
  15. data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
  16. data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
  17. data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
  18. data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
  19. data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
  20. data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
  21. data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
  22. data/lib/garcon/chef/handler/devreporter.rb +127 -0
  23. data/lib/garcon/chef/log.rb +64 -0
  24. data/lib/garcon/chef/node.rb +100 -0
  25. data/lib/garcon/chef/provider/civilize.rb +209 -0
  26. data/lib/garcon/chef/provider/development.rb +159 -0
  27. data/lib/garcon/chef/provider/download.rb +420 -0
  28. data/lib/garcon/chef/provider/house_keeping.rb +265 -0
  29. data/lib/garcon/chef/provider/node_cache.rb +31 -0
  30. data/lib/garcon/chef/provider/partial.rb +183 -0
  31. data/lib/garcon/chef/provider/recovery.rb +80 -0
  32. data/lib/garcon/chef/provider/zip_file.rb +271 -0
  33. data/lib/garcon/chef/resource/attribute.rb +52 -0
  34. data/lib/garcon/chef/resource/base_dsl.rb +174 -0
  35. data/lib/garcon/chef/resource/blender.rb +140 -0
  36. data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
  37. data/lib/garcon/chef/resource/resource_name.rb +109 -0
  38. data/lib/garcon/chef/secret_bag.rb +204 -0
  39. data/lib/garcon/chef/validations.rb +76 -0
  40. data/lib/garcon/chef_inclusions.rb +151 -0
  41. data/lib/garcon/configuration.rb +138 -0
  42. data/lib/garcon/core_ext.rb +39 -0
  43. data/lib/garcon/core_ext/array.rb +27 -0
  44. data/lib/garcon/core_ext/binding.rb +64 -0
  45. data/lib/garcon/core_ext/boolean.rb +66 -0
  46. data/lib/garcon/core_ext/duration.rb +271 -0
  47. data/lib/garcon/core_ext/enumerable.rb +34 -0
  48. data/lib/garcon/core_ext/file.rb +127 -0
  49. data/lib/garcon/core_ext/filetest.rb +62 -0
  50. data/lib/garcon/core_ext/hash.rb +279 -0
  51. data/lib/garcon/core_ext/kernel.rb +159 -0
  52. data/lib/garcon/core_ext/lazy.rb +222 -0
  53. data/lib/garcon/core_ext/method_access.rb +243 -0
  54. data/lib/garcon/core_ext/module.rb +92 -0
  55. data/lib/garcon/core_ext/nil.rb +53 -0
  56. data/lib/garcon/core_ext/numeric.rb +44 -0
  57. data/lib/garcon/core_ext/object.rb +342 -0
  58. data/lib/garcon/core_ext/pathname.rb +152 -0
  59. data/lib/garcon/core_ext/process.rb +41 -0
  60. data/lib/garcon/core_ext/random.rb +497 -0
  61. data/lib/garcon/core_ext/string.rb +312 -0
  62. data/lib/garcon/core_ext/struct.rb +49 -0
  63. data/lib/garcon/core_ext/symbol.rb +170 -0
  64. data/lib/garcon/core_ext/time.rb +234 -0
  65. data/lib/garcon/exceptions.rb +101 -0
  66. data/lib/garcon/inflections.rb +237 -0
  67. data/lib/garcon/inflections/defaults.rb +79 -0
  68. data/lib/garcon/inflections/inflections.rb +182 -0
  69. data/lib/garcon/inflections/rules_collection.rb +37 -0
  70. data/lib/garcon/secret.rb +271 -0
  71. data/lib/garcon/stash/format.rb +114 -0
  72. data/lib/garcon/stash/journal.rb +226 -0
  73. data/lib/garcon/stash/queue.rb +83 -0
  74. data/lib/garcon/stash/serializer.rb +86 -0
  75. data/lib/garcon/stash/store.rb +435 -0
  76. data/lib/garcon/task.rb +31 -0
  77. data/lib/garcon/task/atomic.rb +151 -0
  78. data/lib/garcon/task/atomic_boolean.rb +127 -0
  79. data/lib/garcon/task/condition.rb +99 -0
  80. data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
  81. data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
  82. data/lib/garcon/task/count_down_latch.rb +92 -0
  83. data/lib/garcon/task/delay.rb +196 -0
  84. data/lib/garcon/task/dereferenceable.rb +144 -0
  85. data/lib/garcon/task/event.rb +119 -0
  86. data/lib/garcon/task/executor.rb +275 -0
  87. data/lib/garcon/task/executor_options.rb +59 -0
  88. data/lib/garcon/task/future.rb +107 -0
  89. data/lib/garcon/task/immediate_executor.rb +84 -0
  90. data/lib/garcon/task/ivar.rb +171 -0
  91. data/lib/garcon/task/lazy_reference.rb +74 -0
  92. data/lib/garcon/task/monotonic_time.rb +69 -0
  93. data/lib/garcon/task/obligation.rb +256 -0
  94. data/lib/garcon/task/observable.rb +101 -0
  95. data/lib/garcon/task/priority_queue.rb +234 -0
  96. data/lib/garcon/task/processor_count.rb +128 -0
  97. data/lib/garcon/task/read_write_lock.rb +304 -0
  98. data/lib/garcon/task/safe_task_executor.rb +58 -0
  99. data/lib/garcon/task/single_thread_executor.rb +97 -0
  100. data/lib/garcon/task/thread_pool/cached.rb +71 -0
  101. data/lib/garcon/task/thread_pool/executor.rb +294 -0
  102. data/lib/garcon/task/thread_pool/fixed.rb +61 -0
  103. data/lib/garcon/task/thread_pool/worker.rb +90 -0
  104. data/lib/garcon/task/timer.rb +44 -0
  105. data/lib/garcon/task/timer_set.rb +194 -0
  106. data/lib/garcon/task/timer_task.rb +377 -0
  107. data/lib/garcon/task/waitable_list.rb +58 -0
  108. data/lib/garcon/utility/ansi.rb +199 -0
  109. data/lib/garcon/utility/at_random.rb +77 -0
  110. data/lib/garcon/utility/crypto.rb +292 -0
  111. data/lib/garcon/utility/equalizer.rb +146 -0
  112. data/lib/garcon/utility/faker/extensions/array.rb +22 -0
  113. data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
  114. data/lib/garcon/utility/faker/faker.rb +164 -0
  115. data/lib/garcon/utility/faker/faker/company.rb +17 -0
  116. data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
  117. data/lib/garcon/utility/faker/faker/version.rb +3 -0
  118. data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
  119. data/lib/garcon/utility/faker/locales/en.yml +21 -0
  120. data/lib/garcon/utility/file_helper.rb +170 -0
  121. data/lib/garcon/utility/hookers.rb +178 -0
  122. data/lib/garcon/utility/interpolation.rb +90 -0
  123. data/lib/garcon/utility/memstash.rb +364 -0
  124. data/lib/garcon/utility/misc.rb +54 -0
  125. data/lib/garcon/utility/msg_from_god.rb +62 -0
  126. data/lib/garcon/utility/retry.rb +238 -0
  127. data/lib/garcon/utility/timeout.rb +58 -0
  128. data/lib/garcon/utility/uber/builder.rb +91 -0
  129. data/lib/garcon/utility/uber/callable.rb +7 -0
  130. data/lib/garcon/utility/uber/delegates.rb +13 -0
  131. data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
  132. data/lib/garcon/utility/uber/options.rb +101 -0
  133. data/lib/garcon/utility/uber/uber_version.rb +3 -0
  134. data/lib/garcon/utility/uber/version.rb +33 -0
  135. data/lib/garcon/utility/url_helper.rb +100 -0
  136. data/lib/garcon/utils.rb +29 -0
  137. data/lib/garcon/version.rb +62 -0
  138. data/lib/garcun.rb +24 -0
  139. metadata +680 -0
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require_relative 'condition'
21
+
22
+ module Garcon
23
+ class WaitableList
24
+
25
+ def initialize
26
+ @mutex = Mutex.new
27
+ @condition = Condition.new
28
+
29
+ @list = []
30
+ end
31
+
32
+ def size
33
+ @mutex.synchronize { @list.size }
34
+ end
35
+
36
+ def empty?
37
+ @mutex.synchronize { @list.empty? }
38
+ end
39
+
40
+ def put(value)
41
+ @mutex.synchronize do
42
+ @list << value
43
+ @condition.signal
44
+ end
45
+ end
46
+
47
+ def delete(value)
48
+ @mutex.synchronize { @list.delete(value) }
49
+ end
50
+
51
+ def take
52
+ @mutex.synchronize do
53
+ @condition.wait(@mutex) while @list.empty?
54
+ @list.shift
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,199 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module Garcon
21
+
22
+ # ANSI Mixin Module
23
+ #
24
+ # Standard use is to mix this module into String.
25
+ #
26
+ # @example Mix this module into String to enable easy ANSI coloring methods
27
+ # like:
28
+ # "bold red".red.bold
29
+ #
30
+ # @example Or
31
+ # "green".green
32
+ #
33
+ module ANSI
34
+ extend self
35
+
36
+ # Defines our ANSI color codes
37
+ ANSI_COLORS = {
38
+ black: 30,
39
+ red: 31,
40
+ green: 32,
41
+ yellow: 33,
42
+ blue: 34,
43
+ magenta: 35,
44
+ cyan: 36,
45
+ white: 37
46
+ }
47
+
48
+ # @!method black(string=nil, &block)
49
+ # Sets the foreground color to black for the supplied string.
50
+ # @param [String] string The string to operate on.
51
+ # @yieldreturn [String] The string to operate on.
52
+ # @return [String] The colored string.
53
+ #
54
+ # @!method red(string=nil, &block)
55
+ # Sets the foreground color to red for the supplied string.
56
+ # @param [String] string The string to operate on.
57
+ # @yieldreturn [String] The string to operate on.
58
+ # @return [String] The colored string.
59
+ #
60
+ # @!method green(string=nil, &block)
61
+ # Sets the foreground color to green for the supplied string.
62
+ # @param [String] string The string to operate on.
63
+ # @yieldreturn [String] The string to operate on.
64
+ # @return [String] The colored string.
65
+ #
66
+ # @!method yellow(string=nil, &block)
67
+ # Sets the foreground color to yellow for the supplied string.
68
+ # @param [String] string The string to operate on.
69
+ # @yieldreturn [String] The string to operate on.
70
+ # @return [String] The colored string.
71
+ #
72
+ # @!method blue(string=nil, &block)
73
+ # Sets the foreground color to blue for the supplied string.
74
+ # @param [String] string The string to operate on.
75
+ # @yieldreturn [String] The string to operate on.
76
+ # @return [String] The colored string.
77
+ #
78
+ # @!method magenta(string=nil, &block)
79
+ # Sets the foreground color to magenta for the supplied string.
80
+ # @param [String] string The string to operate on.
81
+ # @yieldreturn [String] The string to operate on.
82
+ # @return [String] The colored string.
83
+ #
84
+ # @!method cyan(string=nil, &block)
85
+ # Sets the foreground color to cyan for the supplied string.
86
+ # @param [String] string The string to operate on.
87
+ # @yieldreturn [String] The string to operate on.
88
+ # @return [String] The colored string.
89
+ #
90
+ # @!method white(string=nil, &block)
91
+ # Sets the foreground color to white for the supplied string.
92
+ # @param [String] string The string to operate on.
93
+ # @yieldreturn [String] The string to operate on.
94
+ # @return [String] The colored string.
95
+
96
+ # Defines our ANSI attribute codes
97
+ ANSI_ATTRIBUTES = {
98
+ normal: 0,
99
+ bold: 1
100
+ }
101
+
102
+ # @!method normal(string=nil, &block)
103
+ # Sets the foreground color to normal for the supplied string.
104
+ # @param [String] string The string to operate on.
105
+ # @yieldreturn [String] The string to operate on.
106
+ # @return [String] The colored string.
107
+ #
108
+ # @!method bold(string=nil, &block)
109
+ # Sets the foreground color to bold for the supplied string.
110
+ # @param [String] string The string to operate on.
111
+ # @yieldreturn [String] The string to operate on.
112
+ # @return [String] The colored string.
113
+
114
+ # Defines a RegEx for stripping ANSI codes from strings
115
+ ANSI_REGEX = /\e\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]/
116
+
117
+ # Dynamicly constructs ANSI methods for the color methods based on the ANSI
118
+ # code hash passed in.
119
+ #
120
+ # @param [Hash] hash
121
+ # A hash where the keys represent the method names and the values are the
122
+ # ANSI codes.
123
+ #
124
+ # @return [Boolean]
125
+ # True if successful.
126
+ #
127
+ def build_ansi_methods(hash)
128
+ hash.each do |key, value|
129
+
130
+ define_method(key) do |string=nil, &block|
131
+ result = Array.new
132
+
133
+ result << %(\e[#{value}m)
134
+ if block_given?
135
+ result << block.call
136
+ elsif string.respond_to?(:to_str)
137
+ result << string.to_str
138
+ elsif respond_to?(:to_str)
139
+ result << to_str
140
+ else
141
+ return result
142
+ end
143
+ result << %(\e[0m)
144
+
145
+ result.join
146
+ end
147
+ end
148
+
149
+ true
150
+ end
151
+
152
+ # Removes ANSI code sequences from a string.
153
+ #
154
+ # @param [String] string
155
+ # The string to operate on.
156
+ #
157
+ # @yieldreturn [String]
158
+ # The string to operate on.
159
+ #
160
+ # @return [String]
161
+ # The supplied string stripped of ANSI codes.
162
+ #
163
+ def uncolor(string = nil, &block)
164
+ if block_given?
165
+ block.call.to_str.gsub(ANSI_REGEX, '')
166
+ elsif string.respond_to?(:to_str)
167
+ string.to_str.gsub(ANSI_REGEX, '')
168
+ elsif respond_to?(:to_str)
169
+ to_str.gsub(ANSI_REGEX, '')
170
+ else
171
+ ''
172
+ end
173
+ end
174
+
175
+ def reset(string = nil, &block)
176
+ result = Array.new
177
+
178
+ result << %(\e[2J)
179
+ if block_given?
180
+ result << block.call
181
+ elsif string.respond_to?(:to_str)
182
+ result << string.to_str
183
+ elsif respond_to?(:to_str)
184
+ result << to_str
185
+ else
186
+ return result
187
+ end
188
+
189
+ result.join
190
+ end
191
+
192
+ def goto(x=0, y=0)
193
+ %(\e[#{x};#{y}H)
194
+ end
195
+
196
+ build_ansi_methods(ANSI_COLORS)
197
+ build_ansi_methods(ANSI_ATTRIBUTES)
198
+ end
199
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'securerandom'
21
+
22
+ module Garcon
23
+ module AtRandom
24
+ module ClassMethods
25
+ def at_random(adjectives, nouns)
26
+ build(random_seed, adjectives, nouns)
27
+ end
28
+
29
+ private
30
+
31
+ def build(seed, adjectives, nouns)
32
+ [ adjectives[seed % adjectives.length],
33
+ nouns[seed % nouns.length]
34
+ ].compact.map(&:capitalize).join(' ')
35
+ end
36
+
37
+ def random_seed
38
+ SecureRandom.random_number(4096)
39
+ end
40
+ end
41
+
42
+ def self.included(other)
43
+ other.extend(ClassMethods)
44
+ end
45
+
46
+ extend ClassMethods
47
+ end
48
+
49
+ module Names
50
+ include AtRandom
51
+ ADJECTIVES = %w(autumn hidden bitter misty silent empty dry dark summer
52
+ icy delicate quiet white cool spring winter patient twilight dawn crimson
53
+ wispy weathered blue billowing broken cold damp falling frosty green long
54
+ late lingering bold little morning muddy old red rough still small
55
+ sparkling throbbing shy wandering withered wild black young holy solitary
56
+ fragrant aged snowy proud floral restless divine polished ancient purple
57
+ lively nameless)
58
+
59
+ NOUNS = %w(waterfall river breeze moon rain wind sea morning snow lake
60
+ sunset pine shadow leaf dawn glitter forest hill cloud meadow sun glade
61
+ bird brook butterfly bush dew dust field fire flower firefly feather grass
62
+ haze mountain night pond darkness snowflake silence sound sky shape surf
63
+ thunder violet water wildflower wave water resonance sun wood dream cherry
64
+ tree fog frost voice paper frog smoke star)
65
+ end
66
+
67
+ module Hacker
68
+ include AtRandom
69
+ ADJECTIVES = %w(auxiliary primary back-end digital open-source virtual
70
+ cross-platform redundant online haptic multi-byte bluetooth wireless 1080p
71
+ neural optical solid state mobile)
72
+
73
+ NOUNS = %w(driver protocol bandwidth panel microchip program port card
74
+ array interface system sensor firewall hard drive pixel alarm feed monitor
75
+ application transmitter bus circuit capacitor matrix)
76
+ end
77
+ end
@@ -0,0 +1,292 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ # __ ____ __ __ ____ ______ ___
21
+ # / ]| \ | T T| \| T / \
22
+ # / / | D )| | || o ) |Y Y
23
+ # / / | / | ~ || _/l_j l_j| O |
24
+ # / \_ | \ l___, || | | | | |
25
+ # \ || . Y| !| | | | l !
26
+ # \____jl__j\_jl____/ l__j l__j \___/
27
+ # _____ ____ _ ______ __ __ __ __ ____ _____ __ __
28
+ # / ___/ / T| T | T| T T | T T / T/ ___/| T T
29
+ # ( \_ Y o || | | || | | | l |Y o ( \_ | l |
30
+ # \__ T| || l___l_j l_j| ~ | | _ || |\__ T| _ |
31
+ # / \ || _ || T | | l___, | | | || _ |/ \ || | |
32
+ # \ || | || | | | | ! | | || | |\ || | |
33
+ # \___jl__j__jl_____j l__j l____/ l__j__jl__j__j \___jl__j__j
34
+
35
+ require 'openssl'
36
+ require 'digest/sha2'
37
+ require 'base64'
38
+ require 'securerandom'
39
+
40
+ module Garcon
41
+ # Crypto uses the AES-256-CBC algorithm by default to encrypt strings
42
+ # securely. It uses both an initialization vector (IV) and a salt to perform
43
+ # this encryption as securely as possible.
44
+ #
45
+ # @example
46
+ # Use `#encrypt` to encrypt a string.
47
+ # text = "what is 42?"
48
+ # salt = "9e5f851900cad8892ac8b737b7370cbe"
49
+ # pass = "!mWh0!s@y!m"
50
+ # encrypted_text = Crypto.encrypt(text, set_password, set_salt)
51
+ # # => "+opVpqJhQsD3dbOQ8GAGjmq7slIms2zCQmOrMxJGpqQ=\n"
52
+ #
53
+ # Then to decrypt the string use `#decrypt`.
54
+ # Crypto.decrypt(encrypted_text, pass, salt)
55
+ # # => "what is 42?"
56
+ #
57
+ # You can also set the salt and password on a configuration object.
58
+ # Garcon::Crypto.config do |config|
59
+ # config.password = "!mWh0!s@y!m"
60
+ # config.salt = "9e5f851900cad8892ac8b737b7370cbe"
61
+ # end
62
+ #
63
+ # Now you can #encrypt and #decrypt without specifying a salt and password.
64
+ # encrypted_text = Crypto.encrypt(text)
65
+ # # => "HQRabUG8BcS+yZR8yG9TqQWfFPFYXztRgoQjdAUseFU=\n"
66
+ # Crypto.decrypt(encrypted_text)
67
+ # # => "what is 42?"
68
+ #
69
+ # What you probably want to use this for is directly on a String.
70
+ # encrypted_text = text.encrypt
71
+ # # => "ew2SEyf+09WdPJHRjmBGp4g6C1oSQaDbQiZ/7WEceEc=\n"
72
+ # encrypted_text.decrypt
73
+ # # => "what is 42?"
74
+ #
75
+ # @note
76
+ # The salt needs to be unique per-use per-encrypted string. Every time a
77
+ # string is encrypted, it should be hashed using a new random salt. Never
78
+ # reuse a salt. The salt also needs to be long, so that there are many
79
+ # possible salts. As a rule of thumb, the salt should be at least 32 random
80
+ # bytes. Garcon includes a easy helper for you to generate a random binary
81
+ # string, `String.random_binary(SIZE)`, where size is the size in bytes.
82
+ #
83
+ module Crypto
84
+ extend self
85
+
86
+ # Adds `encrypt` and `decrypt` methods to strings.
87
+ #
88
+ module String
89
+ # Returns a new string containing the encrypted version of itself
90
+ #
91
+ def encrypt(password = nil, salt = nil)
92
+ Garcon::Crypto.encrypt(self, password, salt)
93
+ end
94
+
95
+ # Returns a new string containing the decrypted version of itself
96
+ #
97
+ def decrypt(password = nil, salt = nil)
98
+ Garcon::Crypto.decrypt(self, password, salt)
99
+ end
100
+ end
101
+
102
+ # A Configuration instance
103
+ class Configuration
104
+
105
+ # @!attribute [rw] :password
106
+ # @return [String] access the password for this instance.
107
+ attr_accessor :password
108
+
109
+ # @!attribute [rw] :salt
110
+ # @return [String] access the salt for this instance.
111
+ attr_accessor :salt
112
+
113
+ # Initialized a configuration instance
114
+ #
115
+ # @return [undefined]
116
+ #
117
+ # @api private
118
+ def initialize(options = {})
119
+ @password = options.fetch(:password, nil)
120
+ @salt = options.fetch(:salt, nil)
121
+
122
+ yield self if block_given?
123
+ end
124
+
125
+ # @api private
126
+ def to_h
127
+ { password: password, salt: salt }.freeze
128
+ end
129
+ end
130
+
131
+ # The default size, iterations and cipher encryption algorithm used.
132
+ SALT_BYTE_SIZE = 64
133
+ HASH_BYTE_SIZE = 256
134
+ CRYPTERATIONS = 4096
135
+ CIPHER_TYPE = 'aes-256-cbc'
136
+
137
+ # Encrypt the given string using the AES-256-CBC algorithm.
138
+ #
139
+ # @param [String] plain_text
140
+ # The text to encrypt.
141
+ #
142
+ # @param [String] password
143
+ # Secret passphrase to encrypt with.
144
+ #
145
+ # @param [String] salt
146
+ # A cryptographically secure pseudo-random string (SecureRandom.base64)
147
+ # to add a little spice to your encryption.
148
+ #
149
+ # @return [String]
150
+ # Encrypted text, can be deciphered with #decrypt.
151
+ #
152
+ # @api public
153
+ def encrypt(plain_text, password = nil, salt = nil)
154
+ password = password.nil? ? Garcon.crypto.password : password
155
+ salt = salt.nil? ? Garcon.crypto.salt : salt
156
+
157
+ cipher = new_cipher(:encrypt, password, salt)
158
+ cipher.iv = iv = cipher.random_iv
159
+ ciphertext = cipher.update(plain_text)
160
+ ciphertext << cipher.final
161
+ Base64.encode64(combine_iv_ciphertext(iv, ciphertext))
162
+ end
163
+
164
+ # Decrypt the given string, using the salt and password supplied.
165
+ #
166
+ # @param [String] encrypted_text
167
+ # The text to decrypt, probably produced with #decrypt.
168
+ #
169
+ # @param [String] password
170
+ # Secret passphrase to decrypt with.
171
+ #
172
+ # @param [String] salt
173
+ # The cryptographically secure pseudo-random string used to spice up the
174
+ # encryption of your strings.
175
+ #
176
+ # @return [String]
177
+ # The decrypted plain_text.
178
+ #
179
+ # @api public
180
+ def decrypt(encrypted_text, password = nil, salt = nil)
181
+ password = password.nil? ? Garcon.crypto.password : password
182
+ salt = salt.nil? ? Garcon.crypto.salt : salt
183
+
184
+ iv_ciphertext = Base64.decode64(encrypted_text)
185
+ cipher = new_cipher(:decrypt, password, salt)
186
+ cipher.iv, ciphertext = separate_iv_ciphertext(cipher, iv_ciphertext)
187
+ plain_text = cipher.update(ciphertext)
188
+ plain_text << cipher.final
189
+ plain_text
190
+ end
191
+
192
+ # Generates a special hash known as a SPASH, a PBKDF2-HMAC-SHA1 Salted
193
+ # Password Hash for safekeeping.
194
+ #
195
+ # @param [String] password
196
+ # A password to generating the SPASH, salted password hash.
197
+ #
198
+ # @return [Hash]
199
+ # `:salt` contains the unique salt used, `:pbkdf2` contains the password
200
+ # hash. Save both the salt and the hash together.
201
+ #
202
+ # @see Garcon::Crypto#validate_salt
203
+ #
204
+ # @api public
205
+ def salted_hash(password)
206
+ salt = SecureRandom.random_bytes(SALT_BYTE_SIZE)
207
+ pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
208
+ password, salt, CRYPTERATIONS, HASH_BYTE_SIZE
209
+ )
210
+
211
+ { salt: salt, pbkdf2: Base64.encode64(pbkdf2) }
212
+ end
213
+
214
+ private # P R O P R I E T À P R I V A T A Vietato L'accesso
215
+
216
+ # Validates a salted PBKDF2-HMAC-SHA1 hash of a password.
217
+ #
218
+ # @param [String] password
219
+ # The password used to create the SPASH, salted password hash.
220
+ #
221
+ # @param opts [Hash]
222
+ #
223
+ # @option opts [String] :salt
224
+ # The salt used in generating the SPASH, salted password hash.
225
+ #
226
+ # @option opts [String] :hash
227
+ # The hash produced when salt and password collided in a algorithm of
228
+ # PBKDF2-HMAC-SHA1 love bites (do you tell lies?) hash.
229
+ #
230
+ # @return [Boolean]
231
+ # True if the password is a match, false if ménage à trois of salt, hash
232
+ # and password don't mix.
233
+ #
234
+ # @see Garcon::Crypto#salted_hash
235
+ #
236
+ # @api private
237
+ def validate_salt(password, hash = {})
238
+ pbkdf2 = Base64.decode64(hash[:pbkdf2])
239
+ salty = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
240
+ password, hash[:salt], CRYPTERATIONS, HASH_BYTE_SIZE
241
+ )
242
+ pbkdf2 == salty
243
+ end
244
+
245
+ protected # A T T E N Z I O N E A R E A P R O T E T T A
246
+
247
+ # Create a new cipher machine, with its dials set in the given direction.
248
+ #
249
+ # @param [Symbol] direction
250
+ # Whether to `:encrypt` or `:decrypt`.
251
+ #
252
+ # @param [String] pass
253
+ # Secret passphrase to decrypt with.
254
+ #
255
+ # @api private
256
+ def new_cipher(direction, password, salt)
257
+ cipher = OpenSSL::Cipher::Cipher.new(CIPHER_TYPE)
258
+ direction == :encrypt ? cipher.encrypt : cipher.decrypt
259
+ cipher.key = encrypt_key(password, salt)
260
+ cipher
261
+ end
262
+
263
+ # Prepend the initialization vector to the encoded message.
264
+ #
265
+ # @api private
266
+ def combine_iv_ciphertext(iv, message)
267
+ message.force_encoding('BINARY') if message.respond_to?(:force_encoding)
268
+ iv.force_encoding('BINARY') if iv.respond_to?(:force_encoding)
269
+ iv + message
270
+ end
271
+
272
+ # Pull the initialization vector from the front of the encoded message.
273
+ #
274
+ # @api private
275
+ def separate_iv_ciphertext(cipher, iv_ciphertext)
276
+ idx = cipher.iv_len
277
+ [iv_ciphertext[0..(idx - 1)], iv_ciphertext[idx..-1]]
278
+ end
279
+
280
+ # Convert the password into a PBKDF2-HMAC-SHA1 salted key used for safely
281
+ # encrypting and decrypting all your ciphers strings.
282
+ #
283
+ # @api private
284
+ def encrypt_key(password, salt)
285
+ iterations, length = CRYPTERATIONS, HASH_BYTE_SIZE
286
+ OpenSSL::PKCS5::pbkdf2_hmac_sha1(password, salt, iterations, length)
287
+ end
288
+ end
289
+ end
290
+
291
+ # Adds `encrypt` and `decrypt` methods to strings.
292
+ String.send(:include, Garcon::Crypto::String)