gtk2passwordapp 1.8.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +2 -8
- data/bin/{gtk2passwordapp → gtk2passwordapp2} +4 -7
- data/lib/gtk2passwordapp/appconfig.rb +23 -21
- data/lib/gtk2passwordapp/iocrypt.rb +2 -2
- data/lib/gtk2passwordapp/passwords.rb +31 -91
- data/lib/gtk2passwordapp/passwords_data.rb +64 -50
- data/lib/gtk2passwordapp/rnd.rb +34 -19
- data/lib/gtk2passwordapp.rb +18 -12
- metadata +7 -7
data/README.txt
CHANGED
@@ -5,24 +5,18 @@ Uses crypt-tea's Tiny Encryption Algorithm to encrypt the datafile.
|
|
5
5
|
Features random password generator and clipboard use.
|
6
6
|
|
7
7
|
|
8
|
-
The main purpose of version 1.8 is to fix the "trust range" from "> 0" to "~> 1.0", so that version one can co-exist with version 2.
|
9
|
-
|
10
8
|
To add an account, enter the new account name in the "Account:" entry/combo box. For the account, write the associated url, a note about the account, and the username in the appropriate entry boxes.
|
11
9
|
|
12
|
-
To set a new password, either enter the password in the "
|
10
|
+
To set a new password, either enter the password in the "Password:" entry box, or generate it by pressing "Random", "Alpha-Numeric", "Numeric", "Letters", or "All-Caps". One can set the password length generated with the spin-box. To make the password generated visible, un-check the check button.
|
13
11
|
|
14
12
|
Once one has edited the account, clicking the "Update Account" button finalizes the record. Note, however, that the change is not yet permanent and saved on disk. To delete an account, select the account in the entry/combo box, and the press the "Delete Account" button. Once one is done with all updates, one then needs to press "Save To Disk". Clicking the "Close" button or closing the window without "Save To Disk" will ignore all of the sessions updates.
|
15
13
|
|
16
14
|
The "Clip Current Password" button copies the current password to the primary clipboard. The "Clip Previous Password" button copies the previous (old) password to the primary clipboard. The "Change Data File Password" button will allow one the change the master password. Do not forget the master password!
|
17
15
|
|
18
|
-
Right click most anywhere on the app's window for the main menu. "Close" will dock the
|
16
|
+
Right click most anywhere on the app's window for the main menu. "Close" will dock the application and has the same effect as the "Close" button.
|
19
17
|
|
20
18
|
Left click on the docked icon to bring back the editor window. Right click on the docked icon to select one of the accounts to load the password and username to the clipboard. The password is copied to the primary clipboard and will paste on middle mouse button click. Right click on an entry box to paste the username (via the clipboard's menu).
|
21
19
|
|
22
|
-
Lastly, do not edit
|
23
|
-
~/.gtk2passwordapp-1/passphrase.txt
|
24
|
-
It's used to "salt" the password... without it, one will not be able to decrypt the datafile.
|
25
|
-
|
26
20
|
For full documentation and comments, see
|
27
21
|
https://sites.google.com/site/gtk2applib/home/gtk2applib-applications/gtk2passwordapp
|
28
22
|
|
@@ -2,16 +2,13 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
gem 'gtk2applib', '~> 15.3'
|
4
4
|
require 'gtk2applib'
|
5
|
-
gem 'gtk2passwordapp', '~> 1.0'
|
6
5
|
require 'gtk2passwordapp'
|
7
6
|
|
8
7
|
if $options=~/-no-gui/ then
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
puts "Warning: selected passwords will be shown."
|
14
|
-
print "Enter Account pattern:"
|
8
|
+
print Gtk2Password::Configuration::COMMAND_LINE_MSG1
|
9
|
+
pwd = $stdin.gets.strip
|
10
|
+
passwords = Gtk2Password::Passwords.new(Gtk2Password::Configuration::PASSWORDS_FILE, pwd)
|
11
|
+
print Gtk2Password::Configuration::COMMAND_LINE_MSG2
|
15
12
|
pattern = Regexp.new( $stdin.gets.strip, Regexp::IGNORECASE )
|
16
13
|
passwords.accounts.each do |account|
|
17
14
|
if account =~ pattern then
|
@@ -1,10 +1,8 @@
|
|
1
|
-
# Note: you'll see in ~/.gtk2passwordapp-* a file called passphrase.txt.
|
2
|
-
# Do not edit or delete passphrase, or you'll loose your passwords data.
|
3
|
-
|
4
1
|
module Gtk2AppLib
|
5
|
-
# Only one gtk2passwordapp will be allowed to run.
|
6
|
-
# Will kill a duplicate proccess...
|
7
|
-
Lock.lock_mode
|
2
|
+
# Only one gtk2passwordapp will be allowed to run.
|
3
|
+
# Will kill a duplicate proccess...
|
4
|
+
Lock.lock_mode
|
5
|
+
|
8
6
|
module Configuration
|
9
7
|
|
10
8
|
padding = Widgets::WIDGET[:Widgets][:pack_start].last
|
@@ -22,7 +20,7 @@ module Configuration
|
|
22
20
|
spin = 75
|
23
21
|
check = 25
|
24
22
|
if Gtk2AppLib::Configuration::OSTYPE == 'Internet Tablet OS: maemo Linux based OS2008' then
|
25
|
-
# Icon works on N800, but not
|
23
|
+
# Icon works on N800, but not N900 (Maemo 5)
|
26
24
|
MENU[:close] = '_Close'
|
27
25
|
end
|
28
26
|
else
|
@@ -82,12 +80,12 @@ module Gtk2Password
|
|
82
80
|
module Configuration
|
83
81
|
# Note that the passwords data file name is auto generated, but...
|
84
82
|
# You can place your passwords data file in a directory other than ~/gtk2passwordapp-*
|
85
|
-
|
83
|
+
PASSWORDS_FILE = File.join( Gtk2AppLib::USERDIR, 'passwords.dat' )
|
86
84
|
# Switches the roles of PRIMARY and CLIPBOARD when true
|
87
85
|
SWITCH_CLIPBOARDS = (Gtk2AppLib::HILDON || !Gtk2AppLib::Configuration::X)? true: false
|
88
86
|
PASSWORD_EXPIRED = 60*60*24*30*3 # 3 months
|
89
87
|
URL_PATTERN = Regexp.new('^https?:\/\/[^\s\']+$')
|
90
|
-
DEFAULT_PASSWORD_LENGTH =
|
88
|
+
DEFAULT_PASSWORD_LENGTH = 16
|
91
89
|
EXPIRED_COLOR = Gtk2AppLib::Color[:Red]
|
92
90
|
|
93
91
|
BAD_URL = ['Need url like http://www.site.com/page.html',{:TITLE => 'Error: Bad Url',:SCROLLED_WINDOW => false}]
|
@@ -113,22 +111,26 @@ module Configuration
|
|
113
111
|
['Datafile', hbox, [:Datafile_Button]],
|
114
112
|
['Clip', hbox, [:Current_Button,:Previous_Button]],
|
115
113
|
]
|
114
|
+
|
115
|
+
# These are the prompts for passwords
|
116
|
+
PASSWORD = 'Password' # for when for asking.
|
117
|
+
AGAIN = 'Again' # for when verifying new passwords.
|
118
|
+
RETRY = 'Retry' # for when you got your password wrong.
|
119
|
+
|
120
|
+
# These are the --no-gui dialogs...
|
121
|
+
COMMAND_LINE_MSG1 = "Warning: password will be shown.\nPassword:"
|
122
|
+
COMMAND_LINE_MSG2 = "Warning: selected passwords will be shown.\nEnter Account pattern:"
|
116
123
|
end
|
117
124
|
|
118
|
-
def self.passwords_updated
|
125
|
+
def self.passwords_updated
|
119
126
|
## After the password files are saved, you have the option here to backup or mirror the files elsewhere.
|
120
127
|
## Here's an example:
|
121
|
-
#
|
122
|
-
# system( "
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
# Gtk2AppLib::DIALOGS.quick_message("Passwords saved on 192.168.1.101 and 102")
|
128
|
-
# return
|
129
|
-
# end
|
130
|
-
# end
|
131
|
-
# Gtk2AppLib::DIALOGS.quick_message("Warning: Could not create backup on 192.168.1.123")
|
128
|
+
#n = '123'
|
129
|
+
#if system( "scp ~/.gtk2passwordapp-2/passwords.dat user@192.168.1.#{n}:.gtk2passwordapp-2/passwords.dat") then
|
130
|
+
# Gtk2AppLib::DIALOGS.quick_message("Passwords saved on 192.168.1.#{n}",{:TITLE => 'Saved',:SCROLLED_WINDOW => false})
|
131
|
+
# return
|
132
|
+
#end
|
133
|
+
#Gtk2AppLib::DIALOGS.quick_message("Warning: Could not create backup on 192.168.1.#{n}",{:TITLE => 'Warning',:SCROLLED_WINDOW => false})
|
132
134
|
Gtk2AppLib::DIALOGS.quick_message("Passwords Data Saved.",{:TITLE => 'Saved',:SCROLLED_WINDOW => false})
|
133
135
|
end
|
134
136
|
end
|
@@ -11,10 +11,10 @@ end
|
|
11
11
|
module Gtk2Password
|
12
12
|
# Wrapper around Crypt::XXTEA
|
13
13
|
class IOCrypt
|
14
|
-
LENGTH =
|
14
|
+
LENGTH = 16
|
15
15
|
|
16
16
|
def initialize(passphrase)
|
17
|
-
@key = Crypt::XXTEA.new(passphrase[0..LENGTH])
|
17
|
+
@key = Crypt::XXTEA.new(passphrase[0..(LENGTH-1)])
|
18
18
|
end
|
19
19
|
|
20
20
|
def load(dumpfile)
|
@@ -1,104 +1,44 @@
|
|
1
1
|
require 'gtk2passwordapp/passwords_data'
|
2
|
-
require 'gtk2passwordapp/rnd'
|
3
2
|
module Gtk2Password
|
4
3
|
# Passwords subclasses PasswordsData :P
|
5
4
|
class Passwords < PasswordsData
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
# Configurable prompts
|
7
|
+
PROMPT = {
|
8
|
+
:password => 'Password',
|
9
|
+
:again => 'Again',
|
10
|
+
:retry => 'Retry',
|
11
|
+
}
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
return passphrase
|
36
|
-
end
|
37
|
-
|
38
|
-
def has_datafile?
|
39
|
-
Find.find(Gtk2AppLib::USERDIR){|fn|
|
40
|
-
Find.prune if !(fn==Gtk2AppLib::USERDIR) && File.directory?(fn)
|
41
|
-
if fn =~/[0123456789abcdef]{32}\.dat$/ then
|
42
|
-
return true
|
43
|
-
end
|
44
|
-
}
|
45
|
-
return false
|
46
|
-
end
|
47
|
-
|
48
|
-
def self._get_salt(prompt)
|
49
|
-
(ret = Gtk2Password.get_salt(prompt,'Salt')) || exit
|
50
|
-
ret.strip
|
51
|
-
end
|
52
|
-
|
53
|
-
attr_reader :pfile
|
54
|
-
def initialize(pwd=nil)
|
55
|
-
@pwd = pwd || Passwords._get_salt('Short Password')
|
56
|
-
@pfile = nil
|
57
|
-
@pph = get_passphrase
|
58
|
-
super(@pwd+@pph)
|
59
|
-
# Password file exist?
|
60
|
-
if self.exist? # then
|
61
|
-
# Yes, load passwords file.
|
62
|
-
self.load
|
63
|
-
else
|
64
|
-
raise "bad salt" if pwd
|
65
|
-
# No, check if there is a file....
|
66
|
-
if has_datafile? # then
|
67
|
-
# Yes, it's got a datafile. Ask for password again.
|
68
|
-
while !self.exist? do
|
69
|
-
@pwd = Passwords._get_salt('Try again!')
|
70
|
-
super(@pwd+@pph)
|
71
|
-
end
|
72
|
-
self.load
|
73
|
-
else
|
74
|
-
# Else, must be a new install.
|
75
|
-
pwd = @pwd
|
76
|
-
@pwd = Passwords._get_salt('Verify New Password')
|
77
|
-
while !(pwd == @pwd) do
|
78
|
-
pwd = Passwords._get_salt('Try again!')
|
79
|
-
@pwd = Passwords._get_salt('Verify New Password')
|
13
|
+
def initialize(dump,pwd=nil)
|
14
|
+
if pwd.nil? then
|
15
|
+
pwd = yield(PROMPT[:password])
|
16
|
+
again = true
|
17
|
+
while again do
|
18
|
+
super(dump,pwd)
|
19
|
+
begin
|
20
|
+
# Password file exist?
|
21
|
+
if self.exist? # then
|
22
|
+
# Yes, load passwords file.
|
23
|
+
self.load
|
24
|
+
else
|
25
|
+
verify = nil
|
26
|
+
while !(verify == pwd) do
|
27
|
+
verify = pwd
|
28
|
+
pwd = yield(PROMPT[:again])
|
29
|
+
end
|
30
|
+
super(dump,pwd)
|
31
|
+
self.save
|
32
|
+
end
|
33
|
+
again = false # good to go!
|
34
|
+
rescue StandardError
|
35
|
+
pwd = yield(PROMPT[:retry])
|
80
36
|
end
|
81
|
-
super(@pwd+@pph)
|
82
|
-
self.save
|
83
37
|
end
|
84
|
-
end
|
85
|
-
# Off to the races...
|
86
|
-
end
|
87
|
-
|
88
|
-
def save(pwd=nil)
|
89
|
-
if pwd.nil? then
|
90
|
-
super()
|
91
38
|
else
|
92
|
-
|
93
|
-
pph = get_passphrase(true) # new passphrase
|
94
|
-
dfbak = self.dumpfile + '.bak'
|
95
|
-
super(pwd+pph)
|
96
|
-
@pwd = pwd
|
97
|
-
@pph = pph
|
98
|
-
File.unlink(pfbak) if File.exist?(pfbak)
|
99
|
-
File.unlink(dfbak) if File.exist?(dfbak)
|
39
|
+
super(dump,pwd)
|
100
40
|
end
|
101
|
-
|
41
|
+
# Off to the races...
|
102
42
|
end
|
103
43
|
|
104
44
|
end
|
@@ -4,9 +4,6 @@ require 'digest/md5'
|
|
4
4
|
module Gtk2Password
|
5
5
|
# PasswordsData maitains passwords
|
6
6
|
class PasswordsData
|
7
|
-
include Configuration
|
8
|
-
attr_accessor :account
|
9
|
-
attr_reader :data, :dumpfile
|
10
7
|
|
11
8
|
PASSWORD = 0
|
12
9
|
PREVIOUS = 1
|
@@ -15,14 +12,18 @@ class PasswordsData
|
|
15
12
|
URL = 4
|
16
13
|
LAST_UPDATE = 5
|
17
14
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
@
|
15
|
+
def reset(password)
|
16
|
+
# MD5 digest length is 16 to match tiny encryption's block length
|
17
|
+
passphrase = Digest::MD5.digest( password )
|
18
|
+
@iocrypt = IOCrypt.new(passphrase)
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
|
21
|
+
attr_reader :data
|
22
|
+
attr_accessor :expired, :dumpfile
|
23
|
+
def initialize(dumpfile,password)
|
24
|
+
reset(password) # sets @iocrypt
|
25
|
+
@dumpfile = dumpfile
|
26
|
+
@expired = 60*60*24*30*3 # 3 months
|
26
27
|
@data = {}
|
27
28
|
end
|
28
29
|
|
@@ -30,33 +31,36 @@ class PasswordsData
|
|
30
31
|
File.exist?(@dumpfile)
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
# will raise an exception on failed decryption
|
35
|
+
def load
|
36
|
+
data = @iocrypt.load(@dumpfile)
|
37
|
+
raise "decryption error" unless data.class == Hash
|
38
|
+
@data = data
|
37
39
|
end
|
38
40
|
|
39
|
-
def save
|
41
|
+
def save
|
40
42
|
# just in case, keep a backup
|
41
|
-
|
42
|
-
_reset(passphrase) if !passphrase.nil?
|
43
|
-
iocrypt = IOCrypt.new(@passphrase)
|
44
|
-
iocrypt.dump(@dumpfile, @data)
|
43
|
+
@iocrypt.dump(@dumpfile, @data)
|
45
44
|
File.chmod(0600, @dumpfile)
|
46
45
|
end
|
47
46
|
|
47
|
+
def save!(password)
|
48
|
+
reset(password)
|
49
|
+
save
|
50
|
+
end
|
51
|
+
|
48
52
|
def add(account)
|
49
|
-
raise "
|
50
|
-
raise "
|
51
|
-
@data[account] = ['','','','','']
|
53
|
+
raise "pre-existing" unless @data[account].nil?
|
54
|
+
raise "can't have nil account" if account.nil?
|
55
|
+
@data[account] = [ '', '', '', '', '', 0 ]
|
52
56
|
end
|
53
57
|
|
54
58
|
def accounts
|
55
|
-
@data.keys.sort
|
59
|
+
@data.keys.sort{|a,b| a.upcase <=> b.upcase }
|
56
60
|
end
|
57
61
|
|
58
62
|
def include?(account)
|
59
|
-
return
|
63
|
+
return !@data[account].nil?
|
60
64
|
end
|
61
65
|
|
62
66
|
def verify?(account,password)
|
@@ -64,55 +68,65 @@ class PasswordsData
|
|
64
68
|
end
|
65
69
|
|
66
70
|
def delete(account)
|
67
|
-
raise "#{account} not found" if
|
71
|
+
raise "#{account} not found" if @data[account].nil?
|
68
72
|
@data.delete(account)
|
69
73
|
end
|
70
74
|
|
71
|
-
def
|
75
|
+
def get_data_account(account)
|
72
76
|
data_account = @data[account]
|
73
77
|
raise "#{account} not found" if data_account.nil?
|
74
|
-
data_account
|
75
|
-
|
78
|
+
return data_account
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.url_of(data_account, url)
|
82
|
+
data_account[URL] = url unless url.nil?
|
83
|
+
return data_account[URL]
|
84
|
+
end
|
85
|
+
|
86
|
+
def url_of(account, url=nil)
|
87
|
+
PasswordsData.url_of( get_data_account(account), url )
|
76
88
|
end
|
77
89
|
|
78
90
|
def expired?(account)
|
79
|
-
data_account =
|
80
|
-
raise "#{account} not found" if data_account.nil?
|
91
|
+
data_account = get_data_account(account)
|
81
92
|
last_update = data_account[LAST_UPDATE]
|
82
|
-
|
83
|
-
|
93
|
+
((Time.now.to_i - last_update) > @expired)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.password_of(data_account,password)
|
97
|
+
data_account[PREVIOUS] = data_account[PASSWORD]
|
98
|
+
data_account[PASSWORD] = password
|
99
|
+
data_account[LAST_UPDATE] = Time.now.to_i
|
84
100
|
end
|
85
101
|
|
86
102
|
def password_of(account, password=nil)
|
87
|
-
data_account =
|
88
|
-
|
89
|
-
|
90
|
-
data_account[PREVIOUS] = data_account[PASSWORD]
|
91
|
-
data_account[PASSWORD] = password
|
92
|
-
data_account[LAST_UPDATE] = Time.now.to_i
|
93
|
-
end
|
94
|
-
return data_account[PASSWORD] || ''
|
103
|
+
data_account = get_data_account(account)
|
104
|
+
PasswordsData.password_of(data_account,password) unless password.nil?
|
105
|
+
return data_account[PASSWORD]
|
95
106
|
end
|
96
107
|
|
97
108
|
# previous password
|
98
109
|
def previous_password_of(account)
|
99
|
-
data_account =
|
100
|
-
|
101
|
-
|
110
|
+
data_account = get_data_account(account)
|
111
|
+
return data_account[PREVIOUS]
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.note_of(data_account,note)
|
115
|
+
data_account[NOTE] = note unless note.nil?
|
116
|
+
return data_account[NOTE]
|
102
117
|
end
|
103
118
|
|
104
119
|
def note_of(account, note=nil)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
120
|
+
PasswordsData.note_of( get_data_account(account), note )
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.username_of(data_account,usr)
|
124
|
+
data_account[USERNAME] = usr unless usr.nil?
|
125
|
+
return data_account[USERNAME]
|
109
126
|
end
|
110
127
|
|
111
128
|
def username_of(account, usr=nil)
|
112
|
-
|
113
|
-
raise "#{account} not found" if data_account.nil?
|
114
|
-
data_account[USERNAME] = usr if !usr.nil?
|
115
|
-
return data_account[USERNAME] || ''
|
129
|
+
PasswordsData.username_of( get_data_account(account), usr )
|
116
130
|
end
|
117
131
|
end
|
118
132
|
end
|
data/lib/gtk2passwordapp/rnd.rb
CHANGED
@@ -12,47 +12,62 @@ module Gtk2Password
|
|
12
12
|
REALRAND = false
|
13
13
|
end
|
14
14
|
|
15
|
+
BUCKET_LENGTH = 100
|
16
|
+
NUMBERS = [75,10,58,26,94]
|
17
|
+
LCF = 2657850
|
18
|
+
|
19
|
+
attr_reader :bucket, :refilling
|
15
20
|
def initialize
|
16
21
|
@bucket = []
|
17
22
|
@refilling = false
|
18
23
|
self.refill if REALRAND
|
19
24
|
end
|
20
25
|
|
26
|
+
def refill_timeout
|
27
|
+
Timeout.timeout(60) do
|
28
|
+
generator = Random::RandomOrg.new
|
29
|
+
@bucket += generator.randnum(BUCKET_LENGTH, 0, LCF - 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
21
33
|
def refill
|
22
34
|
return if @refilling
|
23
35
|
@refilling = true
|
24
36
|
Thread.new do
|
25
37
|
begin
|
26
|
-
|
27
|
-
|
28
|
-
@bucket += generator1.randnum(200, 0, 2657849) # 2657850 % <75,10,58,26,94>
|
29
|
-
end
|
38
|
+
Thread.pass
|
39
|
+
refill_timeout
|
30
40
|
rescue Exception
|
31
41
|
$stderr.puts $!
|
32
|
-
$stderr.puts "Failed to fill the bucket"
|
33
42
|
ensure
|
34
43
|
@refilling = false
|
35
44
|
end
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
39
|
-
def
|
40
|
-
|
48
|
+
def self.randomize(rnd,number)
|
49
|
+
((rnd + rand(number)) % number)
|
50
|
+
end
|
51
|
+
|
52
|
+
def real_random(number)
|
53
|
+
refill if @bucket.length < BUCKET_LENGTH/2
|
54
|
+
if rnd = @bucket.shift then
|
55
|
+
return Rnd.randomize(rnd,number)
|
56
|
+
else
|
57
|
+
return rand(number)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate(number)
|
62
|
+
if !NUMBERS.include?(number) then
|
41
63
|
$stderr.puts "Did not code for that number"
|
42
64
|
exit # seriously messed up! :))
|
43
65
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
return rand(n)
|
51
|
-
end
|
52
|
-
else
|
53
|
-
return rand(n)
|
54
|
-
end
|
55
|
-
raise "Should not get here"
|
66
|
+
end
|
67
|
+
|
68
|
+
def random(number)
|
69
|
+
validate(number)
|
70
|
+
(REALRAND)? real_random(number) : rand(number)
|
56
71
|
end
|
57
72
|
|
58
73
|
RND = Rnd.new
|
data/lib/gtk2passwordapp.rb
CHANGED
@@ -4,18 +4,22 @@ require 'gtk2passwordapp/rnd'
|
|
4
4
|
module Gtk2Password
|
5
5
|
|
6
6
|
ABOUT = {
|
7
|
-
'name' => 'Ruby-Gnome Password Manager',
|
7
|
+
'name' => 'Ruby-Gnome Password Manager II',
|
8
8
|
'authors' => ['carlosjhr64@gmail.com'],
|
9
9
|
'website' => 'https://sites.google.com/site/gtk2applib/home/gtk2applib-applications/gtk2passwordapp',
|
10
10
|
'website-label' => 'Ruby-Gnome Password Manager',
|
11
11
|
'license' => 'GPL',
|
12
|
-
'copyright' => '2011-
|
12
|
+
'copyright' => '2011-07-02 17:53:12',
|
13
13
|
}
|
14
14
|
|
15
15
|
PRIMARY = Gtk::Clipboard.get((Configuration::SWITCH_CLIPBOARDS)? Gdk::Selection::CLIPBOARD: Gdk::Selection::PRIMARY)
|
16
16
|
CLIPBOARD = Gtk::Clipboard.get((Configuration::SWITCH_CLIPBOARDS)? Gdk::Selection::PRIMARY: Gdk::Selection::CLIPBOARD)
|
17
17
|
|
18
|
-
|
18
|
+
Passwords::PROMPT[:password] = Configuration::PASSWORD
|
19
|
+
Passwords::PROMPT[:again] = Configuration::AGAIN
|
20
|
+
Passwords::PROMPT[:retry] = Configuration::RETRY
|
21
|
+
|
22
|
+
def self.get_password(prompt,title=prompt)
|
19
23
|
Gtk2AppLib::DIALOGS.entry( prompt, {:TITLE=>title, :Entry => [{:visibility= => false},'activate']} )
|
20
24
|
end
|
21
25
|
|
@@ -31,7 +35,9 @@ module Gtk2Password
|
|
31
35
|
|
32
36
|
def initialize(program)
|
33
37
|
@program = program
|
34
|
-
@passwords = Gtk2Password::Passwords.new
|
38
|
+
@passwords = Gtk2Password::Passwords.new(Configuration::PASSWORDS_FILE) do |prompt|
|
39
|
+
Gtk2Password.get_password(prompt) || exit
|
40
|
+
end
|
35
41
|
@modified = false
|
36
42
|
self.build_menu
|
37
43
|
program.window do |window|
|
@@ -60,8 +66,8 @@ module Gtk2Password
|
|
60
66
|
end
|
61
67
|
|
62
68
|
def _save
|
63
|
-
|
64
|
-
Gtk2Password.passwords_updated
|
69
|
+
@passwords.save
|
70
|
+
Gtk2Password.passwords_updated
|
65
71
|
build_menu
|
66
72
|
end
|
67
73
|
|
@@ -220,16 +226,16 @@ module Gtk2Password
|
|
220
226
|
end
|
221
227
|
|
222
228
|
when @gui[:datafile_button]
|
223
|
-
if pwd1 = Gtk2Password.
|
224
|
-
if pwd2 = Gtk2Password.
|
229
|
+
if pwd1 = Gtk2Password.get_password(Passwords::PROMPT[:password]) then
|
230
|
+
if pwd2 = Gtk2Password.get_password(Passwords::PROMPT[:again]) then
|
225
231
|
while !(pwd1==pwd2) do
|
226
|
-
pwd1 = Gtk2Password.
|
232
|
+
pwd1 = Gtk2Password.get_password(Passwords::PROMPT[:retry])
|
227
233
|
return if !pwd1
|
228
|
-
pwd2 = Gtk2Password.
|
234
|
+
pwd2 = Gtk2Password.get_password(Passwords::PROMPT[:again])
|
229
235
|
return if !pwd2
|
230
236
|
end
|
231
|
-
|
232
|
-
Gtk2Password.passwords_updated
|
237
|
+
@passwords.save!(pwd1)
|
238
|
+
Gtk2Password.passwords_updated
|
233
239
|
end
|
234
240
|
end
|
235
241
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gtk2passwordapp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 8
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- carlosjhr64@gmail.com
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-02 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: crypt-tea
|
@@ -55,7 +55,7 @@ description: |
|
|
55
55
|
|
56
56
|
email: carlosjhr64@gmail.com
|
57
57
|
executables:
|
58
|
-
-
|
58
|
+
- gtk2passwordapp2
|
59
59
|
extensions: []
|
60
60
|
|
61
61
|
extra_rdoc_files: []
|
@@ -70,7 +70,7 @@ files:
|
|
70
70
|
- ./pngs/logo.png
|
71
71
|
- ./pngs/icon.png
|
72
72
|
- README.txt
|
73
|
-
- bin/
|
73
|
+
- bin/gtk2passwordapp2
|
74
74
|
homepage: https://sites.google.com/site/gtk2applib/home/gtk2applib-applications/gtk2passwordapp
|
75
75
|
licenses: []
|
76
76
|
|