From bc1389480dc1da0cc4d995953a72e3cc77e4c55e Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Thu, 31 Jul 2025 15:46:17 -0400 Subject: [PATCH 1/6] feat: add types for file watcher --- runtimes/protocol/identity-management.ts | 10 ++++++++++ runtimes/runtimes/base-runtime.ts | 2 ++ runtimes/runtimes/standalone.ts | 2 ++ runtimes/server-interface/identity-management.ts | 3 +++ 4 files changed, 17 insertions(+) diff --git a/runtimes/protocol/identity-management.ts b/runtimes/protocol/identity-management.ts index 69f93bc5..5d9853cb 100644 --- a/runtimes/protocol/identity-management.ts +++ b/runtimes/protocol/identity-management.ts @@ -400,3 +400,13 @@ export interface StsCredentialChangedParams { export const stsCredentialChangedRequestType = new ProtocolNotificationType( 'aws/identity/stsCredentialChanged' ) + +// profileChanged +export interface ProfileChangedParams { + profiles: Profile[] + ssoSessions: SsoSession[] +} + +export const profileChangedRequestType = new ProtocolNotificationType( + 'aws/identity/stsCredentialChanged' +) diff --git a/runtimes/runtimes/base-runtime.ts b/runtimes/runtimes/base-runtime.ts index 17591ba0..f1834491 100644 --- a/runtimes/runtimes/base-runtime.ts +++ b/runtimes/runtimes/base-runtime.ts @@ -94,6 +94,7 @@ import { updateProfileRequestType, stsCredentialChangedRequestType, getMfaCodeRequestType, + profileChangedRequestType, } from '../protocol/identity-management' import { IdentityManagement } from '../server-interface/identity-management' import { WebBase64Encoding } from './encoding' @@ -218,6 +219,7 @@ export const baseRuntime = (connections: { reader: MessageReader; writer: Messag onInvalidateStsCredential: handler => lspConnection.onRequest(invalidateStsCredentialRequestType, handler), sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params), sendStsCredentialChanged: params => lspConnection.sendNotification(stsCredentialChangedRequestType, params), + sendProfileChanged: params => lspConnection.sendNotification(profileChangedRequestType, params), sendGetMfaCode: params => lspConnection.sendRequest(getMfaCodeRequestType, params), } diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index 6e10e85f..f2087106 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -34,6 +34,7 @@ import { ShowOpenDialogRequestType, stsCredentialChangedRequestType, getMfaCodeRequestType, + profileChangedRequestType, } from '../protocol' import { ProposedFeatures, createConnection } from 'vscode-languageserver/node' import { @@ -332,6 +333,7 @@ export const standalone = (props: RuntimeProps) => { onInvalidateStsCredential: handler => lspConnection.onRequest(invalidateStsCredentialRequestType, handler), sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params), sendStsCredentialChanged: params => lspConnection.sendNotification(stsCredentialChangedRequestType, params), + sendProfileChanged: params => lspConnection.sendNotification(profileChangedRequestType, params), sendGetMfaCode: params => lspConnection.sendRequest(getMfaCodeRequestType, params), } diff --git a/runtimes/server-interface/identity-management.ts b/runtimes/server-interface/identity-management.ts index 6e0de534..f03d9dae 100644 --- a/runtimes/server-interface/identity-management.ts +++ b/runtimes/server-interface/identity-management.ts @@ -16,6 +16,7 @@ import { UpdateProfileParams, UpdateProfileResult, GetMfaCodeResult, + ProfileChangedParams, } from '../protocol/identity-management' import { RequestHandler } from '../protocol' @@ -54,5 +55,7 @@ export type IdentityManagement = { sendStsCredentialChanged: (params: StsCredentialChangedParams) => void + sendProfileChanged: (params: ProfileChangedParams) => void + sendGetMfaCode: (params: GetMfaCodeParams) => Promise } From 521fd277930e1eed072cf21a1a88cf139172be37 Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Tue, 29 Jul 2025 14:53:46 -0400 Subject: [PATCH 2/6] feat: add optional encryption to updateProfile --- .../runtimes/auth/standalone/encryption.ts | 21 +++++++++++++------ runtimes/runtimes/standalone.ts | 12 ++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/runtimes/runtimes/auth/standalone/encryption.ts b/runtimes/runtimes/auth/standalone/encryption.ts index f5f3475b..a6d90b38 100644 --- a/runtimes/runtimes/auth/standalone/encryption.ts +++ b/runtimes/runtimes/auth/standalone/encryption.ts @@ -1,5 +1,5 @@ import { Readable } from 'stream' -import { CompactEncrypt } from 'jose' +import { compactDecrypt, CompactEncrypt } from 'jose' import { GetIamCredentialResult, GetSsoTokenResult } from '../../../protocol' export function shouldWaitForEncryptionKey(): boolean { @@ -99,6 +99,15 @@ export function encryptObjectWithKey(request: Object, key: string, alg?: string, .encrypt(keyBuffer) } +/** + * Decrypt an object with the provided key + */ +export async function decryptObjectWithKey(request: string, key: string, alg?: string, enc?: string): Promise { + const keyBuffer = Buffer.from(key, 'base64') + const result = await compactDecrypt(request, keyBuffer) + return JSON.parse(new TextDecoder().decode(result.plaintext)) as T +} + /** * Encrypts the SSO access tokens inside the result object with the provided key */ @@ -124,12 +133,12 @@ export async function encryptIamResultWithKey( request: GetIamCredentialResult, key: string ): Promise { + const { accessKeyId, secretAccessKey, sessionToken, expiration } = request.credential.credentials request.credential.credentials = { - accessKeyId: await encryptObjectWithKey(request.credential.credentials.accessKeyId, key), - secretAccessKey: await encryptObjectWithKey(request.credential.credentials.secretAccessKey, key), - ...(request.credential.credentials.sessionToken - ? { sessionToken: await encryptObjectWithKey(request.credential.credentials.sessionToken, key) } - : {}), + accessKeyId: await encryptObjectWithKey(accessKeyId, key), + secretAccessKey: await encryptObjectWithKey(secretAccessKey, key), + sessionToken: sessionToken ? await encryptObjectWithKey(sessionToken, key) : undefined, + expiration: expiration, } if (!request.updateCredentialsParams.encrypted) { request.updateCredentialsParams.data = await encryptObjectWithKey( diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index f2087106..6ece0b04 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -35,9 +35,11 @@ import { stsCredentialChangedRequestType, getMfaCodeRequestType, profileChangedRequestType, + UpdateProfileParams, } from '../protocol' import { ProposedFeatures, createConnection } from 'vscode-languageserver/node' import { + decryptObjectWithKey, encryptIamResultWithKey, EncryptionInitialization, encryptObjectWithKey, @@ -306,7 +308,15 @@ export const standalone = (props: RuntimeProps) => { const identityManagement: IdentityManagement = { onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler), - onUpdateProfile: handler => lspConnection.onRequest(updateProfileRequestType, handler), + onUpdateProfile: handler => + lspConnection.onRequest( + updateProfileRequestType, + async (params: UpdateProfileParams | string, token: CancellationToken) => { + const decrypted: UpdateProfileParams = + typeof params === 'string' ? await decryptObjectWithKey(params, encryptionKey!) : params + return await handler(decrypted, token) + } + ), onGetSsoToken: handler => lspConnection.onRequest( getSsoTokenRequestType, From 6d05538f9328ebd5e46db5fa7409bbe60d3afc82 Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Fri, 1 Aug 2025 12:29:59 -0400 Subject: [PATCH 3/6] Revert "feat: add optional encryption to updateProfile" This reverts commit c0f83ffcc4b49d87cc0990fee3f9cb82ee11145d. --- .../runtimes/auth/standalone/encryption.ts | 21 ++++++------------- runtimes/runtimes/standalone.ts | 12 +---------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/runtimes/runtimes/auth/standalone/encryption.ts b/runtimes/runtimes/auth/standalone/encryption.ts index a6d90b38..f5f3475b 100644 --- a/runtimes/runtimes/auth/standalone/encryption.ts +++ b/runtimes/runtimes/auth/standalone/encryption.ts @@ -1,5 +1,5 @@ import { Readable } from 'stream' -import { compactDecrypt, CompactEncrypt } from 'jose' +import { CompactEncrypt } from 'jose' import { GetIamCredentialResult, GetSsoTokenResult } from '../../../protocol' export function shouldWaitForEncryptionKey(): boolean { @@ -99,15 +99,6 @@ export function encryptObjectWithKey(request: Object, key: string, alg?: string, .encrypt(keyBuffer) } -/** - * Decrypt an object with the provided key - */ -export async function decryptObjectWithKey(request: string, key: string, alg?: string, enc?: string): Promise { - const keyBuffer = Buffer.from(key, 'base64') - const result = await compactDecrypt(request, keyBuffer) - return JSON.parse(new TextDecoder().decode(result.plaintext)) as T -} - /** * Encrypts the SSO access tokens inside the result object with the provided key */ @@ -133,12 +124,12 @@ export async function encryptIamResultWithKey( request: GetIamCredentialResult, key: string ): Promise { - const { accessKeyId, secretAccessKey, sessionToken, expiration } = request.credential.credentials request.credential.credentials = { - accessKeyId: await encryptObjectWithKey(accessKeyId, key), - secretAccessKey: await encryptObjectWithKey(secretAccessKey, key), - sessionToken: sessionToken ? await encryptObjectWithKey(sessionToken, key) : undefined, - expiration: expiration, + accessKeyId: await encryptObjectWithKey(request.credential.credentials.accessKeyId, key), + secretAccessKey: await encryptObjectWithKey(request.credential.credentials.secretAccessKey, key), + ...(request.credential.credentials.sessionToken + ? { sessionToken: await encryptObjectWithKey(request.credential.credentials.sessionToken, key) } + : {}), } if (!request.updateCredentialsParams.encrypted) { request.updateCredentialsParams.data = await encryptObjectWithKey( diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index 6ece0b04..f2087106 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -35,11 +35,9 @@ import { stsCredentialChangedRequestType, getMfaCodeRequestType, profileChangedRequestType, - UpdateProfileParams, } from '../protocol' import { ProposedFeatures, createConnection } from 'vscode-languageserver/node' import { - decryptObjectWithKey, encryptIamResultWithKey, EncryptionInitialization, encryptObjectWithKey, @@ -308,15 +306,7 @@ export const standalone = (props: RuntimeProps) => { const identityManagement: IdentityManagement = { onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler), - onUpdateProfile: handler => - lspConnection.onRequest( - updateProfileRequestType, - async (params: UpdateProfileParams | string, token: CancellationToken) => { - const decrypted: UpdateProfileParams = - typeof params === 'string' ? await decryptObjectWithKey(params, encryptionKey!) : params - return await handler(decrypted, token) - } - ), + onUpdateProfile: handler => lspConnection.onRequest(updateProfileRequestType, handler), onGetSsoToken: handler => lspConnection.onRequest( getSsoTokenRequestType, From 062567d84cb4467a88b4ff3edb689236cbc7c75a Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Tue, 29 Jul 2025 14:53:46 -0400 Subject: [PATCH 4/6] feat: add optional encryption to updateProfile --- .../runtimes/auth/standalone/encryption.ts | 21 +++++++++++++------ runtimes/runtimes/standalone.ts | 12 ++++++++++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/runtimes/runtimes/auth/standalone/encryption.ts b/runtimes/runtimes/auth/standalone/encryption.ts index f5f3475b..a6d90b38 100644 --- a/runtimes/runtimes/auth/standalone/encryption.ts +++ b/runtimes/runtimes/auth/standalone/encryption.ts @@ -1,5 +1,5 @@ import { Readable } from 'stream' -import { CompactEncrypt } from 'jose' +import { compactDecrypt, CompactEncrypt } from 'jose' import { GetIamCredentialResult, GetSsoTokenResult } from '../../../protocol' export function shouldWaitForEncryptionKey(): boolean { @@ -99,6 +99,15 @@ export function encryptObjectWithKey(request: Object, key: string, alg?: string, .encrypt(keyBuffer) } +/** + * Decrypt an object with the provided key + */ +export async function decryptObjectWithKey(request: string, key: string, alg?: string, enc?: string): Promise { + const keyBuffer = Buffer.from(key, 'base64') + const result = await compactDecrypt(request, keyBuffer) + return JSON.parse(new TextDecoder().decode(result.plaintext)) as T +} + /** * Encrypts the SSO access tokens inside the result object with the provided key */ @@ -124,12 +133,12 @@ export async function encryptIamResultWithKey( request: GetIamCredentialResult, key: string ): Promise { + const { accessKeyId, secretAccessKey, sessionToken, expiration } = request.credential.credentials request.credential.credentials = { - accessKeyId: await encryptObjectWithKey(request.credential.credentials.accessKeyId, key), - secretAccessKey: await encryptObjectWithKey(request.credential.credentials.secretAccessKey, key), - ...(request.credential.credentials.sessionToken - ? { sessionToken: await encryptObjectWithKey(request.credential.credentials.sessionToken, key) } - : {}), + accessKeyId: await encryptObjectWithKey(accessKeyId, key), + secretAccessKey: await encryptObjectWithKey(secretAccessKey, key), + sessionToken: sessionToken ? await encryptObjectWithKey(sessionToken, key) : undefined, + expiration: expiration, } if (!request.updateCredentialsParams.encrypted) { request.updateCredentialsParams.data = await encryptObjectWithKey( diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index f2087106..6ece0b04 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -35,9 +35,11 @@ import { stsCredentialChangedRequestType, getMfaCodeRequestType, profileChangedRequestType, + UpdateProfileParams, } from '../protocol' import { ProposedFeatures, createConnection } from 'vscode-languageserver/node' import { + decryptObjectWithKey, encryptIamResultWithKey, EncryptionInitialization, encryptObjectWithKey, @@ -306,7 +308,15 @@ export const standalone = (props: RuntimeProps) => { const identityManagement: IdentityManagement = { onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler), - onUpdateProfile: handler => lspConnection.onRequest(updateProfileRequestType, handler), + onUpdateProfile: handler => + lspConnection.onRequest( + updateProfileRequestType, + async (params: UpdateProfileParams | string, token: CancellationToken) => { + const decrypted: UpdateProfileParams = + typeof params === 'string' ? await decryptObjectWithKey(params, encryptionKey!) : params + return await handler(decrypted, token) + } + ), onGetSsoToken: handler => lspConnection.onRequest( getSsoTokenRequestType, From ec88d28095fd6a34ab30a2a13d1b8b3ab9f7005b Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Fri, 1 Aug 2025 13:57:33 -0400 Subject: [PATCH 5/6] feat: add encryption to listProfiles --- runtimes/protocol/identity-management.ts | 2 +- runtimes/runtimes/auth/standalone/encryption.ts | 2 +- runtimes/runtimes/standalone.ts | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/runtimes/protocol/identity-management.ts b/runtimes/protocol/identity-management.ts index 5d9853cb..f977b2dd 100644 --- a/runtimes/protocol/identity-management.ts +++ b/runtimes/protocol/identity-management.ts @@ -141,7 +141,7 @@ export interface ListProfilesResult { // Potential error codes: E_UNKNOWN | E_TIMEOUT | E_RUNTIME_NOT_SUPPORTED | E_CANNOT_READ_SHARED_CONFIG export const listProfilesRequestType = new ProtocolRequestType< ListProfilesParams, - ListProfilesResult, + ListProfilesResult | string, never, AwsResponseError, void diff --git a/runtimes/runtimes/auth/standalone/encryption.ts b/runtimes/runtimes/auth/standalone/encryption.ts index a6d90b38..001edcbd 100644 --- a/runtimes/runtimes/auth/standalone/encryption.ts +++ b/runtimes/runtimes/auth/standalone/encryption.ts @@ -102,7 +102,7 @@ export function encryptObjectWithKey(request: Object, key: string, alg?: string, /** * Decrypt an object with the provided key */ -export async function decryptObjectWithKey(request: string, key: string, alg?: string, enc?: string): Promise { +export async function decryptObjectWithKey(request: string, key: string): Promise { const keyBuffer = Buffer.from(key, 'base64') const result = await compactDecrypt(request, keyBuffer) return JSON.parse(new TextDecoder().decode(result.plaintext)) as T diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index 6ece0b04..6fd253f5 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -36,6 +36,7 @@ import { getMfaCodeRequestType, profileChangedRequestType, UpdateProfileParams, + ListProfilesParams, } from '../protocol' import { ProposedFeatures, createConnection } from 'vscode-languageserver/node' import { @@ -307,7 +308,17 @@ export const standalone = (props: RuntimeProps) => { } const identityManagement: IdentityManagement = { - onListProfiles: handler => lspConnection.onRequest(listProfilesRequestType, handler), + onListProfiles: handler => + lspConnection.onRequest( + listProfilesRequestType, + async (params: ListProfilesParams, token: CancellationToken) => { + let result = await handler(params, token) + if (result && !(result instanceof Error) && encryptionKey) { + return await encryptObjectWithKey(result, encryptionKey) + } + return result + } + ), onUpdateProfile: handler => lspConnection.onRequest( updateProfileRequestType, From ab52a0e4899c2ba1339bc62af144441297de24eb Mon Sep 17 00:00:00 2001 From: Ramon Li Date: Wed, 6 Aug 2025 10:20:02 -0400 Subject: [PATCH 6/6] feat: encrypt sendProfileChanged --- runtimes/protocol/identity-management.ts | 2 +- runtimes/runtimes/standalone.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/runtimes/protocol/identity-management.ts b/runtimes/protocol/identity-management.ts index f977b2dd..d96cc783 100644 --- a/runtimes/protocol/identity-management.ts +++ b/runtimes/protocol/identity-management.ts @@ -407,6 +407,6 @@ export interface ProfileChangedParams { ssoSessions: SsoSession[] } -export const profileChangedRequestType = new ProtocolNotificationType( +export const profileChangedRequestType = new ProtocolNotificationType( 'aws/identity/stsCredentialChanged' ) diff --git a/runtimes/runtimes/standalone.ts b/runtimes/runtimes/standalone.ts index 6fd253f5..9137e504 100644 --- a/runtimes/runtimes/standalone.ts +++ b/runtimes/runtimes/standalone.ts @@ -354,7 +354,10 @@ export const standalone = (props: RuntimeProps) => { onInvalidateStsCredential: handler => lspConnection.onRequest(invalidateStsCredentialRequestType, handler), sendSsoTokenChanged: params => lspConnection.sendNotification(ssoTokenChangedRequestType, params), sendStsCredentialChanged: params => lspConnection.sendNotification(stsCredentialChangedRequestType, params), - sendProfileChanged: params => lspConnection.sendNotification(profileChangedRequestType, params), + sendProfileChanged: async params => { + const encrypted = encryptionKey ? await encryptObjectWithKey(params, encryptionKey) : params + lspConnection.sendNotification(profileChangedRequestType, encrypted) + }, sendGetMfaCode: params => lspConnection.sendRequest(getMfaCodeRequestType, params), }