Skip to content

ChatSession does not validate that connect() has been invoked before allowing invocation of other methods #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
marcogrcr opened this issue Feb 25, 2023 · 0 comments · Fixed by #186

Comments

@marcogrcr
Copy link
Contributor

Steps to reproduce:

import "amazon-connect-chatjs"; // v1.3.1
import {
  ConnectClient,
  StartChatContactCommand,
} from "@aws-sdk/client-connect"; // v3.254.0

// start a chat contact
const client = new ConnectClient({
  region: "us-east-1",
  credentials: {
    accessKeyId: "...",
    secretAccessKey: "...",
    sessionToken: "...",
  },
});

const { ContactId, ParticipantId, ParticipantToken } = await client.send(
  new StartChatContactCommand({
    InstanceId: "...",
    ContactFlowId: "...",
    ParticipantDetails: { DisplayName: "Customer" },
  })
);

// create chat session
const session = connect.ChatSession.create({
  chatDetails: {
    contactId: ContactId,
    participantId: ParticipantId,
    participantToken: ParticipantToken,
  },
  options: { region: "us-east-1" },
  type: connect.ChatSession.SessionTypes.CUSTOMER,
});

// get chat details
session.getChatDetails();

// download an attachment
try {
  await session.downloadAttachment({
    attachmentId: "some-id",
  });
} catch (e) {
  console.error(e);
}

// get the chat transcript
try {
  await session.getTranscript({});
} catch (e) {
  console.error(e);
}

// send an attachment
try {
  await session.sendAttachment({
    attachment: new File(["Hello World!"], "hello.txt"),
  });
} catch (e) {
  console.error(e);
}

// send typing event
try {
  await session.sendEvent({
    contentType: "application/vnd.amazonaws.connect.event.typing",
  });
} catch (e) {
  console.error(e);
}

// send a message
try {
  await session.sendMessage({
    contentType: "text/plain",
    message: "Hello World!",
  });
} catch (e) {
  console.error(e);
}

Expected result:

All the try/catch blocks after the session.getChatDetails() invocation fail with an Error indicating that the session.connect() method must be invoked first.

Alternatively, the first try/catch block implicitly invokes the connect() method.

Actual result:

All the try/catch blocks after the session.getChatDetails() invocation fail with the following Error:

TypeError: Cannot read properties of undefined (reading 'getConnectionToken')

Analysis:

The failure is because each of these methods invoke this.connectionHelper.getConnectionToken() in ChatController:

downloadAttachment(args){
const startTime = new Date().getTime();
const metadata = args.metadata || null;
const connectionToken = this.connectionHelper.getConnectionToken();

getTranscript(inputArgs) {
const startTime = new Date().getTime();
const metadata = inputArgs.metadata || null;
const args = {
startPosition: inputArgs.startPosition || {},
scanDirection: inputArgs.scanDirection || TRANSCRIPT_DEFAULT_PARAMS.SCAN_DIRECTION,
sortOrder: inputArgs.sortOrder || TRANSCRIPT_DEFAULT_PARAMS.SORT_ORDER,
maxResults: inputArgs.maxResults || TRANSCRIPT_DEFAULT_PARAMS.MAX_RESULTS,
};
if (inputArgs.nextToken) {
args.nextToken = inputArgs.nextToken;
}
if (inputArgs.contactId) {
args.contactId = inputArgs.contactId;
}
const connectionToken = this.connectionHelper.getConnectionToken();

sendAttachment(args){
const startTime = new Date().getTime();
const metadata = args.metadata || null;
//TODO: validation
const connectionToken = this.connectionHelper.getConnectionToken();

sendEvent(args) {
const startTime = new Date().getTime();
const metadata = args.metadata || null;
this.argsValidator.validateSendEvent(args);
const connectionToken = this.connectionHelper.getConnectionToken();

sendMessage(args) {
const startTime = new Date().getTime();
const metadata = args.metadata || null;
this.argsValidator.validateSendMessage(args);
const connectionToken = this.connectionHelper.getConnectionToken();

However, this.connectionHelper is initialized in ChatController.prototype.connect():

connect(args={}) {
this.sessionMetadata = args.metadata || null;
this.argsValidator.validateConnectChat(args);
const connectionDetailsProvider = this._getConnectionDetailsProvider();
return connectionDetailsProvider.fetchConnectionDetails()
.then(
(connectionDetails) =>
this._initConnectionHelper(connectionDetailsProvider, connectionDetails)

_initConnectionHelper(connectionDetailsProvider, connectionDetails) {
this.connectionHelper = new LpcConnectionHelper(
this.contactId,
this.initialContactId,
connectionDetailsProvider,
this.websocketManager,
this.logMetaData,
connectionDetails
);

This error is confusing for users, since they don't know the reason for failure is because the connect() method must be called first.

Proposed fix:

Similarly to #126, add a field in ChatController that indicates whether the connect() method has been successfully invoked and validate it on each method that internally uses this.connectionHelper.getConnectionToken().

@spencerlepine spencerlepine added the ⌛️ Needs Triage Needs team review label Apr 27, 2023
@spencerlepine spencerlepine added 🗒️ In Backlog Reviewed by team, added to backlog and removed ⌛️ Needs Triage Needs team review labels May 19, 2023
@spencerlepine spencerlepine removed the 🗒️ In Backlog Reviewed by team, added to backlog label Aug 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants