Fix osmo bugs: use https, encryption, cancel

Conflicts:
	OsmAnd/res/values/strings.xml
This commit is contained in:
Victor Shcherb 2014-11-23 15:32:46 +01:00
parent 46173129f0
commit 9963f41ccc
13 changed files with 168 additions and 28 deletions

View file

@ -84,6 +84,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dip"
android:autoLink="web"
android:gravity="center"
android:textSize="18sp" />

View file

@ -84,6 +84,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dip"
android:autoLink="web"
android:gravity="center"
android:textSize="18sp" />

View file

@ -1,5 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<resources><string name="srtm_plugin_description">Плагин позволяет загружать контурные линии и затемнение высот для использования оффлайн (\"Настройки\" → \"Управление файлами карт\" → \"Загрузить\").</string>
<resources>
<string name="osmo_use_https_descr">Использовать безопасное соединение с сервером</string>
<string name="osmo_use_https">Использовать https</string>
<string name="srtm_plugin_description">Плагин позволяет загружать контурные линии и затемнение высот для использования оффлайн (\"Настройки\" → \"Управление файлами карт\" → \"Загрузить\").</string>
<string name="srtm_paid_version_msg">Рассмотрите, пожалуйста, покупку плагина \"Линии высот\" в Google Play, чтобы поддержать последующую разработку.</string>
<string name="srtm_paid_version_title">Линии высот</string>
<string name="av_def_action_video">Запись видео</string>

View file

@ -9,6 +9,13 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="osmo_use_https_descr">Use secure connection with server</string>
<string name="osmo_use_https">Use https</string>
<string name="advanced_settings">Advanced</string>
<string name="rendering_attr_publicTransportMode_name">Bus, trolleybus, shuttle routes</string>
<string name="rendering_attr_tramTrainRoutes_name">Tram and train routes</string>
<string name="rendering_attr_subwayMode_name">Subway routes</string>
<string name="lock_screen_request_explanation">%1$s needs this permission to turn off the screen for the power saving feature.</string>
<string name="wake_on_voice">Turn on the screen</string>
<string name="wake_on_voice_descr">Turn on the phone screen when approaching a turn</string>
<string name="select_impassable_road">Select on map</string>

View file

@ -57,6 +57,8 @@ public class OsmandSettings {
void addListener(StateChangedListener<T> listener);
void removeListener(StateChangedListener<T> listener);
boolean isSet();
}
private abstract class PreferenceWithListener<T> implements OsmandPreference<T> {
@ -168,6 +170,11 @@ public class OsmandSettings {
set(ApplicationMode.DEFAULT);
};
@Override
public boolean isSet() {
return true;
};
@Override
public boolean set(ApplicationMode val) {
ApplicationMode oldMode = currentMode;
@ -875,6 +882,9 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> OSMO_AUTO_CONNECT = new BooleanPreference("osmo_automatically_connect", false).makeGlobal();
public final CommonPreference<Boolean> OSMO_USE_HTTPS = new BooleanPreference("osmo_use_https",
Build.VERSION.SDK_INT < 14/*Build.VERSION_CODES.ICE_CREAM_SANDWICH*/? false : true).makeGlobal();
public final OsmandPreference<Long> OSMO_LAST_PING = new LongPreference("osmo_last_ping", 0).makeGlobal().cache();
public final OsmandPreference<Boolean> OSMO_AUTO_SEND_LOCATIONS = new BooleanPreference("osmo_automatically_send_locations", false).makeGlobal();

View file

@ -287,6 +287,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
if (!mid.equals(trackerId)) {
if (toDelete.contains(trackerId)) {
toDelete.remove(trackerId);
OsMoDevice dv = mainGroup.users.get(trackerId);
dv.serverColor = device.userColor;
dv.serverName = device.userName;
} else {
mainGroup.users.put(trackerId, device);
}
@ -478,7 +481,9 @@ public class OsMoGroups implements OsMoReactor, OsmoTrackerListener {
}
points.add(pt);
}
plugin.getSaveGpxTask(gr.groupId + "_points", modify).execute(points.toArray(new WptPt[points.size()]));
if(points.size() > 0) {
plugin.getSaveGpxTask(gr.name + " points", modify, false).execute(points.toArray(new WptPt[points.size()]));
}
}
if(deleteUsers) {
for(OsMoDevice s : toDelete.values()) {

View file

@ -241,8 +241,11 @@ public class OsMoGroupsActivity extends OsmandExpandableListActivity implements
mtd.setVisibility(visible? View.VISIBLE:View.GONE);
if(visible) {
mtd.setText(si.motd);
mtd.setLinksClickable(true);
mtd.setMovementMethod(LinkMovementMethod.getInstance());
}
CompoundButton login = (CompoundButton) header.findViewById(R.id.osmo_login_logoff);
login.setChecked(osMoPlugin.getService().isLoggedIn());
login.setOnCheckedChangeListener(new LoginOnCheckedChangeListener());

View file

@ -1,10 +1,8 @@
package net.osmand.plus.osmo;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -75,6 +73,7 @@ public class OsMoGroupsStorage {
public void load() {
String grp = pref.get();
try {
System.out.println("DEBUG : OsMo groups load info " + grp);
JSONObject obj = new JSONObject(grp);
parseGroupUsers(mainGroup, obj);
if(!obj.has(GROUPS)) {

View file

@ -67,12 +67,12 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
public OsMoPlugin(final OsmandApplication app) {
this.app = app;
service = new OsMoService(app, this);
tracker = new OsMoTracker(service, app.getSettings().OSMO_SAVE_TRACK_INTERVAL,
app.getSettings().OSMO_AUTO_SEND_LOCATIONS);
new OsMoControlDevice(app, this, service, tracker);
groups = new OsMoGroups(this, service, tracker, app);
this.app = app;
ApplicationMode.regWidget("osmo_control", (ApplicationMode[])null);
}
@ -85,6 +85,7 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
return true;
}
public OsMoGroupsActivity getGroupsActivity() {
return groupsActivity;
}
@ -229,8 +230,17 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
if (si != null) {
String uname = si.username;
if (uname != null && uname.length() > 0) {
if (uname.length() > 7 && uname.indexOf(' ') != -1) {
uname = uname.substring(0, uname.indexOf(' '));
if (uname.length() > 7) {
for(int k = 4; k < uname.length(); k++) {
if(!Character.isLetterOrDigit(uname.charAt(k)) &&
uname.charAt(k) != '.' && uname.charAt(k) != '-') {
uname = uname.substring(0, k);
break;
}
}
if(uname.length() > 12) {
uname = uname.substring(0, 12);
}
}
if (uname.length() > 4) {
txt = "";
@ -350,11 +360,11 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
return service;
}
public AsyncTask<WptPt, String, String> getSaveGpxTask(final String name, final long timestamp) {
public AsyncTask<WptPt, String, String> getSaveGpxTask(final String name, final long timestamp, final boolean generateToast) {
return new AsyncTask<WptPt, String, String>() {
protected void onProgressUpdate(String... values) {
if (values != null) {
if (values != null && generateToast) {
String t = "";
for (String s : values) {
t += s + "\n";
@ -381,7 +391,9 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
if (errors == null) {
errors = "";
}
publishProgress(app.getString(R.string.osmo_gpx_points_downloaded, name));
if(generateToast) {
publishProgress(app.getString(R.string.osmo_gpx_points_downloaded, name));
}
}
SelectedGpxFile byPath = app.getSelectedGpxHelper().getSelectedFileByPath(ps.getAbsolutePath());
if (byPath == null || changed) {
@ -396,7 +408,7 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
@Override
protected void onPostExecute(String result) {
if (result.length() > 0) {
if (result.length() > 0 && generateToast) {
app.showToastMessage(app.getString(R.string.osmo_io_error) + result);
}
}
@ -525,4 +537,8 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
}
}
public boolean useHttps() {
return app.getSettings().OSMO_USE_HTTPS.get();
}
}

View file

@ -8,7 +8,6 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import net.osmand.Location;
import net.osmand.access.AccessibleToast;
import net.osmand.core.jni.ColorARGB;
import net.osmand.data.LatLon;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.OsmAndFormatter;
@ -294,6 +293,7 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye
private static String followTrackerId;
private static LatLon followMapLocation;
private static String followDestinationId;
private static LatLon followTargetLocation;
public static void setFollowTrackerId(OsMoDevice d) {
if(d != null) {
@ -322,17 +322,29 @@ public class OsMoPositionLayer extends OsmandMapLayer implements ContextMenuLaye
Location l = device.getLastLocation();
if(sameDestId && l != null) {
TargetPointsHelper targets = map.getMyApplication().getTargetPointsHelper();
RoutingHelper rh = map.getMyApplication().getRoutingHelper();
double dist = 1;
if(rh.isRouteBeingCalculated()) {
dist = 100;
} else if(rh.isRouteCalculated()) {
dist = 30;
}
LatLon lt = new LatLon(l.getLatitude(), l.getLongitude());
final TargetPoint pn = targets.getPointToNavigate();
if(pn == null || MapUtils.getDistance(pn.point, lt) > dist) {
targets.navigateToPoint(lt, true, -1);
LatLon lt = new LatLon(l.getLatitude(), l.getLongitude());
boolean cancelDestinationId = false;
if(followTargetLocation != null ) {
if(pn == null || pn.point == null || !pn.point.equals(lt) ) {
cancelDestinationId = true;
}
}
if(cancelDestinationId) {
followTargetLocation = null;
followDestinationId = null;
} else {
RoutingHelper rh = map.getMyApplication().getRoutingHelper();
double dist = 1;
if (rh.isRouteBeingCalculated()) {
dist = 100;
} else if (rh.isRouteCalculated()) {
dist = 30;
}
if (pn == null || MapUtils.getDistance(pn.point, lt) > dist) {
followTargetLocation = lt;
targets.navigateToPoint(lt, true, -1);
}
}
}

View file

@ -4,11 +4,20 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.crypto.Cipher;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
@ -45,6 +54,12 @@ import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
public class OsMoService implements OsMoReactor {
private static final String HTTP_API_PREPARE = "http://api.osmo.mobi/prepare";
private static final String HTTPS_API_PREPARE = "https://api.osmo.mobi/prepare";
private static final String HTTP_AUTH = "http://api.osmo.mobi/auth";
private static final String HTTPS_AUTH = "https://api.osmo.mobi/auth";
private static final boolean USE_RSA_ENCRYPTION = false;
public static final String REGENERATE_CMD = "TRACKER_REGENERATE_ID";
public static final String SIGN_IN_URL = "http://osmo.mobi/signin?key=";
private OsMoThread thread;
@ -61,6 +76,7 @@ public class OsMoService implements OsMoReactor {
private boolean enabled = false;
private BroadcastReceiver broadcastReceiver;
private Notification notification;
public final static String OSMO_REGISTER_AGAIN = "OSMO_REGISTER_AGAIN"; //$NON-NLS-1$
private final static int SIMPLE_NOTFICATION_ID = 5;
@ -170,7 +186,7 @@ public class OsMoService implements OsMoReactor {
public String registerOsmoDeviceKey() throws IOException {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://api.osmo.mobi/auth");
HttpPost httppost = new HttpPost(plugin.useHttps()? HTTPS_AUTH : HTTP_AUTH);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
@ -209,6 +225,7 @@ public class OsMoService implements OsMoReactor {
public String token;
public String uid;
public String username;
// after auth
public String protocol = "";
public String groupTrackerId;
@ -217,6 +234,8 @@ public class OsMoService implements OsMoReactor {
public long motdTimestamp;
public String motd = "";
public Cipher clientEncCypher;
public Cipher clientDecCypher;
}
public SessionInfo getCurrentSessionInfo() {
@ -258,12 +277,33 @@ public class OsMoService implements OsMoReactor {
deviceKey = registerOsmoDeviceKey();
}
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://api.osmo.mobi/prepare");
KeyPair getMsgPair = null;
if (plugin.useHttps() && USE_RSA_ENCRYPTION) {
try {
KeyPairGenerator rsaGen = KeyPairGenerator.getInstance("RSA");
getMsgPair = rsaGen.generateKeyPair();
} catch (Exception e1) {
if (thread != null) {
thread.exc("Private key can't be generated", e1);
} else {
e1.printStackTrace();
}
}
}
HttpPost httppost = new HttpPost(plugin.useHttps()? HTTPS_API_PREPARE : HTTP_API_PREPARE);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("app", Version.getFullVersion(app)));
nameValuePairs.add(new BasicNameValuePair("key", deviceKey));
if(getMsgPair != null && getMsgPair.getPublic() instanceof RSAPublicKey) {
nameValuePairs.add(new BasicNameValuePair("encAlgorithm", "RSA"));
BigInteger modulus = ((RSAPublicKey) getMsgPair.getPublic()).getModulus();
BigInteger pe = ((RSAPublicKey) getMsgPair.getPublic()).getPublicExponent();
nameValuePairs.add(new BasicNameValuePair("encClientPublicKey1", modulus.toString()));
nameValuePairs.add(new BasicNameValuePair("encClientPublicKey2", pe.toString()));
}
if(app.getSettings().OSMO_USER_PWD.get() != null) {
nameValuePairs.add(new BasicNameValuePair("auth", app.getSettings().OSMO_USER_PWD.get()));
}
@ -304,6 +344,23 @@ public class OsMoService implements OsMoReactor {
si.hostName = a.substring(0, i);
si.port = a.substring(i + 1);
si.token = obj.getString("token");
try {
if(getMsgPair != null && obj.has("encServerPublicKey1")) {
si.clientEncCypher = Cipher.getInstance("RSA");
PublicKey pk = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger(obj.getString("encServerPublicKey1")),
new BigInteger(obj.getString("encServerPublicKey2"))));
si.clientEncCypher.init(Cipher.ENCRYPT_MODE, pk);
si.clientDecCypher = Cipher.getInstance("RSA");
si.clientDecCypher.init(Cipher.DECRYPT_MODE, getMsgPair.getPrivate());
}
} catch (Exception e) {
if (thread != null) {
thread.exc("Error exchanging private keys", e);
} else {
e.printStackTrace();
}
}
return si;
} catch (ClientProtocolException e) {
throw new IOException(e);

View file

@ -17,7 +17,11 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import net.osmand.PlatformUtil;
import net.osmand.osm.io.Base64;
import net.osmand.plus.osmo.OsMoService.SessionInfo;
import org.apache.commons.logging.Log;
@ -261,6 +265,15 @@ public class OsMoThread {
while ((i = readCommand.indexOf('\n')) != -1) {
String cmd = readCommand.substring(0, i);
readCommand = readCommand.substring(i + 1);
if(sessionInfo != null && sessionInfo.clientDecCypher != null) {
try {
final byte[] inMsg = android.util.Base64.decode(cmd.getBytes(), android.util.Base64.DEFAULT);
final byte[] byts = sessionInfo.clientDecCypher.doFinal(inMsg);
cmd = new String(byts);
} catch (Exception e) {
exc("Error decrypting", e);
}
}
queueOfMessages.add(cmd.replace("\\n", "\n"));
}
}
@ -449,15 +462,23 @@ public class OsMoThread {
private String prepareCommand(String l) {
StringBuilder res = new StringBuilder(l.length());
for(int i = 0; i < l.length(); i++) {
for (int i = 0; i < l.length(); i++) {
char c = l.charAt(i);
if(c == '\n' || c == '=' || c == '\\') {
res.append('\\');
if (c == '\n' || c == '=' || c == '\\') {
res.append('\\');
}
res.append(c);
}
return res.toString().trim() + "=\n";
String finalCmd = res.toString().trim();
if(sessionInfo != null && sessionInfo.clientEncCypher != null) {
try {
finalCmd = Base64.encode(sessionInfo.clientEncCypher.doFinal(finalCmd.getBytes()));
} catch (Exception e) {
exc("Error encrypting", e);
}
}
return finalCmd + "=\n";
}
public long getLastCommandTime() {

View file

@ -68,6 +68,11 @@ public class SettingsOsMoActivity extends SettingsBaseActivity {
showGroupNotifiations.setSummary(R.string.osmo_show_group_notifications_descr);
grp.addPreference(showGroupNotifiations);
CheckBoxPreference useHttps = createCheckBoxPreference(settings.OSMO_USE_HTTPS);
useHttps.setTitle(R.string.osmo_use_https);
useHttps.setSummary(R.string.osmo_use_https_descr);
grp.addPreference(useHttps);
if (OsmandPlugin.isDevelopment()) {
debugPref = new Preference(this);
debugPref.setTitle(R.string.osmo_settings_debug);