safedb 0.5.1005 → 0.7.1001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -1
  3. data/genius-decision.txt +25 -0
  4. data/lib/cli.rb +155 -8
  5. data/lib/controller/{admin/auth.rb → abstract/authenticate.rb} +1 -2
  6. data/lib/controller/{controller.rb → abstract/controller.rb} +45 -24
  7. data/lib/controller/{edit/editverse.rb → abstract/edit_verse.rb} +0 -0
  8. data/lib/controller/{query/queryverse.rb → abstract/query_verse.rb} +0 -0
  9. data/lib/controller/{admin → access}/README.md +0 -0
  10. data/lib/controller/access/banner.txt +6 -0
  11. data/lib/controller/{admin → access}/init.rb +4 -4
  12. data/lib/controller/{admin → access}/login.rb +28 -23
  13. data/lib/controller/{admin → access}/logout.rb +0 -0
  14. data/lib/controller/{admin → access}/token.rb +0 -0
  15. data/lib/controller/{admin → access}/use.rb +0 -0
  16. data/lib/controller/api/docker/docker.rb +4 -22
  17. data/lib/controller/api/git/git.rb +104 -0
  18. data/lib/controller/api/terraform/README.md +23 -2
  19. data/lib/controller/api/terraform/terraform.rb +38 -7
  20. data/lib/controller/{admin → book}/commit.rb +2 -3
  21. data/lib/controller/{admin → book}/diff.rb +0 -0
  22. data/lib/controller/{admin → book}/export.rb +0 -0
  23. data/lib/controller/{admin → book}/import.rb +0 -0
  24. data/lib/controller/{admin → book}/refresh.rb +2 -2
  25. data/lib/controller/{admin → book}/view.rb +0 -0
  26. data/lib/{modules/storage/git.store.rb → controller/db/model_git_service.rb} +0 -0
  27. data/lib/controller/db/pull.rb +69 -0
  28. data/lib/controller/db/push.rb +352 -0
  29. data/lib/controller/db/remote.rb +108 -0
  30. data/lib/controller/edit/generate.rb +1 -1
  31. data/lib/controller/edit/keys.rb +72 -0
  32. data/lib/controller/edit/paste.rb +36 -0
  33. data/lib/controller/files/write.rb +11 -3
  34. data/lib/controller/misc/wipe.rb +23 -0
  35. data/lib/controller/navigate/at.rb +42 -0
  36. data/lib/controller/{admin → navigate}/goto.rb +0 -0
  37. data/lib/controller/{admin → navigate}/open.rb +0 -0
  38. data/lib/controller/query/copy.rb +32 -95
  39. data/lib/controller/query/tell.rb +36 -0
  40. data/lib/controller/requirer.rb +4 -4
  41. data/lib/controller/visit/README.md +34 -0
  42. data/lib/controller/visit/visit.rb +33 -0
  43. data/lib/manual/copy-paste.md +19 -2
  44. data/lib/{modules/README.md → manual/crypto-math.md} +0 -0
  45. data/lib/manual/push-pull.md +46 -0
  46. data/lib/manual/remote.md +62 -0
  47. data/lib/model/coordinates.rb +59 -0
  48. data/lib/model/{safe_tree.rb → file_tree.rb} +11 -6
  49. data/lib/model/indices.rb +113 -8
  50. data/lib/model/master.rb +40 -0
  51. data/lib/model/{state.migrate.rb → state_evolve.rb} +13 -5
  52. data/lib/model/{state.inspect.rb → state_query.rb} +5 -1
  53. data/lib/plugin/github.rb +53 -0
  54. data/lib/{modules/cryptology → utils/ciphers}/aes-256.rb +0 -0
  55. data/lib/{modules/cryptology → utils/ciphers}/blowfish.rb +0 -0
  56. data/lib/{modules/cryptology → utils/ciphers}/cipher.rb +0 -0
  57. data/lib/{modules/cryptology → utils/ciphers}/crypt.io.rb +0 -0
  58. data/lib/utils/keys/key.rb +44 -0
  59. data/lib/utils/keys/keypair.rb +52 -0
  60. data/lib/utils/logs/logger.rb +1 -1
  61. data/lib/utils/store/datastore.rb +1 -1
  62. data/lib/utils/store/github.rb +27 -0
  63. data/lib/utils/time/timestamp.rb +91 -0
  64. data/lib/version.rb +1 -1
  65. data/safedb.gemspec +2 -0
  66. metadata +75 -32
  67. data/lib/controller/verse.rb +0 -20
  68. data/lib/modules/storage/coldstore.rb +0 -186
  69. data/lib/utils/store/test-commands.sh +0 -24
