Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

[985][2647] Manage Secure and Non-Secure Template Sources #137

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions dev/src/main/java/org/eclipse/codewind/intellij/core/HttpUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018, 2019 IBM Corporation and others.
* Copyright (c) 2018, 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand All @@ -12,7 +12,6 @@
package org.eclipse.codewind.intellij.core;

import okhttp3.*;
import org.eclipse.codewind.intellij.core.cli.AuthToken;
import org.json.JSONArray;
import org.json.JSONObject;

Expand Down Expand Up @@ -130,55 +129,55 @@ public static HttpResult get(URI uri) throws IOException {
return get(uri, null);
}

public static HttpResult get(URI uri, AuthToken auth) throws IOException {
public static HttpResult get(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("GET", uri, auth, null);
}

public static HttpResult get(URI uri, AuthToken auth, int connectTimeoutMS, int readTimeoutMS) throws IOException {
public static HttpResult get(URI uri, IAuthInfo auth, int connectTimeoutMS, int readTimeoutMS) throws IOException {
return sendRequest("GET", uri, auth, null, connectTimeoutMS, readTimeoutMS);
}

public static HttpResult post(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("POST", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult post(URI uri, AuthToken auth, JSONObject payload, int readTimeoutSeconds) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth, JSONObject payload, int readTimeoutSeconds) throws IOException {
return sendRequest("POST", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, readTimeoutSeconds * 1000);
}

public static HttpResult post(URI uri, AuthToken auth) throws IOException {
public static HttpResult post(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("POST", uri, auth, null);
}

public static HttpResult put(URI uri, AuthToken auth) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("PUT", uri, auth, null);
}

public static HttpResult put(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("PUT", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult put(URI uri, AuthToken auth, JSONObject payload, int readTimoutSeconds) throws IOException {
public static HttpResult put(URI uri, IAuthInfo auth, JSONObject payload, int readTimoutSeconds) throws IOException {
return sendRequest("PUT", uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult head(URI uri, AuthToken auth) throws IOException {
public static HttpResult head(URI uri, IAuthInfo auth) throws IOException {
return sendRequest("HEAD", uri, auth, null);
}

public static HttpResult delete(URI uri, AuthToken auth) throws IOException {
public static HttpResult delete(URI uri, IAuthInfo auth) throws IOException {
return delete(uri, auth, null);
}

public static HttpResult delete(URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult delete(URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest("DELETE", uri, auth, payload);
}

public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSONObject payload) throws IOException {
public static HttpResult sendRequest(String method, URI uri, IAuthInfo auth, JSONObject payload) throws IOException {
return sendRequest(method, uri, auth, payload, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_READ_TIMEOUT_MS);
}

public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSONObject payload, int connectTimeoutMS, int readTimeoutMS) throws IOException {
public static HttpResult sendRequest(String method, URI uri, IAuthInfo auth, JSONObject payload, int connectTimeoutMS, int readTimeoutMS) throws IOException {
HttpURLConnection connection = null;
if (payload != null) {
Logger.log("Making a " + method + " request on " + uri + " with payload: " + payload.toString());
Expand Down Expand Up @@ -210,11 +209,11 @@ public static HttpResult sendRequest(String method, URI uri, AuthToken auth, JSO
}
}

private static void addAuthorization(HttpURLConnection connection, AuthToken auth) {
if (sslContext == null || auth == null || auth.getToken() == null || auth.getTokenType() == null || !(connection instanceof HttpsURLConnection)) {
private static void addAuthorization(HttpURLConnection connection, IAuthInfo auth) {
if (sslContext == null || auth == null || !auth.isValid() || !(connection instanceof HttpsURLConnection)) {
return;
}
connection.setRequestProperty("Authorization", auth.getTokenType() + " " + auth.getToken());
connection.setRequestProperty("Authorization", auth.getHttpAuthorization());
((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
((HttpsURLConnection)connection).setHostnameVerifier(hostnameVerifier);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.codewind.intellij.core;

public interface IAuthInfo {
public boolean isValid();
public String getHttpAuthorization();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

package org.eclipse.codewind.intellij.core.cli;

import org.eclipse.codewind.intellij.core.IAuthInfo;
import org.eclipse.codewind.intellij.core.connection.JSONObjectResult;
import org.json.JSONObject;

public class AuthToken extends JSONObjectResult {
public class AuthToken extends JSONObjectResult implements IAuthInfo {

private static final String ACCESS_TOKEN_KEY = "access_token";
private static final String TOKEN_TYPE_KEY = "token_type";
Expand All @@ -31,4 +32,15 @@ public String getTokenType() {
return getString(TOKEN_TYPE_KEY);
}

@Override
public boolean isValid() {
return getToken() != null && getTokenType() != null;
}

@Override
public String getHttpAuthorization() {
return getTokenType() + " " + getToken();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static ProcessBuilder createCWCTLProcess(String[] globalOptions, String[]
addOptions(cmdList, cmd);
addOptions(cmdList, options);
addOptions(cmdList, args);
Logger.log(cmdList.stream().collect(Collectors.joining(" ")));
// Logger.log(cmdList.stream().collect(Collectors.joining(" ")));
String[] command = cmdList.toArray(new String[cmdList.size()]);
ProcessBuilder builder = new ProcessBuilder(command);
if (PlatformUtil.getOS() == PlatformUtil.OperatingSystem.MAC) {
Expand Down Expand Up @@ -182,13 +182,13 @@ public static void checkResult(String[] command, ProcessResult result, boolean c
// system output.
// Expected format:
// {"error":"con_not_found","error_description":"Connection AGALJKAFD not found"}
String commandName = command.length > 0 ? command[0] : ""; // cwctl with no parameter;
try {
if (result.getOutput() != null && !result.getOutput().isEmpty()) {
JSONObject obj = new JSONObject(result.getOutput());
if (obj.has(ERROR_KEY) && obj.has(ERROR_DESCRIPTION_KEY)) {
String msg = String.format("The cwctl '%s' command failed with error: %s", CoreUtil.formatString(command, " "), obj.getString(ERROR_DESCRIPTION_KEY)); //$NON-NLS-1$
Logger.logWarning(msg);
throw new IOException(obj.getString(ERROR_DESCRIPTION_KEY));
String msg = String.format("The cwctl '%s' command failed with error: %s", commandName, obj.getString(ERROR_DESCRIPTION_KEY)); //$NON-NLS-1$
throw new CLIException(obj.getString(ERROR_KEY), obj.getString(ERROR_DESCRIPTION_KEY));
}
}
} catch (JSONException e) {
Expand All @@ -199,19 +199,27 @@ public static void checkResult(String[] command, ProcessResult result, boolean c
String msg;
String error = result.getError() != null && !result.getError().isEmpty() ? result.getError() : result.getOutput();
if (error == null || error.isEmpty()) {
msg = String.format("The cwctl '%s' command exited with return code %d", CoreUtil.formatString(command, " "), result.getExitValue()); //$NON-NLS-1$
msg = String.format("The cwctl '%s' command exited with return code %d", commandName, result.getExitValue());
} else {
msg = String.format("The cwctl '%s' command exited with return code %d and error: %s", CoreUtil.formatString(command, " "), result.getExitValue(), error); //$NON-NLS-1$
msg = String.format("The cwctl '%s' command exited with return code %d and error: %s", commandName, result.getExitValue(), error);
}
Logger.logWarning(msg);
throw new IOException(msg);
} else if (checkOutput && (result.getOutput() == null || result.getOutput().isEmpty())) {
String msg = String.format("The cwctl '%s' command exited with return code 0 but the output was empty", CoreUtil.formatString(command, " ")); //$NON-NLS-1$
Logger.logWarning(msg);
String msg = String.format("The cwctl '%s' command exited with return code 0 but the output was empty", commandName); //$NON-NLS-1$
throw new IOException(msg);
}

Logger.log(String.format("Result of the cwctl '%s' command: \n%s", CoreUtil.formatString(command, " "), Optional.ofNullable(result.getOutput()).orElse("<empty>")));
}

@SuppressWarnings("serial")
public static class CLIException extends IOException {

public final String errorId;
public final String errorMsg;

public CLIException(String errorId, String errorMsg) {
super(errorMsg);
this.errorId = errorId;
this.errorMsg = errorMsg;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public class TemplateUtil {
private static final String URL_OPTION = "--url";
private static final String NAME_OPTION = "--name";
private static final String DESCRIPTION_OPTION = "--description";
private static final String USERNAME_OPTION = "--username";
private static final String PASSWORD_OPTION = "--password";
private static final String PERSONAL_ACCESS_TOKEN_OPTION = "--personalAccessToken";


public static List<ProjectTemplateInfo> listTemplates(boolean enabledOnly, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
monitor.setIndeterminate(true);
Expand Down Expand Up @@ -84,7 +88,29 @@ public static List<RepositoryInfo> listTemplateSources(String conid, ProgressInd
}
}
}


public static void addTemplateSource(String url, String username, String password, String accessToken, String name, String description, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
List<String> options = new ArrayList<String>();
options.add(URL_OPTION);
options.add(url);
if (username != null && password != null) {
options.add(USERNAME_OPTION);
options.add(username);
options.add(PASSWORD_OPTION);
options.add(password);
} else if (accessToken != null) {
options.add(PERSONAL_ACCESS_TOKEN_OPTION);
options.add(accessToken);
}
options.add(NAME_OPTION);
options.add(name);
options.add(DESCRIPTION_OPTION);
options.add(description);
options.add(CLIUtil.CON_ID_OPTION);
options.add(conid);
runTemplateSourceCmd(REPO_ADD_CMD, options.toArray(new String[options.size()]), null, monitor);
}

public static void addTemplateSource(String url, String name, String description, String conid, ProgressIndicator monitor) throws IOException, JSONException, TimeoutException {
runTemplateSourceCmd(REPO_ADD_CMD, new String[] {URL_OPTION, url, NAME_OPTION, name, DESCRIPTION_OPTION, description, CLIUtil.CON_ID_OPTION, conid}, null, monitor);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import org.json.JSONException;
import org.json.JSONObject;

public abstract class JSONObjectResult {
public class JSONObjectResult {

protected final JSONObject result;
protected final String type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class CodewindToolWindow extends JBPanel<CodewindToolWindow> {
private final AnAction restartDebugModeAction;
private final AnAction attachDebuggerAction;
private final AnAction openShellAction;
private final AnAction manageReposAction;

private final AnAction newProjectAction;

Expand Down Expand Up @@ -113,6 +114,7 @@ public CodewindToolWindow() {
restartDebugModeAction = new RestartDebugModeAction();
attachDebuggerAction = new AttachDebuggerAction();
openShellAction = new OpenContainerShellAction();
manageReposAction = new ManageReposAction();

newProjectAction = new NewCodewindProjectAction();

Expand Down Expand Up @@ -275,6 +277,8 @@ private void handleLocalConnectionPopup(LocalConnection connection, Component co
actions.add(newProjectAction);
actions.add(addExistingProjectAction);
actions.addSeparator();
actions.add(manageReposAction);
actions.addSeparator();
InstallStatus status = CodewindManager.getManager().getInstallStatus();
if (status.isInstalled()) {
// a supported version of Codewind is installed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class IconCache {
public static final String ICONS_THEMELESS_PROJECT_TYPES_SPRING_SVG = "/icons/themeless/project-types/spring.svg";
public static final String ICONS_THEMELESS_PROJECT_TYPES_SWIFT_SVG = "/icons/themeless/project-types/swift.svg";
public static final String ICONS_CODEWIND_13PX_SVG = "/META-INF/pluginIcon13x13.svg";
public static final String ICONS_CODEWIND_BANNER_PNG = "/icons/codewindBanner.png";

private static final Map<String, Icon> iconCache = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.codewind.intellij.ui.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.ui.treeStructure.Tree;
import org.eclipse.codewind.intellij.core.CoreUtil;
import org.eclipse.codewind.intellij.core.Logger;
import org.eclipse.codewind.intellij.core.cli.TemplateUtil;
import org.eclipse.codewind.intellij.core.connection.CodewindConnection;
import org.eclipse.codewind.intellij.core.connection.RepositoryInfo;
import org.eclipse.codewind.intellij.ui.templates.RepositoryManagementDialog;
import org.jetbrains.annotations.NotNull;

import javax.swing.tree.TreePath;
import java.util.List;

import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
import static org.eclipse.codewind.intellij.ui.messages.CodewindUIBundle.message;


public class ManageReposAction extends AnAction {

public ManageReposAction() {
super(message("RepoMgmtActionLabel"));
}

@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
CodewindConnection connection = getSelection(e);
e.getPresentation().setEnabled(connection != null && connection.isConnected());
}

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
CodewindConnection connection = getSelection(e);
final List<RepositoryInfo>[] repoListArray = new List[1];
try {
ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
try {
ProgressIndicator mon = new EmptyProgressIndicator();
repoListArray[0] = TemplateUtil.listTemplateSources(connection.getConid(), mon);
} catch (Exception e1) {
Logger.logWarning("An error occurred trying to get the template sources for: " + connection.getName() + ": " + e1.getMessage());
}
}, message("RepoListTask", "connection"), false, e.getProject());
RepositoryManagementDialog dialog = new RepositoryManagementDialog(e.getProject(), connection, repoListArray[0]);
// Init must be done after
dialog.initForm();
boolean rc = dialog.showAndGet();
if (rc) {
dialog.updateRepos();
}
} catch (Exception ex) {
CoreUtil.openDialog(true, message("RepoListErrorTitle"), message("RepoListErrorMsg", ex));
}
}

private CodewindConnection getSelection(@NotNull AnActionEvent e) {
Object data = e.getData(CONTEXT_COMPONENT);
if (!(data instanceof Tree)) {
Logger.logDebug("Unrecognized component for : " + data);
return null;
}
Tree tree = (Tree) data;
TreePath treePath = tree.getSelectionPath();
if (treePath == null) {
Logger.logDebug("No selection path for ManageReposAction: " + tree);
return null;
}
Object node = treePath.getLastPathComponent();
if (!(node instanceof CodewindConnection)) {
return null;
}
return (CodewindConnection) node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ public abstract class AbstractCodewindDialogWrapper extends DialogWrapper {

private String helpUrl;

/**
* Note: init() should be called after the dialog wrapper has been instantiated
*
* @param project
* @param title
* @param helpUrl
*/
public AbstractCodewindDialogWrapper(Project project, String title, String helpUrl) {
super(project,true); // Can use current dialog window as parent for other child dialogs
init();
setTitle(title);
this.helpUrl = helpUrl;
}
Expand Down
Loading