Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@aws/language-server-runtimes

Package Overview
Dependencies
Maintainers
0
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aws/language-server-runtimes - npm Package Compare versions

Comparing version 0.2.7 to 0.2.8

runtimes/chat/baseChat.d.ts

2

package.json
{
"name": "@aws/language-server-runtimes",
"version": "0.2.7",
"version": "0.2.8",
"description": "Runtimes to host Language Servers for AWS",

@@ -5,0 +5,0 @@ "files": [

@@ -34,2 +34,16 @@ /// <reference types="node" />

*/
export declare function encryptObjectWithKey(request: Object, key: string): Promise<string>;
export declare function encryptObjectWithKey(request: Object, key: string, alg?: string, enc?: string): Promise<string>;
/**
* Check if a message is an encrypted JWE message with the provided key management algorithm and encoding
* As per RFC-7516:
* When using the JWE Compact Serialization, the
* JWE Protected Header, the JWE Encrypted Key, the JWE
* Initialization Vector, the JWE Ciphertext, and the JWE
* Authentication Tag are represented as base64url-encoded values
* in that order, with each value being separated from the next by
* a single period ('.') character, resulting in exactly four
* delimiting period characters being used
* This function checks if the payload is separated by 4 periods and
* Decodes the protected header and verifies that it contains the given key management and content encryption algorithms
*/
export declare function isMessageJWEEncrypted(message: string, algorithm: string, encoding: string): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encryptObjectWithKey = exports.readEncryptionDetails = exports.validateEncryptionDetails = exports.shouldWaitForEncryptionKey = void 0;
exports.isMessageJWEEncrypted = exports.encryptObjectWithKey = exports.readEncryptionDetails = exports.validateEncryptionDetails = exports.shouldWaitForEncryptionKey = void 0;
const jose_1 = require("jose");

@@ -67,8 +67,46 @@ function shouldWaitForEncryptionKey() {

*/
function encryptObjectWithKey(request, key) {
function encryptObjectWithKey(request, key, alg, enc) {
const payload = new TextEncoder().encode(JSON.stringify(request));
const keyBuffer = Buffer.from(key, 'base64');
return new jose_1.CompactEncrypt(payload).setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }).encrypt(keyBuffer);
return new jose_1.CompactEncrypt(payload)
.setProtectedHeader({ alg: alg !== null && alg !== void 0 ? alg : 'dir', enc: enc !== null && enc !== void 0 ? enc : 'A256GCM' })
.encrypt(keyBuffer);
}
exports.encryptObjectWithKey = encryptObjectWithKey;
/**
* Check if a message is an encrypted JWE message with the provided key management algorithm and encoding
* As per RFC-7516:
* When using the JWE Compact Serialization, the
* JWE Protected Header, the JWE Encrypted Key, the JWE
* Initialization Vector, the JWE Ciphertext, and the JWE
* Authentication Tag are represented as base64url-encoded values
* in that order, with each value being separated from the next by
* a single period ('.') character, resulting in exactly four
* delimiting period characters being used
* This function checks if the payload is separated by 4 periods and
* Decodes the protected header and verifies that it contains the given key management and content encryption algorithms
*/
function isMessageJWEEncrypted(message, algorithm, encoding) {
// Check if the message has five parts separated by periods
const parts = message.split('.');
if (parts.length !== 5) {
return false;
}
try {
// Decode the protected header (first part of the message)
const protectedHeader = JSON.parse(Buffer.from(parts[0], 'base64url').toString('utf-8'));
// Check if the header contains the expected fields
if (protectedHeader.alg &&
protectedHeader.enc &&
protectedHeader.alg == algorithm &&
protectedHeader.enc == encoding) {
return true;
}
}
catch (e) {
return false;
}
return false;
}
exports.isMessageJWEEncrypted = isMessageJWEEncrypted;
//# sourceMappingURL=encryption.js.map

@@ -104,2 +104,43 @@ "use strict";

});
describe('isMessageJWEEncrypted', () => {
it('should return false if the message does not have 5 parts separated by periods', () => {
const message = 'part1.part2.part3.part4';
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return false if the protected header is not valid base64url', () => {
const message = 'invalid..part2.part3.part4.part5';
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return false if the protected header is not a valid JSON', () => {
const message = 'aW52YWxpZA==.part2.part3.part4.part5'; // "invalid" in base64url
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return false if the protected header does not contain the expected fields', () => {
const header = Buffer.from(JSON.stringify({ wrongField: 'value' })).toString('base64url');
const message = `${header}.part2.part3.part4.part5`;
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return false if the protected header contains wrong algorithm', () => {
const header = Buffer.from(JSON.stringify({ alg: 'wrongAlg', enc: 'enc' })).toString('base64url');
const message = `${header}.part2.part3.part4.part5`;
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return false if the protected header contains wrong encoding', () => {
const header = Buffer.from(JSON.stringify({ alg: 'alg', enc: 'wrongEnc' })).toString('base64url');
const message = `${header}.part2.part3.part4.part5`;
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, false);
});
it('should return true if the protected header contains the expected algorithm and encoding', () => {
const header = Buffer.from(JSON.stringify({ alg: 'alg', enc: 'enc' })).toString('base64url');
const message = `${header}.part2.part3.part4.part5`;
const result = (0, encryption_1.isMessageJWEEncrypted)(message, 'alg', 'enc');
assert_1.default.strictEqual(result, true);
});
});
//# sourceMappingURL=encryption.test.js.map
import { Connection } from 'vscode-languageserver';
import { ChatParams, ChatResult, EndChatParams, FeedbackParams, FollowUpClickParams, InfoLinkClickParams, InsertToCursorPositionParams, LinkClickParams, NotificationHandler, QuickActionParams, QuickActionResult, RequestHandler, SourceLinkClickParams, TabAddParams, TabChangeParams, TabRemoveParams } from '../../protocol';
import { Chat } from '../../server-interface';
import { CredentialsEncoding } from '../auth/standalone/encryption';
export declare class EncryptedChat implements Chat {
private readonly connection;
import { ChatParams, ChatResult, QuickActionParams, QuickActionResult, RequestHandler } from '../../protocol';
import { BaseChat } from './baseChat';
export declare class EncryptedChat extends BaseChat {
private key;
private encoding;
constructor(connection: Connection, key: string, encoding?: CredentialsEncoding);
private encoding?;
private keyBuffer;
constructor(connection: Connection, key: string, encoding?: "JWT" | undefined);
onChatPrompt(handler: RequestHandler<ChatParams, ChatResult | null | undefined, ChatResult>): void;
onQuickAction(handler: RequestHandler<QuickActionParams, QuickActionResult, void>): void;
onEndChat(handler: RequestHandler<EndChatParams, boolean, void>): import("vscode-languageserver").Disposable;
onSendFeedback(handler: NotificationHandler<FeedbackParams>): void;
onReady(handler: NotificationHandler<void>): void;
onTabAdd(handler: NotificationHandler<TabAddParams>): void;
onTabChange(handler: NotificationHandler<TabChangeParams>): void;
onTabRemove(handler: NotificationHandler<TabRemoveParams>): void;
onCodeInsertToCursorPosition(handler: NotificationHandler<InsertToCursorPositionParams>): void;
onLinkClick(handler: NotificationHandler<LinkClickParams>): void;
onInfoLinkClick(handler: NotificationHandler<InfoLinkClickParams>): void;
onSourceLinkClick(handler: NotificationHandler<SourceLinkClickParams>): void;
onFollowUpClicked(handler: NotificationHandler<FollowUpClickParams>): void;
private registerEncryptedRequestHandler;
private instanceOfEncryptedParams;
private decodeRequest;
private encryptObject;
}

@@ -15,75 +15,58 @@ "use strict";

const protocol_1 = require("../../protocol");
class EncryptedChat {
const encryption_1 = require("../auth/standalone/encryption");
const baseChat_1 = require("./baseChat");
// Default JWE configuration
const KEY_MANAGEMENT_ALGORITHM = 'dir';
const CONTENT_ENCRYPTION_ALGORITHM = 'A256GCM';
class EncryptedChat extends baseChat_1.BaseChat {
constructor(connection, key, encoding) {
this.connection = connection;
this.key = Buffer.from(key, 'base64');
super(connection);
this.key = key;
this.encoding = encoding;
this.keyBuffer = Buffer.from(key, 'base64');
}
onChatPrompt(handler) {
this.connection.onRequest(protocol_1.chatRequestType, (request, cancellationToken) => __awaiter(this, void 0, void 0, function* () {
request = request;
// decrypt the request params
let decryptedRequest = (yield this.decodeRequest(request));
// make sure we don't lose the partial result token
if (request.partialResultToken) {
decryptedRequest.partialResultToken = request.partialResultToken;
}
// call the handler with plaintext
const response = (yield handler(decryptedRequest, cancellationToken));
// encrypt the response
const encryptedResponse = yield this.encryptObject(response);
// send it back
return encryptedResponse;
}));
this.registerEncryptedRequestHandler(protocol_1.chatRequestType, handler);
}
onQuickAction(handler) {
this.connection.onRequest(protocol_1.quickActionRequestType, (request, cancellationToken) => __awaiter(this, void 0, void 0, function* () {
request = request;
// decrypt the request params
let decryptedRequest = (yield this.decodeRequest(request));
// make sure we don't lose the partial result token
if (request.partialResultToken) {
decryptedRequest.partialResultToken = request.partialResultToken;
this.registerEncryptedRequestHandler(protocol_1.quickActionRequestType, handler);
}
registerEncryptedRequestHandler(requestType, handler) {
this.connection.onRequest(requestType, (request, cancellationToken) => __awaiter(this, void 0, void 0, function* () {
// Verify the request is encrypted as expected
if (this.instanceOfEncryptedParams(request)) {
// Decrypt request
let decryptedRequest;
try {
decryptedRequest = yield this.decodeRequest(request);
}
catch (err) {
let errorMessage = 'Request could not be decrypted';
if (err instanceof Error)
errorMessage = err.message;
return new protocol_1.ResponseError(protocol_1.LSPErrorCodes.ServerCancelled, errorMessage);
}
// Preserve the partial result token
if (request.partialResultToken) {
decryptedRequest.partialResultToken = request.partialResultToken;
}
// Call the handler with decrypted params
const response = yield handler(decryptedRequest, cancellationToken);
// If response is null or undefined, return it as is
if (!response) {
return response;
}
// Encrypt the response and return it
const encryptedResponse = yield (0, encryption_1.encryptObjectWithKey)(response, this.key, KEY_MANAGEMENT_ALGORITHM, CONTENT_ENCRYPTION_ALGORITHM);
return encryptedResponse;
}
// call the handler with plaintext
const response = (yield handler(decryptedRequest, cancellationToken));
// encrypt the response
const encryptedResponse = yield this.encryptObject(response);
// send it back
return encryptedResponse;
return new protocol_1.ResponseError(protocol_1.LSPErrorCodes.ServerCancelled, 'The request was not encrypted correctly');
}));
}
onEndChat(handler) {
return this.connection.onRequest(protocol_1.endChatRequestType, handler);
instanceOfEncryptedParams(object) {
if ('message' in object && typeof object['message'] === `string`) {
return (0, encryption_1.isMessageJWEEncrypted)(object.message, KEY_MANAGEMENT_ALGORITHM, CONTENT_ENCRYPTION_ALGORITHM);
}
return false;
}
onSendFeedback(handler) {
this.connection.onNotification(protocol_1.feedbackNotificationType.method, handler);
}
onReady(handler) {
this.connection.onNotification(protocol_1.readyNotificationType.method, handler);
}
onTabAdd(handler) {
this.connection.onNotification(protocol_1.tabAddNotificationType.method, handler);
}
onTabChange(handler) {
this.connection.onNotification(protocol_1.tabChangeNotificationType.method, handler);
}
onTabRemove(handler) {
this.connection.onNotification(protocol_1.tabRemoveNotificationType.method, handler);
}
onCodeInsertToCursorPosition(handler) {
this.connection.onNotification(protocol_1.insertToCursorPositionNotificationType.method, handler);
}
onLinkClick(handler) {
this.connection.onNotification(protocol_1.linkClickNotificationType.method, handler);
}
onInfoLinkClick(handler) {
this.connection.onNotification(protocol_1.infoLinkClickNotificationType.method, handler);
}
onSourceLinkClick(handler) {
this.connection.onNotification(protocol_1.sourceLinkClickNotificationType.method, handler);
}
onFollowUpClicked(handler) {
this.connection.onNotification(protocol_1.followUpClickNotificationType.method, handler);
}
decodeRequest(request) {

@@ -95,6 +78,6 @@ return __awaiter(this, void 0, void 0, function* () {

if (this.encoding === 'JWT') {
const result = yield (0, jose_1.jwtDecrypt)(request.message, this.key, {
clockTolerance: 60, // Allow up to 60 seconds to account for clock differences
contentEncryptionAlgorithms: ['A256GCM'],
keyManagementAlgorithms: ['dir'],
const result = yield (0, jose_1.jwtDecrypt)(request.message, this.keyBuffer, {
clockTolerance: 60,
contentEncryptionAlgorithms: [CONTENT_ENCRYPTION_ALGORITHM],
keyManagementAlgorithms: [KEY_MANAGEMENT_ALGORITHM],
});

@@ -109,12 +92,4 @@ if (!result.payload) {

}
encryptObject(object) {
return __awaiter(this, void 0, void 0, function* () {
const encryptedJWT = yield new jose_1.EncryptJWT(object)
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(this.key);
return encryptedJWT;
});
}
}
exports.EncryptedChat = EncryptedChat;
//# sourceMappingURL=encryptedChat.js.map

@@ -50,2 +50,3 @@ "use strict";

const lspServer_1 = require("./lsp/router/lspServer");
const baseChat_1 = require("./chat/baseChat");
/**

@@ -213,17 +214,3 @@ * The runtime for standalone LSP-based servers.

if (!encryptionKey) {
chat = {
onChatPrompt: handler => lspConnection.onRequest(protocol_1.chatRequestType.method, handler),
onEndChat: handler => lspConnection.onRequest(protocol_1.endChatRequestType.method, handler),
onQuickAction: handler => lspConnection.onRequest(protocol_1.quickActionRequestType.method, handler),
onSendFeedback: handler => lspConnection.onNotification(protocol_1.feedbackNotificationType.method, handler),
onReady: handler => lspConnection.onNotification(protocol_1.readyNotificationType.method, handler),
onTabAdd: handler => lspConnection.onNotification(protocol_1.tabAddNotificationType.method, handler),
onTabChange: handler => lspConnection.onNotification(protocol_1.tabChangeNotificationType.method, handler),
onTabRemove: handler => lspConnection.onNotification(protocol_1.tabRemoveNotificationType.method, handler),
onCodeInsertToCursorPosition: handler => lspConnection.onNotification(protocol_1.insertToCursorPositionNotificationType.method, handler),
onLinkClick: handler => lspConnection.onNotification(protocol_1.linkClickNotificationType.method, handler),
onInfoLinkClick: handler => lspConnection.onNotification(protocol_1.infoLinkClickNotificationType.method, handler),
onSourceLinkClick: handler => lspConnection.onNotification(protocol_1.sourceLinkClickNotificationType.method, handler),
onFollowUpClicked: handler => lspConnection.onNotification(protocol_1.followUpClickNotificationType.method, handler),
};
chat = new baseChat_1.BaseChat(lspConnection);
}

@@ -230,0 +217,0 @@ return s({ chat, credentialsProvider, lsp, workspace, telemetry, logging });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc