mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 06:25:45 +01:00
Handle missing encoding of square brackets in filenames (#2117)
Due to unexpected and largely unchangeable behavior by both react-router and the browser, square brackets are not correctly encoded in the url when clicking a file link in the source view where the filename contains either of these characters. The source view then tries to use the useSources hook to get the file content but fails, because the path param for the file path it gets from the url has unencoded square brackets in them which are illegal in urls except for declaring IPv6 addresses. We have created a catch for exactly this scenario at the latest possible point before the actual http request is fired, which is in the useSources hook. It seems like the square brackets are the only affected special characters so we force encoding on them specifically. Only the path portion of the URL is checked so the host portion of the url may still contain unencoded square brackets which are left untouched.
This commit is contained in:
committed by
GitHub
parent
9ea76073b2
commit
61676c6dd4
@@ -124,6 +124,21 @@ describe("Test sources hooks", () => {
|
||||
};
|
||||
|
||||
describe("useSources tests", () => {
|
||||
const testPath = async (path: string, expectedPath: string) => {
|
||||
const queryClient = createInfiniteCachingClient();
|
||||
fetchMock.getOnce(`/api/v2/src/abc/${expectedPath}?collapse=true`, readmeMd);
|
||||
const { result, waitFor } = renderHook(() => useSources(puzzle42, { revision: "abc", path }), {
|
||||
wrapper: createWrapper(undefined, queryClient),
|
||||
});
|
||||
await waitFor(() => !!result.current.data);
|
||||
expect(result.current.data).toEqual(readmeMd);
|
||||
};
|
||||
|
||||
it("should return file from url with revision and path", () => testPath("README.md", "README.md"));
|
||||
it("should encode square brackets in path", () =>
|
||||
testPath("[...nextauth][...other].ts", "%5B...nextauth%5D%5B...other%5D.ts"));
|
||||
it("should not double-encode path", () => testPath("%7BDatei%7D#42.txt", "%7BDatei%7D#42.txt"));
|
||||
|
||||
it("should return root directory", async () => {
|
||||
const queryClient = createInfiniteCachingClient();
|
||||
fetchMock.getOnce("/api/v2/src?collapse=true", rootDirectory);
|
||||
@@ -134,16 +149,6 @@ describe("Test sources hooks", () => {
|
||||
expect(result.current.data).toEqual(rootDirectory);
|
||||
});
|
||||
|
||||
it("should return file from url with revision and path", async () => {
|
||||
const queryClient = createInfiniteCachingClient();
|
||||
fetchMock.getOnce("/api/v2/src/abc/README.md?collapse=true", readmeMd);
|
||||
const { result, waitFor } = renderHook(() => useSources(puzzle42, { revision: "abc", path: "README.md" }), {
|
||||
wrapper: createWrapper(undefined, queryClient),
|
||||
});
|
||||
await waitFor(() => !!result.current.data);
|
||||
expect(result.current.data).toEqual(readmeMd);
|
||||
});
|
||||
|
||||
it("should fetch next page", async () => {
|
||||
const queryClient = createInfiniteCachingClient();
|
||||
fetchMock.getOnce("/api/v2/src?collapse=true", mainDirectoryTruncated);
|
||||
|
||||
@@ -93,7 +93,7 @@ const createSourcesLink = (repository: Repository, options: UseSourcesOptions) =
|
||||
link = urls.concat(link, encodeURIComponent(options.revision));
|
||||
|
||||
if (options.path) {
|
||||
link = urls.concat(link, options.path);
|
||||
link = urls.concat(link, encodeInvalidCharacters(options.path));
|
||||
}
|
||||
}
|
||||
if (options.collapse) {
|
||||
@@ -102,6 +102,8 @@ const createSourcesLink = (repository: Repository, options: UseSourcesOptions) =
|
||||
return link;
|
||||
};
|
||||
|
||||
const encodeInvalidCharacters = (input: string) => input.replace(/\[/g, "%5B").replace(/]/g, "%5D");
|
||||
|
||||
const merge = (files?: File[]): File | undefined => {
|
||||
if (!files || files.length === 0) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user