clean up stickers

This commit is contained in:
Ryan ZHAO 2021-02-22 10:21:06 +11:00
parent 19a829d011
commit 88bbc0b677
12 changed files with 0 additions and 2439 deletions

View File

@ -274,7 +274,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
String groupId = address.toGroupString();
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
Optional<Quote> quote = getQuoteFor(message);
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
List<SharedContact> sharedContacts = getSharedContactsFor(message);
List<Preview> previews = getPreviewsFor(message);
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();

View File

@ -212,26 +212,6 @@ public abstract class PushSendJob extends SendJob {
return Optional.of(new SignalServiceDataMessage.Quote(quoteId, new SignalServiceAddress(quoteAuthor.serialize()), quoteBody, quoteAttachments));
}
protected Optional<SignalServiceDataMessage.Sticker> getStickerFor(OutgoingMediaMessage message) {
Attachment stickerAttachment = Stream.of(message.getAttachments()).filter(Attachment::isSticker).findFirst().orElse(null);
if (stickerAttachment == null) {
return Optional.absent();
}
try {
byte[] packId = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackId());
byte[] packKey = Hex.fromStringCondensed(stickerAttachment.getSticker().getPackKey());
int stickerId = stickerAttachment.getSticker().getStickerId();
SignalServiceAttachment attachment = getAttachmentPointerFor(stickerAttachment);
return Optional.of(new SignalServiceDataMessage.Sticker(packId, packKey, stickerId, attachment));
} catch (IOException e) {
Log.w(TAG, "Failed to decode sticker id/key", e);
return Optional.absent();
}
}
List<SharedContact> getSharedContactsFor(OutgoingMediaMessage mediaMessage) {
List<SharedContact> sharedContacts = new LinkedList<>();
@ -259,9 +239,5 @@ public abstract class PushSendJob extends SendJob {
}).toList();
}
protected void rotateSenderCertificateIfNecessary() throws IOException {
// Loki - We don't need verification on sender certificates
}
protected abstract void onPushSend() throws Exception;
}

View File

@ -1,13 +0,0 @@
package org.session.libsignal.libsignal.util;
import org.session.libsignal.libsignal.IdentityKey;
import java.util.Comparator;
public class IdentityKeyComparator extends ByteArrayComparator implements Comparator<IdentityKey> {
@Override
public int compare(IdentityKey first, IdentityKey second) {
return compare(first.getPublicKey().serialize(), second.getPublicKey().serialize());
}
}

View File

@ -46,10 +46,6 @@ public class SendMessageResult {
return networkFailure;
}
public boolean isUnregisteredFailure() {
return unregisteredFailure;
}
public IdentityFailure getIdentityFailure() {
return identityFailure;
}

View File

