diff --git a/app/src/main/java/fr/chteufleur/mytrackingdog/models/beans/RandomString.java b/app/src/main/java/fr/chteufleur/mytrackingdog/models/beans/RandomString.java new file mode 100644 index 0000000..e5962d2 --- /dev/null +++ b/app/src/main/java/fr/chteufleur/mytrackingdog/models/beans/RandomString.java @@ -0,0 +1,61 @@ +package fr.chteufleur.mytrackingdog.models.beans; + +import java.security.SecureRandom; +import java.util.Locale; +import java.util.Objects; +import java.util.Random; + +public class RandomString { + + /** + * Generate a random string. + */ + public String nextString() { + for (int idx = 0; idx < buf.length; ++idx) + buf[idx] = symbols[random.nextInt(symbols.length)]; + return new String(buf); + } + + public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static final String lower = upper.toLowerCase(Locale.ROOT); + + public static final String digits = "0123456789"; + + public static final String alphanum = upper + lower + digits; + + private final Random random; + + private final char[] symbols; + + private final char[] buf; + + public RandomString(int length, Random random, String symbols) { + if (length < 1) throw new IllegalArgumentException(); + if (symbols.length() < 2) throw new IllegalArgumentException(); + this.random = Objects.requireNonNull(random); + this.symbols = symbols.toCharArray(); + this.buf = new char[length]; + } + + /** + * Create an alphanumeric string generator. + */ + public RandomString(int length, Random random) { + this(length, random, alphanum); + } + + /** + * Create an alphanumeric strings from a secure generator. + */ + public RandomString(int length) { + this(length, new SecureRandom()); + } + + /** + * Create session identifiers. + */ + public RandomString() { + this(36); + } +} diff --git a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceTrackingDog.java b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceTrackingDog.java index 3e90276..a3e7a8f 100644 --- a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceTrackingDog.java +++ b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceTrackingDog.java @@ -69,7 +69,7 @@ public class ServiceTrackingDog implements Observer { this.serviceGps.addObserver(this); ServiceXmpp sx; try { - sx = new ServiceXmpp(resources); + sx = new ServiceXmpp(preferences, resources); sx.addObserver(this); } catch (UnknownHostException | XmppStringprepException ex) { sx = null; diff --git a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceXmpp.java b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceXmpp.java index 147d04f..41604ff 100644 --- a/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceXmpp.java +++ b/app/src/main/java/fr/chteufleur/mytrackingdog/services/ServiceXmpp.java @@ -1,5 +1,6 @@ package fr.chteufleur.mytrackingdog.services; +import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Environment; import android.os.StrictMode; @@ -9,7 +10,9 @@ import com.google.zxing.WriterException; import org.jivesoftware.smack.AbstractXMPPConnection; import org.jivesoftware.smack.ConnectionConfiguration; +import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.roster.PresenceEventListener; @@ -25,10 +28,13 @@ import org.jivesoftware.smackx.filetransfer.FileTransferManager; import org.jivesoftware.smackx.filetransfer.FileTransferRequest; import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer; import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer; +import org.jivesoftware.smackx.iqregister.AccountManager; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Localpart; +import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; import java.io.File; @@ -37,10 +43,12 @@ import java.net.Inet4Address; import java.net.UnknownHostException; import java.util.LinkedList; import java.util.Observable; +import java.util.Random; import fr.chteufleur.mytrackingdog.QRCodeGeneratorActivity; import fr.chteufleur.mytrackingdog.models.Notification; import fr.chteufleur.mytrackingdog.models.beans.MyLocation; +import fr.chteufleur.mytrackingdog.models.beans.RandomString; import fr.chteufleur.mytrackingdog.models.xmpp.commands.ObjectGeolocCommand; import fr.chteufleur.mytrackingdog.models.xmpp.commands.RealTimeModeCommand; import fr.chteufleur.mytrackingdog.models.xmpp.commands.StartTrailGeolocCommand; @@ -53,7 +61,7 @@ import fr.chteufleur.mytrackingdog.models.xmpp.commands.send.SendStartTrailComma import fr.chteufleur.mytrackingdog.models.xmpp.commands.send.SendStopTrailCommand; import fr.chteufleur.mytrackingdog.models.xmpp.commands.send.SendTrailLocationCommand; -public class ServiceXmpp extends Observable implements Runnable, PresenceEventListener, FileTransferListener { +public class ServiceXmpp extends Observable implements Runnable, ConnectionListener, PresenceEventListener, FileTransferListener { public static final String TAG = ServiceXmpp.class.getName(); @@ -79,15 +87,29 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi public static final String XMPP_NODE_REAL_TIME_MODE = "real_time_mode"; private static final String XMPP_IP_SERVER = "51.254.205.203"; - private static final String XMPP_DOMAIN_SERVER = "anon.xmpp.kingpenguin.tk"; +// private static final String XMPP_DOMAIN_SERVER = "anon.xmpp.kingpenguin.tk"; +// private static final String XMPP_DOMAIN_SERVER = "dog.xmpp.kingpenguin.tk"; + private static final String XMPP_DOMAIN_SERVER = "kingpenguin.tk"; private static final int XMPP_PORT = 5222; + // + private final SharedPreferences preferences; + private static final String PREF_XMPP_USER = "PREF_XMPP_USER"; + private static final String PREF_XMPP_PASSWORD = "PREF_XMPP_PASSWORD"; + private static final String PREF_XMPP_ACCOUNT_REGISTERED = "PREF_XMPP_ACCOUNT_REGISTERED"; + + private String prefXmppUser; + private String prefXmppPassword; + private boolean prefAccountRegistered; + // + private String appName = ""; private final Resources resources; private final XMPPTCPConnectionConfiguration configuration; private AdHocCommandManager commandManager; private FileTransferManager fileManager; + private AccountManager accountManager; private AbstractXMPPConnection connection; private String jid; private String otherJid; @@ -97,7 +119,8 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi private boolean isEnable = false; private boolean isRealTimeMode = false; - public ServiceXmpp(Resources resources) throws UnknownHostException, XmppStringprepException { + public ServiceXmpp(SharedPreferences preferences, Resources resources) throws UnknownHostException, XmppStringprepException { + this.preferences = preferences; this.resources = resources; this.configuration = XMPPTCPConnectionConfiguration.builder() .setSecurityMode(ConnectionConfiguration.SecurityMode.ifpossible) @@ -105,9 +128,30 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi .setPort(XMPP_PORT) .setXmppDomain(XMPP_DOMAIN_SERVER) .setDebuggerEnabled(true) - .performSaslAnonymousAuthentication() +// .performSaslAnonymousAuthentication() .setKeystoreType(null) .build(); + + if (!preferences.contains(PREF_XMPP_USER)) { + RandomString random = new RandomString(); + prefXmppUser = random.nextString(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(PREF_XMPP_USER, prefXmppUser); + editor.commit(); + } else { + prefXmppUser = preferences.getString(PREF_XMPP_USER, ""); + } + if (!preferences.contains(PREF_XMPP_PASSWORD)) { + RandomString random = new RandomString(); + prefXmppPassword = random.nextString(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(PREF_XMPP_PASSWORD, prefXmppPassword); + editor.commit(); + } else { + prefXmppPassword = preferences.getString(PREF_XMPP_PASSWORD, ""); + } + prefAccountRegistered = preferences.getBoolean(PREF_XMPP_ACCOUNT_REGISTERED, false); + this.thsi = this; new Thread(this).start(); } @@ -116,43 +160,19 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi this.appName = appName; } - public boolean connect() throws InterruptedException, XMPPException, SmackException, IOException { + public void connect() throws InterruptedException, XMPPException, SmackException, IOException { if (!isEnable) { - return false; + return; } StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); boolean isConnected; connection = new XMPPTCPConnection(configuration); + connection.addConnectionListener(this); commandManager = AdHocCommandManager.getAddHocCommandsManager(connection); fileManager = FileTransferManager.getInstanceFor(connection); connection.connect(); - connection.login(); - - registerCommands(); - fileManager.addFileTransferListener(this); - Roster roster = Roster.getInstanceFor(connection); - roster.addPresenceEventListener(this); - - isConnected = connection.isConnected(); - if (isConnected) { - jid = connection.getUser().asFullJidIfPossible().toString(); - Log.i(TAG, "JID: "+jid); - setPresenceAvailable(); - } - Runnable r = new Runnable() { - @Override - public void run() { - try { - QRCodeGeneratorActivity.textToImageEncode(jid, resources); - } catch (WriterException ex) { - Log.e(TAG, "Failed to generate QR Code"); - } - } - }; - new Thread(r).start(); - return isConnected; } public void close() { @@ -194,6 +214,7 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi command.executeCommand(); } catch (Exception e) { e.printStackTrace(); + sendCommandFirst(command); } } } @@ -217,6 +238,103 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi return this.isRealTimeMode; } + + // + @Override + public void connected(XMPPConnection _connection) { + if (!prefAccountRegistered) { + accountManager = AccountManager.getInstance(connection); + try { + if (accountManager.supportsAccountCreation()) { + accountManager.createAccount(Localpart.from(prefXmppUser), prefXmppPassword); + } + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException | XmppStringprepException e) { + e.printStackTrace(); + } + } + + try { + connection.login(prefXmppUser, prefXmppPassword, Resourcepart.from("MyTrackingDog")); + } catch (XmppStringprepException e) { + e.printStackTrace(); + } catch (InterruptedException | IOException | SmackException | XMPPException e) { + e.printStackTrace(); + } + + registerCommands(); + fileManager.addFileTransferListener(this); + Roster roster = Roster.getInstanceFor(connection); + roster.addPresenceEventListener(this); + } + + @Override + public void authenticated(XMPPConnection connection, boolean resumed) { + jid = connection.getUser().asFullJidIfPossible().toString(); + Log.i(TAG, "JID: "+jid); + + prefAccountRegistered = true; + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(PREF_XMPP_ACCOUNT_REGISTERED, prefAccountRegistered); + editor.commit(); + + try { + setPresenceAvailable(); + } catch (SmackException.NotConnectedException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Runnable r = new Runnable() { + @Override + public void run() { + try { + QRCodeGeneratorActivity.textToImageEncode(jid, resources); + } catch (WriterException ex) { + Log.e(TAG, "Failed to generate QR Code"); + } + } + }; + new Thread(r).start(); + + } + + @Override + public void connectionClosed() { + Log.i(TAG, "connectionClosed"); + } + + @Override + public void connectionClosedOnError(Exception e) { + Log.i(TAG, "connectionClosedOnError"); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(10_000); + connection.connect(); + } catch (SmackException | IOException | XMPPException | InterruptedException e1) { + e1.printStackTrace(); + } + } + }).start(); + } + + @Override + public void reconnectionSuccessful() { + Log.i(TAG, "reconnectionSuccessful"); + } + + @Override + public void reconnectingIn(int seconds) { + Log.i(TAG, "reconnectingIn"); + } + + @Override + public void reconnectionFailed(Exception e) { + Log.i(TAG, "reconnectionFailed"); + } + // + // public void sendPresenceAvailable() throws SmackException.NotConnectedException, InterruptedException, XmppStringprepException { if (otherJid != null) { @@ -397,6 +515,14 @@ public class ServiceXmpp extends Observable implements Runnable, PresenceEventLi } } + private void sendCommandFirst(SendCommand command) { + if (command != null) { + synchronized (listSendCommand) { + listSendCommand.addFirst(command); + } + } + } + private SendCommand getNextCommand() { SendCommand ret = null; synchronized (listSendCommand) {