66import * as vscode from 'vscode'
77import * as localizedText from '../../shared/localizedText'
88import * as nls from 'vscode-nls'
9+ import * as fs from 'fs'
10+ import * as path from 'path'
11+ import * as crypto from 'crypto'
912import { ToolkitError } from '../../shared/errors'
1013import { AmazonQPromptSettings } from '../../shared/settings'
1114import {
@@ -16,6 +19,9 @@ import {
1619 TelemetryMetadata ,
1720 scopesSsoAccountAccess ,
1821 hasScopes ,
22+ SsoProfile ,
23+ StoredProfile ,
24+ hasExactScopes ,
1925} from '../../auth/connection'
2026import { getLogger } from '../../shared/logger/logger'
2127import { Commands } from '../../shared/vscode/commands2'
@@ -30,6 +36,8 @@ import { builderIdStartUrl, internalStartUrl } from '../../auth/sso/constants'
3036import { VSCODE_EXTENSION_ID } from '../../shared/extensions'
3137import { RegionProfileManager } from '../region/regionProfileManager'
3238import { AuthFormId } from '../../login/webview/vue/types'
39+ import { getEnvironmentSpecificMemento } from '../../shared/utilities/mementos'
40+ import { getCacheDir , getRegistrationCacheFile , getTokenCacheFile } from '../../auth/sso/cache'
3341
3442const localize = nls . loadMessageBundle ( )
3543
@@ -333,4 +341,79 @@ export class AuthUtil implements IAuthProvider {
333341
334342 return authIds
335343 }
344+
345+ /**
346+ * Migrates existing SSO connections to the LSP identity server by updating the cache files
347+ *
348+ * @param clientName - The client name to use for the new registration cache file
349+ * @returns A Promise that resolves when the migration is complete
350+ * @throws Error if file operations fail during migration
351+ */
352+ async migrateSsoConnectionToLsp ( clientName : string ) {
353+ const memento = getEnvironmentSpecificMemento ( )
354+ const key = 'auth.profiles'
355+ const profiles : { readonly [ id : string ] : StoredProfile } | undefined = memento . get ( key )
356+
357+ let toImport : SsoProfile | undefined
358+ let profileId : string | undefined
359+
360+ getLogger ( ) . info ( `codewhisperer: checking for old SSO connections` )
361+ if ( profiles ) {
362+ for ( const [ id , p ] of Object . entries ( profiles ) ) {
363+ if ( p . type === 'sso' && hasExactScopes ( p . scopes ?? [ ] , amazonQScopes ) ) {
364+ toImport = p
365+ profileId = id
366+ if ( p . metadata . connectionState === 'valid' ) {
367+ break
368+ }
369+ }
370+ }
371+
372+ if ( toImport && profileId ) {
373+ getLogger ( ) . info ( `codewhisperer: migrating SSO connection to LSP identity server...` )
374+
375+ const registrationKey = {
376+ startUrl : toImport . startUrl ,
377+ region : toImport . ssoRegion ,
378+ scopes : amazonQScopes ,
379+ }
380+
381+ await this . session . updateProfile ( registrationKey )
382+
383+ const cacheDir = getCacheDir ( )
384+
385+ const hash = ( str : string ) => {
386+ const hasher = crypto . createHash ( 'sha1' )
387+ return hasher . update ( str ) . digest ( 'hex' )
388+ }
389+ const filePath = ( str : string ) => {
390+ return path . join ( cacheDir , hash ( str ) + '.json' )
391+ }
392+
393+ const fromRegistrationFile = getRegistrationCacheFile ( cacheDir , registrationKey )
394+ const toRegistrationFile = filePath (
395+ JSON . stringify ( {
396+ region : toImport . ssoRegion ,
397+ startUrl : toImport . startUrl ,
398+ tool : clientName ,
399+ } )
400+ )
401+
402+ const fromTokenFile = getTokenCacheFile ( cacheDir , profileId )
403+ const toTokenFile = filePath ( this . profileName )
404+
405+ try {
406+ fs . renameSync ( fromRegistrationFile , toRegistrationFile )
407+ fs . renameSync ( fromTokenFile , toTokenFile )
408+ getLogger ( ) . debug ( 'Successfully renamed registration and token files' )
409+ } catch ( err ) {
410+ getLogger ( ) . error ( `Failed to rename files during migration: ${ err } ` )
411+ throw err
412+ }
413+
414+ await memento . update ( key , undefined )
415+ getLogger ( ) . info ( `codewhisperer: successfully migrated SSO connection to LSP identity server` )
416+ }
417+ }
418+ }
336419}
0 commit comments