Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gmail_api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.testsigma.addons</groupId>
<artifactId>gmailapi</artifactId>
<version>1.1.7</version>
<version>1.1.8</version>
<packaging>jar</packaging>

<properties>
Expand Down
107 changes: 107 additions & 0 deletions gmail_api/src/main/java/com/android/GetFilteredGmailContent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.android;

import com.testsigma.sdk.AndroidAction;
import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import com.testsigma.sdk.annotation.RunTimeData;
import com.testsigma.sdk.annotation.TestData;
import lombok.Data;
import utils.GmailUtils;

import javax.mail.*;
import javax.mail.search.SearchTerm;

@Data
@Action(actionText = "Get email content from Gmail using EmailID and Password " +
"filtered by filter-criteria with value filter-value and store it in a runtime variable var1",
description = "Get email content from Gmail filtered by From address, To address, or Subject " +
"and store it in a runtime variable",
applicationType = ApplicationType.ANDROID)
public class GetFilteredGmailContent extends AndroidAction {

@TestData(reference = "EmailID")
private com.testsigma.sdk.TestData EmailID;

@TestData(reference = "Password")
private com.testsigma.sdk.TestData Password;

@TestData(reference = "filter-criteria",
allowedValues = {"From", "To", "Subject"})
private com.testsigma.sdk.TestData filterCriteria;

@TestData(reference = "filter-value")
private com.testsigma.sdk.TestData filterValue;

@TestData(reference = "var1", isRuntimeVariable = true)
private com.testsigma.sdk.TestData var1;

@RunTimeData
private com.testsigma.sdk.RunTimeData runTimeData;

@Override
public Result execute() {
logger.info("Initiating execution");
String username = GmailUtils.sanitizeUsername(EmailID.getValue().toString());
String password = GmailUtils.sanitizePassword(Password.getValue().toString());
String criteria = filterCriteria.getValue().toString().trim();
String value = filterValue.getValue().toString().trim();

logger.info("username: " + username);
logger.info("Filter criteria: " + criteria + ", value: " + value);

Store store = null;
Folder inbox = null;
try {
store = GmailUtils.connectToGmail(username, password, logger);
inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);

SearchTerm searchTerm = GmailUtils.buildSearchTerm(criteria, value);
Message[] messages = inbox.search(searchTerm);
logger.info("Found " + messages.length + " messages matching filter: " + criteria + " = " + value);

if (messages.length == 0) {
setErrorMessage("No emails found in INBOX matching " + criteria + ": '" + value +
"'. Please verify the filter criteria and value are correct.");
return Result.FAILED;
}

Message latestMessage = messages[messages.length - 1];
logger.info("Subject: " + latestMessage.getSubject());

String fullMessage = GmailUtils.extractContent(latestMessage.getContent());

if (fullMessage == null || fullMessage.trim().isEmpty()) {
setErrorMessage("Email matching " + criteria + ": '" + value +
"' was found (Subject: " + latestMessage.getSubject() +
") but the email body is empty or could not be read.");
return Result.FAILED;
}

logger.info("Extracted content length: " + fullMessage.length());
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(fullMessage);
runTimeData.setKey(var1.getValue().toString());
setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
" (filtered by " + criteria + ": " + value + ")");
return Result.SUCCESS;

} catch (AuthenticationFailedException e) {
setErrorMessage("Gmail authentication failed for '" + username +
"'. Please verify: 1) App password is valid 2) 2-Step Verification is ON 3) IMAP is enabled in Gmail settings. Error: " + e.getMessage());
logger.warn("Authentication failed: " + e.getMessage());
return Result.FAILED;
} catch (IllegalArgumentException e) {
setErrorMessage(e.getMessage());
logger.warn(e.getMessage());
return Result.FAILED;
} catch (Exception e) {
setErrorMessage("Failed to retrieve email content. Error: " + e.getMessage());
logger.warn(e.getMessage());
return Result.FAILED;
} finally {
GmailUtils.closeQuietly(inbox, store);
}
}
}
104 changes: 37 additions & 67 deletions gmail_api/src/main/java/com/android/GetGmailContent.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@

