1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-17 06:52:18 +01:00

Added support to openssh config file

This commit is contained in:
Federico Fissore 2013-10-10 15:52:35 +02:00
parent 88f7504e81
commit 9898fd7ae6
16 changed files with 266 additions and 94 deletions

View File

@ -73,9 +73,19 @@ public class DiscoveryManager {
public List<BoardPort> discovery() {
List<BoardPort> res = new ArrayList<BoardPort>();
for (Discovery d : discoverers)
for (Discovery d : discoverers) {
res.addAll(d.discovery());
}
return res;
}
public BoardPort find(String address) {
for (BoardPort boardPort : discovery()) {
if (boardPort.getAddress().equals(address)) {
return boardPort;
}
}
return null;
}
}

View File

@ -31,21 +31,24 @@ package cc.arduino.packages;
import cc.arduino.packages.uploaders.SSHUploader;
import cc.arduino.packages.uploaders.SerialUploader;
import processing.app.*;
import processing.app.AbstractMonitor;
import processing.app.Base;
import processing.app.NetworkMonitor;
import processing.app.SerialMonitor;
import processing.app.debug.TargetBoard;
public class UploaderAndMonitorFactory {
public Uploader newUploader(TargetBoard board, String port) {
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && Constants.IPV4_ADDRESS.matcher(port).find()) {
public Uploader newUploader(TargetBoard board, BoardPort port) {
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && "network".equals(port.getProtocol())) {
return new SSHUploader(port);
}
return new SerialUploader();
}
public AbstractMonitor newMonitor(String port, Base base) {
if (Constants.IPV4_ADDRESS.matcher(port).find()) {
public AbstractMonitor newMonitor(BoardPort port, Base base) {
if ("network".equals(port.getProtocol())) {
return new NetworkMonitor(port, base);
}

View File

@ -31,7 +31,7 @@ package cc.arduino.packages.discoverers;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Discovery;
import cc.arduino.packages.discoverers.network.NetworkChecker;
import cc.arduino.packages.discoverers.network.*;
import processing.app.Base;
import processing.app.helpers.NetUtils;
import processing.app.helpers.PreferencesMap;

View File

@ -0,0 +1,36 @@
package cc.arduino.packages.ssh;
import com.jcraft.jsch.UserInfo;
public class NoInteractionUserInfo implements UserInfo {
private final String password;
public NoInteractionUserInfo(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public boolean promptYesNo(String str) {
return true;
}
public String getPassphrase() {
return password;
}
public boolean promptPassphrase(String message) {
return true;
}
public boolean promptPassword(String message) {
return true;
}
public void showMessage(String message) {
}
}

View File

@ -27,11 +27,10 @@
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.uploaders.ssh;
package cc.arduino.packages.ssh;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.*;

View File

@ -27,7 +27,7 @@
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.uploaders.ssh;
package cc.arduino.packages.ssh;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;

View File

@ -0,0 +1,17 @@
package cc.arduino.packages.ssh;
import cc.arduino.packages.BoardPort;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.IOException;
public interface SSHClientSetupChainRing {
/*
Chain is actually useless as default JSCH behaviour is to follow SSH Server authentication methods list
*/
Session setup(BoardPort port, JSch jSch) throws JSchException, IOException;
}

View File

@ -0,0 +1,93 @@
package cc.arduino.packages.ssh;
import cc.arduino.packages.BoardPort;
import com.jcraft.jsch.*;
import java.io.File;
import java.io.IOException;
public class SSHConfigFileSetup implements SSHClientSetupChainRing {
private final SSHClientSetupChainRing nextChainRing;
public SSHConfigFileSetup(SSHClientSetupChainRing nextChainRing) {
this.nextChainRing = nextChainRing;
}
public Session setup(BoardPort port, JSch jSch) throws JSchException, IOException {
String ipAddress = port.getAddress();
String hostname = port.getBoardName().contains(".local") ? port.getBoardName() : port.getBoardName() + ".local";
File sshFolder = new File(System.getProperty("user.home"), ".ssh");
File sshConfig = new File(sshFolder, "config");
if (!sshFolder.exists() || !sshConfig.exists()) {
if (nextChainRing != null) {
return nextChainRing.setup(port, jSch);
}
throw new JSchException("Unable to find a way to connect");
}
OpenSSHConfig configRepository = OpenSSHConfig.parseFile(sshConfig.getAbsolutePath());
jSch.setConfigRepository(new OpenSSHConfigWrapper(configRepository, ipAddress));
return jSch.getSession(hostname);
}
public static class OpenSSHConfigWrapper implements ConfigRepository {
private final OpenSSHConfig config;
private final String ipAddress;
public OpenSSHConfigWrapper(OpenSSHConfig config, String ipAddress) {
this.config = config;
this.ipAddress = ipAddress;
}
@Override
public Config getConfig(String host) {
return new ConfigWrapper(config.getConfig(host), ipAddress);
}
}
public static class ConfigWrapper implements ConfigRepository.Config {
private final ConfigRepository.Config config;
private final String ipAddress;
public ConfigWrapper(OpenSSHConfig.Config config, String ipAddress) {
this.config = config;
this.ipAddress = ipAddress;
}
@Override
public String getHostname() {
return ipAddress;
}
@Override
public String getUser() {
String user = config.getUser();
if (user != null) {
return user;
}
return "root";
}
@Override
public int getPort() {
return config.getPort();
}
@Override
public String getValue(String key) {
return config.getValue(key);
}
@Override
public String[] getValues(String key) {
return config.getValues(key);
}
}
}

View File

@ -0,0 +1,21 @@
package cc.arduino.packages.ssh;
import cc.arduino.packages.BoardPort;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import processing.app.Preferences;
public class SSHPwdSetup implements SSHClientSetupChainRing {
@Override
public Session setup(BoardPort port, JSch jSch) throws JSchException {
String ipAddress = port.getAddress();
Session session = jSch.getSession("root", ipAddress, 22);
session.setPassword(Preferences.get("runtime.pwd." + ipAddress));
return session;
}
}

View File

@ -29,15 +29,13 @@
package cc.arduino.packages.uploaders;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.uploaders.ssh.SCP;
import cc.arduino.packages.uploaders.ssh.SSH;
import cc.arduino.packages.ssh.*;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import processing.app.Base;
import processing.app.Constants;
import processing.app.NetworkMonitor;
import processing.app.Preferences;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform;
@ -48,7 +46,6 @@ import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import static processing.app.I18n._;
@ -56,22 +53,19 @@ public class SSHUploader extends Uploader {
private static final List<String> FILES_NOT_TO_COPY = Arrays.asList(".DS_Store", ".Trash", "Thumbs.db", "__MACOSX");
private final String ipAddress;
private final BoardPort port;
public SSHUploader(String port) {
Matcher matcher = Constants.IPV4_ADDRESS.matcher(port);
if (!matcher.find()) {
throw new IllegalArgumentException(port);
}
ipAddress = matcher.group();
public SSHUploader(BoardPort port) {
this.port = port;
}
public boolean requiresAuthorization() {
return true;
}
@Override
public String getAuthorizationKey() {
return "runtime.pwd." + ipAddress;
return "runtime.pwd." + port.getAddress();
}
@Override
@ -84,10 +78,10 @@ public class SSHUploader extends Uploader {
SCP scp = null;
try {
JSch jSch = new JSch();
session = jSch.getSession("root", ipAddress, 22);
session.setPassword(Preferences.get(getAuthorizationKey()));
SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
session = sshClientSetupChain.setup(port, jSch);
session.setUserInfo(new NetworkMonitor.NoInteractionUserInfo());
session.setUserInfo(new NoInteractionUserInfo(Preferences.get("runtime.pwd." + port.getAddress())));
session.connect(30000);
scp = new SCP(session);
@ -97,7 +91,8 @@ public class SSHUploader extends Uploader {
return runAVRDude(ssh);
} catch (JSchException e) {
if ("Auth cancel".equals(e.getMessage())) {
String message = e.getMessage();
if ("Auth cancel".equals(message) || "Auth fail".equals(message)) {
return false;
}
throw new RunnerException(e);

View File

@ -1,9 +0,0 @@
package processing.app;
import java.util.regex.Pattern;
public class Constants {
public static final Pattern IPV4_ADDRESS = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
}

View File

@ -209,11 +209,6 @@ public class Editor extends JFrame implements RunnerListener {
//PdeKeywords keywords = new PdeKeywords();
//sketchbook = new Sketchbook(this);
if (serialMonitor == null) {
serialMonitor = new UploaderAndMonitorFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor.setIconImage(getIconImage());
}
buildMenuBar();
// For rev 0120, placing things inside a JPanel
@ -971,13 +966,14 @@ public class Editor extends JFrame implements RunnerListener {
Preferences.set("serial.port.file", name.substring(5));
else
Preferences.set("serial.port.file", name);
try {
serialMonitor.close();
} catch (Exception e) {
// ignore
if (serialMonitor != null) {
try {
serialMonitor.close();
serialMonitor.setVisible(false);
} catch (Exception e) {
// ignore
}
}
serialMonitor.setVisible(false);
serialMonitor = new UploaderAndMonitorFactory().newMonitor(Preferences.get("serial.port"), base);
onBoardOrPortChange();
@ -2389,8 +2385,10 @@ public class Editor extends JFrame implements RunnerListener {
public void run() {
try {
serialMonitor.close();
serialMonitor.setVisible(false);
if (serialMonitor != null) {
serialMonitor.close();
serialMonitor.setVisible(false);
}
uploading = true;
@ -2429,8 +2427,10 @@ public class Editor extends JFrame implements RunnerListener {
public void run() {
try {
serialMonitor.close();
serialMonitor.setVisible(false);
if (serialMonitor != null) {
serialMonitor.close();
serialMonitor.setVisible(false);
}
uploading = true;
@ -2502,6 +2502,19 @@ public class Editor extends JFrame implements RunnerListener {
public void handleSerial() {
if (uploading) return;
if (serialMonitor != null) {
try {
serialMonitor.close();
serialMonitor.setVisible(false);
} catch (Exception e) {
// noop
}
}
BoardPort port = Base.getDiscoveryManager().find(Preferences.get("serial.port"));
serialMonitor = new UploaderAndMonitorFactory().newMonitor(port, base);
serialMonitor.setIconImage(getIconImage());
boolean success = false;
do {
if (serialMonitor.requiresAuthorization() && !Preferences.has(serialMonitor.getAuthorizationKey())) {

View File

@ -1,5 +1,10 @@
package processing.app;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.ssh.NoInteractionUserInfo;
import cc.arduino.packages.ssh.SSHClientSetupChainRing;
import cc.arduino.packages.ssh.SSHConfigFileSetup;
import cc.arduino.packages.ssh.SSHPwdSetup;
import com.jcraft.jsch.*;
import processing.app.debug.MessageSiphon;
@ -9,7 +14,6 @@ import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.regex.Matcher;
import static processing.app.I18n._;
@ -18,6 +22,7 @@ public class NetworkMonitor extends AbstractMonitor {
private static final int MAX_CONNECTION_ATTEMPTS = 5;
private final BoardPort port;
private final String ipAddress;
private MessageSiphon inputConsumer;
@ -26,12 +31,10 @@ public class NetworkMonitor extends AbstractMonitor {
private MessageSiphon errorConsumer;
private int connectionAttempts;
public NetworkMonitor(String port, Base base) {
super(port);
Matcher matcher = Constants.IPV4_ADDRESS.matcher(port);
matcher.find();
this.ipAddress = matcher.group();
public NetworkMonitor(BoardPort port, Base base) {
super(port.getLabel());
this.port = port;
this.ipAddress = port.getAddress();
onSendCommand(new ActionListener() {
public void actionPerformed(ActionEvent event) {
@ -63,10 +66,10 @@ public class NetworkMonitor extends AbstractMonitor {
this.connectionAttempts = 0;
JSch jSch = new JSch();
session = jSch.getSession("root", ipAddress, 22);
session.setPassword(Preferences.get(getAuthorizationKey()));
SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
session = sshClientSetupChain.setup(port, jSch);
session.setUserInfo(new NoInteractionUserInfo());
session.setUserInfo(new NoInteractionUserInfo(Preferences.get(getAuthorizationKey())));
session.connect(30000);
tryConnect();
@ -161,30 +164,4 @@ public class NetworkMonitor extends AbstractMonitor {
}
}
public static class NoInteractionUserInfo implements UserInfo {
public String getPassword() {
return null;
}
public boolean promptYesNo(String str) {
return true;
}
public String getPassphrase() {
return null;
}
public boolean promptPassphrase(String message) {
return false;
}
public boolean promptPassword(String message) {
return false;
}
public void showMessage(String message) {
}
}
}

View File

@ -18,6 +18,7 @@
package processing.app;
import cc.arduino.packages.BoardPort;
import processing.core.PApplet;
import java.awt.*;
@ -32,10 +33,10 @@ public class SerialMonitor extends AbstractMonitor {
private Serial serial;
private int serialRate;
public SerialMonitor(String port) {
super(port);
public SerialMonitor(BoardPort port) {
super(port.getLabel());
this.port = port;
this.port = port.getAddress();
serialRate = Preferences.getInteger("serial.debug_rate");
serialRates.setSelectedItem(serialRate + " " + _("baud"));

View File

@ -23,6 +23,7 @@
package processing.app;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.UploaderAndMonitorFactory;
import cc.arduino.packages.Uploader;
@ -1667,7 +1668,9 @@ public class Sketch {
TargetPlatform target = Base.getTargetPlatform();
String board = Preferences.get("board");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(target.getBoards().get(board), Preferences.get("serial.port"));
BoardPort boardPort = Base.getDiscoveryManager().find(Preferences.get("serial.port"));
Uploader uploader = new UploaderAndMonitorFactory().newUploader(target.getBoards().get(board), boardPort);
boolean success = false;
do {

View File

@ -1,5 +1,6 @@
package processing.app.debug;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderAndMonitorFactory;
import cc.arduino.packages.uploaders.SSHUploader;
@ -24,7 +25,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfSSHUploader() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, "192.168.0.1 (yun)");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("yun");
boardPort.setAddress("192.168.0.1");
boardPort.setProtocol("network");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
assertTrue(uploader instanceof SSHUploader);
}
@ -32,7 +37,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenSSHIsUnsupported() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, "192.168.0.1 (myyun)");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("myyun");
boardPort.setAddress("192.168.0.1");
boardPort.setProtocol("network");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
assertTrue(uploader instanceof SerialUploader);
}
@ -40,7 +49,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, "/dev/ttyACM0 (Arduino Leonardo)");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("Arduino Leonardo");
boardPort.setAddress("/dev/ttyACM0");
boardPort.setProtocol("serial");
Uploader uploader = new UploaderAndMonitorFactory().newUploader(board, boardPort);
assertTrue(uploader instanceof SerialUploader);
}