adamantite 0.0.3 → 0.0.6
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 +4 -4
- data/bin/adamantite +4 -2
- data/lib/adamantite.rb +120 -115
- data/lib/base/adamantite.rb +134 -35
- data/lib/base/editor/password_object_editor.rb +16 -10
- data/lib/base/password_object.rb +8 -3
- data/lib/file_utils/adamantite_file_utils.rb +104 -0
- data/lib/gui/form/password_object_form_window.rb +29 -27
- data/lib/gui/request/add_password_request.rb +8 -7
- data/lib/gui/request/login_request.rb +9 -12
- data/lib/gui/request/set_master_password_request.rb +7 -8
- data/lib/gui/request/update_master_password_request.rb +6 -5
- data/lib/gui/screen/copy_screen.rb +7 -5
- data/lib/gui/screen/login_screen.rb +14 -13
- data/lib/gui/screen/set_master_password_screen.rb +17 -15
- data/lib/gui/screen/show_screen.rb +8 -6
- data/lib/gui/screen/update_master_password_screen.rb +19 -16
- metadata +4 -6
- data/lib/adamantite_command_line.rb +0 -95
- data/lib/file_utils/file_utils.rb +0 -55
- data/lib/pw_utils/pw_utils.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b339af86674a560875455a4ddab002be33d4adcc3219a0ab0f6613cdecc5f4e4
|
4
|
+
data.tar.gz: b710b5092de2a53d49757ee95c2767e3c5a23f5769cc36359fade7d21892784c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8611efaf00d7d6aa3627a6a6f2d0e768ddc3d87ac757391c2536c89fa0e213d41b0b138ee51e66d6239acba0c3b2dd484106e8514392bc4c0fccd5f49be5fd2
|
7
|
+
data.tar.gz: f8628c2fc29cac9e0f27c54f94a0ab4cdd4ef435e3be7225b6c22bd691ddb0b109938a184a0bd5430746796c00ae818f990cf516d210a54e7ebcba0ad98e700a
|
data/bin/adamantite
CHANGED
data/lib/adamantite.rb
CHANGED
@@ -1,133 +1,138 @@
|
|
1
|
-
|
2
|
-
require "bcrypt"
|
3
|
-
require "openssl"
|
4
|
-
require "base64"
|
5
|
-
require "json"
|
6
|
-
require "io/console"
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require "gui/screen/show_screen"
|
15
|
-
require "gui/screen/set_master_password_screen"
|
16
|
-
require "gui/screen/update_master_password_screen"
|
17
|
-
require "gui/request/login_request"
|
18
|
-
require "gui/request/add_password_request"
|
19
|
-
require "gui/request/update_master_password_request"
|
20
|
-
require "gui/request/set_master_password_request"
|
21
|
-
require "gui/form/password_object_form_window"
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
require 'bcrypt'
|
5
|
+
require 'openssl'
|
6
|
+
require 'base64'
|
7
|
+
require 'json'
|
8
|
+
require 'io/console'
|
22
9
|
|
23
|
-
|
24
|
-
|
10
|
+
require 'fileutils'
|
11
|
+
require 'file_utils/adamantite_file_utils'
|
12
|
+
require 'base/adamantite'
|
13
|
+
require 'base/password_object'
|
14
|
+
require 'gui/screen/login_screen'
|
15
|
+
require 'gui/screen/copy_screen'
|
16
|
+
require 'gui/screen/show_screen'
|
17
|
+
require 'gui/screen/set_master_password_screen'
|
18
|
+
require 'gui/screen/update_master_password_screen'
|
19
|
+
require 'gui/request/login_request'
|
20
|
+
require 'gui/request/add_password_request'
|
21
|
+
require 'gui/request/update_master_password_request'
|
22
|
+
require 'gui/request/set_master_password_request'
|
23
|
+
require 'gui/form/password_object_form_window'
|
25
24
|
|
26
|
-
|
27
|
-
|
25
|
+
module Adamantite
|
26
|
+
class AdamantiteApp
|
27
|
+
include Glimmer::LibUI::Application
|
28
|
+
include Adamantite::AdamantiteFileUtils
|
28
29
|
|
29
|
-
|
30
|
+
attr_accessor :add_password_request, :stored_passwords
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
before_body do
|
33
|
+
unless master_password_exists?
|
34
|
+
set_master_password_request = GUI::Request::SetMasterPasswordRequest.new
|
35
|
+
set_master_password_screen(set_master_password_request: set_master_password_request).show
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
login_request = GUI::Request::LoginRequest.new
|
39
|
+
login_screen(login_request: login_request).show
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
unless login_request.authenticated
|
42
|
+
exit(0)
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
@adamantite = login_request.adamantite
|
46
|
+
@stored_passwords = @adamantite.stored_passwords.map do |stored_password|
|
47
|
+
[stored_password[:website_title], stored_password[:username], 'Edit', 'Copy', 'Show', 'Delete']
|
48
|
+
end
|
49
|
+
@master_password = @adamantite.master_password
|
50
|
+
@master_password_salt = @adamantite.master_password_salt
|
51
|
+
@add_password_request = GUI::Request::AddPasswordRequest.new(@master_password, @master_password_salt)
|
47
52
|
end
|
48
|
-
@master_password = login_request.master_password
|
49
|
-
@master_password_salt = login_request.master_password_salt
|
50
|
-
@adamantite_object = Adamantite::Base::Adamantite.new(@master_password)
|
51
|
-
@adamantite_object.authenticate!
|
52
|
-
@add_password_request = Adamantite::GUI::Request::AddPasswordRequest.new(@master_password, @master_password_salt)
|
53
|
-
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
body do
|
55
|
+
window('Adamantite', 800, 400) do
|
56
|
+
margined true
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
58
|
+
vertical_box do
|
59
|
+
table do
|
60
|
+
text_column('Title')
|
61
|
+
text_column('Username')
|
62
|
+
button_column('Edit') do
|
63
|
+
on_clicked do |row|
|
64
|
+
on_save = lambda do |password_object|
|
65
|
+
stored_password = []
|
66
|
+
stored_password << password_object.website_title
|
67
|
+
stored_password << password_object.username
|
68
|
+
stored_password << 'Edit'
|
69
|
+
stored_password << 'Copy'
|
70
|
+
stored_password << 'Show'
|
71
|
+
stored_password << 'Delete'
|
72
|
+
@stored_passwords[password_object.row_index] = stored_password
|
73
|
+
adamantite_stored_password = {
|
74
|
+
'dir_name': password_object.dir_name,
|
75
|
+
'website_title': password_object.website_title,
|
76
|
+
'username': @adamantite.retrieve_password_info(password_object.dir_name, 'username')
|
77
|
+
}
|
78
|
+
@adamantite.stored_passwords[password_object.row_index] = adamantite_stored_password
|
79
|
+
end
|
80
|
+
website_title = @stored_passwords[row][0]
|
81
|
+
username = @stored_passwords[row][1]
|
82
|
+
dir_name = @adamantite.stored_passwords[row][:dir_name]
|
83
|
+
password = @adamantite.retrieve_password_info(dir_name, 'password')
|
84
|
+
password_object = Base::PasswordObject.new(website_title, username, password, password, row, dir_name)
|
85
|
+
password_object_form_window(adamantite: @adamantite, on_save: on_save, password_object: password_object).show
|
86
|
+
end
|
81
87
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
88
|
+
button_column('Copy') do
|
89
|
+
on_clicked do |row|
|
90
|
+
IO.popen('pbcopy', 'w') do |f|
|
91
|
+
dir_name = @adamantite.stored_passwords[row][:dir_name]
|
92
|
+
f << @adamantite.retrieve_password_info(dir_name, 'password')
|
93
|
+
end
|
94
|
+
copy_screen(password_title: @stored_passwords[row].first).show
|
95
|
+
end
|
90
96
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
show_screen(password: stored_pw_selection).show
|
97
|
+
button_column('Show') do
|
98
|
+
on_clicked do |row|
|
99
|
+
dir_name = @adamantite.stored_passwords[row][:dir_name]
|
100
|
+
show_screen(password: @adamantite.retrieve_password_info(dir_name, 'password')).show
|
101
|
+
end
|
97
102
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
+
button_column('Delete') do
|
104
|
+
on_clicked do |row|
|
105
|
+
@adamantite.delete_password(@adamantite.stored_passwords[row][:dir_name])
|
106
|
+
@stored_passwords.delete_at(row)
|
107
|
+
end
|
103
108
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
109
|
+
cell_rows <=> [self, :stored_passwords]
|
110
|
+
end
|
111
|
+
horizontal_box do
|
112
|
+
button('Add Password') do
|
113
|
+
on_clicked do
|
114
|
+
on_save = lambda do |password_object|
|
115
|
+
stored_password = []
|
116
|
+
stored_password << password_object.website_title
|
117
|
+
stored_password << password_object.username
|
118
|
+
stored_password << 'Edit'
|
119
|
+
stored_password << 'Copy'
|
120
|
+
stored_password << 'Show'
|
121
|
+
stored_password << 'Delete'
|
122
|
+
@stored_passwords << stored_password
|
123
|
+
end
|
124
|
+
password_object_form_window(adamantite: @adamantite, on_save: on_save).show
|
125
|
+
end
|
121
126
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
+
button('Update Master Password') do
|
128
|
+
on_clicked do
|
129
|
+
update_master_password_request = GUI::Request::UpdateMasterPasswordRequest.new(@adamantite)
|
130
|
+
update_master_password_screen(update_master_password_request: update_master_password_request).show
|
131
|
+
end
|
127
132
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
133
138
|
end
|
data/lib/base/adamantite.rb
CHANGED
@@ -1,59 +1,158 @@
|
|
1
|
-
|
2
|
-
require "pw_utils/pw_utils"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
require 'file_utils/adamantite_file_utils'
|
4
|
+
require 'rbnacl'
|
5
|
+
require 'base64'
|
6
6
|
|
7
7
|
module Adamantite
|
8
8
|
module Base
|
9
9
|
class Adamantite
|
10
|
+
include AdamantiteFileUtils
|
10
11
|
|
11
|
-
|
12
|
+
attr_reader :authenticated, :master_password, :master_password_salt, :stored_passwords
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
OPSLIMIT = 2**20
|
15
|
+
MEMLIMIT = 2**24
|
16
|
+
DIGEST_SIZE = 32
|
17
|
+
|
18
|
+
def initialize(master_password)
|
19
|
+
@master_password = master_password
|
15
20
|
@authenticated = false
|
16
|
-
@master_pw_exists = pw_file_exists?('master')
|
17
21
|
end
|
18
22
|
|
19
23
|
def authenticate!
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
if master_password_exists?
|
25
|
+
master_password_salt = get_master_password_salt
|
26
|
+
master_encrypted_vault_key = get_master_encrypted_vault_key
|
27
|
+
entered_master_password_hash = rbnacl_scrypt_hash(@master_password, master_password_salt)
|
28
|
+
vault = rbnacl_box(entered_master_password_hash)
|
29
|
+
|
30
|
+
begin
|
31
|
+
@master_vault_key = vault.decrypt(master_encrypted_vault_key)
|
32
|
+
@authenticated = true
|
33
|
+
@master_password_salt = master_password_salt
|
34
|
+
@vault = rbnacl_box(@master_vault_key)
|
35
|
+
update_stored_passwords!
|
36
|
+
true
|
37
|
+
rescue RbNaCl::CryptoError
|
38
|
+
false
|
39
|
+
end
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def save_password(website_title, username, password, password_confirmation)
|
46
|
+
return unless password == password_confirmation && authenticated?
|
47
|
+
|
48
|
+
encrypted_file_name_ascii_8bit = @vault.encrypt(website_title)
|
49
|
+
dir_name = Base64.urlsafe_encode64(encrypted_file_name_ascii_8bit)
|
50
|
+
make_password_dir(dir_name)
|
51
|
+
write_to_file(password_file(dir_name, 'username'), @vault.encrypt(username), true)
|
52
|
+
write_to_file(password_file(dir_name, 'password'), @vault.encrypt(password), true)
|
53
|
+
update_stored_passwords!
|
54
|
+
dir_name
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete_password(password_dir_name)
|
58
|
+
FileUtils.remove_entry_secure(password_file(password_dir_name))
|
59
|
+
update_stored_passwords!
|
60
|
+
end
|
61
|
+
|
62
|
+
def retrieve_password_info(website_title, info_name)
|
63
|
+
return unless authenticated?
|
64
|
+
|
65
|
+
@vault.decrypt(read_file(password_file(website_title, info_name), true))
|
66
|
+
end
|
67
|
+
|
68
|
+
def serialize_master_password(master_password, master_password_confirmation)
|
69
|
+
if master_password == master_password_confirmation
|
70
|
+
master_password_salt = rbnacl_random_bytes
|
71
|
+
master_password_hash = rbnacl_scrypt_hash(master_password, master_password_salt)
|
72
|
+
vault_key = rbnacl_random_bytes
|
73
|
+
vault = rbnacl_box(master_password_hash)
|
74
|
+
encrypted_vault_key = vault.encrypt(vault_key)
|
75
|
+
make_pwmanager_dir
|
76
|
+
write_master_info(master_password_salt, encrypted_vault_key)
|
31
77
|
true
|
32
78
|
else
|
33
79
|
false
|
34
80
|
end
|
35
81
|
end
|
36
82
|
|
37
|
-
def update_master_password!(
|
38
|
-
|
83
|
+
def update_master_password!(new_master_password, new_master_password_confirmation)
|
84
|
+
if new_master_password == new_master_password_confirmation && authenticated?
|
85
|
+
new_master_password_salt = rbnacl_random_bytes
|
86
|
+
new_master_password_hash = rbnacl_scrypt_hash(new_master_password, new_master_password_salt)
|
87
|
+
vault_key = rbnacl_random_bytes
|
88
|
+
vault = rbnacl_box(new_master_password_hash)
|
89
|
+
encrypted_vault_key = vault.encrypt(vault_key)
|
39
90
|
|
40
|
-
|
41
|
-
|
42
|
-
|
91
|
+
new_password_data = @stored_passwords.map do |stored_password|
|
92
|
+
info = {}
|
93
|
+
info['website_title'] = stored_password[:website_title]
|
94
|
+
info['username'] = retrieve_password_info(stored_password[:dir_name], 'username')
|
95
|
+
info['password'] = retrieve_password_info(stored_password[:dir_name], 'password')
|
96
|
+
info
|
97
|
+
end
|
43
98
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
99
|
+
FileUtils.copy_entry(pwmanager_dir, pwmanager_tmp_dir)
|
100
|
+
FileUtils.remove_entry_secure(pwmanager_dir)
|
101
|
+
@vault = rbnacl_box(vault_key)
|
102
|
+
make_pwmanager_dir
|
103
|
+
new_password_data.each do |new_password|
|
104
|
+
website_title = new_password['website_title']
|
105
|
+
username = new_password['username']
|
106
|
+
password = new_password['password']
|
107
|
+
save_password(website_title, username, password, password)
|
108
|
+
end
|
109
|
+
FileUtils.remove_entry_secure(pwmanager_tmp_dir)
|
110
|
+
write_master_info(new_master_password_salt, encrypted_vault_key)
|
111
|
+
@master_password_salt = master_password_salt
|
112
|
+
@master_encrypted_vault_key = encrypted_vault_key
|
113
|
+
true
|
114
|
+
else
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def authenticated?
|
120
|
+
@authenticated
|
121
|
+
end
|
122
|
+
|
123
|
+
def update_stored_passwords!
|
124
|
+
@stored_passwords = get_stored_pws.map do |stored_password|
|
125
|
+
{
|
126
|
+
'dir_name': stored_password,
|
127
|
+
'website_title': decode_encrypted_utf8_string(stored_password),
|
128
|
+
'username': retrieve_password_info(stored_password, 'username')
|
129
|
+
}
|
49
130
|
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def rbnacl_box(key)
|
136
|
+
RbNaCl::SimpleBox.from_secret_key(key)
|
137
|
+
end
|
138
|
+
|
139
|
+
def rbnacl_random_bytes
|
140
|
+
RbNaCl::Random.random_bytes(RbNaCl::PasswordHash::SCrypt::SALTBYTES)
|
141
|
+
end
|
142
|
+
|
143
|
+
def rbnacl_scrypt_hash(password, salt)
|
144
|
+
RbNaCl::PasswordHash.scrypt(password, salt, OPSLIMIT, MEMLIMIT, DIGEST_SIZE)
|
145
|
+
end
|
146
|
+
|
147
|
+
def decode_encrypted_utf8_string(encrypted_string)
|
148
|
+
decoded_data = Base64.urlsafe_decode64(encrypted_string)
|
149
|
+
@vault.decrypt(decoded_data)
|
150
|
+
end
|
50
151
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@master_pw_salt = new_master_pw_salt
|
55
|
-
true
|
152
|
+
def write_master_info(master_password_salt, master_vault_key)
|
153
|
+
write_to_file(password_file('master_password_salt'), master_password_salt, true)
|
154
|
+
write_to_file(password_file('master_encrypted_vault_key'), master_vault_key, true)
|
56
155
|
end
|
57
156
|
end
|
58
157
|
end
|
59
|
-
end
|
158
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base/password_object'
|
4
|
+
require 'file_utils/adamantite_file_utils'
|
5
|
+
require 'pw_utils/pw_utils'
|
4
6
|
|
5
7
|
module Adamantite
|
6
8
|
module Base
|
7
9
|
module Editor
|
8
10
|
class PasswordObjectEditor
|
9
|
-
include
|
11
|
+
include AdamantiteFileUtils
|
10
12
|
include PWUtils
|
11
13
|
|
12
14
|
# editable_user provides the temporary user object for editing
|
@@ -14,10 +16,9 @@ module Adamantite
|
|
14
16
|
|
15
17
|
# initializes a user editor with nil when creating a new user
|
16
18
|
# or with an existing user when editing an existing user
|
17
|
-
def initialize(
|
19
|
+
def initialize(adamantite, password_object = nil)
|
18
20
|
@password_object = password_object || PasswordObject.new
|
19
|
-
@
|
20
|
-
@master_pw_salt = master_pw_salt
|
21
|
+
@adamantite = adamantite
|
21
22
|
reset_editable_password_object
|
22
23
|
end
|
23
24
|
|
@@ -32,12 +33,17 @@ module Adamantite
|
|
32
33
|
# saves editable user data and returns final user to add to DB/File/Array/etc...
|
33
34
|
def save
|
34
35
|
return false unless @password_object.password == @password_object.password_confirmation
|
36
|
+
|
35
37
|
@password_object.website_title = @editable_password_object.website_title
|
36
38
|
@password_object.username = @editable_password_object.username
|
37
39
|
@password_object.password = @editable_password_object.password
|
38
40
|
@password_object.password_confirmation = @editable_password_object.password_confirmation
|
39
|
-
|
40
|
-
|
41
|
+
@password_object.dir_name = @adamantite.save_password(@password_object.website_title,
|
42
|
+
@password_object.username,
|
43
|
+
@password_object.password,
|
44
|
+
@password_object.password_confirmation)
|
45
|
+
|
46
|
+
@adamantite.delete_password(@password_object.initial_dir_name) if @password_object.initial_dir_name
|
41
47
|
@password_object
|
42
48
|
end
|
43
49
|
|
@@ -48,4 +54,4 @@ module Adamantite
|
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
51
|
-
end
|
57
|
+
end
|
data/lib/base/password_object.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Adamantite
|
2
4
|
module Base
|
3
5
|
class PasswordObject
|
4
|
-
attr_accessor :website_title, :username, :password, :password_confirmation,
|
6
|
+
attr_accessor :website_title, :username, :password, :password_confirmation,
|
7
|
+
:row_index, :dir_name, :initial_dir_name
|
5
8
|
|
6
|
-
def initialize(website_title = nil, username = nil, password = nil,
|
9
|
+
def initialize(website_title = nil, username = nil, password = nil,
|
10
|
+
password_confirmation = nil, row_index = nil, initial_dir_name = nil)
|
7
11
|
@website_title = website_title
|
8
12
|
@username = username
|
9
13
|
@password = password
|
10
14
|
@password_confirmation = password_confirmation
|
11
15
|
@row_index = row_index
|
16
|
+
@initial_dir_name = initial_dir_name
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
15
|
-
end
|
20
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Adamantite
|
6
|
+
module AdamantiteFileUtils
|
7
|
+
def home_dir
|
8
|
+
ENV['HOME']
|
9
|
+
end
|
10
|
+
|
11
|
+
def pwmanager_dir
|
12
|
+
File.join(home_dir, '.adamantite')
|
13
|
+
end
|
14
|
+
|
15
|
+
def pwmanager_tmp_dir
|
16
|
+
File.join(home_dir, '.adamantite_tmp')
|
17
|
+
end
|
18
|
+
|
19
|
+
def pwmanager_dir_exists?
|
20
|
+
Dir.exist?(pwmanager_dir)
|
21
|
+
end
|
22
|
+
|
23
|
+
def make_pwmanager_dir
|
24
|
+
Dir.mkdir(pwmanager_dir)
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_password_dir(password_dir_title)
|
28
|
+
Dir.mkdir(File.join(pwmanager_dir, password_dir_title))
|
29
|
+
end
|
30
|
+
|
31
|
+
def pw_file(title)
|
32
|
+
File.join(pwmanager_dir, title)
|
33
|
+
end
|
34
|
+
|
35
|
+
def password_file(*args)
|
36
|
+
File.join(pwmanager_dir, *args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def pw_file_exists?(title)
|
40
|
+
File.exist?(pw_file(title))
|
41
|
+
end
|
42
|
+
|
43
|
+
def write_pw_to_file(title, **kwargs)
|
44
|
+
make_pwmanager_dir unless pwmanager_dir_exists?
|
45
|
+
|
46
|
+
File.open(pw_file(title), 'w') do |f|
|
47
|
+
JSON.dump(kwargs, f)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_to_file(file_name, file_contents, binary)
|
52
|
+
if binary
|
53
|
+
File.open(file_name, 'wb') do |f|
|
54
|
+
f.write(file_contents)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
File.open(file_name, 'w') do |f|
|
58
|
+
f.write(file_contents)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def read_file(file_name, binary)
|
64
|
+
if binary
|
65
|
+
File.open(file_name, 'rb', &:read)
|
66
|
+
else
|
67
|
+
File.open(file_name, 'r', &:read)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete_pw_file(title)
|
72
|
+
File.delete(pw_file(title))
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_pw_file(title)
|
76
|
+
JSON.load_file(pw_file(title))
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_master_password_info
|
80
|
+
get_pw_file('master')
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_master_password_hash
|
84
|
+
File.open(pw_file('master_password_hash'), 'rb', &:read)
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_master_password_salt
|
88
|
+
File.open(pw_file('master_password_salt'), 'rb', &:read)
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_master_encrypted_vault_key
|
92
|
+
File.open(pw_file('master_encrypted_vault_key'), 'rb', &:read)
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_stored_pws
|
96
|
+
excluded_filenames = ['.', '..', 'master_password_hash', 'master_password_salt', 'master_encrypted_vault_key']
|
97
|
+
Dir.entries(pwmanager_dir).filter { |f| !excluded_filenames.include?(f) }
|
98
|
+
end
|
99
|
+
|
100
|
+
def master_password_exists?
|
101
|
+
pw_file_exists?('master_encrypted_vault_key') && pw_file_exists?('master_password_salt')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|