Do not insert text shared over XMPP uri when already drafting message

XMPP uris in the style of `xmpp:test@domain.tld?body=Something` can be used to
directly share a message with a specific contact. Previously the text was
always appended to the message currently in draft. The message was never send
automatically. Essentially those links where treated like normal text share
intents (for example when sharing a URL from the browser) but without the
contact selection.

There is a concern (CVE-2018-18467) that when this URI is invoked automatically
and the user is currently drafting a long message to that particular contact
the text could be inserted in the draft field (input box) without the user
noticing.

To circumvent that the text shared over XMPP uris that contain a particular
contact is now appended only if the draft box is currently empty.

Sharing text normally (**with** manual contact selection) is still treated the
same; meaning the shared text will be appended to the current draft. This is
intended behaviour to make the
'Hey I have this cool link here;' *open browser*, *share link* - secenario
work.
This commit is contained in:
Daniel Gultsch 2018-10-19 15:39:31 +02:00
parent 71bbd379e9
commit 7177c523a1
5 changed files with 37 additions and 18 deletions

View File

@ -27,6 +27,7 @@ import android.os.SystemClock;
import android.support.v13.view.inputmethod.InputConnectionCompat; import android.support.v13.view.inputmethod.InputConnectionCompat;
import android.support.v13.view.inputmethod.InputContentInfoCompat; import android.support.v13.view.inputmethod.InputContentInfoCompat;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
@ -1995,6 +1996,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
final String nick = extras.getString(ConversationsActivity.EXTRA_NICK); final String nick = extras.getString(ConversationsActivity.EXTRA_NICK);
final boolean asQuote = extras.getBoolean(ConversationsActivity.EXTRA_AS_QUOTE); final boolean asQuote = extras.getBoolean(ConversationsActivity.EXTRA_AS_QUOTE);
final boolean pm = extras.getBoolean(ConversationsActivity.EXTRA_IS_PRIVATE_MESSAGE, false); final boolean pm = extras.getBoolean(ConversationsActivity.EXTRA_IS_PRIVATE_MESSAGE, false);
final boolean doNotAppend = extras.getBoolean(ConversationsActivity.EXTRA_DO_NOT_APPEND, false);
final List<Uri> uris = extractUris(extras); final List<Uri> uris = extractUris(extras);
if (uris != null && uris.size() > 0) { if (uris != null && uris.size() > 0) {
final List<Uri> cleanedUris = cleanUris(new ArrayList<>(uris)); final List<Uri> cleanedUris = cleanUris(new ArrayList<>(uris));
@ -2021,7 +2023,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
if (text != null && asQuote) { if (text != null && asQuote) {
quoteText(text); quoteText(text);
} else { } else {
appendText(text); appendText(text, doNotAppend);
} }
} }
final Message message = downloadUuid == null ? null : conversation.findMessageWithFileAndUuid(downloadUuid); final Message message = downloadUuid == null ? null : conversation.findMessageWithFileAndUuid(downloadUuid);
@ -2545,11 +2547,16 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
builder.create().show(); builder.create().show();
} }
public void appendText(String text) { public void appendText(String text, final boolean doNotAppend) {
if (text == null) { if (text == null) {
return; return;
} }
String previous = this.binding.textinput.getText().toString(); final Editable editable = this.binding.textinput.getText();
String previous = editable == null ? "" : editable.toString();
if (doNotAppend && !TextUtils.isEmpty(previous)) {
Toast.makeText(getActivity(),R.string.already_drafting_message, Toast.LENGTH_LONG).show();
return;
}
if (UIHelper.isLastLineQuote(previous)) { if (UIHelper.isLastLineQuote(previous)) {
text = '\n' + text; text = '\n' + text;
} else if (previous.length() != 0 && !Character.isWhitespace(previous.charAt(previous.length() - 1))) { } else if (previous.length() != 0 && !Character.isWhitespace(previous.charAt(previous.length() - 1))) {

View File

@ -92,6 +92,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
public static final String EXTRA_AS_QUOTE = "as_quote"; public static final String EXTRA_AS_QUOTE = "as_quote";
public static final String EXTRA_NICK = "nick"; public static final String EXTRA_NICK = "nick";
public static final String EXTRA_IS_PRIVATE_MESSAGE = "pm"; public static final String EXTRA_IS_PRIVATE_MESSAGE = "pm";
public static final String EXTRA_DO_NOT_APPEND = "do_not_append";
private static List<String> VIEW_AND_SHARE_ACTIONS = Arrays.asList( private static List<String> VIEW_AND_SHARE_ACTIONS = Arrays.asList(
ACTION_VIEW_CONVERSATION, ACTION_VIEW_CONVERSATION,

View File

@ -487,7 +487,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
contact.setServerName(invite.getName()); contact.setServerName(invite.getName());
} }
if (contact.isSelf()) { if (contact.isSelf()) {
switchToConversation(contact, null); switchToConversation(contact);
return true; return true;
} else if (contact.showInRoster()) { } else if (contact.showInRoster()) {
throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists)); throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
@ -496,7 +496,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (invite != null && invite.hasFingerprints()) { if (invite != null && invite.hasFingerprints()) {
xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints()); xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
} }
switchToConversation(contact, invite == null ? null : invite.getBody()); switchToConversationDoNotAppend(contact, invite == null ? null : invite.getBody());
return true; return true;
} }
}); });
@ -543,11 +543,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
return xmppConnectionService.findAccountByJid(jid); return xmppConnectionService.findAccountByJid(jid);
} }
protected void switchToConversation(Contact contact, String body) { protected void switchToConversation(Contact contact) {
Conversation conversation = xmppConnectionService Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
.findOrCreateConversation(contact.getAccount(), switchToConversation(conversation);
contact.getJid(), false, true); }
switchToConversation(conversation, body);
protected void switchToConversationDoNotAppend(Contact contact, String body) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
switchToConversationDoNotAppend(conversation, body);
} }
@Override @Override
@ -777,7 +780,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (invite.isAction(XmppUri.ACTION_JOIN)) { if (invite.isAction(XmppUri.ACTION_JOIN)) {
Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid()); Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
if (muc != null) { if (muc != null) {
switchToConversation(muc, invite.getBody()); switchToConversationDoNotAppend(muc, invite.getBody());
return true; return true;
} else { } else {
showJoinConferenceDialog(invite.getJid().asBareJid().toString()); showJoinConferenceDialog(invite.getJid().asBareJid().toString());
@ -799,7 +802,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (invite.account != null) { if (invite.account != null) {
xmppConnectionService.getShortcutService().report(contact); xmppConnectionService.getShortcutService().report(contact);
} }
switchToConversation(contact, invite.getBody()); switchToConversationDoNotAppend(contact, invite.getBody());
} }
return true; return true;
} else { } else {
@ -827,7 +830,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (isTrustedSource.isChecked() && invite.hasFingerprints()) { if (isTrustedSource.isChecked() && invite.hasFingerprints()) {
xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints()); xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
} }
switchToConversation(contact, invite.getBody()); switchToConversationDoNotAppend(contact, invite.getBody());
}); });
builder.setNegativeButton(R.string.cancel, (dialog, which) -> StartConversationActivity.this.finish()); builder.setNegativeButton(R.string.cancel, (dialog, which) -> StartConversationActivity.this.finish());
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();

