@@ -6,6 +6,7 @@ import { SYSTEM_PATHS, USER_PATHS, ENV_VARS } from '../system/paths.js';
66import { runPs } from '../system/powershell.js' ;
77import fs from 'fs-extra' ;
88import path from 'path' ;
9+ import inquirer from 'inquirer' ;
910
1011export const authCommand = new Command ( 'auth' )
1112 . description ( 'Manage authentication and credentials' ) ;
@@ -68,8 +69,9 @@ authCommand.command('set-service-account')
6869 . description ( 'Configure service account credentials' )
6970 . requiredOption ( '-f, --file <path>' , 'Path to service account JSON key' )
7071 . option ( '-s, --scope <scope>' , 'Scope (Machine or User)' , 'User' )
72+ . option ( '--no-rename' , 'Do not rename the file to service account name' )
7173 . action ( async ( options ) => {
72- const { file, scope } = options ;
74+ const { file, scope, rename } = options ;
7375 if ( ! [ 'Machine' , 'User' ] . includes ( scope ) ) {
7476 logger . error ( 'Scope must be either Machine or User' ) ;
7577 process . exit ( 1 ) ;
@@ -81,10 +83,21 @@ authCommand.command('set-service-account')
8183 process . exit ( 1 ) ;
8284 }
8385
86+ const keyData = await fs . readJson ( file ) ;
87+ if ( keyData . type !== 'service_account' ) {
88+ logger . error ( 'Invalid service account key file.' ) ;
89+ process . exit ( 1 ) ;
90+ }
91+
8492 const paths = scope === 'Machine' ? SYSTEM_PATHS : USER_PATHS ;
8593 await fs . ensureDir ( paths . SECRETS ) ;
8694
87- const fileName = path . basename ( file ) ;
95+ let fileName = path . basename ( file ) ;
96+ if ( rename && keyData . client_email ) {
97+ const saName = keyData . client_email . split ( '@' ) [ 0 ] ;
98+ fileName = `${ saName } .json` ;
99+ }
100+
88101 const dest = path . join ( paths . SECRETS , fileName ) ;
89102
90103 await fs . copy ( file , dest , { overwrite : true } ) ;
@@ -105,3 +118,69 @@ authCommand.command('set-service-account')
105118 process . exit ( 1 ) ;
106119 }
107120 } ) ;
121+
122+ authCommand . command ( 'list-keys' )
123+ . description ( 'List available service account keys' )
124+ . action ( async ( ) => {
125+ try {
126+ const userKeys = ( await fs . pathExists ( USER_PATHS . SECRETS ) ) ? await fs . readdir ( USER_PATHS . SECRETS ) : [ ] ;
127+ const systemKeys = ( await fs . pathExists ( SYSTEM_PATHS . SECRETS ) ) ? await fs . readdir ( SYSTEM_PATHS . SECRETS ) : [ ] ;
128+
129+ logger . info ( 'Available Service Account Keys:' ) ;
130+
131+ if ( userKeys . length > 0 ) {
132+ logger . info ( '\n User Scope:' ) ;
133+ userKeys . filter ( f => f . endsWith ( '.json' ) ) . forEach ( f => logger . info ( ` - ${ f } ` ) ) ;
134+ }
135+
136+ if ( systemKeys . length > 0 ) {
137+ logger . info ( '\n Machine Scope:' ) ;
138+ systemKeys . filter ( f => f . endsWith ( '.json' ) ) . forEach ( f => logger . info ( ` - ${ f } ` ) ) ;
139+ }
140+
141+ if ( userKeys . length === 0 && systemKeys . length === 0 ) {
142+ logger . info ( ' No keys found.' ) ;
143+ }
144+ } catch ( error ) {
145+ logger . error ( 'Failed to list keys' , error ) ;
146+ }
147+ } ) ;
148+
149+ authCommand . command ( 'select-key' )
150+ . description ( 'Interactively select a service account key' )
151+ . option ( '-s, --scope <scope>' , 'Scope (Machine or User)' , 'User' )
152+ . action ( async ( options ) => {
153+ const { scope } = options ;
154+ const paths = scope === 'Machine' ? SYSTEM_PATHS : USER_PATHS ;
155+
156+ try {
157+ if ( ! await fs . pathExists ( paths . SECRETS ) ) {
158+ logger . error ( `No keys found in ${ scope } scope.` ) ;
159+ return ;
160+ }
161+
162+ const keys = ( await fs . readdir ( paths . SECRETS ) ) . filter ( f => f . endsWith ( '.json' ) ) ;
163+ if ( keys . length === 0 ) {
164+ logger . error ( `No keys found in ${ scope } scope.` ) ;
165+ return ;
166+ }
167+
168+ const { selectedKey } = await inquirer . prompt ( [
169+ {
170+ type : 'list' ,
171+ name : 'selectedKey' ,
172+ message : `Select a service account key (${ scope } scope):` ,
173+ choices : keys
174+ }
175+ ] ) ;
176+
177+ const fullPath = path . join ( paths . SECRETS , selectedKey ) ;
178+ await setEnv ( ENV_VARS . GOOGLE_CREDS , fullPath , scope ) ;
179+ logger . info ( `Successfully selected ${ selectedKey } and updated ${ ENV_VARS . GOOGLE_CREDS } ` ) ;
180+
181+ } catch ( error ) {
182+ logger . error ( 'Failed to select key' , error ) ;
183+ process . exit ( 1 ) ;
184+ }
185+ } ) ;
186+
0 commit comments