WeavingAdaptorDumpPathTest.java

/*******************************************************************************
 * Copyright (c) 2026 Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package org.aspectj.weaver.tools;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import junit.framework.TestCase;

public class WeavingAdaptorDumpPathTest extends TestCase {
	private File tempDir, dumpDir;

	protected void setUp() throws Exception {
		super.setUp();
		tempDir = File.createTempFile("dumppathtest", "root");
		tempDir.delete();
		dumpDir = new File(tempDir, "_ajdump");
		dumpDir.mkdirs();
	}

	protected void tearDown() throws Exception {
		dumpDir.delete();
		tempDir.delete();
		super.tearDown();
	}

	public void testNormalNameStaysInDumpDir() throws IOException {
		File f = WeavingAdaptor.resolveDumpFile(dumpDir.getPath(), "ok.Foo");
		assertEquals(new File(dumpDir, "ok/Foo.class").getCanonicalPath(), f.getCanonicalPath());
	}

	public void testTraversalLookingNamesStayInsideBecauseDotsAreReplaced() throws IOException {
		for (String n : new String[] { "../../../tmp/bad", "a/../../b", "/etc/passwd", ".." }) {
			File f = WeavingAdaptor.resolveDumpFile(dumpDir.getPath(), n);
			assertTrue(n, f.getCanonicalFile().toPath().startsWith(dumpDir.getCanonicalFile().toPath()));
		}
	}

	public void testSymlinkOutOfDumpDirIsRejected() throws IOException {
		File outside = new File(tempDir, "outside");
		File link = new File(dumpDir, "link");
		outside.mkdirs();
		try {
			try {
				Files.createSymbolicLink(link.toPath(), outside.toPath());
			} catch (UnsupportedOperationException | IOException e) {
				return; // symlinks unavailable (e.g. Windows without privilege)
			}
			try {
				WeavingAdaptor.resolveDumpFile(dumpDir.getPath(), "link.Foo"); // -> link/Foo.class is outside
				fail("expected a path escaping through a symlink to be rejected");
			} catch (IOException expected) {
			}
		} finally {
			link.delete(); // File.delete() on symlink removes the link not its target
			outside.delete(); // only succeeds if empty
		}
	}
}