Merge pull request 'master' (#19) from Arne/monocles_chat:master into master

Reviewed-on: https://codeberg.org/Pirujo/monocles_chat_translate/pulls/19
This commit is contained in:
Pirujo 2023-01-08 08:29:20 +00:00
commit 28fb42a286
5 changed files with 87 additions and 8 deletions

View file

@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.services.UnifiedPushBroker;
public class UnifiedPushDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "unified-push-distributor";
@ -84,8 +85,7 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
public List<PushTarget> getRenewals(final String account, final String transport) {
final ImmutableList.Builder<PushTarget> renewalBuilder = ImmutableList.builder();
// TODO use a date somewhat in the future to account for period renewal triggers
final long expiration = System.currentTimeMillis();
final long expiration = System.currentTimeMillis() + UnifiedPushBroker.TIME_TO_RENEW;
final SQLiteDatabase sqLiteDatabase = getReadableDatabase();
try (final Cursor cursor =
sqLiteDatabase.query(
@ -108,13 +108,14 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
public ApplicationEndpoint getEndpoint(
final String account, final String transport, final String instance) {
final long expiration = System.currentTimeMillis() + UnifiedPushBroker.TIME_TO_RENEW;
final SQLiteDatabase sqLiteDatabase = getReadableDatabase();
try (final Cursor cursor =
sqLiteDatabase.query(
"push",
new String[] {"application", "endpoint"},
"account = ? AND transport = ? AND instance = ? AND endpoint IS NOT NULL AND expiration >= "
+ System.currentTimeMillis(),
+ expiration,
new String[] {account, transport, instance},
null,
null,
@ -128,6 +129,21 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper {
return null;
}
public boolean hasEndpoints(final UnifiedPushBroker.Transport transport) {
final SQLiteDatabase sqLiteDatabase = getReadableDatabase();
try (final Cursor cursor =
sqLiteDatabase.rawQuery(
"SELECT EXISTS(SELECT endpoint FROM push WHERE account = ? AND transport = ?)",
new String[] {
transport.account.getUuid(), transport.transport.toEscapedString()
})) {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getInt(0) > 0;
}
}
return false;
}
@Override
public void onUpgrade(
final SQLiteDatabase sqLiteDatabase, final int oldVersion, final int newVersion) {}

View file

@ -15,6 +15,9 @@ import com.google.common.io.BaseEncoding;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@ -25,28 +28,54 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
public class UnifiedPushBroker {
// time to expiration before a renewal attempt is made (24 hours)
public static final long TIME_TO_RENEW = 86_400_000L;
// interval for the 'cron tob' that attempts renewals for everything that expires is lass than
// `TIME_TO_RENEW`
public static final long RENEWAL_INTERVAL = 3_600_000L;
private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
private final XmppConnectionService service;
public UnifiedPushBroker(final XmppConnectionService xmppConnectionService) {
this.service = xmppConnectionService;
SCHEDULER.scheduleAtFixedRate(
this::renewUnifiedPushEndpoints,
RENEWAL_INTERVAL,
RENEWAL_INTERVAL,
TimeUnit.MILLISECONDS);
}
public void renewUnifiedPushEndpointsOnBind(final Account account) {
final Optional<Transport> transport = getTransport();
if (transport.isPresent()) {
final Account transportAccount = transport.get().account;
final Optional<Transport> transportOptional = getTransport();
if (transportOptional.isPresent()) {
final Transport transport = transportOptional.get();
final Account transportAccount = transport.account;
if (transportAccount != null && transportAccount.getUuid().equals(account.getUuid())) {
final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(service);
if (database.hasEndpoints(transport)) {
sendDirectedPresence(transportAccount, transport.transport);
}
Log.d(
Config.LOGTAG,
account.getJid().asBareJid() + ": trigger endpoint renewal on bind");
renewUnifiedEndpoint(transport.get());
renewUnifiedEndpoint(transportOptional.get());
}
}
}
private void sendDirectedPresence(final Account account, Jid to) {
final PresencePacket presence = new PresencePacket();
presence.setTo(to);
service.sendPresencePacket(account, presence);
}
public Optional<Transport> renewUnifiedPushEndpoints() {
final Optional<Transport> transportOptional = getTransport();
if (transportOptional.isPresent()) {
@ -68,6 +97,13 @@ public class UnifiedPushBroker {
final List<UnifiedPushDatabase.PushTarget> renewals =
unifiedPushDatabase.getRenewals(
account.getUuid(), transport.transport.toEscapedString());
Log.d(
Config.LOGTAG,
account.getJid().asBareJid()
+ ": "
+ renewals.size()
+ " UnifiedPush endpoints scheduled for renewal on "
+ transport.transport);
for (final UnifiedPushDatabase.PushTarget renewal : renewals) {
Log.d(
Config.LOGTAG,
@ -110,6 +146,8 @@ public class UnifiedPushBroker {
return;
}
renewUnifiedPushEndpoint(transport, renewal, endpoint, expiration);
} else {
Log.d(Config.LOGTAG, "could not register UP endpoint " + response.getErrorCondition());
}
}

View file

@ -5,6 +5,7 @@ import android.content.Intent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@ -31,6 +32,23 @@ public class AccountUtils {
return false;
}
public static String publicDeviceId(final Account account) {
final UUID uuid;
try {
uuid = UUID.fromString(account.getUuid());
} catch (final IllegalArgumentException e) {
return account.getUuid();
}
final UUID publicDeviceId = getUuid(uuid.getLeastSignificantBits(), uuid.getLeastSignificantBits());
return publicDeviceId.toString();
}
protected static UUID getUuid(final long msb, final long lsb) {
final long msb0 = (msb & 0xffffffffffff0fffL) | 4; // set version
final long lsb0 = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // set variant
return new UUID(msb0, lsb0);
}
public static List<String> getEnabledAccounts(final XmppConnectionService service) {
ArrayList<String> accounts = new ArrayList<>();
for (Account account : service.getAccounts()) {

View file

@ -78,6 +78,7 @@ import eu.siacs.conversations.services.MemorizingTrustManager;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.Patterns;
import eu.siacs.conversations.utils.PhoneHelper;
@ -1593,7 +1594,7 @@ public class XmppConnection implements Runnable {
authenticate.addChild("initial-response").setContent(firstMessage);
}
final Element userAgent = authenticate.addChild("user-agent");
userAgent.setAttribute("id", account.getUuid());
userAgent.setAttribute("id", AccountUtils.publicDeviceId(account));
userAgent
.addChild("software")
.setContent(mXmppConnectionService.getString(R.string.app_name));

View file

@ -1235,4 +1235,10 @@
<string name="pref_enable_persistent_rooms_title">Grupos persistentes</string>
<string name="switch_to_video">Cambiar a vídeo</string>
<string name="reject_switch_to_video">Rechazar peticiones de cambio a vídeo</string>
<string name="unified_push_distributor">Distribuidor UnifiedPush</string>
<string name="pref_up_push_account_title">Cuenta XMPP</string>
<string name="pref_up_push_account_summary">Cuenta a través de la cual se recibirán los mensajes push.</string>
<string name="pref_up_push_server_title">Servidor Push</string>
<string name="pref_up_push_server_summary">Servidor push elegido por el usuario para retransmitir mensajes messages vía XMPP a tu dispositivo.</string>
<string name="no_account_deactivated">Nada (desactivado)</string>
</resources>