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