Skip to content

Commit 4ed837e

Browse files
committed
fix: add test for MessageRequestResponse outgoing message
1 parent 84f2ce7 commit 4ed837e

File tree

3 files changed

+218
-74
lines changed

3 files changed

+218
-74
lines changed
Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import ByteBuffer from 'bytebuffer';
2-
import { isEmpty } from 'lodash';
31
import { SignalService } from '../../../../protobuf';
42
import { LokiProfile } from '../../../../types/Message';
53
import { ContentMessage } from '../ContentMessage';
64
import { MessageParams } from '../Message';
5+
import { buildProfileForOutgoingMessage } from '../visibleMessage/VisibleMessage';
76

87
// tslint:disable-next-line: no-empty-interface
98
export interface MessageRequestResponseParams extends MessageParams {
@@ -14,34 +13,16 @@ export class MessageRequestResponse extends ContentMessage {
1413
// we actually send a response only if it is an accept
1514
// private readonly isApproved: boolean;
1615
private readonly profileKey?: Uint8Array;
17-
private readonly displayName?: string;
18-
private readonly avatarPointer?: string;
16+
private readonly profile?: SignalService.DataMessage.ILokiProfile;
1917

2018
constructor(params: MessageRequestResponseParams) {
2119
super({
2220
timestamp: params.timestamp,
2321
} as MessageRequestResponseParams);
2422

25-
if (params.lokiProfile && params.lokiProfile.profileKey) {
26-
if (
27-
params.lokiProfile.profileKey instanceof Uint8Array ||
28-
(params.lokiProfile.profileKey as any) instanceof ByteBuffer
29-
) {
30-
this.profileKey = new Uint8Array(params.lokiProfile.profileKey);
31-
} else {
32-
this.profileKey = new Uint8Array(
33-
ByteBuffer.wrap(params.lokiProfile.profileKey).toArrayBuffer()
34-
);
35-
}
36-
}
37-
38-
this.displayName = params.lokiProfile && params.lokiProfile.displayName;
39-
40-
// no need to iclude the avatarPointer if there is no profileKey associated with it.
41-
this.avatarPointer =
42-
params.lokiProfile?.avatarPointer && !isEmpty(this.profileKey)
43-
? params.lokiProfile.avatarPointer
44-
: undefined;
23+
const profile = buildProfileForOutgoingMessage(params);
24+
this.profile = profile.lokiProfile;
25+
this.profileKey = profile.profileKey;
4526
}
4627

4728
public contentProto(): SignalService.Content {
@@ -51,27 +32,10 @@ export class MessageRequestResponse extends ContentMessage {
5132
}
5233

5334
public messageRequestResponseProto(): SignalService.MessageRequestResponse {
54-
let profileKey: Uint8Array | undefined;
55-
let profile: SignalService.DataMessage.LokiProfile | undefined;
56-
if (this.avatarPointer || this.displayName) {
57-
profile = new SignalService.DataMessage.LokiProfile();
58-
59-
if (this.avatarPointer) {
60-
profile.profilePicture = this.avatarPointer;
61-
}
62-
63-
if (this.displayName) {
64-
profile.displayName = this.displayName;
65-
}
66-
}
67-
68-
if (this.profileKey && this.profileKey.length) {
69-
profileKey = this.profileKey;
70-
}
7135
return new SignalService.MessageRequestResponse({
7236
isApproved: true,
73-
profileKey,
74-
profile,
37+
profileKey: this.profileKey?.length ? this.profileKey : undefined,
38+
profile: this.profile,
7539
});
7640
}
7741
}

ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ export class VisibleMessage extends DataMessage {
8181
private readonly body?: string;
8282
private readonly quote?: Quote;
8383
private readonly profileKey?: Uint8Array;
84-
private readonly displayName?: string;
85-
private readonly avatarPointer?: string;
84+
private readonly profile?: SignalService.DataMessage.ILokiProfile;
8685
private readonly preview?: Array<PreviewWithAttachmentUrl>;
8786

8887
/// In the case of a sync message, the public key of the person the message was targeted at.
@@ -95,25 +94,11 @@ export class VisibleMessage extends DataMessage {
9594
this.body = params.body;
9695
this.quote = params.quote;
9796
this.expireTimer = params.expireTimer;
98-
if (params.lokiProfile && params.lokiProfile.profileKey) {
99-
if (
100-
params.lokiProfile.profileKey instanceof Uint8Array ||
101-
(params.lokiProfile.profileKey as any) instanceof ByteBuffer
102-
) {
103-
this.profileKey = new Uint8Array(params.lokiProfile.profileKey);
104-
} else {
105-
this.profileKey = new Uint8Array(
106-
ByteBuffer.wrap(params.lokiProfile.profileKey).toArrayBuffer()
107-
);
108-
}
109-
}
11097

111-
this.displayName = params.lokiProfile && params.lokiProfile.displayName;
112-
// no need to iclude the avatarPointer if there is no profileKey associated with it.
113-
this.avatarPointer =
114-
params.lokiProfile?.avatarPointer && !isEmpty(this.profileKey)
115-
? params.lokiProfile.avatarPointer
116-
: undefined;
98+
const profile = buildProfileForOutgoingMessage(params);
99+
100+
this.profile = profile.lokiProfile;
101+
this.profileKey = profile.profileKey;
117102

118103
this.preview = params.preview;
119104
this.reaction = params.reaction;
@@ -143,17 +128,8 @@ export class VisibleMessage extends DataMessage {
143128
dataMessage.syncTarget = this.syncTarget;
144129
}
145130

146-
if (this.avatarPointer || this.displayName) {
147-
const profile = new SignalService.DataMessage.LokiProfile();
148-
149-
if (this.avatarPointer) {
150-
profile.profilePicture = this.avatarPointer;
151-
}
152-
153-
if (this.displayName) {
154-
profile.displayName = this.displayName;
155-
}
156-
dataMessage.profile = profile;
131+
if (this.profile) {
132+
dataMessage.profile = this.profile;
157133
}
158134

159135
if (this.profileKey && this.profileKey.length) {
@@ -208,3 +184,47 @@ export class VisibleMessage extends DataMessage {
208184
return this.identifier === comparator.identifier && this.timestamp === comparator.timestamp;
209185
}
210186
}
187+
188+
export function buildProfileForOutgoingMessage(params: { lokiProfile?: LokiProfile }) {
189+
let profileKey: Uint8Array | undefined;
190+
if (params.lokiProfile && params.lokiProfile.profileKey) {
191+
if (
192+
params.lokiProfile.profileKey instanceof Uint8Array ||
193+
(params.lokiProfile.profileKey as any) instanceof ByteBuffer
194+
) {
195+
profileKey = new Uint8Array(params.lokiProfile.profileKey);
196+
} else {
197+
profileKey = new Uint8Array(ByteBuffer.wrap(params.lokiProfile.profileKey).toArrayBuffer());
198+
}
199+
}
200+
201+
const displayName = params.lokiProfile?.displayName;
202+
203+
// no need to iclude the avatarPointer if there is no profileKey associated with it.
204+
const avatarPointer =
205+
params.lokiProfile?.avatarPointer &&
206+
!isEmpty(profileKey) &&
207+
params.lokiProfile.avatarPointer &&
208+
!isEmpty(params.lokiProfile.avatarPointer)
209+
? params.lokiProfile.avatarPointer
210+
: undefined;
211+
212+
let lokiProfile: SignalService.DataMessage.ILokiProfile | undefined;
213+
if (avatarPointer || displayName) {
214+
lokiProfile = new SignalService.DataMessage.LokiProfile();
215+
216+
// we always need a profileKey tom decode an avatar pointer
217+
if (avatarPointer && avatarPointer.length && profileKey) {
218+
lokiProfile.profilePicture = avatarPointer;
219+
}
220+
221+
if (displayName) {
222+
lokiProfile.displayName = displayName;
223+
}
224+
}
225+
226+
return {
227+
lokiProfile,
228+
profileKey: lokiProfile?.profilePicture ? profileKey : undefined,
229+
};
230+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { expect } from 'chai';
2+
import { v4 } from 'uuid';
3+
4+
import { SignalService } from '../../../../protobuf';
5+
import { Constants } from '../../../../session';
6+
import { MessageRequestResponse } from '../../../../session/messages/outgoing/controlMessage/MessageRequestResponse';
7+
// tslint:disable: no-unused-expression
8+
9+
// tslint:disable-next-line: max-func-body-length
10+
describe('MessageRequestResponse', () => {
11+
let message: MessageRequestResponse | undefined;
12+
it('correct ttl', () => {
13+
message = new MessageRequestResponse({
14+
timestamp: Date.now(),
15+
});
16+
17+
expect(message.ttl()).to.equal(Constants.TTL_DEFAULT.TTL_MAX);
18+
});
19+
20+
it('has an identifier', () => {
21+
message = new MessageRequestResponse({
22+
timestamp: Date.now(),
23+
});
24+
25+
expect(message.identifier).to.not.equal(null, 'identifier cannot be null');
26+
expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined');
27+
});
28+
29+
it('has an identifier matching if given', () => {
30+
const identifier = v4();
31+
message = new MessageRequestResponse({
32+
timestamp: Date.now(),
33+
identifier,
34+
});
35+
36+
expect(message.identifier).to.not.equal(identifier, 'identifier should match');
37+
});
38+
39+
it('isApproved is always true', () => {
40+
message = new MessageRequestResponse({
41+
timestamp: Date.now(),
42+
});
43+
const plainText = message.plainTextBuffer();
44+
const decoded = SignalService.Content.decode(plainText);
45+
expect(decoded.messageRequestResponse)
46+
.to.have.property('isApproved')
47+
.to.be.eq(true, 'isApproved is true');
48+
});
49+
50+
it('can create response without lokiProfile', () => {
51+
message = new MessageRequestResponse({
52+
timestamp: Date.now(),
53+
});
54+
const plainText = message.plainTextBuffer();
55+
const decoded = SignalService.Content.decode(plainText);
56+
expect(decoded.messageRequestResponse)
57+
.to.have.property('profile')
58+
.to.be.eq(null, 'no profile field if no profile given');
59+
});
60+
61+
it('can create response with display name only', () => {
62+
message = new MessageRequestResponse({
63+
timestamp: Date.now(),
64+
lokiProfile: { displayName: 'Jane', profileKey: null },
65+
});
66+
const plainText = message.plainTextBuffer();
67+
const decoded = SignalService.Content.decode(plainText);
68+
69+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.deep.eq('Jane');
70+
expect(decoded.messageRequestResponse?.profile?.profilePicture).to.be.empty;
71+
expect(decoded.messageRequestResponse?.profileKey).to.be.empty;
72+
});
73+
74+
it('empty profileKey does not get included', () => {
75+
message = new MessageRequestResponse({
76+
timestamp: Date.now(),
77+
lokiProfile: { displayName: 'Jane', profileKey: new Uint8Array(0) },
78+
});
79+
const plainText = message.plainTextBuffer();
80+
const decoded = SignalService.Content.decode(plainText);
81+
82+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.eq('Jane');
83+
84+
expect(decoded.messageRequestResponse?.profile?.profilePicture).to.be.empty;
85+
expect(decoded.messageRequestResponse?.profileKey).to.be.empty;
86+
});
87+
88+
it('can create response with display name and profileKey and profileImage', () => {
89+
message = new MessageRequestResponse({
90+
timestamp: Date.now(),
91+
lokiProfile: {
92+
displayName: 'Jane',
93+
profileKey: new Uint8Array([1, 2, 3, 4, 5, 6]),
94+
avatarPointer: 'https://somevalidurl.com',
95+
},
96+
});
97+
const plainText = message.plainTextBuffer();
98+
const decoded = SignalService.Content.decode(plainText);
99+
100+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.deep.eq('Jane');
101+
102+
expect(decoded.messageRequestResponse?.profileKey).to.be.not.empty;
103+
104+
if (!decoded.messageRequestResponse?.profileKey?.buffer) {
105+
throw new Error('decoded.messageRequestResponse?.profileKey?.buffer should be set');
106+
}
107+
expect(decoded.messageRequestResponse?.profile?.profilePicture).to.be.eq(
108+
'https://somevalidurl.com'
109+
);
110+
// don't ask me why deep.eq ([1,2,3, ...]) gives nothing interesting but a 8192 buffer not matching
111+
expect(decoded.messageRequestResponse?.profileKey.length).to.be.eq(6);
112+
expect(decoded.messageRequestResponse?.profileKey[0]).to.be.eq(1);
113+
expect(decoded.messageRequestResponse?.profileKey[1]).to.be.eq(2);
114+
expect(decoded.messageRequestResponse?.profileKey[2]).to.be.eq(3);
115+
expect(decoded.messageRequestResponse?.profileKey[3]).to.be.eq(4);
116+
expect(decoded.messageRequestResponse?.profileKey[4]).to.be.eq(5);
117+
expect(decoded.messageRequestResponse?.profileKey[5]).to.be.eq(6);
118+
});
119+
120+
it('profileKey not included if profileUrl not set', () => {
121+
message = new MessageRequestResponse({
122+
timestamp: Date.now(),
123+
lokiProfile: { displayName: 'Jane', profileKey: new Uint8Array([1, 2, 3, 4, 5, 6]) },
124+
});
125+
const plainText = message.plainTextBuffer();
126+
const decoded = SignalService.Content.decode(plainText);
127+
128+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.deep.eq('Jane');
129+
130+
if (!decoded.messageRequestResponse?.profileKey?.buffer) {
131+
throw new Error('decoded.messageRequestResponse?.profileKey?.buffer should be set');
132+
}
133+
134+
expect(decoded.messageRequestResponse?.profile?.profilePicture).to.be.empty;
135+
expect(decoded.messageRequestResponse?.profileKey).to.be.empty;
136+
});
137+
138+
it('url not included if profileKey not set', () => {
139+
message = new MessageRequestResponse({
140+
timestamp: Date.now(),
141+
lokiProfile: {
142+
displayName: 'Jane',
143+
profileKey: null,
144+
avatarPointer: 'https://somevalidurl.com',
145+
},
146+
});
147+
const plainText = message.plainTextBuffer();
148+
const decoded = SignalService.Content.decode(plainText);
149+
150+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.deep.eq('Jane');
151+
152+
if (!decoded.messageRequestResponse?.profileKey?.buffer) {
153+
throw new Error('decoded.messageRequestResponse?.profileKey?.buffer should be set');
154+
}
155+
156+
expect(decoded.messageRequestResponse?.profile?.displayName).to.be.eq('Jane');
157+
expect(decoded.messageRequestResponse?.profile?.profilePicture).to.be.empty;
158+
expect(decoded.messageRequestResponse?.profileKey).to.be.empty;
159+
});
160+
});

0 commit comments

Comments
 (0)