@@ -0,0 +1,62 @@
1
+
2
+ #### create a remote backend store from which you can `safe push` and `safe pull` your encrypted database assets.
3
+
4
+ # provision a github repository backend
5
+
6
+ We want to provision (create) the safe's remote (github) backend so that we can access it from different machines. This is how we provision a Github remote backend do it.
7
+
8
+ ### safe remote --provision
9
+
10
+ Before you use safe remote to provision a github git repository backend for your crypts ensure that
11
+
12
+ - you have a github account (with username)
13
+ - you have created a (40 character hexadecimal) github access token
14
+ - you have inserted this data at a suitable chapter and verse
15
+ - you run **`safe remote --provision`** from this opened book/chapter/verse
16
+
17
+ Below is the sequence of commands leading up to **`safe remote --provision`**
18
+
19
+ ```
20
+ safe init db.admin
21
+ safe login db.admin
22
+ safe open remote.backend github
23
+ safe put @github.token 43210fedcba43210fedcba43210fedcba43210fedcba
24
+ safe configure backend db.admin/remote.backend/github
25
+ safe remote --provision
26
+ ```
27
+
28
+ ## focus | safe put @github.token
29
+
30
+ **@todo** - *we need to refactor out this business of configuring the backend. This should be done **automagically** by the remote commaand expecting to be at the correct book/chapter/verse*
31
+
32
+ safe knows how to talk to the Github Rest API as long as you provide a github access token. [Visit how to acquire a Github access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line).
33
+
34
+ ## safe configure @github.token
35
+
36
+ The **`safe configure`** command tell's safe which book, chapter and verse (in our case db.admin/remote.backend/github) that contains the backend repository access properties.
37
+
38
+ ## safe remote --provision
39
+
40
+ A number of setup tasks are executed when you ask that the backend repository be created.
41
+
42
+ - a repository is created in github
43
+ - the git fetch (https) and git push (ssh) urls are fabricated
44
+ - the fetch url is written into the master keys file
45
+ - the push url is written to the configured chapter/verse location
46
+ - a ssh public/private keypair (using EC25519) is created
47
+ - the private and public keys are placed within the chapter/verse
48
+ - the public (deploy) key is registered with the github repository
49
+
50
+ Now you are ready to push and pull.
51
+
52
+ Visit the [safe push](push-pull) and [safe pull](push-pull) documentation to discover howto use your safe database on as many machines as you need.
53
+
54
+
55
+ ## where is the safe database?
56
+
57
+ A safe database is always encrypted at rest and consiss of just 3 simple parts
58
+
59
+ - **backend** - a set of encrypted files kept either in **`~/.safedb.net/safedb-master-crypts`** or in a git repository
60
+ - **frontend** - a single state tracking file called <tt>safedb-dataase-tracker.ini</tt> (usually) on a removable drive
61
+ - one password - known by the database owner allowing them to login and access the information held within the database
62
+
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # Coordinates point to either a book, or a book/chapter or a book/chapter/verse
6
+ # location. The location pointed to may or may not exist and even if they do they
7
+ # may not be accessible if they exist within a book that (as of yet) we have not
8
+ # logged into.
9
+ class Coordinates
10
+
11
+
12
+ # Initialize coordinates to a location within a book and/or chapter and/or verse.
13
+ #
14
+ # @param coordinates_str [String]
15
+ # this parameter should be a book/chapter/verse separated
16
+ # by forward slashes.
17
+ def initialize( coordinates_str )
18
+
19
+ KeyError.not_new( coordinates_str, self )
20
+ @coords_list = @coords_list.split( "/" )
21
+ bcv_error_msg = "Invalid / separated book chapter and verse coordinates ~> #{@coords_list}"
22
+ raise ArgumentError.new( bcv_error_msg ) unless @coords_list.length() == 3
23
+
24
+ @book_name = @coords_list[ 0 ].strip()
25
+ @chapter_name = @coords_list[ 1 ].strip()
26
+ @verse_name = @coords_list[ 2 ].strip()
27
+
28
+ log.info(x) { "Initializing a book chapter and verse coordinate within book [#{@book_name}]." }
29
+
30
+ end
31
+
32
+
33
+ # Do the (book, chapter or verse) that our said coordinates point
34
+ # to exist.
35
+ def exists?()
36
+ end
37
+
38
+
39
+ # Do our coordinates point to an existing verse in a chapter within
40
+ # the current logged in book.
41
+ def is_verse?()
42
+ end
43
+
44
+
45
+ # Do our coordinates point to an existing chapter within the currently
46
+ # logged in book.
47
+ def is_chapter?()
48
+ end
49
+
50
+
51
+ # Do our coordinates point to any currently logged in book.
52
+ def is_book?()
53
+ end
54
+
55
+
56
+ end
57
+
58
+
59
+ end
@@ -22,9 +22,12 @@ module SafeDb
22
22
  end
