diff --git a/src/node_dotenv.cc b/src/node_dotenv.cc index 9e0205b4e6249f..6e205b7f80eb56 100644 --- a/src/node_dotenv.cc +++ b/src/node_dotenv.cc @@ -151,7 +151,17 @@ void Dotenv::ParseContent(const std::string_view input) { // Expand new line if \n it's inside double quotes // Example: EXPAND_NEWLINES = 'expand\nnew\nlines' if (content.front() == '"') { - auto closing_quote = content.find(content.front(), 1); + std::size_t closing_quote = 0; + do { + closing_quote = content.find(content.front(), closing_quote + 1); + if (closing_quote == std::string_view::npos) { + break; + } + if (closing_quote > 0 && content[closing_quote - 1] != '\\') { + break; + } + } while (closing_quote != std::string_view::npos); + if (closing_quote != std::string_view::npos) { value = content.substr(1, closing_quote - 1); std::string multi_line_value = std::string(value); @@ -163,6 +173,13 @@ void Dotenv::ParseContent(const std::string_view input) { pos += 1; } + pos = 0; + while ((pos = multi_line_value.find(R"(\")", pos)) != + std::string_view::npos) { + multi_line_value.replace(pos, 2, "\""); + pos += 1; + } + store_.insert_or_assign(std::string(key), multi_line_value); content.remove_prefix(content.find('\n', closing_quote + 1)); continue; diff --git a/test/fixtures/dotenv/valid.env b/test/fixtures/dotenv/valid.env index 120488d57917e0..c2ce0e7037e692 100644 --- a/test/fixtures/dotenv/valid.env +++ b/test/fixtures/dotenv/valid.env @@ -43,6 +43,9 @@ EMAIL=therealnerdybeast@example.tld SPACED_KEY = parsed EDGE_CASE_INLINE_COMMENTS="VALUE1" # or "VALUE2" or "VALUE3" +ALL_QUOTES="this 'has' all \"quotes\" in `value` and double quotes around" +ALL_QUOTES_EXPAND_NEWLINES="this\n'has'\nall\n\"quotes\"\nin\n`value`\nand\nmultilines\nto\nexpand" + MULTI_DOUBLE_QUOTED="THIS IS A diff --git a/test/parallel/test-dotenv.js b/test/parallel/test-dotenv.js index 3c81bf98782a97..f460daa81e5896 100644 --- a/test/parallel/test-dotenv.js +++ b/test/parallel/test-dotenv.js @@ -82,3 +82,6 @@ assert.strictEqual(process.env.DONT_EXPAND_SQUOTED, 'dontexpand\\nnewlines'); assert.strictEqual(process.env.EXPORT_EXAMPLE, 'ignore export'); // Ignore spaces before double quotes to avoid quoted strings as value assert.strictEqual(process.env.SPACE_BEFORE_DOUBLE_QUOTES, 'space before double quotes'); +assert.strictEqual(process.env.ALL_QUOTES, 'this \'has\' all "quotes" in `value` and double quotes around'); +assert.strictEqual(process.env.ALL_QUOTES_EXPAND_NEWLINES, 'this\n\'has\'\nall\n"quotes"\nin\n`value`\nand\nmultilines\nto\nexpand'); +