gtk2passwordapp 3.0.1 → 4.0.1
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/README.rdoc +63 -0
- data/bin/gtk2passwordapp +120 -0
- data/data/VERSION +1 -0
- data/data/logo.png +0 -0
- data/lib/gtk2passwordapp.rb +19 -305
- data/lib/gtk2passwordapp/account.rb +75 -0
- data/lib/gtk2passwordapp/accounts.rb +53 -0
- data/lib/gtk2passwordapp/config.rb +158 -0
- data/lib/gtk2passwordapp/gtk2passwordapp.rb +457 -0
- data/lib/gtk2passwordapp/such_parts.rb +22 -0
- data/lib/gtk2passwordapp/version.rb +3 -0
- metadata +166 -26
- data/README.txt +0 -40
- data/bin/gtk2passwordapp3 +0 -60
- data/lib/gtk2passwordapp/appconfig.rb +0 -171
- data/lib/gtk2passwordapp/iocrypt.rb +0 -48
- data/lib/gtk2passwordapp/passwords.rb +0 -45
- data/lib/gtk2passwordapp/passwords_data.rb +0 -130
- data/lib/gtk2passwordapp/rnd.rb +0 -88
- data/pngs/icon.png +0 -0
- data/pngs/logo.png +0 -0
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
require 'zlib'
|
3
|
-
require 'openssl'
|
4
|
-
require 'digest/sha2'
|
5
|
-
|
6
|
-
YAML::ENGINE.yamler = 'psych' # ensure it's psych
|
7
|
-
|
8
|
-
module Gtk2Password
|
9
|
-
|
10
|
-
class IOCrypt
|
11
|
-
def initialize(passphrase)
|
12
|
-
@key = Digest::SHA256.digest passphrase
|
13
|
-
end
|
14
|
-
|
15
|
-
def _cipher(mode, data)
|
16
|
-
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(mode)
|
17
|
-
cipher.key = @key
|
18
|
-
cipher.update(data) << cipher.final
|
19
|
-
end
|
20
|
-
|
21
|
-
def _decrypt(e)
|
22
|
-
Zlib::Inflate.inflate(_cipher(:decrypt, e))
|
23
|
-
end
|
24
|
-
|
25
|
-
def _encrypt(p)
|
26
|
-
_cipher(:encrypt, Zlib::Deflate.deflate(p))
|
27
|
-
end
|
28
|
-
|
29
|
-
def load(dumpfile)
|
30
|
-
data = nil
|
31
|
-
begin
|
32
|
-
File.open(dumpfile,'r'){|fh| data = YAML.load( _decrypt( fh.read ) ) }
|
33
|
-
rescue Psych::SyntaxError
|
34
|
-
# assume it's syck
|
35
|
-
YAML::ENGINE.yamler = 'syck'
|
36
|
-
File.open(dumpfile,'r'){|fh| data = YAML.load( _decrypt( fh.read ) ) }
|
37
|
-
YAML::ENGINE.yamler = 'psych' # make it psych
|
38
|
-
end
|
39
|
-
return data
|
40
|
-
end
|
41
|
-
|
42
|
-
def dump(dumpfile, data)
|
43
|
-
count = nil
|
44
|
-
File.open(dumpfile,'w') { |fh| count = fh.write( _encrypt( YAML.dump( data ) ) ) }
|
45
|
-
return count
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'gtk2passwordapp/passwords_data'
|
2
|
-
module Gtk2Password
|
3
|
-
# Passwords subclasses PasswordsData :P
|
4
|
-
class Passwords < PasswordsData
|
5
|
-
|
6
|
-
# Configurable prompts
|
7
|
-
PROMPT = {
|
8
|
-
:password => 'Password',
|
9
|
-
:again => 'Again',
|
10
|
-
:retry => 'Retry',
|
11
|
-
}
|
12
|
-
|
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])
|
36
|
-
end
|
37
|
-
end
|
38
|
-
else
|
39
|
-
super(dump,pwd)
|
40
|
-
end
|
41
|
-
# Off to the races...
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'gtk2passwordapp/iocrypt'
|
2
|
-
require 'digest/md5'
|
3
|
-
|
4
|
-
module Gtk2Password
|
5
|
-
# PasswordsData maitains passwords
|
6
|
-
class PasswordsData
|
7
|
-
|
8
|
-
PASSWORD = 0
|
9
|
-
PREVIOUS = 1
|
10
|
-
NOTE = 2
|
11
|
-
USERNAME = 3
|
12
|
-
URL = 4
|
13
|
-
LAST_UPDATE = 5
|
14
|
-
|
15
|
-
def reset(password)
|
16
|
-
@iocrypt = IOCrypt.new(password)
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_reader :data
|
20
|
-
attr_accessor :expired, :dumpfile
|
21
|
-
def initialize(dumpfile,password)
|
22
|
-
reset(password) # sets @iocrypt
|
23
|
-
@dumpfile = dumpfile
|
24
|
-
@expired = 60*60*24*30*3 # 3 months
|
25
|
-
@data = {}
|
26
|
-
end
|
27
|
-
|
28
|
-
def exist?
|
29
|
-
File.exist?(@dumpfile)
|
30
|
-
end
|
31
|
-
|
32
|
-
# will raise an exception on failed decryption
|
33
|
-
def load
|
34
|
-
data = @iocrypt.load(@dumpfile)
|
35
|
-
raise "decryption error" unless data.class == Hash
|
36
|
-
@data = data
|
37
|
-
end
|
38
|
-
|
39
|
-
def save
|
40
|
-
# just in case, keep a backup
|
41
|
-
@iocrypt.dump(@dumpfile, @data)
|
42
|
-
File.chmod(0600, @dumpfile)
|
43
|
-
end
|
44
|
-
|
45
|
-
def save!(password)
|
46
|
-
reset(password)
|
47
|
-
save
|
48
|
-
end
|
49
|
-
|
50
|
-
def add(account)
|
51
|
-
raise "pre-existing" unless @data[account].nil?
|
52
|
-
raise "can't have nil account" if account.nil?
|
53
|
-
@data[account] = [ '', '', '', '', '', 0 ]
|
54
|
-
end
|
55
|
-
|
56
|
-
def accounts
|
57
|
-
@data.keys.sort{|a,b| a.upcase <=> b.upcase }
|
58
|
-
end
|
59
|
-
|
60
|
-
def include?(account)
|
61
|
-
return !@data[account].nil?
|
62
|
-
end
|
63
|
-
|
64
|
-
def verify?(account,password)
|
65
|
-
return @data[account][PASSWORD] == password
|
66
|
-
end
|
67
|
-
|
68
|
-
def delete(account)
|
69
|
-
raise "#{account} not found" if @data[account].nil?
|
70
|
-
@data.delete(account)
|
71
|
-
end
|
72
|
-
|
73
|
-
def get_data_account(account)
|
74
|
-
data_account = @data[account]
|
75
|
-
raise "#{account} not found" if data_account.nil?
|
76
|
-
return data_account
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.url_of(data_account, url)
|
80
|
-
data_account[URL] = url unless url.nil?
|
81
|
-
return data_account[URL]
|
82
|
-
end
|
83
|
-
|
84
|
-
def url_of(account, url=nil)
|
85
|
-
PasswordsData.url_of( get_data_account(account), url )
|
86
|
-
end
|
87
|
-
|
88
|
-
def expired?(account)
|
89
|
-
data_account = get_data_account(account)
|
90
|
-
last_update = data_account[LAST_UPDATE]
|
91
|
-
((Time.now.to_i - last_update) > @expired)
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.password_of(data_account,password)
|
95
|
-
data_account[PREVIOUS] = data_account[PASSWORD]
|
96
|
-
data_account[PASSWORD] = password
|
97
|
-
data_account[LAST_UPDATE] = Time.now.to_i
|
98
|
-
end
|
99
|
-
|
100
|
-
def password_of(account, password=nil)
|
101
|
-
data_account = get_data_account(account)
|
102
|
-
PasswordsData.password_of(data_account,password) unless password.nil?
|
103
|
-
return data_account[PASSWORD]
|
104
|
-
end
|
105
|
-
|
106
|
-
# previous password
|
107
|
-
def previous_password_of(account)
|
108
|
-
data_account = get_data_account(account)
|
109
|
-
return data_account[PREVIOUS]
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.note_of(data_account,note)
|
113
|
-
data_account[NOTE] = note unless note.nil?
|
114
|
-
return data_account[NOTE]
|
115
|
-
end
|
116
|
-
|
117
|
-
def note_of(account, note=nil)
|
118
|
-
PasswordsData.note_of( get_data_account(account), note )
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.username_of(data_account,usr)
|
122
|
-
data_account[USERNAME] = usr unless usr.nil?
|
123
|
-
return data_account[USERNAME]
|
124
|
-
end
|
125
|
-
|
126
|
-
def username_of(account, usr=nil)
|
127
|
-
PasswordsData.username_of( get_data_account(account), usr )
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
data/lib/gtk2passwordapp/rnd.rb
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
module Gtk2Password
|
2
|
-
# This class combines realrand with rand such that
|
3
|
-
# if either one is honest, we'll get honest random numbers.
|
4
|
-
class Rnd
|
5
|
-
|
6
|
-
BUCKET_LENGTH = 100
|
7
|
-
NUMBERS = [75,10,58,26,94]
|
8
|
-
LCF = 2657850
|
9
|
-
RANDOM_ORG = 'http://www.random.org/integers/'
|
10
|
-
|
11
|
-
attr_reader :bucket, :refilling
|
12
|
-
def initialize
|
13
|
-
begin
|
14
|
-
raise "no command line realrand" if $options =~ /-no-gui/
|
15
|
-
# Checking if online refill of real random numbers available....
|
16
|
-
require 'open-uri'
|
17
|
-
require 'timeout'
|
18
|
-
@bucket = []
|
19
|
-
@refilling = false
|
20
|
-
self.refill_timeout
|
21
|
-
rescue Exception
|
22
|
-
$stderr.puts $!
|
23
|
-
@bucket = nil
|
24
|
-
@refilling = false
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def refill_timeout
|
29
|
-
Timeout.timeout(60) do
|
30
|
-
@bucket += open("#{RANDOM_ORG}?num=#{BUCKET_LENGTH}&min=0&max=#{LCF-1}&col=#{BUCKET_LENGTH}&format=plain&base=10&rnd=new").read.strip.split(/\s+/).map{|s| s.to_i}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def refill
|
35
|
-
return if @refilling
|
36
|
-
@refilling = true
|
37
|
-
Thread.new do
|
38
|
-
begin
|
39
|
-
Thread.pass
|
40
|
-
refill_timeout
|
41
|
-
rescue Exception
|
42
|
-
$stderr.puts $!
|
43
|
-
ensure
|
44
|
-
@refilling = false
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
begin
|
50
|
-
require 'securerandom'
|
51
|
-
def self.random_number(number)
|
52
|
-
SecureRandom.random_number(number)
|
53
|
-
end
|
54
|
-
rescue Exception
|
55
|
-
$stderr.puts $! unless $quiet
|
56
|
-
def self.random_number(number)
|
57
|
-
rand(number)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.randomize(rnd,number)
|
62
|
-
((rnd + Rnd.random_number(number)) % number)
|
63
|
-
end
|
64
|
-
|
65
|
-
def real_random(number)
|
66
|
-
refill if @bucket.length < BUCKET_LENGTH/2
|
67
|
-
if rnd = @bucket.shift then
|
68
|
-
return Rnd.randomize(rnd,number)
|
69
|
-
else
|
70
|
-
return Rnd.random_number(number)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def validate(number)
|
75
|
-
if !NUMBERS.include?(number) then
|
76
|
-
$stderr.puts "Did not code for that number"
|
77
|
-
exit # seriously messed up! :))
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def random(number)
|
82
|
-
validate(number)
|
83
|
-
(@bucket)? real_random(number) : Rnd.random_number(number)
|
84
|
-
end
|
85
|
-
|
86
|
-
RND = Rnd.new
|
87
|
-
end
|
88
|
-
end
|
data/pngs/icon.png
DELETED
Binary file
|
data/pngs/logo.png
DELETED
Binary file
|