23
23
 
24
24
 
25
+ # Get the path to the folder that holds the master crypts for the
26
+ # book ID specified in the parameter.
27
+ # @param book_id [String] the identifier of the book in question
28
+ # @return [File] path to the master crypts folder for the book
25
29
  def self.master_crypts_folder( book_id )
26
- master_crypts_folder = File.join( Indices::SAFE_DATABASE_FOLDER, Indices::MASTER_CRYPTS_FOLDER_NAME )
27
- return File.join( master_crypts_folder, "safedb.book.#{book_id}" )
30
+ return File.join( Indices::MASTER_CRYPTS_FOLDER_PATH, "safedb.book.#{book_id}" )
28
31
  end
29
32
 
30
33
 
@@ -34,14 +37,16 @@ module SafeDb
34
37
 
35
38
 
36
39
  def self.branch_crypts_folder( book_id, branch_id )
37
- branch_crypts_folder = File.join( Indices::SAFE_DATABASE_FOLDER, Indices::BRANCH_CRYPTS_FOLDER_NAME )
38
- return File.join( branch_crypts_folder, "safedb-branch-#{book_id}-#{branch_id}" )
40
+ return File.join( Indices::BRANCH_CRYPTS_FOLDER_PATH, "safedb-branch-#{book_id}-#{branch_id}" )
39
41
  end
40
42
 
41
43
 
44
+ # Get the path to the branch indices file for the branch ID
45
+ # specified in the parameter.
46
+ # @param branch_id [String] the identifier of the branch in question
47
+ # @return [File] path to the branch indices file for the given branch
42
48
  def self.branch_indices_filepath( branch_id )
43
- branch_indices_folder = File.join( Indices::SAFE_DATABASE_FOLDER, Indices::BRANCH_INDICES_FOLDER_NAME )
44
- return File.join( branch_indices_folder, "safedb-indices-#{branch_id}.ini" )
49
+ return File.join( Indices::BRANCH_INDICES_FOLDER_PATH, "safedb-indices-#{branch_id}.ini" )
45
50
  end
46
51
 
47
52
 
data/lib/model/indices.rb CHANGED
@@ -16,26 +16,119 @@ module SafeDb
16
16
  # The desired length of a safe book ergonomic identifier.
17
17
  SAFE_BOOK_ID_LENGTH = 12
18
18
 
19
+ # The file-system location of the safe database tree
20
+ SAFE_DATABASE_FOLDER = File.join( Dir.home, ".#{SAFE_URL_NAME}" )
21
+
19
22
  # The fully qualified domain name of the safedb home website
20
23
  SAFE_GEM_WEBSITE = "https://www.#{SAFE_URL_NAME}"
21
24
 
