Try all gateway translations options

Send jabber:iq:gateway if we're responding to that and fetch translated
response as the JID.  Otherwise use JID escaping if supported.
Otherwise fall back to the dumb ancient % escaping.
This commit is contained in:
Stephen Paul Weber 2022-03-07 15:08:07 -05:00
parent 1d0e285816
commit 7845ded2d3
No known key found for this signature in database
GPG key ID: D11C2911CE519CDE
3 changed files with 78 additions and 51 deletions

View file

@ -145,7 +145,7 @@ import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnBindListener; import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged; import eu.siacs.conversations.xmpp.OnContactStatusChanged;
import eu.siacs.conversations.xmpp.OnGatewayPromptResult; import eu.siacs.conversations.xmpp.OnGatewayResult;
import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnMessageAcknowledged; import eu.siacs.conversations.xmpp.OnMessageAcknowledged;
@ -4656,19 +4656,20 @@ public class XmppConnectionService extends Service {
} }
} }
public void fetchGatewayPrompt(Account account, final Jid jid, final OnGatewayPromptResult callback) { public void fetchFromGateway(Account account, final Jid jid, final String input, final OnGatewayResult callback) {
IqPacket request = new IqPacket(IqPacket.TYPE.GET); IqPacket request = new IqPacket(input == null ? IqPacket.TYPE.GET : IqPacket.TYPE.SET);
request.setTo(jid); request.setTo(jid);
request.query("jabber:iq:gateway"); Element query = request.query("jabber:iq:gateway");
sendIqPacket(account, request, new OnIqPacketReceived() { if (input != null) {
@Override Element prompt = query.addChild("prompt");
public void onIqPacketReceived(Account account, IqPacket packet) { prompt.setContent(input);
if (packet.getType() == IqPacket.TYPE.RESULT) { }
callback.onGatewayPromptResult(packet.query().findChildContent("prompt"), null); sendIqPacket(account, request, (Account acct, IqPacket packet) -> {
} else { if (packet.getType() == IqPacket.TYPE.RESULT) {
Element error = packet.findChild("error"); callback.onGatewayResult(packet.query().findChildContent(input == null ? "prompt" : "jid"), null);
callback.onGatewayPromptResult(null, error == null ? null : error.findChildContent("text")); } else {
} Element error = packet.findChild("error");
callback.onGatewayResult(null, error == null ? null : error.findChildContent("text"));
} }
}); });
} }

View file

@ -43,7 +43,7 @@ import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.ui.interfaces.OnBackendConnected; import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
import eu.siacs.conversations.ui.util.DelayedHintHelper; import eu.siacs.conversations.ui.util.DelayedHintHelper;
import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnGatewayPromptResult; import eu.siacs.conversations.xmpp.OnGatewayResult;
public class EnterJidDialog extends DialogFragment implements OnBackendConnected, TextWatcher { public class EnterJidDialog extends DialogFragment implements OnBackendConnected, TextWatcher {
@ -161,7 +161,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
for (final Contact contact : account.getRoster().getContacts()) { for (final Contact contact : account.getRoster().getContacts()) {
if (contact.showInRoster() && (contact.getPresences().anyIdentity("gateway", null) || contact.getPresences().anySupport("jabber:iq:gateway"))) { if (contact.showInRoster() && (contact.getPresences().anyIdentity("gateway", null) || contact.getPresences().anySupport("jabber:iq:gateway"))) {
context.xmppConnectionService.fetchGatewayPrompt(account, contact.getJid(), (final String prompt, String errorMessage) -> { context.xmppConnectionService.fetchFromGateway(account, contact.getJid(), null, (final String prompt, String errorMessage) -> {
if (prompt == null) return; if (prompt == null) return;
context.runOnUiThread(() -> { context.runOnUiThread(() -> {
@ -216,41 +216,67 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
return; return;
} }
final Jid accountJid = accountJid(); final Jid accountJid = accountJid();
final Jid contactJid; final OnGatewayResult finish = (final String jidString, final String errorMessage) -> {
try { getActivity().runOnUiThread(() -> {
contactJid = Jid.ofEscaped(binding.jid.getText().toString()); if (errorMessage != null) {
} catch (final IllegalArgumentException e) { binding.jidLayout.setError(errorMessage);
binding.jidLayout.setError(getActivity().getString(R.string.invalid_jid)); return;
return;
}
if (!issuedWarning && sanityCheckJid) {
if (contactJid.isDomainJid()) {
binding.jidLayout.setError(
getActivity().getString(R.string.this_looks_like_a_domain));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
return;
}
if (suspiciousSubDomain(contactJid.getDomain().toEscapedString())) {
binding.jidLayout.setError(
getActivity().getString(R.string.this_looks_like_channel));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
return;
}
}
if (mListener != null) {
try {
if (mListener.onEnterJidDialogPositive(accountJid, contactJid)) {
dialog.dismiss();
} }
} catch (JidError error) { if (jidString == null) {
binding.jidLayout.setError(error.toString()); binding.jidLayout.setError(getActivity().getString(R.string.invalid_jid));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add); return;
issuedWarning = false; }
}
final Jid contactJid;
try {
contactJid = Jid.ofEscaped(jidString);
} catch (final IllegalArgumentException e) {
binding.jidLayout.setError(getActivity().getString(R.string.invalid_jid));
return;
}
if (!issuedWarning && sanityCheckJid) {
if (contactJid.isDomainJid()) {
binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_a_domain));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
return;
}
if (suspiciousSubDomain(contactJid.getDomain().toEscapedString())) {
binding.jidLayout.setError(getActivity().getString(R.string.this_looks_like_channel));
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add_anway);
issuedWarning = true;
return;
}
}
if (mListener != null) {
try {
if (mListener.onEnterJidDialogPositive(accountJid, contactJid)) {
dialog.dismiss();
}
} catch (JidError error) {
binding.jidLayout.setError(error.toString());
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setText(R.string.add);
issuedWarning = false;
}
}
});
};
Pair<String,Pair<Jid,Presence>> p = gatewayListAdapter.getSelected();
if (p == null) {
finish.onGatewayResult(binding.jid.getText().toString(), null);
} else if (p.first != null) { // Gateway already responsed to jabber:iq:gateway once
final Account acct = ((XmppActivity) getActivity()).xmppConnectionService.findAccountByJid(accountJid);
((XmppActivity) getActivity()).xmppConnectionService.fetchFromGateway(acct, p.second.first, binding.jid.getText().toString(), finish);
} else if (p.second.first.isDomainJid() && p.second.second.getServiceDiscoveryResult().getFeatures().contains("jid\\20escaping")) {
finish.onGatewayResult(Jid.ofLocalAndDomain(binding.jid.getText().toString(), p.second.first.getDomain().toString()).toString(), null);
} else if (p.second.first.isDomainJid()) {
finish.onGatewayResult(Jid.ofLocalAndDomain(binding.jid.getText().toString().replace("@", "%"), p.second.first.getDomain().toString()).toString(), null);
} else {
finish.onGatewayResult(null, null);
} }
} }

View file

@ -1,7 +1,7 @@
package eu.siacs.conversations.xmpp; package eu.siacs.conversations.xmpp;
public interface OnGatewayPromptResult { public interface OnGatewayResult {
// if prompt is null, there was an error // if prompt is null, there was an error
// errorText may or may not be set // errorText may or may not be set
public void onGatewayPromptResult(String prompt, String errorText); public void onGatewayResult(String prompt, String errorText);
} }