Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store and forward #2423

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
<service android:enabled="true" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".service.RegistrationService"/>
<service android:enabled="true" android:name=".service.MessageRetrievalService"/>

<service android:name=".service.QuickResponseService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
Expand Down
1 change: 1 addition & 0 deletions libtextsecure/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {
compile 'com.googlecode.libphonenumber:libphonenumber:6.1'
compile 'org.whispersystems:gson:2.2.4'
compile 'org.whispersystems:axolotl-android:1.0.0'
compile 'com.squareup.okhttp:okhttp:2.2.0'
}

android {
Expand Down
2 changes: 1 addition & 1 deletion libtextsecure/protobuf/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

all:
protoc --java_out=../src/main/java/ IncomingPushMessageSignal.proto Provisioning.proto
protoc --java_out=../src/main/java/ IncomingPushMessageSignal.proto Provisioning.proto WebSocketResources.proto
46 changes: 46 additions & 0 deletions libtextsecure/protobuf/WebSocketResources.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (C) 2014-2015 Open WhisperSystems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package textsecure;

option java_package = "org.whispersystems.textsecure.internal.websocket";
option java_outer_classname = "WebSocketProtos";

message WebSocketRequestMessage {
optional string verb = 1;
optional string path = 2;
optional bytes body = 3;
optional uint64 id = 4;
}

message WebSocketResponseMessage {
optional uint64 id = 1;
optional uint32 status = 2;
optional string message = 3;
optional bytes body = 4;
}

message WebSocketMessage {
enum Type {
UNKNOWN = 0;
REQUEST = 1;
RESPONSE = 2;
}

optional Type type = 1;
optional WebSocketRequestMessage request = 2;
optional WebSocketResponseMessage response = 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.whispersystems.textsecure.api.push.TrustStore;
import org.whispersystems.textsecure.internal.crypto.ProvisioningCipher;
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
import org.whispersystems.textsecure.internal.util.StaticCredentialsProvider;

import java.io.IOException;
import java.util.List;
Expand All @@ -45,7 +46,7 @@ public class TextSecureAccountManager {
public TextSecureAccountManager(String url, TrustStore trustStore,
String user, String password)
{
this.pushServiceSocket = new PushServiceSocket(url, trustStore, user, password);
this.pushServiceSocket = new PushServiceSocket(url, trustStore, new StaticCredentialsProvider(user, password, null));
this.user = user;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.whispersystems.textsecure.api;

import org.whispersystems.libaxolotl.InvalidVersionException;
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
import org.whispersystems.textsecure.api.util.CredentialsProvider;
import org.whispersystems.textsecure.internal.websocket.WebSocketConnection;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketResponseMessage;

public class TextSecureMessagePipe {

private final WebSocketConnection websocket;
private final CredentialsProvider credentialsProvider;

public TextSecureMessagePipe(WebSocketConnection websocket, CredentialsProvider credentialsProvider) {
this.websocket = websocket;
this.credentialsProvider = credentialsProvider;

this.websocket.connect();
}

public TextSecureEnvelope read(long timeout, TimeUnit unit)
throws InvalidVersionException, IOException, TimeoutException
{
return read(timeout, unit, new NullMessagePipeCallback());
}

public TextSecureEnvelope read(long timeout, TimeUnit unit, MessagePipeCallback callback)
throws TimeoutException, IOException, InvalidVersionException
{
while (true) {
WebSocketRequestMessage request = websocket.readRequest(unit.toMillis(timeout));
WebSocketResponseMessage response = createWebSocketResponse(request);

try {
if (isTextSecureEnvelope(request)) {
TextSecureEnvelope envelope = new TextSecureEnvelope(request.getBody().toByteArray(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since body is optional in the protobuf, could someone just send an envelope without one and cause NPE here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"someone" here is the server, which i'm willing to trust with an npe

credentialsProvider.getSignalingKey());

callback.onMessage(envelope);
return envelope;
}
} finally {
websocket.sendResponse(response);
}
}
}

public void shutdown() throws IOException {
websocket.disconnect();
}

private boolean isTextSecureEnvelope(WebSocketRequestMessage message) {
return "PUT".equals(message.getVerb()) && "/api/v1/message".equals(message.getPath());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the endpoint refer to the PushServiceSocket constants for when the API changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint is unrelated to PushServiceSocket, it's strictly a websocket thing.

}

private WebSocketResponseMessage createWebSocketResponse(WebSocketRequestMessage request) {
if (isTextSecureEnvelope(request)) {
return WebSocketResponseMessage.newBuilder()
.setId(request.getId())
.setStatus(200)
.setMessage("OK")
.build();
} else {
return WebSocketResponseMessage.newBuilder()
.setId(request.getId())
.setStatus(400)
.setMessage("Unknown")
.build();
}
}

public static interface MessagePipeCallback {
public void onMessage(TextSecureEnvelope envelope);
}

private static class NullMessagePipeCallback implements MessagePipeCallback {
@Override
public void onMessage(TextSecureEnvelope envelope) {}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,43 @@
package org.whispersystems.textsecure.api;

import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.libaxolotl.InvalidVersionException;
import org.whispersystems.textsecure.api.crypto.AttachmentCipherInputStream;
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer;
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
import org.whispersystems.textsecure.api.push.TrustStore;
import org.whispersystems.textsecure.api.util.CredentialsProvider;
import org.whispersystems.textsecure.internal.push.PushServiceSocket;
import org.whispersystems.textsecure.internal.util.StaticCredentialsProvider;
import org.whispersystems.textsecure.internal.websocket.WebSocketConnection;
import org.whispersystems.textsecure.internal.websocket.WebSocketProtos;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static org.whispersystems.textsecure.internal.websocket.WebSocketProtos.WebSocketRequestMessage;

public class TextSecureMessageReceiver {

private final PushServiceSocket socket;
private final PushServiceSocket socket;
private final TrustStore trustStore;
private final String url;
private final CredentialsProvider credentialsProvider;

public TextSecureMessageReceiver(String url, TrustStore trustStore,
String user, String password)
String user, String password, String signalingKey)
{
this.socket = new PushServiceSocket(url, trustStore, user, password);
this(url, trustStore, new StaticCredentialsProvider(user, password, signalingKey));
}

public TextSecureMessageReceiver(String url, TrustStore trustStore, CredentialsProvider credentials) {
this.url = url;
this.trustStore = trustStore;
this.credentialsProvider = credentials;
this.socket = new PushServiceSocket(url, trustStore, credentials);
}

public InputStream retrieveAttachment(TextSecureAttachmentPointer pointer, File destination)
Expand All @@ -43,4 +63,9 @@ public InputStream retrieveAttachment(TextSecureAttachmentPointer pointer, File
return new AttachmentCipherInputStream(destination, pointer.getKey());
}

public TextSecureMessagePipe createMessagePipe() {
WebSocketConnection webSocket = new WebSocketConnection(url, trustStore, credentialsProvider);
return new TextSecureMessagePipe(webSocket, credentialsProvider);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
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;
import org.whispersystems.textsecure.internal.util.Util;

import java.io.IOException;
Expand All @@ -72,7 +73,7 @@ public TextSecureMessageSender(String url, TrustStore trustStore,
long userId, AxolotlStore store,
Optional<EventListener> eventListener)
{
this.socket = new PushServiceSocket(url, trustStore, user, password);
this.socket = new PushServiceSocket(url, trustStore, new StaticCredentialsProvider(user, password, null));
this.store = store;
this.syncAddress = new PushAddress(userId, user, null);
this.eventListener = eventListener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ public class TextSecureEnvelope {
public TextSecureEnvelope(String message, String signalingKey)
throws IOException, InvalidVersionException
{
byte[] ciphertext = Base64.decode(message);
this(Base64.decode(message), signalingKey);
}

public TextSecureEnvelope(byte[] ciphertext, String signalingKey)
throws InvalidVersionException, IOException
{
if (ciphertext.length < VERSION_LENGTH || ciphertext[VERSION_OFFSET] != SUPPORTED_VERSION)
throw new InvalidVersionException("Unsupported version!");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.whispersystems.textsecure.api.util;

public interface CredentialsProvider {
public String getUser();
public String getPassword();
public String getSignalingKey();
}
Loading