1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-29 18:52:13 +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() { public List<BoardPort> discovery() {
List<BoardPort> res = new ArrayList<BoardPort>(); List<BoardPort> res = new ArrayList<BoardPort>();
for (Discovery d : discoverers) for (Discovery d : discoverers) {
res.addAll(d.discovery()); res.addAll(d.discovery());
}
return res; 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.SSHUploader;
import cc.arduino.packages.uploaders.SerialUploader; 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; import processing.app.debug.TargetBoard;
public class UploaderAndMonitorFactory { public class UploaderAndMonitorFactory {
public Uploader newUploader(TargetBoard board, String port) { public Uploader newUploader(TargetBoard board, BoardPort port) {
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && Constants.IPV4_ADDRESS.matcher(port).find()) { if ("true".equals(board.getPreferences().get("upload.via_ssh")) && "network".equals(port.getProtocol())) {
return new SSHUploader(port); return new SSHUploader(port);
} }
return new SerialUploader(); return new SerialUploader();
} }
public AbstractMonitor newMonitor(String port, Base base) { public AbstractMonitor newMonitor(BoardPort port, Base base) {
if (Constants.IPV4_ADDRESS.matcher(port).find()) { if ("network".equals(port.getProtocol())) {
return new NetworkMonitor(port, base); 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.BoardPort;
import cc.arduino.packages.Discovery; 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.Base;
import processing.app.helpers.NetUtils; import processing.app.helpers.NetUtils;
import processing.app.helpers.PreferencesMap; 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/) * 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.Channel;
import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import java.io.*; import java.io.*;

View File

@ -27,7 +27,7 @@
* Copyright 2013 Arduino LLC (http://www.arduino.cc/) * 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.Channel;
import com.jcraft.jsch.ChannelExec; 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; package cc.arduino.packages.uploaders;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader; import cc.arduino.packages.Uploader;
import cc.arduino.packages.uploaders.ssh.SCP; import cc.arduino.packages.ssh.*;
import cc.arduino.packages.uploaders.ssh.SSH;
import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import processing.app.Base; import processing.app.Base;
import processing.app.Constants;
import processing.app.NetworkMonitor;
import processing.app.Preferences; import processing.app.Preferences;
import processing.app.debug.RunnerException; import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform; import processing.app.debug.TargetPlatform;
@ -48,7 +46,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import static processing.app.I18n._; 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 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) { public SSHUploader(BoardPort port) {
Matcher matcher = Constants.IPV4_ADDRESS.matcher(port); this.port = port;
if (!matcher.find()) {
throw new IllegalArgumentException(port);
}
ipAddress = matcher.group();
} }
public boolean requiresAuthorization() { public boolean requiresAuthorization() {
return true; return true;
} }
@Override
public String getAuthorizationKey() { public String getAuthorizationKey() {
return "runtime.pwd." + ipAddress; return "runtime.pwd." + port.getAddress();
} }
@Override @Override
@ -84,10 +78,10 @@ public class SSHUploader extends Uploader {
SCP scp = null; SCP scp = null;
try { try {
JSch jSch = new JSch(); JSch jSch = new JSch();
session = jSch.getSession("root", ipAddress, 22); SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
session.setPassword(Preferences.get(getAuthorizationKey())); session = sshClientSetupChain.setup(port, jSch);
session.setUserInfo(new NetworkMonitor.NoInteractionUserInfo()); session.setUserInfo(new NoInteractionUserInfo(Preferences.get("runtime.pwd." + port.getAddress())));
session.connect(30000); session.connect(30000);
scp = new SCP(session); scp = new SCP(session);
@ -97,7 +91,8 @@ public class SSHUploader extends Uploader {
return runAVRDude(ssh); return runAVRDude(ssh);
} catch (JSchException e) { } catch (JSchException e) {
if ("Auth cancel".equals(e.getMessage())) { String message = e.getMessage();
if ("Auth cancel".equals(message) || "Auth fail".equals(message)) {
return false; return false;
} }
throw new RunnerException(e); 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(); //PdeKeywords keywords = new PdeKeywords();
//sketchbook = new Sketchbook(this); //sketchbook = new Sketchbook(this);
if (serialMonitor == null) {
serialMonitor = new UploaderAndMonitorFactory().newMonitor(Preferences.get("serial.port"), base);
serialMonitor.setIconImage(getIconImage());
}
buildMenuBar(); buildMenuBar();
// For rev 0120, placing things inside a JPanel // 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)); Preferences.set("serial.port.file", name.substring(5));
else else
Preferences.set("serial.port.file", name); Preferences.set("serial.port.file", name);
if (serialMonitor != null) {
try { try {
serialMonitor.close(); serialMonitor.close();
serialMonitor.setVisible(false);
} catch (Exception e) { } catch (Exception e) {
// ignore // ignore
} }
serialMonitor.setVisible(false); }
serialMonitor = new UploaderAndMonitorFactory().newMonitor(Preferences.get("serial.port"), base);
onBoardOrPortChange(); onBoardOrPortChange();
@ -2389,8 +2385,10 @@ public class Editor extends JFrame implements RunnerListener {
public void run() { public void run() {
try { try {
if (serialMonitor != null) {
serialMonitor.close(); serialMonitor.close();
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
}
uploading = true; uploading = true;
@ -2429,8 +2427,10 @@ public class Editor extends JFrame implements RunnerListener {
public void run() { public void run() {
try { try {
if (serialMonitor != null) {
serialMonitor.close(); serialMonitor.close();
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
}
uploading = true; uploading = true;
@ -2502,6 +2502,19 @@ public class Editor extends JFrame implements RunnerListener {
public void handleSerial() { public void handleSerial() {
if (uploading) return; 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; boolean success = false;
do { do {
if (serialMonitor.requiresAuthorization() && !Preferences.has(serialMonitor.getAuthorizationKey())) { if (serialMonitor.requiresAuthorization() && !Preferences.has(serialMonitor.getAuthorizationKey())) {

View File

@ -1,5 +1,10 @@
package processing.app; 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 com.jcraft.jsch.*;
import processing.app.debug.MessageSiphon; import processing.app.debug.MessageSiphon;
@ -9,7 +14,6 @@ import java.awt.event.ActionListener;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.regex.Matcher;
import static processing.app.I18n._; import static processing.app.I18n._;
@ -18,6 +22,7 @@ public class NetworkMonitor extends AbstractMonitor {
private static final int MAX_CONNECTION_ATTEMPTS = 5; private static final int MAX_CONNECTION_ATTEMPTS = 5;
private final BoardPort port;
private final String ipAddress; private final String ipAddress;
private MessageSiphon inputConsumer; private MessageSiphon inputConsumer;
@ -26,12 +31,10 @@ public class NetworkMonitor extends AbstractMonitor {
private MessageSiphon errorConsumer; private MessageSiphon errorConsumer;
private int connectionAttempts; private int connectionAttempts;
public NetworkMonitor(String port, Base base) { public NetworkMonitor(BoardPort port, Base base) {
super(port); super(port.getLabel());
this.port = port;
Matcher matcher = Constants.IPV4_ADDRESS.matcher(port); this.ipAddress = port.getAddress();
matcher.find();
this.ipAddress = matcher.group();
onSendCommand(new ActionListener() { onSendCommand(new ActionListener() {
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
@ -63,10 +66,10 @@ public class NetworkMonitor extends AbstractMonitor {
this.connectionAttempts = 0; this.connectionAttempts = 0;
JSch jSch = new JSch(); JSch jSch = new JSch();
session = jSch.getSession("root", ipAddress, 22); SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup());
session.setPassword(Preferences.get(getAuthorizationKey())); session = sshClientSetupChain.setup(port, jSch);
session.setUserInfo(new NoInteractionUserInfo()); session.setUserInfo(new NoInteractionUserInfo(Preferences.get(getAuthorizationKey())));
session.connect(30000); session.connect(30000);
tryConnect(); 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; package processing.app;
import cc.arduino.packages.BoardPort;
import processing.core.PApplet; import processing.core.PApplet;
import java.awt.*; import java.awt.*;
@ -32,10 +33,10 @@ public class SerialMonitor extends AbstractMonitor {
private Serial serial; private Serial serial;
private int serialRate; private int serialRate;
public SerialMonitor(String port) { public SerialMonitor(BoardPort port) {
super(port); super(port.getLabel());
this.port = port; this.port = port.getAddress();
serialRate = Preferences.getInteger("serial.debug_rate"); serialRate = Preferences.getInteger("serial.debug_rate");
serialRates.setSelectedItem(serialRate + " " + _("baud")); serialRates.setSelectedItem(serialRate + " " + _("baud"));

View File

@ -23,6 +23,7 @@
package processing.app; package processing.app;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.UploaderAndMonitorFactory; import cc.arduino.packages.UploaderAndMonitorFactory;
import cc.arduino.packages.Uploader; import cc.arduino.packages.Uploader;
@ -1667,7 +1668,9 @@ public class Sketch {
TargetPlatform target = Base.getTargetPlatform(); TargetPlatform target = Base.getTargetPlatform();
String board = Preferences.get("board"); 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; boolean success = false;
do { do {

View File

@ -1,5 +1,6 @@
package processing.app.debug; package processing.app.debug;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader; import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderAndMonitorFactory; import cc.arduino.packages.UploaderAndMonitorFactory;
import cc.arduino.packages.uploaders.SSHUploader; import cc.arduino.packages.uploaders.SSHUploader;
@ -24,7 +25,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfSSHUploader() throws Exception { public void shouldCreateAnInstanceOfSSHUploader() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun"); 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); assertTrue(uploader instanceof SSHUploader);
} }
@ -32,7 +37,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfBasicUploaderWhenSSHIsUnsupported() throws Exception { public void shouldCreateAnInstanceOfBasicUploaderWhenSSHIsUnsupported() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno"); 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); assertTrue(uploader instanceof SerialUploader);
} }
@ -40,7 +49,11 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test @Test
public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception { public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno"); 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); assertTrue(uploader instanceof SerialUploader);
} }