22
25
  # The safe database github clonable url for the ruby software
23
26
  SAFE_GITHUB_URL = "https://github.com/devops4me/#{SAFE_URL_NAME}"
24
27
 
25
- # The name ofthe master crypts folder.
28
+ # The name of the master crypts folder.
26
29
  MASTER_CRYPTS_FOLDER_NAME = "safedb-master-crypts"
27
30
 
28
- # The name ofthe branch indices folder.
29
- BRANCH_INDICES_FOLDER_NAME = "safedb-branch-indices"
31
+ # The path to the master crypts folder.
32
+ MASTER_CRYPTS_FOLDER_PATH = File.join( SAFE_DATABASE_FOLDER, MASTER_CRYPTS_FOLDER_NAME )
33
+
34
+ # The path to the master crypts .git directory.
35
+ MASTER_CRYPTS_GIT_PATH = File.join( MASTER_CRYPTS_FOLDER_PATH, ".git" )
36
+
37
+ # The name of the branch indices folder.
38
+ BRANCH_INDICES_FOLDER_NAME = "safedb-branch-keys"
39
+
40
+ # The path to the branch indices folder.
41
+ BRANCH_INDICES_FOLDER_PATH = File.join( SAFE_DATABASE_FOLDER, BRANCH_INDICES_FOLDER_NAME )
30
42
 
31
- # The name ofthe branch crypts folder.
43
+ # The name of the branch crypts folder.
32
44
  BRANCH_CRYPTS_FOLDER_NAME = "safedb-branch-crypts"
33
45
 
34
- # The file-system location of the safe database tree
35
- SAFE_DATABASE_FOLDER = File.join( Dir.home, ".#{SAFE_URL_NAME}" )
46
+ # The path to the branch crypts folder.
47
+ BRANCH_CRYPTS_FOLDER_PATH = File.join( SAFE_DATABASE_FOLDER, BRANCH_CRYPTS_FOLDER_NAME )
48
+
49
+ # The master indices file name
50
+ MASTER_INDICES_FILE_NAME = "safedb-master-keys.ini"
36
51
 
37
52
  # The path to the master indices file
38
- MASTER_INDICES_FILEPATH = File.join( SAFE_DATABASE_FOLDER, "safedb-master-indices.ini" )
53
+ MASTER_INDICES_FILEPATH = File.join( SAFE_DATABASE_FOLDER, MASTER_INDICES_FILE_NAME )
54
+
55
+ # The path to the remote storage configuration INI file
56
+ MACHINE_CONFIG_FILEPATH = File.join( SAFE_DATABASE_FOLDER, "safedb-remote-storage.ini" )
57
+
58
+ # The name of the machine removable drive path location directive
59
+ MACHINE_REMOVABLE_DRIVE_PATH = "removable.drive"
60
+
61
+
62
+
63
+ # The keyname whose value denotes a local folder path to clone to
64
+ GIT_CLONE_BASE_PATH = "git.clone.base.path"
65
+
66
+
67
+
68
+
69
+ # The name of the keys section that holds remote mirror properties
70
+ REMOTE_MIRROR_SECTION_NAME = "remote.mirror"
71
+
72
+ # The name of the property that points to the book/chapter/verse (page)
73
+ REMOTE_MIRROR_PAGE_NAME = "remote.mirror.page"
74
+
75
+ # The ending of the private key filename for remote mirror push access
76
+ REMOTE_MIRROR_PRIVATE_KEY_POSTFIX = "private-key.pem"
77
+
78
+ # The key name that holds the remote mirror private key filename
79
+ REMOTE_PRIVATE_KEY_KEYNAME = "private.key.filename"
80
+
81
+ # The key name that holds the remote mirror ssh config host value
82
+ REMOTE_MIRROR_SSH_HOST_KEYNAME = "ssh.config.host"
83
+
84
+ # The path to the SSH directory
85
+ SSH_DIRECTORY_PATH = File.join( Dir.home(), ".ssh" )
86
+
87
+ # The path to the SSH config file
88
+ SSH_CONFIG_FILE_PATH = File.join( SSH_DIRECTORY_PATH, "config" )
89
+
90
+
91
+
92
+
93
+
94
+ # This access token allows us to talk to the Github API
95
+ GITHUB_ACCESS_TOKEN = "@github.access.token"
96
+
97
+ # Github repository keyname
98
+ GIT_REPOSITORY_NAME_KEYNAME = "repository.name"
99
+
100
+ # Github Username Keyname
101
+ GIT_REPOSITORY_USER_KEYNAME = "repository.user"
102
+
103
+ # Github Host Keyname
104
+ GIT_REPOSITORY_HOST_KEYNAME = "repository.host"
105
+
106
+
107
+
108
+
109
+ # Keyname for when the last backend push occured
110
+ REMOTE_LAST_PUSH_ON = "last.push.on"
111
+
112
+ # Keyname for the user and hostname that evoked the last push
113
+ REMOTE_LAST_PUSH_BY = "last.push.by"
114
+
115
+ # Keyname for the ID of the last push (Usually Git Commit Reference)
116
+ REMOTE_LAST_PUSH_ID = "last.push.id"
117
+
118
+ # Private Key Default Key Name
119
+ PRIVATE_KEY_DEFAULT_KEY_NAME = "private.key"
120
+
121
+ # Public Key Default Key Name
122
+ PUBLIC_KEY_DEFAULT_KEY_NAME = "public.key"
123
+
124
+ # The parameter key name to configure the backend coordinates
125
+ CONFIGURE_BACKEND_KEY_NAME = "backend"
126
+
127
+ # The name of the remote database git pull url key
128
+ REMOTE_DATABASE_GIT_PULL_URL = "git.pull.url"
129
+
130
+ # The name of the remote database git push url key
131
+ REMOTE_DATABASE_GIT_PUSH_URL = "git.push.url"
39
132
 