@ -25,10 +25,6 @@ public class SignalServiceAttachmentStream extends SignalServiceAttachment {
private final int height;
private final Optional<String> caption;
public SignalServiceAttachmentStream(InputStream inputStream, String contentType, long length, Optional<String> fileName, boolean voiceNote, ProgressListener listener) {
this(inputStream, contentType, length, fileName, voiceNote, Optional.<byte[]>absent(), 0, 0, Optional.<String>absent(), listener);
}
public SignalServiceAttachmentStream(InputStream inputStream, String contentType, long length, Optional<String> fileName, boolean voiceNote, Optional<byte[]> preview, int width, int height, Optional<String> caption, ProgressListener listener) {
super(contentType);
this.inputStream = inputStream;

View File

@ -276,11 +276,6 @@ public class SignalServiceDataMessage {
return this;
}
public Builder withAttachment(SignalServiceAttachment attachment) {
this.attachments.add(attachment);
return this;
}
public Builder withAttachments(List<SignalServiceAttachment> attachments) {
this.attachments.addAll(attachments);
return this;
@ -296,10 +291,6 @@ public class SignalServiceDataMessage {
return this;
}
public Builder asExpirationUpdate() {
return asExpirationUpdate(true);
}
public Builder asExpirationUpdate(boolean expirationUpdate) {
this.expirationUpdate = expirationUpdate;
return this;
@ -320,11 +311,6 @@ public class SignalServiceDataMessage {
return this;
}
public Builder withSharedContact(SharedContact contact) {
this.sharedContacts.add(contact);
return this;
}
public Builder withSharedContacts(List<SharedContact> contacts) {
this.sharedContacts.addAll(contacts);
return this;
@ -420,34 +406,4 @@ public class SignalServiceDataMessage {
return image;
}
}
public static class Sticker {
private final byte[] packId;
private final byte[] packKey;
private final int stickerId;
private final SignalServiceAttachment attachment;
public Sticker(byte[] packId, byte[] packKey, int stickerId, SignalServiceAttachment attachment) {
this.packId = packId;
this.packKey = packKey;
this.stickerId = stickerId;
this.attachment = attachment;
}
public byte[] getPackId() {
return packId;
}
public byte[] getPackKey() {
return packKey;
}
public int getStickerId() {
return stickerId;
}
public SignalServiceAttachment getAttachment() {
return attachment;
}
}
}

View File

@ -39,63 +39,8 @@ import javax.crypto.spec.SecretKeySpec;
*/
public class SignalServiceEnvelope {
private static final String TAG = SignalServiceEnvelope.class.getSimpleName();
private static final int SUPPORTED_VERSION = 1;
private static final int CIPHER_KEY_SIZE = 32;
private static final int MAC_KEY_SIZE = 20;
private static final int MAC_SIZE = 10;
private static final int VERSION_OFFSET = 0;
private static final int VERSION_LENGTH = 1;
private static final int IV_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
private static final int IV_LENGTH = 16;
private static final int CIPHERTEXT_OFFSET = IV_OFFSET + IV_LENGTH;
private final Envelope envelope;
/**
* Construct an envelope from a serialized, Base64 encoded SignalServiceEnvelope, encrypted
* with a signaling key.
*
* @param message The serialized SignalServiceEnvelope, base64 encoded and encrypted.
* @param signalingKey The signaling key.
* @throws IOException
* @throws InvalidVersionException
*/
public SignalServiceEnvelope(String message, String signalingKey, boolean isSignalingKeyEncrypted)
throws IOException, InvalidVersionException
{
this(Base64.decode(message), signalingKey, isSignalingKeyEncrypted);
}
/**
* Construct an envelope from a serialized SignalServiceEnvelope, encrypted with a signaling key.
*
* @param input The serialized and (optionally) encrypted SignalServiceEnvelope.
* @param signalingKey The signaling key.
* @throws InvalidVersionException
* @throws IOException
*/
public SignalServiceEnvelope(byte[] input, String signalingKey, boolean isSignalingKeyEncrypted)
throws InvalidVersionException, IOException
{
if (!isSignalingKeyEncrypted) {
this.envelope = Envelope.parseFrom(input);
} else {
if (input.length < VERSION_LENGTH || input[VERSION_OFFSET] != SUPPORTED_VERSION) {
throw new InvalidVersionException("Unsupported version!");
}
SecretKeySpec cipherKey = getCipherKey(signalingKey);
SecretKeySpec macKey = getMacKey(signalingKey);
verifyMac(input, macKey);
this.envelope = Envelope.parseFrom(getPlaintext(input, cipherKey));
}
}
public SignalServiceEnvelope(Envelope proto) {
Envelope.Builder builder = Envelope.newBuilder();
builder.setType(Envelope.Type.valueOf(proto.getType().getNumber()));
@ -126,17 +71,6 @@ public class SignalServiceEnvelope {
this.envelope = builder.build();
}
public SignalServiceEnvelope(int type, long timestamp, byte[] content, long serverTimestamp) {
Envelope.Builder builder = Envelope.newBuilder()
.setType(Envelope.Type.valueOf(type))
.setTimestamp(timestamp)
.setServerTimestamp(serverTimestamp);
if (content != null) builder.setContent(ByteString.copyFrom(content));
this.envelope = builder.build();
}
public boolean hasSource() {
return envelope.hasSource() && envelope.getSource().length() > 0;
}
@ -205,80 +139,4 @@ public class SignalServiceEnvelope {
public boolean isClosedGroupCiphertext() {
return envelope.getType().getNumber() == Envelope.Type.CLOSED_GROUP_CIPHERTEXT_VALUE;
}
private byte[] getPlaintext(byte[] ciphertext, SecretKeySpec cipherKey) throws IOException {
try {
byte[] ivBytes = new byte[IV_LENGTH];
System.arraycopy(ciphertext, IV_OFFSET, ivBytes, 0, ivBytes.length);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, cipherKey, iv);
return cipher.doFinal(ciphertext, CIPHERTEXT_OFFSET,
ciphertext.length - VERSION_LENGTH - IV_LENGTH - MAC_SIZE);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (NoSuchPaddingException e) {
throw new AssertionError(e);
} catch (InvalidKeyException e) {
throw new AssertionError(e);
} catch (InvalidAlgorithmParameterException e) {
throw new AssertionError(e);
} catch (IllegalBlockSizeException e) {
throw new AssertionError(e);
} catch (BadPaddingException e) {
Log.w(TAG, e);
throw new IOException("Bad padding?");
}
}
private void verifyMac(byte[] ciphertext, SecretKeySpec macKey) throws IOException {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(macKey);
if (ciphertext.length < MAC_SIZE + 1)
throw new IOException("Invalid MAC!");
mac.update(ciphertext, 0, ciphertext.length - MAC_SIZE);
byte[] ourMacFull = mac.doFinal();
byte[] ourMacBytes = new byte[MAC_SIZE];
System.arraycopy(ourMacFull, 0, ourMacBytes, 0, ourMacBytes.length);
byte[] theirMacBytes = new byte[MAC_SIZE];
System.arraycopy(ciphertext, ciphertext.length-MAC_SIZE, theirMacBytes, 0, theirMacBytes.length);
Log.w(TAG, "Our MAC: " + Hex.toString(ourMacBytes));
Log.w(TAG, "Thr MAC: " + Hex.toString(theirMacBytes));
if (!Arrays.equals(ourMacBytes, theirMacBytes)) {
throw new IOException("Invalid MAC compare!");
}
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (InvalidKeyException e) {
throw new AssertionError(e);
}
}
private SecretKeySpec getCipherKey(String signalingKey) throws IOException {
byte[] signalingKeyBytes = Base64.decode(signalingKey);
byte[] cipherKey = new byte[CIPHER_KEY_SIZE];
System.arraycopy(signalingKeyBytes, 0, cipherKey, 0, cipherKey.length);
return new SecretKeySpec(cipherKey, "AES");
}
private SecretKeySpec getMacKey(String signalingKey) throws IOException {
byte[] signalingKeyBytes = Base64.decode(signalingKey);
byte[] macKey = new byte[MAC_KEY_SIZE];
System.arraycopy(signalingKeyBytes, CIPHER_KEY_SIZE, macKey, 0, macKey.length);
return new SecretKeySpec(macKey, "HmacSHA256");
}
}

View File

@ -105,10 +105,6 @@ public class SignalServiceGroup {
return admins;
}
public static Builder newUpdateBuilder() {
return new Builder(Type.UPDATE);
}
public static Builder newBuilder(Type type) {
return new Builder(type);
}

View File

@ -1,56 +0,0 @@
package org.session.libsignal.service.api.messages;
import org.session.libsignal.libsignal.util.guava.Optional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SignalServiceStickerManifest {
private final Optional<String> title;
private final Optional<String> author;
private final Optional<StickerInfo> cover;
private final List<StickerInfo> stickers;
public SignalServiceStickerManifest(String title, String author, StickerInfo cover, List<StickerInfo> stickers) {
this.title = Optional.of(title);
this.author = Optional.of(author);
this.cover = Optional.of(cover);
this.stickers = (stickers == null) ? Collections.<StickerInfo>emptyList() : new ArrayList<StickerInfo>(stickers);
}
public Optional<String> getTitle() {
return title;
}
public Optional<String> getAuthor() {
return author;
}
public Optional<StickerInfo> getCover() {
return cover;
}
public List<StickerInfo> getStickers() {
return stickers;
}
public static final class StickerInfo {
private final int id;
private final String emoji;
public StickerInfo(int id, String emoji) {
this.id = id;
this.emoji = emoji;
}
public int getId() {
return id;
}
public String getEmoji() {
return emoji;
}
}
}

View File

@ -1,340 +0,0 @@
package org.session.libsignal.service.internal.websocket;
import com.google.protobuf.InvalidProtocolBufferException;
import org.session.libsignal.utilities.logging.Log;
import org.session.libsignal.libsignal.util.Pair;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.push.TrustStore;
import org.session.libsignal.service.api.util.CredentialsProvider;
import org.session.libsignal.service.api.util.SleepTimer;
import org.session.libsignal.service.api.util.Tls12SocketFactory;
import org.session.libsignal.service.api.websocket.ConnectivityListener;
import org.session.libsignal.service.internal.util.BlacklistingTrustManager;
import org.session.libsignal.service.internal.util.Util;
import org.session.libsignal.utilities.concurrent.SettableFuture;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
import static org.session.libsignal.service.internal.websocket.WebSocketProtos.WebSocketMessage;
import static org.session.libsignal.service.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
import static org.session.libsignal.service.internal.websocket.WebSocketProtos.WebSocketResponseMessage;
public class WebSocketConnection extends WebSocketListener {
private static final String TAG = WebSocketConnection.class.getSimpleName();
private static final int KEEPALIVE_TIMEOUT_SECONDS = 55;
private final LinkedList<WebSocketRequestMessage> incomingRequests = new LinkedList<WebSocketRequestMessage>();
private final Map<Long, SettableFuture<Pair<Integer, String>>> outgoingRequests = new HashMap<Long, SettableFuture<Pair<Integer, String>>>();
private final String wsUri;
private final TrustStore trustStore;
private final Optional<CredentialsProvider> credentialsProvider;
private final String userAgent;
private final ConnectivityListener listener;
private final SleepTimer sleepTimer;
private WebSocket client;
private KeepAliveSender keepAliveSender;
private int attempts;
private boolean connected;
public WebSocketConnection(String httpUri,
TrustStore trustStore,
Optional<CredentialsProvider> credentialsProvider,
String userAgent,
ConnectivityListener listener,
SleepTimer timer)
{
this.trustStore = trustStore;
this.credentialsProvider = credentialsProvider;
this.userAgent = userAgent;
this.listener = listener;
this.sleepTimer = timer;
this.attempts = 0;
this.connected = false;
String uri = httpUri.replace("https://", "wss://").replace("http://", "ws://");
if (credentialsProvider.isPresent()) this.wsUri = uri + "/v1/websocket/?login=%s&password=%s";
else this.wsUri = uri + "/v1/websocket/";
}
public synchronized void connect() {
Log.w(TAG, "WSC connect()...");
if (client == null) {
String filledUri;
if (credentialsProvider.isPresent()) {
filledUri = String.format(wsUri, credentialsProvider.get().getUser(), credentialsProvider.get().getPassword());
} else {
filledUri = wsUri;
}
Pair<SSLSocketFactory, X509TrustManager> socketFactory = createTlsSocketFactory(trustStore);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.sslSocketFactory(new Tls12SocketFactory(socketFactory.first()), socketFactory.second())
.connectionSpecs(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))
.readTimeout(KEEPALIVE_TIMEOUT_SECONDS + 10, TimeUnit.SECONDS)
.connectTimeout(KEEPALIVE_TIMEOUT_SECONDS + 10, TimeUnit.SECONDS)
.build();
Request.Builder requestBuilder = new Request.Builder().url(filledUri);
if (userAgent != null) {
requestBuilder.addHeader("X-Signal-Agent", userAgent);
}
if (listener != null) {
listener.onConnecting();
}
this.connected = false;
this.client = okHttpClient.newWebSocket(requestBuilder.build(), this);
}
}
public synchronized void disconnect() {
Log.w(TAG, "WSC disconnect()...");
if (client != null) {
client.close(1000, "OK");
client = null;
connected = false;
}
if (keepAliveSender != null) {
keepAliveSender.shutdown();
keepAliveSender = null;
}
}
public synchronized WebSocketRequestMessage readRequest(long timeoutMillis)
throws TimeoutException, IOException
{
if (client == null) {
throw new IOException("Connection closed!");
}
long startTime = System.currentTimeMillis();
while (client != null && incomingRequests.isEmpty() && elapsedTime(startTime) < timeoutMillis) {
Util.wait(this, Math.max(1, timeoutMillis - elapsedTime(startTime)));
}
if (incomingRequests.isEmpty() && client == null) throw new IOException("Connection closed!");
else if (incomingRequests.isEmpty()) throw new TimeoutException("Timeout exceeded");
else return incomingRequests.removeFirst();
}
public synchronized Future<Pair<Integer, String>> sendRequest(WebSocketRequestMessage request) throws IOException {
if (client == null || !connected) throw new IOException("No connection!");
WebSocketMessage message = WebSocketMessage.newBuilder()
.setType(WebSocketMessage.Type.REQUEST)
.setRequest(request)
.build();
SettableFuture<Pair<Integer, String>> future = new SettableFuture<Pair<Integer, String>>();
outgoingRequests.put(request.getId(), future);
if (!client.send(ByteString.of(message.toByteArray()))) {
throw new IOException("Write failed!");
}
return future;
}
public synchronized void sendResponse(WebSocketResponseMessage response) throws IOException {
if (client == null) {
throw new IOException("Connection closed!");
}
WebSocketMessage message = WebSocketMessage.newBuilder()
.setType(WebSocketMessage.Type.RESPONSE)
.setResponse(response)
.build();
if (!client.send(ByteString.of(message.toByteArray()))) {
throw new IOException("Write failed!");
}
}
private synchronized void sendKeepAlive() throws IOException {
if (keepAliveSender != null && client != null) {
byte[] message = WebSocketMessage.newBuilder()
.setType(WebSocketMessage.Type.REQUEST)
.setRequest(WebSocketRequestMessage.newBuilder()
.setId(System.currentTimeMillis())
.setPath("/v1/keepalive")
.setVerb("GET")
.build()).build()
.toByteArray();
if (!client.send(ByteString.of(message))) {
throw new IOException("Write failed!");
}
}
}
@Override
public synchronized void onOpen(WebSocket webSocket, Response response) {
if (client != null && keepAliveSender == null) {
Log.w(TAG, "onConnected()");
attempts = 0;
connected = true;
keepAliveSender = new KeepAliveSender();
keepAliveSender.start();
if (listener != null) listener.onConnected();
}
}
@Override
public synchronized void onMessage(WebSocket webSocket, ByteString payload) {
Log.w(TAG, "WSC onMessage()");
try {
WebSocketMessage message = WebSocketMessage.parseFrom(payload.toByteArray());
Log.w(TAG, "Message Type: " + message.getType().getNumber());
if (message.getType().getNumber() == WebSocketMessage.Type.REQUEST_VALUE) {
incomingRequests.add(message.getRequest());
} else if (message.getType().getNumber() == WebSocketMessage.Type.RESPONSE_VALUE) {
SettableFuture<Pair<Integer, String>> listener = outgoingRequests.get(message.getResponse().getId());
if (listener != null) listener.set(new Pair<Integer, String>(message.getResponse().getStatus(),
new String(message.getResponse().getBody().toByteArray())));
}
notifyAll();
} catch (InvalidProtocolBufferException e) {
Log.w(TAG, e);
}
}
@Override
public synchronized void onClosed(WebSocket webSocket, int code, String reason) {
Log.w(TAG, "onClose()...");
this.connected = false;
Iterator<Map.Entry<Long, SettableFuture<Pair<Integer, String>>>> iterator = outgoingRequests.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Long, SettableFuture<Pair<Integer, String>>> entry = iterator.next();
entry.getValue().setException(new IOException("Closed: " + code + ", " + reason));
iterator.remove();
}
if (keepAliveSender != null) {
keepAliveSender.shutdown();
keepAliveSender = null;
}
if (listener != null) {
listener.onDisconnected();
}
Util.wait(this, Math.min(++attempts * 200, TimeUnit.SECONDS.toMillis(15)));
if (client != null) {
client.close(1000, "OK");
client = null;
connected = false;
connect();
}
notifyAll();
}
@Override
public synchronized void onFailure(WebSocket webSocket, Throwable t, Response response) {
Log.w(TAG, "onFailure()");
Log.w(TAG, t);
if (response != null && (response.code() == 401 || response.code() == 403)) {
if (listener != null) listener.onAuthenticationFailure();
}
if (client != null) {
onClosed(webSocket, 1000, "OK");
}
}
@Override
public void onMessage(WebSocket webSocket, String text) {
Log.w(TAG, "onMessage(text)! " + text);
}
@Override
public synchronized void onClosing(WebSocket webSocket, int code, String reason) {
Log.w(TAG, "onClosing()!...");
webSocket.close(1000, "OK");
}
private long elapsedTime(long startTime) {
return System.currentTimeMillis() - startTime;
}
private Pair<SSLSocketFactory, X509TrustManager> createTlsSocketFactory(TrustStore trustStore) {
try {
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = BlacklistingTrustManager.createFor(trustStore);
context.init(null, trustManagers, null);
return new Pair<SSLSocketFactory, X509TrustManager>(context.getSocketFactory(), (X509TrustManager)trustManagers[0]);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyManagementException e) {
throw new AssertionError(e);
}
}
private class KeepAliveSender extends Thread {
private AtomicBoolean stop = new AtomicBoolean(false);
public void run() {
while (!stop.get()) {
try {
sleepTimer.sleep(TimeUnit.SECONDS.toMillis(KEEPALIVE_TIMEOUT_SECONDS));
Log.w(TAG, "Sending keep alive...");
sendKeepAlive();
} catch (Throwable e) {
Log.w(TAG, e);
}
}
}
public void shutdown() {
stop.set(true);
}
}
}

View File

@ -1,9 +0,0 @@
package org.session.libsignal.service.internal.websocket;
public interface WebSocketEventListener {
public void onMessage(byte[] payload);
public void onClose();
public void onConnected();
}