firefox-data 1.0.0
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 +7 -0
- data/LICENSE +13 -0
- data/bin/firefox-data +93 -0
- data/firefox-data.gemspec +21 -0
- data/lib/firefox.rb +25 -0
- data/lib/firefox/login.rb +109 -0
- data/lib/firefox/profile.rb +54 -0
- data/lib/firefox/profile_index.rb +65 -0
- data/lib/nss.rb +123 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 69f8af3ca8b398607350277c4525297d73cf77c0
|
4
|
+
data.tar.gz: 68217687204f43a15abc0d1db16404c0b820fecf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4796e5e185a385c37052bb3d6f07c312c44c7f73029d8fd8e93dee677a44ffdd3df6800c3f2da5b870a5a5cf47d40f1db559ac13d2d070a0867dca72c8cc5ea
|
7
|
+
data.tar.gz: 7ca0eff0b21d59cb366d4f228bd6fec66d3111b8c6935f9665f39889ad5ab8ac1f6f52c6ee058ae4521c43c0706e55ed94fbdebba616a8abcff933e5cc6e44d3
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/bin/firefox-data
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
4
|
+
#
|
5
|
+
# Permission to use, copy, modify, and distribute this software for any
|
6
|
+
# purpose with or without fee is hereby granted, provided that the above
|
7
|
+
# copyright notice and this permission notice appear in all copies.
|
8
|
+
#
|
9
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
10
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
11
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
12
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
13
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
16
|
+
|
17
|
+
require 'bundler/setup'
|
18
|
+
|
19
|
+
require 'firefox'
|
20
|
+
require 'nss'
|
21
|
+
require 'termios'
|
22
|
+
require 'thor'
|
23
|
+
|
24
|
+
class FirefoxData < Thor
|
25
|
+
class_option :profile,
|
26
|
+
desc: 'the name of the profile',
|
27
|
+
banner: 'NAME',
|
28
|
+
type: :string,
|
29
|
+
default: 'default',
|
30
|
+
aliases: ['p']
|
31
|
+
|
32
|
+
desc "search-logins REGEXP", "Search for logins in the password database"
|
33
|
+
option :password,
|
34
|
+
desc: 'ask for the master password',
|
35
|
+
type: :boolean,
|
36
|
+
aliases: ['w']
|
37
|
+
def search_logins(re_string)
|
38
|
+
re = Regexp.new(re_string, Regexp::IGNORECASE)
|
39
|
+
|
40
|
+
index = Firefox::ProfileIndex.new()
|
41
|
+
index.load()
|
42
|
+
|
43
|
+
profile = index.profiles[options[:profile]]
|
44
|
+
|
45
|
+
password = ''
|
46
|
+
if options[:password]
|
47
|
+
password = ask_password()
|
48
|
+
end
|
49
|
+
|
50
|
+
NSS.init(profile.path)
|
51
|
+
NSS.authenticate(password)
|
52
|
+
|
53
|
+
profile.load_logins(decrypt: true)
|
54
|
+
matches = profile.logins.select {|l| l.hostname.match? re}
|
55
|
+
renders = matches.map do |login|
|
56
|
+
"hostname #{login.hostname}\n" + \
|
57
|
+
"username #{login.username}\n" + \
|
58
|
+
"password #{login.password}\n"
|
59
|
+
end
|
60
|
+
puts renders.join("\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
no_commands do
|
64
|
+
def without_term_echo(&block)
|
65
|
+
attr = Termios.tcgetattr($stdin)
|
66
|
+
|
67
|
+
nattr = attr.dup
|
68
|
+
nattr.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
|
69
|
+
Termios.tcsetattr($stdin, Termios::TCSANOW, nattr)
|
70
|
+
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
ensure
|
74
|
+
Termios.tcsetattr($stdin, Termios::TCSANOW, attr)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def ask_password()
|
79
|
+
printf('Password: ')
|
80
|
+
|
81
|
+
password = ''
|
82
|
+
|
83
|
+
without_term_echo() do
|
84
|
+
password = $stdin.gets().chomp()
|
85
|
+
puts ''
|
86
|
+
end
|
87
|
+
|
88
|
+
password
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
FirefoxData.start(ARGV)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'firefox-data'
|
6
|
+
s.version = '1.0.0'
|
7
|
+
s.date = '2017-02-11'
|
8
|
+
s.summary = 'A library to extract data from firefox profiles.'
|
9
|
+
s.description = 'The firefox-data library extracts various types of ' + \
|
10
|
+
'data from firefox profiles.'
|
11
|
+
s.homepage = 'https://github.com/galdor/rb-firefox-data'
|
12
|
+
s.license = 'ISC'
|
13
|
+
s.author = 'Nicolas Martyanoff'
|
14
|
+
s.email = 'khaelin@gmail.com'
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 2.4.0'
|
17
|
+
|
18
|
+
s.files = FileList['firefox-data.gemspec', 'LICENSE',
|
19
|
+
'bin/*.rb', 'lib/**/*.rb']
|
20
|
+
s.executables = ['firefox-data']
|
21
|
+
end
|
data/lib/firefox.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
require 'bundler/setup'
|
16
|
+
|
17
|
+
require 'pathname'
|
18
|
+
|
19
|
+
module Firefox
|
20
|
+
ROOT_PATH = Pathname.new("#{Dir.home}/.mozilla/firefox")
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'firefox/profile_index'
|
24
|
+
require 'firefox/profile'
|
25
|
+
require 'firefox/login'
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
require 'date'
|
16
|
+
|
17
|
+
require 'json-schema'
|
18
|
+
|
19
|
+
require 'nss'
|
20
|
+
|
21
|
+
module Firefox
|
22
|
+
class InvalidLogin < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
class Login
|
26
|
+
JSON_SCHEMA = {
|
27
|
+
'type' => 'object',
|
28
|
+
'required' => ['id', 'hostname',
|
29
|
+
'encryptedUsername', 'encryptedPassword'],
|
30
|
+
'properties' => {
|
31
|
+
'id' => {'type': 'integer'},
|
32
|
+
'hostname' => {'type': 'string'},
|
33
|
+
'httpRealm' => {'type': ['string', 'null']},
|
34
|
+
'formSubmitURL' => {'type': ['string', 'null']},
|
35
|
+
'usernameField' => {'type': ['string', 'null']},
|
36
|
+
'passwordField' => {'type': ['string', 'null']},
|
37
|
+
'encryptedUsername' => {'type': 'string'},
|
38
|
+
'encryptedPassword' => {'type': 'string'},
|
39
|
+
'guid' => {'type': ['string', 'null']},
|
40
|
+
'encType' => {'type': 'integer'},
|
41
|
+
'timeCreated' => {'type': 'integer'},
|
42
|
+
'timeLastUsed' => {'type': 'integer'},
|
43
|
+
'timePasswordChanged' => {'type': 'integer'},
|
44
|
+
'timesUsed' => {'type': 'integer'},
|
45
|
+
},
|
46
|
+
}
|
47
|
+
|
48
|
+
attr_accessor :id, :hostname, :http_realm, :form_submit_url,
|
49
|
+
:username_field, :password_field,
|
50
|
+
:encrypted_username, :encrypted_password, :enc_type,
|
51
|
+
:username, :password,
|
52
|
+
:guid,
|
53
|
+
:time_created, :time_last_used, :time_password_changed,
|
54
|
+
:times_used
|
55
|
+
|
56
|
+
def initialize()
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s()
|
60
|
+
"#<Firefox::Login #{@hostname}>"
|
61
|
+
end
|
62
|
+
|
63
|
+
def inspect()
|
64
|
+
to_s()
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.from_json(data)
|
68
|
+
# In firefox (checked in the mercurial repository on 2017-02-11),
|
69
|
+
# logins.json is updated in
|
70
|
+
# toolkit/components/passwordmgr/storage-json.js
|
71
|
+
|
72
|
+
begin
|
73
|
+
JSON::Validator.validate!(JSON_SCHEMA, data)
|
74
|
+
rescue JSON::Schema::ValidationError => err
|
75
|
+
raise InvalidLogin, "invalid login data: #{err.message}"
|
76
|
+
end
|
77
|
+
|
78
|
+
login = Login.new()
|
79
|
+
|
80
|
+
to_date = lambda do |timestamp|
|
81
|
+
seconds = timestamp / 1000
|
82
|
+
milliseconds = timestamp % 1000
|
83
|
+
Time.at(seconds, milliseconds).utc()
|
84
|
+
end
|
85
|
+
|
86
|
+
login.id = data['id']
|
87
|
+
login.hostname = data['hostname']
|
88
|
+
login.http_realm = data['httpRealm']
|
89
|
+
login.form_submit_url = data['formSubmitURL']
|
90
|
+
login.username_field = data['usernameField']
|
91
|
+
login.password_field = data['passwordField']
|
92
|
+
login.encrypted_username = data['encryptedUsername']
|
93
|
+
login.encrypted_password = data['encryptedPassword']
|
94
|
+
login.enc_type = data['encType']
|
95
|
+
login.guid = data['guid']
|
96
|
+
login.time_created = to_date.(data['timeCreated'])
|
97
|
+
login.time_last_used = to_date.(data['timeLastUsed'])
|
98
|
+
login.time_password_changed = to_date.(data['timePasswordChanged'])
|
99
|
+
login.times_used = data['timesUsed']
|
100
|
+
|
101
|
+
login
|
102
|
+
end
|
103
|
+
|
104
|
+
def decrypt()
|
105
|
+
@username = NSS.decrypt(@encrypted_username)
|
106
|
+
@password = NSS.decrypt(@encrypted_password)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
require 'json'
|
16
|
+
|
17
|
+
module Firefox
|
18
|
+
class InvalidProfile < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
class Profile
|
22
|
+
attr_reader :name, :path, :logins
|
23
|
+
|
24
|
+
def initialize(name, path)
|
25
|
+
@name = name
|
26
|
+
@path = path
|
27
|
+
@logins = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s()
|
31
|
+
"#<Firefox::Profile #{@name}>"
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect()
|
35
|
+
to_s()
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_logins(decrypt: false)
|
39
|
+
path = @path.join('logins.json')
|
40
|
+
data = JSON.parse(File.read(path))
|
41
|
+
unless data.key? 'logins'
|
42
|
+
raise InvalidProfile, "missing 'logins' entry in #{path}"
|
43
|
+
end
|
44
|
+
|
45
|
+
logins = []
|
46
|
+
data['logins'].each do |login_data|
|
47
|
+
login = Login.from_json(login_data)
|
48
|
+
login.decrypt() if decrypt
|
49
|
+
logins << login
|
50
|
+
end
|
51
|
+
@logins = logins
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
module Firefox
|
16
|
+
class ProfileIndex
|
17
|
+
DEFAULT_PATH = ROOT_PATH.join('profiles.ini')
|
18
|
+
|
19
|
+
attr_reader :path, :profiles
|
20
|
+
|
21
|
+
def initialize(path: DEFAULT_PATH)
|
22
|
+
@path = path
|
23
|
+
@profiles = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def load()
|
27
|
+
sections = []
|
28
|
+
section = nil
|
29
|
+
|
30
|
+
File.open(@path).each do |line|
|
31
|
+
if line.match(/^\[([^\]]+)\]/)
|
32
|
+
title = $1
|
33
|
+
next if title == 'General'
|
34
|
+
|
35
|
+
section = {}
|
36
|
+
sections << section
|
37
|
+
elsif !section.nil? && line.match(/^([^=]+)\s*=\s*(.*)/)
|
38
|
+
key = $1
|
39
|
+
value = $2
|
40
|
+
|
41
|
+
section[key] = value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
profiles = {}
|
46
|
+
sections.each do |section|
|
47
|
+
name = section['Name']
|
48
|
+
path = Pathname.new(section['Path'])
|
49
|
+
is_relative = section['IsRelative']
|
50
|
+
|
51
|
+
if is_relative == '1'
|
52
|
+
path = ROOT_PATH.join(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
profile = Profile.new(name, path)
|
56
|
+
profiles[name] = profile
|
57
|
+
end
|
58
|
+
@profiles = profiles
|
59
|
+
end
|
60
|
+
|
61
|
+
def profile?(name)
|
62
|
+
return @profiles.key? name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/nss.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# Copyright (c) 2017 Nicolas Martyanoff <khaelin@gmail.com>
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
require 'ffi'
|
16
|
+
|
17
|
+
module NSSFFI
|
18
|
+
extend FFI::Library
|
19
|
+
|
20
|
+
class SecItemStr < FFI::Struct
|
21
|
+
layout :type, :int,
|
22
|
+
:data, :pointer,
|
23
|
+
:len, :uint
|
24
|
+
|
25
|
+
def string()
|
26
|
+
self[:data].read_string(self[:len])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ffi_lib 'nss3'
|
31
|
+
|
32
|
+
enum :sec_status, [:wouldblock, -2,
|
33
|
+
:failure, -1,
|
34
|
+
:success, 0]
|
35
|
+
|
36
|
+
typedef :int, :pr_bool
|
37
|
+
typedef SecItemStr.ptr(), :sec_item
|
38
|
+
typedef :int, :sec_item_type
|
39
|
+
typedef :pointer, :pl_arena_pool
|
40
|
+
typedef :pointer, :pk11_slot_info
|
41
|
+
|
42
|
+
attach_function :nss_init, 'NSS_Init', [:string], :sec_status
|
43
|
+
attach_function :nss_base64_decode_buffer, 'NSSBase64_DecodeBuffer',
|
44
|
+
[:pl_arena_pool, :sec_item, :string, :uint], :sec_item
|
45
|
+
|
46
|
+
attach_function :pk11_get_internal_key_slot, 'PK11_GetInternalKeySlot',
|
47
|
+
[], :pk11_slot_info
|
48
|
+
attach_function :pk11_free_slot, 'PK11_FreeSlot', [:pk11_slot_info], :void
|
49
|
+
attach_function :pk11_check_user_password, 'PK11_CheckUserPassword',
|
50
|
+
[:pk11_slot_info, :string], :sec_status
|
51
|
+
attach_function :pk11sdr_decrypt, 'PK11SDR_Decrypt',
|
52
|
+
[:sec_item, :sec_item, :pointer], :sec_status
|
53
|
+
|
54
|
+
attach_function :secitem_alloc_item, 'SECITEM_AllocItem',
|
55
|
+
[:pl_arena_pool, :sec_item, :uint], :sec_item
|
56
|
+
attach_function :secitem_free_item, 'SECITEM_FreeItem',
|
57
|
+
[:sec_item, :pr_bool], :void
|
58
|
+
end
|
59
|
+
|
60
|
+
module NSS
|
61
|
+
class Error < StandardError
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.init(profile_path)
|
65
|
+
res = NSSFFI.nss_init(profile_path.to_s())
|
66
|
+
raise NSS::Error, "cannot initialize nss" unless res == :success
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.with_internal_key_slot(&block)
|
70
|
+
slot = NSSFFI.pk11_get_internal_key_slot()
|
71
|
+
raise NSS::Error, "cannot retrieve internal key slot" if slot.nil?
|
72
|
+
|
73
|
+
begin
|
74
|
+
yield slot
|
75
|
+
ensure
|
76
|
+
NSSFFI.pk11_free_slot(slot)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.check_user_password(slot, password)
|
81
|
+
res = NSSFFI.pk11_check_user_password(slot, password)
|
82
|
+
raise NSS::Error, "authentication failed" unless res == :success
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.authenticate(password)
|
86
|
+
with_internal_key_slot do |slot|
|
87
|
+
check_user_password(slot, password)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.base64_decode(str, &block)
|
92
|
+
str_item = NSSFFI.nss_base64_decode_buffer(nil, nil, str, str.bytesize())
|
93
|
+
raise NSS::Error, "cannot decode base64 string" if str_item.nil?
|
94
|
+
|
95
|
+
begin
|
96
|
+
yield str_item
|
97
|
+
ensure
|
98
|
+
NSSFFI.secitem_free_item(str_item, 1)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.decrypt(b64str)
|
103
|
+
base64_decode(b64str) do |str_item|
|
104
|
+
with_sec_item do |res_item|
|
105
|
+
res = NSSFFI.pk11sdr_decrypt(str_item, res_item, nil)
|
106
|
+
raise NSS::Error, "cannot decrypt string" unless res == :success
|
107
|
+
|
108
|
+
res_item.string()
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.with_sec_item(&block)
|
114
|
+
item = NSSFFI.secitem_alloc_item(nil, nil, 0)
|
115
|
+
raise NSS::Error, "cannot allocate sec item" if item.nil?
|
116
|
+
|
117
|
+
begin
|
118
|
+
yield item
|
119
|
+
ensure
|
120
|
+
NSSFFI.secitem_free_item(item, 1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: firefox-data
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicolas Martyanoff
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: The firefox-data library extracts various types of data from firefox
|
14
|
+
profiles.
|
15
|
+
email: khaelin@gmail.com
|
16
|
+
executables:
|
17
|
+
- firefox-data
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- LICENSE
|
22
|
+
- bin/firefox-data
|
23
|
+
- firefox-data.gemspec
|
24
|
+
- lib/firefox.rb
|
25
|
+
- lib/firefox/login.rb
|
26
|
+
- lib/firefox/profile.rb
|
27
|
+
- lib/firefox/profile_index.rb
|
28
|
+
- lib/nss.rb
|
29
|
+
homepage: https://github.com/galdor/rb-firefox-data
|
30
|
+
licenses:
|
31
|
+
- ISC
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.4.0
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 2.6.8
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: A library to extract data from firefox profiles.
|
53
|
+
test_files: []
|