mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-25 17:28:05 +01:00
Support for ephemeral provisioning communication channels.
// FREEBIE
This commit is contained in:
@@ -12,7 +12,7 @@ import org.whispersystems.textsecuregcm.storage.StoredMessages;
|
||||
import org.whispersystems.websocket.session.WebSocketSessionContext;
|
||||
import org.whispersystems.websocket.setup.WebSocketConnectListener;
|
||||
|
||||
public class ConnectListener implements WebSocketConnectListener {
|
||||
public class AuthenticatedConnectListener implements WebSocketConnectListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebSocketConnection.class);
|
||||
|
||||
@@ -21,8 +21,8 @@ public class ConnectListener implements WebSocketConnectListener {
|
||||
private final StoredMessages storedMessages;
|
||||
private final PubSubManager pubSubManager;
|
||||
|
||||
public ConnectListener(AccountsManager accountsManager, PushSender pushSender,
|
||||
StoredMessages storedMessages, PubSubManager pubSubManager)
|
||||
public AuthenticatedConnectListener(AccountsManager accountsManager, PushSender pushSender,
|
||||
StoredMessages storedMessages, PubSubManager pubSubManager)
|
||||
{
|
||||
this.accountsManager = accountsManager;
|
||||
this.pushSender = pushSender;
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.whispersystems.textsecuregcm.websocket;
|
||||
|
||||
import org.whispersystems.textsecuregcm.util.Base64;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class ProvisioningAddress extends WebsocketAddress {
|
||||
|
||||
private static final String PREFIX = ">>ephemeral-";
|
||||
|
||||
private final String address;
|
||||
|
||||
public ProvisioningAddress(String address) throws InvalidWebsocketAddressException {
|
||||
super(address, 0);
|
||||
this.address = address;
|
||||
|
||||
if (address == null || !address.startsWith(PREFIX)) {
|
||||
throw new InvalidWebsocketAddressException(address);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public static ProvisioningAddress generate() {
|
||||
try {
|
||||
byte[] random = new byte[16];
|
||||
SecureRandom.getInstance("SHA1PRNG").nextBytes(random);
|
||||
|
||||
return new ProvisioningAddress(PREFIX + Base64.encodeBytesWithoutPadding(random)
|
||||
.replace('+', '-').replace('/', '_'));
|
||||
} catch (NoSuchAlgorithmException | InvalidWebsocketAddressException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.whispersystems.textsecuregcm.websocket;
|
||||
|
||||
import org.whispersystems.textsecuregcm.storage.PubSubManager;
|
||||
import org.whispersystems.websocket.session.WebSocketSessionContext;
|
||||
import org.whispersystems.websocket.setup.WebSocketConnectListener;
|
||||
|
||||
public class ProvisioningConnectListener implements WebSocketConnectListener {
|
||||
|
||||
private final PubSubManager pubSubManager;
|
||||
|
||||
public ProvisioningConnectListener(PubSubManager pubSubManager) {
|
||||
this.pubSubManager = pubSubManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(WebSocketSessionContext context) {
|
||||
final ProvisioningConnection connection = new ProvisioningConnection(pubSubManager, context.getClient());
|
||||
connection.onConnected();
|
||||
|
||||
context.addListener(new WebSocketSessionContext.WebSocketEventListener() {
|
||||
@Override
|
||||
public void onWebSocketClose(WebSocketSessionContext context, int statusCode, String reason) {
|
||||
connection.onConnectionLost();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.whispersystems.textsecuregcm.websocket;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos.ProvisioningUuid;
|
||||
import org.whispersystems.textsecuregcm.storage.PubSubListener;
|
||||
import org.whispersystems.textsecuregcm.storage.PubSubManager;
|
||||
import org.whispersystems.textsecuregcm.storage.PubSubProtos.PubSubMessage;
|
||||
import org.whispersystems.websocket.WebSocketClient;
|
||||
import org.whispersystems.websocket.messages.WebSocketResponseMessage;
|
||||
|
||||
public class ProvisioningConnection implements PubSubListener {
|
||||
|
||||
private final PubSubManager pubSubManager;
|
||||
private final ProvisioningAddress provisioningAddress;
|
||||
private final WebSocketClient client;
|
||||
|
||||
public ProvisioningConnection(PubSubManager pubSubManager, WebSocketClient client) {
|
||||
this.pubSubManager = pubSubManager;
|
||||
this.client = client;
|
||||
this.provisioningAddress = ProvisioningAddress.generate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPubSubMessage(PubSubMessage outgoingMessage) {
|
||||
if (outgoingMessage.getType() == PubSubMessage.Type.DELIVER) {
|
||||
Optional<byte[]> body = Optional.of(outgoingMessage.getContent().toByteArray());
|
||||
|
||||
ListenableFuture<WebSocketResponseMessage> response = client.sendRequest("PUT", "/v1/message", body);
|
||||
|
||||
Futures.addCallback(response, new FutureCallback<WebSocketResponseMessage>() {
|
||||
@Override
|
||||
public void onSuccess(WebSocketResponseMessage webSocketResponseMessage) {
|
||||
pubSubManager.unsubscribe(provisioningAddress, ProvisioningConnection.this);
|
||||
client.close(1001, "All you get.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
pubSubManager.unsubscribe(provisioningAddress, ProvisioningConnection.this);
|
||||
client.close(1001, "That's all!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void onConnected() {
|
||||
this.pubSubManager.subscribe(provisioningAddress, this);
|
||||
this.client.sendRequest("PUT", "/v1/address", Optional.of(ProvisioningUuid.newBuilder()
|
||||
.setUuid(provisioningAddress.getAddress())
|
||||
.build()
|
||||
.toByteArray()));
|
||||
}
|
||||
|
||||
public void onConnectionLost() {
|
||||
this.pubSubManager.unsubscribe(provisioningAddress, this);
|
||||
this.client.close(1001, "Done");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user