chore: commit before merge unstable

pull/3052/head
Audric Ackermann 10 months ago committed by Audric Ackermann
parent 4d7a0e7a04
commit 74aa448631
No known key found for this signature in database

@ -578,6 +578,8 @@
"respondingToGroupRequestWarning": "Sending a message to this group will automatically accept the group invite.", "respondingToGroupRequestWarning": "Sending a message to this group will automatically accept the group invite.",
"userInvitedYouToGroup": "<b>$name$</b> invited you to join <b>$groupName$</b>.", "userInvitedYouToGroup": "<b>$name$</b> invited you to join <b>$groupName$</b>.",
"youWereInvitedToGroup": "<b>You</b> were invited to join <b>$groupName$</b>.", "youWereInvitedToGroup": "<b>You</b> were invited to join <b>$groupName$</b>.",
"userInvitedYouToGroupAsAdmin": "<b>$name$</b> invited you to join <b>$groupName$</b>, where you are an Admin.",
"youWereInvitedToGroupAsAdmin": "<b>You</b> were invited to join <b>$groupName$</b>, where you are an Admin.",
"hideRequestBanner": "Hide Message Request Banner", "hideRequestBanner": "Hide Message Request Banner",
"openMessageRequestInbox": "Message Requests", "openMessageRequestInbox": "Message Requests",
"noMessageRequestsPending": "No pending message requests", "noMessageRequestsPending": "No pending message requests",

@ -95,7 +95,7 @@
"fs-extra": "9.0.0", "fs-extra": "9.0.0",
"glob": "10.3.10", "glob": "10.3.10",
"image-type": "^4.1.0", "image-type": "^4.1.0",
"libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.19/libsession_util_nodejs-v0.3.19.tar.gz", "libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.21/libsession_util_nodejs-v0.3.21.tar.gz",
"libsodium-wrappers-sumo": "^0.7.9", "libsodium-wrappers-sumo": "^0.7.9",
"linkify-it": "^4.0.1", "linkify-it": "^4.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",

