mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 11:28:05 +01:00
Introduce "service identifiers"
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.identity;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
import java.util.UUID;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
||||
|
||||
/**
|
||||
* An identifier for an account based on the account's ACI.
|
||||
*
|
||||
* @param uuid the account's ACI UUID
|
||||
*/
|
||||
@Schema(
|
||||
type = "string",
|
||||
description = "An identifier for an account based on the account's ACI"
|
||||
)
|
||||
public record AciServiceIdentifier(UUID uuid) implements ServiceIdentifier {
|
||||
|
||||
private static final IdentityType IDENTITY_TYPE = IdentityType.ACI;
|
||||
|
||||
@Override
|
||||
public IdentityType identityType() {
|
||||
return IDENTITY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toServiceIdentifierString() {
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toCompactByteArray() {
|
||||
return UUIDUtil.toBytes(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toFixedWidthByteArray() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.allocate(17);
|
||||
byteBuffer.put(IDENTITY_TYPE.getBytePrefix());
|
||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
||||
byteBuffer.flip();
|
||||
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public static AciServiceIdentifier valueOf(final String string) {
|
||||
return new AciServiceIdentifier(
|
||||
UUID.fromString(string.startsWith(IDENTITY_TYPE.getStringPrefix())
|
||||
? string.substring(IDENTITY_TYPE.getStringPrefix().length()) : string));
|
||||
}
|
||||
|
||||
public static AciServiceIdentifier fromBytes(final byte[] bytes) {
|
||||
final UUID uuid;
|
||||
|
||||
if (bytes.length == 17) {
|
||||
if (bytes[0] != IDENTITY_TYPE.getBytePrefix()) {
|
||||
throw new IllegalArgumentException("Unexpected byte array prefix: " + HexFormat.of().formatHex(new byte[] { bytes[0] }));
|
||||
}
|
||||
|
||||
uuid = UUIDUtil.fromBytes(Arrays.copyOfRange(bytes, 1, bytes.length));
|
||||
} else {
|
||||
uuid = UUIDUtil.fromBytes(bytes);
|
||||
}
|
||||
|
||||
return new AciServiceIdentifier(uuid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.identity;
|
||||
|
||||
public enum IdentityType {
|
||||
ACI((byte) 0x00, "ACI:"),
|
||||
PNI((byte) 0x01, "PNI:");
|
||||
|
||||
private final byte bytePrefix;
|
||||
private final String stringPrefix;
|
||||
|
||||
IdentityType(final byte bytePrefix, final String stringPrefix) {
|
||||
this.bytePrefix = bytePrefix;
|
||||
this.stringPrefix = stringPrefix;
|
||||
}
|
||||
|
||||
byte getBytePrefix() {
|
||||
return bytePrefix;
|
||||
}
|
||||
|
||||
String getStringPrefix() {
|
||||
return stringPrefix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.identity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* An identifier for an account based on the account's phone number identifier (PNI).
|
||||
*
|
||||
* @param uuid the account's PNI UUID
|
||||
*/
|
||||
@Schema(
|
||||
type = "string",
|
||||
description = "An identifier for an account based on the account's phone number identifier (PNI)"
|
||||
)
|
||||
public record PniServiceIdentifier(UUID uuid) implements ServiceIdentifier {
|
||||
|
||||
private static final IdentityType IDENTITY_TYPE = IdentityType.PNI;
|
||||
|
||||
@Override
|
||||
public IdentityType identityType() {
|
||||
return IDENTITY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toServiceIdentifierString() {
|
||||
return IDENTITY_TYPE.getStringPrefix() + uuid.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toCompactByteArray() {
|
||||
return toFixedWidthByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toFixedWidthByteArray() {
|
||||
final ByteBuffer byteBuffer = ByteBuffer.allocate(17);
|
||||
byteBuffer.put(IDENTITY_TYPE.getBytePrefix());
|
||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
||||
byteBuffer.flip();
|
||||
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public static PniServiceIdentifier valueOf(final String string) {
|
||||
if (!string.startsWith(IDENTITY_TYPE.getStringPrefix())) {
|
||||
throw new IllegalArgumentException("PNI account identifier did not start with \"PNI:\" prefix");
|
||||
}
|
||||
|
||||
return new PniServiceIdentifier(UUID.fromString(string.substring(IDENTITY_TYPE.getStringPrefix().length())));
|
||||
}
|
||||
|
||||
public static PniServiceIdentifier fromBytes(final byte[] bytes) {
|
||||
if (bytes.length == 17) {
|
||||
if (bytes[0] != IDENTITY_TYPE.getBytePrefix()) {
|
||||
throw new IllegalArgumentException("Unexpected byte array prefix: " + HexFormat.of().formatHex(new byte[] { bytes[0] }));
|
||||
}
|
||||
|
||||
return new PniServiceIdentifier(UUIDUtil.fromBytes(Arrays.copyOfRange(bytes, 1, bytes.length)));
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unexpected byte array length: " + bytes.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.identity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A "service identifier" is a tuple of a UUID and identity type that identifies an account and identity within the
|
||||
* Signal service.
|
||||
*/
|
||||
@Schema(
|
||||
type = "string",
|
||||
description = "A service identifier is a tuple of a UUID and identity type that identifies an account and identity within the Signal service.",
|
||||
subTypes = {AciServiceIdentifier.class, PniServiceIdentifier.class}
|
||||
)
|
||||
public interface ServiceIdentifier {
|
||||
|
||||
/**
|
||||
* Returns the identity type of this account identifier.
|
||||
*
|
||||
* @return the identity type of this account identifier
|
||||
*/
|
||||
IdentityType identityType();
|
||||
|
||||
/**
|
||||
* Returns the UUID for this account identifier.
|
||||
*
|
||||
* @return the UUID for this account identifier
|
||||
*/
|
||||
UUID uuid();
|
||||
|
||||
/**
|
||||
* Returns a string representation of this account identifier in a format that clients can unambiguously resolve into
|
||||
* an identity type and UUID.
|
||||
*
|
||||
* @return a "strongly-typed" string representation of this account identifier
|
||||
*/
|
||||
String toServiceIdentifierString();
|
||||
|
||||
/**
|
||||
* Returns a compact binary representation of this account identifier.
|
||||
*
|
||||
* @return a binary representation of this account identifier
|
||||
*/
|
||||
byte[] toCompactByteArray();
|
||||
|
||||
/**
|
||||
* Returns a fixed-width binary representation of this account identifier.
|
||||
*
|
||||
* @return a binary representation of this account identifier
|
||||
*/
|
||||
byte[] toFixedWidthByteArray();
|
||||
|
||||
static ServiceIdentifier valueOf(final String string) {
|
||||
try {
|
||||
return AciServiceIdentifier.valueOf(string);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return PniServiceIdentifier.valueOf(string);
|
||||
}
|
||||
}
|
||||
|
||||
static ServiceIdentifier fromBytes(final byte[] bytes) {
|
||||
try {
|
||||
return AciServiceIdentifier.fromBytes(bytes);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return PniServiceIdentifier.fromBytes(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user