Merge branch 'master' into develop

This commit is contained in:
René Pfeuffer
2022-01-18 08:20:23 +01:00
20 changed files with 95 additions and 61 deletions

View File

@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.29.1] - 2022-01-17
### Fixed
- Path traversal vulnerability
## [2.29.0] - 2022-01-07 ## [2.29.0] - 2022-01-07
### Added ### Added
- CSS variables for plugins ([#1910](https://github.com/scm-manager/scm-manager/pull/1910)) - CSS variables for plugins ([#1910](https://github.com/scm-manager/scm-manager/pull/1910))
@@ -900,3 +904,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[2.27.4]: https://scm-manager.org/download/2.27.4 [2.27.4]: https://scm-manager.org/download/2.27.4
[2.28.0]: https://scm-manager.org/download/2.28.0 [2.28.0]: https://scm-manager.org/download/2.28.0
[2.29.0]: https://scm-manager.org/download/2.29.0 [2.29.0]: https://scm-manager.org/download/2.29.0
[2.29.1]: https://scm-manager.org/download/2.29.1

View File

@@ -22,5 +22,5 @@
# SOFTWARE. # SOFTWARE.
# #
group = sonia.scm group = sonia.scm
version = 2.29.1-SNAPSHOT version = 2.29.2-SNAPSHOT
org.gradle.jvmargs=-Xmx1024M org.gradle.jvmargs=-Xmx1024M

View File

@@ -5,5 +5,5 @@
], ],
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"version": "2.29.1-SNAPSHOT" "version": "2.29.2-SNAPSHOT"
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "@scm-manager/scm-git-plugin", "name": "@scm-manager/scm-git-plugin",
"private": true, "private": true,
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"license": "MIT", "license": "MIT",
"main": "./src/main/js/index.ts", "main": "./src/main/js/index.ts",
"scripts": { "scripts": {
@@ -11,7 +11,7 @@
"typecheck": "tsc" "typecheck": "tsc"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-plugins": "^2.29.1-SNAPSHOT" "@scm-manager/ui-plugins": "^2.29.2-SNAPSHOT"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/babel-preset": "^2.12.0", "@scm-manager/babel-preset": "^2.12.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "@scm-manager/scm-hg-plugin", "name": "@scm-manager/scm-hg-plugin",
"private": true, "private": true,
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"license": "MIT", "license": "MIT",
"main": "./src/main/js/index.ts", "main": "./src/main/js/index.ts",
"scripts": { "scripts": {
@@ -10,7 +10,7 @@
"typecheck": "tsc" "typecheck": "tsc"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-plugins": "^2.29.1-SNAPSHOT" "@scm-manager/ui-plugins": "^2.29.2-SNAPSHOT"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/babel-preset": "^2.12.0", "@scm-manager/babel-preset": "^2.12.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "@scm-manager/scm-legacy-plugin", "name": "@scm-manager/scm-legacy-plugin",
"private": true, "private": true,
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"license": "MIT", "license": "MIT",
"main": "./src/main/js/index.tsx", "main": "./src/main/js/index.tsx",
"scripts": { "scripts": {
@@ -10,7 +10,7 @@
"typecheck": "tsc" "typecheck": "tsc"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-plugins": "^2.29.1-SNAPSHOT" "@scm-manager/ui-plugins": "^2.29.2-SNAPSHOT"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/babel-preset": "^2.12.0", "@scm-manager/babel-preset": "^2.12.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "@scm-manager/scm-svn-plugin", "name": "@scm-manager/scm-svn-plugin",
"private": true, "private": true,
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"license": "MIT", "license": "MIT",
"main": "./src/main/js/index.ts", "main": "./src/main/js/index.ts",
"scripts": { "scripts": {
@@ -10,7 +10,7 @@
"typecheck": "tsc" "typecheck": "tsc"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-plugins": "^2.29.1-SNAPSHOT" "@scm-manager/ui-plugins": "^2.29.2-SNAPSHOT"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/babel-preset": "^2.12.0", "@scm-manager/babel-preset": "^2.12.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/e2e-tests", "name": "@scm-manager/e2e-tests",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "End to end Tests for SCM-Manager", "description": "End to end Tests for SCM-Manager",
"main": "index.js", "main": "index.js",
"author": "Eduard Heimbuch <eduard.heimbuch@cloudogu.com>", "author": "Eduard Heimbuch <eduard.heimbuch@cloudogu.com>",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-api", "name": "@scm-manager/ui-api",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "React hook api for the SCM-Manager backend", "description": "React hook api for the SCM-Manager backend",
"main": "src/index.ts", "main": "src/index.ts",
"files": [ "files": [
@@ -25,7 +25,7 @@
"react-test-renderer": "^17.0.1" "react-test-renderer": "^17.0.1"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-types": "^2.29.1-SNAPSHOT", "@scm-manager/ui-types": "^2.29.2-SNAPSHOT",
"fetch-mock-jest": "^1.5.1", "fetch-mock-jest": "^1.5.1",
"gitdiff-parser": "^0.1.2", "gitdiff-parser": "^0.1.2",
"query-string": "6.14.1", "query-string": "6.14.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-components", "name": "@scm-manager/ui-components",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "UI Components for SCM-Manager and its plugins", "description": "UI Components for SCM-Manager and its plugins",
"main": "src/index.ts", "main": "src/index.ts",
"files": [ "files": [
@@ -25,7 +25,7 @@
"@scm-manager/jest-preset": "^2.13.0", "@scm-manager/jest-preset": "^2.13.0",
"@scm-manager/prettier-config": "^2.10.1", "@scm-manager/prettier-config": "^2.10.1",
"@scm-manager/tsconfig": "^2.12.0", "@scm-manager/tsconfig": "^2.12.0",
"@scm-manager/ui-tests": "^2.29.1-SNAPSHOT", "@scm-manager/ui-tests": "^2.29.2-SNAPSHOT",
"@storybook/addon-actions": "^6.3.12", "@storybook/addon-actions": "^6.3.12",
"@storybook/addon-storyshots": "^6.3.12", "@storybook/addon-storyshots": "^6.3.12",
"@storybook/builder-webpack5": "^6.3.12", "@storybook/builder-webpack5": "^6.3.12",
@@ -65,9 +65,9 @@
"worker-plugin": "^3.2.0" "worker-plugin": "^3.2.0"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-api": "^2.29.1-SNAPSHOT", "@scm-manager/ui-api": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-extensions": "^2.29.1-SNAPSHOT", "@scm-manager/ui-extensions": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-types": "^2.29.1-SNAPSHOT", "@scm-manager/ui-types": "^2.29.2-SNAPSHOT",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"date-fns": "^2.4.1", "date-fns": "^2.4.1",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-extensions", "name": "@scm-manager/ui-extensions",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"main": "src/index.ts", "main": "src/index.ts",
"license": "MIT", "license": "MIT",
"private": false, "private": false,
@@ -10,7 +10,7 @@
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-types": "^2.29.1-SNAPSHOT", "@scm-manager/ui-types": "^2.29.2-SNAPSHOT",
"react": "^17.0.1" "react": "^17.0.1"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,13 +1,13 @@
{ {
"name": "@scm-manager/ui-plugins", "name": "@scm-manager/ui-plugins",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"ui-plugins": "./bin/ui-plugins.js" "ui-plugins": "./bin/ui-plugins.js"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-components": "^2.29.1-SNAPSHOT", "@scm-manager/ui-components": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-extensions": "^2.29.1-SNAPSHOT", "@scm-manager/ui-extensions": "^2.29.2-SNAPSHOT",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"query-string": "6.14.1", "query-string": "6.14.1",
"react": "^17.0.1", "react": "^17.0.1",
@@ -25,9 +25,9 @@
"@scm-manager/plugin-scripts": "^1.2.2", "@scm-manager/plugin-scripts": "^1.2.2",
"@scm-manager/prettier-config": "^2.10.1", "@scm-manager/prettier-config": "^2.10.1",
"@scm-manager/tsconfig": "^2.12.0", "@scm-manager/tsconfig": "^2.12.0",
"@scm-manager/ui-scripts": "^2.29.1-SNAPSHOT", "@scm-manager/ui-scripts": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-tests": "^2.29.1-SNAPSHOT", "@scm-manager/ui-tests": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-types": "^2.29.1-SNAPSHOT", "@scm-manager/ui-types": "^2.29.2-SNAPSHOT",
"@types/classnames": "^2.2.9", "@types/classnames": "^2.2.9",
"@types/enzyme": "^3.10.3", "@types/enzyme": "^3.10.3",
"@types/fetch-mock": "^7.3.1", "@types/fetch-mock": "^7.3.1",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-polyfill", "name": "@scm-manager/ui-polyfill",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "Polyfills for SCM-Manager UI", "description": "Polyfills for SCM-Manager UI",
"main": "src/index.js", "main": "src/index.js",
"author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>", "author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-scripts", "name": "@scm-manager/ui-scripts",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "Build scripts for SCM-Manager", "description": "Build scripts for SCM-Manager",
"main": "src/index.js", "main": "src/index.js",
"author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>", "author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-styles", "name": "@scm-manager/ui-styles",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "Styles for SCM-Manager", "description": "Styles for SCM-Manager",
"main": "src/scm.scss", "main": "src/scm.scss",
"license": "MIT", "license": "MIT",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-tests", "name": "@scm-manager/ui-tests",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "UI-Tests helpers", "description": "UI-Tests helpers",
"author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>", "author": "Sebastian Sdorra <sebastian.sdorra@cloudogu.com>",
"license": "MIT", "license": "MIT",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@scm-manager/ui-types", "name": "@scm-manager/ui-types",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"description": "Typescript types for SCM-Manager related Objects", "description": "Typescript types for SCM-Manager related Objects",
"main": "src/index.ts", "main": "src/index.ts",
"files": [ "files": [

View File

@@ -1,11 +1,11 @@
{ {
"name": "@scm-manager/ui-webapp", "name": "@scm-manager/ui-webapp",
"version": "2.29.1-SNAPSHOT", "version": "2.29.2-SNAPSHOT",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@scm-manager/ui-api": "^2.29.1-SNAPSHOT", "@scm-manager/ui-api": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-components": "^2.29.1-SNAPSHOT", "@scm-manager/ui-components": "^2.29.2-SNAPSHOT",
"@scm-manager/ui-extensions": "^2.29.1-SNAPSHOT", "@scm-manager/ui-extensions": "^2.29.2-SNAPSHOT",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"history": "^4.10.1", "history": "^4.10.1",
"i18next": "^19.6.0", "i18next": "^19.6.0",
@@ -30,7 +30,7 @@
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/jest-preset": "^2.13.0", "@scm-manager/jest-preset": "^2.13.0",
"@scm-manager/ui-tests": "^2.29.1-SNAPSHOT", "@scm-manager/ui-tests": "^2.29.2-SNAPSHOT",
"@types/classnames": "^2.2.9", "@types/classnames": "^2.2.9",
"@types/enzyme": "^3.10.3", "@types/enzyme": "^3.10.3",
"@types/fetch-mock": "^7.3.1", "@types/fetch-mock": "^7.3.1",

View File

@@ -38,37 +38,32 @@ import java.nio.file.Path;
* @author Sebastian Sdorra * @author Sebastian Sdorra
* @since 2.0.0 * @since 2.0.0
*/ */
public class PathWebResourceLoader implements WebResourceLoader public class PathWebResourceLoader implements WebResourceLoader {
{
private static final String SEPARATOR = "/"; private static final String SEPARATOR = "/";
private final Path directory;
/** /**
* the logger for PathWebResourceLoader * the logger for PathWebResourceLoader
*/ */
private static final Logger LOG = private static final Logger LOG = LoggerFactory.getLogger(PathWebResourceLoader.class);
LoggerFactory.getLogger(PathWebResourceLoader.class);
public PathWebResourceLoader(Path directory) public PathWebResourceLoader(Path directory) {
{ this.directory = directory.toAbsolutePath().normalize();
this.directory = directory;
} }
@Override @Override
public URL getResource(String path) { public URL getResource(String path) {
URL resource = null; URL resource = null;
Path file = directory.resolve(filePath(path)); Path file = directory.resolve(filePath(path)).toAbsolutePath().normalize();
if (Files.exists(file) && ! Files.isDirectory(file)) if (isValidPath(file)) {
{
LOG.trace("found path {} at {}", path, file); LOG.trace("found path {} at {}", path, file);
try try {
{
resource = file.toUri().toURL(); resource = file.toUri().toURL();
} } catch (MalformedURLException ex) {
catch (MalformedURLException ex)
{
LOG.error("could not transform path to url", ex); LOG.error("could not transform path to url", ex);
} }
} else { } else {
@@ -78,6 +73,12 @@ public class PathWebResourceLoader implements WebResourceLoader
return resource; return resource;
} }
private boolean isValidPath(Path file) {
return Files.exists(file)
&& !Files.isDirectory(file)
&& file.startsWith(directory);
}
private String filePath(String path) { private String filePath(String path) {
if (path.startsWith(SEPARATOR)) { if (path.startsWith(SEPARATOR)) {
return path.substring(1); return path.substring(1);
@@ -85,8 +86,4 @@ public class PathWebResourceLoader implements WebResourceLoader
return path; return path;
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private final Path directory;
} }

View File

@@ -42,11 +42,10 @@ import java.net.URL;
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase {
{
@Test @Test
public void testGetNullForDirectories() throws IOException { public void shouldReturnNullForDirectories() throws IOException {
File directory = temp.newFolder(); File directory = temp.newFolder();
assertTrue(new File(directory, "awesome").mkdir()); assertTrue(new File(directory, "awesome").mkdir());
@@ -56,7 +55,7 @@ public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase
@Test @Test
public void testGetResource() throws IOException { public void shouldReturnResource() throws IOException {
File directory = temp.newFolder(); File directory = temp.newFolder();
URL url = file(directory, "myresource").toURI().toURL(); URL url = file(directory, "myresource").toURI().toURL();
@@ -68,4 +67,36 @@ public class PathWebResourceLoaderTest extends WebResourceLoaderTestBase
assertNull(resourceLoader.getResource("other")); assertNull(resourceLoader.getResource("other"));
} }
@Test
public void shouldNotReturnPathsWithAbsolutePath() throws IOException {
File base = temp.newFolder();
File one = new File(base, "one");
assertTrue(one.mkdirs());
File two = new File(base, "two");
assertTrue(two.mkdirs());
File secret = new File(two, "secret");
assertTrue(secret.createNewFile());
WebResourceLoader resourceLoader = new PathWebResourceLoader(one.toPath());
assertNull(resourceLoader.getResource(secret.getAbsolutePath()));
assertNull(resourceLoader.getResource("/" + secret.getAbsolutePath()));
}
@Test
public void shouldNotReturnPathsWithPathTraversal() throws IOException {
File base = temp.newFolder();
File one = new File(base, "one");
assertTrue(one.mkdirs());
File two = new File(base, "two");
assertTrue(two.mkdirs());
File secret = new File(two, "secret");
assertTrue(secret.createNewFile());
WebResourceLoader resourceLoader = new PathWebResourceLoader(one.toPath());
assertNull(resourceLoader.getResource("../two/secret"));
}
} }