encode and decode % and # in invite links

This commit is contained in:
Daniel Gultsch 2018-05-04 12:18:31 +02:00
parent 9b73029267
commit 77fc8d2d9e
4 changed files with 78 additions and 69 deletions

View file

@ -6,9 +6,6 @@ import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.PgpDecryptionService;
import org.json.JSONException;
import org.json.JSONObject;
@ -19,7 +16,9 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpDecryptionService;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.services.XmppConnectionService;
@ -95,7 +94,7 @@ public class Account extends AbstractEntity {
public boolean setShowErrorNotification(boolean newValue) {
boolean oldValue = showErrorNotification();
setKey("show_error",Boolean.toString(newValue));
setKey("show_error", Boolean.toString(newValue));
return newValue != oldValue;
}
@ -109,7 +108,7 @@ public class Account extends AbstractEntity {
}
public enum State {
DISABLED(false,false),
DISABLED(false, false),
OFFLINE(false),
CONNECTING(false),
ONLINE(false),
@ -117,12 +116,12 @@ public class Account extends AbstractEntity {
UNAUTHORIZED,
SERVER_NOT_FOUND,
REGISTRATION_SUCCESSFUL(false),
REGISTRATION_FAILED(true,false),
REGISTRATION_WEB(true,false),
REGISTRATION_CONFLICT(true,false),
REGISTRATION_NOT_SUPPORTED(true,false),
REGISTRATION_PLEASE_WAIT(true,false),
REGISTRATION_PASSWORD_TOO_WEAK(true,false),
REGISTRATION_FAILED(true, false),
REGISTRATION_WEB(true, false),
REGISTRATION_CONFLICT(true, false),
REGISTRATION_NOT_SUPPORTED(true, false),
REGISTRATION_PLEASE_WAIT(true, false),
REGISTRATION_PASSWORD_TOO_WEAK(true, false),
TLS_ERROR,
INCOMPATIBLE_SERVER,
TOR_NOT_AVAILABLE,
@ -148,7 +147,7 @@ public class Account extends AbstractEntity {
}
State(final boolean isError) {
this(isError,true);
this(isError, true);
}
State(final boolean isError, final boolean reconnect) {
@ -157,7 +156,7 @@ public class Account extends AbstractEntity {
}
State() {
this(true,true);
this(true, true);
}
public int getReadableId() {
@ -254,9 +253,9 @@ public class Account extends AbstractEntity {
}
private Account(final String uuid, final Jid jid,
final String password, final int options, final String rosterVersion, final String keys,
final String avatar, String displayName, String hostname, int port,
final Presence.Status status, String statusMessage) {
final String password, final int options, final String rosterVersion, final String keys,
final String avatar, String displayName, String hostname, int port,
final Presence.Status status, String statusMessage) {
this.uuid = uuid;
this.jid = jid;
this.password = password;
@ -265,7 +264,7 @@ public class Account extends AbstractEntity {
JSONObject tmp;
try {
tmp = new JSONObject(keys);
} catch(JSONException e) {
} catch (JSONException e) {
tmp = new JSONObject();
}
this.keys = tmp;
@ -286,7 +285,7 @@ public class Account extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(SERVER)),
resource == null || resource.trim().isEmpty() ? null : resource);
} catch (final IllegalArgumentException ignored) {
Log.d(Config.LOGTAG,cursor.getString(cursor.getColumnIndex(USERNAME))+"@"+cursor.getString(cursor.getColumnIndex(SERVER)));
Log.d(Config.LOGTAG, cursor.getString(cursor.getColumnIndex(USERNAME)) + "@" + cursor.getString(cursor.getColumnIndex(SERVER)));
throw new AssertionError(ignored);
}
return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
@ -480,7 +479,7 @@ public class Account extends AbstractEntity {
values.put(PORT, port);
values.put(STATUS, presenceStatus.toShowString());
values.put(STATUS_MESSAGE, presenceStatusMessage);
values.put(RESOURCE,jid.getResource());
values.put(RESOURCE, jid.getResource());
return values;
}
@ -584,7 +583,7 @@ public class Account extends AbstractEntity {
}
public Bookmark getBookmark(final Jid jid) {
for(final Bookmark bookmark : this.bookmarks) {
for (final Bookmark bookmark : this.bookmarks) {
if (bookmark.getJid() != null && jid.asBareJid().equals(bookmark.getJid().asBareJid())) {
return bookmark;
}
@ -619,9 +618,9 @@ public class Account extends AbstractEntity {
public String getShareableUri() {
List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
String uri = "xmpp:"+this.getJid().asBareJid().toEscapedString();
String uri = "xmpp:" + this.getJid().asBareJid().toEscapedString();
if (fingerprints.size() > 0) {
return XmppUri.getFingerprintUri(uri,fingerprints,';');
return XmppUri.getFingerprintUri(uri, fingerprints, ';');
} else {
return uri;
}
@ -629,9 +628,9 @@ public class Account extends AbstractEntity {
public String getShareableLink() {
List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
String uri = "https://conversations.im/i/"+this.getJid().asBareJid().toEscapedString();
String uri = "https://conversations.im/i/" + XmppUri.lameUrlEncode(this.getJid().asBareJid().toEscapedString());
if (fingerprints.size() > 0) {
return XmppUri.getFingerprintUri(uri,fingerprints,'&');
return XmppUri.getFingerprintUri(uri, fingerprints, '&');
} else {
return uri;
}
@ -642,10 +641,10 @@ public class Account extends AbstractEntity {
if (axolotlService == null) {
return fingerprints;
}
fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO,axolotlService.getOwnFingerprint().substring(2),axolotlService.getOwnDeviceId()));
for(XmppAxolotlSession session : axolotlService.findOwnSessions()) {
fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO, axolotlService.getOwnFingerprint().substring(2), axolotlService.getOwnDeviceId()));
for (XmppAxolotlSession session : axolotlService.findOwnSessions()) {
if (session.getTrust().isVerified() && session.getTrust().isActive()) {
fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO,session.getFingerprint().substring(2).replaceAll("\\s",""),session.getRemoteAddress().getDeviceId()));
fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO, session.getFingerprint().substring(2).replaceAll("\\s", ""), session.getRemoteAddress().getDeviceId()));
}
}
return fingerprints;

View file

@ -45,6 +45,7 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat
import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import rocks.xmpp.addr.Jid;
public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnRoleChanged, XmppConnectionService.OnConfigurationPushed {
@ -298,7 +299,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
protected String getShareableUri(boolean http) {
if (mConversation != null) {
if (http) {
return "https://conversations.im/j/" + mConversation.getJid().asBareJid().toEscapedString();
return "https://conversations.im/j/" + XmppUri.lameUrlEncode(mConversation.getJid().asBareJid().toEscapedString());
} else {
return "xmpp:" + mConversation.getJid().asBareJid() + "?join";
}

View file

@ -10,7 +10,6 @@ import android.preference.PreferenceManager;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
@ -63,14 +62,14 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
boolean isChecked) {
if (isChecked) {
if (contact
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
xmppConnectionService.sendPresencePacket(contact
.getAccount(),
.getAccount(),
xmppConnectionService.getPresenceGenerator()
.sendPresenceUpdatesTo(contact));
.sendPresenceUpdatesTo(contact));
} else {
contact.setOption(Contact.Options.PREEMPTIVE_GRANT);
}
@ -78,7 +77,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
contact.resetOption(Contact.Options.PREEMPTIVE_GRANT);
xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator()
.stopPresenceUpdatesTo(contact));
.stopPresenceUpdatesTo(contact));
}
}
};
@ -86,15 +85,15 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
boolean isChecked) {
if (isChecked) {
xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator()
.requestPresenceUpdatesFrom(contact));
.requestPresenceUpdatesFrom(contact));
} else {
xmppConnectionService.sendPresencePacket(contact.getAccount(),
xmppConnectionService.getPresenceGenerator()
.stopPresenceUpdatesFrom(contact));
.stopPresenceUpdatesFrom(contact));
}
}
};
@ -163,18 +162,17 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
protected String getShareableUri(boolean http) {
final String prefix = http ? "https://conversations.im/i/" : "xmpp:";
if (contact != null) {
return prefix+contact.getJid().asBareJid().toEscapedString();
if (http) {
return "https://conversations.im/j/" + XmppUri.lameUrlEncode(contact.getJid().asBareJid().toEscapedString());
} else {
return "";
return "xmpp:" + contact.getJid().asBareJid().toEscapedString();
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showInactiveOmemo = savedInstanceState != null && savedInstanceState.getBoolean("show_inactive_omemo",false);
showInactiveOmemo = savedInstanceState != null && savedInstanceState.getBoolean("show_inactive_omemo", false);
if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) {
try {
this.accountJid = Jid.of(getIntent().getExtras().getString(EXTRA_ACCOUNT));
@ -199,7 +197,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
savedInstanceState.putBoolean("show_inactive_omemo",showInactiveOmemo);
savedInstanceState.putBoolean("show_inactive_omemo", showInactiveOmemo);
super.onSaveInstanceState(savedInstanceState);
}
@ -235,9 +233,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
break;
case R.id.action_delete_contact:
builder.setTitle(getString(R.string.action_delete_contact))
.setMessage(getString(R.string.remove_contact_text, contact.getJid().toString()))
.setPositiveButton(getString(R.string.delete),
removeFromRoster).create().show();
.setMessage(getString(R.string.remove_contact_text, contact.getJid().toString()))
.setPositiveButton(getString(R.string.delete),
removeFromRoster).create().show();
break;
case R.id.action_edit_contact:
Uri systemAccount = contact.getSystemAccount();
@ -317,7 +315,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
StringBuilder builder = new StringBuilder();
binding.statusMessage.setVisibility(View.VISIBLE);
int s = statusMessages.size();
for(int i = 0; i < s; ++i) {
for (int i = 0; i < s; ++i) {
if (s > 1) {
builder.append("");
}
@ -384,7 +382,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
}
binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this,contact.getJid()));
binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid()));
String account;
if (Config.DOMAIN_LOCK != null) {
account = contact.getAccount().getJid().getLocal();
@ -429,7 +427,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
binding.scanButton.setVisibility(hasKeys && isCameraFeatureAvailable() ? View.VISIBLE : View.GONE);
if (hasKeys) {
binding.scanButton.setOnClickListener((v)-> ScanActivity.scan(this));
binding.scanButton.setOnClickListener((v) -> ScanActivity.scan(this));
}
if (Config.supportOpenPgp() && contact.getPgpKeyId() != 0) {
hasKeys = true;
@ -455,8 +453,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
} else {
binding.tags.setVisibility(View.VISIBLE);
binding.tags.removeAllViewsInLayout();
for(final ListItem.Tag tag : tagList) {
final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag,binding.tags,false);
for (final ListItem.Tag tag : tagList) {
final TextView tv = (TextView) inflater.inflate(R.layout.list_item_tag, binding.tags, false);
tv.setText(tag.getName());
tv.setBackgroundColor(tag.getColor());
binding.tags.addView(tv);
@ -487,11 +485,11 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
protected void processFingerprintVerification(XmppUri uri) {
if (contact != null && contact.getJid().asBareJid().equals(uri.getJid()) && uri.hasFingerprints()) {
if (xmppConnectionService.verifyFingerprints(contact,uri.getFingerprints())) {
Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show();
if (xmppConnectionService.verifyFingerprints(contact, uri.getFingerprints())) {
Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this,R.string.invalid_barcode,Toast.LENGTH_SHORT).show();
Toast.makeText(this, R.string.invalid_barcode, Toast.LENGTH_SHORT).show();
}
}
}

View file

@ -1,6 +1,7 @@
package eu.siacs.conversations.utils;
import android.net.Uri;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@ -8,6 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import eu.siacs.conversations.Config;
import rocks.xmpp.addr.Jid;
public class XmppUri {
@ -21,7 +23,6 @@ public class XmppUri {
protected boolean safeSource = true;
public static final String OMEMO_URI_PARAM = "omemo-sid-";
public static final String OTR_URI_PARAM = "otr-fingerprint";
public static final String ACTION_JOIN = "join";
public static final String ACTION_MESSAGE = "message";
@ -60,8 +61,9 @@ public class XmppUri {
if (segments.size() >= 2 && segments.get(1).contains("@")) {
// sample : https://conversations.im/i/foo@bar.com
try {
jid = Jid.of(segments.get(1)).toString();
jid = Jid.of(lameUrlDecode(segments.get(1))).toString();
} catch (Exception e) {
Log.d(Config.LOGTAG, "parsing failed ", e);
jid = null;
}
} else if (segments.size() >= 3) {
@ -71,7 +73,7 @@ public class XmppUri {
if (segments.size() > 1 && "j".equalsIgnoreCase(segments.get(0))) {
action = ACTION_JOIN;
}
fingerprints = parseFingerprints(uri.getQuery(),'&');
fingerprints = parseFingerprints(uri.getQuery(), '&');
} else if ("xmpp".equalsIgnoreCase(scheme)) {
// sample: xmpp:foo@bar.com
@ -120,21 +122,21 @@ public class XmppUri {
}
protected List<Fingerprint> parseFingerprints(String query) {
return parseFingerprints(query,';');
return parseFingerprints(query, ';');
}
protected List<Fingerprint> parseFingerprints(String query, char seperator) {
List<Fingerprint> fingerprints = new ArrayList<>();
String[] pairs = query == null ? new String[0] : query.split(String.valueOf(seperator));
for(String pair : pairs) {
String[] parts = pair.split("=",2);
for (String pair : pairs) {
String[] parts = pair.split("=", 2);
if (parts.length == 2) {
String key = parts[0].toLowerCase(Locale.US);
String value = parts[1].toLowerCase(Locale.US);
if (key.startsWith(OMEMO_URI_PARAM)) {
try {
int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
fingerprints.add(new Fingerprint(FingerprintType.OMEMO,value,id));
fingerprints.add(new Fingerprint(FingerprintType.OMEMO, value, id));
} catch (Exception e) {
//ignoring invalid device id
}
@ -145,11 +147,11 @@ public class XmppUri {
}
protected String parseParameter(String key, String query) {
for(String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=",2);
for (String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=", 2);
if (parts.length == 2 && key.equals(parts[0].toLowerCase(Locale.US))) {
try {
return URLDecoder.decode(parts[1],"UTF-8");
return URLDecoder.decode(parts[1], "UTF-8");
} catch (UnsupportedEncodingException e) {
return null;
}
@ -159,8 +161,8 @@ public class XmppUri {
}
private boolean hasAction(String query, String action) {
for(String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=",2);
for (String pair : query == null ? new String[0] : query.split(";")) {
final String[] parts = pair.split("=", 2);
if (parts.length == 1 && parts[0].equals(action)) {
return true;
}
@ -178,7 +180,7 @@ public class XmppUri {
public Jid getJid() {
try {
return this.jid == null ? null :Jid.of(this.jid.toLowerCase());
return this.jid == null ? null : Jid.of(this.jid.toLowerCase());
} catch (IllegalArgumentException e) {
return null;
}
@ -211,6 +213,7 @@ public class XmppUri {
public boolean hasFingerprints() {
return fingerprints.size() > 0;
}
public enum FingerprintType {
OMEMO
}
@ -218,7 +221,7 @@ public class XmppUri {
public static String getFingerprintUri(String base, List<XmppUri.Fingerprint> fingerprints, char seperator) {
StringBuilder builder = new StringBuilder(base);
builder.append('?');
for(int i = 0; i < fingerprints.size(); ++i) {
for (int i = 0; i < fingerprints.size(); ++i) {
XmppUri.FingerprintType type = fingerprints.get(i).type;
if (type == XmppUri.FingerprintType.OMEMO) {
builder.append(XmppUri.OMEMO_URI_PARAM);
@ -226,7 +229,7 @@ public class XmppUri {
}
builder.append('=');
builder.append(fingerprints.get(i).fingerprint);
if (i != fingerprints.size() -1) {
if (i != fingerprints.size() - 1) {
builder.append(seperator);
}
}
@ -250,7 +253,15 @@ public class XmppUri {
@Override
public String toString() {
return type.toString()+": "+fingerprint+(deviceId != 0 ? " "+String.valueOf(deviceId) : "");
return type.toString() + ": " + fingerprint + (deviceId != 0 ? " " + String.valueOf(deviceId) : "");
}
}
public static String lameUrlDecode(String url) {
return url.replace("%23", "#").replace("%25", "%");
}
public static String lameUrlEncode(String url) {
return url.replace("%", "%25").replace("#", "%23");
}
}