mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
Convert CDSI, KBS, and WebSocket protos to wire.
This commit is contained in:
@@ -38,6 +38,10 @@ wire {
|
||||
sourcePath {
|
||||
srcDir 'src/main/protowire'
|
||||
}
|
||||
|
||||
protoPath {
|
||||
srcDir "${project.rootDir}/libsignal/service/src/main/protowire"
|
||||
}
|
||||
}
|
||||
|
||||
ktlint {
|
||||
|
||||
@@ -27,8 +27,8 @@ import org.thoughtcrime.securesms.testing.FakeClientHelpers
|
||||
import org.thoughtcrime.securesms.testing.SignalActivityRule
|
||||
import org.thoughtcrime.securesms.testing.awaitFor
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketMessage
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketMessage
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
@@ -179,32 +179,19 @@ class MessageProcessingPerformanceTest {
|
||||
}
|
||||
|
||||
private fun webSocketTombstone(): ByteString {
|
||||
return WebSocketMessage
|
||||
.newBuilder()
|
||||
.setRequest(
|
||||
WebSocketRequestMessage.newBuilder()
|
||||
.setVerb("PUT")
|
||||
.setPath("/api/v1/queue/empty")
|
||||
)
|
||||
.build()
|
||||
.toByteArray()
|
||||
.toByteString()
|
||||
return WebSocketMessage(request = WebSocketRequestMessage(verb = "PUT", path = "/api/v1/queue/empty")).encodeByteString()
|
||||
}
|
||||
|
||||
private fun Envelope.toWebSocketPayload(): ByteString {
|
||||
return WebSocketMessage
|
||||
.newBuilder()
|
||||
.setType(WebSocketMessage.Type.REQUEST)
|
||||
.setRequest(
|
||||
WebSocketRequestMessage.newBuilder()
|
||||
.setVerb("PUT")
|
||||
.setPath("/api/v1/message")
|
||||
.setId(Random(System.currentTimeMillis()).nextLong())
|
||||
.addHeaders("X-Signal-Timestamp: ${this.timestamp}")
|
||||
.setBody(this.toByteString())
|
||||
return WebSocketMessage(
|
||||
type = WebSocketMessage.Type.REQUEST,
|
||||
request = WebSocketRequestMessage(
|
||||
verb = "PUT",
|
||||
path = "/api/v1/message",
|
||||
id = Random(System.currentTimeMillis()).nextLong(),
|
||||
headers = listOf("X-Signal-Timestamp: ${this.timestamp}"),
|
||||
body = this.toByteArray().toByteString()
|
||||
)
|
||||
.build()
|
||||
.toByteArray()
|
||||
.toByteString()
|
||||
).encodeByteString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ plugins {
|
||||
id 'signal-library'
|
||||
id 'com.google.protobuf'
|
||||
id 'kotlin-kapt'
|
||||
id 'com.squareup.wire'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -33,3 +34,13 @@ dependencies {
|
||||
exclude group: 'com.google.protobuf', module: 'protobuf-java'
|
||||
}
|
||||
}
|
||||
|
||||
wire {
|
||||
kotlin {
|
||||
javaInterop = true
|
||||
}
|
||||
|
||||
sourcePath {
|
||||
srcDir 'src/main/protowire'
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okio.ByteString
|
||||
import okio.ByteString.Companion.encodeUtf8
|
||||
import org.json.JSONObject
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
@@ -263,7 +264,7 @@ class StripeApi(
|
||||
private fun getRequestBuilder(endpoint: String): Request.Builder {
|
||||
return Request.Builder()
|
||||
.url("${configuration.baseUrl}/$endpoint")
|
||||
.addHeader("Authorization", "Basic ${ByteString.encodeUtf8("${configuration.publishableKey}:").base64()}")
|
||||
.addHeader("Authorization", "Basic ${"${configuration.publishableKey}:".encodeUtf8().base64()}")
|
||||
}
|
||||
|
||||
private fun checkResponseForErrors(response: Response): Response {
|
||||
|
||||
@@ -175,14 +175,13 @@ public class KeyBackupService {
|
||||
final KeyBackupResponse response = pushServiceSocket.putKbsData(authorization, request, remoteAttestation.getCookies(), enclaveName);
|
||||
final RestoreResponse status = KeyBackupCipher.getKeyRestoreResponse(response, remoteAttestation);
|
||||
|
||||
TokenResponse nextToken = status.hasToken()
|
||||
? new TokenResponse(token.getBackupId(), status.getToken().toByteArray(), status.getTries())
|
||||
: token;
|
||||
TokenResponse nextToken = status.token != null ? new TokenResponse(token.getBackupId(), status.token.toByteArray(), status.tries)
|
||||
: token;
|
||||
|
||||
Log.i(TAG, "Restore " + status.getStatus());
|
||||
switch (status.getStatus()) {
|
||||
Log.i(TAG, "Restore " + status.status);
|
||||
switch (status.status) {
|
||||
case OK:
|
||||
KbsData kbsData = PinHashUtil.decryptSvrDataIVCipherText(hashedPin, status.getData().toByteArray());
|
||||
KbsData kbsData = PinHashUtil.decryptSvrDataIVCipherText(hashedPin, status.data_.toByteArray());
|
||||
MasterKey masterKey = kbsData.getMasterKey();
|
||||
return new SvrPinData(masterKey, nextToken);
|
||||
case PIN_MISMATCH:
|
||||
@@ -191,8 +190,8 @@ public class KeyBackupService {
|
||||
case TOKEN_MISMATCH:
|
||||
Log.i(TAG, "Restore TOKEN_MISMATCH");
|
||||
// if the number of tries has not fallen, the pin is correct we're just using an out of date token
|
||||
boolean canRetry = remainingTries == status.getTries();
|
||||
Log.i(TAG, String.format(Locale.US, "Token MISMATCH remainingTries: %d, status.getTries(): %d", remainingTries, status.getTries()));
|
||||
boolean canRetry = remainingTries == status.tries;
|
||||
Log.i(TAG, String.format(Locale.US, "Token MISMATCH remainingTries: %d, status.getTries(): %d", remainingTries, status.tries));
|
||||
throw new TokenException(nextToken, canRetry);
|
||||
case MISSING:
|
||||
Log.i(TAG, "Restore OK! No data though");
|
||||
@@ -259,11 +258,11 @@ public class KeyBackupService {
|
||||
KeyBackupRequest request = KeyBackupCipher.createKeyBackupRequest(kbsAccessKey, kbsData, token, remoteAttestation, serviceId, maxTries);
|
||||
KeyBackupResponse response = pushServiceSocket.putKbsData(authorization, request, remoteAttestation.getCookies(), enclaveName);
|
||||
BackupResponse backupResponse = KeyBackupCipher.getKeyBackupResponse(response, remoteAttestation);
|
||||
BackupResponse.Status status = backupResponse.getStatus();
|
||||
BackupResponse.Status status = backupResponse.status;
|
||||
|
||||
switch (status) {
|
||||
case OK:
|
||||
return backupResponse.hasToken() ? new TokenResponse(token.getBackupId(), backupResponse.getToken().toByteArray(), maxTries) : token;
|
||||
return backupResponse.token != null ? new TokenResponse(token.getBackupId(), backupResponse.token.toByteArray(), maxTries) : token;
|
||||
case ALREADY_EXISTS:
|
||||
throw new UnauthenticatedResponseException("Already exists");
|
||||
case NOT_YET_VALID:
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.whispersystems.signalservice.api;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.messages.EnvelopeResponse;
|
||||
@@ -10,8 +8,8 @@ import org.whispersystems.signalservice.api.websocket.WebSocketFactory;
|
||||
import org.whispersystems.signalservice.api.websocket.WebSocketUnavailableException;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketConnection;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketResponseMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketResponseMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebsocketResponse;
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
@@ -202,9 +200,11 @@ public final class SignalWebSocket {
|
||||
|
||||
public Single<WebsocketResponse> request(WebSocketRequestMessage requestMessage, Optional<UnidentifiedAccess> unidentifiedAccess) {
|
||||
if (unidentifiedAccess.isPresent()) {
|
||||
WebSocketRequestMessage message = WebSocketRequestMessage.newBuilder(requestMessage)
|
||||
.addHeaders("Unidentified-Access-Key:" + Base64.encodeBytes(unidentifiedAccess.get().getUnidentifiedAccessKey()))
|
||||
.build();
|
||||
List<String> headers = new ArrayList<>(requestMessage.headers);
|
||||
headers.add("Unidentified-Access-Key:" + Base64.encodeBytes(unidentifiedAccess.get().getUnidentifiedAccessKey()));
|
||||
WebSocketRequestMessage message = requestMessage.newBuilder()
|
||||
.headers(headers)
|
||||
.build();
|
||||
try {
|
||||
return getUnidentifiedWebSocket().sendRequest(message)
|
||||
.flatMap(r -> {
|
||||
@@ -299,7 +299,7 @@ public final class SignalWebSocket {
|
||||
}
|
||||
|
||||
private static EnvelopeResponse requestToEnvelopeResponse(WebSocketRequestMessage request)
|
||||
throws InvalidProtocolBufferException
|
||||
throws IOException
|
||||
{
|
||||
Optional<String> timestampHeader = findHeader(request);
|
||||
long timestamp = 0;
|
||||
@@ -312,41 +312,41 @@ public final class SignalWebSocket {
|
||||
}
|
||||
}
|
||||
|
||||
SignalServiceProtos.Envelope envelope = SignalServiceProtos.Envelope.parseFrom(request.getBody().toByteArray());
|
||||
SignalServiceProtos.Envelope envelope = SignalServiceProtos.Envelope.parseFrom(request.body.toByteArray());
|
||||
|
||||
return new EnvelopeResponse(envelope, timestamp, request);
|
||||
}
|
||||
|
||||
private static boolean isSignalServiceEnvelope(WebSocketRequestMessage message) {
|
||||
return "PUT".equals(message.getVerb()) && "/api/v1/message".equals(message.getPath());
|
||||
return "PUT".equals(message.verb) && "/api/v1/message".equals(message.path);
|
||||
}
|
||||
|
||||
private static boolean isSocketEmptyRequest(WebSocketRequestMessage message) {
|
||||
return "PUT".equals(message.getVerb()) && "/api/v1/queue/empty".equals(message.getPath());
|
||||
return "PUT".equals(message.verb) && "/api/v1/queue/empty".equals(message.path);
|
||||
}
|
||||
|
||||
private static WebSocketResponseMessage createWebSocketResponse(WebSocketRequestMessage request) {
|
||||
if (isSignalServiceEnvelope(request)) {
|
||||
return WebSocketResponseMessage.newBuilder()
|
||||
.setId(request.getId())
|
||||
.setStatus(200)
|
||||
.setMessage("OK")
|
||||
.build();
|
||||
return new WebSocketResponseMessage.Builder()
|
||||
.id(request.id)
|
||||
.status(200)
|
||||
.message("OK")
|
||||
.build();
|
||||
} else {
|
||||
return WebSocketResponseMessage.newBuilder()
|
||||
.setId(request.getId())
|
||||
.setStatus(400)
|
||||
.setMessage("Unknown")
|
||||
.build();
|
||||
return new WebSocketResponseMessage.Builder()
|
||||
.id(request.id)
|
||||
.status(400)
|
||||
.message("Unknown")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> findHeader(WebSocketRequestMessage message) {
|
||||
if (message.getHeadersCount() == 0) {
|
||||
if (message.headers.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
for (String header : message.getHeadersList()) {
|
||||
for (String header : message.headers) {
|
||||
if (header.startsWith(SERVER_DELIVERED_TIMESTAMP_HEADER)) {
|
||||
String[] split = header.split(":");
|
||||
if (split.length == 2 && split[0].trim().toLowerCase().equals(SERVER_DELIVERED_TIMESTAMP_HEADER.toLowerCase())) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.whispersystems.signalservice.api.messages
|
||||
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Envelope
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage
|
||||
|
||||
/**
|
||||
* Represents an envelope off the wire, paired with the metadata needed to process it.
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.whispersystems.signalservice.internal.ServiceResponseProcessor;
|
||||
import org.whispersystems.signalservice.internal.push.AttachmentV2UploadAttributes;
|
||||
import org.whispersystems.signalservice.internal.push.AttachmentV3UploadAttributes;
|
||||
import org.whispersystems.signalservice.internal.websocket.DefaultResponseMapper;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
@@ -25,11 +25,11 @@ public final class AttachmentService {
|
||||
}
|
||||
|
||||
public Single<ServiceResponse<AttachmentV2UploadAttributes>> getAttachmentV2UploadAttributes() {
|
||||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("GET")
|
||||
.setPath("/v2/attachments/form/upload")
|
||||
.build();
|
||||
WebSocketRequestMessage requestMessage = new WebSocketRequestMessage.Builder()
|
||||
.id(new SecureRandom().nextLong())
|
||||
.verb("GET")
|
||||
.path("/v2/attachments/form/upload")
|
||||
.build();
|
||||
|
||||
return signalWebSocket.request(requestMessage)
|
||||
.map(DefaultResponseMapper.getDefault(AttachmentV2UploadAttributes.class)::map)
|
||||
@@ -37,11 +37,11 @@ public final class AttachmentService {
|
||||
}
|
||||
|
||||
public Single<ServiceResponse<AttachmentV3UploadAttributes>> getAttachmentV3UploadAttributes() {
|
||||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("GET")
|
||||
.setPath("/v3/attachments/form/upload")
|
||||
.build();
|
||||
WebSocketRequestMessage requestMessage = new WebSocketRequestMessage.Builder()
|
||||
.id(new SecureRandom().nextLong())
|
||||
.verb("GET")
|
||||
.path("/v3/attachments/form/upload")
|
||||
.build();
|
||||
|
||||
return signalWebSocket.request(requestMessage)
|
||||
.map(DefaultResponseMapper.getDefault(AttachmentV3UploadAttributes.class)::map)
|
||||
|
||||
@@ -128,7 +128,7 @@ final class CdsiSocket {
|
||||
Log.d(TAG, "[onMessage] Handshake read success.");
|
||||
|
||||
Log.d(TAG, "[onMessage] Sending data...");
|
||||
byte[] ciphertextBytes = client.establishedSend(clientRequest.toByteArray());
|
||||
byte[] ciphertextBytes = client.establishedSend(clientRequest.encode());
|
||||
webSocket.send(okio.ByteString.of(ciphertextBytes));
|
||||
Log.d(TAG, "[onMessage] Data sent.");
|
||||
|
||||
@@ -136,24 +136,24 @@ final class CdsiSocket {
|
||||
break;
|
||||
|
||||
case WAITING_FOR_TOKEN:
|
||||
ClientResponse tokenResponse = ClientResponse.parseFrom(client.establishedRecv(bytes.toByteArray()));
|
||||
ClientResponse tokenResponse = ClientResponse.ADAPTER.decode(client.establishedRecv(bytes.toByteArray()));
|
||||
|
||||
if (tokenResponse.getToken().isEmpty()) {
|
||||
if (tokenResponse.token.size() == 0) {
|
||||
throw new IOException("No token! Cannot continue!");
|
||||
}
|
||||
|
||||
tokenSaver.accept(tokenResponse.getToken().toByteArray());
|
||||
tokenSaver.accept(tokenResponse.token.toByteArray());
|
||||
|
||||
Log.d(TAG, "[onMessage] Sending token ack...");
|
||||
webSocket.send(okio.ByteString.of(client.establishedSend(ClientRequest.newBuilder()
|
||||
.setTokenAck(true)
|
||||
.build()
|
||||
.toByteArray())));
|
||||
webSocket.send(okio.ByteString.of(client.establishedSend(new ClientRequest.Builder()
|
||||
.tokenAck(true)
|
||||
.build()
|
||||
.encode())));
|
||||
stage.set(Stage.WAITING_FOR_RESPONSE);
|
||||
break;
|
||||
|
||||
case WAITING_FOR_RESPONSE:
|
||||
emitter.onNext(ClientResponse.parseFrom(client.establishedRecv(bytes.toByteArray())));
|
||||
emitter.onNext(ClientResponse.ADAPTER.decode(client.establishedRecv(bytes.toByteArray())));
|
||||
break;
|
||||
|
||||
case CLOSED:
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
package org.whispersystems.signalservice.api.services;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.cdsi.proto.ClientRequest;
|
||||
import org.signal.cdsi.proto.ClientResponse;
|
||||
import org.signal.libsignal.protocol.util.ByteUtil;
|
||||
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
@@ -29,6 +28,7 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import okio.ByteString;
|
||||
|
||||
/**
|
||||
* Handles network interactions with CDSI, the SGX-backed version of the CDSv2 API.
|
||||
@@ -75,7 +75,7 @@ public final class CdsiV2Service {
|
||||
|
||||
private static Response parseEntries(ClientResponse clientResponse) {
|
||||
Map<String, ResponseItem> results = new HashMap<>();
|
||||
ByteBuffer parser = clientResponse.getE164PniAciTriples().asReadOnlyByteBuffer();
|
||||
ByteBuffer parser = clientResponse.e164PniAciTriples.asByteBuffer();
|
||||
|
||||
while (parser.remaining() >= RESPONSE_ITEM_SIZE) {
|
||||
String e164 = "+" + parser.getLong();
|
||||
@@ -89,7 +89,7 @@ public final class CdsiV2Service {
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(results, clientResponse.getDebugPermitsUsed());
|
||||
return new Response(results, clientResponse.debugPermitsUsed);
|
||||
}
|
||||
|
||||
private static ClientRequest buildClientRequest(Request request) {
|
||||
@@ -97,22 +97,22 @@ public final class CdsiV2Service {
|
||||
List<Long> newE164s = parseAndSortE164Strings(request.newE164s);
|
||||
List<Long> removedE164s = parseAndSortE164Strings(request.removedE164s);
|
||||
|
||||
ClientRequest.Builder builder = ClientRequest.newBuilder()
|
||||
.setPrevE164S(toByteString(previousE164s))
|
||||
.setNewE164S(toByteString(newE164s))
|
||||
.setDiscardE164S(toByteString(removedE164s))
|
||||
.setAciUakPairs(toByteString(request.serviceIds))
|
||||
.setReturnAcisWithoutUaks(request.requireAcis);
|
||||
ClientRequest.Builder builder = new ClientRequest.Builder()
|
||||
.prevE164s(toByteString(previousE164s))
|
||||
.newE164s(toByteString(newE164s))
|
||||
.discardE164s(toByteString(removedE164s))
|
||||
.aciUakPairs(toByteString(request.serviceIds))
|
||||
.returnAcisWithoutUaks(request.requireAcis);
|
||||
|
||||
if (request.token != null) {
|
||||
builder.setToken(ByteString.copyFrom(request.token));
|
||||
builder.token(ByteString.of(request.token));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static ByteString toByteString(List<Long> numbers) {
|
||||
ByteString.Output os = ByteString.newOutput();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
for (long number : numbers) {
|
||||
try {
|
||||
@@ -122,11 +122,11 @@ public final class CdsiV2Service {
|
||||
}
|
||||
}
|
||||
|
||||
return os.toByteString();
|
||||
return ByteString.of(os.toByteArray());
|
||||
}
|
||||
|
||||
private static ByteString toByteString(Map<ServiceId, ProfileKey> serviceIds) {
|
||||
ByteString.Output os = ByteString.newOutput();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
for (Map.Entry<ServiceId, ProfileKey> entry : serviceIds.entrySet()) {
|
||||
try {
|
||||
@@ -137,7 +137,7 @@ public final class CdsiV2Service {
|
||||
}
|
||||
}
|
||||
|
||||
return os.toByteString();
|
||||
return ByteString.of(os.toByteArray());
|
||||
}
|
||||
|
||||
private static List<Long> parseAndSortE164Strings(Collection<String> e164s) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.whispersystems.signalservice.api.services;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.signalservice.api.SignalWebSocket;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
|
||||
@@ -20,7 +18,7 @@ import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
import org.whispersystems.signalservice.internal.websocket.DefaultResponseMapper;
|
||||
import org.whispersystems.signalservice.internal.websocket.ResponseMapper;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage;
|
||||
import org.whispersystems.util.Base64;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
@@ -30,6 +28,7 @@ import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import okio.ByteString;
|
||||
|
||||
/**
|
||||
* Provide WebSocket based interface to message sending endpoints.
|
||||
@@ -48,13 +47,13 @@ public class MessagingService {
|
||||
add("content-type:application/json");
|
||||
}};
|
||||
|
||||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("PUT")
|
||||
.setPath(String.format("/v1/messages/%s?story=%s", list.getDestination(), story ? "true" : "false"))
|
||||
.addAllHeaders(headers)
|
||||
.setBody(ByteString.copyFrom(JsonUtil.toJson(list).getBytes()))
|
||||
.build();
|
||||
WebSocketRequestMessage requestMessage = new WebSocketRequestMessage.Builder()
|
||||
.id(new SecureRandom().nextLong())
|
||||
.verb("PUT")
|
||||
.path(String.format("/v1/messages/%s?story=%s", list.getDestination(), story ? "true" : "false"))
|
||||
.headers(headers)
|
||||
.body(ByteString.of(JsonUtil.toJson(list).getBytes()))
|
||||
.build();
|
||||
|
||||
ResponseMapper<SendMessageResponse> responseMapper = DefaultResponseMapper.extend(SendMessageResponse.class)
|
||||
.withResponseMapper((status, body, getHeader, unidentified) -> {
|
||||
@@ -80,13 +79,13 @@ public class MessagingService {
|
||||
|
||||
String path = String.format(Locale.US, "/v1/messages/multi_recipient?ts=%s&online=%s&urgent=%s&story=%s", timestamp, online, urgent, story);
|
||||
|
||||
WebSocketRequestMessage requestMessage = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("PUT")
|
||||
.setPath(path)
|
||||
.addAllHeaders(headers)
|
||||
.setBody(ByteString.copyFrom(body))
|
||||
.build();
|
||||
WebSocketRequestMessage requestMessage = new WebSocketRequestMessage.Builder()
|
||||
.id(new SecureRandom().nextLong())
|
||||
.verb("PUT")
|
||||
.path(path)
|
||||
.headers(headers)
|
||||
.body(ByteString.of(body))
|
||||
.build();
|
||||
|
||||
return signalWebSocket.request(requestMessage)
|
||||
.map(DefaultResponseMapper.extend(SendGroupMessageResponse.class)
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.whispersystems.signalservice.internal.util.Hex;
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
import org.whispersystems.signalservice.internal.websocket.DefaultResponseMapper;
|
||||
import org.whispersystems.signalservice.internal.websocket.ResponseMapper;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
@@ -78,9 +78,9 @@ public final class ProfileService {
|
||||
SecureRandom random = new SecureRandom();
|
||||
ProfileKeyCredentialRequestContext requestContext = null;
|
||||
|
||||
WebSocketRequestMessage.Builder builder = WebSocketRequestMessage.newBuilder()
|
||||
.setId(random.nextLong())
|
||||
.setVerb("GET");
|
||||
WebSocketRequestMessage.Builder builder = new WebSocketRequestMessage.Builder()
|
||||
.id(random.nextLong())
|
||||
.verb("GET");
|
||||
|
||||
if (profileKey.isPresent()) {
|
||||
if (!(serviceId instanceof ACI)) {
|
||||
@@ -98,15 +98,15 @@ public final class ProfileService {
|
||||
ProfileKeyCredentialRequest request = requestContext.getRequest();
|
||||
String credentialRequest = Hex.toStringCondensed(request.serialize());
|
||||
|
||||
builder.setPath(String.format("/v1/profile/%s/%s/%s?credentialType=expiringProfileKey", serviceId, version, credentialRequest));
|
||||
builder.path(String.format("/v1/profile/%s/%s/%s?credentialType=expiringProfileKey", serviceId, version, credentialRequest));
|
||||
} else {
|
||||
builder.setPath(String.format("/v1/profile/%s/%s", serviceId, version));
|
||||
builder.path(String.format("/v1/profile/%s/%s", serviceId, version));
|
||||
}
|
||||
} else {
|
||||
builder.setPath(String.format("/v1/profile/%s", address.getIdentifier()));
|
||||
builder.path(String.format("/v1/profile/%s", address.getIdentifier()));
|
||||
}
|
||||
|
||||
builder.addHeaders(AcceptLanguagesUtil.getAcceptLanguageHeader(locale));
|
||||
builder.headers(Collections.singletonList(AcceptLanguagesUtil.getAcceptLanguageHeader(locale)));
|
||||
|
||||
WebSocketRequestMessage requestMessage = builder.build();
|
||||
|
||||
@@ -128,12 +128,12 @@ public final class ProfileService {
|
||||
|
||||
IdentityCheckRequest request = new IdentityCheckRequest(serviceIdKeyPairs);
|
||||
|
||||
WebSocketRequestMessage.Builder builder = WebSocketRequestMessage.newBuilder()
|
||||
.setId(new SecureRandom().nextLong())
|
||||
.setVerb("POST")
|
||||
.setPath("/v1/profile/identity_check/batch")
|
||||
.addAllHeaders(Collections.singleton("content-type:application/json"))
|
||||
.setBody(JsonUtil.toJsonByteString(request));
|
||||
WebSocketRequestMessage.Builder builder = new WebSocketRequestMessage.Builder()
|
||||
.id(new SecureRandom().nextLong())
|
||||
.verb("POST")
|
||||
.path("/v1/profile/identity_check/batch")
|
||||
.headers(Collections.singletonList("content-type:application/json"))
|
||||
.body(JsonUtil.toJsonByteString(request));
|
||||
|
||||
ResponseMapper<IdentityCheckResponse> responseMapper = DefaultResponseMapper.getDefault(IdentityCheckResponse.class);
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package org.whispersystems.signalservice.internal.contacts.crypto;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.KeyBackupRequest;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.KeyBackupResponse;
|
||||
@@ -16,8 +13,11 @@ import org.whispersystems.signalservice.internal.keybackup.protos.Response;
|
||||
import org.whispersystems.signalservice.internal.keybackup.protos.RestoreRequest;
|
||||
import org.whispersystems.signalservice.internal.keybackup.protos.RestoreResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
public final class KeyBackupCipher {
|
||||
|
||||
private KeyBackupCipher() {
|
||||
@@ -34,17 +34,17 @@ public final class KeyBackupCipher {
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
BackupRequest backupRequest = BackupRequest.newBuilder()
|
||||
.setServiceId(ByteString.copyFrom(serviceId))
|
||||
.setBackupId(ByteString.copyFrom(token.getBackupId()))
|
||||
.setToken(ByteString.copyFrom(token.getToken()))
|
||||
.setValidFrom(getValidFromSeconds(now))
|
||||
.setData(ByteString.copyFrom(kbsData))
|
||||
.setPin(ByteString.copyFrom(kbsAccessKey))
|
||||
.setTries(tries)
|
||||
.build();
|
||||
BackupRequest backupRequest = new BackupRequest.Builder()
|
||||
.serviceId(ByteString.of(serviceId))
|
||||
.backupId(ByteString.of(token.getBackupId()))
|
||||
.token(ByteString.of(token.getToken()))
|
||||
.validFrom(getValidFromSeconds(now))
|
||||
.data_(ByteString.of(kbsData))
|
||||
.pin(ByteString.of(kbsAccessKey))
|
||||
.tries(tries)
|
||||
.build();
|
||||
|
||||
Request requestData = Request.newBuilder().setBackup(backupRequest).build();
|
||||
Request requestData = new Request.Builder().backup(backupRequest).build();
|
||||
|
||||
return createKeyBackupRequest(requestData, remoteAttestation, "backup");
|
||||
}
|
||||
@@ -56,15 +56,15 @@ public final class KeyBackupCipher {
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
RestoreRequest restoreRequest = RestoreRequest.newBuilder()
|
||||
.setServiceId(ByteString.copyFrom(serviceId))
|
||||
.setBackupId(ByteString.copyFrom(token.getBackupId()))
|
||||
.setToken(ByteString.copyFrom(token.getToken()))
|
||||
.setValidFrom(getValidFromSeconds(now))
|
||||
.setPin(ByteString.copyFrom(kbsAccessKey))
|
||||
.build();
|
||||
RestoreRequest restoreRequest = new RestoreRequest.Builder()
|
||||
.serviceId(ByteString.of(serviceId))
|
||||
.backupId(ByteString.of(token.getBackupId()))
|
||||
.token(ByteString.of(token.getToken()))
|
||||
.validFrom(getValidFromSeconds(now))
|
||||
.pin(ByteString.of(kbsAccessKey))
|
||||
.build();
|
||||
|
||||
Request request = Request.newBuilder().setRestore(restoreRequest).build();
|
||||
Request request = new Request.Builder().restore(restoreRequest).build();
|
||||
|
||||
return createKeyBackupRequest(request, remoteAttestation, "restore");
|
||||
}
|
||||
@@ -73,47 +73,47 @@ public final class KeyBackupCipher {
|
||||
RemoteAttestation remoteAttestation,
|
||||
byte[] serviceId)
|
||||
{
|
||||
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
|
||||
.setServiceId(ByteString.copyFrom(serviceId))
|
||||
.setBackupId(ByteString.copyFrom(token.getBackupId()))
|
||||
.build();
|
||||
DeleteRequest deleteRequest = new DeleteRequest.Builder()
|
||||
.serviceId(ByteString.of(serviceId))
|
||||
.backupId(ByteString.of(token.getBackupId()))
|
||||
.build();
|
||||
|
||||
Request request = Request.newBuilder().setDelete(deleteRequest).build();
|
||||
Request request = new Request.Builder().delete(deleteRequest).build();
|
||||
|
||||
return createKeyBackupRequest(request, remoteAttestation, "delete");
|
||||
}
|
||||
|
||||
public static BackupResponse getKeyBackupResponse(KeyBackupResponse response, RemoteAttestation remoteAttestation)
|
||||
throws InvalidCiphertextException, InvalidProtocolBufferException
|
||||
throws InvalidCiphertextException, IOException
|
||||
{
|
||||
byte[] data = decryptData(response, remoteAttestation);
|
||||
|
||||
Response backupResponse = Response.parseFrom(data);
|
||||
Response backupResponse = Response.ADAPTER.decode(data);
|
||||
|
||||
return backupResponse.getBackup();
|
||||
return backupResponse.backup;
|
||||
}
|
||||
|
||||
public static RestoreResponse getKeyRestoreResponse(KeyBackupResponse response, RemoteAttestation remoteAttestation)
|
||||
throws InvalidCiphertextException, InvalidProtocolBufferException
|
||||
throws InvalidCiphertextException, IOException
|
||||
{
|
||||
byte[] data = decryptData(response, remoteAttestation);
|
||||
|
||||
return Response.parseFrom(data).getRestore();
|
||||
return Response.ADAPTER.decode(data).restore;
|
||||
}
|
||||
|
||||
public static DeleteResponse getKeyDeleteResponseStatus(KeyBackupResponse response, RemoteAttestation remoteAttestation)
|
||||
throws InvalidCiphertextException, InvalidProtocolBufferException
|
||||
throws InvalidCiphertextException, IOException
|
||||
{
|
||||
byte[] data = decryptData(response, remoteAttestation);
|
||||
|
||||
return DeleteResponse.parseFrom(data);
|
||||
return DeleteResponse.ADAPTER.decode(data);
|
||||
}
|
||||
|
||||
private static KeyBackupRequest createKeyBackupRequest(Request requestData, RemoteAttestation remoteAttestation, String type) {
|
||||
byte[] clientKey = remoteAttestation.getKeys().getClientKey();
|
||||
byte[] aad = remoteAttestation.getRequestId();
|
||||
|
||||
AESCipher.AESEncryptedResult aesEncryptedResult = AESCipher.encrypt(clientKey, aad, requestData.toByteArray());
|
||||
AESCipher.AESEncryptedResult aesEncryptedResult = AESCipher.encrypt(clientKey, aad, requestData.encode());
|
||||
|
||||
return new KeyBackupRequest(aesEncryptedResult.aad, aesEncryptedResult.iv, aesEncryptedResult.data, aesEncryptedResult.mac, type);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
@@ -35,6 +34,8 @@ import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class JsonUtil {
|
||||
|
||||
@@ -57,7 +58,7 @@ public class JsonUtil {
|
||||
}
|
||||
|
||||
public static @Nonnull ByteString toJsonByteString(@Nonnull Object object) {
|
||||
return ByteString.copyFrom(toJson(object).getBytes());
|
||||
return ByteString.of(toJson(object).getBytes());
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> clazz)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.whispersystems.signalservice.internal.websocket;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
@@ -52,10 +50,6 @@ import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
import okio.ByteString;
|
||||
|
||||
import static org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketMessage;
|
||||
import static org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketRequestMessage;
|
||||
import static org.whispersystems.signalservice.internal.websocket.WebSocketProtos.WebSocketResponseMessage;
|
||||
|
||||
public class WebSocketConnection extends WebSocketListener {
|
||||
|
||||
private static final String TAG = WebSocketConnection.class.getSimpleName();
|
||||
@@ -228,16 +222,16 @@ public class WebSocketConnection extends WebSocketListener {
|
||||
throw new IOException("No connection!");
|
||||
}
|
||||
|
||||
WebSocketMessage message = WebSocketMessage.newBuilder()
|
||||
.setType(WebSocketMessage.Type.REQUEST)
|
||||
.setRequest(request)
|
||||
.build();
|
||||
WebSocketMessage message = new WebSocketMessage.Builder()
|
||||
.type(WebSocketMessage.Type.REQUEST)
|
||||
.request(request)
|
||||
.build();
|
||||
|
||||
SingleSubject<WebsocketResponse> single = SingleSubject.create();
|
||||
|
||||
outgoingRequests.put(request.getId(), new OutgoingRequest(single));
|
||||
outgoingRequests.put(request.id, new OutgoingRequest(single));
|
||||
|
||||
if (!client.send(ByteString.of(message.toByteArray()))) {
|
||||
if (!client.send(ByteString.of(message.encode()))) {
|
||||
throw new IOException("Write failed!");
|
||||
}
|
||||
|
||||
@@ -251,12 +245,12 @@ public class WebSocketConnection extends WebSocketListener {
|
||||
throw new IOException("Connection closed!");
|
||||
}
|
||||
|
||||
WebSocketMessage message = WebSocketMessage.newBuilder()
|
||||
.setType(WebSocketMessage.Type.RESPONSE)
|
||||
.setResponse(response)
|
||||
.build();
|
||||
WebSocketMessage message = new WebSocketMessage.Builder()
|
||||
.type(WebSocketMessage.Type.RESPONSE)
|
||||
.response(response)
|
||||
.build();
|
||||
|
||||
if (!client.send(ByteString.of(message.toByteArray()))) {
|
||||
if (!client.send(ByteString.of(message.encode()))) {
|
||||
throw new IOException("Write failed!");
|
||||
}
|
||||
}
|
||||
@@ -265,15 +259,15 @@ public class WebSocketConnection extends WebSocketListener {
|
||||
if (client != null) {
|
||||
log( "Sending keep alive...");
|
||||
long id = System.currentTimeMillis();
|
||||
byte[] message = WebSocketMessage.newBuilder()
|
||||
.setType(WebSocketMessage.Type.REQUEST)
|
||||
.setRequest(WebSocketRequestMessage.newBuilder()
|
||||
.setId(id)
|
||||
.setPath("/v1/keepalive")
|
||||
.setVerb("GET")
|
||||
.build())
|
||||
.build()
|
||||
.toByteArray();
|
||||
byte[] message = new WebSocketMessage.Builder()
|
||||
.type(WebSocketMessage.Type.REQUEST)
|
||||
.request(new WebSocketRequestMessage.Builder()
|
||||
.id(id)
|
||||
.path("/v1/keepalive")
|
||||
.verb("GET")
|
||||
.build())
|
||||
.build()
|
||||
.encode();
|
||||
keepAlives.add(id);
|
||||
if (!client.send(ByteString.of(message))) {
|
||||
throw new IOException("Write failed!");
|
||||
@@ -292,27 +286,27 @@ public class WebSocketConnection extends WebSocketListener {
|
||||
@Override
|
||||
public synchronized void onMessage(WebSocket webSocket, ByteString payload) {
|
||||
try {
|
||||
WebSocketMessage message = WebSocketMessage.parseFrom(payload.toByteArray());
|
||||
WebSocketMessage message = WebSocketMessage.ADAPTER.decode(payload.toByteArray());
|
||||
|
||||
if (message.getType().getNumber() == WebSocketMessage.Type.REQUEST_VALUE) {
|
||||
incomingRequests.add(message.getRequest());
|
||||
} else if (message.getType().getNumber() == WebSocketMessage.Type.RESPONSE_VALUE) {
|
||||
OutgoingRequest listener = outgoingRequests.remove(message.getResponse().getId());
|
||||
if (message.type == WebSocketMessage.Type.REQUEST) {
|
||||
incomingRequests.add(message.request);
|
||||
} else if (message.type == WebSocketMessage.Type.RESPONSE) {
|
||||
OutgoingRequest listener = outgoingRequests.remove(message.response.id);
|
||||
if (listener != null) {
|
||||
listener.onSuccess(new WebsocketResponse(message.getResponse().getStatus(),
|
||||
new String(message.getResponse().getBody().toByteArray()),
|
||||
message.getResponse().getHeadersList(),
|
||||
listener.onSuccess(new WebsocketResponse(message.response.status,
|
||||
new String(message.response.body.toByteArray()),
|
||||
message.response.headers,
|
||||
!credentialsProvider.isPresent()));
|
||||
if (message.getResponse().getStatus() >= 400) {
|
||||
healthMonitor.onMessageError(message.getResponse().getStatus(), credentialsProvider.isPresent());
|
||||
if (message.response.status >= 400) {
|
||||
healthMonitor.onMessageError(message.response.status, credentialsProvider.isPresent());
|
||||
}
|
||||
} else if (keepAlives.remove(message.getResponse().getId())) {
|
||||
healthMonitor.onKeepAliveResponse(message.getResponse().getId(), credentialsProvider.isPresent());
|
||||
} else if (keepAlives.remove(message.response.id)) {
|
||||
healthMonitor.onKeepAliveResponse(message.response.id, credentialsProvider.isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
notifyAll();
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
} catch (IOException e) {
|
||||
warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ package org.signal.cdsi;
|
||||
message ClientRequest {
|
||||
// Each ACI/UAK pair is a 32-byte buffer, containing the 16-byte ACI followed
|
||||
// by its 16-byte UAK.
|
||||
bytes aci_uak_pairs = 1;
|
||||
bytes aciUakPairs = 1;
|
||||
|
||||
// Each E164 is an 8-byte big-endian number, as 8 bytes.
|
||||
bytes prev_e164s = 2;
|
||||
bytes new_e164s = 3;
|
||||
bytes discard_e164s = 4;
|
||||
bytes prevE164s = 2;
|
||||
bytes newE164s = 3;
|
||||
bytes discardE164s = 4;
|
||||
|
||||
// If true, the client has more pairs or e164s to send. If false or unset,
|
||||
// this is the client's last request, and processing should commence.
|
||||
@@ -27,11 +27,11 @@ message ClientRequest {
|
||||
|
||||
// After receiving a new token from the server, send back a message just
|
||||
// containing a token_ack.
|
||||
bool token_ack = 7;
|
||||
bool tokenAck = 7;
|
||||
|
||||
// Request that, if the server allows, both ACI and PNI be returned even
|
||||
// if the aci_uak_pairs don't match.
|
||||
bool return_acis_without_uaks = 8;
|
||||
bool returnAcisWithoutUaks = 8;
|
||||
}
|
||||
|
||||
message ClientResponse {
|
||||
@@ -47,14 +47,14 @@ message ClientResponse {
|
||||
// where the additional 2 bytes are the id/type/length additions of the
|
||||
// protobuf marshaling added to each byte array. This avoids any data
|
||||
// leakage based on the size of the encrypted output.
|
||||
bytes e164_pni_aci_triples = 1;
|
||||
bytes e164PniAciTriples = 1;
|
||||
|
||||
// If the user has run out of quota for lookups, they will receive
|
||||
// a response with just the following field set, followed by a websocket
|
||||
// closure of type 4008 (RESOURCE_EXHAUSTED). Should they retry exactly
|
||||
// the same request after the provided number of seconds has passed,
|
||||
// we expect it should work.
|
||||
int32 retry_after_secs = 2;
|
||||
int32 retryAfterSecs = 2;
|
||||
|
||||
// A token which allows subsequent calls' rate limiting to discount the
|
||||
// e164s sent up in this request, only counting those in the next
|
||||
@@ -64,28 +64,28 @@ message ClientResponse {
|
||||
// On a successful response to a token_ack request, the number of permits
|
||||
// that were deducted from the user's rate-limit in order to process the
|
||||
// request
|
||||
int32 debug_permits_used = 4;
|
||||
int32 debugPermitsUsed = 4;
|
||||
}
|
||||
|
||||
message EnclaveLoad {
|
||||
// If set, before loading any tuples entirely clear the current map,
|
||||
// zero'ing out all current data.
|
||||
bool clear_all = 1;
|
||||
bool clearAll = 1;
|
||||
|
||||
// Each tuple is an 8-byte e164, a 16-byte PNI, a 16-byte ACI, and a
|
||||
// 16-byte UAK. These should be loaded as a 48-byte value (PNI,ACI,UAK)
|
||||
// associated with an 8-byte key (e164).
|
||||
// ACI/PNI/UAK may all be zeros, in which case this is a delete of the e164.
|
||||
bytes e164_aci_pni_uak_tuples = 2;
|
||||
bytes e164AciPniUakTuples = 2;
|
||||
|
||||
// If non-empty, overwrite the shared token secret with this value.
|
||||
bytes shared_token_secret = 3;
|
||||
bytes sharedTokenSecret = 3;
|
||||
}
|
||||
|
||||
message ClientHandshakeStart {
|
||||
// Public key associated with this server's enclave. For use in test-only
|
||||
// contexts where attestation is not available
|
||||
bytes test_only_pubkey = 1;
|
||||
bytes testonlyPubkey = 1;
|
||||
|
||||
// Remote-attestation evidence associated with the public key
|
||||
bytes evidence = 2;
|
||||
@@ -23,13 +23,13 @@ message Response {
|
||||
}
|
||||
|
||||
message BackupRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
optional bytes token = 3;
|
||||
optional uint64 valid_from = 4;
|
||||
optional bytes data = 5;
|
||||
optional bytes pin = 6;
|
||||
optional uint32 tries = 7;
|
||||
optional bytes serviceId = 1;
|
||||
optional bytes backupId = 2;
|
||||
optional bytes token = 3;
|
||||
optional uint64 validFrom = 4;
|
||||
optional bytes data = 5;
|
||||
optional bytes pin = 6;
|
||||
optional uint32 tries = 7;
|
||||
}
|
||||
|
||||
message BackupResponse {
|
||||
@@ -44,11 +44,11 @@ message BackupResponse {
|
||||
}
|
||||
|
||||
message RestoreRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
optional bytes token = 3;
|
||||
optional uint64 valid_from = 4;
|
||||
optional bytes pin = 5;
|
||||
optional bytes serviceId = 1;
|
||||
optional bytes backupId = 2;
|
||||
optional bytes token = 3;
|
||||
optional uint64 validFrom = 4;
|
||||
optional bytes pin = 5;
|
||||
}
|
||||
|
||||
message RestoreResponse {
|
||||
@@ -67,8 +67,8 @@ message RestoreResponse {
|
||||
}
|
||||
|
||||
message DeleteRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
optional bytes serviceId = 1;
|
||||
optional bytes backupId = 2;
|
||||
}
|
||||
|
||||
message DeleteResponse {
|
||||
Reference in New Issue
Block a user