safedb 0.01.0001
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +793 -0
- data/Rakefile +16 -0
- data/bin/safe +5 -0
- data/lib/configs/README.md +58 -0
- data/lib/extension/array.rb +162 -0
- data/lib/extension/dir.rb +35 -0
- data/lib/extension/file.rb +123 -0
- data/lib/extension/hash.rb +33 -0
- data/lib/extension/string.rb +572 -0
- data/lib/factbase/facts.safedb.net.ini +38 -0
- data/lib/interprete.rb +462 -0
- data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
- data/lib/keytools/kdf.api.rb +243 -0
- data/lib/keytools/kdf.bcrypt.rb +265 -0
- data/lib/keytools/kdf.pbkdf2.rb +262 -0
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1391 -0
- data/lib/keytools/key.db.rb +330 -0
- data/lib/keytools/key.docs.rb +195 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.ident.rb +243 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +259 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +585 -0
- data/lib/logging/gem.logging.rb +132 -0
- data/lib/modules/README.md +43 -0
- data/lib/modules/cryptology/aes-256.rb +154 -0
- data/lib/modules/cryptology/amalgam.rb +70 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +138 -0
- data/lib/modules/cryptology/crypt.io.rb +225 -0
- data/lib/modules/cryptology/engineer.rb +99 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/modules/storage/git.store.rb +399 -0
- data/lib/session/fact.finder.rb +334 -0
- data/lib/session/require.gem.rb +112 -0
- data/lib/session/time.stamp.rb +340 -0
- data/lib/session/user.home.rb +49 -0
- data/lib/usecase/cmd.rb +487 -0
- data/lib/usecase/config/README.md +57 -0
- data/lib/usecase/docker/README.md +146 -0
- data/lib/usecase/docker/docker.rb +49 -0
- data/lib/usecase/edit/README.md +43 -0
- data/lib/usecase/edit/delete.rb +46 -0
- data/lib/usecase/export.rb +40 -0
- data/lib/usecase/files/README.md +37 -0
- data/lib/usecase/files/eject.rb +56 -0
- data/lib/usecase/files/file_me.rb +78 -0
- data/lib/usecase/files/read.rb +169 -0
- data/lib/usecase/files/write.rb +89 -0
- data/lib/usecase/goto.rb +57 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +157 -0
- data/lib/usecase/init.rb +63 -0
- data/lib/usecase/jenkins/README.md +146 -0
- data/lib/usecase/jenkins/jenkins.rb +208 -0
- data/lib/usecase/login.rb +71 -0
- data/lib/usecase/logout.rb +28 -0
- data/lib/usecase/open.rb +71 -0
- data/lib/usecase/print.rb +40 -0
- data/lib/usecase/put.rb +81 -0
- data/lib/usecase/set.rb +44 -0
- data/lib/usecase/show.rb +138 -0
- data/lib/usecase/terraform/README.md +91 -0
- data/lib/usecase/terraform/terraform.rb +121 -0
- data/lib/usecase/token.rb +35 -0
- data/lib/usecase/update/README.md +55 -0
- data/lib/usecase/update/rename.rb +180 -0
- data/lib/usecase/use.rb +41 -0
- data/lib/usecase/verse.rb +20 -0
- data/lib/usecase/view.rb +71 -0
- data/lib/usecase/vpn/README.md +150 -0
- data/lib/usecase/vpn/vpn.ini +31 -0
- data/lib/usecase/vpn/vpn.rb +54 -0
- data/lib/version.rb +3 -0
- data/safedb.gemspec +34 -0
- metadata +193 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# This docker use case handles the ...
|
6
|
+
#
|
7
|
+
# safe docker login
|
8
|
+
# safe docker logout
|
9
|
+
|
10
|
+
class Docker < UseCase
|
11
|
+
|
12
|
+
# The command which currently must be login, logout or
|
13
|
+
# an empty string.
|
14
|
+
attr_writer :command
|
15
|
+
|
16
|
+
def execute
|
17
|
+
|
18
|
+
return unless ops_key_exists?
|
19
|
+
master_db = get_master_database()
|
20
|
+
return if unopened_envelope?( master_db )
|
21
|
+
|
22
|
+
# Get the open chapter identifier (id).
|
23
|
+
# Decide whether chapter already exists.
|
24
|
+
# Then get (or instantiate) the chapter's hash data structure
|
25
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
26
|
+
verse_id = master_db[ KEY_PATH ]
|
27
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
28
|
+
|
29
|
+
# Unlock the chapter data structure by supplying
|
30
|
+
# key/value mini-dictionary breadcrumbs sitting
|
31
|
+
# within the master database at the section labelled
|
32
|
+
# envelope@<<actual_chapter_id>>.
|
33
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) )
|
34
|
+
|
35
|
+
key_value_dictionary = chapter_data[ verse_id ]
|
36
|
+
docker_username = key_value_dictionary[ "docker.username" ]
|
37
|
+
docker_password = key_value_dictionary[ "@docker.password" ]
|
38
|
+
docker_login_cmd = "docker login --username #{docker_username} --password #{docker_password} 2>/dev/null"
|
39
|
+
docker_logout_cmd = "docker logout"
|
40
|
+
docker_cmd = @command.eql?( "logout" ) ? docker_logout_cmd : docker_login_cmd
|
41
|
+
system docker_cmd
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
### safe put | safe delete | safe copy | safe paste
|
3
|
+
|
4
|
+
# edit use cases | copy | paste | delete
|
5
|
+
|
6
|
+
The edit use cases create, delete and update the credentials and configuration inside your safe.
|
7
|
+
|
8
|
+
## Common Usage
|
9
|
+
|
10
|
+
Typically you login to a book, open a chapter and verse, then you put **`key/value`** pairs, known as **lines**.
|
11
|
+
|
12
|
+
```
|
13
|
+
safe login joe@home
|
14
|
+
|
15
|
+
# -- -------------------------------------------------- -- #
|
16
|
+
# -- Create chapter (email) and verse <<email-address>> -- #
|
17
|
+
# -- -------------------------------------------------- -- #
|
18
|
+
safe open email joebloggs@gmail.com
|
19
|
+
|
20
|
+
# -- ---------------------------- -- #
|
21
|
+
# -- Populate it with credentials -- #
|
22
|
+
# -- ---------------------------- -- #
|
23
|
+
safe put gmail.id joebloggs
|
24
|
+
safe put @password s3cr3et
|
25
|
+
safe put recovery.phone 07500875278
|
26
|
+
|
27
|
+
# -- ----------------------------------------------- -- #
|
28
|
+
# -- Now copy and then paste a line (key/value pair) -- #
|
29
|
+
# -- ----------------------------------------------- -- #
|
30
|
+
safe copy recovery.phone
|
31
|
+
safe open email joe@ywork.com
|
32
|
+
safe paste
|
33
|
+
```
|
34
|
+
|
35
|
+
## editing behaviour
|
36
|
+
|
37
|
+
**These use cases are intuitive and behave almost like what you would expect.** The safe ethos is for commands to behave according to which of the 5 levels you are at.
|
38
|
+
|
39
|
+
|
40
|
+
| Command | Verse | Chapter | Book |
|
41
|
+
|:---------------- |:----------------------------- |:-------------------------------- |:------------------------------- |
|
42
|
+
| safe copy <<id>> | Copy one of the verse's lines | Copy one of the chapter's verses | Copy one of the book's chapters |
|
43
|
+
| safe copy | Copy all of the verse's lines | Copy all of the chapter's verses | Copy all of the book's chapters |
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>delete use case</b> delete's one or more of the safe's entities.
|
6
|
+
#
|
7
|
+
# - at <tt>verse</tt> level - it can delete one or more lines
|
8
|
+
# - at <tt>chapter</tt> level - it can delete one or more verses
|
9
|
+
# - at <tt>book</tt> level - it can delete one or more chapters
|
10
|
+
# - at <tt>safe</tt> level - it can delete one book
|
11
|
+
#
|
12
|
+
class DeleteMe < UseCase
|
13
|
+
|
14
|
+
attr_writer :entity_id
|
15
|
+
|
16
|
+
# Deletion that currently expects an open chapter and verse and always
|
17
|
+
# wants to delete only one line (key/value pair).
|
18
|
+
def execute
|
19
|
+
|
20
|
+
return unless ops_key_exists?
|
21
|
+
master_db = KeyApi.read_master_db()
|
22
|
+
return if unopened_envelope?( master_db )
|
23
|
+
|
24
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
25
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
26
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) ) if chapter_exists
|
27
|
+
chapter_data = KeyDb.new() unless chapter_exists
|
28
|
+
|
29
|
+
content_hdr = create_header()
|
30
|
+
master_db[ chapter_id ] = {} unless chapter_exists
|
31
|
+
verse_id = master_db[ KEY_PATH ]
|
32
|
+
|
33
|
+
chapter_data.delete_entry( verse_id, @entity_id )
|
34
|
+
chapter_data.delete_entry( verse_id, "#{FILE_KEY_PREFIX}#{@entity_id}" )
|
35
|
+
|
36
|
+
KeyApi.content_lock( master_db[ chapter_id ], chapter_data.to_json, content_hdr )
|
37
|
+
KeyApi.write_master_db( content_hdr, master_db )
|
38
|
+
Show.new.flow_of_events
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# Export the entire book if no chapter and verse is specified (achieved with a safe close),
|
6
|
+
# or the chapter if only the chapter is open (safe shut or safe open <<chapter>>, or the
|
7
|
+
# mini-dictionary at the verse if both chapter and verse are open.
|
8
|
+
class Export < UseCase
|
9
|
+
|
10
|
+
def get_chapter_data( chapter_key )
|
11
|
+
return KeyDb.from_json( KeyApi.content_unlock( chapter_key ) )
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
|
16
|
+
return unless ops_key_exists?
|
17
|
+
master_db = KeyApi.read_master_db()
|
18
|
+
|
19
|
+
return if unopened_envelope?( master_db )
|
20
|
+
|
21
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
22
|
+
has_chapter = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
23
|
+
|
24
|
+
unless has_chapter
|
25
|
+
puts "{}"
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
chapter_data = get_chapter_data( master_db[ chapter_id ] )
|
30
|
+
puts JSON.pretty_generate( chapter_data )
|
31
|
+
|
32
|
+
return
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
# safe file | ingest and eject files
|
3
|
+
|
4
|
+
You ingest a file with **safe file** and then **safe eject** will output that file into the present working directory.
|
5
|
+
|
6
|
+
If safe detects during an eject, that a file already exists with the same name - it backs it up with a timestamp before ejecting and clobbering the existing file.
|
7
|
+
|
8
|
+
```bash
|
9
|
+
safe open <<chapter-name>> <<verse-name>>
|
10
|
+
safe file <<keyname>> <</path/to/private-key.pem>>
|
11
|
+
safe eject <<keyname>>
|
12
|
+
safe show
|
13
|
+
```
|
14
|
+
|
15
|
+
To pull in 3 certificate oriented files for Kubernetes one could use these commands.
|
16
|
+
|
17
|
+
```bash
|
18
|
+
safe open production kubernetes
|
19
|
+
safe file kubernetes.cert ~/.kubectl/kube.prod.cert.pem
|
20
|
+
safe file kubernetes.ca.cert ~/.kubectl/kube.prod.ca.cert.pem
|
21
|
+
safe file kubernetes.key ~/.kubectl/kube.prod.key.pem
|
22
|
+
cd /tmp
|
23
|
+
safe eject
|
24
|
+
```
|
25
|
+
|
26
|
+
The safe ingests the files and spits them out whenever you so desire.
|
27
|
+
**Binary files** are supported and can be safely pulled in with <tt>safe file</tt> and ejected at any point in the future.
|
28
|
+
|
29
|
+
## remote (external) files
|
30
|
+
|
31
|
+
The **local filesystem** is the most common, but by no means the only file storage location. You can read from and write to
|
32
|
+
|
33
|
+
- a zip file **`zip://`**
|
34
|
+
- an S3 filesystem **`s3://`**
|
35
|
+
- SSH locations **`<<user>>@<<hostname>>:/path/to/file`**
|
36
|
+
- a git repository **`git@github.com`**
|
37
|
+
- a **google drive** store
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>eject use case</b> writes (or overwrites) a file or files.
|
6
|
+
# Files are always ejected into the present working directory. If an
|
7
|
+
# overwrite is detected a backup is taken of the about to be clobbered
|
8
|
+
# file.
|
9
|
+
#
|
10
|
+
# If a keyname is provided then only the file against that key is ejected.
|
11
|
+
# No keyname will eject every file in the opened chapter and verse.
|
12
|
+
class Eject < UseCase
|
13
|
+
|
14
|
+
attr_writer :file_key
|
15
|
+
|
16
|
+
# Files are always ejected into the present working directory and any
|
17
|
+
# about to be clobbered files are backed up with a timestamp.
|
18
|
+
#
|
19
|
+
# If a keyname is provided then only the file against that key is ejected.
|
20
|
+
# No keyname will eject every file in the opened chapter and verse.
|
21
|
+
def execute
|
22
|
+
|
23
|
+
return unless ops_key_exists?
|
24
|
+
master_db = get_master_database()
|
25
|
+
return if unopened_envelope?( master_db )
|
26
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
27
|
+
verse_id = master_db[ KEY_PATH ]
|
28
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) )
|
29
|
+
|
30
|
+
base64_content = chapter_data[ verse_id ][ "#{FILE_KEY_PREFIX}#{@file_key}" ][ FILE_CONTENT_KEY ]
|
31
|
+
simple_filename = chapter_data[ verse_id ][ "#{FILE_KEY_PREFIX}#{@file_key}" ][ FILE_NAME_KEY ]
|
32
|
+
file_full_path = File.join( Dir.pwd, simple_filename )
|
33
|
+
backup_filename = KeyNow.yyjjj_hhmm_sst() + "-" + simple_filename
|
34
|
+
backup_file_path = File.join( Dir.pwd, backup_filename )
|
35
|
+
will_clobber = File.file?( file_full_path )
|
36
|
+
|
37
|
+
File.write( backup_file_path, File.read( file_full_path ) ) if will_clobber
|
38
|
+
::File.write( file_full_path, Base64.urlsafe_decode64( base64_content ) )
|
39
|
+
|
40
|
+
puts ""
|
41
|
+
puts "File successfully ejected from safe into current directory."
|
42
|
+
puts ""
|
43
|
+
puts "Clobbered File = #{backup_filename}" if will_clobber
|
44
|
+
puts "Current Directory = #{Dir.pwd}"
|
45
|
+
puts "Ejected Filename = #{simple_filename}"
|
46
|
+
puts "Chapter and Verse = #{master_db[ENV_PATH]}:#{verse_id}"
|
47
|
+
puts "Ejected File Key = #{@file_key}"
|
48
|
+
puts ""
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>file use case</b> pulls a file in from either an accessible filesystem
|
6
|
+
# or from a remote http, https, git, S3, GoogleDrive and/or ssh source.
|
7
|
+
#
|
8
|
+
# The @file_url is the most common parameter given to this use case.
|
9
|
+
class FileMe < UseCase
|
10
|
+
|
11
|
+
attr_writer :file_key, :file_url
|
12
|
+
|
13
|
+
# There are 3 maps involved in the implementation and they are all (or in part) retrieved and/or
|
14
|
+
# created as necessary. They are
|
15
|
+
#
|
16
|
+
# - the current chapter as a map
|
17
|
+
# - the current verse as a map
|
18
|
+
# - the file's keyname as a map
|
19
|
+
#
|
20
|
+
# Once the maps have been found and/or created if necessary the file's keyname map is either
|
21
|
+
# populated or amended with the following data.
|
22
|
+
#
|
23
|
+
# - filename | {UseCase::FILE_NAME_KEY} | the file's simple name
|
24
|
+
# - content64 | {UseCase::FILE_CONTENT_KEY} | the file's base64 content
|
25
|
+
def execute
|
26
|
+
|
27
|
+
return unless ops_key_exists?
|
28
|
+
master_db = KeyApi.read_master_db()
|
29
|
+
return if unopened_envelope?( master_db )
|
30
|
+
|
31
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
32
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
33
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) ) if chapter_exists
|
34
|
+
chapter_data = KeyDb.new() unless chapter_exists
|
35
|
+
|
36
|
+
content_hdr = create_header()
|
37
|
+
master_db[ chapter_id ] = {} unless chapter_exists
|
38
|
+
verse_id = master_db[ KEY_PATH ]
|
39
|
+
|
40
|
+
file_full_path = ::File.absolute_path( @file_url )
|
41
|
+
file_base_name = ::File.basename( file_full_path )
|
42
|
+
file_content64 = Base64.urlsafe_encode64( ::File.read( file_full_path ) )
|
43
|
+
|
44
|
+
log.info(x) { "Key name of the file to ingest => #{@file_key}" }
|
45
|
+
log.info(x) { "Ingesting file at path => #{file_full_path}" }
|
46
|
+
log.info(x) { "The name of the file to ingest is => #{file_base_name}" }
|
47
|
+
log.info(x) { "Size of base64 file content => [#{file_content64.length}]" }
|
48
|
+
|
49
|
+
chapter_data.create_map_entry( verse_id, "#{FILE_KEY_PREFIX}#{@file_key}", FILE_NAME_KEY, file_base_name )
|
50
|
+
chapter_data.create_map_entry( verse_id, "#{FILE_KEY_PREFIX}#{@file_key}", FILE_CONTENT_KEY, file_content64 )
|
51
|
+
|
52
|
+
KeyApi.content_lock( master_db[ chapter_id ], chapter_data.to_json, content_hdr )
|
53
|
+
KeyApi.write_master_db( content_hdr, master_db )
|
54
|
+
|
55
|
+
Show.new.flow_of_events
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
|
63
|
+
# Perform pre-conditional validations in preparation to executing the main flow
|
64
|
+
# of events for this use case. This method may throw the below exceptions.
|
65
|
+
#
|
66
|
+
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
67
|
+
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
68
|
+
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
69
|
+
def pre_validation
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>read use case</b> pulls a file in from either an accessible filesystem
|
6
|
+
# or from a remote http, https, git, S3, GoogleDrive and/or ssh source.
|
7
|
+
#
|
8
|
+
# This use case expects a @file_url parameter. The actions it takes are to
|
9
|
+
#
|
10
|
+
# - register @in.url to mirror @file_url
|
11
|
+
# - register @out.url to mirror @file_url
|
12
|
+
# - check the location of @file_url
|
13
|
+
# - if no file exists it humbly finishes up
|
14
|
+
#
|
15
|
+
# If a file does exist at the @in.url this use case
|
16
|
+
#
|
17
|
+
# - handles HOME directory enabling portability
|
18
|
+
# - creates an encryption key and random iv
|
19
|
+
# - creates a file (name) id
|
20
|
+
# - stores the file byte and human readable size
|
21
|
+
# - stores the extension if it has one
|
22
|
+
# - stores the last created date
|
23
|
+
# - stores the last modified date
|
24
|
+
# - stores the (now) in date
|
25
|
+
#
|
26
|
+
# Once done it displays <b><em>key facts about the file</em></b>.
|
27
|
+
class Read < UseCase
|
28
|
+
|
29
|
+
# -- ---------------------- --#
|
30
|
+
# -- ---------------------- --#
|
31
|
+
# -- [SAFE] Name Changes --#
|
32
|
+
# -- ---------------------- --#
|
33
|
+
# -- Change env.path ~> open.chapter
|
34
|
+
# -- Change key.path ~> open.verse
|
35
|
+
# -- Change envelope@xxxx ~> chapter@xxxx
|
36
|
+
# --
|
37
|
+
# -- Change filenames to ~~~~~> book.db.breadcrumbs
|
38
|
+
# -- Change filenames to ~~~~~> chapter.cipher.file
|
39
|
+
# -- Change filenames to ~~~~~> safe.db.abc123xyzpq
|
40
|
+
# -- ---------------------- --#
|
41
|
+
# -- {
|
42
|
+
# -- "db.create.date": "Sat Aug 11 11:20:16 2018 ( 18223.1120.07.511467675 )",
|
43
|
+
# -- "db.domain.name": "ab.com",
|
44
|
+
# -- "db.domain.id": "uhow-ku9l",
|
45
|
+
# -- "env.path": "aa",
|
46
|
+
# -- "key.path": "aa",
|
47
|
+
# -- "envelope@aa": {
|
48
|
+
# -- "content.xid": "3uzk12dxity",
|
49
|
+
# -- "content.iv": "XTVe%qIGKVvWw@EKcgSa153nfVPaMVJH",
|
50
|
+
# -- "content.key": "1u3b2o6KLiAUmt11yYEDThJw1E5Mh4%1iHYOpJQjWiYLthUGgl8IZ5szus8Fz2Jt"
|
51
|
+
# -- }
|
52
|
+
# -- }
|
53
|
+
# -- ---------------------- --#
|
54
|
+
# -- ---------------------- --#
|
55
|
+
|
56
|
+
attr_writer :file_url
|
57
|
+
|
58
|
+
# The <b>read use case</b> pulls a file in from either an accessible filesystem
|
59
|
+
# or from a remote http, https, git, S3, GoogleDrive and/or ssh source.
|
60
|
+
def execute
|
61
|
+
|
62
|
+
return unless ops_key_exists?
|
63
|
+
master_db = KeyApi.read_master_db()
|
64
|
+
return if unopened_envelope?( master_db )
|
65
|
+
|
66
|
+
# -- Get the open chapter identifier (id).
|
67
|
+
# -- Decide whether chapter already exists.
|
68
|
+
# -- Then get (or instantiate) the chapter's hash data structure
|
69
|
+
# --
|
70
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
71
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
72
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) ) if chapter_exists
|
73
|
+
chapter_data = KeyDb.new() unless chapter_exists
|
74
|
+
|
75
|
+
content_hdr = create_header()
|
76
|
+
|
77
|
+
# -- If no content envelope exists we need to place
|
78
|
+
# -- an empty one inside the appdb content database.
|
79
|
+
# --
|
80
|
+
master_db[ chapter_id ] = {} unless chapter_exists
|
81
|
+
|
82
|
+
# -- We populate (PUT) file instance attributes into
|
83
|
+
# -- the mini-dictionary at the [VERSE] location.
|
84
|
+
# --
|
85
|
+
verse_id = master_db[ KEY_PATH ]
|
86
|
+
file_absolute_path = ::File.absolute_path( @file_url )
|
87
|
+
chapter_data.create_entry( verse_id, "@in.url", file_absolute_path )
|
88
|
+
chapter_data.create_entry( verse_id, "@out.url", file_absolute_path )
|
89
|
+
|
90
|
+
# -- Lock No.1
|
91
|
+
# --
|
92
|
+
# -- Lock the file content and leave the 3 breadcrumbs
|
93
|
+
# -- (content id, content iv and content key) inside
|
94
|
+
# -- the file attributes mini dictionary to facilitate
|
95
|
+
# -- decrypting and writing out the file again.
|
96
|
+
# --
|
97
|
+
KeyApi.content_lock( chapter_data[ verse_id ], ::File.read( @file_url ), content_hdr )
|
98
|
+
|
99
|
+
# -- Lock No.2
|
100
|
+
# --
|
101
|
+
# -- Lock the chapter's data which includes the new or
|
102
|
+
# -- updated mini-dictionary that holds the breadcrumbs
|
103
|
+
# -- (content id, content iv and content key) that will
|
104
|
+
# -- be used to decrypt and write out the file content.
|
105
|
+
# --
|
106
|
+
# -- Leave another set of breadcrumbs inside the master
|
107
|
+
# -- database (content id, content iv and content key)
|
108
|
+
# -- to facilitate decrypting the chapter's data.
|
109
|
+
# --
|
110
|
+
KeyApi.content_lock( master_db[ chapter_id ], chapter_data.to_json, content_hdr )
|
111
|
+
|
112
|
+
# -- Lock No.3
|
113
|
+
# --
|
114
|
+
# -- Re-lock the master database including the breadcrumbs
|
115
|
+
# -- (content id, content iv and content key) that will
|
116
|
+
# -- (in the future) decrypt this chapter's data.
|
117
|
+
# --
|
118
|
+
KeyApi.write_master_db( content_hdr, master_db )
|
119
|
+
|
120
|
+
|
121
|
+
# -- Communicate that the indicated file has just been
|
122
|
+
# -- successfully ingested into the safe.
|
123
|
+
# --
|
124
|
+
print_file_success master_db[ ENV_PATH ], verse_id, file_absolute_path
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
|
132
|
+
def print_file_success chapter_id, verse_id, file_url
|
133
|
+
|
134
|
+
puts ""
|
135
|
+
puts "|-"
|
136
|
+
puts "|- Chapter ~> #{chapter_id}"
|
137
|
+
puts "|- + Verse ~> #{verse_id}"
|
138
|
+
puts "|-"
|
139
|
+
puts "|- In File ~> #{file_url}"
|
140
|
+
puts "|-"
|
141
|
+
puts "|- File cocooned inside your safe."
|
142
|
+
puts "|-"
|
143
|
+
puts "|-Command Options"
|
144
|
+
puts "|-"
|
145
|
+
puts "|- #{COMMANDMENT} put out.dir ~/this/folder"
|
146
|
+
puts "|- #{COMMANDMENT} put out.name new-filename.txt"
|
147
|
+
puts "|- #{COMMANDMENT} write"
|
148
|
+
puts "|-"
|
149
|
+
puts ""
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Perform pre-conditional validations in preparation to executing the main flow
|
155
|
+
# of events for this use case. This method may throw the below exceptions.
|
156
|
+
#
|
157
|
+
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
158
|
+
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
159
|
+
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
160
|
+
def pre_validation
|
161
|
+
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>write use case</b> writes (or overwrites) a file at the
|
6
|
+
# out url destination.
|
7
|
+
class Write < UseCase
|
8
|
+
|
9
|
+
attr_writer :file_url
|
10
|
+
|
11
|
+
# The <b>read use case</b> pulls a file in from either an accessible filesystem
|
12
|
+
# or from a remote http, https, git, S3, GoogleDrive and/or ssh source.
|
13
|
+
def execute
|
14
|
+
|
15
|
+
return unless ops_key_exists?
|
16
|
+
master_db = get_master_database()
|
17
|
+
return if unopened_envelope?( master_db )
|
18
|
+
|
19
|
+
# Get the open chapter identifier (id).
|
20
|
+
# Decide whether chapter already exists.
|
21
|
+
# Then get (or instantiate) the chapter's hash data structure
|
22
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
23
|
+
verse_id = master_db[ KEY_PATH ]
|
24
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
25
|
+
|
26
|
+
|
27
|
+
# @todo begin
|
28
|
+
# Throw an exception (error) if the chapter
|
29
|
+
# either exists and is empty or does not exist.
|
30
|
+
# @todo end
|
31
|
+
|
32
|
+
|
33
|
+
# Unlock the chapter data structure by supplying
|
34
|
+
# key/value mini-dictionary breadcrumbs sitting
|
35
|
+
# within the master database at the section labelled
|
36
|
+
# envelope@<<actual_chapter_id>>.
|
37
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) )
|
38
|
+
|
39
|
+
|
40
|
+
# Unlock the file content by supplying the
|
41
|
+
# key/value mini-dictionary breadcrumbs sitting
|
42
|
+
# within the chapter's data structure in the
|
43
|
+
# section labelled <<verse_id>>.
|
44
|
+
file_content = KeyApi.content_unlock( chapter_data[ verse_id ] )
|
45
|
+
|
46
|
+
|
47
|
+
# We read the location url we plan to eject the
|
48
|
+
# file out into.
|
49
|
+
file_path = @file_url ? @file_url : chapter_data[ verse_id ][ "@out.url" ]
|
50
|
+
file_name = ::File.basename( file_path)
|
51
|
+
|
52
|
+
# If the directory the file will be exported to does
|
53
|
+
# not exist we promptly create it.
|
54
|
+
FileUtils.mkdir_p( File.dirname( file_path ) )
|
55
|
+
|
56
|
+
# Create a backup file if we can detect that a
|
57
|
+
# file occupies the eject (write) filepath.
|
58
|
+
backup_file_path = ::File.join( ::File.dirname( file_path ), KeyNow.yyjjj_hhmm_sst() + "-" + file_name )
|
59
|
+
::File.write( backup_file_path, ::File.read( file_path ) ) if ::File.file?( file_path )
|
60
|
+
|
61
|
+
|
62
|
+
# Now write (and if necessary overwrite) the eject
|
63
|
+
# file url path with the previously ingested content.
|
64
|
+
::File.write( file_path, file_content )
|
65
|
+
|
66
|
+
|
67
|
+
# Communicate that the indicated file has just been
|
68
|
+
# successfully written out from the safe.
|
69
|
+
print_file_success( master_db[ ENV_PATH ], verse_id, file_path )
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
|
77
|
+
# Document a successful write of a file cocooned in the safe.
|
78
|
+
# @param chapter_id the chapter of the file written out
|
79
|
+
# @param verse_id the verse of the file written out
|
80
|
+
# @param file_url the filepath the file was written to
|
81
|
+
def print_file_success chapter_id, verse_id, file_url
|
82
|
+
puts "File [#{file_url}] written out of safe at chapter [#{chapter_id}] and verse [#{verse_id}]."
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
data/lib/usecase/goto.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# Goto is a shortcut (or alias even) for the open command that takes an integer
|
6
|
+
# index that effectively specifies which <envelope> and <key> to open.
|
7
|
+
#
|
8
|
+
# Use <b>view</b> to list the valid integer indices for each envelope and key
|
9
|
+
# combination.
|
10
|
+
#
|
11
|
+
# View maps out and numbers each envelope/key combination.
|
12
|
+
# Goto with the number effectively shortcuts the open pin pointer command.
|
13
|
+
# Show prints the dictionary at the opened path masking any secrets.
|
14
|
+
#
|
15
|
+
# Once goto is enacted all path CRUD commands come into play as if you had
|
16
|
+
# opened the path. These include put, copy, paste, show, tell and delete.
|
17
|
+
class Goto < UseCase
|
18
|
+
|
19
|
+
# The index (number) starting with 1 of the envelope and key-path
|
20
|
+
# combination that should be opened.
|
21
|
+
attr_writer :index
|
22
|
+
|
23
|
+
def execute
|
24
|
+
|
25
|
+
return unless ops_key_exists?
|
26
|
+
master_db = KeyApi.read_master_db()
|
27
|
+
|
28
|
+
goto_location = 0
|
29
|
+
envelope_dictionaries = KeyApi.to_matching_dictionary( master_db, ENVELOPE_KEY_PREFIX )
|
30
|
+
envelope_dictionaries.each_pair do | envelope_name, crumb_dictionary |
|
31
|
+
|
32
|
+
envelope_content = KeyDb.from_json( KeyApi.content_unlock( crumb_dictionary ) )
|
33
|
+
envelope_content.each_key do | envelope_key |
|
34
|
+
|
35
|
+
goto_location += 1
|
36
|
+
next unless @index.to_i == goto_location
|
37
|
+
|
38
|
+
open_uc = Open.new
|
39
|
+
open_uc.env_path = envelope_name
|
40
|
+
open_uc.key_path = envelope_key
|
41
|
+
open_uc.flow_of_events
|
42
|
+
|
43
|
+
return
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|