40
133
  # The desired length of a content identifier
41
134
  CONTENT_ID_LENGTH = 14
@@ -90,7 +183,7 @@ module SafeDb
90
183
 
91
184
  # Character (randomly) repeated to mask credentials
92
185
  # Asterices, hyphens, plus and equal signs are common alternatives.
93
- SECRET_MASK_STRING = "*" * rand( 7 .. 17 )
186
+ SECRET_MASK_STRING = "*" * rand( 18 .. 30 )
94
187
 
95
188
  # The birthday (initialization time) of this safe book.
96
189
  SAFE_BOOK_INITIALIZE_TIME = "book.init.time"
@@ -125,6 +218,18 @@ module SafeDb
125
218
  # Handle to the simple name of the ingested file in the submap verse
126
219
  INGESTED_FILE_BASE_NAME_KEY = "file.name"
127
220
 
221
+ # The permission setting (chmod) key name
222
+ FILE_CHMOD_PERMISSIONS_KEY = "file.access"
223
+
224
+ # The keypair name prefix for private keys.
225
+ PRIVATE_KEY_PREFIX = "private.key"
226
+
227
+ # The keypair name prefix for public keys.
228
+ PUBLIC_KEY_PREFIX = "public.key"
229
+
230
+ # Elliptic Curve SSL Key Type
231
+ ELLIPTIC_CURVE_KEY_TYPE = "secp384r1"
232
+
128
233
 
129
234
  end
130
235
 
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # This master data structure controls the key publicly visible properties for
6
+ # the safe database be it in a local or remote location.
7
+ #
8
+ # This object mapper seals away details of the persistence engine involved.
9
+ # Who knows, it could be a local drive, an S3 bucket and even a database.
10
+ class Master
11
+
12
+ # Initialize an instance of this safe database's master properties.
13
+ def initialize()
14
+ @master = DataMap.new( Indices::MASTER_INDICES_FILEPATH )
15
+ end
16
+
17
+
18
+ # Get the coordinates (book, chapter and verse) of the verse that holds
19
+ # the remote backend properties. An exception will be thrown if no backend
20
+ # coordinates have been set.
21
+ # @return [String] the backend coordinates to set
22
+ def get_backend_coordinates()
23
+ @master.use( Indices::REMOTE_MIRROR_SECTION_NAME )
24
+ return @master.get( Indices::REMOTE_MIRROR_PAGE_NAME )
25
+ end
26
+
27
+
28
+ # Set the coordinates (book, chapter and verse) of the verse that holds
29
+ # the remote backend properties.
30
+ # @param backend_coordinates [String] the backend coordinates to set
31
+ def set_backend_coordinates( backend_coordinates )
32
+ @master.use( Indices::REMOTE_MIRROR_SECTION_NAME )
33
+ @master.set( Indices::REMOTE_MIRROR_PAGE_NAME, backend_coordinates )
34
+ end
35
+
36
+
37
+ end
38
+
39
+
40
+ end
@@ -10,7 +10,7 @@ module SafeDb
10
10
  # - <tt>commit</tt> - transfers state from branch to master