@ -6,6 +6,7 @@ import { blobToArrayBuffer } from 'blob-util';
import loadImage from 'blueimp-load-image'; import loadImage from 'blueimp-load-image';
import classNames from 'classnames'; import classNames from 'classnames';
import styled from 'styled-components'; import styled from 'styled-components';
import { useDispatch } from 'react-redux';
import { import {
CompositionBox, CompositionBox,
SendMessageType, SendMessageType,
@ -60,7 +61,6 @@ import { SessionSpinner } from '../basic/SessionSpinner';
import { ConversationMessageRequestButtons } from './MessageRequestButtons'; import { ConversationMessageRequestButtons } from './MessageRequestButtons';
import { RightPanel, StyledRightPanelContainer } from './right-panel/RightPanel'; import { RightPanel, StyledRightPanelContainer } from './right-panel/RightPanel';
import { showLinkVisitWarningDialog } from '../dialog/SessionConfirm'; import { showLinkVisitWarningDialog } from '../dialog/SessionConfirm';
import { useDispatch } from 'react-redux';
const DEFAULT_JPEG_QUALITY = 0.85; const DEFAULT_JPEG_QUALITY = 0.85;
interface State { interface State {

@ -25,6 +25,7 @@ import {
useLibGroupInviteGroupName, useLibGroupInviteGroupName,
useLibGroupInvitePending, useLibGroupInvitePending,
useLibGroupKicked, useLibGroupKicked,
useLibGroupWeHaveSecretKey,
} from '../../state/selectors/userGroups'; } from '../../state/selectors/userGroups';
import { LocalizerKeys } from '../../types/LocalizerKeys'; import { LocalizerKeys } from '../../types/LocalizerKeys';
import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer'; import { SessionHtmlRenderer } from '../basic/SessionHTMLRenderer';
@ -119,6 +120,8 @@ export const InvitedToGroupControlMessage = () => {
const adminNameInvitedUs = const adminNameInvitedUs =
useNicknameOrProfileNameOrShortenedPubkey(conversationOrigin) || window.i18n('unknown'); useNicknameOrProfileNameOrShortenedPubkey(conversationOrigin) || window.i18n('unknown');
const isGroupPendingInvite = useLibGroupInvitePending(selectedConversation); const isGroupPendingInvite = useLibGroupInvitePending(selectedConversation);
const weHaveSecretKey = useLibGroupWeHaveSecretKey(selectedConversation);
if ( if (
!selectedConversation || !selectedConversation ||
isApproved || isApproved ||
@ -131,7 +134,11 @@ export const InvitedToGroupControlMessage = () => {
} }
// when restoring from seed we might not have the pubkey of who invited us, in that case, we just use a fallback // when restoring from seed we might not have the pubkey of who invited us, in that case, we just use a fallback
const html = conversationOrigin const html = conversationOrigin
? window.i18n('userInvitedYouToGroup', [adminNameInvitedUs, groupName]) ? weHaveSecretKey
? window.i18n('userInvitedYouToGroupAsAdmin', [adminNameInvitedUs, groupName])
: window.i18n('userInvitedYouToGroup', [adminNameInvitedUs, groupName])
: weHaveSecretKey
? window.i18n('youWereInvitedToGroupAsAdmin', [groupName])
: window.i18n('youWereInvitedToGroup', [groupName]); : window.i18n('youWereInvitedToGroup', [groupName]);
return ( return (

@ -517,7 +517,7 @@ class CompositionBoxInner extends React.Component<Props, State> {
data-testid="message-input-text-area" data-testid="message-input-text-area"
style={style} style={style}
suggestionsPortalHost={this.container as any} suggestionsPortalHost={this.container as any}
forceSuggestionsAboveCursor={true} // force mentions to be rendered on top of the cursor, this is working with a fork of react-mentions for now forceSuggestionsAboveCursor={true}
> >
<Mention <Mention
appendSpaceOnAdd={true} appendSpaceOnAdd={true}

@ -32,6 +32,7 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S
import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionSpinner } from '../basic/SessionSpinner';
import { SessionToggle } from '../basic/SessionToggle'; import { SessionToggle } from '../basic/SessionToggle';
import { GroupInviteRequiredVersionBanner } from '../NoticeBanner'; import { GroupInviteRequiredVersionBanner } from '../NoticeBanner';
import { isDevProd } from '../../shared/env_vars';
type Props = { type Props = {
conversationId: string; conversationId: string;
@ -190,7 +191,9 @@ const InviteContactsDialogInner = (props: Props) => {
{hasContacts && isGroupV2 && <GroupInviteRequiredVersionBanner />} {hasContacts && isGroupV2 && <GroupInviteRequiredVersionBanner />}
<SpacerLG /> <SpacerLG />
{isGroupV2 && (
{/* TODO: localize those strings once out releasing those buttons for real */}
{isGroupV2 && isDevProd() && (
<> <>
<span style={{ display: 'flex', alignItems: 'center' }}> <span style={{ display: 'flex', alignItems: 'center' }}>
Share History?{' '} Share History?{' '}

@ -219,17 +219,11 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
); );
}; };
export const showLinkVisitWarningDialog = (urlToOpen: string, dispatch: Dispatch<any>) => { export const showLinkVisitWarningDialog = (urlToOpen: string, dispatch: Dispatch<any>) => {
function onClickOk() { function onClickOk() {
void shell.openExternal(urlToOpen); void shell.openExternal(urlToOpen);
} }
dispatch( dispatch(
updateConfirmModal({ updateConfirmModal({
title: window.i18n('linkVisitWarningTitle'), title: window.i18n('linkVisitWarningTitle'),

@ -1,3 +1,4 @@
/* eslint-disable no-await-in-loop */
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';

@ -5,6 +5,7 @@ import useKey from 'react-use/lib/useKey';
import styled from 'styled-components'; import styled from 'styled-components';
import { concat } from 'lodash'; import { concat } from 'lodash';
import useUpdate from 'react-use/lib/useUpdate';
import { MemberListItem } from '../../MemberListItem'; import { MemberListItem } from '../../MemberListItem';
import { SessionButton } from '../../basic/SessionButton'; import { SessionButton } from '../../basic/SessionButton';
import { SessionIdEditable } from '../../basic/SessionIdEditable'; import { SessionIdEditable } from '../../basic/SessionIdEditable';
@ -24,6 +25,8 @@ import { useOurPkStr } from '../../../state/selectors/user';
import { SessionSearchInput } from '../../SessionSearchInput'; import { SessionSearchInput } from '../../SessionSearchInput';
import { SpacerLG } from '../../basic/Text'; import { SpacerLG } from '../../basic/Text';
import { GroupInviteRequiredVersionBanner } from '../../NoticeBanner'; import { GroupInviteRequiredVersionBanner } from '../../NoticeBanner';
import { isDevProd } from '../../../shared/env_vars';
import { SessionToggle } from '../../basic/SessionToggle';
const StyledMemberListNoContacts = styled.div` const StyledMemberListNoContacts = styled.div`
font-family: var(--font-mono), var(--font-default); font-family: var(--font-mono), var(--font-default);
@ -100,6 +103,7 @@ export const OverlayClosedGroupV2 = () => {
const privateContactsPubkeys = useContactsToInviteToGroup(); const privateContactsPubkeys = useContactsToInviteToGroup();
const isCreatingGroup = useIsCreatingGroupFromUIPending(); const isCreatingGroup = useIsCreatingGroupFromUIPending();
const [groupName, setGroupName] = useState(''); const [groupName, setGroupName] = useState('');
const forceUpdate = useUpdate();
const { const {
uniqueValues: members, uniqueValues: members,
addTo: addToSelected, addTo: addToSelected,
@ -177,6 +181,22 @@ export const OverlayClosedGroupV2 = () => {
/> />
</div> </div>
<SessionSpinner loading={isCreatingGroup} /> <SessionSpinner loading={isCreatingGroup} />
{/* TODO: localize those strings once out releasing those buttons for real */}
{isDevProd() && (
<>
<span style={{ display: 'flex', alignItems: 'center' }}>
Invite as admin?{' '}
<SessionToggle
active={window.sessionFeatureFlags.useGroupV2InviteAsAdmin}
onClick={() => {
window.sessionFeatureFlags.useGroupV2InviteAsAdmin =
!window.sessionFeatureFlags.useGroupV2InviteAsAdmin;
forceUpdate();
}}
/>
</span>
</>
)}
<SpacerLG /> <SpacerLG />
<SessionSearchInput /> <SessionSearchInput />
{!noContactsForClosedGroup && window.sessionFeatureFlags.useClosedGroupV2 && ( {!noContactsForClosedGroup && window.sessionFeatureFlags.useClosedGroupV2 && (

@ -1,6 +1,7 @@
import { GroupPubkeyType, PubkeyType, WithGroupPubkey } from 'libsession_util_nodejs'; import { GroupPubkeyType, PubkeyType, WithGroupPubkey } from 'libsession_util_nodejs';
import { compact, isEmpty, isFinite, isNumber } from 'lodash'; import { compact, isEmpty, isFinite, isNumber } from 'lodash';
import { Data } from '../../data/data'; import { Data } from '../../data/data';
import { deleteAllMessagesByConvoIdNoConfirmation } from '../../interactions/conversationInteractions';
import { deleteMessagesFromSwarmOnly } from '../../interactions/conversations/unsendingInteractions'; import { deleteMessagesFromSwarmOnly } from '../../interactions/conversations/unsendingInteractions';
import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { HexString } from '../../node/hexStrings'; import { HexString } from '../../node/hexStrings';
@ -14,6 +15,7 @@ import { WithDisappearingMessageUpdate } from '../../session/disappearing_messag
import { ClosedGroup } from '../../session/group/closed-group'; import { ClosedGroup } from '../../session/group/closed-group';
import { GroupUpdateInviteResponseMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage'; import { GroupUpdateInviteResponseMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { WithMessageHash } from '../../session/types/with';
import { UserUtils } from '../../session/utils'; import { UserUtils } from '../../session/utils';
import { sleepFor } from '../../session/utils/Promise'; import { sleepFor } from '../../session/utils/Promise';
import { ed25519Str, stringToUint8Array } from '../../session/utils/String'; import { ed25519Str, stringToUint8Array } from '../../session/utils/String';
@ -29,8 +31,6 @@ import {
MetaGroupWrapperActions, MetaGroupWrapperActions,
UserGroupsWrapperActions, UserGroupsWrapperActions,
} from '../../webworker/workers/browser/libsession_worker_interface'; } from '../../webworker/workers/browser/libsession_worker_interface';
import { WithMessageHash } from '../../session/types/with';
import { deleteAllMessagesByConvoIdNoConfirmation } from '../../interactions/conversationInteractions';
type WithSignatureTimestamp = { signatureTimestamp: number }; type WithSignatureTimestamp = { signatureTimestamp: number };
type WithAuthor = { author: PubkeyType }; type WithAuthor = { author: PubkeyType };
@ -503,41 +503,109 @@ async function handleGroupUpdateInviteResponseMessage({
async function handleGroupUpdatePromoteMessage({ async function handleGroupUpdatePromoteMessage({
change, change,
author,
signatureTimestamp,
}: Omit<GroupUpdateGeneric<SignalService.GroupUpdatePromoteMessage>, 'groupPk'>) { }: Omit<GroupUpdateGeneric<SignalService.GroupUpdatePromoteMessage>, 'groupPk'>) {
const seed = change.groupIdentitySeed; const seed = change.groupIdentitySeed;
const sodium = await getSodiumRenderer(); const sodium = await getSodiumRenderer();
const groupKeypair = sodium.crypto_sign_seed_keypair(seed); const groupKeypair = sodium.crypto_sign_seed_keypair(seed);
const groupPk = `03${HexString.toHexString(groupKeypair.publicKey)}` as GroupPubkeyType; const groupPk = `03${HexString.toHexString(groupKeypair.publicKey)}` as GroupPubkeyType;
// we can be invited via a GroupUpdatePromoteMessage as an admin right away,
// so we potentially need to deal with part of the invite process here too.
const convo = ConvoHub.use().get(groupPk); if (BlockedNumberController.isBlocked(author)) {
if (!convo) { window.log.info(
`received promote to group ${ed25519Str(groupPk)} by blocked user:${ed25519Str(
author
)}... dropping it`
);
return; return;
} }
window.log.info(`handleGroupUpdatePromoteMessage for ${ed25519Str(groupPk)}`);
// no group update message here, another message is sent to the group's swarm for the update message.
// this message is just about the keys that we need to save, and accepting the promotion.
const found = await UserGroupsWrapperActions.getGroup(groupPk); const authorIsApproved = ConvoHub.use().get(author)?.isApproved() || false;
if (!found) {
// could have been removed by the user already so let's not force create it
window.log.info( window.log.info(
'received group promote message but that group is not in the usergroups wrapper' `received promote to group ${ed25519Str(groupPk)} by author:${ed25519Str(author)}. authorIsApproved:${authorIsApproved} `
); );
return;
const convo = await ConvoHub.use().getOrCreateAndWait(groupPk, ConversationTypeEnum.GROUPV2);
convo.set({
active_at: signatureTimestamp,
didApproveMe: true,
conversationIdOrigin: author,
});
if (change.name && isEmpty(convo.getRealSessionUsername())) {
convo.set({
displayNameInProfile: change.name,
});
} }
const userEd25519Secretkey = (await UserUtils.getUserED25519KeyPairBytes()).privKeyBytes;
let found = await UserGroupsWrapperActions.getGroup(groupPk);
const wasKicked = found?.kicked || false;
if (!found) {
found = {
authData: null,
joinedAtSeconds: Date.now(),
name: change.name,
priority: 0,
pubkeyHex: groupPk,
secretKey: groupKeypair.privateKey,
kicked: false,
invitePending: true,
};
} else {
found.kicked = false;
found.name = change.name;
found.secretKey = groupKeypair.privateKey; found.secretKey = groupKeypair.privateKey;
}
if (authorIsApproved) {
// pre approve invite to groups when we've already approved the person who invited us
found.invitePending = false;
}
await UserGroupsWrapperActions.setGroup(found); await UserGroupsWrapperActions.setGroup(found);
await UserSync.queueNewJobIfNeeded(); // force markedAsUnread to be true so it shows the unread banner (we only show the banner if there are unread messages on at least one msg/group request)
await convo.markAsUnread(true, false);
await convo.commit();
window.inboxStore.dispatch( await SessionUtilConvoInfoVolatile.insertConvoFromDBIntoWrapperAndRefresh(convo.id);
groupInfoActions.markUsAsAdmin({
groupPk, if (wasKicked) {
secret: groupKeypair.privateKey, // we have been reinvited to a group which we had been kicked from.
}) // Let's empty the conversation again to remove any "you were removed from the group" control message
await deleteAllMessagesByConvoIdNoConfirmation(groupPk);
}
try {
await MetaGroupWrapperActions.init(groupPk, {
metaDumped: null,
groupEd25519Secretkey: groupKeypair.privateKey,
userEd25519Secretkey: toFixedUint8ArrayOfLength(userEd25519Secretkey, 64).buffer,
groupEd25519Pubkey: toFixedUint8ArrayOfLength(HexString.fromHexStringNoPrefix(groupPk), 32)
.buffer,
});
} catch (e) {
window.log.warn(
`handleGroupUpdatePromoteMessage: init of ${ed25519Str(groupPk)} failed with ${e.message}. Trying to just load admin keys`
); );
try {
await MetaGroupWrapperActions.loadAdminKeys(groupPk, groupKeypair.privateKey);
} catch (e2) {
window.log.warn(
`handleGroupUpdatePromoteMessage: loadAdminKeys of ${ed25519Str(groupPk)} failed with ${e.message}`
);
}
}
await LibSessionUtil.saveDumpsToDb(UserUtils.getOurPubKeyStrFromCache());
await UserSync.queueNewJobIfNeeded();
if (!found.invitePending) {
// This group should already be polling based on if that author is pre-approved or we've already approved that group from another device.
// Start polling from it, we will mark ourselves as admin once we get the first merge result, if needed.
getSwarmPollingInstance().addGroupId(groupPk);
}
} }
async function handle1o1GroupUpdateMessage( async function handle1o1GroupUpdateMessage(

@ -61,12 +61,12 @@ async function getGroupPromoteMessage({
member, member,
secretKey, secretKey,
groupPk, groupPk,
name, groupName,
}: { }: {
member: PubkeyType; member: PubkeyType;
secretKey: Uint8ArrayLen64; // len 64 secretKey: Uint8ArrayLen64; // len 64
groupPk: GroupPubkeyType; groupPk: GroupPubkeyType;
name: string; groupName: string;
}) { }) {
const createAtNetworkTimestamp = GetNetworkTime.now(); const createAtNetworkTimestamp = GetNetworkTime.now();
@ -80,7 +80,7 @@ async function getGroupPromoteMessage({
groupIdentitySeed: secretKey.slice(0, 32), // the seed is the first 32 bytes of the secretkey groupIdentitySeed: secretKey.slice(0, 32), // the seed is the first 32 bytes of the secretkey
expirationType: 'unknown', // a promote message is not expiring expirationType: 'unknown', // a promote message is not expiring
expireTimer: 0, expireTimer: 0,
name, groupName,
}); });
return msg; return msg;
} }

@ -15,6 +15,8 @@ import { SnodeNamespaces } from '../namespaces';
import { RetrieveMessageItemWithNamespace } from '../types'; import { RetrieveMessageItemWithNamespace } from '../types';
import { ConvoHub } from '../../../conversations'; import { ConvoHub } from '../../../conversations';
import { ProfileManager } from '../../../profile_manager/ProfileManager'; import { ProfileManager } from '../../../profile_manager/ProfileManager';
import { UserUtils } from '../../../utils';
import { GroupSync } from '../../../utils/job_runners/jobs/GroupSyncJob';
/** /**
* This is a basic optimization to avoid running the logic when the `deleteBeforeSeconds` * This is a basic optimization to avoid running the logic when the `deleteBeforeSeconds`
@ -36,7 +38,6 @@ async function handleMetaMergeResults(groupPk: GroupPubkeyType) {
to_hex(dumps) to_hex(dumps)
); );
} }
if (infos) {
if (infos.isDestroyed) { if (infos.isDestroyed) {
window.log.info(`${ed25519Str(groupPk)} is marked as destroyed after merge. Removing it.`); window.log.info(`${ed25519Str(groupPk)} is marked as destroyed after merge. Removing it.`);
await ConvoHub.use().deleteGroup(groupPk, { await ConvoHub.use().deleteGroup(groupPk, {
@ -103,7 +104,39 @@ async function handleMetaMergeResults(groupPk: GroupPubkeyType) {
await GroupPendingRemovals.addJob({ groupPk }); await GroupPendingRemovals.addJob({ groupPk });
} }
} }
const us = UserUtils.getOurPubKeyStrFromCache();
const usMember = await MetaGroupWrapperActions.memberGet(groupPk, us);
let keysAlreadyHaveAdmin = await MetaGroupWrapperActions.keysAdmin(groupPk);
const secretKeyInUserWrapper = (await UserGroupsWrapperActions.getGroup(groupPk))?.secretKey;
// load admin keys if needed
if (
usMember &&
secretKeyInUserWrapper &&
!isEmpty(secretKeyInUserWrapper) &&
!keysAlreadyHaveAdmin
) {
try {
await MetaGroupWrapperActions.loadAdminKeys(groupPk, secretKeyInUserWrapper);
keysAlreadyHaveAdmin = await MetaGroupWrapperActions.keysAdmin(groupPk);
} catch (e) {
window.log.warn(
`tried to update our adminKeys/state for group ${ed25519Str(groupPk)} but failed with, ${e.message}`
);
}
} }
// mark ourselves as accepting the invite if needed
if (usMember?.invitePending && keysAlreadyHaveAdmin) {
await MetaGroupWrapperActions.memberSetAccepted(groupPk, us);
}
// mark ourselves as accepting the promotion if needed
if (usMember?.promotionPending && keysAlreadyHaveAdmin) {
await MetaGroupWrapperActions.memberSetPromotionAccepted(groupPk, us);
}
// this won't do anything if there is no need for a sync, so we can safely plan one
await GroupSync.queueNewJobIfNeeded(groupPk);
const convo = ConvoHub.use().get(groupPk); const convo = ConvoHub.use().get(groupPk);
const refreshedInfos = await MetaGroupWrapperActions.infoGet(groupPk); const refreshedInfos = await MetaGroupWrapperActions.infoGet(groupPk);

@ -319,7 +319,7 @@ class ConvoController {
const us = UserUtils.getOurPubKeyStrFromCache(); const us = UserUtils.getOurPubKeyStrFromCache();
const allMembers = await MetaGroupWrapperActions.memberGetAll(groupPk); const allMembers = await MetaGroupWrapperActions.memberGetAll(groupPk);
const otherAdminsCount = allMembers const otherAdminsCount = allMembers
.filter(m => m.admin || m.promoted) .filter(m => m.promoted)
.filter(m => m.pubkeyHex !== us).length; .filter(m => m.pubkeyHex !== us).length;
const weAreLastAdmin = otherAdminsCount === 0; const weAreLastAdmin = otherAdminsCount === 0;
const infos = await MetaGroupWrapperActions.infoGet(groupPk); const infos = await MetaGroupWrapperActions.infoGet(groupPk);

@ -5,7 +5,7 @@ import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMess
interface Params extends GroupUpdateMessageParams { interface Params extends GroupUpdateMessageParams {
groupPk: GroupPubkeyType; groupPk: GroupPubkeyType;
groupIdentitySeed: Uint8Array; groupIdentitySeed: Uint8Array;
name: string; groupName: string;
} }
/** /**
@ -13,17 +13,17 @@ interface Params extends GroupUpdateMessageParams {
*/ */
export class GroupUpdatePromoteMessage extends GroupUpdateMessage { export class GroupUpdatePromoteMessage extends GroupUpdateMessage {
public readonly groupIdentitySeed: Params['groupIdentitySeed']; public readonly groupIdentitySeed: Params['groupIdentitySeed'];
public readonly name: Params['name']; public readonly groupName: Params['groupName'];
constructor(params: Params) { constructor(params: Params) {
super(params); super(params);
this.groupIdentitySeed = params.groupIdentitySeed; this.groupIdentitySeed = params.groupIdentitySeed;
this.name = params.name; this.groupName = params.groupName;
if (!this.groupIdentitySeed || this.groupIdentitySeed.length !== 32) { if (!this.groupIdentitySeed || this.groupIdentitySeed.length !== 32) {
throw new Error('groupIdentitySeed must be set'); throw new Error('groupIdentitySeed must be set');
} }
if (!this.name) { if (!this.groupName) {
throw new Error('name must be set and not empty'); throw new Error('name must be set and not empty');
} }
} }
@ -31,7 +31,7 @@ export class GroupUpdatePromoteMessage extends GroupUpdateMessage {
public dataProto(): SignalService.DataMessage { public dataProto(): SignalService.DataMessage {
const promoteMessage = new SignalService.GroupUpdatePromoteMessage({ const promoteMessage = new SignalService.GroupUpdatePromoteMessage({
groupIdentitySeed: this.groupIdentitySeed, groupIdentitySeed: this.groupIdentitySeed,
name: this.name, name: this.groupName,
}); });
return new SignalService.DataMessage({ return new SignalService.DataMessage({

@ -17,7 +17,6 @@ import {
FinalRelayOptions, FinalRelayOptions,
Onions, Onions,
STATUS_NO_STATUS, STATUS_NO_STATUS,
SnodeResponse,
buildErrorMessageWithFailedCode, buildErrorMessageWithFailedCode,
} from '../apis/snode_api/onions'; } from '../apis/snode_api/onions';
import { PROTOCOLS } from '../constants'; import { PROTOCOLS } from '../constants';
@ -75,12 +74,6 @@ const getOnionPathForSending = async () => {
return pathNodes; return pathNodes;
}; };
export type OnionSnodeResponse = {
result: SnodeResponse;
txtResponse: string;
response: string;
};
export type OnionV4SnodeResponse = { export type OnionV4SnodeResponse = {
body: string | object | null; // if the content can be decoded as string body: string | object | null; // if the content can be decoded as string
bodyBinary: Uint8Array | null; // otherwise we return the raw content (could be an image data or file from sogs/fileserver) bodyBinary: Uint8Array | null; // otherwise we return the raw content (could be an image data or file from sogs/fileserver)

@ -153,7 +153,14 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
} }
let failed = true; let failed = true;
try { try {
const inviteDetails = await SnodeGroupSignature.getGroupInviteMessage({ const inviteDetails = window.sessionFeatureFlags.useGroupV2InviteAsAdmin
? await SnodeGroupSignature.getGroupPromoteMessage({
groupName: group.name,
member,
secretKey: group.secretKey,
groupPk,
})
: await SnodeGroupSignature.getGroupInviteMessage({
groupName: group.name, groupName: group.name,
member, member,
secretKey: group.secretKey, secretKey: group.secretKey,

@ -134,7 +134,7 @@ class GroupPendingRemovalsJob extends PersistedJob<GroupPendingRemovalsPersisted
return RunJobResult.Success; return RunJobResult.Success;
} }
const deleteMessagesOfMembers = pendingRemovals const deleteMessagesOfMembers = pendingRemovals
.filter(m => m.removedStatus === 2) .filter(m => m.shouldRemoveMessages)
.map(m => m.pubkeyHex); .map(m => m.pubkeyHex);
const sessionIdsHex = pendingRemovals.map(m => m.pubkeyHex); const sessionIdsHex = pendingRemovals.map(m => m.pubkeyHex);

@ -102,7 +102,7 @@ class GroupPromoteJob extends PersistedJob<GroupPromotePersistedData> {
member, member,
secretKey: group.secretKey, secretKey: group.secretKey,
groupPk, groupPk,
name: group.name, groupName: group.name,
}); });
const storedAt = await getMessageQueue().sendTo1o1NonDurably({ const storedAt = await getMessageQueue().sendTo1o1NonDurably({
@ -118,7 +118,11 @@ class GroupPromoteJob extends PersistedJob<GroupPromotePersistedData> {
groupInfoActions.setPromotionPending({ groupPk, pubkey: member, sending: false }) groupInfoActions.setPromotionPending({ groupPk, pubkey: member, sending: false })
); );
try { try {
await MetaGroupWrapperActions.memberSetPromoted(groupPk, member, failed); if (failed) {
await MetaGroupWrapperActions.memberSetPromotionFailed(groupPk, member);
} else {
await MetaGroupWrapperActions.memberSetPromotionSent(groupPk, member);
}
} catch (e) { } catch (e) {
window.log.warn('GroupPromoteJob memberSetPromoted failed with', e.message); window.log.warn('GroupPromoteJob memberSetPromoted failed with', e.message);
} }

@ -410,7 +410,7 @@ async function createMemberAndSetDetails({
await MetaGroupWrapperActions.memberConstructAndSet(groupPk, memberPubkey); await MetaGroupWrapperActions.memberConstructAndSet(groupPk, memberPubkey);
if (displayName) { if (displayName) {
await MetaGroupWrapperActions.memberSetName(groupPk, memberPubkey, displayName); await MetaGroupWrapperActions.memberSetNameTruncated(groupPk, memberPubkey, displayName);
} }
if (profileKeyHex && avatarUrl) { if (profileKeyHex && avatarUrl) {
await MetaGroupWrapperActions.memberSetProfilePicture(groupPk, memberPubkey, { await MetaGroupWrapperActions.memberSetProfilePicture(groupPk, memberPubkey, {

@ -156,6 +156,8 @@ const initNewGroupInWrapper = createAsyncThunk(
const profileKeyHex = convoMember?.getProfileKey() || null; const profileKeyHex = convoMember?.getProfileKey() || null;
const avatarUrl = convoMember?.getAvatarPointer() || null; const avatarUrl = convoMember?.getAvatarPointer() || null;
// we just create the members in the state. Their invite state defaults to NOT_SENT,
// which will make our logic kick in to send them an invite in the `GroupInviteJob`
await LibSessionUtil.createMemberAndSetDetails({ await LibSessionUtil.createMemberAndSetDetails({
avatarUrl, avatarUrl,
displayName, displayName,
@ -165,9 +167,8 @@ const initNewGroupInWrapper = createAsyncThunk(
}); });
if (member === us) { if (member === us) {
await MetaGroupWrapperActions.memberSetAdmin(groupPk, member); // we need to excplicitely mark us as having accepted the promotion
} else { await MetaGroupWrapperActions.memberSetPromotionAccepted(groupPk, member);
await MetaGroupWrapperActions.memberSetInvited(groupPk, member, false);
} }
} }
@ -1122,48 +1123,6 @@ const handleMemberLeftMessage = createAsyncThunk(
} }
); );
const markUsAsAdmin = createAsyncThunk(
'group/markUsAsAdmin',
async (
{
groupPk,
secret,
}: {
groupPk: GroupPubkeyType;
secret: Uint8ArrayLen64;
},
payloadCreator
): Promise<GroupDetailsUpdate> => {
const state = payloadCreator.getState() as StateType;
if (!state.groups.infos[groupPk] || !state.groups.members[groupPk]) {
throw new PreConditionFailed('markUsAsAdmin group not present in redux slice');
}
if (secret.length !== 64) {
throw new PreConditionFailed('markUsAsAdmin secret needs to be 64');
}
await MetaGroupWrapperActions.loadAdminKeys(groupPk, secret);
const us = UserUtils.getOurPubKeyStrFromCache();
if (state.groups.members[groupPk].find(m => m.pubkeyHex === us)?.admin) {
// we are already an admin, nothing to do
return {
groupPk,
infos: await MetaGroupWrapperActions.infoGet(groupPk),
members: await MetaGroupWrapperActions.memberGetAll(groupPk),
};
}
await MetaGroupWrapperActions.memberSetAdmin(groupPk, us);
await GroupSync.queueNewJobIfNeeded(groupPk);
return {
groupPk,
infos: await MetaGroupWrapperActions.infoGet(groupPk),
members: await MetaGroupWrapperActions.memberGetAll(groupPk),
};
}
);
const inviteResponseReceived = createAsyncThunk( const inviteResponseReceived = createAsyncThunk(
'group/inviteResponseReceived', 'group/inviteResponseReceived',
async ( async (
@ -1443,21 +1402,6 @@ const metaGroupSlice = createSlice({
window.log.error('a handleMemberLeftMessage was rejected', action.error); window.log.error('a handleMemberLeftMessage was rejected', action.error);
}); });
/** markUsAsAdmin */
builder.addCase(markUsAsAdmin.fulfilled, (state, action) => {
const { infos, members, groupPk } = action.payload;
state.infos[groupPk] = infos;
state.members[groupPk] = members;
refreshConvosModelProps([groupPk]);
if (window.sessionFeatureFlags.debug.debugLibsessionDumps) {
window.log.info(`groupInfo after markUsAsAdmin: ${stringify(infos)}`);
window.log.info(`groupMembers after markUsAsAdmin: ${stringify(members)}`);
}
});
builder.addCase(markUsAsAdmin.rejected, (_state, action) => {
window.log.error('a markUsAsAdmin was rejected', action.error);
});
builder.addCase(inviteResponseReceived.fulfilled, (state, action) => { builder.addCase(inviteResponseReceived.fulfilled, (state, action) => {
const { infos, members, groupPk } = action.payload; const { infos, members, groupPk } = action.payload;
state.infos[groupPk] = infos; state.infos[groupPk] = infos;
@ -1488,7 +1432,6 @@ export const groupInfoActions = {
refreshGroupDetailsFromWrapper, refreshGroupDetailsFromWrapper,
handleUserGroupUpdate, handleUserGroupUpdate,
currentDeviceGroupMembersChange, currentDeviceGroupMembersChange,
markUsAsAdmin,
inviteResponseReceived, inviteResponseReceived,
handleMemberLeftMessage, handleMemberLeftMessage,
currentDeviceGroupNameChange, currentDeviceGroupNameChange,

@ -1,4 +1,5 @@
/* eslint-disable no-restricted-syntax */ /* eslint-disable no-restricted-syntax */
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { filter, isEmpty, isFinite, isNumber, pick, sortBy, toNumber } from 'lodash'; import { filter, isEmpty, isFinite, isNumber, pick, sortBy, toNumber } from 'lodash';

@ -1,4 +1,5 @@
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { isEmpty } from 'lodash';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { UserGroupState } from '../ducks/userGroups'; import { UserGroupState } from '../ducks/userGroups';
import { StateType } from '../reducer'; import { StateType } from '../reducer';
@ -11,6 +12,12 @@ const getGroupById = (state: StateType, convoId?: string) => {
: undefined; : undefined;
}; };
export function useLibGroupWeHaveSecretKey(convoId?: string) {
return useSelector((state: StateType) => {
return !isEmpty(getGroupById(state, convoId)?.secretKey);
});
}
export function useLibGroupInvitePending(convoId?: string) { export function useLibGroupInvitePending(convoId?: string) {
return useSelector((state: StateType) => getGroupById(state, convoId)?.invitePending); return useSelector((state: StateType) => getGroupById(state, convoId)?.invitePending);
} }

@ -28,8 +28,11 @@ function emptyMember(pubkeyHex: PubkeyType): GroupMemberGet {
promoted: false, promoted: false,
promotionFailed: false, promotionFailed: false,
promotionPending: false, promotionPending: false,
admin: false, inviteAccepted: false,
removedStatus: 0, inviteNotSent: false,
isRemoved: false,
promotionNotSent: false,
shouldRemoveMessages: false,
pubkeyHex, pubkeyHex,
}; };
} }
@ -166,7 +169,7 @@ describe('libsession_metagroup', () => {
}); });
it('can add member by setting its promoted state, both ok and nok', () => { it('can add member by setting its promoted state, both ok and nok', () => {
metaGroupWrapper.memberSetPromoted(member, false); metaGroupWrapper.memberSetPromotionSent(member);
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq({ expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq({
...emptyMember(member), ...emptyMember(member),
@ -176,7 +179,7 @@ describe('libsession_metagroup', () => {
admin: false, admin: false,
}); });
metaGroupWrapper.memberSetPromoted(member2, true); metaGroupWrapper.memberSetPromotionFailed(member2);
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(2); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(2);
// the list is sorted by member pk, which means that index based test do not work // the list is sorted by member pk, which means that index based test do not work
expect(metaGroupWrapper.memberGet(member2)).to.be.deep.eq({ expect(metaGroupWrapper.memberGet(member2)).to.be.deep.eq({
@ -224,7 +227,7 @@ describe('libsession_metagroup', () => {
it('can erase member', () => { it('can erase member', () => {
metaGroupWrapper.memberSetAccepted(member); metaGroupWrapper.memberSetAccepted(member);
metaGroupWrapper.memberSetPromoted(member2, false); metaGroupWrapper.memberSetPromoted(member2);
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(2); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(2);
expect(metaGroupWrapper.memberGet(member)).to.be.deep.eq({ expect(metaGroupWrapper.memberGet(member)).to.be.deep.eq({
@ -245,7 +248,7 @@ describe('libsession_metagroup', () => {
}); });
it('can add via name set', () => { it('can add via name set', () => {
metaGroupWrapper.memberSetName(member, 'member name'); metaGroupWrapper.memberSetNameTruncated(member, 'member name');
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq({ expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq({
...emptyMember(member), ...emptyMember(member),
@ -263,14 +266,14 @@ describe('libsession_metagroup', () => {
}); });
it('can add via admin set', () => { it('can add via admin set', () => {
metaGroupWrapper.memberSetAdmin(member); metaGroupWrapper.memberSetPromotionAccepted(member);
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
const expected: GroupMemberGet = { const expected: GroupMemberGet = {
...emptyMember(member), ...emptyMember(member),
admin: true,
promoted: true, promoted: true,
promotionFailed: false, promotionFailed: false,
promotionPending: false, promotionPending: false,
promotionNotSent: false,
}; };
expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected); expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected);
@ -281,7 +284,8 @@ describe('libsession_metagroup', () => {
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
const expected: GroupMemberGet = { const expected: GroupMemberGet = {
...emptyMember(member), ...emptyMember(member),
removedStatus: 2, shouldRemoveMessages: true,
isRemoved: true,
}; };
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected); expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected);
@ -292,7 +296,8 @@ describe('libsession_metagroup', () => {
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
const expected: GroupMemberGet = { const expected: GroupMemberGet = {
...emptyMember(member), ...emptyMember(member),
removedStatus: 1, shouldRemoveMessages: false,
isRemoved: true,
}; };
expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1); expect(metaGroupWrapper.memberGetAll().length).to.be.deep.eq(1);
expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected); expect(metaGroupWrapper.memberGetAll()[0]).to.be.deep.eq(expected);
@ -319,8 +324,8 @@ describe('libsession_metagroup', () => {
}); });
// mark current user as admin // mark current user as admin
metaGroupWrapper.memberSetPromoted(us.x25519KeyPair.pubkeyHex, false); metaGroupWrapper.memberSetPromotionAccepted(us.x25519KeyPair.pubkeyHex);
metaGroupWrapper2.memberSetPromoted(us.x25519KeyPair.pubkeyHex, false); metaGroupWrapper2.memberSetPromotionAccepted(us.x25519KeyPair.pubkeyHex);
// add 2 normal members to each of those wrappers // add 2 normal members to each of those wrappers
const m1 = TestUtils.generateFakePubKeyStr(); const m1 = TestUtils.generateFakePubKeyStr();

@ -582,6 +582,7 @@ export type LocalizerKeys =
| 'userBanFailed' | 'userBanFailed'
| 'userBanned' | 'userBanned'
| 'userInvitedYouToGroup' | 'userInvitedYouToGroup'
| 'userInvitedYouToGroupAsAdmin'
| 'userRemovedFromModerators' | 'userRemovedFromModerators'
| 'userUnbanFailed' | 'userUnbanFailed'
| 'userUnbanned' | 'userUnbanned'
@ -609,6 +610,7 @@ export type LocalizerKeys =
| 'youLeftTheGroup' | 'youLeftTheGroup'
| 'youSetYourDisappearingMessages' | 'youSetYourDisappearingMessages'
| 'youWereInvitedToGroup' | 'youWereInvitedToGroup'
| 'youWereInvitedToGroupAsAdmin'
| 'youWereRemovedFrom' | 'youWereRemovedFrom'
| 'yourSessionID' | 'yourSessionID'
| 'yourUniqueSessionID' | 'yourUniqueSessionID'

@ -548,17 +548,29 @@ export const MetaGroupWrapperActions: MetaGroupWrapperActionsCalls = {
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'memberSetAccepted', pubkeyHex]) as Promise< callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'memberSetAccepted', pubkeyHex]) as Promise<
ReturnType<MetaGroupWrapperActionsCalls['memberSetAccepted']> ReturnType<MetaGroupWrapperActionsCalls['memberSetAccepted']>
>, >,
memberSetPromoted: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType, failed: boolean) => memberSetPromoted: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType) =>
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'memberSetPromoted', pubkeyHex]) as Promise<
ReturnType<MetaGroupWrapperActionsCalls['memberSetPromoted']>
>,
memberSetPromotionAccepted: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType) =>
callLibSessionWorker([ callLibSessionWorker([
`MetaGroupConfig-${groupPk}`, `MetaGroupConfig-${groupPk}`,
'memberSetPromoted', 'memberSetPromotionAccepted',
pubkeyHex, pubkeyHex,
failed, ]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetPromotionAccepted']>>,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetPromoted']>>, memberSetPromotionFailed: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType) =>
memberSetAdmin: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType) => callLibSessionWorker([
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'memberSetAdmin', pubkeyHex]) as Promise< `MetaGroupConfig-${groupPk}`,
ReturnType<MetaGroupWrapperActionsCalls['memberSetAdmin']> 'memberSetPromotionFailed',
>, pubkeyHex,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetPromotionFailed']>>,
memberSetPromotionSent: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType) =>
callLibSessionWorker([
`MetaGroupConfig-${groupPk}`,
'memberSetPromotionSent',
pubkeyHex,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetPromotionSent']>>,
memberSetInvited: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType, failed: boolean) => memberSetInvited: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType, failed: boolean) =>
callLibSessionWorker([ callLibSessionWorker([
`MetaGroupConfig-${groupPk}`, `MetaGroupConfig-${groupPk}`,
@ -566,13 +578,13 @@ export const MetaGroupWrapperActions: MetaGroupWrapperActionsCalls = {
pubkeyHex, pubkeyHex,
failed, failed,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetInvited']>>, ]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetInvited']>>,
memberSetName: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType, name: string) => memberSetNameTruncated: async (groupPk: GroupPubkeyType, pubkeyHex: PubkeyType, name: string) =>
callLibSessionWorker([ callLibSessionWorker([
`MetaGroupConfig-${groupPk}`, `MetaGroupConfig-${groupPk}`,
'memberSetName', 'memberSetNameTruncated',
pubkeyHex, pubkeyHex,
name, name,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetName']>>, ]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['memberSetNameTruncated']>>,
memberSetProfilePicture: async ( memberSetProfilePicture: async (
groupPk: GroupPubkeyType, groupPk: GroupPubkeyType,
pubkeyHex: PubkeyType, pubkeyHex: PubkeyType,
@ -617,6 +629,10 @@ export const MetaGroupWrapperActions: MetaGroupWrapperActionsCalls = {
data, data,
timestampMs, timestampMs,
]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['loadKeyMessage']>>, ]) as Promise<ReturnType<MetaGroupWrapperActionsCalls['loadKeyMessage']>>,
keysAdmin: async (groupPk: GroupPubkeyType) =>
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'keysAdmin']) as Promise<
ReturnType<MetaGroupWrapperActionsCalls['keysAdmin']>
>,
keyGetCurrentGen: async (groupPk: GroupPubkeyType) => keyGetCurrentGen: async (groupPk: GroupPubkeyType) =>
callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'keyGetCurrentGen']) as Promise< callLibSessionWorker([`MetaGroupConfig-${groupPk}`, 'keyGetCurrentGen']) as Promise<
ReturnType<MetaGroupWrapperActionsCalls['keyGetCurrentGen']> ReturnType<MetaGroupWrapperActionsCalls['keyGetCurrentGen']>

1
ts/window.d.ts vendored

@ -31,6 +31,7 @@ declare global {
useTestNet: boolean; useTestNet: boolean;
useClosedGroupV2: boolean; useClosedGroupV2: boolean;
useClosedGroupV2QAButtons: boolean; useClosedGroupV2QAButtons: boolean;
useGroupV2InviteAsAdmin: boolean;
debug: { debug: {
debugLogging: boolean; debugLogging: boolean;
debugLibsessionDumps: boolean; debugLibsessionDumps: boolean;

@ -2906,7 +2906,7 @@ available-typed-arrays@^1.0.7:
dependencies: dependencies:
possible-typed-array-names "^1.0.0" possible-typed-array-names "^1.0.0"
axios@^1.3.2: axios@^1.6.5:
version "1.7.2" version "1.7.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
@ -3527,24 +3527,24 @@ clsx@^1.0.4, clsx@^1.1.1, clsx@^1.2.1:
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
cmake-js@7.2.1: cmake-js@^7.2.1:
version "7.2.1" version "7.3.0"
resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.2.1.tgz#757c0d39994121b084bab96290baf115ee7712cd" resolved "https://registry.yarnpkg.com/cmake-js/-/cmake-js-7.3.0.tgz#6fd6234b7aeec4545c1c806f9e3f7ffacd9798b2"
integrity sha512-AdPSz9cSIJWdKvm0aJgVu3X8i0U3mNTswJkSHzZISqmYVjZk7Td4oDFg0mCBA383wO+9pG5Ix7pEP1CZH9x2BA== integrity sha512-dXs2zq9WxrV87bpJ+WbnGKv8WUBXDw8blNiwNHoRe/it+ptscxhQHKB1SJXa1w+kocLMeP28Tk4/eTCezg4o+w==
dependencies: dependencies:
axios "^1.3.2" axios "^1.6.5"
debug "^4" debug "^4"
fs-extra "^10.1.0" fs-extra "^11.2.0"
lodash.isplainobject "^4.0.6" lodash.isplainobject "^4.0.6"
memory-stream "^1.0.0" memory-stream "^1.0.0"
node-api-headers "^0.0.2" node-api-headers "^1.1.0"
npmlog "^6.0.2" npmlog "^6.0.2"
rc "^1.2.7" rc "^1.2.7"
semver "^7.3.8" semver "^7.5.4"
tar "^6.1.11" tar "^6.2.0"
url-join "^4.0.1" url-join "^4.0.1"
which "^2.0.2" which "^2.0.2"
yargs "^17.6.0" yargs "^17.7.2"
color-convert@^1.9.0: color-convert@^1.9.0:
version "1.9.3" version "1.9.3"
@ -3966,7 +3966,14 @@ debug@2.6.9, debug@^2.2.0, debug@^2.6.8, debug@^2.6.9:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.5"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
dependencies:
ms "2.1.2"
debug@4.3.4:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -3981,9 +3988,9 @@ debug@^3.2.7:
ms "^2.1.1" ms "^2.1.1"
debug@^4: debug@^4:
version "4.3.5" version "4.3.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b"
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==
dependencies: dependencies:
ms "2.1.2" ms "2.1.2"
@ -5177,7 +5184,7 @@ fs-extra@^10.0.0, fs-extra@^10.1.0:
jsonfile "^6.0.1" jsonfile "^6.0.1"
universalify "^2.0.0" universalify "^2.0.0"
fs-extra@^11.0.0: fs-extra@^11.0.0, fs-extra@^11.2.0:
version "11.2.0" version "11.2.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
@ -6599,9 +6606,12 @@ levn@~0.3.0:
prelude-ls "~1.1.2" prelude-ls "~1.1.2"
type-check "~0.3.2" type-check "~0.3.2"
"libsession_util_nodejs@link:../libsession-util-nodejs": "libsession_util_nodejs@https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.21/libsession_util_nodejs-v0.3.21.tar.gz":
version "0.0.0" version "0.3.21"
uid "" resolved "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.21/libsession_util_nodejs-v0.3.21.tar.gz#64705b1f7c934ca32f929ea8127370cc82bab97a"
dependencies:
cmake-js "^7.2.1"
node-addon-api "^6.1.0"
libsodium-sumo@^0.7.13: libsodium-sumo@^0.7.13:
version "0.7.13" version "0.7.13"
@ -7483,10 +7493,10 @@ node-addon-api@^6.1.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
node-api-headers@^0.0.2: node-api-headers@^1.1.0:
version "0.0.2" version "1.2.0"
resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-0.0.2.tgz#31f4c6c2750b63e598128e76a60aefca6d76ac5d" resolved "https://registry.yarnpkg.com/node-api-headers/-/node-api-headers-1.2.0.tgz#b717cd420aec79031f8dc83a50eb0a8bdf24c70d"
integrity sha512-YsjmaKGPDkmhoNKIpkChtCsPVaRE0a274IdERKnuc/E8K1UJdBZ4/mvI006OijlQZHCfpRNOH3dfHQs92se8gg== integrity sha512-L9AiEkBfgupC0D/LsudLPOhzy/EdObsp+FHyL1zSK0kKv5FDA9rJMoRz8xd+ojxzlqfg0tTZm2h8ot2nS7bgRA==
node-dir@^0.1.17: node-dir@^0.1.17:
version "0.1.17" version "0.1.17"
@ -9112,7 +9122,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.1.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.4: semver@^7.1.2, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.4:
version "7.6.2" version "7.6.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
@ -9707,7 +9717,7 @@ tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
tar@^6.1.0, tar@^6.1.11: tar@^6.1.0, tar@^6.1.11, tar@^6.2.0:
version "6.2.1" version "6.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
@ -10695,7 +10705,7 @@ yargs@^15.1.0:
y18n "^4.0.0" y18n "^4.0.0"
yargs-parser "^18.1.2" yargs-parser "^18.1.2"
yargs@^17.0.0, yargs@^17.0.1, yargs@^17.6.0, yargs@^17.6.2: yargs@^17.0.0, yargs@^17.0.1, yargs@^17.6.2, yargs@^17.7.2:
version "17.7.2" version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==

Loading…
Cancel
Save