Skip to content

Commit

Permalink
Always refetch profile key credential if expired
Browse files Browse the repository at this point in the history
  • Loading branch information
indutny-signal committed Jul 18, 2022
1 parent 52686ed commit d743412
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
2 changes: 1 addition & 1 deletion ts/background.ts
Expand Up @@ -818,7 +818,7 @@ export async function startApp(): Promise<void> {
await window.Signal.Data.clearAllErrorStickerPackAttempts();
}

if (window.isBeforeVersion(lastVersion, 'v5.50.0-alpha.1')) {
if (window.isBeforeVersion(lastVersion, 'v5.51.0-beta.2')) {
await window.storage.put('groupCredentials', []);
await window.Signal.Data.removeAllProfileKeyCredentials();
}
Expand Down
89 changes: 59 additions & 30 deletions ts/groups.ts
Expand Up @@ -61,6 +61,7 @@ import type {
GroupCredentialsType,
GroupLogResponseType,
} from './textsecure/WebAPI';
import { HTTPError } from './textsecure/Errors';
import type MessageSender from './textsecure/SendMessage';
import { CURRENT_SCHEMA_VERSION as MAX_MESSAGE_SCHEMA } from './types/Message2';
import type { ConversationModel } from './models/conversations';
Expand Down Expand Up @@ -1496,13 +1497,6 @@ export async function modifyGroupV2({
log.info(`modifyGroupV2/${logId}: Fetching profiles for ${logIds}`);
}

for (const member of membersMissingCredentials) {
member.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});
}

// eslint-disable-next-line no-await-in-loop
await profileFetchQueue.addAll(
membersMissingCredentials.map(member => () => member.getProfiles())
Expand Down Expand Up @@ -1740,19 +1734,25 @@ export async function fetchMembershipProof({

// Creating a group

export async function createGroupV2({
name,
avatar,
expireTimer,
conversationIds,
avatars,
}: Readonly<{
name: string;
avatar: undefined | Uint8Array;
expireTimer: undefined | number;
conversationIds: Array<string>;
avatars?: Array<AvatarDataType>;
}>): Promise<ConversationModel> {
export async function createGroupV2(
options: Readonly<{
name: string;
avatar: undefined | Uint8Array;
expireTimer: undefined | number;
conversationIds: Array<string>;
avatars?: Array<AvatarDataType>;
refreshedCredentials?: boolean;
}>
): Promise<ConversationModel> {
const {
name,
avatar,
expireTimer,
conversationIds,
avatars,
refreshedCredentials = false,
} = options;

// Ensure we have the credentials we need before attempting GroupsV2 operations
await maybeFetchNewCredentials();

Expand All @@ -1775,10 +1775,6 @@ export async function createGroupV2({
window.ConversationController.getOurConversationOrThrow();
if (ourConversation.hasProfileKeyCredentialExpired()) {
log.info(`createGroupV2/${logId}: fetching our own credentials`);
ourConversation.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});
await ourConversation.getProfiles();
}

Expand Down Expand Up @@ -1874,12 +1870,45 @@ export async function createGroupV2({
...protoAndConversationAttributes,
});

await makeRequestWithTemporalRetry({
logId: `createGroupV2/${logId}`,
publicParams,
secretParams,
request: (sender, options) => sender.createGroup(groupProto, options),
});
try {
await makeRequestWithTemporalRetry({
logId: `createGroupV2/${logId}`,
publicParams,
secretParams,
request: (sender, requestOptions) =>
sender.createGroup(groupProto, requestOptions),
});
} catch (error) {
if (!(error instanceof HTTPError)) {
throw error;
}
if (error.code !== 400 || refreshedCredentials) {
throw error;
}

const logIds = conversationIds.map(conversationId => {
const contact = window.ConversationController.get(conversationId);
if (!contact) {
return;
}
contact.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});

return contact.idForLogging();
});

log.warn(
`createGroupV2/${logId}: Profile key credentials were not ` +
`up-to-date. Updating profiles for ${logIds} and retrying`
);

return createGroupV2({
...options,
refreshedCredentials: true,
});
}

let avatarAttribute: ConversationAttributesType['avatar'];
if (uploadedAvatar) {
Expand Down
4 changes: 0 additions & 4 deletions ts/routineProfileRefresh.ts
Expand Up @@ -196,10 +196,6 @@ function* getFilteredConversations(
(conversation.id === ourConversationId ||
!conversationIdsSeen.has(conversation.id))
) {
conversation.set({
profileKeyCredential: null,
profileKeyCredentialExpiration: null,
});
conversationIdsSeen.add(conversation.id);
yield conversation;
break;
Expand Down
3 changes: 1 addition & 2 deletions ts/util/getProfile.ts
Expand Up @@ -123,7 +123,6 @@ async function doGetProfile(c: ConversationModel): Promise<void> {
const profileKey = c.get('profileKey');
const profileKeyVersion = c.deriveProfileKeyVersion();
const uuid = c.getCheckedUuid('getProfile');
const existingProfileKeyCredential = c.get('profileKeyCredential');
const lastProfile = c.get('lastProfile');

let profileCredentialRequestContext:
Expand All @@ -139,7 +138,7 @@ async function doGetProfile(c: ConversationModel): Promise<void> {
'profileKeyVersion and accessKey are derived from profileKey'
);

if (existingProfileKeyCredential) {
if (!c.hasProfileKeyCredentialExpired()) {
getProfileOptions = {
accessKey,
profileKeyVersion,
Expand Down

0 comments on commit d743412

Please sign in to comment.