@@ -2,20 +2,9 @@ import * as vscode from 'vscode';
2
2
import { nanoid } from 'nanoid' ;
3
3
4
4
import { keychain } from './common/keychain' ;
5
- import Logger from './common/logger'
5
+ import Logger from './common/logger' ;
6
6
import { CodingServer } from './codingServer' ;
7
- import { RepoInfo } from './typings/types' ;
8
-
9
- interface SessionData {
10
- id : string ;
11
- account ?: {
12
- label ?: string ;
13
- displayName ?: string ;
14
- id : string ;
15
- }
16
- scopes : string [ ] ;
17
- accessToken : string ;
18
- }
7
+ import { RepoInfo , SessionData , TokenType } from './typings/commonTypes' ;
19
8
20
9
export const ScopeList = [
21
10
`user` ,
@@ -29,7 +18,7 @@ const NETWORK_ERROR = 'network error';
29
18
export const onDidChangeSessions = new vscode . EventEmitter < vscode . AuthenticationProviderAuthenticationSessionsChangeEvent > ( ) ;
30
19
31
20
export class CodingAuthenticationProvider {
32
- private _sessions : vscode . AuthenticationSession [ ] = [ ] ;
21
+ private _session : SessionData | null = null ;
33
22
private _codingServer = new CodingServer ( ) ;
34
23
private _repo : RepoInfo = {
35
24
team : `` ,
@@ -45,141 +34,66 @@ export class CodingAuthenticationProvider {
45
34
46
35
public async initialize ( context : vscode . ExtensionContext ) : Promise < void > {
47
36
try {
48
- this . _sessions = await this . _readSessions ( ) ;
49
- } catch ( e ) {
50
- // Ignore, network request failed
51
- }
52
-
53
- context . subscriptions . push ( vscode . authentication . onDidChangePassword ( ( ) => this . _checkForUpdates ( ) ) ) ;
54
- }
55
-
56
- private async _checkForUpdates ( ) {
57
- let storedSessions : vscode . AuthenticationSession [ ] ;
58
- try {
59
- storedSessions = await this . _readSessions ( ) ;
37
+ this . _session = await this . _readSessions ( ) ;
60
38
} catch ( e ) {
61
39
// Ignore, network request failed
62
- return ;
63
- }
64
-
65
- const added : string [ ] = [ ] ;
66
- const removed : string [ ] = [ ] ;
67
-
68
- storedSessions . forEach ( session => {
69
- const matchesExisting = this . _sessions . some ( s => s . id === session . id ) ;
70
- // Another window added a session to the keychain, add it to our state as well
71
- if ( ! matchesExisting ) {
72
- Logger . info ( 'Adding session found in keychain' ) ;
73
- this . _sessions . push ( session ) ;
74
- added . push ( session . id ) ;
75
- }
76
- } ) ;
77
-
78
- this . _sessions . map ( session => {
79
- const matchesExisting = storedSessions . some ( s => s . id === session . id ) ;
80
- // Another window has logged out, remove from our state
81
- if ( ! matchesExisting ) {
82
- Logger . info ( 'Removing session no longer found in keychain' ) ;
83
- const sessionIndex = this . _sessions . findIndex ( s => s . id === session . id ) ;
84
- if ( sessionIndex > - 1 ) {
85
- this . _sessions . splice ( sessionIndex , 1 ) ;
86
- }
87
-
88
- removed . push ( session . id ) ;
89
- }
90
- } ) ;
91
-
92
- if ( added . length || removed . length ) {
93
- onDidChangeSessions . fire ( { added, removed, changed : [ ] } ) ;
94
40
}
95
41
}
96
42
97
- private async _readSessions ( ) : Promise < vscode . AuthenticationSession [ ] > {
98
- const storedSessions = await keychain . getToken ( ) || await keychain . tryMigrate ( ) ;
99
- if ( storedSessions ) {
43
+ private async _readSessions ( ) : Promise < SessionData | null > {
44
+ const [ accessToken , refreshToken ] = await Promise . all ( [
45
+ keychain . getToken ( TokenType . AccessToken ) ,
46
+ keychain . getToken ( TokenType . RefreshToken ) ,
47
+ ] ) ;
48
+ if ( accessToken && refreshToken ) {
100
49
try {
101
- const sessionData : SessionData [ ] = JSON . parse ( storedSessions ) ;
102
- const sessionPromises = sessionData . map ( async ( session : SessionData ) : Promise < vscode . AuthenticationSession > => {
103
- const needsUserInfo = ! session . account ;
104
- let userInfo : { id : string , accountName : string } ;
105
- if ( needsUserInfo ) {
106
- userInfo = await this . _codingServer . getUserInfo ( this . _repo . team , session . accessToken ) ;
107
- }
108
-
109
- return {
110
- id : session . id ,
111
- account : {
112
- label : session . account
113
- ? session . account . label || session . account . displayName !
114
- : userInfo ! . accountName ,
115
- id : session . account ?. id ?? userInfo ! . id
116
- } ,
117
- scopes : session . scopes ,
118
- accessToken : session . accessToken
119
- } ;
120
- } ) ;
121
-
122
- return Promise . all ( sessionPromises ) ;
50
+ const session = await this . getSessionData ( accessToken as TokenType . AccessToken , refreshToken as TokenType . RefreshToken ) ;
51
+ return session ;
123
52
} catch ( e ) {
124
53
if ( e === NETWORK_ERROR ) {
125
- return [ ] ;
54
+ return null ;
126
55
}
127
56
128
57
Logger . error ( `Error reading sessions: ${ e } ` ) ;
129
- await keychain . deleteToken ( ) ;
58
+ await keychain . deleteToken ( TokenType . AccessToken ) ;
130
59
}
131
60
}
132
61
133
- return [ ] ;
134
- }
135
-
136
- private async _tokenToSession ( token : string , scopes : string [ ] ) : Promise < vscode . AuthenticationSession > {
137
- const userInfo = await this . _codingServer . getUserInfo ( this . _repo . team , token ) ;
138
-
139
- return {
140
- id : nanoid ( ) ,
141
- accessToken : token ,
142
- account : {
143
- label : userInfo . name ,
144
- id : userInfo . global_key ,
145
- } ,
146
- scopes,
147
- } ;
62
+ return null ;
148
63
}
149
64
150
- public async login ( team : string , scopes : string = SCOPES ) : Promise < vscode . AuthenticationSession > {
151
- const { access_token : token } = await this . _codingServer . login ( team , scopes ) ;
152
- const session = await this . _tokenToSession ( token , scopes . split ( ' ' ) ) ;
153
- await this . _setToken ( session ) ;
154
- return session ;
155
- }
156
-
157
- private async _storeSessions ( ) : Promise < void > {
158
- await keychain . setToken ( JSON . stringify ( this . _sessions ) ) ;
65
+ public async getSessionData ( accessToken : TokenType . AccessToken , refreshToken : TokenType . RefreshToken ) : Promise < SessionData | null > {
66
+ try {
67
+ const { data : userInfo } = await this . _codingServer . getUserInfo ( this . _repo . team , accessToken ) ;
68
+ const ret : SessionData = {
69
+ id : nanoid ( ) ,
70
+ user : userInfo ,
71
+ accessToken,
72
+ refreshToken,
73
+ } ;
74
+
75
+ vscode . window . showInformationMessage ( `USER ${ userInfo . name } @ TEAM ${ userInfo . team } ` ) ;
76
+ return ret ;
77
+ } catch ( err ) {
78
+ return null ;
79
+ }
159
80
}
160
81
161
- private async _setToken ( session : vscode . AuthenticationSession ) : Promise < void > {
162
- const sessionIndex = this . _sessions . findIndex ( s => s . id === session . id ) ;
163
- if ( sessionIndex > - 1 ) {
164
- this . _sessions . splice ( sessionIndex , 1 , session ) ;
165
- } else {
166
- this . _sessions . push ( session ) ;
82
+ public async login ( team : string , scopes : string = SCOPES ) : Promise < SessionData | null > {
83
+ const { access_token : accessToken , refresh_token : refreshToken } = await this . _codingServer . login ( team , scopes ) ;
84
+ if ( accessToken && refreshToken ) {
85
+ const session = await this . getSessionData ( accessToken , refreshToken ) ;
86
+ await Promise . all ( [
87
+ keychain . setToken ( accessToken , TokenType . AccessToken ) ,
88
+ keychain . setToken ( refreshToken , TokenType . RefreshToken ) ,
89
+ ] ) ;
90
+ return session ;
167
91
}
168
92
169
- await this . _storeSessions ( ) ;
93
+ return null ;
170
94
}
171
95
172
- // @ts -ignore
173
- get sessions ( ) : vscode . AuthenticationSession [ ] {
174
- return this . _sessions ;
175
- }
176
-
177
- public async logout ( id : string ) {
178
- const sessionIndex = this . _sessions . findIndex ( session => session . id === id ) ;
179
- if ( sessionIndex > - 1 ) {
180
- this . _sessions . splice ( sessionIndex , 1 ) ;
181
- }
182
-
183
- await this . _storeSessions ( ) ;
96
+ get session ( ) {
97
+ return this . _session ;
184
98
}
185
99
}
0 commit comments