Skip to content

Commit

Permalink
v3.5 (build 260)
Browse files Browse the repository at this point in the history
  • Loading branch information
finiasz committed Dec 29, 2024
1 parent f68d1f0 commit 54f7ff9
Show file tree
Hide file tree
Showing 128 changed files with 7,824 additions and 2,549 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# Build 260 (3.5)
2024-12-29

- Fix some issues with internal PDF viewer

# ~~Build 259 (3.5)~~
2024-12-22

- optimized message download at app startup
- better GPS management when sharing your location
- show sent message status in discussion list
- recognize text content inside images (OCR)
- avoid some useless messages during phone calls in a multi-device settings
- (experimental) internal PDF viewer (opt-in in "other settings")
- several small bug fixes

# Build 258 (3.4.1)
2024-12-03

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ private void decryptAndProcess(ChannelManagerSession channelManagerSession, Netw
if (!channelManagerSession.identityDelegate.isIdentityAContactOfOwnedIdentity(channelManagerSession.session, ownedIdentity, contactIdentity)) {
// contact unknown, set the from identity of the inbox message to reprocess it once the contact is created
Logger.i("Received a PreKey encrypted message from an unknown contact, putting it on hold...");
channelManagerSession.networkFetchDelegate.setInboxMessageFromIdentityForMissingPreKeyContact(channelManagerSession.session, networkReceivedMessage.getOwnedIdentity(), networkReceivedMessage.getMessageUid(), contactIdentity);
channelManagerSession.networkFetchDelegate.setInboxMessageFromIdentityForMissingPreKeyContact(
channelManagerSession.session,
networkReceivedMessage.getOwnedIdentity(),
networkReceivedMessage.getMessageUid(),
contactIdentity);
return;
} else {
EnumSet<ObvContactActiveOrInactiveReason> reasons = channelManagerSession.identityDelegate.getContactActiveOrInactiveReasons(channelManagerSession.session, ownedIdentity, contactIdentity);
Expand Down Expand Up @@ -166,6 +170,7 @@ private void decryptAndProcess(ChannelManagerSession channelManagerSession, Netw
channelReceivedApplicationMessage.getOwnedIdentity(),
channelReceivedApplicationMessage.getMessageUid(),
authEncKeyAndChannelInfo.getReceptionChannelInfo().getRemoteIdentity(),
authEncKeyAndChannelInfo.getReceptionChannelInfo().getRemoteDeviceUid(),
channelReceivedApplicationMessage.getAttachmentsKeyAndMetadata(),
channelReceivedApplicationMessage.getMessagePayload(),
channelReceivedMessage.getExtendedPayloadKey()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -73,11 +72,11 @@ public class ObliviousChannel extends NetworkChannel implements ObvDatabase {

private final ChannelManagerSession channelManagerSession;

private UID currentDeviceUid;
private final UID currentDeviceUid;
static final String CURRENT_DEVICE_UID = "current_device_uid";
private UID remoteDeviceUid;
private final UID remoteDeviceUid;
static final String REMOTE_DEVICE_UID = "remote_device_uid";
private Identity remoteIdentity;
private final Identity remoteIdentity;
static final String REMOTE_IDENTITY = "contact_identity";
private boolean confirmed;
static final String CONFIRMED = "confirmed";
Expand Down Expand Up @@ -742,7 +741,9 @@ public static NetworkChannel[] acceptableChannelsForPosting(ChannelManagerSessio
case SendChannelInfo.ALL_CONFIRMED_OBLIVIOUS_CHANNELS_OR_PRE_KEY_ON_SAME_SERVER_TYPE: {
List<NetworkChannel> acceptableChannels = new ArrayList<>();
UID currentDeviceUid = channelManagerSession.identityDelegate.getCurrentDeviceUidOfOwnedIdentity(channelManagerSession.session, message.getSendChannelInfo().getFromIdentity());
for (Identity toIdentity: message.getSendChannelInfo().getToIdentities()) {
for (int i = 0; i < message.getSendChannelInfo().getToIdentities().length; i++) {
Identity toIdentity = message.getSendChannelInfo().getToIdentities()[i];
UID toDeviceUid = message.getSendChannelInfo().getRemoteDeviceUids()[i];
List<UidAndPreKey> uidsAndPreKeys = new ArrayList<>();
if (Objects.equals(message.getSendChannelInfo().getFromIdentity(), toIdentity)) {
List<OwnedDeviceAndPreKey> ownedDeviceAndPreKeys = channelManagerSession.identityDelegate.getDevicesAndPreKeysOfOwnedIdentity(channelManagerSession.session, message.getSendChannelInfo().getFromIdentity());
Expand All @@ -754,6 +755,20 @@ public static NetworkChannel[] acceptableChannelsForPosting(ChannelManagerSessio
} else {
uidsAndPreKeys = channelManagerSession.identityDelegate.getDeviceUidsAndPreKeysOfContactIdentity(channelManagerSession.session, message.getSendChannelInfo().getFromIdentity(), toIdentity);
}
// if a toDeviceUid is specified, only send to it. If not found, still send to all devices
if (toDeviceUid != null) {
UidAndPreKey uidAndPreKeyFound = null;
for (UidAndPreKey uidAndPreKey : uidsAndPreKeys) {
if (uidAndPreKey.uid.equals(toDeviceUid)) {
uidAndPreKeyFound = uidAndPreKey;
break;
}
}
if (uidAndPreKeyFound != null) {
acceptableChannels.addAll(ObliviousChannel.getAcceptableObliviousOrPreKeyChannels(channelManagerSession, message.getSendChannelInfo().getFromIdentity(), currentDeviceUid, new UidAndPreKey[]{uidAndPreKeyFound}, toIdentity));
continue;
}
}
acceptableChannels.addAll(ObliviousChannel.getAcceptableObliviousOrPreKeyChannels(channelManagerSession, message.getSendChannelInfo().getFromIdentity(), currentDeviceUid, uidsAndPreKeys.toArray(new UidAndPreKey[0]), toIdentity));
}
return acceptableChannels.toArray(new NetworkChannel[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@

public class ProvisionedKeyMaterial implements ObvDatabase {
static final String TABLE_NAME = "provisioned_key_material";
static final String GET_ALL_INDEX_NAME = "provisioned_key_material_get_all_index";
static final String EXPIRE_INDEX_NAME = "provisioned_key_material_expire_index";


private final ChannelManagerSession channelManagerSession;

Expand Down Expand Up @@ -202,6 +205,9 @@ public static void createTable(Session session) throws SQLException {
PROVISION_OBLIVIOUS_CHANNEL_REMOTE_IDENTITY + " BLOB NOT NULL, " +
"CONSTRAINT PK_" + TABLE_NAME + " PRIMARY KEY(" + SELF_RATCHETING_COUNT + ", " + PROVISION_FULL_RATCHETING_COUNT + ", " + PROVISION_OBLIVIOUS_CHANNEL_CURRENT_DEVICE_UID + ", " + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_DEVICE_UID + ", " + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_IDENTITY + "), " +
"FOREIGN KEY (" + PROVISION_FULL_RATCHETING_COUNT + ", " + PROVISION_OBLIVIOUS_CHANNEL_CURRENT_DEVICE_UID + ", " + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_DEVICE_UID + ", " + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_IDENTITY + ") REFERENCES " + Provision.TABLE_NAME + "(" + Provision.FULL_RATCHETING_COUNT + ", " + Provision.OBLIVIOUS_CHANNEL_CURRENT_DEVICE_UID + ", " + Provision.OBLIVIOUS_CHANNEL_REMOTE_DEVICE_UID + ", " + Provision.OBLIVIOUS_CHANNEL_REMOTE_IDENTITY + ") ON DELETE CASCADE);");

statement.execute("CREATE INDEX IF NOT EXISTS " + GET_ALL_INDEX_NAME + " ON " + TABLE_NAME + "(" + KEY_ID + "," + PROVISION_OBLIVIOUS_CHANNEL_CURRENT_DEVICE_UID + ")");
statement.execute("CREATE INDEX IF NOT EXISTS " + EXPIRE_INDEX_NAME + " ON " + TABLE_NAME + "(" + EXPIRATION_TIMESTAMP + "," + PROVISION_OBLIVIOUS_CHANNEL_CURRENT_DEVICE_UID + "," + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_DEVICE_UID + "," + PROVISION_OBLIVIOUS_CHANNEL_REMOTE_IDENTITY + ")");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import java.nio.charset.StandardCharsets;

public abstract class Constants {
public static final int CURRENT_ENGINE_DB_SCHEMA_VERSION = 42;
public static final int SERVER_API_VERSION = 18;
public static final int CURRENT_ENGINE_DB_SCHEMA_VERSION = 43;
public static final int SERVER_API_VERSION = 19;
public static final int CURRENT_BACKUP_JSON_VERSION = 0;

// files / folders
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ public void queue(Operation op) {
if (uid != null) {
lockOnQueuedOperationUids.lock();
if (queuedOperationUids.contains(uid)) {
Logger.d("NoDuplicateOperationQueue already contains an operation of type " + op.getClass() + " with UID " + uid);
Logger.d("queue size: " + operations.size() + " set size: " + queuedOperationUids.size());
lockOnQueuedOperationUids.unlock();
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Olvid for Android
* Copyright © 2019-2024 Olvid SAS
*
* This file is part of Olvid for Android.
*
* Olvid is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* Olvid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Olvid. If not, see <https://www.gnu.org/licenses/>.
*/

package io.olvid.engine.datatypes;


import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import io.olvid.engine.Logger;

public class NoDuplicatePriorityOperationQueue {
private final PriorityBlockingQueue<PriorityOperation> operations;
private final Lock lockOnQueuedOperationUids;
private final Set<UID> queuedOperationUids;

private boolean executing = false;

public NoDuplicatePriorityOperationQueue() {
queuedOperationUids = new HashSet<>();
lockOnQueuedOperationUids = new ReentrantLock();
operations = new PriorityBlockingQueue<>();
}

public void queue(PriorityOperation op) {
if (!op.getDependencies().isEmpty()) {
Logger.e("Cannot queue an operation with dependencies into a NoDuplicatePriorityOperationQueue.");
return;
}
UID uid = op.getUid();
if (uid != null) {
lockOnQueuedOperationUids.lock();
if (queuedOperationUids.contains(uid)) {
lockOnQueuedOperationUids.unlock();
return;
}
queuedOperationUids.add(uid);
lockOnQueuedOperationUids.unlock();
}
op.setPending();
operations.add(op);
}

public void execute(int numberOfThreads) {
execute(numberOfThreads, null);
}

public void execute(int numberOfThreads, String tag) {
if (executing) {
Logger.e("You can only call execute once on a NoDuplicatePriorityOperationQueue.");
return;
}
executing = true;
for (int i=0; i<numberOfThreads; i++) {
new NoDuplicatePriorityOperationQueueThread(i, tag).start();
}
}

class NoDuplicatePriorityOperationQueueThread extends Thread {
final int threadNumber;
NoDuplicatePriorityOperationQueueThread(int i, String tag) {
super();
threadNumber = i;
if (tag != null) {
setName(tag + "-" + threadNumber);
}
}

@Override
public void run() {
//noinspection InfiniteLoopStatement
while (true) {
PriorityOperation op;
try {
op = operations.take();
} catch (InterruptedException e) {
continue;
}

op.updateReadiness();
op.processCancel();

if (op.getTimestampOfLastExecution() != 0) {
long timeToWait = op.getTimestampOfLastExecution() - System.currentTimeMillis() + OperationQueue.MILLISECONDS_TO_WAIT_BETWEEN_TWO_OPERATION_EXECUTIONS;
if (timeToWait > 0) {
try {
sleep(timeToWait);
} catch (InterruptedException ignored) {}
}
}
op.setTimestampOfLastExecution(System.currentTimeMillis());

if (op.isReady()) {
if (op.areConditionsFulfilled()) {
if (op.getUid() != null) {
lockOnQueuedOperationUids.lock();
queuedOperationUids.remove(op.getUid());
lockOnQueuedOperationUids.unlock();
}
try {
op.execute();
} catch (Exception e) {
Logger.e("Exception in operation that could have killed a queue!");
Logger.x(e);
}
} else {
operations.add(op);
}
}
}
}
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public PriorityOperationQueue() {
}

public void queue(PriorityOperation op) {
if (op.getDependencies().size() > 0) {
if (!op.getDependencies().isEmpty()) {
Logger.e("Cannot queue an operation with dependencies into a PriorityOperationQueue.");
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import io.olvid.engine.Logger;
import io.olvid.engine.datatypes.Identity;
import io.olvid.engine.datatypes.UID;

public class ChannelApplicationMessageToSend implements ChannelMessageToSend {
private final SendChannelInfo sendChannelInfo;
Expand All @@ -45,6 +46,21 @@ public ChannelApplicationMessageToSend(Identity[] toIdentities, Identity fromIde
this.isVoipMessage = isVoipMessage;
}

// some toDeviceUids may be null: send to all devices for this contact in that case
public ChannelApplicationMessageToSend(Identity[] toIdentities, UID[] toDeviceUids, Identity fromIdentity, byte[] messagePayload, byte[] extendedMessagePayload, Attachment[] attachments, boolean hasUserContent, boolean isVoipMessage) throws Exception {
SendChannelInfo[] sendChannelInfos = SendChannelInfo.createAllConfirmedObliviousChannelsOrPreKeysInfoForMultipleIdentities(toIdentities, toDeviceUids, fromIdentity);
if (sendChannelInfos.length != 1) {
Logger.e("Error: trying to create a ChannelApplicationMessageToSend for identities on different servers");
throw new Exception();
}
this.sendChannelInfo = sendChannelInfos[0];
this.messagePayload = messagePayload;
this.extendedMessagePayload = extendedMessagePayload;
this.attachments = attachments;
this.hasUserContent = hasUserContent;
this.isVoipMessage = isVoipMessage;
}


@Override
public int getMessageType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ public class DecryptedApplicationMessage {
private final UID messageUid;
private final byte[] messagePayload;
private final Identity fromIdentity;
private final UID fromDeviceUid;
private final Identity toIdentity;
private final long serverTimestamp;
private final long downloadTimestamp;
private final long localDownloadTimestamp;

public DecryptedApplicationMessage(UID messageUid, byte[] messagePayload, Identity fromIdentity, Identity toIdentity, long serverTimestamp, long downloadTimestamp, long localDownloadTimestamp) {
public DecryptedApplicationMessage(UID messageUid, byte[] messagePayload, Identity fromIdentity, UID fromDeviceUid, Identity toIdentity, long serverTimestamp, long downloadTimestamp, long localDownloadTimestamp) {
this.messageUid = messageUid;
this.messagePayload = messagePayload;
this.fromIdentity = fromIdentity;
this.fromDeviceUid = fromDeviceUid;
this.toIdentity = toIdentity;
this.serverTimestamp = serverTimestamp;
this.downloadTimestamp = downloadTimestamp;
Expand All @@ -57,6 +59,10 @@ public Identity getToIdentity() {
return toIdentity;
}

public UID getFromDeviceUid() {
return fromDeviceUid;
}

public long getServerTimestamp() {
return serverTimestamp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
import io.olvid.engine.datatypes.UID;

public class IdentityAndUid {
public final Identity ownedIdentity;
public final Identity identity;
public final UID uid;

public IdentityAndUid(Identity ownedIdentity, UID uid) {
this.ownedIdentity = ownedIdentity;
public IdentityAndUid(Identity identity, UID uid) {
this.identity = identity;
this.uid = uid;
}

Expand All @@ -39,17 +39,17 @@ public boolean equals(Object o) {
return false;
}
IdentityAndUid other = (IdentityAndUid) o;
return ownedIdentity.equals(other.ownedIdentity) && uid.equals(other.uid);
return identity.equals(other.identity) && uid.equals(other.uid);
}

@Override
public int hashCode() {
return ownedIdentity.hashCode() ^ uid.hashCode();
return identity.hashCode() ^ uid.hashCode();
}

@Override
public String toString() {
return ownedIdentity + " - " + uid;
return identity + " - " + uid;
}

public static UID computeUniqueUid(Identity ownedIdentity, UID uid) {
Expand Down
Loading

0 comments on commit 54f7ff9

Please sign in to comment.