Allow primary devices to change names of linked devices

This commit is contained in:
Jon Chambers
2024-10-29 09:52:38 -04:00
committed by GitHub
parent 712f3affd9
commit f3b22e04e8
14 changed files with 231 additions and 41 deletions

View File

@@ -6,13 +6,15 @@
package org.whispersystems.textsecuregcm.grpc;
import io.grpc.Status;
import org.whispersystems.textsecuregcm.storage.Device;
public class DeviceIdUtil {
static byte validate(int deviceId) {
if (deviceId > Byte.MAX_VALUE) {
if (deviceId < Device.PRIMARY_ID || deviceId > Byte.MAX_VALUE) {
throw Status.INVALID_ARGUMENT.withDescription("Device ID is out of range").asRuntimeException();
}
return (byte) deviceId;
}
}

View File

@@ -89,6 +89,17 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
public Mono<SetDeviceNameResponse> setDeviceName(final SetDeviceNameRequest request) {
final AuthenticatedDevice authenticatedDevice = AuthenticationUtil.requireAuthenticatedDevice();
final byte deviceId = DeviceIdUtil.validate(request.getId());
final boolean mayChangeName = authenticatedDevice.deviceId() == Device.PRIMARY_ID ||
authenticatedDevice.deviceId() == deviceId;
if (!mayChangeName) {
throw Status.PERMISSION_DENIED
.withDescription("Authenticated device is not authorized to change target device name")
.asRuntimeException();
}
if (request.getName().isEmpty()) {
throw Status.INVALID_ARGUMENT.withDescription("Must specify a device name").asRuntimeException();
}
@@ -100,7 +111,12 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
return Mono.fromFuture(() -> accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()))
.map(maybeAccount -> maybeAccount.orElseThrow(Status.UNAUTHENTICATED::asRuntimeException))
.flatMap(account -> Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(),
.doOnNext(account -> {
if (account.getDevice(deviceId).isEmpty()) {
throw Status.NOT_FOUND.withDescription("No device found with given ID").asRuntimeException();
}
})
.flatMap(account -> Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, deviceId,
device -> device.setName(request.getName().toByteArray()))))
.thenReturn(SetDeviceNameResponse.newBuilder().build());
}

View File

@@ -47,7 +47,9 @@ public class KeysAnonymousGrpcService extends ReactorKeysAnonymousGrpc.KeysAnony
final ServiceIdentifier serviceIdentifier =
ServiceIdentifierUtil.fromGrpcServiceIdentifier(request.getRequest().getTargetIdentifier());
final byte deviceId = DeviceIdUtil.validate(request.getRequest().getDeviceId());
final byte deviceId = request.getRequest().hasDeviceId()
? DeviceIdUtil.validate(request.getRequest().getDeviceId())
: KeysGrpcHelper.ALL_DEVICES;
return switch (request.getAuthorizationCase()) {
case GROUP_SEND_TOKEN ->

View File

@@ -5,7 +5,6 @@
package org.whispersystems.textsecuregcm.grpc;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.ByteString;
import io.grpc.Status;
import org.signal.chat.common.EcPreKey;
@@ -26,7 +25,6 @@ import reactor.util.function.Tuples;
class KeysGrpcHelper {
@VisibleForTesting
static final byte ALL_DEVICES = 0;
static Mono<GetPreKeysResponse> getPreKeys(final Account targetAccount,

View File

@@ -122,7 +122,9 @@ public class KeysGrpcService extends ReactorKeysGrpc.KeysImplBase {
final ServiceIdentifier targetIdentifier =
ServiceIdentifierUtil.fromGrpcServiceIdentifier(request.getTargetIdentifier());
final byte deviceId = DeviceIdUtil.validate(request.getDeviceId());
final byte deviceId = request.hasDeviceId()
? DeviceIdUtil.validate(request.getDeviceId())
: KeysGrpcHelper.ALL_DEVICES;
final String rateLimitKey = authenticatedDevice.accountIdentifier() + "." +
authenticatedDevice.deviceId() + "__" +