1- import { app , ipcMain , shell } from 'electron'
1+ import { app , BrowserWindow , ipcMain , shell } from 'electron'
22import log from 'electron-log/main'
33
44import { getProfileData } from '@/handlers/auth/fs'
@@ -10,17 +10,19 @@ import {
1010 generateState ,
1111 startCallbackServer ,
1212} from '@/services/grafana/assistantAuth'
13+ import { browserWindowFromEvent } from '@/utils/electron'
1314
15+ import { abortAllActiveAssistantSessions } from '../grafanaAssistantProvider'
1416import { AssistantAuthHandler } from '../types'
1517
18+ import { LOG_PREFIX } from './constants'
1619import {
1720 clearAssistantTokens ,
1821 hasAssistantTokens ,
22+ mapTokenResponse ,
1923 saveAssistantTokens ,
2024} from './tokenStore'
2125
22- const PREFIX = '[GrafanaAssistant]'
23-
2426export type AssistantAuthResult =
2527 | { type : 'authenticated' }
2628 | { type : 'error' ; error : string }
@@ -47,11 +49,23 @@ function isAllowedEndpoint(endpoint: string, stackUrl: string): boolean {
4749 }
4850}
4951
52+ function verificationCode ( codeChallenge : string ) : string {
53+ try {
54+ const hex = Buffer . from ( codeChallenge , 'base64url' )
55+ . subarray ( 0 , 4 )
56+ . toString ( 'hex' )
57+ return hex . slice ( 0 , 4 ) + '-' + hex . slice ( 4 )
58+ } catch {
59+ return '----'
60+ }
61+ }
62+
5063let pendingAbortController : AbortController | null = null
5164
5265async function performSignIn (
5366 stackId : string ,
54- stackUrl : string
67+ stackUrl : string ,
68+ browserWindow : BrowserWindow
5569) : Promise < AssistantAuthResult > {
5670 const abortController = new AbortController ( )
5771 pendingAbortController = abortController
@@ -65,22 +79,25 @@ async function performSignIn(
6579 const authUrl = buildAssistantAuthUrl ( stackUrl , codeChallenge , state , port )
6680
6781 log . info (
68- PREFIX ,
82+ LOG_PREFIX ,
6983 'Initiating assistant auth for stack' ,
7084 stackId ,
7185 'on port' ,
7286 port
7387 )
7488 void shell . openExternal ( authUrl )
7589
90+ const code = verificationCode ( codeChallenge )
91+ browserWindow . webContents . send ( AssistantAuthHandler . VerificationCode , code )
92+
7693 const callback = await result
7794 app . focus ( { steal : true } )
7895
7996 if ( callback . state !== state ) {
80- log . error ( PREFIX , 'State mismatch in assistant auth callback' )
97+ log . error ( LOG_PREFIX , 'State mismatch in assistant auth callback' )
8198 return {
8299 type : 'error' ,
83- error : 'State mismatch — possible CSRF attack. Please try again.' ,
100+ error : 'State mismatch, possible CSRF attack. Please try again.' ,
84101 }
85102 }
86103
@@ -93,7 +110,7 @@ async function performSignIn(
93110
94111 if ( ! isAllowedEndpoint ( callback . endpoint , stackUrl ) ) {
95112 log . error (
96- PREFIX ,
113+ LOG_PREFIX ,
97114 'Callback endpoint does not match expected stack URL:' ,
98115 callback . endpoint
99116 )
@@ -114,22 +131,18 @@ async function performSignIn(
114131 return { type : 'aborted' }
115132 }
116133
117- await saveAssistantTokens ( stackId , {
118- accessToken : tokenResponse . token ,
119- refreshToken : tokenResponse . refresh_token ,
120- apiEndpoint : tokenResponse . api_endpoint ,
121- expiresAt : new Date ( tokenResponse . expires_at ) . getTime ( ) ,
122- refreshExpiresAt : new Date ( tokenResponse . refresh_expires_at ) . getTime ( ) ,
123- } )
134+ const tokens = mapTokenResponse ( tokenResponse , tokenResponse . api_endpoint )
135+
136+ await saveAssistantTokens ( stackId , tokens )
124137
125- log . info ( PREFIX , 'Assistant auth completed for stack' , stackId )
138+ log . info ( LOG_PREFIX , 'Assistant auth completed for stack' , stackId )
126139 return { type : 'authenticated' }
127140 } catch ( error ) {
128141 if ( abortController . signal . aborted ) {
129142 return { type : 'aborted' }
130143 }
131144
132- log . error ( PREFIX , 'Assistant auth failed:' , error )
145+ log . error ( LOG_PREFIX , 'Assistant auth failed:' , error )
133146 return {
134147 type : 'error' ,
135148 error : error instanceof Error ? error . message : 'Authentication failed' ,
@@ -144,7 +157,8 @@ async function performSignIn(
144157export function initialize ( ) {
145158 ipcMain . handle (
146159 AssistantAuthHandler . SignIn ,
147- async ( ) : Promise < AssistantAuthResult > => {
160+ async ( event ) : Promise < AssistantAuthResult > => {
161+ const browserWindow = browserWindowFromEvent ( event )
148162 const profile = await getProfileData ( )
149163 const stackId = profile . profiles . currentStack
150164
@@ -170,7 +184,7 @@ export function initialize() {
170184 pendingAbortController . abort ( )
171185 }
172186
173- return performSignIn ( stackId , stack . url )
187+ return performSignIn ( stackId , stack . url , browserWindow )
174188 }
175189 )
176190
@@ -207,8 +221,9 @@ export function initialize() {
207221 const stackId = profile . profiles . currentStack
208222
209223 if ( stackId ) {
224+ abortAllActiveAssistantSessions ( )
210225 await clearAssistantTokens ( stackId )
211- log . info ( PREFIX , 'Cleared assistant tokens for stack' , stackId )
226+ log . info ( LOG_PREFIX , 'Cleared assistant tokens for stack' , stackId )
212227 }
213228 } )
214229}
0 commit comments