Skip to content

Commit 8113dfe

Browse files
committed
fix: add security detection for exist HTML files
1 parent ce397d2 commit 8113dfe

File tree

6 files changed

+94
-6
lines changed

6 files changed

+94
-6
lines changed

src/template.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function fetchTemplateHTML(entry: EntryPath, pageConfig: PagePluginConfig
6363
},
6464
entry.__options.ejsOption
6565
);
66-
const generatedHtml = htmlContent.replace(
66+
const generatedHtml = "<!--This is generated by vite-plugin-auto-mpa-html.-->".concat(htmlContent).replace(
6767
"</html>",
6868
`<script type="module" src="./${entry.__options.entryName}"></script></html>`
6969
);
@@ -88,6 +88,10 @@ export function prepareTempEntries(
8888
throw new Error(`Page entry: ${entry.abs}, its config (config.json) cannot be found, please check!`)
8989
}
9090
const generatedHtml = fetchTemplateHTML(entry, pageData)
91+
if (existsSync(entry.abs + "/" + entry.__options.templateName)) {
92+
console.error(`There is a same name HTML file already exist in entry '${entry.value}', template generation skipped`)
93+
return;
94+
}
9195
writeFileSync(entry.abs + "/" + entry.__options.templateName, generatedHtml, {
9296
encoding: "utf-8",
9397
});
@@ -102,7 +106,9 @@ export function cleanTempEntries(
102106
entries.forEach(k => {
103107
// generate temp entries for build
104108
const absTemplatePath = k.abs + "/" + k.__options.templateName
105-
if (existsSync(absTemplatePath))
106-
unlinkSync(absTemplatePath);
109+
if (existsSync(absTemplatePath)) {
110+
const tmp = readFileSync(absTemplatePath, { encoding: "utf-8" })
111+
if (tmp.startsWith("<!--This is generated by vite-plugin-auto-mpa-html.-->")) unlinkSync(absTemplatePath);
112+
}
107113
});
108114
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useState } from 'react'
2+
import '../App.css'
3+
4+
function App() {
5+
const [count, setCount] = useState(0)
6+
7+
return (
8+
<div className="App">
9+
<div>
10+
<a href="https://vitejs.dev" target="_blank">
11+
Vite
12+
</a>
13+
<a href="https://reactjs.org" target="_blank">
14+
React
15+
</a>
16+
</div>
17+
<h1>Vite + React</h1>
18+
<div className="card">
19+
<button onClick={() => setCount((count) => count + 1)}>
20+
count is {count}
21+
</button>
22+
<p>
23+
Edit <code>src/App.jsx</code> and save to test HMR
24+
</p>
25+
</div>
26+
<p className="read-the-docs">
27+
Click on the Vite and React logos to learn more
28+
</p>
29+
</div>
30+
)
31+
}
32+
33+
export default App
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"template": "../../templates/tpl.html",
3+
"data": {
4+
"title": "Something else that not match tpl's title"
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>This is an exist HTML</title>
8+
</head>
9+
<body>
10+
11+
</body>
12+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react'
2+
import ReactDOM from 'react-dom/client'
3+
import App from './App'
4+
5+
ReactDOM.createRoot(document.getElementById('root')).render(
6+
<React.StrictMode>
7+
<App />
8+
</React.StrictMode>,
9+
)

tests/vite-lifecycles.test.ts

+25-3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ describe("Test plugin's lifecycle - buildStart", () => {
5555
); // contain needed entry module
5656
});
5757

58+
// TODO:
59+
it("when template is exist in target path, should not be overwritten", () => {
60+
// Do a generation
61+
const filePath = path.join(__dirname, "example", "src", "exist-template", "index.html");
62+
const configPath = path.join(__dirname, "example", "src", "exist-template", "config.json");
63+
const configData = fs.readFileSync(configPath, { encoding: "utf-8" });
64+
expect(fs.existsSync(filePath)).toBe(true); // temporary generated an entry HTML for build
65+
const fileContent = fs.readFileSync(filePath, { encoding: "utf-8" });
66+
expect(fileContent).toMatch("</html>"); // correctly end html doc.
67+
expect(fileContent).toMatch(
68+
`<title>This is an exist HTML</title>`
69+
); // correctly render ejs template with given data
70+
});
71+
5872
// Skip EJS Option tests
5973
});
6074

@@ -68,8 +82,16 @@ describe("Test plugin's lifecycle - buildEnd", () => {
6882
})
6983

7084
it("temporary entries should be cleaned after calling `cleanTempEntries`", () => {
71-
entries.entries.forEach((key) => {
72-
expect(fs.existsSync(path.resolve(key.abs + "/" + key.__options.templateName))).toBe(false);
73-
});
85+
const example = entries.entries.find(key => key.value === 'subdir')
86+
expect(example).not.toBeUndefined()
87+
if(example === undefined) return;
88+
expect(fs.existsSync(path.resolve(example.abs + "/" + example.__options.templateName))).toBe(false);
89+
});
90+
91+
// TODO:
92+
it("template is not generated by plugin, should not be cleaned", () => {
93+
// Do a generation
94+
const filePath = path.join(__dirname, "example", "src", "exist-template", "index.html");
95+
expect(fs.existsSync(filePath)).toBe(true); // temporary generated an entry HTML for build
7496
});
7597
});

0 commit comments

Comments
 (0)