Update libsignal-service-java

This commit is contained in:
AsamK 2022-07-24 10:01:22 +02:00
parent 72293d8d87
commit 956cb97331
12 changed files with 122 additions and 108 deletions

View file

@ -761,7 +761,6 @@
"queryAllDeclaredMethods":true, "queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true, "queryAllDeclaredConstructors":true,
"methods":[ "methods":[
{"name":"date","parameterTypes":[] },
{"name":"description","parameterTypes":[] }, {"name":"description","parameterTypes":[] },
{"name":"image","parameterTypes":[] }, {"name":"image","parameterTypes":[] },
{"name":"title","parameterTypes":[] }, {"name":"title","parameterTypes":[] },
@ -1041,18 +1040,6 @@
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true
}, },
{
"name":"org.asamk.signal.manager.storage.profiles.SignalProfile",
"allDeclaredFields":true,
"allDeclaredMethods":true,
"allDeclaredConstructors":true
},
{
"name":"org.asamk.signal.manager.storage.profiles.SignalProfile$Capabilities",
"allDeclaredFields":true,
"allDeclaredMethods":true,
"allDeclaredConstructors":true
},
{ {
"name":"org.asamk.signal.manager.storage.protocol.LegacyJsonIdentityKeyStore$JsonIdentityKeyStoreDeserializer", "name":"org.asamk.signal.manager.storage.protocol.LegacyJsonIdentityKeyStore$JsonIdentityKeyStoreDeserializer",
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":[] }]
@ -1634,13 +1621,13 @@
"queryAllDeclaredMethods":true "queryAllDeclaredMethods":true
}, },
{ {
"name":"org.signal.libsignal.zkgroup.profiles.ProfileKey", "name":"org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential",
"allDeclaredFields":true, "allDeclaredFields":true,
"queryAllDeclaredMethods":true, "queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true "queryAllDeclaredConstructors":true
}, },
{ {
"name":"org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential", "name":"org.signal.libsignal.zkgroup.profiles.ProfileKey",
"allDeclaredFields":true, "allDeclaredFields":true,
"queryAllDeclaredMethods":true, "queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true "queryAllDeclaredConstructors":true
@ -1728,6 +1715,7 @@
{"name":"modifyMemberRoles_"}, {"name":"modifyMemberRoles_"},
{"name":"modifyTitle_"}, {"name":"modifyTitle_"},
{"name":"promotePendingMembers_"}, {"name":"promotePendingMembers_"},
{"name":"promotePendingPniAciMembers_"},
{"name":"promoteRequestingMembers_"}, {"name":"promoteRequestingMembers_"},
{"name":"revision_"}, {"name":"revision_"},
{"name":"sourceUuid_"} {"name":"sourceUuid_"}
@ -1798,7 +1786,11 @@
}, },
{ {
"name":"org.signal.storageservice.protos.groups.GroupChange$Actions$ModifyMemberProfileKeyAction", "name":"org.signal.storageservice.protos.groups.GroupChange$Actions$ModifyMemberProfileKeyAction",
"fields":[{"name":"presentation_"}] "fields":[
{"name":"presentation_"},
{"name":"profileKey_"},
{"name":"userId_"}
]
}, },
{ {
"name":"org.signal.storageservice.protos.groups.GroupChange$Actions$ModifyMemberRoleAction", "name":"org.signal.storageservice.protos.groups.GroupChange$Actions$ModifyMemberRoleAction",
@ -1817,7 +1809,20 @@
}, },
{ {
"name":"org.signal.storageservice.protos.groups.GroupChange$Actions$PromotePendingMemberAction", "name":"org.signal.storageservice.protos.groups.GroupChange$Actions$PromotePendingMemberAction",
"fields":[{"name":"presentation_"}] "fields":[
{"name":"presentation_"},
{"name":"profileKey_"},
{"name":"userId_"}
]
},
{
"name":"org.signal.storageservice.protos.groups.GroupChange$Actions$PromotePendingPniAciMemberProfileKeyAction",
"fields":[
{"name":"pni_"},
{"name":"presentation_"},
{"name":"profileKey_"},
{"name":"userId_"}
]
}, },
{ {
"name":"org.signal.storageservice.protos.groups.GroupChange$Actions$PromoteRequestingMemberAction", "name":"org.signal.storageservice.protos.groups.GroupChange$Actions$PromoteRequestingMemberAction",
@ -1946,6 +1951,7 @@
{"name":"newTimer_"}, {"name":"newTimer_"},
{"name":"newTitle_"}, {"name":"newTitle_"},
{"name":"promotePendingMembers_"}, {"name":"promotePendingMembers_"},
{"name":"promotePendingPniAciMembers_"},
{"name":"promoteRequestingMembers_"}, {"name":"promoteRequestingMembers_"},
{"name":"revision_"} {"name":"revision_"}
] ]
@ -1967,6 +1973,7 @@
"name":"org.signal.storageservice.protos.groups.local.DecryptedMember", "name":"org.signal.storageservice.protos.groups.local.DecryptedMember",
"fields":[ "fields":[
{"name":"joinedAtRevision_"}, {"name":"joinedAtRevision_"},
{"name":"pni_"},
{"name":"profileKey_"}, {"name":"profileKey_"},
{"name":"role_"}, {"name":"role_"},
{"name":"uuid_"} {"name":"uuid_"}
@ -2142,7 +2149,7 @@
"allDeclaredFields":true, "allDeclaredFields":true,
"queryAllDeclaredMethods":true, "queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true, "queryAllDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":["java.lang.String","java.lang.String"] }]
}, },
{ {
"name":"org.whispersystems.signalservice.api.storage.StorageAuthResponse", "name":"org.whispersystems.signalservice.api.storage.StorageAuthResponse",

View file

@ -14,7 +14,7 @@ repositories {
} }
dependencies { dependencies {
implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_51") implementation("com.github.turasa", "signal-service-java", "2.15.3_unofficial_52")
implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.3") implementation("com.fasterxml.jackson.core", "jackson-databind", "2.13.3")
implementation("com.google.protobuf", "protobuf-javalite", "3.11.4") implementation("com.google.protobuf", "protobuf-javalite", "3.11.4")
implementation("org.bouncycastle", "bcprov-jdk15on", "1.70") implementation("org.bouncycastle", "bcprov-jdk15on", "1.70")

View file

@ -46,7 +46,7 @@ class LiveConfig {
private final static Optional<SignalProxy> proxy = Optional.empty(); private final static Optional<SignalProxy> proxy = Optional.empty();
private final static byte[] zkGroupServerPublicParams = Base64.getDecoder() private final static byte[] zkGroupServerPublicParams = Base64.getDecoder()
.decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXQ=="); .decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X36nOoGPs54XsEGzPdEV+itQNGUFEjY6X9Uv+Acuks7NpyGvCoKxGwgKgE5XyJ+nNKlyHHOLb6N1NuHyBrZrgtY/JYJHRooo5CEqYKBqdFnmbTVGEkCvJKxLnjwKWf+fEPoWeQFj5ObDjcKMZf2Jm2Ae69x+ikU5gBXsRmoF94GXTLfN0/vLt98KDPnxwAQL9j5V1jGOY8jQl6MLxEs56cwXN0dqCnImzVH3TZT1cJ8SW1BRX6qIVxEzjsSGx3yxF3suAilPMqGRp4ffyopjMD1JXiKR2RwLKzizUe5e8XyGOy9fplzhw3jVzTRyUZTRSZKkMLWcQ/gv0E4aONNqs4P");
static SignalServiceConfiguration createDefaultServiceConfiguration( static SignalServiceConfiguration createDefaultServiceConfiguration(
final List<Interceptor> interceptors final List<Interceptor> interceptors

View file

@ -46,7 +46,7 @@ class StagingConfig {
private final static Optional<SignalProxy> proxy = Optional.empty(); private final static Optional<SignalProxy> proxy = Optional.empty();
private final static byte[] zkGroupServerPublicParams = Base64.getDecoder() private final static byte[] zkGroupServerPublicParams = Base64.getDecoder()
.decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXQ=="); .decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdlukrpzzsCIvEwjwQlJYVPOQPj4V0F4UXXBdHSLK05uoPBCQG8G9rYIGedYsClJXnbrgGYG3eMTG5hnx4X4ntARBgELuMWWUEEfSK0mjXg+/2lPmWcTZWR9nkqgQQP0tbzuiPm74H2wMO4u1Wafe+UwyIlIT9L7KLS19Aw8r4sPrXZSSsOZ6s7M1+rTJN0bI5CKY2PX29y5Ok3jSWufIKcgKOnWoP67d5b2du2ZVJjpjfibNIHbT/cegy/sBLoFwtHogVYUewANUAXIaMPyCLRArsKhfJ5wBtTminG/PAvuBdJ70Z/bXVPf8TVsR292zQ65xwvWTejROW6AZX6aqucUj");
static SignalServiceConfiguration createDefaultServiceConfiguration( static SignalServiceConfiguration createDefaultServiceConfiguration(
final List<Interceptor> interceptors final List<Interceptor> interceptors

View file

@ -16,7 +16,7 @@ import org.asamk.signal.manager.util.IOUtils;
import org.asamk.signal.manager.util.Utils; import org.asamk.signal.manager.util.Utils;
import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException; import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.auth.AuthCredentialResponse; import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse;
import org.signal.libsignal.zkgroup.groups.GroupMasterKey; import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams; import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.groups.UuidCiphertext; import org.signal.libsignal.zkgroup.groups.UuidCiphertext;
@ -41,6 +41,7 @@ import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException; import org.whispersystems.signalservice.api.groupsv2.InvalidGroupStateException;
import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException; import org.whispersystems.signalservice.api.groupsv2.NotAbleToApplyGroupV2ChangeException;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
@ -69,7 +70,7 @@ class GroupV2Helper {
private final SignalDependencies dependencies; private final SignalDependencies dependencies;
private final Context context; private final Context context;
private HashMap<Integer, AuthCredentialResponse> groupApiCredentials; private HashMap<Long, AuthCredentialWithPniResponse> groupApiCredentials;
GroupV2Helper(final Context context) { GroupV2Helper(final Context context) {
this.dependencies = context.getDependencies(); this.dependencies = context.getDependencies();
@ -177,7 +178,7 @@ class GroupV2Helper {
String name, Set<RecipientId> members, byte[] avatar String name, Set<RecipientId> members, byte[] avatar
) { ) {
final var profileKeyCredential = context.getProfileHelper() final var profileKeyCredential = context.getProfileHelper()
.getRecipientProfileKeyCredential(context.getAccount().getSelfRecipientId()); .getExpiringProfileKeyCredential(context.getAccount().getSelfRecipientId());
if (profileKeyCredential == null) { if (profileKeyCredential == null) {
logger.warn("Cannot create a V2 group as self does not have a versioned profile"); logger.warn("Cannot create a V2 group as self does not have a versioned profile");
return null; return null;
@ -185,7 +186,7 @@ class GroupV2Helper {
final var self = new GroupCandidate(getSelfAci().uuid(), Optional.of(profileKeyCredential)); final var self = new GroupCandidate(getSelfAci().uuid(), Optional.of(profileKeyCredential));
final var memberList = new ArrayList<>(members); final var memberList = new ArrayList<>(members);
final var credentials = context.getProfileHelper().getRecipientProfileKeyCredential(memberList).stream(); final var credentials = context.getProfileHelper().getExpiringProfileKeyCredential(memberList).stream();
final var uuids = memberList.stream() final var uuids = memberList.stream()
.map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getServiceId().uuid()); .map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getServiceId().uuid());
var candidates = Utils.zip(uuids, var candidates = Utils.zip(uuids,
@ -234,7 +235,7 @@ class GroupV2Helper {
GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2); GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
final var memberList = new ArrayList<>(newMembers); final var memberList = new ArrayList<>(newMembers);
final var credentials = context.getProfileHelper().getRecipientProfileKeyCredential(memberList).stream(); final var credentials = context.getProfileHelper().getExpiringProfileKeyCredential(memberList).stream();
final var uuids = memberList.stream() final var uuids = memberList.stream()
.map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getServiceId().uuid()); .map(member -> context.getRecipientHelper().resolveSignalServiceAddress(member).getServiceId().uuid());
var candidates = Utils.zip(uuids, var candidates = Utils.zip(uuids,
@ -396,7 +397,7 @@ class GroupV2Helper {
logger.debug("Updating own profile key in group " + groupInfoV2.getGroupId().toBase64()); logger.debug("Updating own profile key in group " + groupInfoV2.getGroupId().toBase64());
final var selfRecipientId = context.getAccount().getSelfRecipientId(); final var selfRecipientId = context.getAccount().getSelfRecipientId();
final var profileKeyCredential = context.getProfileHelper().getRecipientProfileKeyCredential(selfRecipientId); final var profileKeyCredential = context.getProfileHelper().getExpiringProfileKeyCredential(selfRecipientId);
if (profileKeyCredential == null) { if (profileKeyCredential == null) {
logger.trace("Cannot update profile key as self does not have a versioned profile"); logger.trace("Cannot update profile key as self does not have a versioned profile");
return null; return null;
@ -417,7 +418,7 @@ class GroupV2Helper {
final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams); final var groupOperations = dependencies.getGroupsV2Operations().forGroup(groupSecretParams);
final var selfRecipientId = context.getAccount().getSelfRecipientId(); final var selfRecipientId = context.getAccount().getSelfRecipientId();
final var profileKeyCredential = context.getProfileHelper().getRecipientProfileKeyCredential(selfRecipientId); final var profileKeyCredential = context.getProfileHelper().getExpiringProfileKeyCredential(selfRecipientId);
if (profileKeyCredential == null) { if (profileKeyCredential == null) {
throw new IOException("Cannot join a V2 group as self does not have a versioned profile"); throw new IOException("Cannot join a V2 group as self does not have a versioned profile");
} }
@ -439,7 +440,7 @@ class GroupV2Helper {
final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2); final GroupsV2Operations.GroupOperations groupOperations = getGroupOperations(groupInfoV2);
final var selfRecipientId = context.getAccount().getSelfRecipientId(); final var selfRecipientId = context.getAccount().getSelfRecipientId();
final var profileKeyCredential = context.getProfileHelper().getRecipientProfileKeyCredential(selfRecipientId); final var profileKeyCredential = context.getProfileHelper().getExpiringProfileKeyCredential(selfRecipientId);
if (profileKeyCredential == null) { if (profileKeyCredential == null) {
throw new IOException("Cannot join a V2 group as self does not have a versioned profile"); throw new IOException("Cannot join a V2 group as self does not have a versioned profile");
} }
@ -609,31 +610,49 @@ class GroupV2Helper {
return null; return null;
} }
private static int currentTimeDays() { private static long currentDaySeconds() {
return (int) TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()); return TimeUnit.DAYS.toSeconds(TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()));
} }
private GroupsV2AuthorizationString getGroupAuthForToday( private GroupsV2AuthorizationString getGroupAuthForToday(
final GroupSecretParams groupSecretParams final GroupSecretParams groupSecretParams
) throws IOException { ) throws IOException {
final var today = currentTimeDays(); final var todaySeconds = currentDaySeconds();
if (groupApiCredentials == null || !groupApiCredentials.containsKey(today)) { if (groupApiCredentials == null || !groupApiCredentials.containsKey(todaySeconds)) {
// Returns credentials for the next 7 days // Returns credentials for the next 7 days
final var isAci = true; // TODO enable group handling with PNI groupApiCredentials = dependencies.getGroupsV2Api().getCredentials(todaySeconds);
groupApiCredentials = dependencies.getGroupsV2Api().getCredentials(today, isAci);
// TODO cache credentials on disk until they expire // TODO cache credentials on disk until they expire
} }
var authCredentialResponse = groupApiCredentials.get(today);
final var aci = getSelfAci();
try { try {
return dependencies.getGroupsV2Api() return getAuthorizationString(groupSecretParams, todaySeconds);
.getGroupsV2AuthorizationString(aci, today, groupSecretParams, authCredentialResponse); } catch (VerificationFailedException e) {
logger.debug("Group api credentials invalid, renewing and trying again.");
groupApiCredentials.clear();
}
groupApiCredentials = dependencies.getGroupsV2Api().getCredentials(todaySeconds);
try {
return getAuthorizationString(groupSecretParams, todaySeconds);
} catch (VerificationFailedException e) { } catch (VerificationFailedException e) {
throw new IOException(e); throw new IOException(e);
} }
} }
private GroupsV2AuthorizationString getAuthorizationString(
final GroupSecretParams groupSecretParams, final long todaySeconds
) throws VerificationFailedException {
var authCredentialResponse = groupApiCredentials.get(todaySeconds);
final var aci = getSelfAci();
final var pni = getSelfPni();
return dependencies.getGroupsV2Api()
.getGroupsV2AuthorizationString(aci, pni, todaySeconds, groupSecretParams, authCredentialResponse);
}
private ACI getSelfAci() { private ACI getSelfAci() {
return context.getAccount().getAci(); return context.getAccount().getAci();
} }
private PNI getSelfPni() {
return context.getAccount().getPni();
}
} }

View file

@ -16,8 +16,8 @@ import org.asamk.signal.manager.util.ProfileUtils;
import org.asamk.signal.manager.util.Utils; import org.asamk.signal.manager.util.Utils;
import org.signal.libsignal.protocol.IdentityKey; import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.InvalidKeyException; import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
@ -28,6 +28,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.NotFoundException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import org.whispersystems.signalservice.api.services.ProfileService; import org.whispersystems.signalservice.api.services.ProfileService;
import org.whispersystems.signalservice.api.util.ExpiringProfileCredentialUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -106,11 +107,12 @@ public final class ProfileHelper {
getRecipientProfiles(recipientIds, true); getRecipientProfiles(recipientIds, true);
} }
public List<ProfileKeyCredential> getRecipientProfileKeyCredential(List<RecipientId> recipientIds) { public List<ExpiringProfileKeyCredential> getExpiringProfileKeyCredential(List<RecipientId> recipientIds) {
try { try {
account.getRecipientStore().setBulkUpdating(true); account.getRecipientStore().setBulkUpdating(true);
final var profileFetches = Flowable.fromIterable(recipientIds) final var profileFetches = Flowable.fromIterable(recipientIds)
.filter(recipientId -> account.getProfileStore().getProfileKeyCredential(recipientId) == null) .filter(recipientId -> !ExpiringProfileCredentialUtil.isValid(account.getProfileStore()
.getExpiringProfileKeyCredential(recipientId)))
.map(recipientId -> retrieveProfile(recipientId, .map(recipientId -> retrieveProfile(recipientId,
SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL).onErrorComplete()); SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL).onErrorComplete());
Maybe.merge(profileFetches, 10).blockingSubscribe(); Maybe.merge(profileFetches, 10).blockingSubscribe();
@ -118,12 +120,12 @@ public final class ProfileHelper {
account.getRecipientStore().setBulkUpdating(false); account.getRecipientStore().setBulkUpdating(false);
} }
return recipientIds.stream().map(r -> account.getProfileStore().getProfileKeyCredential(r)).toList(); return recipientIds.stream().map(r -> account.getProfileStore().getExpiringProfileKeyCredential(r)).toList();
} }
public ProfileKeyCredential getRecipientProfileKeyCredential(RecipientId recipientId) { public ExpiringProfileKeyCredential getExpiringProfileKeyCredential(RecipientId recipientId) {
var profileKeyCredential = account.getProfileStore().getProfileKeyCredential(recipientId); var profileKeyCredential = account.getProfileStore().getExpiringProfileKeyCredential(recipientId);
if (profileKeyCredential != null) { if (ExpiringProfileCredentialUtil.isValid(profileKeyCredential)) {
return profileKeyCredential; return profileKeyCredential;
} }
@ -134,7 +136,7 @@ public final class ProfileHelper {
return null; return null;
} }
return account.getProfileStore().getProfileKeyCredential(recipientId); return account.getProfileStore().getExpiringProfileKeyCredential(recipientId);
} }
/** /**
@ -327,10 +329,11 @@ public final class ProfileHelper {
final var encryptedProfile = p.getProfile(); final var encryptedProfile = p.getProfile();
if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL
|| account.getProfileStore().getProfileKeyCredential(recipientId) == null) { || !ExpiringProfileCredentialUtil.isValid(account.getProfileStore()
.getExpiringProfileKeyCredential(recipientId))) {
logger.trace("Storing profile credential"); logger.trace("Storing profile credential");
final var profileKeyCredential = p.getProfileKeyCredential().orElse(null); final var profileKeyCredential = p.getExpiringProfileKeyCredential().orElse(null);
account.getProfileStore().storeProfileKeyCredential(recipientId, profileKeyCredential); account.getProfileStore().storeExpiringProfileKeyCredential(recipientId, profileKeyCredential);
} }
final var profile = account.getProfileStore().getProfile(recipientId); final var profile = account.getProfileStore().getProfile(recipientId);

View file

@ -756,7 +756,7 @@ public class SignalAccount implements Closeable {
final var legacyProfileStore = jsonProcessor.convertValue(profileStoreNode, LegacyProfileStore.class); final var legacyProfileStore = jsonProcessor.convertValue(profileStoreNode, LegacyProfileStore.class);
for (var profileEntry : legacyProfileStore.getProfileEntries()) { for (var profileEntry : legacyProfileStore.getProfileEntries()) {
var recipientId = getRecipientResolver().resolveRecipient(profileEntry.getAddress()); var recipientId = getRecipientResolver().resolveRecipient(profileEntry.getAddress());
getProfileStore().storeProfileKeyCredential(recipientId, profileEntry.getProfileKeyCredential()); // Not migrating profile key credential here, it was changed to expiring profile key credentials
getProfileStore().storeProfileKey(recipientId, profileEntry.getProfileKey()); getProfileStore().storeProfileKey(recipientId, profileEntry.getProfileKey());
final var profile = profileEntry.getProfile(); final var profile = profileEntry.getProfile();
if (profile != null) { if (profile != null) {

View file

@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
import org.whispersystems.signalservice.api.util.UuidUtil; import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException; import java.io.IOException;
@ -51,21 +50,9 @@ public class LegacyProfileStore {
profileKey = new ProfileKey(Base64.getDecoder().decode(entry.get("profileKey").asText())); profileKey = new ProfileKey(Base64.getDecoder().decode(entry.get("profileKey").asText()));
} catch (InvalidInputException ignored) { } catch (InvalidInputException ignored) {
} }
ProfileKeyCredential profileKeyCredential = null;
if (entry.hasNonNull("profileKeyCredential")) {
try {
profileKeyCredential = new ProfileKeyCredential(Base64.getDecoder()
.decode(entry.get("profileKeyCredential").asText()));
} catch (Throwable ignored) {
}
}
var lastUpdateTimestamp = entry.get("lastUpdateTimestamp").asLong(); var lastUpdateTimestamp = entry.get("lastUpdateTimestamp").asLong();
var profile = jsonProcessor.treeToValue(entry.get("profile"), LegacySignalProfile.class); var profile = jsonProcessor.treeToValue(entry.get("profile"), LegacySignalProfile.class);
profileEntries.add(new LegacySignalProfileEntry(address, profileEntries.add(new LegacySignalProfileEntry(address, profileKey, lastUpdateTimestamp, profile));
profileKey,
lastUpdateTimestamp,
profile,
profileKeyCredential));
} }
} }

View file

@ -2,7 +2,6 @@ package org.asamk.signal.manager.storage.profiles;
import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientAddress;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
public class LegacySignalProfileEntry { public class LegacySignalProfileEntry {
@ -14,20 +13,16 @@ public class LegacySignalProfileEntry {
private final LegacySignalProfile profile; private final LegacySignalProfile profile;
private final ProfileKeyCredential profileKeyCredential;
public LegacySignalProfileEntry( public LegacySignalProfileEntry(
final RecipientAddress address, final RecipientAddress address,
final ProfileKey profileKey, final ProfileKey profileKey,
final long lastUpdateTimestamp, final long lastUpdateTimestamp,
final LegacySignalProfile profile, final LegacySignalProfile profile
final ProfileKeyCredential profileKeyCredential
) { ) {
this.address = address; this.address = address;
this.profileKey = profileKey; this.profileKey = profileKey;
this.lastUpdateTimestamp = lastUpdateTimestamp; this.lastUpdateTimestamp = lastUpdateTimestamp;
this.profile = profile; this.profile = profile;
this.profileKeyCredential = profileKeyCredential;
} }
public RecipientAddress getAddress() { public RecipientAddress getAddress() {
@ -45,8 +40,4 @@ public class LegacySignalProfileEntry {
public LegacySignalProfile getProfile() { public LegacySignalProfile getProfile() {
return profile; return profile;
} }
public ProfileKeyCredential getProfileKeyCredential() {
return profileKeyCredential;
}
} }

View file

@ -2,8 +2,8 @@ package org.asamk.signal.manager.storage.profiles;
import org.asamk.signal.manager.storage.recipients.Profile; import org.asamk.signal.manager.storage.recipients.Profile;
import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.recipients.RecipientId;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
public interface ProfileStore { public interface ProfileStore {
@ -11,7 +11,7 @@ public interface ProfileStore {
ProfileKey getProfileKey(RecipientId recipientId); ProfileKey getProfileKey(RecipientId recipientId);
ProfileKeyCredential getProfileKeyCredential(RecipientId recipientId); ExpiringProfileKeyCredential getExpiringProfileKeyCredential(RecipientId recipientId);
void storeProfile(RecipientId recipientId, Profile profile); void storeProfile(RecipientId recipientId, Profile profile);
@ -19,5 +19,8 @@ public interface ProfileStore {
void storeProfileKey(RecipientId recipientId, ProfileKey profileKey); void storeProfileKey(RecipientId recipientId, ProfileKey profileKey);
void storeProfileKeyCredential(RecipientId recipientId, ProfileKeyCredential profileKeyCredential); void storeExpiringProfileKeyCredential(
RecipientId recipientId,
ExpiringProfileKeyCredential expiringProfileKeyCredential
);
} }

View file

@ -1,7 +1,7 @@
package org.asamk.signal.manager.storage.recipients; package org.asamk.signal.manager.storage.recipients;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
import java.util.Objects; import java.util.Objects;
@ -15,7 +15,7 @@ public class Recipient {
private final ProfileKey profileKey; private final ProfileKey profileKey;
private final ProfileKeyCredential profileKeyCredential; private final ExpiringProfileKeyCredential expiringProfileKeyCredential;
private final Profile profile; private final Profile profile;
@ -24,14 +24,14 @@ public class Recipient {
final RecipientAddress address, final RecipientAddress address,
final Contact contact, final Contact contact,
final ProfileKey profileKey, final ProfileKey profileKey,
final ProfileKeyCredential profileKeyCredential, final ExpiringProfileKeyCredential expiringProfileKeyCredential,
final Profile profile final Profile profile
) { ) {
this.recipientId = recipientId; this.recipientId = recipientId;
this.address = address; this.address = address;
this.contact = contact; this.contact = contact;
this.profileKey = profileKey; this.profileKey = profileKey;
this.profileKeyCredential = profileKeyCredential; this.expiringProfileKeyCredential = expiringProfileKeyCredential;
this.profile = profile; this.profile = profile;
} }
@ -40,7 +40,7 @@ public class Recipient {
address = builder.address; address = builder.address;
contact = builder.contact; contact = builder.contact;
profileKey = builder.profileKey; profileKey = builder.profileKey;
profileKeyCredential = builder.profileKeyCredential; expiringProfileKeyCredential = builder.expiringProfileKeyCredential1;
profile = builder.profile; profile = builder.profile;
} }
@ -54,7 +54,7 @@ public class Recipient {
builder.address = copy.getAddress(); builder.address = copy.getAddress();
builder.contact = copy.getContact(); builder.contact = copy.getContact();
builder.profileKey = copy.getProfileKey(); builder.profileKey = copy.getProfileKey();
builder.profileKeyCredential = copy.getProfileKeyCredential(); builder.expiringProfileKeyCredential1 = copy.getExpiringProfileKeyCredential();
builder.profile = copy.getProfile(); builder.profile = copy.getProfile();
return builder; return builder;
} }
@ -75,8 +75,8 @@ public class Recipient {
return profileKey; return profileKey;
} }
public ProfileKeyCredential getProfileKeyCredential() { public ExpiringProfileKeyCredential getExpiringProfileKeyCredential() {
return profileKeyCredential; return expiringProfileKeyCredential;
} }
public Profile getProfile() { public Profile getProfile() {
@ -92,13 +92,13 @@ public class Recipient {
&& Objects.equals(address, recipient.address) && Objects.equals(address, recipient.address)
&& Objects.equals(contact, recipient.contact) && Objects.equals(contact, recipient.contact)
&& Objects.equals(profileKey, recipient.profileKey) && Objects.equals(profileKey, recipient.profileKey)
&& Objects.equals(profileKeyCredential, recipient.profileKeyCredential) && Objects.equals(expiringProfileKeyCredential, recipient.expiringProfileKeyCredential)
&& Objects.equals(profile, recipient.profile); && Objects.equals(profile, recipient.profile);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(recipientId, address, contact, profileKey, profileKeyCredential, profile); return Objects.hash(recipientId, address, contact, profileKey, expiringProfileKeyCredential, profile);
} }
public static final class Builder { public static final class Builder {
@ -107,7 +107,7 @@ public class Recipient {
private RecipientAddress address; private RecipientAddress address;
private Contact contact; private Contact contact;
private ProfileKey profileKey; private ProfileKey profileKey;
private ProfileKeyCredential profileKeyCredential; private ExpiringProfileKeyCredential expiringProfileKeyCredential1;
private Profile profile; private Profile profile;
private Builder() { private Builder() {
@ -133,8 +133,8 @@ public class Recipient {
return this; return this;
} }
public Builder withProfileKeyCredential(final ProfileKeyCredential val) { public Builder withExpiringProfileKeyCredential(final ExpiringProfileKeyCredential val) {
profileKeyCredential = val; expiringProfileKeyCredential1 = val;
return this; return this;
} }

View file

@ -8,8 +8,8 @@ import org.asamk.signal.manager.storage.Utils;
import org.asamk.signal.manager.storage.contacts.ContactsStore; import org.asamk.signal.manager.storage.contacts.ContactsStore;
import org.asamk.signal.manager.storage.profiles.ProfileStore; import org.asamk.signal.manager.storage.profiles.ProfileStore;
import org.signal.libsignal.zkgroup.InvalidInputException; import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredential;
import org.signal.libsignal.zkgroup.profiles.ProfileKey; import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredential;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
@ -89,11 +89,11 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
} }
} }
ProfileKeyCredential profileKeyCredential = null; ExpiringProfileKeyCredential expiringProfileKeyCredential = null;
if (r.profileKeyCredential != null) { if (r.expiringProfileKeyCredential != null) {
try { try {
profileKeyCredential = new ProfileKeyCredential(Base64.getDecoder() expiringProfileKeyCredential = new ExpiringProfileKeyCredential(Base64.getDecoder()
.decode(r.profileKeyCredential)); .decode(r.expiringProfileKeyCredential));
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
} }
@ -116,7 +116,7 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
.collect(Collectors.toSet())); .collect(Collectors.toSet()));
} }
return new Recipient(recipientId, address, contact, profileKey, profileKeyCredential, profile); return new Recipient(recipientId, address, contact, profileKey, expiringProfileKeyCredential, profile);
}).collect(Collectors.toMap(Recipient::getRecipientId, r -> r)); }).collect(Collectors.toMap(Recipient::getRecipientId, r -> r));
recipientStore.addRecipients(recipients); recipientStore.addRecipients(recipients);
@ -333,9 +333,9 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
} }
@Override @Override
public ProfileKeyCredential getProfileKeyCredential(final RecipientId recipientId) { public ExpiringProfileKeyCredential getExpiringProfileKeyCredential(final RecipientId recipientId) {
final var recipient = getRecipient(recipientId); final var recipient = getRecipient(recipientId);
return recipient == null ? null : recipient.getProfileKeyCredential(); return recipient == null ? null : recipient.getExpiringProfileKeyCredential();
} }
@Override @Override
@ -371,7 +371,7 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
final var builder = Recipient.newBuilder(recipient) final var builder = Recipient.newBuilder(recipient)
.withProfileKey(profileKey) .withProfileKey(profileKey)
.withProfileKeyCredential(null); .withExpiringProfileKeyCredential(null);
if (resetProfile) { if (resetProfile) {
builder.withProfile(recipient.getProfile() == null builder.withProfile(recipient.getProfile() == null
? null ? null
@ -383,11 +383,15 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
} }
@Override @Override
public void storeProfileKeyCredential(RecipientId recipientId, final ProfileKeyCredential profileKeyCredential) { public void storeExpiringProfileKeyCredential(
RecipientId recipientId, final ExpiringProfileKeyCredential expiringProfileKeyCredential
) {
synchronized (recipients) { synchronized (recipients) {
final var recipient = recipients.get(recipientId); final var recipient = recipients.get(recipientId);
storeRecipientLocked(recipientId, storeRecipientLocked(recipientId,
Recipient.newBuilder(recipient).withProfileKeyCredential(profileKeyCredential).build()); Recipient.newBuilder(recipient)
.withExpiringProfileKeyCredential(expiringProfileKeyCredential)
.build());
} }
} }
@ -535,9 +539,9 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
recipient.getProfileKey() != null recipient.getProfileKey() != null
? recipient.getProfileKey() ? recipient.getProfileKey()
: toBeMergedRecipient.getProfileKey(), : toBeMergedRecipient.getProfileKey(),
recipient.getProfileKeyCredential() != null recipient.getExpiringProfileKeyCredential() != null
? recipient.getProfileKeyCredential() ? recipient.getExpiringProfileKeyCredential()
: toBeMergedRecipient.getProfileKeyCredential(), : toBeMergedRecipient.getExpiringProfileKeyCredential(),
recipient.getProfile() != null ? recipient.getProfile() : toBeMergedRecipient.getProfile())); recipient.getProfile() != null ? recipient.getProfile() : toBeMergedRecipient.getProfile()));
recipients.remove(toBeMergedRecipientId); recipients.remove(toBeMergedRecipientId);
recipientsMerged.put(toBeMergedRecipientId.id(), recipientId.id()); recipientsMerged.put(toBeMergedRecipientId.id(), recipientId.id());
@ -607,9 +611,9 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
recipient.getProfileKey() == null recipient.getProfileKey() == null
? null ? null
: base64.encodeToString(recipient.getProfileKey().serialize()), : base64.encodeToString(recipient.getProfileKey().serialize()),
recipient.getProfileKeyCredential() == null recipient.getExpiringProfileKeyCredential() == null
? null ? null
: base64.encodeToString(recipient.getProfileKeyCredential().serialize()), : base64.encodeToString(recipient.getExpiringProfileKeyCredential().serialize()),
contact, contact,
profile); profile);
}).toList(), lastId); }).toList(), lastId);
@ -634,7 +638,7 @@ public class RecipientStore implements RecipientResolver, RecipientTrustedResolv
String number, String number,
String uuid, String uuid,
String profileKey, String profileKey,
String profileKeyCredential, String expiringProfileKeyCredential,
Storage.Recipient.Contact contact, Storage.Recipient.Contact contact,
Storage.Recipient.Profile profile Storage.Recipient.Profile profile
) { ) {