mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-21 00:29:21 +01:00
Issue #730: Allow multiple suppression files in Maven
The core has been extended to handle multiple suppression files Extended the Ant test to cover multiple suppression files NOTE: This change is breaking for users of the Maven plugin
This commit is contained in:
@@ -92,6 +92,9 @@
|
|||||||
<fileset dir="${project.build.directory}/test-classes/jars">
|
<fileset dir="${project.build.directory}/test-classes/jars">
|
||||||
<include name="axis-1.4.jar"/>
|
<include name="axis-1.4.jar"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
|
<filelist
|
||||||
|
dir="${project.build.directory}/test-classes/list"
|
||||||
|
files="jetty-6.1.0.jar,org.mortbay.jetty.jar"/>
|
||||||
</dependency-check>
|
</dependency-check>
|
||||||
</target>
|
</target>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,10 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Test suppression file for the DependencyCheckTaskTest#testSuppressingCVE() test -->
|
<!--
|
||||||
|
This file is part of dependency-check-core.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
-->
|
||||||
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
|
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
|
||||||
<suppress>
|
<suppress>
|
||||||
<notes><![CDATA[
|
<notes><![CDATA[
|
||||||
file name: axis-1.4.jar
|
file name: axis-1.4.jar
|
||||||
]]></notes>
|
]]></notes>
|
||||||
<gav regex="true">^org\.apache\.axis:axis:.*$</gav>
|
<gav regex="true">^org\.apache\.axis:axis:.*$</gav>
|
||||||
<cpe>cpe:/a:apache:axis</cpe>
|
<cpe>cpe:/a:apache:axis</cpe>
|
||||||
</suppress>
|
</suppress>
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
This file is part of dependency-check-core.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
-->
|
||||||
|
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
|
||||||
|
<suppress>
|
||||||
|
<notes><![CDATA[
|
||||||
|
file name: org.mortbay.jetty.jar
|
||||||
|
]]></notes>
|
||||||
|
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
|
||||||
|
<cpe>cpe:/a:jetty:jetty</cpe>
|
||||||
|
</suppress>
|
||||||
|
<suppress>
|
||||||
|
<notes><![CDATA[
|
||||||
|
file name: org.mortbay.jetty.jar
|
||||||
|
]]></notes>
|
||||||
|
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
|
||||||
|
<cpe>cpe:/a:mortbay:jetty</cpe>
|
||||||
|
</suppress>
|
||||||
|
<suppress>
|
||||||
|
<notes><![CDATA[
|
||||||
|
file name: org.mortbay.jetty.jar
|
||||||
|
]]></notes>
|
||||||
|
<gav regex="true">^jetty:org\.mortbay\.jetty:.*$</gav>
|
||||||
|
<cpe>cpe:/a:mortbay_jetty:jetty</cpe>
|
||||||
|
</suppress>
|
||||||
|
</suppressions>
|
||||||
@@ -117,66 +117,67 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO support more than one file
|
for (final String suppressionFilePath : suppressionFilePaths) {
|
||||||
final String suppressionFilePath = suppressionFilePaths[0];
|
LOGGER.debug("Loading suppression rules from '{}'", suppressionFilePath);
|
||||||
|
|
||||||
boolean deleteTempFile = false;
|
boolean deleteTempFile = false;
|
||||||
try {
|
try {
|
||||||
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||||
if (uriRx.matcher(suppressionFilePath).matches()) {
|
if (uriRx.matcher(suppressionFilePath).matches()) {
|
||||||
deleteTempFile = true;
|
deleteTempFile = true;
|
||||||
file = FileUtils.getTempFile("suppression", "xml");
|
file = FileUtils.getTempFile("suppression", "xml");
|
||||||
final URL url = new URL(suppressionFilePath);
|
final URL url = new URL(suppressionFilePath);
|
||||||
try {
|
try {
|
||||||
Downloader.fetchFile(url, file, false);
|
Downloader.fetchFile(url, file, false);
|
||||||
} catch (DownloadFailedException ex) {
|
} catch (DownloadFailedException ex) {
|
||||||
Downloader.fetchFile(url, file, true);
|
Downloader.fetchFile(url, file, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file = new File(suppressionFilePath);
|
file = new File(suppressionFilePath);
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
|
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
|
||||||
if (suppressionsFromClasspath != null) {
|
if (suppressionsFromClasspath != null) {
|
||||||
deleteTempFile = true;
|
deleteTempFile = true;
|
||||||
file = FileUtils.getTempFile("suppression", "xml");
|
file = FileUtils.getTempFile("suppression", "xml");
|
||||||
try {
|
try {
|
||||||
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
|
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (file != null) {
|
||||||
if (file != null) {
|
if (!file.exists()) {
|
||||||
if (!file.exists()) {
|
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
|
||||||
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
|
LOGGER.warn(msg);
|
||||||
LOGGER.warn(msg);
|
throw new SuppressionParseException(msg);
|
||||||
throw new SuppressionParseException(msg);
|
}
|
||||||
|
try {
|
||||||
|
rules.addAll(parser.parseSuppressionRules(file));
|
||||||
|
} catch (SuppressionParseException ex) {
|
||||||
|
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
|
||||||
|
LOGGER.warn(ex.getMessage());
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
} catch (DownloadFailedException ex) {
|
||||||
rules.addAll(parser.parseSuppressionRules(file));
|
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
||||||
LOGGER.debug("{} suppression rules were loaded.", rules.size());
|
} catch (MalformedURLException ex) {
|
||||||
} catch (SuppressionParseException ex) {
|
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
||||||
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
|
} catch (SuppressionParseException ex) {
|
||||||
LOGGER.warn(ex.getMessage());
|
throw ex;
|
||||||
throw ex;
|
} catch (IOException ex) {
|
||||||
|
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
||||||
|
} finally {
|
||||||
|
if (deleteTempFile && file != null) {
|
||||||
|
FileUtils.delete(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (DownloadFailedException ex) {
|
|
||||||
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
|
||||||
} catch (SuppressionParseException ex) {
|
|
||||||
throw ex;
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
|
||||||
} finally {
|
|
||||||
if (deleteTempFile && file != null) {
|
|
||||||
FileUtils.delete(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
LOGGER.debug("{} suppression rules were loaded.", rules.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>test-dataformat-jackson</artifactId>
|
<artifactId>test-dataformat-jackson</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.4.5</version>
|
<version>2.4.5</version>
|
||||||
@@ -38,10 +38,10 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>jackson-dataformat-cbor</artifactId>
|
<artifactId>jackson-dataformat-cbor</artifactId>
|
||||||
<version>2.4.5</version>
|
<version>2.4.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
<artifactId>jackson-dataformat-xml</artifactId>
|
<artifactId>jackson-dataformat-xml</artifactId>
|
||||||
<version>2.4.5</version>
|
<version>2.4.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#
|
||||||
|
# This file is part of dependency-check-core.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
#
|
||||||
|
invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
This file is part of dependency-check-core.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.owasp.test</groupId>
|
||||||
|
<artifactId>test-multiple-suppression-files</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- These can be replaced by any other vulnerable dependency -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.vaadin.external.google</groupId>
|
||||||
|
<artifactId>android-json</artifactId>
|
||||||
|
<version>0.0.20131108.vaadin1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-xml</artifactId>
|
||||||
|
<version>2.4.5</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.owasp</groupId>
|
||||||
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<suppressionFiles>
|
||||||
|
<param>${project.basedir}/test-suppression1.xml</param>
|
||||||
|
<param>${project.basedir}/test-suppression2.xml</param>
|
||||||
|
</suppressionFiles>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import org.apache.commons.lang.StringUtils
|
||||||
|
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
// Check that suppression worked.
|
||||||
|
String log = FileUtils.readFileToString(new File(basedir, "build.log"), Charset.defaultCharset().name());
|
||||||
|
int count = StringUtils.countMatches(log, "CVE-2016-5696");
|
||||||
|
if (count > 0) {
|
||||||
|
System.out.println(String.format("CVE-2016-5696 (android-json-0.0.20131108.vaadin1.jar) was identified and should be suppressed"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
count = StringUtils.countMatches(log, "CVE-2016-7051");
|
||||||
|
if (count > 0) {
|
||||||
|
System.out.println(String.format("CVE-2016-7051 (jackson-module-jaxb-annotations-2.4.5.jar) was identified and should be suppressed"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
This file is part of dependency-check-core.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
-->
|
||||||
|
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
|
||||||
|
<suppress>
|
||||||
|
<notes><![CDATA[
|
||||||
|
file name: android-json-0.0.20131108.vaadin1.jar
|
||||||
|
]]></notes>
|
||||||
|
<gav regex="true">^com\.vaadin\.external\.google:android-json:.*$</gav>
|
||||||
|
<cpe>cpe:/a:google:android</cpe>
|
||||||
|
</suppress>
|
||||||
|
</suppressions>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
This file is part of dependency-check-core.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Copyright (c) 2017 The OWASP Foundation. All Rights Reserved.
|
||||||
|
-->
|
||||||
|
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
|
||||||
|
<suppress>
|
||||||
|
<notes><![CDATA[
|
||||||
|
file name: jackson-dataformat-xml-2.4.5.jar
|
||||||
|
]]></notes>
|
||||||
|
<gav regex="true">^com\.fasterxml\.jackson.*:.*:.*$</gav>
|
||||||
|
<cpe>cpe:/a:fasterxml:jackson</cpe>
|
||||||
|
</suppress>
|
||||||
|
</suppressions>
|
||||||
@@ -199,10 +199,10 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
|||||||
@Parameter(property = "connectionTimeout", defaultValue = "", required = false)
|
@Parameter(property = "connectionTimeout", defaultValue = "", required = false)
|
||||||
private String connectionTimeout;
|
private String connectionTimeout;
|
||||||
/**
|
/**
|
||||||
* The path to the suppression file.
|
* The paths to the suppression files.
|
||||||
*/
|
*/
|
||||||
@Parameter(property = "suppressionFile", defaultValue = "", required = false)
|
@Parameter(required = false)
|
||||||
private String suppressionFile;
|
private String[] suppressionFiles;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path to the hints file.
|
* The path to the hints file.
|
||||||
@@ -920,8 +920,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
|||||||
Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
|
Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFiles);
|
||||||
|
|
||||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
|
||||||
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
||||||
|
|
||||||
//File Type Analyzer Settings
|
//File Type Analyzer Settings
|
||||||
|
|||||||
Reference in New Issue
Block a user