mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-30 09:40:46 +00:00
Simplify API, add builders.
This commit is contained in:
parent
3399d0feb3
commit
64b1dbfdae
@ -23,7 +23,6 @@ import org.whispersystems.libaxolotl.AxolotlAddress;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.SessionBuilder;
|
||||
import org.whispersystems.libaxolotl.logging.Log;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.state.AxolotlStore;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
@ -35,18 +34,17 @@ import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureMessage;
|
||||
import org.whispersystems.textsecure.api.push.TextSecureAddress;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.NetworkFailureException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.textsecure.internal.push.MismatchedDevices;
|
||||
import org.whispersystems.textsecure.internal.push.OutgoingPushMessage;
|
||||
import org.whispersystems.textsecure.internal.push.OutgoingPushMessageList;
|
||||
import org.whispersystems.textsecure.internal.push.PushAttachmentData;
|
||||
import org.whispersystems.textsecure.internal.push.PushBody;
|
||||
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.internal.push.SendMessageResponse;
|
||||
import org.whispersystems.textsecure.internal.push.StaleDevices;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.MismatchedDevicesException;
|
||||
import org.whispersystems.textsecure.internal.push.exceptions.StaleDevicesException;
|
||||
import org.whispersystems.textsecure.internal.util.StaticCredentialsProvider;
|
||||
@ -56,7 +54,6 @@ import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.IncomingPushMessageSignal.Type;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.AttachmentPointer;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext;
|
||||
@ -304,22 +301,21 @@ public class TextSecureMessageSender {
|
||||
List<OutgoingPushMessage> messages = new LinkedList<>();
|
||||
|
||||
if (!recipient.equals(syncAddress)) {
|
||||
PushBody masterBody = getEncryptedMessage(socket, recipient, TextSecureAddress.DEFAULT_DEVICE_ID, plaintext);
|
||||
messages.add(new OutgoingPushMessage(recipient, TextSecureAddress.DEFAULT_DEVICE_ID, masterBody));
|
||||
messages.add(getEncryptedMessage(socket, recipient, TextSecureAddress.DEFAULT_DEVICE_ID, plaintext));
|
||||
}
|
||||
|
||||
for (int deviceId : store.getSubDeviceSessions(recipient.getNumber())) {
|
||||
PushBody body = getEncryptedMessage(socket, recipient, deviceId, plaintext);
|
||||
messages.add(new OutgoingPushMessage(recipient, deviceId, body));
|
||||
messages.add(getEncryptedMessage(socket, recipient, deviceId, plaintext));
|
||||
}
|
||||
|
||||
return new OutgoingPushMessageList(recipient.getNumber(), timestamp, recipient.getRelay().orNull(), messages);
|
||||
}
|
||||
|
||||
private PushBody getEncryptedMessage(PushServiceSocket socket, TextSecureAddress recipient, int deviceId, byte[] plaintext)
|
||||
private OutgoingPushMessage getEncryptedMessage(PushServiceSocket socket, TextSecureAddress recipient, int deviceId, byte[] plaintext)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
AxolotlAddress axolotlAddress = new AxolotlAddress(recipient.getNumber(), deviceId);
|
||||
TextSecureCipher cipher = new TextSecureCipher(store);
|
||||
|
||||
if (!store.containsSession(axolotlAddress)) {
|
||||
try {
|
||||
@ -343,17 +339,7 @@ public class TextSecureMessageSender {
|
||||
}
|
||||
}
|
||||
|
||||
TextSecureCipher cipher = new TextSecureCipher(store, axolotlAddress);
|
||||
CiphertextMessage message = cipher.encrypt(plaintext);
|
||||
int remoteRegistrationId = cipher.getRemoteRegistrationId();
|
||||
|
||||
if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
|
||||
return new PushBody(Type.PREKEY_BUNDLE_VALUE, remoteRegistrationId, message.serialize());
|
||||
} else if (message.getType() == CiphertextMessage.WHISPER_TYPE) {
|
||||
return new PushBody(Type.CIPHERTEXT_VALUE, remoteRegistrationId, message.serialize());
|
||||
} else {
|
||||
throw new AssertionError("Unknown ciphertext type: " + message.getType());
|
||||
}
|
||||
return cipher.encrypt(axolotlAddress, plaintext);
|
||||
}
|
||||
|
||||
private void handleMismatchedDevices(PushServiceSocket socket, TextSecureAddress recipient,
|
||||
|
@ -37,11 +37,15 @@ import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureMessage;
|
||||
import org.whispersystems.textsecure.internal.push.OutgoingPushMessage;
|
||||
import org.whispersystems.textsecure.internal.push.PushMessageProtos;
|
||||
import org.whispersystems.textsecure.internal.push.PushTransportDetails;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.IncomingPushMessageSignal.Type;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent;
|
||||
import static org.whispersystems.textsecure.internal.push.PushMessageProtos.PushMessageContent.GroupContext.Type.DELIVER;
|
||||
|
||||
@ -52,15 +56,28 @@ import static org.whispersystems.textsecure.internal.push.PushMessageProtos.Push
|
||||
*/
|
||||
public class TextSecureCipher {
|
||||
|
||||
private final SessionCipher sessionCipher;
|
||||
private final AxolotlStore axolotlStore;
|
||||
|
||||
public TextSecureCipher(AxolotlStore axolotlStore, AxolotlAddress destination) {
|
||||
this.sessionCipher = new SessionCipher(axolotlStore, destination);
|
||||
public TextSecureCipher(AxolotlStore axolotlStore) {
|
||||
this.axolotlStore = axolotlStore;
|
||||
}
|
||||
|
||||
public CiphertextMessage encrypt(byte[] unpaddedMessage) {
|
||||
public OutgoingPushMessage encrypt(AxolotlAddress destination, byte[] unpaddedMessage) {
|
||||
SessionCipher sessionCipher = new SessionCipher(axolotlStore, destination);
|
||||
PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
|
||||
return sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
|
||||
CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
|
||||
int remoteRegistrationId = sessionCipher.getRemoteRegistrationId();
|
||||
String body = Base64.encodeBytes(message.serialize());
|
||||
|
||||
int type;
|
||||
|
||||
switch (message.getType()) {
|
||||
case CiphertextMessage.PREKEY_TYPE: type = Type.PREKEY_BUNDLE_VALUE; break;
|
||||
case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT_VALUE; break;
|
||||
default: throw new AssertionError("Bad type: " + message.getType());
|
||||
}
|
||||
|
||||
return new OutgoingPushMessage(type, destination.getDeviceId(), remoteRegistrationId, body);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,6 +100,9 @@ public class TextSecureCipher {
|
||||
LegacyMessageException, NoSessionException
|
||||
{
|
||||
try {
|
||||
AxolotlAddress sourceAddress = new AxolotlAddress(envelope.getSource(), envelope.getSourceDevice());
|
||||
SessionCipher sessionCipher = new SessionCipher(axolotlStore, sourceAddress);
|
||||
|
||||
byte[] paddedMessage;
|
||||
|
||||
if (envelope.isPreKeyWhisperMessage()) {
|
||||
@ -104,10 +124,6 @@ public class TextSecureCipher {
|
||||
}
|
||||
}
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
return sessionCipher.getRemoteRegistrationId();
|
||||
}
|
||||
|
||||
private TextSecureMessage createTextSecureMessage(TextSecureEnvelope envelope, PushMessageContent content) {
|
||||
TextSecureGroup groupInfo = createGroupInfo(envelope, content);
|
||||
List<TextSecureAttachment> attachments = new LinkedList<>();
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.whispersystems.textsecure.api.messages;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class TextSecureAttachment {
|
||||
|
||||
private final String contentType;
|
||||
@ -38,4 +40,40 @@ public abstract class TextSecureAttachment {
|
||||
public TextSecureAttachmentPointer asPointer() {
|
||||
return (TextSecureAttachmentPointer)this;
|
||||
}
|
||||
|
||||
public static Builder newStreamBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private InputStream inputStream;
|
||||
private String contentType;
|
||||
private long length;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder withStream(InputStream inputStream) {
|
||||
this.inputStream = inputStream;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withLength(long length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextSecureAttachmentStream build() {
|
||||
if (inputStream == null) throw new IllegalArgumentException("Must specify stream!");
|
||||
if (contentType == null) throw new IllegalArgumentException("No content type specified!");
|
||||
if (length == 0) throw new IllegalArgumentException("No length specified!");
|
||||
|
||||
return new TextSecureAttachmentStream(inputStream, contentType, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.logging.Log;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
import org.whispersystems.textsecure.api.push.TextSecureAddress;
|
||||
import org.whispersystems.textsecure.internal.push.PushMessageProtos.IncomingPushMessageSignal;
|
||||
import org.whispersystems.textsecure.internal.util.Base64;
|
||||
import org.whispersystems.textsecure.internal.util.Hex;
|
||||
@ -127,6 +129,15 @@ public class TextSecureEnvelope {
|
||||
return signal.getSourceDevice();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The envelope's sender as a TextSecureAddress.
|
||||
*/
|
||||
public TextSecureAddress getSourceAddress() {
|
||||
return new TextSecureAddress(signal.getSource(),
|
||||
signal.hasRelay() ? Optional.fromNullable(signal.getRelay()) :
|
||||
Optional.<String>absent());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The envelope content type.
|
||||
*/
|
||||
|
@ -96,4 +96,56 @@ public class TextSecureGroup {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public static Builder newUpdateBuilder() {
|
||||
return new Builder(Type.UPDATE);
|
||||
}
|
||||
|
||||
public static Builder newBuilder(Type type) {
|
||||
return new Builder(type);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Type type;
|
||||
private byte[] id;
|
||||
private String name;
|
||||
private List<String> members;
|
||||
private TextSecureAttachment avatar;
|
||||
|
||||
private Builder(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Builder withId(byte[] id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withMembers(List<String> members) {
|
||||
this.members = members;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAvatar(TextSecureAttachment avatar) {
|
||||
this.avatar = avatar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextSecureGroup build() {
|
||||
if (id == null) throw new IllegalArgumentException("No group ID specified!");
|
||||
|
||||
if (type == Type.UPDATE && name == null && members == null && avatar == null) {
|
||||
throw new IllegalArgumentException("Group update with no updates!");
|
||||
}
|
||||
|
||||
return new TextSecureGroup(type, id, name, members, avatar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,6 +94,10 @@ public class TextSecureMessage {
|
||||
}
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The message timestamp.
|
||||
*/
|
||||
@ -133,4 +137,55 @@ public class TextSecureMessage {
|
||||
public boolean isGroupUpdate() {
|
||||
return group.isPresent() && group.get().getType() != TextSecureGroup.Type.DELIVER;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private List<TextSecureAttachment> attachments = new LinkedList<>();
|
||||
private long timestamp;
|
||||
private TextSecureGroup group;
|
||||
private String body;
|
||||
private boolean endSession;
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder withTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder asGroupMessage(TextSecureGroup group) {
|
||||
this.group = group;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAttachment(TextSecureAttachment attachment) {
|
||||
this.attachments.add(attachment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAttachments(List<TextSecureAttachment> attachments) {
|
||||
this.attachments.addAll(attachments);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withBody(String body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder asEndSessionMessage() {
|
||||
this.endSession = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder asEndSessionMessage(boolean endSession) {
|
||||
this.endSession = endSession;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextSecureMessage build() {
|
||||
if (timestamp == 0) timestamp = System.currentTimeMillis();
|
||||
return new TextSecureMessage(timestamp, group, attachments, body, true, endSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,15 @@ public class OutgoingPushMessage {
|
||||
@JsonProperty
|
||||
private String body;
|
||||
|
||||
public OutgoingPushMessage(TextSecureAddress address, int deviceId, PushBody body) {
|
||||
this.type = body.getType();
|
||||
this.destinationDeviceId = deviceId;
|
||||
this.destinationRegistrationId = body.getRemoteRegistrationId();
|
||||
this.body = Base64.encodeBytes(body.getBody());
|
||||
public OutgoingPushMessage(int type,
|
||||
int destinationDeviceId,
|
||||
int destinationRegistrationId,
|
||||
String body)
|
||||
{
|
||||
this.type = type;
|
||||
this.destinationDeviceId = destinationDeviceId;
|
||||
this.destinationRegistrationId = destinationRegistrationId;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public int getDestinationDeviceId() {
|
||||
|
@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2014 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecure.internal.push;
|
||||
|
||||
public class PushBody {
|
||||
|
||||
private final int type;
|
||||
private final int remoteRegistrationId;
|
||||
private final byte[] body;
|
||||
|
||||
public PushBody(int type, int remoteRegistrationId, byte[] body) {
|
||||
this.type = type;
|
||||
this.remoteRegistrationId = remoteRegistrationId;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
return remoteRegistrationId;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user