View File

@ -453,22 +453,26 @@ public abstract class XmppActivity extends ActionBarActivity {
} }
public void switchToConversationAndQuote(Conversation conversation, String text) { public void switchToConversationAndQuote(Conversation conversation, String text) {
switchToConversation(conversation, text, true, null, false); switchToConversation(conversation, text, true, null, false, false);
} }
public void switchToConversation(Conversation conversation, String text) { public void switchToConversation(Conversation conversation, String text) {
switchToConversation(conversation, text, false, null, false); switchToConversation(conversation, text, false, null, false, false);
}
public void switchToConversationDoNotAppend(Conversation conversation, String text) {
switchToConversation(conversation, text, false, null, false, true);
} }
public void highlightInMuc(Conversation conversation, String nick) { public void highlightInMuc(Conversation conversation, String nick) {
switchToConversation(conversation, null, false, nick, false); switchToConversation(conversation, null, false, nick, false, false);
} }
public void privateMsgInMuc(Conversation conversation, String nick) { public void privateMsgInMuc(Conversation conversation, String nick) {
switchToConversation(conversation, null, false, nick, true); switchToConversation(conversation, null, false, nick, true, false);
} }
private void switchToConversation(Conversation conversation, String text, boolean asQuote, String nick, boolean pm) { private void switchToConversation(Conversation conversation, String text, boolean asQuote, String nick, boolean pm, boolean doNotAppend) {
Intent intent = new Intent(this, ConversationsActivity.class); Intent intent = new Intent(this, ConversationsActivity.class);
intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION); intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION);
intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid()); intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
@ -482,6 +486,9 @@ public abstract class XmppActivity extends ActionBarActivity {
intent.putExtra(ConversationsActivity.EXTRA_NICK, nick); intent.putExtra(ConversationsActivity.EXTRA_NICK, nick);
intent.putExtra(ConversationsActivity.EXTRA_IS_PRIVATE_MESSAGE, pm); intent.putExtra(ConversationsActivity.EXTRA_IS_PRIVATE_MESSAGE, pm);
} }
if (doNotAppend) {
intent.putExtra(ConversationsActivity.EXTRA_DO_NOT_APPEND, true);
}
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent); startActivity(intent);
finish(); finish();

View File

@ -746,4 +746,5 @@
<string name="video_360p">Medium (360p)</string> <string name="video_360p">Medium (360p)</string>
<string name="video_720p">High (720p)</string> <string name="video_720p">High (720p)</string>
<string name="cancelled">cancelled</string> <string name="cancelled">cancelled</string>
<string name="already_drafting_message">You are already drafting a message.</string>
</resources> </resources>