Skip to content

Commit

Permalink
fixes #63 string oob with ignore malformed (#74)
Browse files Browse the repository at this point in the history
Co-authored-by: carmine <carmine@everco.ai>
  • Loading branch information
cdimascio and carmine authored Sep 1, 2024
1 parent d216732 commit 4e23eda
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.0.1</version>
<version>3.0.2</version>

<licenses>
<license>
Expand Down
60 changes: 49 additions & 11 deletions src/main/java/io/github/cdimascio/dotenv/internal/DotenvParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ public class DotenvParser {
private final boolean throwIfMissing;
private final boolean throwIfMalformed;

private final Predicate<String> isWhiteSpace = s -> matches(WHITE_SPACE_REGEX, s);
private final Predicate<String> isComment = s -> s.startsWith("#") || s.startsWith("////");
private final Predicate<String> isQuoted = s -> s.startsWith("\"") && s.endsWith("\"");
private static final Predicate<String> isWhiteSpace = s -> matches(WHITE_SPACE_REGEX, s);
private static final Predicate<String> isComment = s -> s.startsWith("#") || s.startsWith("////");
private static final Predicate<String> isQuoted = s -> s.length() > 1 && s.startsWith("\"") && s.endsWith("\"");
private final Function<String, DotenvEntry> parseLine = s -> matchEntry(DOTENV_ENTRY_REGEX, s);

/**
* Creates a dotenv parser
* @param reader the dotenv reader
* @param throwIfMissing if true, throws when the .env file is missing
*
* @param reader the dotenv reader
* @param throwIfMissing if true, throws when the .env file is missing
* @param throwIfMalformed if true, throws when the .env file is malformed
*/
public DotenvParser(final DotenvReader reader, final boolean throwIfMissing, final boolean throwIfMalformed) {
Expand All @@ -53,6 +54,7 @@ public DotenvParser(final DotenvReader reader, final boolean throwIfMissing, fin

/**
* (Internal) parse the .env file
*
* @return a list of DotenvEntries
* @throws DotenvException if an error is encountered during the parse
*/
Expand All @@ -77,8 +79,13 @@ private void addNewEntry(final List<DotenvEntry> entries, final String line) {
return;
}

if (!QuotedStringValidator.isValid(entry.getValue())) {
if (throwIfMalformed)
throw new DotenvException("Malformed entry, unmatched quotes " + line);
return;
}
final var key = entry.getKey();
final var value = normalizeValue(entry.getValue());
final var value = QuotedStringValidator.stripQuotes(entry.getValue());
entries.add(new DotenvEntry(key, value));
}

Expand All @@ -94,11 +101,6 @@ private List<String> lines() throws DotenvException {
}
}

private String normalizeValue(final String value) {
final var tr = value.trim();
return isQuoted.test(tr) ? tr.substring(1, value.length() - 1) : tr;
}

private static boolean matches(final Pattern regex, final String text) {
return regex.matcher(text).matches();
}
Expand All @@ -114,4 +116,40 @@ private static DotenvEntry matchEntry(final Pattern regex, final String text) {
private static boolean isBlank(String s) {
return s == null || s.trim().isEmpty();
}

/**
* Internal: Validates quoted strings
*/
private static class QuotedStringValidator {
private static boolean isValid(String input) {
final var s = input.trim();
if (!s.startsWith("\"") && !s.endsWith("\"")) {
// not quoted, its valid
return true;
}
if (input.length() == 1 || !(s.startsWith("\"") && s.endsWith("\""))) {
// doesn't start and end with quote
return false;
}
// remove start end quote
var content = s.substring(1, s.length() - 1);
var quotePattern = Pattern.compile("\"");
var matcher = quotePattern.matcher(content);

// Check for unescaped quotes
while (matcher.find()) {
int quoteIndex = matcher.start();
// Check if the quote is escaped
if (quoteIndex == 0 || content.charAt(quoteIndex - 1) != '\\') {
return false; // unescaped quote found
}
}
return true; // No unescaped quotes found
}
private static String stripQuotes(String input) {
var tr = input.trim();
return isQuoted.test(tr) ? tr.substring(1, input.length() - 1) : tr;
}
}
}

12 changes: 12 additions & 0 deletions src/test/java/tests/DotenvTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,16 @@ void configureWithIgnoreMissingAndMalformed() {

assertNotNull(dotenv.get("PATH"));
}

@Test
void malformedWithUncloseQuote() {
final var dotenv = Dotenv.configure()
.directory("/unclosed.quote")
.ignoreIfMalformed()
.load();

assertNull(dotenv.get("FOO"));
assertEquals(dotenv.get("BAR"), "bar");
assertNull(dotenv.get("BAZ"), "baz");
}
}
3 changes: 3 additions & 0 deletions src/test/resources/unclosed.quote/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FOO="
BAR="bar"
BAZ="baz

0 comments on commit 4e23eda

Please sign in to comment.