| 218 | } |
| 219 | |
| 220 | export class PasswordInteractor implements IInteractor { |
| 221 | static ID = 'password'; |
| 222 | |
| 223 | constructor(private readonly host: ISshHostInfo, private readonly passwordProvider: IStringProvider) { } |
| 224 | |
| 225 | get id(): string { |
| 226 | return PasswordInteractor.ID; |
| 227 | } |
| 228 | |
| 229 | async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> { |
| 230 | const result: IInteraction = { postAction: 'keep' }; |
| 231 | const pwPrompt: { user?: string; message?: string } | undefined = getPasswordPrompt(data, extraDetails); |
| 232 | if (pwPrompt && typeof pwPrompt.user === 'string') { |
| 233 | result.postAction = 'consume'; |
| 234 | const actualUser: string = pwPrompt.user === '' ? getFullHostAddress(this.host) : pwPrompt.user; |
| 235 | const passwordCacheKey: string = `SSH:${actualUser}`; |
| 236 | const cachedPassword: string | undefined = await extensionContext?.secrets?.get(passwordCacheKey); |
| 237 | if (cachedPassword !== undefined && !autoFilledPasswordForUsers.has(actualUser)) { |
| 238 | autoFilledPasswordForUsers.add(actualUser); |
| 239 | result.response = cachedPassword; |
| 240 | result.isPassword = true; |
| 241 | } else { |
| 242 | const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken); |
| 243 | if (typeof password === 'string') { |
| 244 | await extensionContext?.secrets?.store(passwordCacheKey, password); |
| 245 | autoFilledPasswordForUsers.add(actualUser); |
| 246 | result.response = password; |
| 247 | result.isPassword = true; |
| 248 | } else { |
| 249 | result.canceled = true; |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | return result; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | export type IVerificationCodeProvider = |
| 259 | (msg: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>; |
nothing calls this directly
no outgoing calls
no test coverage detected