Moved opengroupv1 test to opengroupv2 tests

pull/1671/head
Audric Ackermann 4 years ago
parent b15eeb00cd
commit 3456162402
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -11,7 +11,16 @@ module.exports = async function(context) {
return;
}
const isAppImage = context.targets.find(target => target.name === 'appImage');
console.log(
'targets',
context.targets.map(target => target.name)
);
console.log('AppImage', isAppImage.options);
if (!isAppImage) {
console.log('afterPack hook not triggered', context);
return;
}
// eslint-disable-next-line no-console

@ -100,19 +100,6 @@
window.log.info('Storage fetch');
storage.fetch();
let specialConvInited = false;
const initSpecialConversations = async () => {
if (specialConvInited) {
return;
}
const publicConversations = await window.Signal.Data.getAllOpenGroupV1Conversations();
publicConversations.forEach(conversation => {
// weird but create the object and does everything we need
conversation.getPublicSendData();
});
specialConvInited = true;
};
const initAPIs = () => {
if (window.initialisedAPI) {
return;
@ -743,7 +730,6 @@
window.NewReceiver.queueAllCached();
initAPIs();
await initSpecialConversations();
messageReceiver = new textsecure.MessageReceiver();
// those handleMessageEvent calls are only used by opengroupv1
messageReceiver.addEventListener('message', window.DataMessageReceiver.handleMessageEvent);

@ -2,7 +2,7 @@
"name": "session-desktop",
"productName": "Session",
"description": "Private messaging from your desktop",
"version": "1.6.4",
"version": "1.6.5",
"license": "GPL-3.0",
"author": {
"name": "Loki Project",
@ -14,7 +14,9 @@
},
"main": "main.js",
"scripts": {
"postinstall": "electron-builder install-app-deps && rimraf node_modules/dtrace-provider && husky install",
"prepare": "patch-package",
"postinstall": "yarn custom-react-mentions-build && electron-builder install-app-deps && rimraf node_modules/dtrace-provider && husky install",
"custom-react-mentions-build": "cd node_modules/react-mentions && yarn install --node_modules=../node_modules && yarn build && rimraf node_modules/react node_modules/react-dom && cd ..",
"start": "cross-env NODE_APP_INSTANCE=$MULTI electron .",
"start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .",
"start-swarm-test": "cross-env NODE_ENV=swarm-testing NODE_APP_INSTANCE=$MULTI electron .",
@ -33,7 +35,6 @@
"test-electron": "yarn grunt test",
"test-integration": "ELECTRON_DISABLE_SANDBOX=1 mocha --exit --full-trace --timeout 10000 ts/test/session/integration/integration_itest.js",
"test-node": "mocha --recursive --exit --timeout 10000 test/app test/modules \"./ts/test/**/*_test.js\" ",
"test-audric": "mocha --recursive --exit --timeout 500 test/app test/modules \"./ts/test/session/unit/onion/*.js\" ",
"eslint-full": "eslint . --cache",
"lint-full": "yarn format-full && yarn lint-files-full",
"lint-files-full": "yarn eslint-full && yarn tslint",
@ -41,7 +42,7 @@
"format-full": "prettier --list-different --write \"*.{css,js,json,scss,ts,tsx}\" \"./**/*.{css,js,json,scss,ts,tsx}\"",
"transpile": "tsc --incremental",
"transpile:watch": "tsc -w",
"clean-transpile": "rimraf ts/**/*.js ts/*.js ts/*.js.map ts/**/*.js.map && rimraf tsconfig.tsbuildinfo;",
"clean-transpile": "rimraf ts/**/*.js && rimraf ts/*.js && rimraf tsconfig.tsbuildinfo;",
"ready": "yarn clean-transpile; yarn grunt && yarn lint-full && yarn test"
},
"dependencies": {
@ -76,7 +77,7 @@
"jquery": "3.3.1",
"jsbn": "1.1.0",
"libsodium-wrappers": "^0.7.8",
"linkify-it": "3.0.2",
"linkify-it": "2.0.3",
"lodash": "4.17.11",
"long": "^4.0.0",
"mic-recorder-to-mp3": "^2.2.2",
@ -97,7 +98,7 @@
"react-emoji-render": "^1.2.4",
"react-h5-audio-player": "^3.2.0",
"react-intersection-observer": "^8.30.3",
"react-mentions": "^4.2.0",
"react-mentions": "https://github.com/Bilb/react-mentions",
"react-portal": "^4.2.0",
"react-qr-svg": "^2.2.1",
"react-redux": "7.2.1",
@ -125,7 +126,7 @@
"@types/blueimp-load-image": "^2.23.8",
"@types/buffer-crc32": "^0.2.0",
"@types/bytebuffer": "^5.0.41",
"@types/chai": "^4.2.18",
"@types/chai": "4.1.2",
"@types/chai-as-promised": "^7.1.2",
"@types/classnames": "2.2.3",
"@types/color": "^3.0.0",
@ -148,7 +149,7 @@
"@types/rc-slider": "^8.6.5",
"@types/react": "16.8.5",
"@types/react-dom": "16.8.2",
"@types/react-mentions": "^4.1.1",
"@types/react-mentions": "^3.3.1",
"@types/react-mic": "^12.4.1",
"@types/react-portal": "^4.0.2",
"@types/react-redux": "7.1.9",
@ -163,7 +164,7 @@
"arraybuffer-loader": "1.0.3",
"asar": "0.14.0",
"bower": "1.8.2",
"chai": "4.3.4",
"chai": "4.1.2",
"chai-as-promised": "^7.1.1",
"chai-bytes": "^0.1.2",
"css-loader": "^3.6.0",
@ -194,6 +195,7 @@
"node-gyp": "3.8.0",
"node-sass-import-once": "1.2.0",
"nyc": "11.4.1",
"patch-package": "^6.2.2",
"postinstall-prepare": "^1.0.1",
"prettier": "1.19.0",
"qs": "6.5.1",

@ -100,41 +100,22 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
private async submitForOpenGroup(pubkeys: Array<string>) {
const { convo } = this.props;
if (convo.isOpenGroupV1()) {
const v1 = convo.toOpenGroupV1();
const groupInvitation = {
serverAddress: v1.server,
serverName: convo.getName(),
channelId: 1, // always 1
};
pubkeys.forEach(async pubkeyStr => {
const privateConvo = await ConversationController.getInstance().getOrCreateAndWait(
pubkeyStr,
ConversationTypeEnum.PRIVATE
);
if (privateConvo) {
void privateConvo.sendMessage('', null, null, null, groupInvitation);
}
});
} else if (convo.isOpenGroupV2()) {
const v2 = convo.toOpenGroupV2();
const completeUrl = await getCompleteUrlForV2ConvoId(convo.id);
const groupInvitation = {
serverAddress: completeUrl,
serverName: convo.getName(),
};
pubkeys.forEach(async pubkeyStr => {
const privateConvo = await ConversationController.getInstance().getOrCreateAndWait(
pubkeyStr,
ConversationTypeEnum.PRIVATE
);
if (privateConvo) {
void privateConvo.sendMessage('', null, null, null, groupInvitation);
}
});
}
const completeUrl = await getCompleteUrlForV2ConvoId(convo.id);
const groupInvitation = {
serverAddress: completeUrl,
serverName: convo.getName(),
};
pubkeys.forEach(async pubkeyStr => {
const privateConvo = await ConversationController.getInstance().getOrCreateAndWait(
pubkeyStr,
ConversationTypeEnum.PRIVATE
);
if (privateConvo) {
void privateConvo.sendMessage('', null, null, null, groupInvitation);
}
});
}
private async submitForClosedGroup(pubkeys: Array<string>) {

@ -36,11 +36,7 @@ export class AddModeratorsDialog extends React.Component<Props, State> {
};
}
public async componentDidMount() {
if (this.props.convo.isOpenGroupV1()) {
this.channelAPI = await this.props.convo.getPublicSendData();
}
public componentDidMount() {
this.setState({ firstLoading: false });
}
@ -60,13 +56,11 @@ export class AddModeratorsDialog extends React.Component<Props, State> {
addingInProgress: true,
});
let isAdded: any;
if (this.props.convo.isOpenGroupV1()) {
isAdded = await this.channelAPI.serverAPI.addModerator([pubkey.key]);
} else {
// this is a v2 opengroup
const roomInfos = this.props.convo.toOpenGroupV2();
isAdded = await ApiV2.addModerator(pubkey, roomInfos);
}
// this is a v2 opengroup
const roomInfos = this.props.convo.toOpenGroupV2();
isAdded = await ApiV2.addModerator(pubkey, roomInfos);
if (!isAdded) {
window?.log?.warn('failed to add moderators:', isAdded);

@ -40,11 +40,7 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> {
};
}
public async componentDidMount() {
if (this.props.convo.isOpenGroupV1()) {
this.channelAPI = await this.props.convo.getPublicSendData();
}
public componentDidMount() {
void this.refreshModList();
}
@ -137,14 +133,10 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> {
});
}
private async refreshModList() {
private refreshModList() {
let modPubKeys: Array<string> = [];
if (this.props.convo.isOpenGroupV1()) {
// get current list of moderators
modPubKeys = (await this.channelAPI.getModerators()) as Array<string>;
} else if (this.props.convo.isOpenGroupV2()) {
modPubKeys = this.props.convo.getGroupAdmins() || [];
}
modPubKeys = this.props.convo.getGroupAdmins() || [];
const convos = ConversationController.getInstance().getConversations();
const moderatorsConvos = modPubKeys
.map(
@ -197,19 +189,16 @@ export class RemoveModeratorsDialog extends React.Component<Props, State> {
removingInProgress: true,
});
let res;
if (this.props.convo.isOpenGroupV1()) {
res = await this.channelAPI.serverAPI.removeModerators(removedMods);
} else if (this.props.convo.isOpenGroupV2()) {
const roomInfos = this.props.convo.toOpenGroupV2();
const modsToRemove = _.compact(removedMods.map(m => PubKey.from(m)));
res = await Promise.all(
modsToRemove.map(async m => {
return ApiV2.removeModerator(m, roomInfos);
})
);
// all moderators are removed means all promise resolved with bool= true
res = res.every(r => !!r);
}
const roomInfos = this.props.convo.toOpenGroupV2();
const modsToRemove = _.compact(removedMods.map(m => PubKey.from(m)));
res = await Promise.all(
modsToRemove.map(async m => {
return ApiV2.removeModerator(m, roomInfos);
})
);
// all moderators are removed means all promise resolved with bool= true
res = res.every(r => !!r);
if (!res) {
window?.log?.warn('failed to remove moderators:', res);

@ -53,6 +53,11 @@ export async function copyPublicKey(convoId: string) {
ToastUtils.pushCopiedToClipBoard();
}
/**
*
* @param messages the list of MessageModel to delete
* @param convo the conversation to delete from (only v2 opengroups are supported)
*/
export async function deleteOpenGroupMessages(
messages: Array<MessageModel>,
convo: ConversationModel
@ -99,42 +104,7 @@ export async function deleteOpenGroupMessages(
);
return [];
}
} else if (convo.isOpenGroupV1()) {
const channelAPI = await convo.getPublicSendData();
if (!channelAPI) {
throw new Error('Unable to get public channel API');
}
const invalidMessages = messages.filter(m => !m.attributes.serverId);
const pendingMessages = messages.filter(m => m.attributes.serverId);
let deletedServerIds = [];
let ignoredServerIds = [];
if (pendingMessages.length > 0) {
const result = await channelAPI.deleteMessages(
pendingMessages.map(m => m.attributes.serverId)
);
deletedServerIds = result.deletedIds;
ignoredServerIds = result.ignoredIds;
}
const toDeleteLocallyServerIds = _.union(deletedServerIds, ignoredServerIds);
let toDeleteLocally = messages.filter(m =>
toDeleteLocallyServerIds.includes(m.attributes.serverId)
);
toDeleteLocally = _.union(toDeleteLocally, invalidMessages);
await Promise.all(
toDeleteLocally.map(async m => {
await convo.removeMessage(m.id);
})
);
await convo.updateLastMessage();
return toDeleteLocally;
} else {
throw new Error('Opengroupv1 are not supported anymore');
}
return [];
}

@ -114,36 +114,17 @@ export async function removeSenderFromModerator(sender: string, convoId: string)
try {
const pubKeyToRemove = PubKey.cast(sender);
const convo = ConversationController.getInstance().getOrThrow(convoId);
if (convo.isOpenGroupV1()) {
const channelAPI = await convo.getPublicSendData();
if (!channelAPI) {
throw new Error('No channelAPI');
}
const res = await channelAPI.serverAPI.removeModerators([pubKeyToRemove.key]);
if (!res) {
window?.log?.warn('failed to remove moderators:', res);
ToastUtils.pushErrorHappenedWhileRemovingModerator();
} else {
// refresh the moderator list. Will trigger a refresh
const modPubKeys = await channelAPI.getModerators();
await convo.updateGroupAdmins(modPubKeys);
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators();
}
} else if (convo.isOpenGroupV2()) {
// FXIME audric removeModerator not working serverside
const roomInfo = convo.toOpenGroupV2();
const res = await ApiV2.removeModerator(pubKeyToRemove, roomInfo);
if (!res) {
window?.log?.warn('failed to remove moderator:', res);
// FXIME audric removeModerator not working serverside
const roomInfo = convo.toOpenGroupV2();
const res = await ApiV2.removeModerator(pubKeyToRemove, roomInfo);
if (!res) {
window?.log?.warn('failed to remove moderator:', res);
ToastUtils.pushErrorHappenedWhileRemovingModerator();
} else {
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators();
}
ToastUtils.pushErrorHappenedWhileRemovingModerator();
} else {
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserRemovedFromModerators();
}
} catch (e) {
window?.log?.error('Got error while removing moderator:', e);
@ -153,41 +134,18 @@ export async function removeSenderFromModerator(sender: string, convoId: string)
export async function addSenderAsModerator(sender: string, convoId: string) {
try {
const pubKeyToRemove = PubKey.cast(sender);
const convo = ConversationController.getInstance().getOrThrow(convoId);
if (convo.isOpenGroupV1()) {
const channelAPI = await convo.getPublicSendData();
if (!channelAPI) {
throw new Error('No channelAPI');
}
if (!channelAPI.serverAPI) {
throw new Error('No serverAPI');
}
const res = await channelAPI.serverAPI.addModerator([pubKeyToRemove.key]);
if (!res) {
window?.log?.warn('failed to add moderators:', res);
ToastUtils.pushUserNeedsToHaveJoined();
} else {
window?.log?.info(`${pubKeyToRemove.key} added as moderator...`);
// refresh the moderator list. Will trigger a refresh
const modPubKeys = await channelAPI.getModerators();
await convo.updateGroupAdmins(modPubKeys);
// FXIME audric addModerator not working serverside
const roomInfo = convo.toOpenGroupV2();
const res = await ApiV2.addModerator(pubKeyToRemove, roomInfo);
if (!res) {
window?.log?.warn('failed to add moderator:', res);
ToastUtils.pushUserAddedToModerators();
}
} else if (convo.isOpenGroupV2()) {
// FXIME audric addModerator not working serverside
const roomInfo = convo.toOpenGroupV2();
const res = await ApiV2.addModerator(pubKeyToRemove, roomInfo);
if (!res) {
window?.log?.warn('failed to add moderator:', res);
ToastUtils.pushUserNeedsToHaveJoined();
} else {
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserAddedToModerators();
}
ToastUtils.pushUserNeedsToHaveJoined();
} else {
window?.log?.info(`${pubKeyToRemove.key} removed from moderators...`);
ToastUtils.pushUserAddedToModerators();
}
} catch (e) {
window?.log?.error('Got error while adding moderator:', e);

@ -27,7 +27,6 @@ import {
ConversationType as ReduxConversationType,
LastMessageStatusType,
} from '../state/ducks/conversations';
import { OpenGroupMessage } from '../session/messages/outgoing';
import { ExpirationTimerUpdateMessage } from '../session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage';
import { TypingMessage } from '../session/messages/outgoing/controlMessage/TypingMessage';
import {
@ -203,9 +202,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
public isOpenGroupV2(): boolean {
return OpenGroupUtils.isOpenGroupV2(this.id);
}
public isOpenGroupV1(): boolean {
return OpenGroupUtils.isOpenGroupV1(this.id);
}
public isClosedGroup() {
return this.get('type') === ConversationTypeEnum.GROUP && !this.isPublic();
}
@ -587,17 +583,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return getOpenGroupV2FromConversationId(this.id);
}
public toOpenGroupV1(): OpenGroup {
if (!this.isOpenGroupV1()) {
throw new Error('tried to run toOpenGroup for not public group v1');
}
return new OpenGroup({
server: this.get('server'),
channel: this.get('channelId'),
conversationId: this.id,
});
}
public async sendMessageJob(message: MessageModel, expireTimer: number | undefined) {
try {
const uploads = await message.uploadData();
@ -611,22 +596,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
if (this.isPublic() && !this.isOpenGroupV2()) {
const openGroup = this.toOpenGroupV1();
const openGroupParams = {
body: uploads.body,
timestamp: sentAt,
group: openGroup,
attachments: uploads.attachments,
preview: uploads.preview,
quote: uploads.quote,
identifier: id,
};
const openGroupMessage = new OpenGroupMessage(openGroupParams);
// we need the return await so that errors are caught in the catch {}
await getMessageQueue().sendToOpenGroup(openGroupMessage);
return;
throw new Error('Only opengroupv2 are supported now');
}
// an OpenGroupV2 message is just a visible message
const chatMessageParams: VisibleMessageParams = {

@ -6,7 +6,7 @@ import { SignalService } from '../../ts/protobuf';
import { getMessageQueue, Utils } from '../../ts/session';
import { ConversationController } from '../../ts/session/conversations';
import { MessageController } from '../../ts/session/messages';
import { DataMessage, OpenGroupMessage } from '../../ts/session/messages/outgoing';
import { DataMessage } from '../../ts/session/messages/outgoing';
import { ClosedGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage';
import { PubKey } from '../../ts/session/types';
import { UserUtils } from '../../ts/session/utils';
@ -31,6 +31,9 @@ import {
uploadQuoteThumbnailsV2,
} from '../session/utils/AttachmentsV2';
import { acceptOpenGroupInvitation } from '../interactions/message';
import { OpenGroupMessageV2 } from '../opengroup/opengroupV2/OpenGroupMessageV2';
import { OpenGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
import { getV2OpenGroupRoom } from '../data/opengroups';
export class MessageModel extends Backbone.Model<MessageAttributes> {
public propsForTimerNotification: any;
public propsForGroupNotification: any;
@ -771,17 +774,9 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
} else {
// NOTE: we want to go for the v1 if this is an OpenGroupV1 or not an open group at all
// because there is a fallback invoked on uploadV1() for attachments for not open groups attachments
const openGroupV1 = conversation?.isOpenGroupV1() ? conversation?.toOpenGroupV1() : undefined;
attachmentPromise = AttachmentFsV2Utils.uploadAttachmentsToFsV2(
filenameOverridenAttachments,
openGroupV1
);
linkPreviewPromise = AttachmentFsV2Utils.uploadLinkPreviewsToFsV2(
previewWithData,
openGroupV1
);
quotePromise = AttachmentFsV2Utils.uploadQuoteThumbnailsToFsV2(quoteWithData, openGroupV1);
attachmentPromise = AttachmentFsV2Utils.uploadAttachmentsToFsV2(filenameOverridenAttachments);
linkPreviewPromise = AttachmentFsV2Utils.uploadLinkPreviewsToFsV2(previewWithData);
quotePromise = AttachmentFsV2Utils.uploadQuoteThumbnailsToFsV2(quoteWithData);
}
const [attachments, preview, quote] = await Promise.all([
@ -817,21 +812,24 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
}
if (conversation.isPublic()) {
const openGroup = {
server: conversation.get('server'),
channel: conversation.get('channelId'),
conversationId: conversation.id,
};
if (!conversation.isOpenGroupV2()) {
throw new Error('Only opengroupv2 are supported now');
}
const uploaded = await this.uploadData();
const openGroupParams = {
identifier: this.id,
timestamp: Date.now(),
group: openGroup,
lokiProfile: UserUtils.getOurProfile(),
...uploaded,
};
const openGroupMessage = new OpenGroupMessage(openGroupParams);
return getMessageQueue().sendToOpenGroup(openGroupMessage);
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (!roomInfos) {
throw new Error('Could not find roomInfos for this conversation');
}
const openGroupMessage = new OpenGroupVisibleMessage(openGroupParams);
return getMessageQueue().sendToOpenGroupV2(openGroupMessage, roomInfos);
}
const { body, attachments, preview, quote } = await this.uploadData();

@ -49,27 +49,27 @@ export const parseMessages = async (
const messages = await Promise.all(
rawMessages.map(async r => {
try {
const opengroupMessage = OpenGroupMessageV2.fromJson(r);
const opengroupv2Message = OpenGroupMessageV2.fromJson(r);
if (
!opengroupMessage?.serverId ||
!opengroupMessage.sentTimestamp ||
!opengroupMessage.base64EncodedData ||
!opengroupMessage.base64EncodedSignature
!opengroupv2Message?.serverId ||
!opengroupv2Message.sentTimestamp ||
!opengroupv2Message.base64EncodedData ||
!opengroupv2Message.base64EncodedSignature
) {
window?.log?.warn('invalid open group message received');
return null;
}
// Validate the message signature
const senderPubKey = PubKey.cast(opengroupMessage.sender).withoutPrefix();
const signature = fromBase64ToArrayBuffer(opengroupMessage.base64EncodedSignature);
const messageData = fromBase64ToArrayBuffer(opengroupMessage.base64EncodedData);
const senderPubKey = PubKey.cast(opengroupv2Message.sender).withoutPrefix();
const signature = fromBase64ToArrayBuffer(opengroupv2Message.base64EncodedSignature);
const messageData = fromBase64ToArrayBuffer(opengroupv2Message.base64EncodedData);
// throws if signature failed
await window.libsignal.Curve.async.verifySignature(
fromHex(senderPubKey),
messageData,
signature
);
return opengroupMessage;
return opengroupv2Message;
} catch (e) {
window?.log?.error('An error happened while fetching getMessages output:', e);
return null;

@ -20,6 +20,9 @@ import { isOpenGroupV2Request } from '../../fileserver/FileServerApiV2';
import { getAuthToken } from './ApiAuth';
import pRetry from 'p-retry';
// used to be overwritten by testing
export const getMinTimeout = () => 1000;
/**
* This function returns a base url to this room
* This is basically used for building url after posting an attachment
@ -171,7 +174,7 @@ export async function openGroupV2GetRoomInfo({
isAuthRequired: false,
endpoint: `rooms/${roomId}`,
};
const result = (await sendApiV2Request(request)) as any;
const result = (await exports.sendApiV2Request(request)) as any;
if (result?.result?.room) {
const { id, name, image_id: imageId } = result?.result?.room;
@ -194,10 +197,9 @@ export async function openGroupV2GetRoomInfo({
/**
* Send the specified message to the specified room.
* If an error happens, this function throws it
*
* Exported only for testing
*/
const postMessageRetryable = async (
export const postMessageRetryable = async (
message: OpenGroupMessageV2,
room: OpenGroupRequestCommonType
) => {
@ -213,7 +215,7 @@ const postMessageRetryable = async (
endpoint: 'messages',
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
@ -234,12 +236,12 @@ export const postMessage = async (
) => {
const result = await pRetry(
async () => {
return postMessageRetryable(message, room);
return exports.postMessageRetryable(message, room);
},
{
retries: 3, // each path can fail 3 times before being dropped, we have 3 paths at most
factor: 2,
minTimeout: 1000,
minTimeout: exports.getMinTimeout(),
maxTimeout: 4000,
onFailedAttempt: e => {
window?.log?.warn(
@ -265,7 +267,7 @@ export const banUser = async (
queryParams,
endpoint: 'block_list',
};
const banResult = await sendApiV2Request(request);
const banResult = await exports.sendApiV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(banResult) === 200;
return isOk;
};
@ -281,7 +283,7 @@ export const unbanUser = async (
isAuthRequired: true,
endpoint: `block_list/${userToBan.key}`,
};
const unbanResult = await sendApiV2Request(request);
const unbanResult = await exports.sendApiV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(unbanResult) === 200;
return isOk;
};
@ -298,7 +300,7 @@ export const deleteMessageByServerIds = async (
endpoint: 'delete_messages',
queryParams: { ids: idsToRemove },
};
const messageDeletedResult = await sendApiV2Request(request);
const messageDeletedResult = await exports.sendApiV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(messageDeletedResult) === 200;
return isOk;
};
@ -313,7 +315,7 @@ export const getAllRoomInfos = async (roomInfos: OpenGroupV2Room) => {
endpoint: 'rooms',
serverPublicKey: roomInfos.serverPublicKey,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
@ -334,7 +336,7 @@ export const getMemberCount = async (
isAuthRequired: true,
endpoint: 'member_count',
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
if (parseStatusCodeFromOnionRequest(result) !== 200) {
window?.log?.warn('getMemberCount failed invalid status code');
return;
@ -368,7 +370,7 @@ export const downloadFileOpenGroupV2 = async (
endpoint: `files/${fileId}`,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
return null;
@ -395,7 +397,7 @@ export const downloadFileOpenGroupV2ByUrl = async (
endpoint: pathName,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
return null;
@ -427,7 +429,7 @@ export const downloadPreviewOpenGroupV2 = async (
serverPublicKey: roomInfos.serverPublicKey,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
return null;
@ -466,7 +468,7 @@ export const uploadFileOpenGroupV2 = async (
queryParams,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
return null;
@ -506,7 +508,7 @@ export const uploadImageForRoomOpenGroupV2 = async (
queryParams,
};
const result = await sendApiV2Request(request);
const result = await exports.sendApiV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
return null;
@ -531,7 +533,7 @@ export const addModerator = async (
queryParams: { public_key: userToAddAsMods.key, room_id: roomInfos.roomId },
endpoint: 'moderators',
};
const addModResult = await sendApiV2Request(request);
const addModResult = await exports.sendApiV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(addModResult) === 200;
return isOk;
};
@ -547,7 +549,7 @@ export const removeModerator = async (
isAuthRequired: true,
endpoint: `moderators/${userToAddAsMods.key}`,
};
const removeModResult = await sendApiV2Request(request);
const removeModResult = await exports.sendApiV2Request(request);
const isOk = parseStatusCodeFromOnionRequest(removeModResult) === 200;
return isOk;
};

@ -44,13 +44,6 @@ export const openGroupPrefix = 'publicChat:';
*/
export const openGroupPrefixRegex = new RegExp(`^${openGroupPrefix}`);
/**
* An open group v1 conversation id can only have the char '1' as roomId
*/
export const openGroupV1ConversationIdRegex = new RegExp(
`${openGroupPrefix}1@${protocolRegex.source}${hostnameRegex.source}`
);
export const openGroupV2ConversationIdRegex = new RegExp(
`${openGroupPrefix}${roomIdV2Regex}@${protocolRegex.source}${hostnameRegex.source}${portRegex}`
);
@ -190,16 +183,6 @@ export function getOpenGroupV2FromConversationId(
throw new Error('Not a v2 open group convo id');
}
/**
* Check if this conversation id corresponds to an OpenGroupV1 conversation.
* No access to database are made. Only regex matches
* @param conversationId the convo id to evaluate
* @returns true if this conversation id matches the Opengroupv1 conversation id regex
*/
export function isOpenGroupV1(conversationId: string) {
return openGroupV1ConversationIdRegex.test(conversationId);
}
/**
* Check if this conversation id corresponds to an OpenGroupV2 conversation.
* No access to database are made. Only regex matches
@ -207,10 +190,5 @@ export function isOpenGroupV1(conversationId: string) {
* @returns true if this conversation id matches the Opengroupv2 conversation id regex
*/
export function isOpenGroupV2(conversationId: string) {
if (openGroupV1ConversationIdRegex.test(conversationId)) {
// this is an open group v1
return false;
}
return openGroupV2ConversationIdRegex.test(conversationId);
}

@ -93,8 +93,8 @@ export async function initiateGroupUpdate(
);
if (convo.isPublic()) {
if (convo.isOpenGroupV1()) {
await updateOpenGroupV1(convo, groupName, avatar);
if (!convo.isOpenGroupV2()) {
throw new Error('Only opengroupv2 are supported');
} else {
await updateOpenGroupV2(convo, groupName, avatar);
}

@ -1,39 +0,0 @@
import { Message, MessageParams } from './Message';
import { OpenGroup } from '../../../opengroup/opengroupV1/OpenGroup';
import { AttachmentPointer, Preview, Quote } from './visibleMessage/VisibleMessage';
interface OpenGroupMessageParams extends MessageParams {
group: OpenGroup;
attachments?: Array<AttachmentPointer>;
preview?: Array<Preview>;
body?: string;
quote?: Quote;
}
/**
* This class is only used for OpenGroup v1 (deprecated)
*/
export class OpenGroupMessage extends Message {
public readonly group: OpenGroup;
public readonly body?: string;
public readonly attachments: Array<AttachmentPointer>;
public readonly quote?: Quote;
public readonly preview?: Array<Preview>;
constructor({
timestamp,
group,
attachments,
body,
quote,
identifier,
preview,
}: OpenGroupMessageParams) {
super({ timestamp, identifier });
this.group = group;
this.body = body;
this.attachments = attachments ?? [];
this.quote = quote;
this.preview = preview ?? [];
}
}

@ -1,7 +1,6 @@
import { Message } from './Message';
import { OpenGroupMessage } from './OpenGroupMessage';
export * from './ContentMessage';
export * from './DataMessage';
export { Message, OpenGroupMessage };
export { Message };

@ -8,7 +8,7 @@ import { ClosedGroupNameChangeMessage } from '../messages/outgoing/controlMessag
import { ClosedGroupMemberLeftMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupMemberLeftMessage';
import { MessageSentHandler } from './MessageSentHandler';
import { ContentMessage, OpenGroupMessage } from '../messages/outgoing';
import { ContentMessage } from '../messages/outgoing';
import { ExpirationTimerUpdateMessage } from '../messages/outgoing/controlMessage/ExpirationTimerUpdateMessage';
import { ClosedGroupAddedMembersMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupAddedMembersMessage';
import { ClosedGroupEncryptionPairMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupEncryptionPairMessage';
@ -53,35 +53,6 @@ export class MessageQueue {
await this.process(user, message, sentCb);
}
/**
* DEPRECATED This function is synced. It will wait for the message to be delivered to the open
* group to return.
* So there is no need for a sendCb callback
*
*/
public async sendToOpenGroup(message: OpenGroupMessage) {
// Open groups
if (!(message instanceof OpenGroupMessage)) {
throw new Error('sendToOpenGroup can only be used with OpenGroupMessage');
}
// No queue needed for Open Groups; send directly
const error = new Error('Failed to send message to open group.');
// This is absolutely yucky ... we need to make it not use Promise<boolean>
try {
const result = await MessageSender.sendToOpenGroup(message);
// sendToOpenGroup returns -1 if failed or an id if succeeded
if (result.serverId < 0) {
void MessageSentHandler.handleMessageSentFailure(message, error);
} else {
void MessageSentHandler.handlePublicMessageSentSuccess(message, result);
}
} catch (e) {
window?.log?.warn(`Failed to send message to open group: ${message.group.server}`, e);
void MessageSentHandler.handleMessageSentFailure(message, error);
}
}
/**
* This function is synced. It will wait for the message to be delivered to the open
* group to return.
@ -97,7 +68,7 @@ export class MessageQueue {
try {
const { sentTimestamp, serverId } = await MessageSender.sendToOpenGroupV2(message, roomInfos);
if (!serverId) {
if (!serverId || serverId === -1) {
throw new Error(`Invalid serverId returned by server: ${serverId}`);
}
void MessageSentHandler.handlePublicMessageSentSuccess(message, {

@ -1,7 +1,6 @@
// REMOVE COMMENT AFTER: This can just export pure functions as it doesn't need state
import { RawMessage } from '../types/RawMessage';
import { OpenGroupMessage } from '../messages/outgoing';
import { SignalService } from '../../protobuf';
import { MessageEncrypter } from '../crypto';
import pRetry from 'p-retry';
@ -92,44 +91,8 @@ function wrapEnvelope(envelope: SignalService.Envelope): Uint8Array {
}
// ================ Open Group ================
/**
* Deprecated Send a message to an open group v2.
* @param message The open group message.
*/
export async function sendToOpenGroup(
message: OpenGroupMessage
): Promise<{ serverId: number; serverTimestamp: number }> {
/*
Note: Retrying wasn't added to this but it can be added in the future if needed.
The only problem is that `channelAPI.sendMessage` returns true/false and doesn't throw any error so we can never be sure why sending failed.
This should be fixed and we shouldn't rely on returning true/false, rather return nothing (success) or throw an error (failure)
*/
const { group, quote, attachments, preview, body, timestamp } = message;
const channelAPI = await window.lokiPublicChatAPI.findOrCreateChannel(
group.server,
group.channel,
group.conversationId
);
if (!channelAPI) {
return { serverId: -1, serverTimestamp: -1 };
}
// Returns -1 on fail or an id > 0 on success
return channelAPI.sendMessage(
{
quote,
attachments: attachments || [],
preview: preview || [],
body,
},
timestamp
);
}
/**
* Deprecated Send a message to an open group v2.
* Send a message to an open group v2.
* @param message The open group message.
*/
export async function sendToOpenGroupV2(

@ -2,7 +2,6 @@ import _ from 'lodash';
import { getMessageById } from '../../data/data';
import { SignalService } from '../../protobuf';
import { MessageController } from '../messages';
import { OpenGroupMessage } from '../messages/outgoing';
import { OpenGroupVisibleMessage } from '../messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
import { EncryptionType, RawMessage } from '../types';
import { UserUtils } from '../utils';
@ -10,7 +9,7 @@ import { UserUtils } from '../utils';
// tslint:disable-next-line no-unnecessary-class
export class MessageSentHandler {
public static async handlePublicMessageSentSuccess(
sentMessage: OpenGroupMessage | OpenGroupVisibleMessage,
sentMessage: OpenGroupVisibleMessage,
result: { serverId: number; serverTimestamp: number }
) {
const { serverId, serverTimestamp } = result;
@ -44,7 +43,7 @@ export class MessageSentHandler {
sentMessage: RawMessage,
wrappedEnvelope?: Uint8Array
) {
// The wrappedEnvelope will be set only if the message is not one of OpenGroupMessage type.
// The wrappedEnvelope will be set only if the message is not one of OpenGroupV2Message type.
const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData(sentMessage);
if (!fetchedMessage) {
return;
@ -131,7 +130,7 @@ export class MessageSentHandler {
}
public static async handleMessageSentFailure(
sentMessage: RawMessage | OpenGroupMessage | OpenGroupVisibleMessage,
sentMessage: RawMessage | OpenGroupVisibleMessage,
error: any
) {
const fetchedMessage = await MessageSentHandler.fetchHandleMessageSentData(sentMessage);
@ -143,10 +142,7 @@ export class MessageSentHandler {
await fetchedMessage.saveErrors(error);
}
if (
!(sentMessage instanceof OpenGroupMessage) &&
!(sentMessage instanceof OpenGroupVisibleMessage)
) {
if (!(sentMessage instanceof OpenGroupVisibleMessage)) {
const isOurDevice = UserUtils.isUsFromCache(sentMessage.device);
// if this message was for ourself, and it was not already synced,
// it means that we failed to sync it.
@ -179,9 +175,7 @@ export class MessageSentHandler {
* In this case, this function will look for it in the database and return it.
* If the message is found on the db, it will also register it to the MessageController so our subsequent calls are quicker.
*/
private static async fetchHandleMessageSentData(
m: RawMessage | OpenGroupMessage | OpenGroupVisibleMessage
) {
private static async fetchHandleMessageSentData(m: RawMessage | OpenGroupVisibleMessage) {
// if a message was sent and this message was sent after the last app restart,
// this message is still in memory in the MessageController
const msg = MessageController.getInstance().get(m.identifier);

@ -7,13 +7,11 @@ import {
Quote,
QuotedAttachment,
} from '../messages/outgoing/visibleMessage/VisibleMessage';
import { OpenGroup } from '../../opengroup/opengroupV1/OpenGroup';
import { FSv2 } from '../../fileserver';
import { addAttachmentPadding } from '../crypto/BufferPadding';
interface UploadParams {
attachment: Attachment;
openGroup?: OpenGroup;
isAvatar?: boolean;
isRaw?: boolean;
shouldPad?: boolean;
@ -43,7 +41,7 @@ export class AttachmentFsV2Utils {
private constructor() {}
public static async uploadToFsV2(params: UploadParams): Promise<AttachmentPointer> {
const { attachment, openGroup, isRaw = false, shouldPad = false } = params;
const { attachment, isRaw = false, shouldPad = false } = params;
if (typeof attachment !== 'object' || attachment == null) {
throw new Error('Invalid attachment passed.');
}
@ -53,10 +51,6 @@ export class AttachmentFsV2Utils {
`\`attachment.data\` must be an \`ArrayBuffer\`; got: ${typeof attachment.data}`
);
}
// this can only be an opengroupv1
if (openGroup) {
throw new Error('opengroupv1 attachments are not supported anymore');
}
const pointer: AttachmentPointer = {
contentType: attachment.contentType || undefined,
size: attachment.size,
@ -67,8 +61,7 @@ export class AttachmentFsV2Utils {
let attachmentData: ArrayBuffer;
// We don't pad attachments for opengroup as they are unencrypted
if (isRaw || openGroup) {
if (isRaw) {
attachmentData = attachment.data;
} else {
pointer.key = new Uint8Array(crypto.randomBytes(64));
@ -103,13 +96,11 @@ export class AttachmentFsV2Utils {
}
public static async uploadAttachmentsToFsV2(
attachments: Array<Attachment>,
openGroup?: OpenGroup
attachments: Array<Attachment>
): Promise<Array<AttachmentPointer>> {
const promises = (attachments || []).map(async attachment =>
this.uploadToFsV2({
attachment,
openGroup,
shouldPad: true,
})
);
@ -118,8 +109,7 @@ export class AttachmentFsV2Utils {
}
public static async uploadLinkPreviewsToFsV2(
previews: Array<RawPreview>,
openGroup?: OpenGroup
previews: Array<RawPreview>
): Promise<Array<Preview>> {
const promises = (previews || []).map(async item => {
// some links does not have an image associated, and it makes the whole message fail to send
@ -130,17 +120,13 @@ export class AttachmentFsV2Utils {
...item,
image: await this.uploadToFsV2({
attachment: item.image,
openGroup,
}),
};
});
return Promise.all(promises);
}
public static async uploadQuoteThumbnailsToFsV2(
quote?: RawQuote,
openGroup?: OpenGroup
): Promise<Quote | undefined> {
public static async uploadQuoteThumbnailsToFsV2(quote?: RawQuote): Promise<Quote | undefined> {
if (!quote) {
return undefined;
}
@ -150,7 +136,6 @@ export class AttachmentFsV2Utils {
if (attachment.thumbnail) {
thumbnail = await this.uploadToFsV2({
attachment: attachment.thumbnail,
openGroup,
});
}
return {

@ -178,11 +178,6 @@ export const getCurrentConfigurationMessage = async (convos: Array<ConversationM
const ourPubKey = UserUtils.getOurPubKeyStrFromCache();
const ourConvo = convos.find(convo => convo.id === ourPubKey);
// Filter open groups v1
const openGroupsV1Ids = convos
.filter(c => !!c.get('active_at') && c.isOpenGroupV1() && !c.get('left'))
.map(c => c.id.substring((c.id as string).lastIndexOf('@') + 1)) as Array<string>;
const opengroupV2CompleteUrls = await getActiveOpenGroupV2CompleteUrls(convos);
const onlyValidClosedGroup = await getValidClosedGroups(convos);
const validContacts = getValidContacts(convos);
@ -196,7 +191,7 @@ export const getCurrentConfigurationMessage = async (convos: Array<ConversationM
const profilePicture = ourConvo?.get('avatarPointer') || undefined;
const displayName = ourConvo?.getLokiProfile()?.displayName || undefined;
const activeOpenGroups = [...openGroupsV1Ids, ...opengroupV2CompleteUrls];
const activeOpenGroups = [...opengroupV2CompleteUrls];
return new ConfigurationMessage({
identifier: uuid(),

@ -1,89 +0,0 @@
import { expect } from 'chai';
import { OpenGroupMessage } from '../../../../session/messages/outgoing';
import * as MIME from '../../../../../ts/types/MIME';
import { AttachmentPointer } from '../../../../session/messages/outgoing/visibleMessage/VisibleMessage';
import { OpenGroup } from '../../../../opengroup/opengroupV1/OpenGroup';
describe('OpenGroupMessage', () => {
const group = new OpenGroup({
server: 'chat.example.server',
channel: 1,
conversationId: '0',
});
it('can create empty message with just a timestamp and group', () => {
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
});
expect(message?.timestamp).to.be.approximately(Date.now(), 10);
expect(message?.group).to.deep.equal(group);
expect(message?.body).to.be.equal(undefined, 'body should be undefined');
expect(message?.quote).to.be.equal(undefined, 'quote should be undefined');
expect(message?.attachments).to.have.lengthOf(0);
expect(message?.preview).to.have.lengthOf(0);
});
it('can create message with a body', () => {
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
body: 'body',
});
expect(message).to.have.deep.property('body', 'body');
});
it('can create message with a quote', () => {
const attachment = {
contentType: MIME.IMAGE_JPEG,
fileName: 'fileName',
isVoiceMessage: false,
};
const quote = {
id: 0,
author: 'me',
text: 'hi',
attachments: [attachment],
};
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
quote,
});
expect(message?.quote).to.deep.equal(quote);
});
it('can create message with an attachment', () => {
const attachment: AttachmentPointer = {
id: 0,
contentType: 'type',
key: new Uint8Array(1),
size: 10,
thumbnail: new Uint8Array(2),
digest: new Uint8Array(3),
fileName: 'filename',
flags: 0,
width: 10,
height: 20,
caption: 'caption',
url: 'url',
};
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
attachments: [attachment],
});
expect(message?.attachments).to.have.lengthOf(1);
expect(message?.attachments[0]).to.deep.equal(attachment);
});
it('has an identifier', () => {
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
});
expect(message.identifier).to.not.equal(null, 'identifier cannot be null');
expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined');
});
});

@ -8,7 +8,7 @@ import { describe } from 'mocha';
import { GroupUtils, PromiseUtils, UserUtils } from '../../../../session/utils';
import { TestUtils } from '../../../../test/test-utils';
import { MessageQueue } from '../../../../session/sending/MessageQueue';
import { ContentMessage, OpenGroupMessage } from '../../../../session/messages/outgoing';
import { ContentMessage } from '../../../../session/messages/outgoing';
import { PubKey, RawMessage } from '../../../../session/types';
import { MessageSender } from '../../../../session/sending';
import { PendingMessageCacheStub } from '../../../test-utils/stubs';
@ -202,31 +202,31 @@ describe('MessageQueue', () => {
);
});
describe('open groups', () => {
let sendToOpenGroupStub: sinon.SinonStub<
[OpenGroupMessage],
Promise<{ serverId: number; serverTimestamp: number }>
>;
describe('open groupsv2', () => {
let sendToOpenGroupV2Stub: sinon.SinonStub;
beforeEach(() => {
sendToOpenGroupStub = sandbox
.stub(MessageSender, 'sendToOpenGroup')
.resolves({ serverId: -1, serverTimestamp: -1 });
sendToOpenGroupV2Stub = sandbox
.stub(MessageSender, 'sendToOpenGroupV2')
.resolves(TestUtils.generateOpenGroupMessageV2());
});
it('can send to open group', async () => {
const message = TestUtils.generateOpenGroupMessage();
await messageQueueStub.sendToOpenGroup(message);
expect(sendToOpenGroupStub.callCount).to.equal(1);
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
await messageQueueStub.sendToOpenGroupV2(message, roomInfos);
expect(sendToOpenGroupV2Stub.callCount).to.equal(1);
});
it('should emit a success event when send was successful', async () => {
sendToOpenGroupStub.resolves({
sendToOpenGroupV2Stub.resolves({
serverId: 5125,
serverTimestamp: 5126,
sentTimestamp: 5126,
});
const message = TestUtils.generateOpenGroupMessage();
await messageQueueStub.sendToOpenGroup(message);
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
await messageQueueStub.sendToOpenGroupV2(message, roomInfos);
expect(messageSentPublicHandlerSuccessStub.callCount).to.equal(1);
expect(messageSentPublicHandlerSuccessStub.lastCall.args[0].identifier).to.equal(
message.identifier
@ -238,10 +238,11 @@ describe('MessageQueue', () => {
});
it('should emit a fail event if something went wrong', async () => {
sendToOpenGroupStub.resolves({ serverId: -1, serverTimestamp: -1 });
const message = TestUtils.generateOpenGroupMessage();
sendToOpenGroupV2Stub.resolves({ serverId: -1, serverTimestamp: -1 });
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
await messageQueueStub.sendToOpenGroup(message);
await messageQueueStub.sendToOpenGroupV2(message, roomInfos);
expect(messageSentHandlerFailedStub.callCount).to.equal(1);
expect(messageSentHandlerFailedStub.lastCall.args[0].identifier).to.equal(
message.identifier

@ -6,10 +6,10 @@ import { LokiMessageApi, MessageSender } from '../../../../session/sending';
import { TestUtils } from '../../../test-utils';
import { MessageEncrypter } from '../../../../session/crypto';
import { SignalService } from '../../../../protobuf';
import { OpenGroupMessage } from '../../../../session/messages/outgoing';
import { EncryptionType } from '../../../../session/types/EncryptionType';
import { PubKey } from '../../../../session/types';
import { UserUtils } from '../../../../session/utils';
import { ApiV2 } from '../../../../opengroup/opengroupV2';
describe('MessageSender', () => {
const sandbox = sinon.createSandbox();
@ -185,34 +185,56 @@ describe('MessageSender', () => {
});
});
describe('sendToOpenGroup', () => {
it('should send the message to the correct server and channel', async () => {
// We can do this because LokiPublicChatFactoryAPI has a module export in it
const stub = sandbox.stub().resolves({
sendMessage: sandbox.stub(),
});
describe('sendToOpenGroupV2', () => {
const sandbox2 = sinon.createSandbox();
let postMessageRetryableStub: sinon.SinonStub;
beforeEach(() => {
sandbox
.stub(UserUtils, 'getOurPubKeyStrFromCache')
.resolves(TestUtils.generateFakePubKey().key);
TestUtils.stubWindow('lokiPublicChatAPI', {
findOrCreateChannel: stub,
});
postMessageRetryableStub = sandbox
.stub(ApiV2, 'postMessageRetryable')
.resolves(TestUtils.generateOpenGroupMessageV2());
});
const group = {
server: 'server',
channel: 1,
conversationId: '0',
};
afterEach(() => {
sandbox2.restore();
});
const message = new OpenGroupMessage({
timestamp: Date.now(),
group,
});
it('should call postMessageRetryableStub', async () => {
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
await MessageSender.sendToOpenGroupV2(message, roomInfos);
expect(postMessageRetryableStub.callCount).to.eq(1);
});
await MessageSender.sendToOpenGroup(message);
it('should retry postMessageRetryableStub ', async () => {
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
postMessageRetryableStub.throws('whate');
sandbox2.stub(ApiV2, 'getMinTimeout').returns(2);
postMessageRetryableStub.onThirdCall().resolves();
await MessageSender.sendToOpenGroupV2(message, roomInfos);
expect(postMessageRetryableStub.callCount).to.eq(3);
});
const [server, channel, conversationId] = stub.getCall(0).args;
expect(server).to.equal(group.server);
expect(channel).to.equal(group.channel);
expect(conversationId).to.equal(group.conversationId);
it('should not retry more than 3 postMessageRetryableStub ', async () => {
const message = TestUtils.generateOpenGroupVisibleMessage();
const roomInfos = TestUtils.generateOpenGroupV2RoomInfos();
sandbox2.stub(ApiV2, 'getMinTimeout').returns(2);
postMessageRetryableStub.throws('fake error');
postMessageRetryableStub.onCall(4).resolves();
try {
await MessageSender.sendToOpenGroupV2(message, roomInfos);
throw new Error('Error expected');
} catch (e) {
expect(e.name).to.eq('fake error');
}
expect(postMessageRetryableStub.calledThrice);
});
});
});

@ -2,10 +2,12 @@ import { v4 as uuid } from 'uuid';
import { generateFakePubKey, generateFakePubKeys } from './pubkey';
import { ClosedGroupVisibleMessage } from '../../../session/messages/outgoing/visibleMessage/ClosedGroupVisibleMessage';
import { ConversationAttributes, ConversationTypeEnum } from '../../../models/conversation';
import { OpenGroupMessage } from '../../../session/messages/outgoing';
import { VisibleMessage } from '../../../session/messages/outgoing/visibleMessage/VisibleMessage';
import { OpenGroup } from '../../../opengroup/opengroupV1/OpenGroup';
import { openGroupPrefixRegex } from '../../../opengroup/utils/OpenGroupUtils';
import { OpenGroupMessageV2 } from '../../../opengroup/opengroupV2/OpenGroupMessageV2';
import { TestUtils } from '..';
import { OpenGroupRequestCommonType } from '../../../opengroup/opengroupV2/ApiUtil';
import { OpenGroupVisibleMessage } from '../../../session/messages/outgoing/visibleMessage/OpenGroupVisibleMessage';
export function generateVisibleMessage(identifier?: string): VisibleMessage {
return new VisibleMessage({
@ -20,23 +22,24 @@ export function generateVisibleMessage(identifier?: string): VisibleMessage {
});
}
export function generateOpenGroupMessage(): OpenGroupMessage {
const group = new OpenGroup({
server: 'chat.example.server',
channel: 0,
conversationId: '0',
export function generateOpenGroupMessageV2(): OpenGroupMessageV2 {
return new OpenGroupMessageV2({
sentTimestamp: Date.now(),
sender: TestUtils.generateFakePubKey().key,
base64EncodedData: 'whatever',
});
}
return new OpenGroupMessage({
export function generateOpenGroupVisibleMessage(): OpenGroupVisibleMessage {
return new OpenGroupVisibleMessage({
timestamp: Date.now(),
group,
attachments: undefined,
preview: undefined,
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
quote: undefined,
});
}
export function generateOpenGroupV2RoomInfos(): OpenGroupRequestCommonType {
return { roomId: 'main', serverUrl: 'http://116.203.70.33' };
}
export function generateClosedGroupMessage(groupId?: string): ClosedGroupVisibleMessage {
return new ClosedGroupVisibleMessage({
identifier: uuid(),

Loading…
Cancel
Save