@@ -369,4 +369,163 @@ export const registerCommands = (context: vscode.ExtensionContext, configuration
369369 ? terminal . sendText ( `${ devProxyExe } --discover --watch-process-names ${ processNames . trim ( ) } ` )
370370 : terminal . sendText ( `${ devProxyExe } --discover` ) ;
371371 } ) ) ;
372+
373+ context . subscriptions . push (
374+ vscode . commands . registerCommand ( 'dev-proxy-toolkit.jwt-create' , async ( ) => {
375+ try {
376+ // Collect JWT parameters through input dialogs with sensible defaults
377+ const name = await vscode . window . showInputBox ( {
378+ prompt : 'Enter the name of the user to create the token for' ,
379+ placeHolder : 'Dev Proxy' ,
380+ value : 'Dev Proxy' ,
381+ title : 'JWT Generation - User Name'
382+ } ) ;
383+
384+ if ( name === undefined ) {
385+ return ; // User cancelled
386+ }
387+
388+ const issuer = await vscode . window . showInputBox ( {
389+ prompt : 'Enter the issuer of the token' ,
390+ placeHolder : 'dev-proxy' ,
391+ value : 'dev-proxy' ,
392+ title : 'JWT Generation - Issuer'
393+ } ) ;
394+
395+ if ( issuer === undefined ) {
396+ return ; // User cancelled
397+ }
398+
399+ const audiences = await vscode . window . showInputBox ( {
400+ prompt : 'Enter the audiences (comma-separated for multiple)' ,
401+ placeHolder : 'https://myserver.com' ,
402+ value : 'https://myserver.com' ,
403+ title : 'JWT Generation - Audiences'
404+ } ) ;
405+
406+ if ( audiences === undefined ) {
407+ return ; // User cancelled
408+ }
409+
410+ const roles = await vscode . window . showInputBox ( {
411+ prompt : 'Enter roles (comma-separated, leave empty for none)' ,
412+ placeHolder : 'admin,user' ,
413+ value : '' ,
414+ title : 'JWT Generation - Roles (Optional)'
415+ } ) ;
416+
417+ if ( roles === undefined ) {
418+ return ; // User cancelled
419+ }
420+
421+ const scopes = await vscode . window . showInputBox ( {
422+ prompt : 'Enter scopes (comma-separated, leave empty for none)' ,
423+ placeHolder : 'read,write' ,
424+ value : '' ,
425+ title : 'JWT Generation - Scopes (Optional)'
426+ } ) ;
427+
428+ if ( scopes === undefined ) {
429+ return ; // User cancelled
430+ }
431+
432+ const claims = await vscode . window . showInputBox ( {
433+ prompt : 'Enter custom claims in format name:value (comma-separated, leave empty for none)' ,
434+ placeHolder : 'custom:claim,department:engineering' ,
435+ value : '' ,
436+ title : 'JWT Generation - Custom Claims (Optional)'
437+ } ) ;
438+
439+ if ( claims === undefined ) {
440+ return ; // User cancelled
441+ }
442+
443+ const validFor = await vscode . window . showInputBox ( {
444+ prompt : 'Enter token validity duration in minutes' ,
445+ placeHolder : '60' ,
446+ value : '60' ,
447+ title : 'JWT Generation - Validity Duration' ,
448+ validateInput : ( value : string ) => {
449+ const num = parseInt ( value ) ;
450+ if ( isNaN ( num ) || num <= 0 ) {
451+ return 'Please enter a positive number' ;
452+ }
453+ return undefined ;
454+ }
455+ } ) ;
456+
457+ if ( validFor === undefined ) {
458+ return ; // User cancelled
459+ }
460+
461+ // Build the command with all parameters
462+ let command = `${ devProxyExe } jwt create --name "${ name } " --issuer "${ issuer } " --valid-for ${ validFor } ` ;
463+
464+ // Add audiences (can have multiple)
465+ const audienceList = audiences . split ( ',' ) . map ( a => a . trim ( ) ) . filter ( a => a ) ;
466+ audienceList . forEach ( audience => {
467+ command += ` --audiences "${ audience } "` ;
468+ } ) ;
469+
470+ // Add roles if provided
471+ const roleList = roles . split ( ',' ) . map ( r => r . trim ( ) ) . filter ( r => r ) ;
472+ roleList . forEach ( role => {
473+ command += ` --roles "${ role } "` ;
474+ } ) ;
475+
476+ // Add scopes if provided
477+ const scopeList = scopes . split ( ',' ) . map ( s => s . trim ( ) ) . filter ( s => s ) ;
478+ scopeList . forEach ( scope => {
479+ command += ` --scopes "${ scope } "` ;
480+ } ) ;
481+
482+ // Add custom claims if provided
483+ const claimList = claims . split ( ',' ) . map ( c => c . trim ( ) ) . filter ( c => c ) ;
484+ claimList . forEach ( claim => {
485+ if ( claim . includes ( ':' ) ) {
486+ command += ` --claims "${ claim } "` ;
487+ }
488+ } ) ;
489+
490+ // Show progress and execute the command
491+ await vscode . window . withProgress ( {
492+ location : vscode . ProgressLocation . Notification ,
493+ title : 'Generating JWT...' ,
494+ cancellable : false
495+ } , async ( ) => {
496+ try {
497+ const result = await executeCommand ( command ) ;
498+
499+ // Extract the token from the result (it should be on the last non-empty line)
500+ const lines = result . split ( '\n' ) . filter ( line => line . trim ( ) ) ;
501+ const token = lines [ lines . length - 1 ] . trim ( ) ;
502+
503+ // Show the token in a dialog with copy option
504+ const choice = await vscode . window . showInformationMessage (
505+ 'JWT generated successfully!' ,
506+ { modal : true } ,
507+ 'Copy to Clipboard' ,
508+ 'Show Token'
509+ ) ;
510+
511+ if ( choice === 'Copy to Clipboard' ) {
512+ await vscode . env . clipboard . writeText ( token ) ;
513+ vscode . window . showInformationMessage ( 'JWT copied to clipboard' ) ;
514+ } else if ( choice === 'Show Token' ) {
515+ // Create a new untitled document to show the token
516+ const document = await vscode . workspace . openTextDocument ( {
517+ content : `JWT Generated: ${ new Date ( ) . toISOString ( ) } \n\nToken: ${ token } \n\nCommand used:\n${ command } ` ,
518+ language : 'plaintext'
519+ } ) ;
520+ await vscode . window . showTextDocument ( document ) ;
521+ }
522+ } catch ( error ) {
523+ vscode . window . showErrorMessage ( `Failed to generate JWT token: ${ error } ` ) ;
524+ }
525+ } ) ;
526+
527+ } catch ( error ) {
528+ vscode . window . showErrorMessage ( `Error in JWT generation: ${ error } ` ) ;
529+ }
530+ } ) ) ;
372531} ;
0 commit comments