11
11
  # - <tt>refresh</tt> - transfers state from master to branch
12
12
  #
13
- class StateMigrate
13
+ class EvolveState
14
14
 
15
15
  # The login process recycles the content encryption key by regenerating the human
16
16
  # key from the password text and salts and then accessing the old crypt key, generating
@@ -42,7 +42,7 @@ module SafeDb
42
42
  # used for the asymmetric decryption of the content ciphertext which is in a
43
43
  # file marked with the content identifier also within the book keys.
44
44
  #
45
- # @param secret [String]
45
+ # @param human_secret [String]
46
46
  # the secret text that can potentially be cryptographically weak (low entropy).
47
47
  # This text is severely strengthened and morphed into a key using multiple key
48
48
  # derivation functions like <b>PBKDF2, BCrypt</b> and <b>SCrypt</b>.
@@ -54,22 +54,30 @@ module SafeDb
54
54
  # The key ring only stores the salts. This means the secret text based key can
55
55
  # only be regenerated at the next login, which explains the inter-branch label.
56
56
  #
57
- def self.login( book_keys, secret )
57
+ # @return [Boolean]
58
+ # return false if failure decrypting with human password occurs.
59
+ # True is returned if the login logic completes naturally.
60
+ def self.login( book_keys, human_secret )
58
61
 
59
62
  the_book_id = book_keys.section()
60
63
 
61
- old_human_key = KdfApi.regenerate_from_salts( secret, book_keys )
64
+ old_human_key = KdfApi.regenerate_from_salts( human_secret, book_keys )
65
+ is_correct_password = old_human_key.can_decrypt_key( book_keys.get( Indices::CRYPT_CIPHER_TEXT ) )
66
+ return false unless is_correct_password
67
+
62
68
  the_crypt_key = old_human_key.do_decrypt_key( book_keys.get( Indices::CRYPT_CIPHER_TEXT ) )
63
69
  plain_content = Content.unlock_master( the_crypt_key, book_keys )
64
70
 
65
71
  first_login_since_boot = StateInspect.is_first_login?( book_keys )
66
72
  the_crypt_key = Key.from_random if first_login_since_boot
67
- recycle_keys( the_crypt_key, the_book_id, secret, book_keys, plain_content )
73
+ recycle_keys( the_crypt_key, the_book_id, human_secret, book_keys, plain_content )
68
74
  set_bootup_id( book_keys ) if first_login_since_boot
69
75
 
70
76
  branch_id = Identifier.derive_branch_id( Branch.to_token() )
71
77
  clone_book_into_branch( the_book_id, branch_id, book_keys, the_crypt_key )
72
78
 
79
+ return true
80
+
73
81
  end
74
82
 
75
83
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module SafeDb
4
4
 
5
- # State queries are related to {StateMigrate} but they simple ask for information
5
+ # State queries are related to {EvolveState} but they simple ask for information
6
6
  # about the state without changing any state.
7
7
  #
8
8
  class StateInspect
@@ -42,6 +42,9 @@ module SafeDb
42
42
  branch_key_ciphertext = branch_keys.get( Indices::CRYPT_CIPHER_TEXT )
43
43
  branch_key = KeyDerivation.regenerate_shell_key( Branch.to_token() )
44
44
 
