Skip to content

Commit 7863f59

Browse files
committed
fix(react-router-serve): serve /.well-known files
Express 5's static middleware ignores every dot-segment path by default (send v1 dropped send v0's allowance for dot directories), so RFC 8615 well-known URIs — ACME challenges, Android's assetlinks.json, Apple's apple-app-site-association — fell through to the request handler and came back as app-rendered HTML instead of the static file. Mount the .well-known directory of the client build explicitly; other dotfiles remain hidden.
1 parent d2f1f1b commit 7863f59

4 files changed

Lines changed: 48 additions & 0 deletions

File tree

contributors.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
- KimHyeongRae0
252252
- kirillgroshkov
253253
- kkirsche
254+
- kklem0
254255
- kno-raziel
255256
- knownasilya
256257
- koojaa

integration/react-router-serve-test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,46 @@ test.describe("react-router-serve", () => {
8181
});
8282
});
8383
}
84+
85+
test.describe("well-known URIs", () => {
86+
for (const templateName of templateNames) {
87+
test.describe(`template: ${templateName}`, () => {
88+
let fixture: Fixture;
89+
let appFixture: AppFixture;
90+
91+
test.beforeAll(async () => {
92+
fixture = await createFixture({
93+
templateName,
94+
useReactRouterServe: true,
95+
files: {
96+
"public/.well-known/security.txt":
97+
"Contact: mailto:security@example.com",
98+
"public/.hidden.txt": "should not be served",
99+
},
100+
});
101+
appFixture = await createAppFixture(fixture);
102+
});
103+
104+
test.afterAll(() => {
105+
appFixture.close();
106+
});
107+
108+
test("serves files under /.well-known", async () => {
109+
let response = await fetch(
110+
`${appFixture.serverUrl}/.well-known/security.txt`,
111+
);
112+
expect(response.status).toBe(200);
113+
expect(await response.text()).toContain(
114+
"Contact: mailto:security@example.com",
115+
);
116+
});
117+
118+
test("keeps other dotfiles hidden", async () => {
119+
let response = await fetch(`${appFixture.serverUrl}/.hidden.txt`);
120+
expect(response.status).toBe(404);
121+
expect(await response.text()).not.toContain("should not be served");
122+
});
123+
});
124+
}
125+
});
84126
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Serve `/.well-known/*` files from the client build directory. Express 5's static middleware ignores every dot-segment path by default, so RFC 8615 well-known URIs — ACME challenges, Android's `assetlinks.json`, Apple's `apple-app-site-association` — fell through to the request handler and came back as app-rendered HTML instead of the static file. Other dotfiles remain hidden.

packages/react-router-serve/cli.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ async function run() {
206206
);
207207
app.use(expressPublicPath, express.static(build.assetsBuildDirectory));
208208
app.use(express.static("public", { maxAge: "1h" }));
209+
app.use(
210+
"/.well-known",
211+
express.static(path.join(build.assetsBuildDirectory, ".well-known")),
212+
);
209213
app.use(morgan("tiny"));
210214

211215
if (build.fetch) {

0 commit comments

Comments
 (0)