diff --git a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF index 80f81aad40..91f5fa4369 100644 --- a/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF @@ -37,7 +37,6 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls. org.eclipse.jdt.ls.core.internal.commands;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.contentassist;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.corext.codemanipulation;x-friends:="org.eclipse.jdt.ls.tests", - org.eclipse.jdt.ls.core.internal.corext.template.java;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.corext.dom;x-internal:=true, org.eclipse.jdt.ls.core.internal.corext.refactoring;x-internal:=true, org.eclipse.jdt.ls.core.internal.corext.refactoring.changes;x-internal:=true, @@ -46,6 +45,7 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls. org.eclipse.jdt.ls.core.internal.corext.refactoring.reorg;x-internal:=true, org.eclipse.jdt.ls.core.internal.corext.refactoring.tagging;x-internal:=true, org.eclipse.jdt.ls.core.internal.corext.refactoring.util;x-internal:=true, + org.eclipse.jdt.ls.core.internal.corext.template.java;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.corext.util;x-internal:=true, org.eclipse.jdt.ls.core.internal.corrections;x-internal:=true, org.eclipse.jdt.ls.core.internal.corrections.proposals;x-internal:=true, @@ -56,9 +56,10 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls. org.eclipse.jdt.ls.core.internal.lsp;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.managers;x-friends:="org.eclipse.jdt.ls.tests,org.eclipse.jdt.ls.tests.syntaxserver", org.eclipse.jdt.ls.core.internal.preferences;x-friends:="org.eclipse.jdt.ls.tests,org.eclipse.jdt.ls.tests.syntaxserver", + org.eclipse.jdt.ls.core.internal.semantictokens;x-friends:="org.eclipse.jdt.ls.tests", org.eclipse.jdt.ls.core.internal.syntaxserver;x-friends:="org.eclipse.jdt.ls.tests.syntaxserver", org.eclipse.jdt.ls.core.internal.text.correction;x-friends:="org.eclipse.jdt.ls.tests", - org.eclipse.jdt.ls.core.internal.semantictokens;x-friends:="org.eclipse.jdt.ls.tests" + org.eclipse.jdt.ls.internal.gradle.checksums;x-friends:="org.eclipse.jdt.ls.tests" Bundle-ClassPath: lib/jsoup-1.9.2.jar, lib/remark-1.2.0.jar, . diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ExceptionFactory.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ExceptionFactory.java new file mode 100644 index 0000000000..ee01ae8a66 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/ExceptionFactory.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal; + +import org.eclipse.core.runtime.CoreException; + +/** + * + * @author snjeza + * + */ +public class ExceptionFactory { + + private ExceptionFactory() { + } + + public static CoreException newException(String message) { + return new CoreException(StatusFactory.newErrorStatus(message)); + } + + public static CoreException newException(Throwable e) { + return new CoreException(StatusFactory.newErrorStatus(e.getMessage(), e)); + } + +} + diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JobHelpers.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JobHelpers.java index ca0e83e7bb..f5a79e1bce 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JobHelpers.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JobHelpers.java @@ -210,6 +210,10 @@ public static void waitForJobs(String jobFamily, IProgressMonitor monitor) { } } + public static void waitForLoadingGradleVersionJob() { + waitForJobs(LoadingGradleVersionJobMatcher.INSTANCE, MAX_TIME_MILLIS); + } + interface IJobMatcher { boolean matches(Job job); @@ -239,6 +243,17 @@ public boolean matches(Job job) { } + static class LoadingGradleVersionJobMatcher implements IJobMatcher { + + public static final IJobMatcher INSTANCE = new LoadingGradleVersionJobMatcher(); + + @Override + public boolean matches(Job job) { + return job.getClass().getName().matches("org.eclipse.buildship.core.internal.util.gradle.PublishedGradleVersionsWrapper.LoadVersionsJob"); + } + + } + static class DownloadSourcesJobMatcher implements IJobMatcher { public static final IJobMatcher INSTANCE = new DownloadSourcesJobMatcher(); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java index d77fab2642..c4d15b1341 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleBuildSupport.java @@ -14,6 +14,7 @@ import java.io.File; import java.nio.file.Paths; +import java.util.Optional; import org.eclipse.buildship.core.BuildConfiguration; import org.eclipse.buildship.core.GradleBuild; @@ -56,10 +57,17 @@ public void update(IProject project, boolean force, IProgressMonitor monitor) th return; } JavaLanguageServerPlugin.logInfo("Starting Gradle update for " + project.getName()); - String projectPath = project.getLocation().toFile().getAbsolutePath(); - BuildConfiguration buildConfiguration = GradleProjectImporter.getBuildConfiguration(Paths.get(projectPath)); - GradleBuild build = GradleCore.getWorkspace().createBuild(buildConfiguration); - build.synchronize(monitor); + if (force) { + String projectPath = project.getLocation().toFile().getAbsolutePath(); + BuildConfiguration buildConfiguration = GradleProjectImporter.getBuildConfiguration(Paths.get(projectPath)); + GradleBuild build = GradleCore.getWorkspace().createBuild(buildConfiguration); + build.synchronize(monitor); + } else { + Optional build = GradleCore.getWorkspace().getBuild(project); + if (build.isPresent()) { + build.get().synchronize(monitor); + } + } } @Override diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java index 73885f41d8..2909c4bf1a 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java @@ -12,6 +12,8 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.managers; +import static java.util.Arrays.asList; + import java.io.File; import java.io.FilenameFilter; import java.nio.file.Files; @@ -42,6 +44,11 @@ import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; +import org.eclipse.jdt.ls.internal.gradle.checksums.ValidationResult; +import org.eclipse.jdt.ls.internal.gradle.checksums.WrapperValidator; +import org.eclipse.lsp4j.ExecuteCommandParams; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; /** * @author Fred Bricon @@ -59,6 +66,17 @@ public class GradleProjectImporter extends AbstractProjectImporter { public static final String IMPORTING_GRADLE_PROJECTS = "Importing Gradle project(s)"; + //@formatter:off + public static final String GRADLE_WRAPPER_CHEKSUM_WARNING_TEMPLATE = + "Security Warning! The gradle wrapper '@wrapper@' could be malicious. " + + "If you trust it, please add \n" + + "`{\"sha256\": \"@checksum@\"," + + "\n\"allowed\": true}`" + + "\n to the `java.import.gradle.wrapper.checksums` preference." + + "" + .replaceAll("\n", System.lineSeparator()); + //@formatter:on + private Collection directories; /* (non-Javadoc) @@ -107,13 +125,39 @@ private void importDir(Path rootFolder, IProgressMonitor monitor) { } public static GradleDistribution getGradleDistribution(Path rootFolder) { - if (JavaLanguageServerPlugin.getPreferencesManager() != null && JavaLanguageServerPlugin.getPreferencesManager().getPreferences().isGradleWrapperEnabled() && Files.exists(rootFolder.resolve("gradlew"))) { - return GradleDistribution.fromBuild(); + PreferenceManager preferencesManager = JavaLanguageServerPlugin.getPreferencesManager(); + if (preferencesManager != null && preferencesManager.getPreferences().isGradleWrapperEnabled() && Files.exists(rootFolder.resolve("gradlew"))) { + WrapperValidator validator = new WrapperValidator(); + try { + ValidationResult result = validator.checkWrapper(rootFolder.toFile().getAbsolutePath()); + if (result.isValid()) { + WrapperGradleDistribution gradleDistribution = GradleDistribution.fromBuild(); + return gradleDistribution; + } else { + if (!WrapperValidator.contains(result.getChecksum())) { + ProjectsManager pm = JavaLanguageServerPlugin.getProjectsManager(); + if (pm != null && pm.getConnection() != null) { + if (preferencesManager.getClientPreferences().isGradleChecksumWrapperPromptSupport()) { + String id = "gradle/checksum/prompt"; + ExecuteCommandParams params = new ExecuteCommandParams(id, asList(result.getWrapperJar(), result.getChecksum())); + pm.getConnection().sendNotification(params); + } else { + //@formatter:off + String message = GRADLE_WRAPPER_CHEKSUM_WARNING_TEMPLATE.replaceAll("@wrapper@", result.getWrapperJar()).replaceAll("@checksum@", result.getChecksum()); + //@formatter:on + pm.getConnection().showMessage(new MessageParams(MessageType.Error, message)); + } + } + } + } + } catch (CoreException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } } - if (JavaLanguageServerPlugin.getPreferencesManager() != null && JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getGradleVersion() != null) { + if (preferencesManager != null && preferencesManager.getPreferences().getGradleVersion() != null) { List versions = CorePlugin.publishedGradleVersions().getVersions(); GradleVersion gradleVersion = null; - String versionString = JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getGradleVersion(); + String versionString = preferencesManager.getPreferences().getGradleVersion(); GradleVersion requiredVersion = GradleVersion.version(versionString); for (GradleVersion version : versions) { if (version.compareTo(requiredVersion) == 0) { diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java index 6540bf983f..b0cdc97266 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java @@ -372,6 +372,10 @@ public void setConnection(JavaLanguageClient client) { this.client = client; } + public JavaLanguageClient getConnection() { + return this.client; + } + private String getWorkspaceInfo() { StringBuilder b = new StringBuilder(); b.append("Projects:\n"); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java index fcbd019aef..4d1e2a1a23 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/ClientPreferences.java @@ -221,6 +221,14 @@ public boolean isClientDocumentSymbolProviderRegistered() { return Boolean.parseBoolean(extendedClientCapabilities.getOrDefault("clientDocumentSymbolProvider", "false").toString()); } + public boolean isActionableNotificationSupported() { + return Boolean.parseBoolean(extendedClientCapabilities.getOrDefault("actionableNotificationSupported", "false").toString()); + } + + public boolean isGradleChecksumWrapperPromptSupport() { + return Boolean.parseBoolean(extendedClientCapabilities.getOrDefault("gradleChecksumWrapperPromptSupport", "false").toString()); + } + public boolean isSupportsCompletionDocumentationMarkdown() { //@formatter:off return v3supported && capabilities.getTextDocument().getCompletion() != null diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java index e5b0fb4522..0b437f2422 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java @@ -31,6 +31,7 @@ import java.util.UUID; import org.eclipse.core.internal.resources.PreferenceInitializer; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; @@ -39,9 +40,12 @@ import org.eclipse.jdt.internal.core.manipulation.MembersOrderPreferenceCacheCommon; import org.eclipse.jdt.ls.core.internal.IConstants; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.ResourceUtils; import org.eclipse.jdt.ls.core.internal.RuntimeEnvironment; import org.eclipse.jdt.ls.core.internal.contentassist.TypeFilter; +import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; +import org.eclipse.jdt.ls.internal.gradle.checksums.WrapperValidator; import org.eclipse.lsp4j.MessageType; /** @@ -60,7 +64,7 @@ public class Preferences { * Specifies Java Execution Environments. */ public static final String JAVA_CONFIGURATION_RUNTIMES = "java.configuration.runtimes"; - public static final Set JAVA_CONFIGURATION_RUNTIMES_DEFAULT; + public static final List JAVA_CONFIGURATION_RUNTIMES_DEFAULT; /** * Specifies the file path to the formatter xml url. */ @@ -209,6 +213,15 @@ public class Preferences { */ public static final String SELECTIONRANGE_ENABLED_KEY = "java.selectionRange.enabled"; + /** + * A named preference that holds the allowed gradle wrapper sha256 checksums. + *

+ * Value is of type String: list of checksums. + *

+ */ + public static final String JAVA_GRADLE_WRAPPER_SHA256_KEY = "java.imports.gradle.wrapper.checksums"; + public static final List JAVA_GRADLE_WRAPPER_SHA256_DEFAULT; + /** * A named preference that holds the favorite static members. *

@@ -412,6 +425,8 @@ public class Preferences { private String mavenUserSettings; private List javaCompletionFavoriteMembers; + private List sha256Allowed; + private List sha256Disallowed; private List javaImportExclusions = new LinkedList<>(); private ReferencedLibraries referencedLibraries; @@ -430,7 +445,8 @@ public class Preferences { static { JAVA_IMPORT_EXCLUSIONS_DEFAULT = new LinkedList<>(); - JAVA_CONFIGURATION_RUNTIMES_DEFAULT = new HashSet<>(); + JAVA_CONFIGURATION_RUNTIMES_DEFAULT = new ArrayList<>(); + JAVA_GRADLE_WRAPPER_SHA256_DEFAULT = new ArrayList<>(); JAVA_IMPORT_EXCLUSIONS_DEFAULT.add("**/node_modules/**"); JAVA_IMPORT_EXCLUSIONS_DEFAULT.add("**/.metadata/**"); JAVA_IMPORT_EXCLUSIONS_DEFAULT.add("**/archetype-resources/**"); @@ -731,6 +747,43 @@ public static Preferences createFrom(Map configuration) { List javaCompletionFavoriteMembers = getList(configuration, JAVA_COMPLETION_FAVORITE_MEMBERS_KEY, JAVA_COMPLETION_FAVORITE_MEMBERS_DEFAULT); prefs.setJavaCompletionFavoriteMembers(javaCompletionFavoriteMembers); + List gradleWrapperList = getList(configuration, JAVA_GRADLE_WRAPPER_SHA256_KEY, JAVA_GRADLE_WRAPPER_SHA256_DEFAULT); + List sha256Allowed = new ArrayList<>(); + List sha256Disallowed = new ArrayList<>(); + for (Object object : gradleWrapperList) { + if (object instanceof Map) { + Map map = (Map) object; + final ChecksumWrapper sha256 = prefs.new ChecksumWrapper(); + sha256.allowed = true; + map.forEach((k, v) -> { + if (k instanceof String) { + switch ((String) k) { + case "sha256": + if (v instanceof String) { + sha256.checksum = (String) v; + } + break; + case "allowed": + if (v instanceof Boolean) { + sha256.allowed = (Boolean) v; + } + break; + default: + break; + } + } + }); + if (sha256.checksum != null) { + if (sha256.allowed) { + sha256Allowed.add(sha256.checksum); + } else { + sha256Disallowed.add(sha256.checksum); + } + } + } + } + prefs.putSha256(sha256Allowed, sha256Disallowed); + String mavenUserSettings = getString(configuration, MAVEN_USER_SETTINGS_KEY, null); prefs.setMavenUserSettings(mavenUserSettings); @@ -771,7 +824,7 @@ public static Preferences createFrom(Map configuration) { int staticOnDemandThreshold = getInt(configuration, IMPORTS_STATIC_ONDEMANDTHRESHOLD, IMPORTS_STATIC_ONDEMANDTHRESHOLD_DEFAULT); prefs.setStaticImportOnDemandThreshold(staticOnDemandThreshold); - List runtimeList = getList(configuration, JAVA_CONFIGURATION_RUNTIMES, JAVA_IMPORT_ORDER_DEFAULT); + List runtimeList = getList(configuration, JAVA_CONFIGURATION_RUNTIMES, JAVA_CONFIGURATION_RUNTIMES_DEFAULT); Set runtimes = new HashSet<>(); boolean[] hasDefault = { false }; for (Object object : runtimeList) { @@ -888,6 +941,24 @@ public Preferences setJavaCompletionFavoriteMembers(List javaCompletionF return this; } + public Preferences putSha256(List sha256Allowed, List sha256Disallowed) { + List oldAllowed = this.sha256Allowed; + List oldDisallowed = this.sha256Disallowed; + WrapperValidator.clear(); + this.sha256Allowed = sha256Allowed; + if (sha256Disallowed != null) { + WrapperValidator.disallow(sha256Disallowed); + } + this.sha256Disallowed = sha256Disallowed; + ProjectsManager projectsManager = JavaLanguageServerPlugin.getProjectsManager(); + if (projectsManager != null && (!Objects.equals(oldAllowed, this.sha256Allowed) || !Objects.equals(oldDisallowed, this.sha256Disallowed))) { + for (IProject project : ProjectUtils.getGradleProjects()) { + projectsManager.updateProject(project, true); + } + } + return this; + } + private Preferences setMembersSortOrder(String sortOrder) { if (sortOrder != null) { IEclipsePreferences fPreferenceStore = InstanceScope.INSTANCE.getNode(IConstants.PLUGIN_ID); @@ -1092,6 +1163,10 @@ public String[] getJavaCompletionFavoriteMembers() { return javaCompletionFavoriteMembers.toArray(new String[0]); } + public List getSha256Allowed() { + return sha256Allowed; + } + public String getJavaHome() { return javaHome; } @@ -1367,4 +1442,9 @@ public Preferences setStaticImportOnDemandThreshold(int staticImportOnDemandThre defEclipsePrefs.put(CodeStyleConfiguration.ORGIMPORTS_STATIC_ONDEMANDTHRESHOLD, String.valueOf(this.staticImportOnDemandThreshold)); return this; } + + class ChecksumWrapper { + private String checksum; + private boolean allowed; + } } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/DownloadChecksumJob.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/DownloadChecksumJob.java new file mode 100644 index 0000000000..b0ad3022bb --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/DownloadChecksumJob.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.internal.gradle.checksums; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; + +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; + +/** + * + * @author snjeza + * + */ +public class DownloadChecksumJob extends Job { + + public static final String WRAPPER_VALIDATOR_JOBS = "WrapperValidatorJobs"; + + private final BlockingQueue queue = new LinkedBlockingQueue<>(); + + public DownloadChecksumJob() { + super("Download Gradle Wrapper checksums"); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IStatus run(IProgressMonitor monitor) { + int totalWork = 2 * queue.size(); + SubMonitor subMonitor = SubMonitor.convert(monitor, totalWork); + while (!queue.isEmpty() && !monitor.isCanceled()) { + String urlStr = queue.poll(); + URL url; + try { + url = new URL(urlStr); + } catch (MalformedURLException e1) { + JavaLanguageServerPlugin.logInfo("Invalid wrapper URL " + urlStr); + continue; + } + subMonitor.setTaskName(url.toString()); + final HttpURLConnection connection; + try { + connection = (HttpURLConnection) url.openConnection(); + connection.setConnectTimeout(30000); + connection.setReadTimeout(30000); + } catch (IOException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + continue; + } + try (AutoCloseable closer = (() -> connection.disconnect()); InputStreamReader reader = new InputStreamReader(connection.getInputStream(), Charsets.UTF_8);) { + String sha256 = CharStreams.toString(reader); + File sha256File = new File(WrapperValidator.getSha256CacheFile(), WrapperValidator.getFileName(urlStr)); + write(sha256File, sha256); + WrapperValidator.allow(sha256); + subMonitor.worked(2); + } catch (Exception e) { + JavaLanguageServerPlugin.logException("Cannot download Gradle sha256 checksum: " + url.toString(), e); + continue; + } + } + subMonitor.done(); + return Status.OK_STATUS; + } + + public void add(String urlStr) { + queue.add(urlStr); + } + + private void write(File sha256File, String sha256) { + try { + Files.write(Paths.get(sha256File.getAbsolutePath()), sha256.getBytes()); + } catch (IOException e) { + JavaLanguageServerPlugin.logException(e); + } + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) + */ + @Override + public boolean belongsTo(Object family) { + return WRAPPER_VALIDATOR_JOBS.equals(family); + } + + public boolean isEmpty() { + return queue.isEmpty(); + } +} + diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/HashProvider.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/HashProvider.java new file mode 100644 index 0000000000..000821c122 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/HashProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.internal.gradle.checksums; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; + +/** + * + * @author snjeza + * + */ +public class HashProvider { + public static final String SHA256 = "SHA-256"; + + private String alghorithm; + + public HashProvider() { + this(SHA256); + } + + public HashProvider(String alghorithm) { + this.alghorithm = alghorithm; + } + + public String getChecksum(File file) throws IOException { + MessageDigest messageDigest; + try { + messageDigest = MessageDigest.getInstance(alghorithm); + } catch (NoSuchAlgorithmException e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + return null; + } + try (DigestInputStream dis = new DigestInputStream(new FileInputStream(file), messageDigest)) { + byte[] bytes = new byte[32768]; + while (dis.read(bytes) != -1) { + ; + } + messageDigest = dis.getMessageDigest(); + } + StringBuilder result = new StringBuilder(); + for (byte b : messageDigest.digest()) { + result.append(String.format("%02x", b)); + } + return result.toString(); + } +} + diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/ValidationResult.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/ValidationResult.java new file mode 100644 index 0000000000..44dc2497b4 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/ValidationResult.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.internal.gradle.checksums; + +/** + * + * @author snjeza + * + */ +public class ValidationResult { + + private String checksum; + private String wrapperJar; + private boolean valid; + + public ValidationResult(String wrapperJar, String checksum, boolean valid) { + this.wrapperJar = wrapperJar; + this.checksum = checksum; + this.valid = valid; + } + + public String getChecksum() { + return checksum; + } + + public boolean isValid() { + return valid; + } + + public String getWrapperJar() { + return wrapperJar; + } + +} + diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/WrapperValidator.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/WrapperValidator.java new file mode 100644 index 0000000000..d6e38559c3 --- /dev/null +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/internal/gradle/checksums/WrapperValidator.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.internal.gradle.checksums; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.ls.core.internal.ExceptionFactory; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.JobHelpers; +import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager; + +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.io.CharStreams; +import com.google.common.io.Closeables; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +/** + * + * @author snjeza + * + */ +public class WrapperValidator { + + private static final int QUEUE_LENGTH = 20; + private static final String WRAPPER_CHECKSUM_URL = "wrapperChecksumUrl"; + private static final String GRADLE_WRAPPER_JAR = "gradle/wrapper/gradle-wrapper.jar"; + + private static Set allowed = new HashSet<>(); + private static Set disallowed = new HashSet<>(); + private static AtomicBoolean downloaded = new AtomicBoolean(false); + private HashProvider hashProvider; + private int queueLength; + + public WrapperValidator(int queueLength) { + this.hashProvider = new HashProvider(); + queueLength = queueLength; + } + + public WrapperValidator() { + this(QUEUE_LENGTH); + } + + public ValidationResult checkWrapper(String baseDir) throws CoreException { + Path wrapperJar = Paths.get(baseDir, GRADLE_WRAPPER_JAR); + if (!wrapperJar.toFile().exists()) { + throw ExceptionFactory.newException(wrapperJar.toString() + " doesn't exist."); + } + if (!downloaded.get() || allowed.isEmpty()) { + PreferenceManager preferenceManager = JavaLanguageServerPlugin.getPreferencesManager(); + if (preferenceManager != null && preferenceManager.getPreferences().getSha256Allowed() != null) { + allow(preferenceManager.getPreferences().getSha256Allowed()); + } + File versionFile = getVersionCacheFile(); + if (!versionFile.exists()) { + JobHelpers.waitForLoadingGradleVersionJob(); + } + if (versionFile.exists()) { + InputStreamReader reader = null; + try { + reader = new InputStreamReader(new FileInputStream(versionFile), Charsets.UTF_8); + String json = CharStreams.toString(reader); + Gson gson = new GsonBuilder().create(); + TypeToken>> typeToken = new TypeToken>>() { + }; + List> versions = gson.fromJson(json, typeToken.getType()); + //@formatter:off + ImmutableList wrapperChecksumUrls = FluentIterable + .from(versions) + .filter(new Predicate>() { + @Override + public boolean apply(Map input) { + return input.get(WRAPPER_CHECKSUM_URL) != null; + } + }) + .transform(new Function, String>() { + @Override + public String apply(Map input) { + return input.get(WRAPPER_CHECKSUM_URL); + } + }) + .toList(); + // @formatter:on + DownloadChecksumJob downloadJob = new DownloadChecksumJob(); + int count = 0; + File cacheDir = getSha256CacheFile(); + for (String wrapperChecksumUrl : wrapperChecksumUrls) { + try { + String fileName = getFileName(wrapperChecksumUrl); + if (fileName == null) { + continue; + } + File sha256File = new File(cacheDir, fileName); + if (!sha256File.exists() || sha256File.lastModified() < versionFile.lastModified()) { + count++; + if (count > queueLength) { + downloadJob.schedule(); + downloadJob = new DownloadChecksumJob(); + count = 0; + } + downloadJob.add(wrapperChecksumUrl); + } else { + String sha256 = read(sha256File); + allowed.add(sha256); + } + } catch (Exception e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + } + if (!downloadJob.isEmpty()) { + downloadJob.schedule(); + } + JobHelpers.waitForJobs(DownloadChecksumJob.WRAPPER_VALIDATOR_JOBS, new NullProgressMonitor()); + downloaded.set(true); + } catch (IOException | OperationCanceledException e) { + throw ExceptionFactory.newException(e); + } finally { + try { + Closeables.close(reader, false); + } catch (IOException e) { + // ignore + } + } + } + } + try { + String sha256 = hashProvider.getChecksum(wrapperJar.toFile()); + return new ValidationResult(wrapperJar.toString(), sha256, allowed.contains(sha256)); + } catch (IOException e) { + throw ExceptionFactory.newException(e); + } + } + + public static String getFileName(String url) { + int index = url.lastIndexOf("/"); + if (index < 0 || url.length() < index + 1) { + JavaLanguageServerPlugin.logInfo("Invalid wrapper URL " + url); + return null; + } + return url.substring(index + 1); + } + + private static String read(File file) { + Optional firstLine; + try { + firstLine = Files.lines(Paths.get(file.getAbsolutePath()), StandardCharsets.UTF_8).findFirst(); + } catch (IOException e) { + JavaLanguageServerPlugin.logException(e); + return null; + } + if (firstLine.isPresent()) { + return firstLine.get(); + } + return null; + } + + private static File getVersionCacheFile() { + return new File(System.getProperty("user.home"), ".tooling/gradle/versions.json"); + } + + public static File getSha256CacheFile() { + String checksumCache = System.getProperty("gradle.checksum.cacheDir"); + File file; + if (checksumCache == null || checksumCache.isEmpty()) { + file = new File(System.getProperty("user.home"), ".tooling/gradle/checksums"); + } else { + file = new File(checksumCache); + } + file.mkdirs(); + return file; + } + + public static void clear() { + allowed.clear(); + disallowed.clear(); + } + + public static void allow(Collection c) { + allowed.addAll(c); + } + + public static void allow(String checksum) { + allowed.add(checksum); + } + + public static void disallow(Collection c) { + disallowed.addAll(c); + } + + public static boolean contains(String checksum) { + return disallowed.contains(checksum); + } + + public static int size() { + return allowed.size() + disallowed.size(); + } + +} diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/build.gradle b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/build.gradle new file mode 100644 index 0000000000..cc67a20f14 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/build.gradle @@ -0,0 +1,33 @@ +/* + * This build file was auto generated by running the Gradle 'init' task + * by 'fbricon' at '24/10/16 11:28' with Gradle 3.0 + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at https://docs.gradle.org/3.0/userguide/tutorial_java_projects.html + */ + +// Apply the java plugin to add support for Java +apply plugin: 'java' +apply plugin: 'eclipse' + +sourceCompatibility = 1.8 + +// In this section you declare where to find the dependencies of your project +repositories { + // Use 'jcenter' for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +// In this section you declare the dependencies for your production and test code +dependencies { + // The production code uses the SLF4J logging API at compile time + compile 'org.slf4j:slf4j-api:1.7.21' + + // Declare the dependency for your favourite test framework you want to use in your tests. + // TestNG is also supported by the Gradle Test task. Just change the + // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add + // 'test.useTestNG()' to your build script. + testCompile 'junit:junit:4.12' +} diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle.properties b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle.properties new file mode 100644 index 0000000000..792d600548 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle.properties @@ -0,0 +1 @@ +# diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..2713e396b3 Binary files /dev/null and b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.jar differ diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..e80808e58f --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat May 09 17:34:24 CEST 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew new file mode 100755 index 0000000000..cccdd3d517 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew.bat b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew.bat new file mode 100644 index 0000000000..e95643d6a2 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/settings.gradle b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/settings.gradle new file mode 100644 index 0000000000..9d527fdf87 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/settings.gradle @@ -0,0 +1,19 @@ +/* + * This settings file was auto generated by the Gradle buildInit task + * by 'fbricon' at '24/10/16 11:28' with Gradle 3.0 + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/3.0/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'gradle-4.0' diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/main/java/Library.java b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/main/java/Library.java new file mode 100644 index 0000000000..526aadc25a --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/main/java/Library.java @@ -0,0 +1,11 @@ +/* + * This Java source file was auto generated by running 'gradle buildInit --type java-library' + * by 'fbricon' at '24/10/16 11:28' with Gradle 3.0 + * + * @author fbricon, @date 24/10/16 11:28 + */ +public class Library { + public boolean someLibraryMethod() { + return true; + } +} diff --git a/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/test/java/LibraryTest.java b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/test/java/LibraryTest.java new file mode 100644 index 0000000000..af8df3303c --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/gradle/gradle-4.0/src/test/java/LibraryTest.java @@ -0,0 +1,15 @@ +import org.junit.Test; +import static org.junit.Assert.*; + +/* + * This Java source file was auto generated by running 'gradle init --type java-library' + * by 'fbricon' at '24/10/16 11:28' with Gradle 3.0 + * + * @author fbricon, @date 24/10/16 11:28 + */ +public class LibraryTest { + @Test public void testSomeLibraryMethod() { + Library classUnderTest = new Library(); + assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); + } +} diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/WrapperValidatorTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/WrapperValidatorTest.java new file mode 100644 index 0000000000..ea85e40b27 --- /dev/null +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/WrapperValidatorTest.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2020 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.ls.core.internal.managers; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.preferences.Preferences; +import org.eclipse.jdt.ls.internal.gradle.checksums.ValidationResult; +import org.eclipse.jdt.ls.internal.gradle.checksums.WrapperValidator; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * @author snjeza + * + */ +@RunWith(MockitoJUnitRunner.class) +public class WrapperValidatorTest extends AbstractGradleBasedTest{ + + @Before + public void setProperty() throws Exception { + System.setProperty("gradle.checksum.cacheDir", "target/gradle/checksums"); + WrapperValidator.clear(); + } + + @After + public void clearProperty() throws IOException { + System.clearProperty("gradle.checksum.cacheDir"); + } + + @Test + public void testGradleWrapper() throws Exception { + File file = new File(getSourceProjectDirectory(), "gradle/simple-gradle"); + assertTrue(file.isDirectory()); + File sha256Directory = WrapperValidator.getSha256CacheFile(); + assertTrue(sha256Directory.isDirectory()); + ValidationResult result = new WrapperValidator(100).checkWrapper(file.getAbsolutePath()); + assertTrue(result.isValid()); + // test cache + assertTrue(sha256Directory.isDirectory()); + String message = Files.list(Paths.get(sha256Directory.getAbsolutePath())).collect(Collectors.toList()).toString(); + file = new File(sha256Directory, "gradle-6.3-wrapper.jar.sha256"); + assertTrue(message, file.isFile()); + String sha256 = Files.lines(Paths.get(file.getAbsolutePath()), StandardCharsets.UTF_8).findFirst().get(); + assertEquals("1cef53de8dc192036e7b0cc47584449b0cf570a00d560bfaa6c9eabe06e1fc06", sha256); + } + + @Test + public void testMissingSha256() throws Exception { + Preferences prefs = JavaLanguageServerPlugin.getPreferencesManager().getPreferences(); + List allowed = prefs.getSha256Allowed(); + int size = WrapperValidator.size(); + WrapperValidator wrapperValidator = new WrapperValidator(100); + File file = new File(getSourceProjectDirectory(), "gradle/gradle-4.0"); + List sha256 = new ArrayList<>(); + try { + sha256.add("41c8aa7a337a44af18d8cda0d632ebba469aef34f3041827624ef5c1a4e4419d"); + prefs.putSha256(null, sha256); + assertTrue(file.isDirectory()); + ValidationResult result = wrapperValidator.checkWrapper(file.getAbsolutePath()); + assertFalse(result.isValid()); + size = WrapperValidator.size(); + assertNotNull(result.getChecksum()); + prefs.putSha256(sha256, null); + result = wrapperValidator.checkWrapper(file.getAbsolutePath()); + assertTrue(result.isValid()); + } finally { + prefs.putSha256(allowed, null); + prefs.putSha256(sha256, null); + wrapperValidator.checkWrapper(file.getAbsolutePath()); + assertEquals(size, WrapperValidator.size()); + } + } +}