45
+ return branch_key.can_decrypt_key( branch_key_ciphertext )
46
+
47
+ =begin
45
48
  begin
46
49
  branch_key.do_decrypt_key( branch_key_ciphertext )
47
50
  return true
@@ -50,6 +53,7 @@ module SafeDb
50
53
  log.warn(x) { "Login failure error message is #{e.message}" }
51
54
  return false
52
55
  end
56
+ =end
53
57
 
54
58
  end
55
59
 
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # This class knows how to talk to Github and callers can delegate common
6
+ # github functionality like creating repositories, listing repositories,
7
+ # downloading repositories and the like.
8
+ #
9
+ class Github
10
+
11
+ # Initialize an instance of this safe database's master properties.
12
+ def initialize()
13
+
14
+
15
+
16
+
17
+ #
18
+ #
19
+ # Test the Github api using curl
20
+ #
21
+ #
22
+ # curl -H "Authorization: token OAUTH-TOKEN" https://api.github.com
23
+ #
24
+ #
25
+
26
+
27
+ @master = DataMap.new( Indices::MASTER_INDICES_FILEPATH )
28
+ end
29
+
30
+
31
+ # Get the coordinates (book, chapter and verse) of the verse that holds
32
+ # the remote backend properties. An exception will be thrown if no backend
33
+ # coordinates have been set.
34
+ # @return [String] the backend coordinates to set
35
+ def get_backend_coordinates()
36
+ @master.use( Indices::REMOTE_MIRROR_SECTION_NAME )
37
+ return @master.get( Indices::REMOTE_MIRROR_PAGE_NAME )
38
+ end
39
+
40
+
41
+ # Set the coordinates (book, chapter and verse) of the verse that holds
42
+ # the remote backend properties.
43
+ # @param backend_coordinates [String] the backend coordinates to set
44
+ def set_backend_coordinates( backend_coordinates )
45
+ @master.use( Indices::REMOTE_MIRROR_SECTION_NAME )
46
+ @master.set( Indices::REMOTE_MIRROR_PAGE_NAME, backend_coordinates )
47
+ end
48
+
49
+
50
+ end
51
+
52
+
53
+ end
File without changes
@@ -478,6 +478,50 @@ module SafeDb
478
478
  end
479
479
 
480
480
 
481
+ # Return true if this key object can decrypt the parameter ciphertext that
482
+ # represents a key.
483
+ #
484
+ # The parameter cipher text must comprise of an 80 character key and a 16
485
+ # character random initialization vector (IV). When transformed to a bit string
486
+ # of ones and zeroes, the bit string length must be <tt>96 * 8 = 768</tt>.
487
+ #
488
+ # @param key_iv_ciphertext [String]
489
+ # Provide the ciphertext produced by our sister key encryption method.
490
+ # The ciphertext should hold 96 bytes which equates to 128 base64 characters.
491
+ # The random initialization vector (iv) accounts for the first 16 bytes.
492
+ # The actual crypt ciphertext then accounts for the final 80 bytes.
493
+ #
494
+ # @return [Boolean]
495
+ # return true if the ciphertext is of the expected length and the
496
+ # <tt>dry run of the decrypt operation</tt> completes without a
497
+ # cipher error from {OpenSSL::Cipher::CipherError} being thrown.
498
+ #
499
+ def can_decrypt_key( key_iv_ciphertext )
500
+
501
+ bit_text = Key64.to_bits( key_iv_ciphertext )
502
+ ciphertext_size_msg = "Expected bit length of #{EXPECTED_CIPHER_BIT_LENGTH} not #{bit_text.length}."
503
+ is_expected_length = bit_text.length == EXPECTED_CIPHER_BIT_LENGTH
504
+ log.warn(x) { ciphertext_size_msg } unless is_expected_length
505
+ return false unless is_expected_length
506
+
507
+ the_cipher = OpenSSL::Cipher::AES256.new(:CBC)
508
+ the_cipher.decrypt()
509
+ rawbytes = [ bit_text ].pack("B*")
510
+ the_cipher.key = to_aes_key()
511
+ the_cipher.iv = rawbytes[ 0 .. ( RANDOM_IV_BYTE_COUNT - 1 ) ]
512
+
513
+ begin
514
+ the_cipher.update( rawbytes[ RANDOM_IV_BYTE_COUNT .. -1 ] ) + the_cipher.final
515
+ return true
516
+ rescue OpenSSL::Cipher::CipherError => e
517
+ log.warn(x) { "Auth failure decrypting this ciphertext ~~ #{key_iv_ciphertext}" }
518
+ log.warn(x) { "Auth (maybe login failure) error message is ~~ #{e.message}" }
519
+ return false
520
+ end
521
+
522
+ end
523
+
524
+
481
525
  # Use the {OpenSSL::Cipher::AES256} block cipher in CBC mode and the binary
