1
- const ProcessSpawner = require ( 'util/process.js' )
2
- const path = require ( 'path' )
1
+
2
+ const { join } = require ( 'path' )
3
3
const fs = require ( 'fs' )
4
- var { ipcRenderer } = require ( 'electron' )
4
+ const { ipcRenderer } = require ( 'electron' )
5
+
6
+ const ProcessSpawner = require ( 'util/process.js' )
5
7
6
8
// Bitwarden password manager. Requires session key to unlock the vault.
7
9
class Bitwarden {
@@ -12,18 +14,17 @@ class Bitwarden {
12
14
}
13
15
14
16
getDownloadLink ( ) {
15
- switch ( window . platformType ) {
16
- case 'mac' :
17
- return 'https://vault.bitwarden.com/download/?app=cli&platform=macos'
18
- case 'windows' :
19
- return 'https://vault.bitwarden.com/download/?app=cli&platform=windows'
20
- case 'linux' :
21
- return 'https://vault.bitwarden.com/download/?app=cli&platform=linux'
17
+ if ( window . platformType === 'mac' ) {
18
+ return 'https://vault.bitwarden.com/download/?app=cli&platform=macos'
22
19
}
20
+ if ( window . platformType === 'windows' ) {
21
+ return 'https://vault.bitwarden.com/download/?app=cli&platform=windows'
22
+ }
23
+ return 'https://vault.bitwarden.com/download/?app=cli&platform=linux'
23
24
}
24
25
25
26
getLocalPath ( ) {
26
- return path . join ( window . globalArgs [ 'user-data-path' ] , 'tools' , ( platformType === 'windows' ? 'bw.exe' : 'bw' ) )
27
+ return join ( window . globalArgs [ 'user-data-path' ] , 'tools' , ( platformType === 'windows' ? 'bw.exe' : 'bw' ) )
27
28
}
28
29
29
30
getSetupMode ( ) {
@@ -41,7 +42,7 @@ class Bitwarden {
41
42
try {
42
43
await fs . promises . access ( localPath , fs . constants . X_OK )
43
44
local = true
44
- } catch ( e ) { }
45
+ } catch { }
45
46
if ( local ) {
46
47
return localPath
47
48
}
@@ -71,7 +72,7 @@ class Bitwarden {
71
72
72
73
// Tries to get a list of credential suggestions for a given domain name.
73
74
async getSuggestions ( domain ) {
74
- if ( this . lastCallList [ domain ] != null ) {
75
+ if ( this . lastCallList [ domain ] ) {
75
76
return this . lastCallList [ domain ]
76
77
}
77
78
@@ -84,32 +85,31 @@ class Bitwarden {
84
85
throw new Error ( )
85
86
}
86
87
87
- this . lastCallList [ domain ] = this . loadSuggestions ( command , domain ) . then ( suggestions => {
88
- this . lastCallList [ domain ] = null
88
+ try {
89
+ const suggestions = await this . loadSuggestions ( command , domain )
90
+ this . lastCallList [ domain ] = suggestions
89
91
return suggestions
90
- } ) . catch ( ex => {
92
+ } catch ( e ) {
91
93
this . lastCallList [ domain ] = null
92
- } )
94
+ }
93
95
94
96
return this . lastCallList [ domain ]
95
97
}
96
98
97
99
// Loads credential suggestions for given domain name.
98
100
async loadSuggestions ( command , domain ) {
99
101
try {
100
- const process = new ProcessSpawner ( command , [ 'list' , 'items' , '--url' , this . sanitize ( domain ) , '--session' , this . sessionKey ] )
101
- const data = await process . execute ( )
102
-
103
- const matches = JSON . parse ( data )
104
- const credentials = matches . map ( match => {
105
- const { login : { username, password } } = match
106
- return { username, password, manager : 'Bitwarden' }
107
- } )
108
-
109
- return credentials
110
- } catch ( ex ) {
111
- const { error, data } = ex
112
- console . error ( 'Error accessing Bitwarden CLI. STDOUT: ' + data + '. STDERR: ' + error )
102
+ const process = new ProcessSpawner (
103
+ command ,
104
+ [ 'list' , 'items' , '--url' , domain . replace ( / [ ^ a - z A - Z 0 - 9 . - ] / g, '' ) , '--session' , this . sessionKey ]
105
+ )
106
+ const matches = JSON . parse ( await process . execute ( ) )
107
+ return matches . map (
108
+ ( { login : { username, password } } ) =>
109
+ ( { username, password, manager : 'Bitwarden' } )
110
+ )
111
+ } catch ( { error, data } ) {
112
+ console . error ( `Error accessing Bitwarden CLI. STDOUT: ${ data } . STDERR: ${ error } ` )
113
113
return [ ]
114
114
}
115
115
}
@@ -118,9 +118,8 @@ class Bitwarden {
118
118
try {
119
119
const process = new ProcessSpawner ( command , [ 'sync' , '--session' , this . sessionKey ] )
120
120
await process . execute ( )
121
- } catch ( ex ) {
122
- const { error, data } = ex
123
- console . error ( 'Error accessing Bitwarden CLI. STDOUT: ' + data + '. STDERR: ' + error )
121
+ } catch ( { error, data } ) {
122
+ console . error ( `Error accessing Bitwarden CLI. STDOUT: ${ data } . STDERR: ${ error } ` )
124
123
}
125
124
}
126
125
@@ -138,17 +137,17 @@ class Bitwarden {
138
137
await this . forceSync ( this . path )
139
138
140
139
return true
141
- } catch ( ex ) {
142
- const { error, data } = ex
140
+ } catch ( err ) {
141
+ const { error, data } = err
143
142
144
- console . error ( ' Error accessing Bitwarden CLI. STDOUT: ' + data + ' . STDERR: ' + error )
143
+ console . error ( ` Error accessing Bitwarden CLI. STDOUT: ${ data } . STDERR: ${ error } ` )
145
144
146
145
if ( error . includes ( 'not logged in' ) ) {
147
146
await this . signInAndSave ( )
148
147
return await this . unlockStore ( password )
149
148
}
150
149
151
- throw ex
150
+ throw err
152
151
}
153
152
}
154
153
@@ -161,41 +160,43 @@ class Bitwarden {
161
160
console . warn ( e )
162
161
}
163
162
164
- // show credentials dialog
165
-
166
- var signInFields = [
163
+ // show ask-for-credential dialog
164
+ const signInFields = [
165
+ { placeholder : 'Server URL (Leave blank for the default Bitwarden server)' , id : 'url' , type : 'text' } ,
167
166
{ placeholder : 'Client ID' , id : 'clientID' , type : 'password' } ,
168
167
{ placeholder : 'Client Secret' , id : 'clientSecret' , type : 'password' }
169
168
]
170
169
171
- const credentials = ipcRenderer . sendSync ( 'prompt' , {
172
- text : l ( 'passwordManagerBitwardenSignIn' ) ,
173
- values : signInFields ,
174
- ok : l ( 'dialogConfirmButton' ) ,
175
- cancel : l ( 'dialogSkipButton' ) ,
176
- width : 500 ,
177
- height : 260
178
- } )
179
-
180
- for ( const key in credentials ) {
181
- if ( credentials [ key ] === '' ) {
182
- throw new Error ( 'no credentials entered' )
170
+ const credentials = ipcRenderer . sendSync (
171
+ 'prompt' ,
172
+ {
173
+ text : l ( 'passwordManagerBitwardenSignIn' ) ,
174
+ values : signInFields ,
175
+ ok : l ( 'dialogConfirmButton' ) ,
176
+ cancel : l ( 'dialogSkipButton' ) ,
177
+ width : 500 ,
178
+ height : 260
183
179
}
184
- }
180
+ )
185
181
186
- const process = new ProcessSpawner ( path , [ 'login' , '--apikey' ] , {
187
- BW_CLIENTID : credentials . clientID . trim ( ) ,
188
- BW_CLIENTSECRET : credentials . clientSecret . trim ( )
189
- } )
182
+ if ( credentials . clientID === '' || credentials . clientSecret === '' ) {
183
+ throw new Error ( 'no credentials entered' )
184
+ }
190
185
191
- await process . execute ( )
186
+ credentials . url = credentials . url || 'bitwarden.com'
192
187
193
- return true
194
- }
188
+ const process1 = new ProcessSpawner ( path , [ 'config' , 'server' , credentials . url . trim ( ) ] )
189
+ await process1 . execute ( )
195
190
196
- // Basic domain name cleanup. Removes any non-ASCII symbols.
197
- sanitize ( domain ) {
198
- return domain . replace ( / [ ^ a - z A - Z 0 - 9 . - ] / g, '' )
191
+ const process2 = new ProcessSpawner (
192
+ path ,
193
+ [ 'login' , '--apikey' ] ,
194
+ {
195
+ BW_CLIENTID : credentials . clientID . trim ( ) ,
196
+ BW_CLIENTSECRET : credentials . clientSecret . trim ( )
197
+ }
198
+ )
199
+ await process2 . execute ( )
199
200
}
200
201
}
201
202
0 commit comments