opensecret 0.0.988 → 0.0.9925

Sign up to get free protection for your applications and to get access to all the features.
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