package code; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileReader; import java.security.KeyPair; import java.security.KeyStore; import java.security.Security; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManagerFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttTopic; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public class Antifurto { private static String brokerUrl; private String interruttore; private String interruttoreOutputSuono; private String nomeOutputAntifurto; private static JSONArray sensori; // sensori di movimento private static ArrayList<String> topicsSub; private Date date = new Date(); private String clientId = Long.toString(date.getTime()) + "-sub-pub"; // unique client id private Automa automa; private MqttClient mqttClient; private static String mqttDomain; private static String mqttSubdomain; public static final String PATH_BB = "/home/debian/CONFIG/antifurto"; private final String CONF_FILE = PATH_BB + "/res/CONF/conf.json"; public static final String CONF_ZONA = PATH_BB + "/res/CONF/zona.json"; public Antifurto(Automa automa) throws JSONException, IOException, MqttException { this.automa = automa; JSONObject jsonObject = new JSONObject(Helper.leggiFile(CONF_FILE)); brokerUrl = jsonObject.getString("protocol") + "://" + jsonObject.getString("broker") + ":" + jsonObject.getInt("port"); mqttDomain = jsonObject.getString("mqttDomain"); mqttSubdomain = jsonObject.getString("mqttSubdomain"); topicsSub = new ArrayList<String>(); // Su questo topic ricevero' un messaggio del tipo {request:description} // Dovro' quindi mandare la mia descrizione json topicsSub.add("to/all"); // Su questo topic ricevero' le richieste di inviare il mio stato attuale topicsSub.add("rpc/"+getMqttTree()+"/antifurto"); jsonObject = new JSONObject(Helper.leggiFile(CONF_ZONA)); interruttore = jsonObject.getString("interruttore"); topicsSub.add("from/"+getMqttTree()+"/gpio/" + interruttore); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore // Per ogni sensore di movimento, sottoscrivo i messaggi che notificano il loro cambiamento di stato sensori = jsonObject.getJSONArray("sensoriMovimento"); for(int i=0; i<sensori.length(); i++) { topicsSub.add("from/"+getMqttTree()+"/gpio/" + sensori.get(i)); } nomeOutputAntifurto = jsonObject.getString("nomeOutputAntifurto"); topicsSub.add("from/"+getMqttTree()+"/gpio/" + nomeOutputAntifurto); interruttoreOutputSuono = jsonObject.getString("outputSuono"); topicsSub.add("from/"+getMqttTree()+"/gpio/" + interruttoreOutputSuono); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore topicsSub.add("conf/"+getMqttTree()+"/antifurto/soglia"); // Su questo topic mi arrivera' un messaggio {"soglia": 30} e dovro' impostare la soglia di conseguenza topicsSub.add("conf/"+getMqttTree()+"/antifurto"); topicsSub.add("conf/"+getMqttTree()+"/antifurto/sensore"); // Su questo topic mi arrivera' un messaggio per l'aggiunta di un sensore di movimento. // Ad esempio se mi arriva il messaggio {"in": "IN3", "delta":33 } devo aggiungere il sensore di movimento che si // chiama IN3, il cui valore di delta e' 33 (devo quindi aggiornare il file deltaSensoriMovimento.json topicsSub.add("to/"+getMqttTree()+"/antifurto/luceAntifurto"); this.mqttClient = new MqttClient(brokerUrl, clientId, new MemoryPersistence()); } public void startClient(Esecutore esec, Publisher publisher) throws MqttException, JSONException { String caFilePath = ""; String clientCrtFilePath = ""; String clientKeyFilePath = ""; MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(false); if(brokerUrl.contains("luci.local")) { // devo connettermi al mosquitto della beaglebone caFilePath = PATH_BB + "/certificates/beaglebone/caGruppo2.crt"; clientCrtFilePath = PATH_BB + "/certificates/beaglebone/clientGruppo2.crt"; clientKeyFilePath = PATH_BB + "/certificates/beaglebone/clientGruppo2.key"; options.setUserName("gruppo2"); options.setPassword("funziona".toCharArray()); } else { System.out.println("Unknown broken url " + brokerUrl); System.exit(1); } options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1); SSLSocketFactory socketFactory; try { socketFactory = getSocketFactory(caFilePath, clientCrtFilePath, clientKeyFilePath, ""); options.setSocketFactory(socketFactory); } catch (Exception e) { e.printStackTrace(); } SubscribeCallback subCall = new SubscribeCallback(this, publisher, esec, automa); mqttClient.setCallback(subCall); mqttClient.connect(options); for(String t: topicsSub) addTopicToSubscribe(t); subCall.sendOutAntifurto(); } // sottoscrive il topic passato come parametro public void addTopicToSubscribe(String topic) throws MqttException { mqttClient.subscribe(topic); } public void publishMethod(String topic, String msg) throws MqttException { final MqttTopic msgTopic = mqttClient.getTopic(topic); msgTopic.publish(new MqttMessage(msg.getBytes())); } public static void main(String args[]) throws JSONException, IOException { boolean exc = true; System.out.println("antifurto started"); while(true) { if(exc) { try { startSystem(); exc = false; } catch(MqttException e) { System.out.println("Error: "+ e.getMessage() + "\nRestarting system..."); e.printStackTrace(); exc = true; } } } } private static void startSystem() throws JSONException, IOException, MqttException { MyQueue<Integer> codaVal = new MyQueue<Integer>(); MyQueue<Pair> codaMsg = new MyQueue<Pair>(); Automa automa = new Automa(); Antifurto antifurto = new Antifurto(automa); Publisher publisher = new Publisher(codaMsg, antifurto); Esecutore esec = new Esecutore(publisher, codaVal, automa, antifurto); Timer timer = new Timer(6000,-1,esec,automa); antifurto.startClient(esec, publisher); publisher.start(); esec.start(); timer.start(); } public static String getMqttTree() { return mqttDomain+"/"+mqttSubdomain; } public static JSONArray getSensori() { return sensori; } public static void addSensore(String newSensore) { // aggiunge un sensore di movimento sensori.put(newSensore); } public String getNomeInterruttoreAntifurto() { return interruttore; } public String getNomeOutputAntifurto() { return nomeOutputAntifurto; } public String getNomeOutputSuono() { return interruttoreOutputSuono; } public void setNomeInterruttoreAntifurto(String nuovoNome) { if(nuovoNome.startsWith("IN")) this.interruttore = nuovoNome; } public void setNomeOutputAntifurto(String nuovoNome) { if(nuovoNome.startsWith("OUT")) this.nomeOutputAntifurto = nuovoNome; } public void setNomeOutputSuono(String nuovoNome) { if(nuovoNome.startsWith("OUT")) this.interruttoreOutputSuono = nuovoNome; } public void unsubscribeTopic(String topic) throws MqttException { mqttClient.unsubscribe(topic); } private static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile, final String password) throws Exception { Security.addProvider(new BouncyCastleProvider()); // load CA certificate X509Certificate caCert = null; FileInputStream fis = new FileInputStream(caCrtFile); BufferedInputStream bis = new BufferedInputStream(fis); CertificateFactory cf = CertificateFactory.getInstance("X.509"); while (bis.available() > 0) { caCert = (X509Certificate) cf.generateCertificate(bis); } // load client certificate bis = new BufferedInputStream(new FileInputStream(crtFile)); X509Certificate cert = null; while (bis.available() > 0) { cert = (X509Certificate) cf.generateCertificate(bis); } // load client private key PEMParser pemParser = new PEMParser(new FileReader(keyFile)); Object object = pemParser.readObject(); PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder() .build(password.toCharArray()); JcaPEMKeyConverter converter = new JcaPEMKeyConverter() .setProvider("BC"); KeyPair key; if (object instanceof PEMEncryptedKeyPair) { //System.out.println("Encrypted key - we will use provided password"); key = converter.getKeyPair(((PEMEncryptedKeyPair) object) .decryptKeyPair(decProv)); } else { //System.out.println("Unencrypted key - no password needed"); key = converter.getKeyPair((PEMKeyPair) object); } pemParser.close(); // CA certificate is used to authenticate server KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType()); caKs.load(null, null); caKs.setCertificateEntry("ca-certificate", caCert); TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(caKs); // client key and certificates are sent to server so it can authenticate // us KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(null, null); ks.setCertificateEntry("certificate", cert); ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[] { cert }); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory .getDefaultAlgorithm()); kmf.init(ks, password.toCharArray()); // finally, create SSL socket factory SSLContext context = SSLContext.getInstance("TLSv1.2"); context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return context.getSocketFactory(); } }