adamantite 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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 -13
- 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: 47190df18bbcffa68fd20d16d9ffb048f6f7b0b521104727f3e849a40aa29b48
|
4
|
+
data.tar.gz: 6acad9247d871f293b81f33976ce37b6465e043afacf5849fa31edf8640475ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36b1e5ac28a539c7a2e5461bcfa4b0d0c512ae572ff8e8b2b4faf56b52a9212e0d2566e89c963b7347782d03a43cfdde3179289a2f0b73a3dd582e7855a5be51
|
7
|
+
data.tar.gz: 7a46bbccbf113303a4ed2f6db562ecd4c59f4fbdf8abcaff582e9c7e0425869b02f4b1a3a778f356ce22f22196ffabff31cdb40234029e95f783584c538cbb74
|
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
|