482
526
  # 256bit representation of this key to encrypt the parameter plaintext using
483
527
  # the parameter random initialization vector.
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ # This class creates and represents an Elliptic Curve cryptographic key.
7
+ # The generated key can then be comsumed via its various aspects like its
8
+ # ssh formatted public key and/or the pem formatted private key.
9
+ class Keypair
10
+
11
+ # Generate an elliptic curve cryptographic keypair. After the key is
12
+ # generated, both the public and private keys can be retrieved through
13
+ # the accessors.
14
+ #
15
+ def initialize
16
+
17
+ @ec_keypair = OpenSSL::PKey::EC.new( Indices::ELLIPTIC_CURVE_KEY_TYPE )
18
+ @ec_keypair.generate_key!
19
+
20
+ log.info(x) { "An elliptic curve keypair has just been generated." }
21
+
22
+ end
23
+
24
+
25
+ # Get the private key aspect of this elliptic curve cryptographic key
26
+ # in PEM format.
27
+ # @return [String] the PEM formatted private key
28
+ def private_key_pem()
29
+ return @ec_keypair.to_pem()
30
+ end
31
+
32
+
33
+ # Get the public key aspect of this elliptic curve cryptographic key
34
+ # in the long line SSH format. This format states the key type which
35
+ # will be **ecdsa-sha2-nistp384** followed by base64 encoded data.
36
+ #
37
+ # The returned one line public key will likely contain forward slashes
38
+ # and possibly equal signs at the end of the string.
39
+ #
40
+ # @return [String] the SSH formatted public key prefixed by the key type
41
+ def public_key_ssh()
42
+ require 'net/ssh'
43
+ key_type = @ec_keypair.ssh_type()
44
+ key_data = [ @ec_keypair.to_blob ].pack('m0')
45
+ return "#{key_type} #{key_data}"
46
+ end
47
+
48
+
49
+ end
50
+
51
+
52
+ end
@@ -88,7 +88,7 @@ module LogImpl
88
88
  def get_logger
89
89
 
90
90
  file_logger = Logger.new @@log_path
91
- file_logger.level = Logger::INFO
91
+ file_logger.level = Logger::DEBUG
92
92
  original_formatter = Logger::Formatter.new
93
93
 
94
94
  file_logger.formatter = proc { |severity, datetime, progname, msg|
@@ -5,7 +5,7 @@ module SafeDb
5
5
 
6
6
  require 'json'
7
7
 
8
- # A Key/Value database knows how to manipulate a JSON backed data structure
8
+ # A Key/Value database knows how to manipulate a JSON backend data structure
9
9
  # (put, add etc) <b>after reading and then decrypting it</b> from a
10
10
  # file and <b>before encrypting and then writing it</b> to a file.
11
11
  #
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ # The Github class uses the REST API to talk to Github and create, query,
7
+ # change and delete assets within a specified hosted git repository.
8
+ class Github
9
+
10
+ # Initialize a Github repository given the parameter name.
11
+ # the parameter JSON string.
12
+ #
13
+ # @param repository_name [String] name of the Github repository
14
+ #
15
+ def initialize( repository_name )
16
+
17
+ data_db = DataStore.new()
18
+ data_db.merge!( JSON.parse( db_json_string ) )
19
+ return data_db
20
+
21
+ end
22
+
23
+
24
+ end
25
+
26
+
27
+ end