import com.testsigma.sdk.AndroidAction;
import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.WebAction;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import com.testsigma.sdk.annotation.RunTimeData;
import com.testsigma.sdk.annotation.TestData;
import lombok.Data;
import utils.GmailUtils;

import javax.mail.*;
import java.util.Properties;

@Data
@Action(actionText = "Get complete email content from Gmail using EmailID and Password and store it in a runtime variable var1",
description = "Get complete email content from Gmail using EmailID and Password and store it in a runtime variable var1",
applicationType = ApplicationType.ANDROID)

public class GetGmailContent extends AndroidAction {

@TestData(reference = "EmailID")
Expand All @@ -28,85 +27,56 @@ public class GetGmailContent extends AndroidAction {
private com.testsigma.sdk.RunTimeData runTimeData;

@Override
public com.testsigma.sdk.Result execute() {

com.testsigma.sdk.Result result = com.testsigma.sdk.Result.SUCCESS;
public Result execute() {
logger.info("Initiating execution");
String host = "imap.gmail.com";
String port = "993";
String username = EmailID.getValue().toString();
String password = Password.getValue().toString();
String username = GmailUtils.sanitizeUsername(EmailID.getValue().toString());
String password = GmailUtils.sanitizePassword(Password.getValue().toString());
logger.info("username: " + username);
logger.info("password: " + password);
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
props.setProperty("mail.imaps.host", host);
props.setProperty("mail.imaps.port", port);
props.setProperty("mail.imaps.auth", "true");
props.setProperty("mail.imaps.starttls.enable", "true");
props.setProperty("mail.imap.ssl.protocols", "TLSv1.2");
props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

logger.info("properties fixed");
Store store = null;
Folder inbox = null;
try {

Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
logger.info("");

Store store = session.getStore("imaps");
store.connect(host, username, password);
logger.info("store ");
Folder inbox = store.getFolder("INBOX");
store = GmailUtils.connectToGmail(username, password, logger);
inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message[] messages = inbox.getMessages();
logger.info("messages: " + messages.length);

if (messages.length == 0) {
setErrorMessage("No emails found in the INBOX for '" + username + "'. The mailbox is empty.");
return Result.FAILED;
}

Message latestMessage = messages[messages.length - 1];
logger.info("latestMessage" + latestMessage.getContent());
Object content = latestMessage.getContent();
BodyPart bodyPart = null;
String FullMessage = null;
if (content instanceof String) {
System.out.println(content);
FullMessage = (String) content;
logger.info("latestMessage subject: " + latestMessage.getSubject());

} else if (content instanceof Multipart) {
// content is already a Multipart object, so just cast it and process the body part
Multipart multipart = (Multipart) content;
bodyPart = multipart.getBodyPart(0);
Object bodycontent = bodyPart.getContent();
if (bodycontent instanceof String) {
FullMessage = (String) bodycontent;
String fullMessage = GmailUtils.extractContent(latestMessage.getContent());

} else if (bodycontent instanceof Multipart) {
Multipart bodymultipart = (Multipart) bodycontent;
logger.info("Body content" + bodymultipart.getBodyPart(0).getContent());
logger.info("Body content type:" + bodymultipart.getContentType());
FullMessage = (String) bodymultipart.getBodyPart(0).getContent();
}
} else {
System.out.println("No content");
logger.info("NO CONTENT");
if (fullMessage == null || fullMessage.trim().isEmpty()) {
setErrorMessage("Latest email (Subject: " + latestMessage.getSubject() +
") was found but the email body is empty or could not be read.");
return Result.FAILED;
}

logger.info(FullMessage);
logger.info("Extracted content length: " + fullMessage.length());
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(FullMessage);
runTimeData.setValue(fullMessage);
runTimeData.setKey(var1.getValue().toString());
setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() + "and value: " + FullMessage);

inbox.close(false);
store.close();

setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
" and value: " + fullMessage);
return Result.SUCCESS;
Comment on lines +65 to +67
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not echo the full email body in the success message.

fullMessage is already stored in runTimeData. Repeating it here exposes the entire email in persisted step output, which is risky for a public Gmail addon.

🔒 Proposed fix
-            setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
-                    " and value: " + fullMessage);
+            setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString());
             return Result.SUCCESS;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString() +
" and value: " + fullMessage);
return Result.SUCCESS;
setSuccessMessage("Email content stored in runtime variable: " + var1.getValue().toString());
return Result.SUCCESS;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gmail_api/src/main/java/com/android/GetGmailContent.java` around lines 65 -
67, The success message currently includes the full email body via fullMessage,
which leaks sensitive content; update the setSuccessMessage call in
GetGmailContent (the code that constructs the message using setSuccessMessage,
var1.getValue().toString(), and fullMessage) to remove fullMessage from the
output and only reference the runtime variable name (e.g.,
var1.getValue().toString()) or a non-sensitive placeholder (e.g., "email stored
in runtime variable") so the actual email body is not echoed in persisted step
output.


} catch (AuthenticationFailedException e) {
setErrorMessage("Gmail authentication failed for '" + username +
"'. Please verify: 1) App password is valid 2) 2-Step Verification is ON 3) IMAP is enabled in Gmail settings. Error: " + e.getMessage());
logger.warn("Authentication failed: " + e.getMessage());
return Result.FAILED;
} catch (Exception e) {

result = com.testsigma.sdk.Result.FAILED;
setErrorMessage("Could not retrieve the email content. The error is " + e.getMessage());
setErrorMessage("Failed to retrieve email content. Error: " + e.getMessage());
logger.warn(e.getMessage());
return Result.FAILED;
} finally {
GmailUtils.closeQuietly(inbox, store);
}
return result;
}
}
}
133 changes: 133 additions & 0 deletions gmail_api/src/main/java/com/android/GetGmailContentByRegex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.android;

import com.testsigma.sdk.AndroidAction;
import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import com.testsigma.sdk.annotation.RunTimeData;
import com.testsigma.sdk.annotation.TestData;
import lombok.Data;
import utils.GmailUtils;

import javax.mail.*;
import javax.mail.search.SearchTerm;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Data
@Action(actionText = "Get email content from Gmail using EmailID and Password " +
"filtered by filter-criteria with value filter-value " +
"and extract matching content using regex-pattern and store it in a runtime variable var1",
description = "Get email content from Gmail filtered by From address, To address, or Subject, " +
"then extract the portion matching the given regex pattern and store it in a runtime variable",
applicationType = ApplicationType.ANDROID)
public class GetGmailContentByRegex extends AndroidAction {

@TestData(reference = "EmailID")
private com.testsigma.sdk.TestData EmailID;

@TestData(reference = "Password")
private com.testsigma.sdk.TestData Password;

@TestData(reference = "filter-criteria",
allowedValues = {"From", "To", "Subject"})
private com.testsigma.sdk.TestData filterCriteria;

@TestData(reference = "filter-value")
private com.testsigma.sdk.TestData filterValue;

@TestData(reference = "regex-pattern")
private com.testsigma.sdk.TestData regexPattern;

@TestData(reference = "var1", isRuntimeVariable = true)
private com.testsigma.sdk.TestData var1;

@RunTimeData
private com.testsigma.sdk.RunTimeData runTimeData;

@Override
public Result execute() {
logger.info("Initiating execution");
String username = GmailUtils.sanitizeUsername(EmailID.getValue().toString());
String password = GmailUtils.sanitizePassword(Password.getValue().toString());
String criteria = filterCriteria.getValue().toString().trim();
String value = filterValue.getValue().toString().trim();
String regex = regexPattern.getValue().toString();

logger.info("username: " + username);
logger.info("Filter criteria: " + criteria + ", value: " + value);
logger.info("Regex pattern: " + regex);

Store store = null;
Folder inbox = null;
try {
store = GmailUtils.connectToGmail(username, password, logger);
inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);

SearchTerm searchTerm = GmailUtils.buildSearchTerm(criteria, value);
Message[] messages = inbox.search(searchTerm);
logger.info("Found " + messages.length + " messages matching filter: " + criteria + " = " + value);

if (messages.length == 0) {
setErrorMessage("No emails found in INBOX matching " + criteria + ": '" + value +
"'. Please verify the filter criteria and value are correct.");
return Result.FAILED;
}

Message latestMessage = messages[messages.length - 1];
logger.info("Subject: " + latestMessage.getSubject());

String fullMessage = GmailUtils.extractContent(latestMessage.getContent());

if (fullMessage == null || fullMessage.trim().isEmpty()) {
setErrorMessage("Email matching " + criteria + ": '" + value +
"' was found (Subject: " + latestMessage.getSubject() +
") but the email body is empty or could not be read.");
return Result.FAILED;
}

logger.info("Extracted content length: " + fullMessage.length());

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(fullMessage);

if (matcher.find()) {
String matchedContent = matcher.group(0);
logger.info("Regex matched: " + matchedContent);

runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
", value: " + matchedContent);
Comment on lines +96 to +103
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep the extracted regex match out of logs and success output.

The match is usually the secret the caller wanted to capture. Logging it and echoing it in the success text leaks OTPs/tokens outside the runtime variable channel.

🔒 Proposed fix
                 String matchedContent = matcher.group(0);
-                logger.info("Regex matched: " + matchedContent);
+                logger.info("Regex match found. Length: " + matchedContent.length());

                 runTimeData = new com.testsigma.sdk.RunTimeData();
                 runTimeData.setValue(matchedContent);
                 runTimeData.setKey(var1.getValue().toString());
-                setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
-                        ", value: " + matchedContent);
+                setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString());
                 return Result.SUCCESS;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String matchedContent = matcher.group(0);
logger.info("Regex matched: " + matchedContent);
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString() +
", value: " + matchedContent);
String matchedContent = matcher.group(0);
logger.info("Regex match found. Length: " + matchedContent.length());
runTimeData = new com.testsigma.sdk.RunTimeData();
runTimeData.setValue(matchedContent);
runTimeData.setKey(var1.getValue().toString());
setSuccessMessage("Matched content stored in variable: " + var1.getValue().toString());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gmail_api/src/main/java/com/android/GetGmailContentByRegex.java` around lines
96 - 103, The code currently logs and echoes the sensitive regex match
(matchedContent) via logger.info and setSuccessMessage; remove the secret from
logs and success output: keep extracting matcher.group(0) and storing it in
runTimeData.setValue(matchedContent) and
runTimeData.setKey(var1.getValue().toString()), but change the logger.info call
to not include matchedContent (e.g., log a generic "Regex matched" or include
only non-sensitive metadata) and update setSuccessMessage to only mention the
target variable name (var1.getValue().toString()) without appending the
matchedContent; ensure no other references to matchedContent are logged or
returned.

return Result.SUCCESS;
} else {
setErrorMessage("Email found (Subject: " + latestMessage.getSubject() +
") but no content matching regex '" + regex +
"' was found in the email body. Body length: " + fullMessage.length() + " chars.");
return Result.FAILED;
}

} catch (java.util.regex.PatternSyntaxException e) {
setErrorMessage("Invalid regex pattern '" + regex + "': " + e.getMessage());
logger.warn("Invalid regex: " + e.getMessage());
return Result.FAILED;
} catch (AuthenticationFailedException e) {
setErrorMessage("Gmail authentication failed for '" + username +
"'. Please verify: 1) App password is valid 2) 2-Step Verification is ON 3) IMAP is enabled in Gmail settings. Error: " + e.getMessage());
logger.warn("Authentication failed: " + e.getMessage());
return Result.FAILED;
} catch (IllegalArgumentException e) {
setErrorMessage(e.getMessage());
logger.warn(e.getMessage());
return Result.FAILED;
} catch (Exception e) {
setErrorMessage("Failed to retrieve email content. Error: " + e.getMessage());
logger.warn(e.getMessage());
return Result.FAILED;
} finally {
GmailUtils.closeQuietly(inbox, store);
}
}
}
Loading