opensecret 0.0.988 → 0.0.9925

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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+
6
+ class Id < Command
7
+
8
+
9
+ def execute
10
+
11
+ puts ""
12
+ puts OpenKey::KeyNow.grab()
13
+ puts OpenKey::KeyNow.fetch()
14
+ puts ""
15
+
16
+ return
17
+
18
+ end
19
+
20
+
21
+ # Perform pre-conditional validations in preparation to executing the main flow
22
+ # of events for this use case. This method may throw the below exceptions.
23
+ #
24
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
25
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
26
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
27
+ def pre_validation
28
+
29
+
30
+ end
31
+
32
+
33
+ end
34
+
35
+
36
+ end
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <b>import use case</b> follows <b>open</b> and it pulls a file into an
8
+ # <em>(encrypted at rest)</em> <b>envelope</b> while writing metadata about
9
+ # the file into the opened tree dictionary position.
10
+ #
11
+ # == import and reimport commands
12
+ #
13
+ # - the import command expects a path parameter and errors if not recvd
14
+ # - the reimport command is happy with either one or zero parameters
15
+ #
16
+ # If the reimport command has no parameters it expects that the opened path
17
+ # already contains an imported file. It uses the import.path key to locate
18
+ # the file.
19
+ #
20
+ # If the path parameter is given to reimport it uses it and also resets the
21
+ # import.path key to reflect the path it was given.
22
+ #
23
+ # == garbage collect dangling files
24
+ #
25
+ # Like dangling envelopes - dangling files will pop up when re-imported.
26
+ # These are handled by the garbage collection policy which can be to
27
+ # remove immediately - remove on next login - remove after a time period
28
+ # or to never remove (manual garbage collection).
29
+ #
30
+ class Import < Command
31
+
32
+ attr_writer :secret_id, :secret_value
33
+
34
+ # The <b>put use case</b> follows <b>open</b> and it adds secrets into an
35
+ # <em>(encrypted at rest)</em> envelope. Put can be called many times to
36
+ # add secrets. Finally the <b>lock use case</b> commits all opened secrets
37
+ # into the configured storage engines.
38
+ #
39
+ # Calling <em>put</em> <b>before</b> calling open or <b>after</b> calling lock
40
+ # is not allowed and will result in an error.
41
+ #
42
+ # == Put Pre-Conditions
43
+ #
44
+ # When the put use case is called - the below conditions ring true.
45
+ #
46
+ # - the <b>folder path</b> ending in ../../my must exist
47
+ # - a session id, filename and encryption key ( in workstation config )
48
+ #
49
+ # == Observable Value
50
+ #
51
+ # The observable value delivered by +put+ boils down to
52
+ #
53
+ # - a new <b>friends.xyz123abc.os.txt</b> file if this is the first put.
54
+ # - a new group_name/key_name (like monica/surname) entry is added if required
55
+ # - a secret value is added against the key or updated if it already exists
56
+ # - a new session id and encryption key is generated and used to re-encrypt
57
+ def execute
58
+
59
+ ## @todo - rename appdb_content as master_db
60
+ ## @todo - rename appdb_content as master_db
61
+ ## @todo - rename appdb_content as master_db
62
+ ## @todo - rename appdb_content as master_db
63
+ ## @todo - rename appdb_content as master_db
64
+ ## @todo - rename appdb_content as master_db
65
+ ## @todo - rename appdb_content as master_db
66
+ ## @todo - rename appdb_content as master_db
67
+ ## @todo - rename appdb_content as master_db
68
+ ## @todo - rename appdb_content as master_db
69
+ ## @todo - rename appdb_content as master_db
70
+ ## @todo - rename appdb_content as master_db
71
+ ## @todo - rename appdb_content as master_db
72
+ ## @todo - rename appdb_content as master_db
73
+
74
+ return unless ops_key_exists?
75
+ appdb_content = OpenKey::KeyApi.read_app_content()
76
+
77
+ puts "---\n"
78
+ puts "--- The Master Database (Before)\n"
79
+ puts "---\n"
80
+ puts JSON.pretty_generate( appdb_content )
81
+ puts "---\n"
82
+
83
+ return if unopened_envelope?( appdb_content )
84
+
85
+ envelope_id = ENVELOPE_KEY_PREFIX + appdb_content[ ENV_PATH ]
86
+ has_content = OpenKey::KeyApi.content_exists?( appdb_content[ envelope_id ] )
87
+
88
+ # --
89
+ # -- To get hold of the content we must either
90
+ # --
91
+ # -- a) unlock it using the breadcrumbs or
92
+ # -- b) start afresh with a new content db
93
+ # --
94
+ content_box = OpenKey::KeyApi.content_unlock( appdb_content[ envelope_id ] ) if has_content
95
+ content_box = OpenKey::KeyDb.new() unless has_content
96
+ content_hdr = create_header()
97
+
98
+ # --
99
+ # -- If no content envelope exists we need to place
100
+ # -- an empty one inside the appdb content database.
101
+ # --
102
+ appdb_content[ envelope_id ] = {} unless has_content
103
+
104
+ # --
105
+ # -- This is the PUT use case so we append a
106
+ # --
107
+ # -- a) key for the new dictionary entry
108
+ # -- b) value for the new dictionary entry
109
+ # --
110
+ # -- into the current content envelope and write
111
+ # -- the envelope to the content filepath.
112
+ # --
113
+ crumbs_dict = appdb_content[ envelope_id ]
114
+ content_box.create_entry( appdb_content[ KEY_PATH ], @secret_id, @secret_value )
115
+ OpenKey::KeyApi.content_lock( crumbs_dict, content_box.to_json, content_hdr )
116
+
117
+ puts "---\n"
118
+ puts "--- The Master Database (After)\n"
119
+ puts "---\n"
120
+ puts JSON.pretty_generate( appdb_content )
121
+ puts "---\n"
122
+
123
+ # --
124
+ # -- Three envelope crumbs namely the external ID, the
125
+ # -- random iv and the crypt key are written afreshinto
126
+ # -- the master database.
127
+ # --
128
+ OpenKey::KeyApi.write_app_content( content_hdr, appdb_content )
129
+ print_put_success
130
+
131
+ return
132
+
133
+
134
+ # ---> secret_ids = @secret_id.split("/")
135
+ # ---> if ( envelope.has_key? secret_ids.first )
136
+ # ---> envelope[secret_ids.first][secret_ids.last] = @secret_value
137
+ # ---> else
138
+ # ---> envelope[secret_ids.first] = { secret_ids.last => @secret_value }
139
+ # ---> end
140
+
141
+ end
142
+
143
+
144
+ private
145
+
146
+
147
+ def print_put_success
148
+
149
+ puts ""
150
+ puts "Success putting a key/value pair into the open envelope."
151
+ puts "You can put more in and then close the envelope."
152
+ puts ""
153
+ puts " ops close"
154
+ puts ""
155
+
156
+ end
157
+
158
+
159
+ # Perform pre-conditional validations in preparation to executing the main flow
160
+ # of events for this use case. This method may throw the below exceptions.
161
+ #
162
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
163
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
164
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
165
+ def pre_validation
166
+
167
+
168
+ end
169
+
170
+
171
+ end
172
+
173
+
174
+ end
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <b>init use case</b> initializes opensecret thus preparing it
8
+ # for the ability to lock secrets, unlock them, transport their keys and
9
+ # much more.
10
+ #
11
+ # opensecret is a <b>(glorified) placeholder</b>. It takes things in now,
12
+ # keeps them safe and gives them back later, in a <b>helpful manner</b>.
13
+ #
14
+ # ---
15
+ #
16
+ # ops init bob@gmail.com $HOME/bob.credentials
17
+ #
18
+ # or
19
+ #
20
+ # xport init bob@gmail.com $HOME/apollo.team.x
21
+ #
22
+ # ---
23
+ #
24
+ # == Alternat Error Flows
25
+ #
26
+ # An error will be thrown
27
+ #
28
+ # - if ops can't create or extend the base directory
29
+ # - if the domain is already in the configuration file
30
+ # - if domain has non alphanums, excl hyphens, underscores, @ symbols, periods
31
+ # - if domain does not begin or end with alphanums.
32
+ # - if non alpha-nums (excl at signs) appear consecutively
33
+ # - if no alpha-nums appear in the string
34
+ # - if the domain string's length is less than 5
35
+ # - if "base.opensecret.io" appears twice (or more) in a directory tree
36
+ #
37
+ class Init < Command
38
+
39
+ attr_writer :master_p4ss, :domain_name, :base_path
40
+
41
+
42
+ # The init use case prepares <b>opensecret</b> so that you can <b>open</b> an envelope,
43
+ # <b>put</b> secrets into it and then <b>seal</b> (lock) it. Locking effectively writes
44
+ # crypted blocks to both keystore and crypt store.
45
+ #
46
+ # ops init apollo@work $HOME/apollo.work.drive
47
+ #
48
+ def execute
49
+
50
+ return unless ops_key_exists?
51
+
52
+ OpenKey::KeyApi.init_app_domain( @domain_name, @base_path )
53
+ keys_setup = OpenKey::KeyApi.is_domain_keys_setup?( @domain_name )
54
+
55
+ if ( keys_setup )
56
+ print_already_initialized
57
+ return
58
+ end
59
+
60
+ domain_password = OpenKey::KeyPass.password_from_shell( true )
61
+ OpenKey::KeyApi.setup_domain_keys( @domain_name, domain_password, create_header() )
62
+ print_domain_initialized
63
+
64
+ # --> unless @base_path.nil?
65
+ # --> key_api.register_keystore( @base_path )
66
+ # --> end
67
+
68
+ end
69
+
70
+
71
+ def pre_validation
72
+ end
73
+
74
+
75
+ end
76
+
77
+
78
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <b>login use case</b> is given the domain name and if needs be
8
+ # it collects the password then (if correct) logs the user in.
9
+ #
10
+ # Here are some key facts about the login command
11
+ #
12
+ # - its domain name parameter is mandatory
13
+ # - it is called at the start of every session
14
+ # - it is undone by the logout command
15
+ # - it requires the OPEN_SESSION_TOKEN environment variable
16
+ # - you can nest login commands thus using multiple domains
17
+ # - you can call it with a --with=password switch
18
+ # - you can deliver the password in multiple ways
19
+ class Login < Command
20
+
21
+ attr_writer :master_p4ss, :domain_name
22
+
23
+
24
+ def execute
25
+
26
+ return unless ops_key_exists?
27
+
28
+ unless ( OpenKey::KeyApi.is_domain_keys_setup?( @domain_name ) )
29
+ print_not_initialized
30
+ return
31
+ end
32
+
33
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
34
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
35
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
36
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
37
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
38
+ ############## Call [[ KeyApi.is_logged_in? ]] - then print msg and skip password collection below
39
+
40
+ domain_secret = OpenKey::KeyPass.password_from_shell( false )
41
+
42
+ ############## Use [[ KeyApi.valid_password? ]] and give error if not valid
43
+ ############## Use [[ KeyApi.valid_password? ]] and give error if not valid
44
+ ############## Use [[ KeyApi.valid_password? ]] and give error if not valid
45
+ ############## Use [[ KeyApi.valid_password? ]] and give error if not valid
46
+ ############## Use [[ KeyApi.valid_password? ]] and give error if not valid
47
+
48
+ OpenKey::KeyApi.do_login( @domain_name, domain_secret, create_header() )
49
+ print_login_success
50
+
51
+ end
52
+
53
+
54
+ # Perform pre-conditional validations in preparation to executing the main flow
55
+ # of events for this use case. This method may throw the below exceptions.
56
+ #
57
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
58
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
59
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
60
+ def pre_validation
61
+
62
+ end
63
+
64
+
65
+ end
66
+
67
+
68
+ end
69
+
70
+
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ class Logout < Command
8
+
9
+ def execute
10
+
11
+ end
12
+
13
+
14
+ # Perform pre-conditional validations in preparation to executing the main flow
15
+ # of events for this use case. This method may throw the below exceptions.
16
+ #
17
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
18
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
19
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
20
+ def pre_validation
21
+
22
+ end
23
+
24
+
25
+ end
26
+
27
+
28
+ end
29
+
30
+
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <tt>open use case</tt> allows us to add (put), subtract (del)ete, change
8
+ # (update) and list the secrets within an envelope (outer path) at a given
9
+ # position (inner path), whether that envelope exists or not.
10
+ #
11
+ # Also see the <b>reopen</b> command which only differs from open in that it
12
+ # fails if the path specified does not exist in either the sealed or session
13
+ # envelopes.
14
+ #
15
+ # == The Open Path Parameter
16
+ #
17
+ # Open must be called with a single <b>path</b> parameter with an optional
18
+ # single colon separating the outer (path to envelope) from the inner (path
19
+ # within envelope).
20
+ #
21
+ # ops open aws.credentials:s3reader
22
+ #
23
+ # The outer and inner paths can contain forward slashes that segment the path.
24
+ #
25
+ # ops open production/aws.credentials:s3/s3reader
26
+ # ops put access_key ABCD1234
27
+ # ops put secret_key FGHIJ56789
28
+ # ops put region_key eu-central-1
29
+ # ops seal
30
+ #
31
+ # == Open (Path) Pre-Conditions
32
+ #
33
+ # The domain must have been initialized on this machine stating the path to
34
+ # the base folder that contains the key and crypt material.
35
+ #
36
+ # To open a path these conditions must be true.
37
+ #
38
+ # - the shell session token must have been set at the session beginning
39
+ # - a successful <tt>ops login</tt> command must have been issued
40
+ # - the external drive (eg usb key) must be configured and accessible
41
+ #
42
+ # == Observable Value
43
+ #
44
+ # $ ops open home/wifi
45
+ #
46
+ # The observable value delivered by +[open]+ boils down to
47
+ #
48
+ # - an openkey (eg asdfx1234) and corresponding open encryption key
49
+ # - open encryption key written to <tt>~/.opensecret/open.keys/asdfx1234.x.txt</tt>
50
+ # - the opened path (ending in filename) written to session.cache base in [safe]
51
+ # - the INI string (were the file to be decrypted) would look like the below
52
+ #
53
+ # [session]
54
+ # base.path = home/wifi
55
+ #
56
+ class Open < Command
57
+
58
+ # The two paths that have been posted to the open command.
59
+ # First is a relative path to the obfuscated envelope and then
60
+ # the path in envelope to the point of interest.
61
+ attr_writer :env_path, :key_path
62
+
63
+ def execute
64
+
65
+ return unless ops_key_exists?
66
+ appdb_content = OpenKey::KeyApi.read_app_content()
67
+
68
+ puts "---\n"
69
+ puts "--- The Master Database (Before)\n"
70
+ puts "---\n"
71
+ puts JSON.pretty_generate( appdb_content )
72
+ puts "---\n"
73
+
74
+ appdb_content[ ENV_PATH ] = @env_path
75
+ appdb_content[ KEY_PATH ] = @key_path
76
+
77
+ puts "---\n"
78
+ puts "--- The Master Database (After)\n"
79
+ puts "---\n"
80
+ puts JSON.pretty_generate( appdb_content )
81
+ puts "---\n"
82
+
83
+ OpenKey::KeyApi.write_app_content( create_header(), appdb_content )
84
+ print_open_success
85
+
86
+ return
87
+
88
+ end
89
+
90
+
91
+ private
92
+
93
+
94
+ def print_open_success
95
+
96
+ puts ""
97
+ puts "Success opening a path to a data bucket."
98
+ puts "You can now put data into a dictionary or"
99
+ puts "add it to a list or set a scalar value."
100
+ puts ""
101
+ puts " ops put aws.iam.usr joebloggs"
102
+ puts " ops put access.key ABCD1234"
103
+ puts " ops put secret.key FGHIJ56789"
104
+ puts " ops put region.key eu-central-1"
105
+ puts " ops close"
106
+ puts ""
107
+
108
+ end
109
+
110
+
111
+ # Perform pre-conditional validations in preparation to executing the main flow
112
+ # of events for this use case. This method may throw the below exceptions.
113
+ #
114
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
115
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
116
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
117
+ def pre_validation
118
+
119
+
120
+ end
121
+
122
+
123
+ end
124
+
125
+
126
+ end