lastpass 1.3.0 → 1.7.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/.github/workflows/ruby.yml +23 -0
- data/.gitignore +5 -4
- data/.travis.yml +8 -3
- data/CHANGELOG.md +41 -0
- data/README.md +5 -5
- data/Rakefile +1 -0
- data/example/example.rb +5 -3
- data/lastpass.gemspec +7 -8
- data/lib/lastpass.rb +1 -1
- data/lib/lastpass/account.rb +3 -1
- data/lib/lastpass/blob.rb +4 -2
- data/lib/lastpass/fetcher.rb +33 -26
- data/lib/lastpass/http.rb +3 -3
- data/lib/lastpass/note.rb +15 -0
- data/lib/lastpass/parser.rb +58 -43
- data/lib/lastpass/session.rb +4 -2
- data/lib/lastpass/vault.rb +44 -18
- data/lib/lastpass/version.rb +1 -1
- data/spec/account_spec.rb +3 -1
- data/spec/blob_spec.rb +3 -1
- data/spec/fetcher_spec.rb +43 -17
- data/spec/http_spec.rb +17 -9
- data/spec/parser_spec.rb +10 -8
- data/spec/session_spec.rb +3 -1
- data/spec/test_data.rb +100 -100
- data/spec/vault_spec.rb +37 -1
- metadata +36 -64
- data/.ruby-version +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '09a65355723c0ba7300141aa42b691b35072efe71328f6095dce6580c4ff0ccd'
|
4
|
+
data.tar.gz: 3a18f05b3a62ef6fc42568956cc5a99f0bb229597795333363e54fadd036c107
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e08bffaa03731f26519611ea40b52aec82097e3421cda2e0b68ebd785fdafaf9e9e9d6bb39ca8ae4c8df606d43e417003032d006e6a8966591a6db1727073328
|
7
|
+
data.tar.gz: b49b1995780a93c08b87396e78cb8d6718e0920336cd4981c0421290cfaee653904aaca4af23573aa2458a51a8aeb8d4dc4d1e0775dd20410602bb188b7cd7b4
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
ruby: [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7]
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2
|
18
|
+
- uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
21
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
22
|
+
- run: bundle install
|
23
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
coverage
|
4
|
-
example/credentials.yaml
|
1
|
+
/pkg/
|
2
|
+
/Gemfile.lock
|
3
|
+
/coverage
|
4
|
+
/example/credentials.yaml
|
5
|
+
/vendor/
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
Version 1.7.0
|
2
|
+
-------------
|
3
|
+
|
4
|
+
- Parse generic secure notes (thanks to Michael Chui @saraid)
|
5
|
+
- Parse and store secure notes for accounts (see `Account.note` property)
|
6
|
+
|
7
|
+
Version 1.6.1
|
8
|
+
-------------
|
9
|
+
|
10
|
+
- Obsolete URI.encode is replaced with URI.encode_www_form_component to
|
11
|
+
inhibit the warning
|
12
|
+
- Travic CI runs on all 2.* latest minor version releases (2.0.0 to 2.7.1)
|
13
|
+
|
14
|
+
Version 1.6.0
|
15
|
+
-------------
|
16
|
+
|
17
|
+
- Changed the way the private keys are parsed
|
18
|
+
- OpenSSL 1.1.0 support
|
19
|
+
- Bug fixes
|
20
|
+
|
21
|
+
Version 1.5.0
|
22
|
+
-------------
|
23
|
+
|
24
|
+
- Fixed failing `get_iteraction_count`. POST parameters are moved from the
|
25
|
+
query (URL) to the body.
|
26
|
+
- pbkdf2-ruby gem is no longer used as it was causing problems. Relying on
|
27
|
+
built-in `OpenSSL::PKCS5.pbkdf2_hmac`
|
28
|
+
- Minimum supported Ruby version is 2.0.0
|
29
|
+
- Dependencies updated to their laters versions
|
30
|
+
- Travis CI fixed
|
31
|
+
|
32
|
+
Version 1.4.0
|
33
|
+
-------------
|
34
|
+
|
35
|
+
- Added device id (IMEI/UUID) support
|
36
|
+
- Log out after fetching the blob to close the newly open session on LP server
|
37
|
+
to prevent triggering anti-hacking logic (hopefully)
|
38
|
+
- Verify that the recieved blob is marked with ENDM chunk and hasn't been
|
39
|
+
truncated in the process
|
40
|
+
|
41
|
+
|
1
42
|
Version 1.3.0
|
2
43
|
-------------
|
3
44
|
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
LastPass Ruby API
|
2
2
|
=================
|
3
3
|
|
4
|
-
[](https://travis-ci.org/detunized/lastpass-ruby)
|
5
|
+
[](https://coveralls.io/r/detunized/lastpass-ruby?branch=master)
|
6
|
+
[](https://codeclimate.com/github/detunized/lastpass-ruby)
|
7
|
+
[](https://gemnasium.com/detunized/lastpass-ruby)
|
8
8
|
|
9
9
|
**This is unofficial LastPass API.**
|
10
10
|
|
11
|
-
There
|
11
|
+
There are also [a C#/.NET port](https://github.com/detunized/lastpass-sharp) and [a Python port](https://github.com/konomae/lastpass-python) available.
|
12
12
|
|
13
13
|
This library implements fetching and parsing of LastPass data. The library is
|
14
14
|
still in the proof of concept stage and doesn't support all LastPass features
|
data/Rakefile
CHANGED
data/example/example.rb
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
require "lastpass"
|
8
8
|
require "yaml"
|
9
9
|
|
10
|
+
DEVICE_ID = "example.rb"
|
11
|
+
|
10
12
|
credentials = YAML.load_file File.join File.dirname(__FILE__), "credentials.yaml"
|
11
13
|
|
12
14
|
username = credentials["username"]
|
@@ -14,21 +16,21 @@ password = credentials["password"]
|
|
14
16
|
|
15
17
|
begin
|
16
18
|
# First try without a multifactor password
|
17
|
-
vault = LastPass::Vault.open_remote username, password
|
19
|
+
vault = LastPass::Vault.open_remote username, password, nil, DEVICE_ID
|
18
20
|
rescue LastPass::LastPassIncorrectGoogleAuthenticatorCodeError => e
|
19
21
|
# Get the code
|
20
22
|
puts "Enter Google Authenticator code:"
|
21
23
|
multifactor_password = gets.chomp
|
22
24
|
|
23
25
|
# And now retry with the code
|
24
|
-
vault = LastPass::Vault.open_remote username, password, multifactor_password
|
26
|
+
vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID
|
25
27
|
rescue LastPass::LastPassIncorrectYubikeyPasswordError => e
|
26
28
|
# Get the password
|
27
29
|
puts "Enter Yubikey password:"
|
28
30
|
multifactor_password = gets.chomp
|
29
31
|
|
30
32
|
# And now retry with the Yubikey password
|
31
|
-
vault = LastPass::Vault.open_remote username, password, multifactor_password
|
33
|
+
vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID
|
32
34
|
end
|
33
35
|
|
34
36
|
vault.accounts.each_with_index do |i, index|
|
data/lastpass.gemspec
CHANGED
@@ -12,17 +12,16 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = "detunized@gmail.com"
|
13
13
|
s.homepage = "https://github.com/detunized/lastpass-ruby"
|
14
14
|
s.summary = "Unofficial LastPass API"
|
15
|
-
s.description = "
|
15
|
+
s.description = "Read only access to the online LastPass vault"
|
16
16
|
|
17
|
-
s.required_ruby_version = ">=
|
17
|
+
s.required_ruby_version = ">= 2.0.0"
|
18
18
|
|
19
|
-
s.add_dependency "httparty", "~> 0.
|
20
|
-
s.add_dependency "pbkdf2-ruby", "~> 0.2.0"
|
19
|
+
s.add_dependency "httparty", "~> 0.14.0"
|
21
20
|
|
22
|
-
s.add_development_dependency "rake", "~>
|
23
|
-
s.add_development_dependency "rspec", "~> 3.
|
24
|
-
s.add_development_dependency "rspec-its", "~> 1.
|
25
|
-
s.add_development_dependency "coveralls", "~> 0.
|
21
|
+
s.add_development_dependency "rake", "~> 12.0"
|
22
|
+
s.add_development_dependency "rspec", "~> 3.5"
|
23
|
+
s.add_development_dependency "rspec-its", "~> 1.2"
|
24
|
+
s.add_development_dependency "coveralls", "~> 0.8.19"
|
26
25
|
|
27
26
|
s.files = `git ls-files`.split "\n"
|
28
27
|
s.test_files = `git ls-files spec`.split "\n"
|
data/lib/lastpass.rb
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
require "base64"
|
5
5
|
require "httparty"
|
6
6
|
require "openssl"
|
7
|
-
require "pbkdf2"
|
8
7
|
require "stringio"
|
9
8
|
|
10
9
|
require "lastpass/account"
|
@@ -13,6 +12,7 @@ require "lastpass/chunk"
|
|
13
12
|
require "lastpass/exceptions"
|
14
13
|
require "lastpass/http"
|
15
14
|
require "lastpass/fetcher"
|
15
|
+
require "lastpass/note"
|
16
16
|
require "lastpass/parser"
|
17
17
|
require "lastpass/session"
|
18
18
|
require "lastpass/vault"
|
data/lib/lastpass/account.rb
CHANGED
@@ -8,14 +8,16 @@ module LastPass
|
|
8
8
|
:username,
|
9
9
|
:password,
|
10
10
|
:url,
|
11
|
+
:notes,
|
11
12
|
:group
|
12
13
|
|
13
|
-
def initialize id, name, username, password, url, group
|
14
|
+
def initialize id, name, username, password, url, notes, group
|
14
15
|
@id = id
|
15
16
|
@name = name
|
16
17
|
@username = username
|
17
18
|
@password = password
|
18
19
|
@url = url
|
20
|
+
@notes = notes
|
19
21
|
@group = group
|
20
22
|
end
|
21
23
|
end
|
data/lib/lastpass/blob.rb
CHANGED
@@ -4,11 +4,13 @@
|
|
4
4
|
module LastPass
|
5
5
|
class Blob
|
6
6
|
attr_reader :bytes,
|
7
|
-
:key_iteration_count
|
7
|
+
:key_iteration_count,
|
8
|
+
:encrypted_private_key
|
8
9
|
|
9
|
-
def initialize bytes, key_iteration_count
|
10
|
+
def initialize bytes, key_iteration_count, encrypted_private_key
|
10
11
|
@bytes = bytes
|
11
12
|
@key_iteration_count = key_iteration_count
|
13
|
+
@encrypted_private_key = encrypted_private_key
|
12
14
|
end
|
13
15
|
|
14
16
|
def encryption_key username, password
|
data/lib/lastpass/fetcher.rb
CHANGED
@@ -3,24 +3,33 @@
|
|
3
3
|
|
4
4
|
module LastPass
|
5
5
|
class Fetcher
|
6
|
-
def self.login username, password, multifactor_password = nil
|
6
|
+
def self.login username, password, multifactor_password = nil, client_id = nil
|
7
7
|
key_iteration_count = request_iteration_count username
|
8
|
-
request_login username, password, key_iteration_count, multifactor_password
|
8
|
+
request_login username, password, key_iteration_count, multifactor_password, client_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logout session, web_client = http
|
12
|
+
response = web_client.get "https://lastpass.com/logout.php?method=cli&noredirect=1",
|
13
|
+
cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)}
|
14
|
+
|
15
|
+
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
9
16
|
end
|
10
17
|
|
11
18
|
def self.fetch session, web_client = http
|
12
|
-
response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=
|
19
|
+
response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=cli",
|
13
20
|
format: :plain,
|
14
|
-
cookies: {"PHPSESSID" => URI.
|
21
|
+
cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)}
|
15
22
|
|
16
23
|
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
17
24
|
|
18
|
-
Blob.new decode_blob(response.parsed_response),
|
25
|
+
Blob.new decode_blob(response.parsed_response),
|
26
|
+
session.key_iteration_count,
|
27
|
+
session.encrypted_private_key
|
19
28
|
end
|
20
29
|
|
21
30
|
def self.request_iteration_count username, web_client = http
|
22
31
|
response = web_client.post "https://lastpass.com/iterations.php",
|
23
|
-
|
32
|
+
body: {email: username}
|
24
33
|
|
25
34
|
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
26
35
|
|
@@ -39,18 +48,20 @@ module LastPass
|
|
39
48
|
password,
|
40
49
|
key_iteration_count,
|
41
50
|
multifactor_password = nil,
|
51
|
+
client_id = nil,
|
42
52
|
web_client = http
|
43
53
|
|
44
54
|
body = {
|
45
|
-
method: "
|
46
|
-
|
47
|
-
xml: 1,
|
55
|
+
method: "cli",
|
56
|
+
xml: 2,
|
48
57
|
username: username,
|
49
58
|
hash: make_hash(username, password, key_iteration_count),
|
50
|
-
iterations: key_iteration_count
|
59
|
+
iterations: key_iteration_count,
|
60
|
+
includeprivatekeyenc: 1
|
51
61
|
}
|
52
62
|
|
53
63
|
body[:otp] = multifactor_password if multifactor_password
|
64
|
+
body[:imei] = client_id if client_id
|
54
65
|
|
55
66
|
response = web_client.post "https://lastpass.com/login.php",
|
56
67
|
format: :xml,
|
@@ -66,11 +77,14 @@ module LastPass
|
|
66
77
|
end
|
67
78
|
|
68
79
|
def self.create_session parsed_response, key_iteration_count
|
69
|
-
ok = parsed_response["ok"]
|
80
|
+
ok = (parsed_response["response"] || {})["ok"]
|
70
81
|
if ok.is_a? Hash
|
71
82
|
session_id = ok["sessionid"]
|
72
83
|
if session_id.is_a? String
|
73
|
-
|
84
|
+
private_key = ok["privatekeyenc"]
|
85
|
+
private_key = nil if private_key == ""
|
86
|
+
|
87
|
+
return Session.new session_id, key_iteration_count, private_key
|
74
88
|
end
|
75
89
|
end
|
76
90
|
|
@@ -86,7 +100,7 @@ module LastPass
|
|
86
100
|
"unknownpassword" => LastPassInvalidPasswordError,
|
87
101
|
"googleauthrequired" => LastPassIncorrectGoogleAuthenticatorCodeError,
|
88
102
|
"googleauthfailed" => LastPassIncorrectGoogleAuthenticatorCodeError,
|
89
|
-
"
|
103
|
+
"otprequired" => LastPassIncorrectYubikeyPasswordError,
|
90
104
|
}
|
91
105
|
|
92
106
|
cause = error["cause"]
|
@@ -108,13 +122,7 @@ module LastPass
|
|
108
122
|
if key_iteration_count == 1
|
109
123
|
Digest::SHA256.digest username + password
|
110
124
|
else
|
111
|
-
|
112
|
-
.new(password: password,
|
113
|
-
salt: username,
|
114
|
-
iterations: key_iteration_count,
|
115
|
-
key_length: 32)
|
116
|
-
.bin_string
|
117
|
-
.force_encoding "BINARY"
|
125
|
+
OpenSSL::PKCS5.pbkdf2_hmac password, username, key_iteration_count, 32, "sha256"
|
118
126
|
end
|
119
127
|
end
|
120
128
|
|
@@ -122,12 +130,11 @@ module LastPass
|
|
122
130
|
if key_iteration_count == 1
|
123
131
|
Digest::SHA256.hexdigest Digest.hexencode(make_key(username, password, 1)) + password
|
124
132
|
else
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
.hex_string
|
133
|
+
Digest.hexencode OpenSSL::PKCS5.pbkdf2_hmac make_key(username, password, key_iteration_count),
|
134
|
+
password,
|
135
|
+
1,
|
136
|
+
32,
|
137
|
+
"sha256"
|
131
138
|
end
|
132
139
|
end
|
133
140
|
|
data/lib/lastpass/http.rb
CHANGED
data/lib/lastpass/parser.rb
CHANGED
@@ -7,7 +7,7 @@ module LastPass
|
|
7
7
|
RSA_PKCS1_OAEP_PADDING = 4
|
8
8
|
|
9
9
|
# Secure note types that contain account-like information
|
10
|
-
|
10
|
+
ACCOUNT_LIKE_SECURE_NOTE_TYPES = {
|
11
11
|
"Server" => true,
|
12
12
|
"Email Account" => true,
|
13
13
|
"Database" => true,
|
@@ -28,9 +28,9 @@ module LastPass
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Parses an account chunk, decrypts and creates an Account object.
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# information.
|
31
|
+
# Returns either an Account or a Note object, in case of a generic
|
32
|
+
# note that doesn't represent an account. All secure notes are ACCTs
|
33
|
+
# but not all of them store account information.
|
34
34
|
#
|
35
35
|
# TODO: Make a test case that covers secure note account
|
36
36
|
def self.parse_ACCT chunk, encryption_key
|
@@ -48,44 +48,20 @@ module LastPass
|
|
48
48
|
|
49
49
|
# Parse secure note
|
50
50
|
if secure_note == "1"
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if !ALLOWED_SECURE_NOTE_TYPES.key? secure_note_type
|
55
|
-
return nil
|
51
|
+
parsed = parse_secure_note_server notes
|
52
|
+
if !ACCOUNT_LIKE_SECURE_NOTE_TYPES.key? parsed[:type]
|
53
|
+
return Note.new id, name, notes, group
|
56
54
|
end
|
57
55
|
|
58
|
-
url
|
56
|
+
url = parsed[:url] if parsed.key? :url
|
57
|
+
username = parsed[:username] if parsed.key? :username
|
58
|
+
password = parsed[:password] if parsed.key? :password
|
59
59
|
end
|
60
60
|
|
61
|
-
Account.new id, name, username, password, url, group
|
61
|
+
Account.new id, name, username, password, url, notes, group
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
# Parse PRIK chunk which contains private RSA key
|
66
|
-
def self.parse_PRIK chunk, encryption_key
|
67
|
-
decrypted = decode_aes256 "cbc",
|
68
|
-
encryption_key[0, 16],
|
69
|
-
decode_hex(chunk.payload),
|
70
|
-
encryption_key
|
71
|
-
|
72
|
-
/^LastPassPrivateKey<(?<hex_key>.*)>LastPassPrivateKey$/ =~ decrypted
|
73
|
-
asn1_encoded_all = OpenSSL::ASN1.decode decode_hex hex_key
|
74
|
-
asn1_encoded_key = OpenSSL::ASN1.decode asn1_encoded_all.value[2].value
|
75
|
-
|
76
|
-
rsa_key = OpenSSL::PKey::RSA.new
|
77
|
-
rsa_key.n = asn1_encoded_key.value[1].value
|
78
|
-
rsa_key.e = asn1_encoded_key.value[2].value
|
79
|
-
rsa_key.d = asn1_encoded_key.value[3].value
|
80
|
-
rsa_key.p = asn1_encoded_key.value[4].value
|
81
|
-
rsa_key.q = asn1_encoded_key.value[5].value
|
82
|
-
rsa_key.dmp1 = asn1_encoded_key.value[6].value
|
83
|
-
rsa_key.dmq1 = asn1_encoded_key.value[7].value
|
84
|
-
rsa_key.iqmp = asn1_encoded_key.value[8].value
|
85
|
-
|
86
|
-
rsa_key
|
87
|
-
end
|
88
|
-
|
89
65
|
# TODO: Fake some data and make a test
|
90
66
|
def self.parse_SHAR chunk, encryption_key, rsa_key
|
91
67
|
StringIO.open chunk.payload do |io|
|
@@ -112,24 +88,63 @@ module LastPass
|
|
112
88
|
end
|
113
89
|
end
|
114
90
|
|
91
|
+
# Parse and decrypt the encrypted private RSA key
|
92
|
+
def self.parse_private_key encrypted_private_key, encryption_key
|
93
|
+
decrypted = decode_aes256 "cbc",
|
94
|
+
encryption_key[0, 16],
|
95
|
+
decode_hex(encrypted_private_key),
|
96
|
+
encryption_key
|
97
|
+
|
98
|
+
/^LastPassPrivateKey<(?<hex_key>.*)>LastPassPrivateKey$/ =~ decrypted
|
99
|
+
asn1_encoded_all = OpenSSL::ASN1.decode decode_hex hex_key
|
100
|
+
asn1_encoded_key = OpenSSL::ASN1.decode asn1_encoded_all.value[2].value
|
101
|
+
|
102
|
+
rsa_key = OpenSSL::PKey::RSA.new
|
103
|
+
n = asn1_encoded_key.value[1].value
|
104
|
+
e = asn1_encoded_key.value[2].value
|
105
|
+
d = asn1_encoded_key.value[3].value
|
106
|
+
p = asn1_encoded_key.value[4].value
|
107
|
+
q = asn1_encoded_key.value[5].value
|
108
|
+
dmp1 = asn1_encoded_key.value[6].value
|
109
|
+
dmq1 = asn1_encoded_key.value[7].value
|
110
|
+
iqmp = asn1_encoded_key.value[8].value
|
111
|
+
|
112
|
+
if rsa_key.respond_to? :set_key
|
113
|
+
rsa_key.set_key n, e, d
|
114
|
+
rsa_key.set_factors p, q
|
115
|
+
rsa_key.set_crt_params dmp1, dmq1, iqmp
|
116
|
+
else
|
117
|
+
rsa_key.n = n
|
118
|
+
rsa_key.e = e
|
119
|
+
rsa_key.d = d
|
120
|
+
rsa_key.p = p
|
121
|
+
rsa_key.q = q
|
122
|
+
rsa_key.dmp1 = dmp1
|
123
|
+
rsa_key.dmq1 = dmq1
|
124
|
+
rsa_key.iqmp = iqmp
|
125
|
+
end
|
126
|
+
|
127
|
+
rsa_key
|
128
|
+
end
|
129
|
+
|
115
130
|
def self.parse_secure_note_server notes
|
116
|
-
|
117
|
-
username = nil
|
118
|
-
password = nil
|
131
|
+
info = {}
|
119
132
|
|
120
133
|
notes.split("\n").each do |i|
|
121
134
|
key, value = i.split ":", 2
|
122
135
|
case key
|
136
|
+
when "NoteType"
|
137
|
+
info[:type] = value
|
123
138
|
when "Hostname"
|
124
|
-
url = value
|
139
|
+
info[:url] = value
|
125
140
|
when "Username"
|
126
|
-
username = value
|
141
|
+
info[:username] = value
|
127
142
|
when "Password"
|
128
|
-
password = value
|
143
|
+
info[:password] = value
|
129
144
|
end
|
130
145
|
end
|
131
146
|
|
132
|
-
|
147
|
+
info
|
133
148
|
end
|
134
149
|
|
135
150
|
# Reads one chunk from a stream and creates a Chunk object with the data read.
|
@@ -275,7 +290,7 @@ module LastPass
|
|
275
290
|
# Allowed ciphers are: :ecb, :cbc.
|
276
291
|
# If for :ecb iv is not used and should be set to "".
|
277
292
|
def self.decode_aes256 cipher, iv, data, encryption_key
|
278
|
-
aes = OpenSSL::Cipher
|
293
|
+
aes = OpenSSL::Cipher.new "aes-256-#{cipher}"
|
279
294
|
aes.decrypt
|
280
295
|
aes.key = encryption_key
|
281
296
|
aes.iv = iv
|