chore: renamed getnowwithnetworkoffset to now()

pull/2963/head
Audric Ackermann 2 years ago
parent 9595f09085
commit 93d87d82ae

@ -162,6 +162,10 @@ message GroupUpdateMessage {
message DataMessage {
// 7 = timestamp unused and should not be used
reserved 7;
reserved "timestamp";
enum Flags {
EXPIRATION_TIMER_UPDATE = 2;
}
@ -253,7 +257,6 @@ message DataMessage {
optional uint32 flags = 4;
optional uint32 expireTimer = 5;
optional bytes profileKey = 6;
optional uint64 timestamp = 7;
optional Quote quote = 8;
repeated Preview preview = 10;
optional Reaction reaction = 11;

@ -553,7 +553,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const chatMessageParams: VisibleMessageParams = {
body: '',
// we need to use a new timestamp here, otherwise android&iOS will consider this message as a duplicate and drop the synced reaction
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
reaction,
lokiProfile: UserUtils.getOurProfile(),
};
@ -744,7 +744,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const { attachments, body, groupInvitation, preview, quote } = msg;
this.clearTypingTimers();
const expireTimer = this.get('expireTimer');
const networkTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const networkTimestamp = GetNetworkTime.now();
window?.log?.info(
'Sending message to conversation',
@ -2219,9 +2219,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
const typingParams = {
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
isTyping,
typingTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
typingTimestamp: GetNetworkTime.now(),
};
const typingMessage = new TypingMessage(typingParams);

@ -791,7 +791,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
if (conversation.isPublic()) {
const openGroupParams: VisibleMessageParams = {
identifier: this.id,
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
lokiProfile: UserUtils.getOurProfile(),
body,
attachments,

@ -14,7 +14,7 @@ const isHexString = (maybeHex: string) =>
*
* Throws an error if this string is not a hex string.
* @param hexString the string to convert from
* @returns the Uint8Arraty
* @returns the Uint8Arrat
*/
const fromHexString = (hexString: string): Uint8Array => {
if (!isHexString(hexString)) {
@ -27,11 +27,24 @@ const fromHexString = (hexString: string): Uint8Array => {
return Uint8Array.from(matches.map(byte => parseInt(byte, 16)));
};
/**
* Returns the Uint8Array corresponding to the given string, without a 03/05 prefix when there is a prefix
* Note: this is different than the libsodium.from_hex().
*/
const fromHexStringNoPrefix = (hexString: string): Uint8Array => {
const asHex = fromHexString(hexString);
if (asHex.length === 33) {
return asHex.slice(1);
}
return asHex;
};
const toHexString = (bytes: Uint8Array) =>
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
export const HexString = {
toHexString,
fromHexString,
fromHexStringNoPrefix,
isHexString,
};

@ -49,9 +49,7 @@ export async function handleCallMessage(
}
if (type === SignalService.CallMessage.Type.OFFER) {
if (
Math.max(sentTimestamp - GetNetworkTime.getNowWithNetworkOffset()) > TTL_DEFAULT.CALL_MESSAGE
) {
if (Math.max(sentTimestamp - GetNetworkTime.now()) > TTL_DEFAULT.CALL_MESSAGE) {
window?.log?.info('Dropping incoming OFFER callMessage sent a while ago: ', sentTimestamp);
await IncomingMessageCache.removeFromCache(envelope);

@ -1,5 +1,5 @@
/* eslint-disable no-param-reassign */
import { isEmpty, isFinite, noop, omit, toNumber } from 'lodash';
import { isEmpty, noop, omit, toNumber } from 'lodash';
import { SignalService } from '../protobuf';
import { IncomingMessageCache } from './cache';
@ -100,10 +100,7 @@ export function messageHasVisibleContent(message: SignalService.DataMessage) {
);
}
export function cleanIncomingDataMessage(
rawDataMessage: SignalService.DataMessage,
envelope?: EnvelopePlus
) {
export function cleanIncomingDataMessage(rawDataMessage: SignalService.DataMessage) {
const FLAGS = SignalService.DataMessage.Flags;
// Now that its decrypted, validate the message and clean it up for consumer
@ -134,11 +131,6 @@ export function cleanIncomingDataMessage(
}
cleanAttachments(rawDataMessage);
// if the decrypted dataMessage timestamp is not set, copy the one from the envelope
if (!isFinite(rawDataMessage?.timestamp) && envelope) {
rawDataMessage.timestamp = envelope.timestamp;
}
return rawDataMessage;
}
@ -162,7 +154,7 @@ export async function handleSwarmDataMessage(
): Promise<void> {
window.log.info('handleSwarmDataMessage');
const cleanDataMessage = cleanIncomingDataMessage(rawDataMessage, envelope);
const cleanDataMessage = cleanIncomingDataMessage(rawDataMessage);
if (cleanDataMessage.groupUpdateMessage) {
await GroupV2Receiver.handleGroupUpdateMessage({

@ -4,10 +4,13 @@ import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { HexString } from '../../node/hexStrings';
import { SignalService } from '../../protobuf';
import { getSwarmPollingInstance } from '../../session/apis/snode_api';
import { GetNetworkTime } from '../../session/apis/snode_api/getNetworkTime';
import { ConvoHub } from '../../session/conversations';
import { getSodiumRenderer } from '../../session/crypto';
import { ClosedGroup } from '../../session/group/closed-group';
import { GroupUpdateInviteResponseMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage';
import { ed25519Str } from '../../session/onions/onionPath';
import { getMessageQueue } from '../../session/sending';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { stringToUint8Array } from '../../session/utils/String';
@ -57,7 +60,7 @@ async function handleGroupInviteMessage({
return;
}
const sigValid = await verifySig({
pubKey: HexString.fromHexString(inviteMessage.groupSessionId),
pubKey: HexString.fromHexStringNoPrefix(inviteMessage.groupSessionId),
signature: inviteMessage.adminSignature,
data: stringToUint8Array(`INVITE${UserUtils.getOurPubKeyStrFromCache()}${envelopeTimestamp}`),
});
@ -108,13 +111,23 @@ async function handleGroupInviteMessage({
groupEd25519Secretkey: null,
userEd25519Secretkey: toFixedUint8ArrayOfLength(userEd25519Secretkey, 64).buffer,
groupEd25519Pubkey: toFixedUint8ArrayOfLength(
HexString.fromHexString(inviteMessage.groupSessionId.slice(2)),
HexString.fromHexStringNoPrefix(inviteMessage.groupSessionId),
32
).buffer,
});
await LibSessionUtil.saveDumpsToDb(UserUtils.getOurPubKeyStrFromCache());
await UserSync.queueNewJobIfNeeded();
// TODO currently sending auto-accept of invite. needs to be removed once we get the Group message request logic
console.warn('currently sending auto accept invite response');
await getMessageQueue().sendToGroupV2({
message: new GroupUpdateInviteResponseMessage({
groupPk: inviteMessage.groupSessionId,
isApproved: true,
timestamp: GetNetworkTime.now(),
}),
});
// TODO use the pending so we actually don't start polling here unless it is not in the pending state.
// once everything is ready, start polling using that authData to get the keys, members, details of that group, and its messages.
getSwarmPollingInstance().addGroupId(inviteMessage.groupSessionId);
@ -140,7 +153,7 @@ async function handleGroupInfoChangeMessage({
author,
}: GroupUpdateGeneric<SignalService.GroupUpdateInfoChangeMessage>) {
const sigValid = await verifySig({
pubKey: HexString.fromHexString(groupPk),
pubKey: HexString.fromHexStringNoPrefix(groupPk),
signature: change.adminSignature,
data: stringToUint8Array(`INFO_CHANGE${change.type}${envelopeTimestamp}`),
});
@ -200,7 +213,7 @@ async function handleGroupMemberChangeMessage({
}
const sigValid = await verifySig({
pubKey: HexString.fromHexString(groupPk),
pubKey: HexString.fromHexStringNoPrefix(groupPk),
signature: change.adminSignature,
data: stringToUint8Array(`MEMBER_CHANGE${change.type}${envelopeTimestamp}`),
});
@ -281,7 +294,7 @@ async function handleGroupDeleteMemberContentMessage({
}
const sigValid = await verifySig({
pubKey: HexString.fromHexString(groupPk),
pubKey: HexString.fromHexStringNoPrefix(groupPk),
signature: change.adminSignature,
data: stringToUint8Array(
`DELETE_CONTENT${envelopeTimestamp}${change.memberSessionIds.join()}${change.messageHashes.join()}`
@ -312,7 +325,7 @@ async function handleGroupUpdateDeleteMessage({
return;
}
const sigValid = await verifySig({
pubKey: HexString.fromHexString(groupPk),
pubKey: HexString.fromHexStringNoPrefix(groupPk),
signature: change.adminSignature,
data: stringToUint8Array(`DELETE${envelopeTimestamp}${change.memberSessionIds.join()}`),
});
@ -331,20 +344,22 @@ async function handleGroupUpdateDeleteMessage({
async function handleGroupUpdateInviteResponseMessage({
groupPk,
envelopeTimestamp,
change,
author,
}: GroupUpdateGeneric<SignalService.GroupUpdateInviteResponseMessage>) {
// no sig verify for this type of messages
// no sig verify for this type of message
const convo = ConvoHub.use().get(groupPk);
if (!convo) {
return;
}
convo.set({
active_at: envelopeTimestamp,
});
console.warn('Not implemented');
if (!change.isApproved) {
window.log.info('got inviteResponse but isApproved is false. Dropping');
return;
}
window.inboxStore.dispatch(groupInfoActions.inviteResponseReceived({ groupPk, member: author }));
// TODO We should process this message type even if the sender is blocked
throw new Error('Not implemented');
}
async function handleGroupUpdatePromoteMessage({

@ -1,12 +1,12 @@
import { compact } from 'lodash';
import { OpenGroupData, OpenGroupV2Room } from '../../../../data/opengroups';
import { OpenGroupMessageV2 } from './OpenGroupMessageV2';
import { getSodiumRenderer } from '../../../crypto';
import { UserUtils } from '../../../utils';
import { fromHexToArray } from '../../../utils/String';
import { getSodiumRenderer } from '../../../crypto';
import { SogsBlinding } from '../sogsv3/sogsBlinding';
import { GetNetworkTime } from '../../snode_api/getNetworkTime';
import { SogsBlinding } from '../sogsv3/sogsBlinding';
import { OpenGroupMessageV2 } from './OpenGroupMessageV2';
export type OpenGroupRequestHeaders = {
'X-SOGS-Pubkey': string;
@ -42,7 +42,7 @@ const getOurOpenGroupHeaders = async (
const nonce = (await getSodiumRenderer()).randombytes_buf(16);
const timestamp = Math.floor(GetNetworkTime.getNowWithNetworkOffset() / 1000);
const timestamp = Math.floor(GetNetworkTime.now() / 1000);
return SogsBlinding.getOpenGroupHeaders({
signingKeys,
serverPK: fromHexToArray(serverPublicKey),

@ -196,7 +196,7 @@ export async function expireMessageOnSnode(props: ExpireMessageOnSnodeProps) {
const swarm = await getSwarmFor(ourPubKey);
const expiry = GetNetworkTime.getNowWithNetworkOffset() + expireTimer;
const expiry = GetNetworkTime.now() + expireTimer;
const signResult = await SnodeSignature.generateUpdateExpiryOurSignature({
shortenOrExtend,
timestamp: expiry,

@ -6,8 +6,8 @@
import { isNumber } from 'lodash';
import { Snode } from '../../../data/data';
import { doSnodeBatchRequest } from './batchRequest';
import { NetworkTimeSubRequest } from './SnodeRequestTypes';
import { doSnodeBatchRequest } from './batchRequest';
function getNetworkTimeSubRequests(): Array<NetworkTimeSubRequest> {
const request: NetworkTimeSubRequest = { method: 'info', params: {} };
@ -43,11 +43,11 @@ let latestTimestampOffset = Number.MAX_SAFE_INTEGER;
function handleTimestampOffsetFromNetwork(_request: string, snodeTimestamp: number) {
if (snodeTimestamp && isNumber(snodeTimestamp) && snodeTimestamp > 1609419600 * 1000) {
// first january 2021. Arbitrary, just want to make sure the return timestamp is somehow valid and not some crazy low value
const now = Date.now();
const clockTime = Date.now();
if (latestTimestampOffset === Number.MAX_SAFE_INTEGER) {
window?.log?.info(`first timestamp offset received: ${now - snodeTimestamp}ms`);
window?.log?.info(`first timestamp offset received: ${clockTime - snodeTimestamp}ms`);
}
latestTimestampOffset = now - snodeTimestamp;
latestTimestampOffset = clockTime - snodeTimestamp;
}
}
@ -65,7 +65,7 @@ function getLatestTimestampOffset() {
return latestTimestampOffset;
}
function getNowWithNetworkOffset() {
function now() {
// make sure to call exports here, as we stub the exported one for testing.
return Date.now() - GetNetworkTime.getLatestTimestampOffset();
}
@ -74,5 +74,5 @@ export const GetNetworkTime = {
getNetworkTime,
handleTimestampOffsetFromNetwork,
getLatestTimestampOffset,
getNowWithNetworkOffset,
now,
};

@ -140,7 +140,7 @@ async function buildRetrieveRequest(
const retrieveParam = {
pubkey,
last_hash: lastHashes.at(index) || '',
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
max_size: foundMaxSize,
};
@ -163,7 +163,7 @@ async function buildRetrieveRequest(
);
if (configHashesToBump?.length) {
const expiry = GetNetworkTime.getNowWithNetworkOffset() + DURATION.DAYS * 30;
const expiry = GetNetworkTime.now() + DURATION.DAYS * 30;
if (isUs) {
const signResult = await SnodeSignature.generateUpdateExpiryOurSignature({
shortenOrExtend: '',

@ -29,7 +29,7 @@ async function getRevokeSubaccountRequest({
throw new Error('revokeSubaccountForGroup: not a 03 group');
}
const timestamp = GetNetworkTime.getNowWithNetworkOffset();
const timestamp = GetNetworkTime.now();
const revokeParams: Array<RevokeSubaccountSubRequest | UnrevokeSubaccountSubRequest> =
await Promise.all(

@ -13,7 +13,7 @@ import {
import { getSodiumRenderer } from '../../../crypto/MessageEncrypter';
import { GroupUpdateInviteMessage } from '../../../messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage';
import { StringUtils, UserUtils } from '../../../utils';
import { fromUInt8ArrayToBase64 } from '../../../utils/String';
import { fromUInt8ArrayToBase64, stringToUint8Array } from '../../../utils/String';
import { PreConditionFailed } from '../../../utils/errors';
import { GetNetworkTime } from '../getNetworkTime';
import { SnodeNamespacesGroup } from '../namespaces';
@ -33,15 +33,18 @@ async function getGroupInviteMessage({
groupPk: GroupPubkeyType;
}) {
const sodium = await getSodiumRenderer();
const timestamp = GetNetworkTime.getNowWithNetworkOffset();
const timestamp = GetNetworkTime.now();
if (UserUtils.isUsFromCache(member)) {
throw new Error('getGroupInviteMessage: we cannot invite ourselves');
}
const tosign = `INVITE${member}${timestamp}`;
debugger;
// Note: as the signature is built with the timestamp here, we cannot override the timestamp later on the sending pipeline
const adminSignature = sodium.crypto_sign_detached(tosign, secretKey);
const adminSignature = sodium.crypto_sign_detached(
stringToUint8Array(`INVITE${member}${timestamp}`),
secretKey
);
const memberAuthData = await MetaGroupWrapperActions.makeSwarmSubAccount(groupPk, member);
const invite = new GroupUpdateInviteMessage({

@ -27,7 +27,7 @@ export type SnodeSigParamsUs = SnodeSigParamsShared & {
};
function getVerificationDataForStoreRetrieve(params: SnodeSigParamsShared) {
const signatureTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const signatureTimestamp = GetNetworkTime.now();
const verificationData = StringUtils.encode(
`${params.method}${params.namespace === 0 ? '' : params.namespace}${signatureTimestamp}`,
'utf8'

@ -84,7 +84,7 @@ function isSigParamsForGroupAdmin(
}
function getVerificationData(params: SnodeSigParamsShared) {
const signatureTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const signatureTimestamp = GetNetworkTime.now();
const verificationData = StringUtils.encode(
`${params.method}${params.namespace === 0 ? '' : params.namespace}${signatureTimestamp}`,
'utf8'

@ -473,7 +473,7 @@ async function leaveClosedGroup(groupId: string, fromSyncMessage: boolean) {
await convo.updateGroupAdmins(admins, false);
await convo.commit();
const networkTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const networkTimestamp = GetNetworkTime.now();
getSwarmPollingInstance().removePubkey(groupId, 'leaveClosedGroup');

@ -414,7 +414,7 @@ async function generateAndSendNewEncryptionKeyPair(
const keypairsMessage = new ClosedGroupEncryptionPairMessage({
groupId: toHex(groupId),
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
encryptedKeyPairs: wrappers,
});

@ -14,8 +14,9 @@ export abstract class Message {
if (identifier && identifier.length === 0) {
throw new Error('Cannot set empty identifier');
}
if (!timestamp) {
throw new Error('Cannot set undefined timestamp');
if (!timestamp || timestamp <= 0) {
throw new Error('Cannot set undefined timestamp or <=0');
}
this.identifier = identifier || uuid();
}

@ -175,8 +175,6 @@ export class VisibleMessage extends DataMessage {
});
}
dataMessage.timestamp = this.timestamp;
return dataMessage;
}

@ -3,7 +3,7 @@
import { AbortController } from 'abort-controller';
import ByteBuffer from 'bytebuffer';
import { GroupPubkeyType, PubkeyType } from 'libsession_util_nodejs';
import _, { isEmpty, sample, toNumber } from 'lodash';
import { isEmpty, sample, toNumber } from 'lodash';
import pRetry from 'p-retry';
import { Data } from '../../data/data';
import { SignalService } from '../../protobuf';
@ -48,7 +48,7 @@ import { EmptySwarmError } from '../utils/errors';
// ================ SNODE STORE ================
function overwriteOutgoingTimestampWithNetworkTimestamp(message: { plainTextBuffer: Uint8Array }) {
const networkTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const networkTimestamp = GetNetworkTime.now();
const { plainTextBuffer } = message;
const contentDecoded = SignalService.Content.decode(plainTextBuffer);
@ -68,7 +68,7 @@ function overwriteOutgoingTimestampWithNetworkTimestamp(message: { plainTextBuff
) {
return {
overRiddenTimestampBuffer: plainTextBuffer,
networkTimestamp: _.toNumber(dataMessage.timestamp),
networkTimestamp: toNumber(dataMessage.timestamp),
};
}
dataMessage.timestamp = networkTimestamp;
@ -533,7 +533,7 @@ async function sendToOpenGroupV2(
// we agreed to pad message for opengroupv2
const paddedBody = addMessagePadding(rawMessage.plainTextBuffer());
const v2Message = new OpenGroupMessageV2({
sentTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
sentTimestamp: GetNetworkTime.now(),
base64EncodedData: fromUInt8ArrayToBase64(paddedBody),
filesToLink,
});
@ -558,7 +558,7 @@ async function sendToOpenGroupV2BlindedRequest(
recipientBlindedId: string
): Promise<{ serverId: number; serverTimestamp: number }> {
const v2Message = new OpenGroupMessageV2({
sentTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
sentTimestamp: GetNetworkTime.now(),
base64EncodedData: fromUInt8ArrayToBase64(encryptedContent),
});

@ -5,34 +5,34 @@ import { v4 as uuidv4 } from 'uuid';
import { MessageUtils, ToastUtils, UserUtils } from '..';
import { SignalService } from '../../../protobuf';
import { openConversationWithMessages } from '../../../state/ducks/conversations';
import {
CallStatusEnum,
answerCall,
callConnected,
callReconnecting,
CallStatusEnum,
endCall,
incomingCall,
setFullScreenCall,
startingCallWith,
} from '../../../state/ducks/call';
import { openConversationWithMessages } from '../../../state/ducks/conversations';
import { ConvoHub } from '../../conversations';
import { CallMessage } from '../../messages/outgoing/controlMessage/CallMessage';
import { ed25519Str } from '../../onions/onionPath';
import { PubKey } from '../../types';
import { getIsRinging } from '../RingingManager';
import { getBlackSilenceMediaStream } from './Silence';
import { getMessageQueue } from '../..';
import { MessageSender } from '../../sending';
import { DURATION } from '../../constants';
import { Data } from '../../../data/data';
import { getCallMediaPermissionsSettings } from '../../../components/settings/SessionSettings';
import { PnServer } from '../../apis/push_notification_api';
import { Data } from '../../../data/data';
import { approveConvoAndSendResponse } from '../../../interactions/conversationInteractions';
import { READ_MESSAGE_STATE } from '../../../models/conversationAttributes';
import { PnServer } from '../../apis/push_notification_api';
import { GetNetworkTime } from '../../apis/snode_api/getNetworkTime';
import { SnodeNamespaces } from '../../apis/snode_api/namespaces';
import { READ_MESSAGE_STATE } from '../../../models/conversationAttributes';
import { DURATION } from '../../constants';
import { MessageSender } from '../../sending';
import { getIsRinging } from '../RingingManager';
import { getBlackSilenceMediaStream } from './Silence';
export type InputItem = { deviceId: string; label: string };
@ -856,7 +856,7 @@ export async function USER_acceptIncomingCallRequest(fromSender: string) {
await peerConnection.addIceCandidate(candicate);
}
}
const networkTimestamp = GetNetworkTime.getNowWithNetworkOffset();
const networkTimestamp = GetNetworkTime.now();
const callerConvo = ConvoHub.use().get(fromSender);
callerConvo.set('active_at', networkTimestamp);
await callerConvo.unhideIfNeeded(false);
@ -1192,14 +1192,14 @@ async function addMissedCallMessage(callerPubkey: string, sentAt: number) {
const incomingCallConversation = ConvoHub.use().get(callerPubkey);
if (incomingCallConversation.isActive() || incomingCallConversation.isHidden()) {
incomingCallConversation.set('active_at', GetNetworkTime.getNowWithNetworkOffset());
incomingCallConversation.set('active_at', GetNetworkTime.now());
await incomingCallConversation.unhideIfNeeded(false);
}
await incomingCallConversation?.addSingleIncomingMessage({
source: callerPubkey,
sent_at: sentAt,
received_at: GetNetworkTime.getNowWithNetworkOffset(),
received_at: GetNetworkTime.now(),
expireTimer: 0,
callNotificationType: 'missed-call',
unread: READ_MESSAGE_STATE.unread,

@ -83,7 +83,7 @@ async function pushChangesToGroupSwarmIfNeeded(
return {
namespace: item.namespace,
pubkey: groupPk,
networkTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
networkTimestamp: GetNetworkTime.now(),
ttl: TTL_DEFAULT.TTL_CONFIG,
data: item.ciphertext,
};
@ -94,7 +94,7 @@ async function pushChangesToGroupSwarmIfNeeded(
namespace: SnodeNamespaces.ClosedGroupKeys,
pubkey: groupPk,
ttl: TTL_DEFAULT.TTL_CONFIG,
networkTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
networkTimestamp: GetNetworkTime.now(),
data: key,
})
);

@ -90,7 +90,7 @@ async function pushChangesToUserSwarmIfNeeded() {
return {
namespace: item.namespace,
pubkey: us,
networkTimestamp: GetNetworkTime.getNowWithNetworkOffset(),
networkTimestamp: GetNetworkTime.now(),
ttl: TTL_DEFAULT.TTL_CONFIG,
data: item.ciphertext,
};

@ -74,6 +74,15 @@ type GroupDetailsUpdate = {
members: Array<GroupMemberGet>;
};
async function checkWeAreAdminOrThrow(groupPk: GroupPubkeyType, context: string) {
const us = UserUtils.getOurPubKeyStrFromCache();
const inGroup = await MetaGroupWrapperActions.memberGet(groupPk, us);
const haveAdminkey = await UserGroupsWrapperActions.getGroup(groupPk);
if (!haveAdminkey || inGroup?.promoted) {
throw new Error(`checkWeAreAdminOrThrow failed with ctx: ${context}`);
}
}
/**
* Create a brand new group with a 03 prefix.
* To be called only when our current logged in user, through the UI, creates a brand new closed group given a name and a list of members.
@ -464,7 +473,7 @@ async function handleRemoveMembers({
}
await MetaGroupWrapperActions.memberEraseAndRekey(groupPk, removed);
const timestamp = GetNetworkTime.getNowWithNetworkOffset();
const timestamp = GetNetworkTime.now();
await Promise.all(
removed.map(async m => {
const adminSignature = await SnodeGroupSignature.signDataWithAdminSecret(
@ -540,6 +549,8 @@ async function handleMemberChangeFromUIOrNot({
throw new Error('tried to make change to group but we do not have the admin secret key');
}
await checkWeAreAdminOrThrow(groupPk, 'handleMemberChangeFromUIOrNot');
const { removed, withHistory, withoutHistory, convo, us } = validateMemberChange({
withHistory: addMembersWithHistory,
withoutHistory: addMembersWithoutHistory,
@ -622,7 +633,7 @@ async function handleMemberChangeFromUIOrNot({
groupPk,
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.REMOVED,
identifier: msg.id,
timestamp: GetNetworkTime.getNowWithNetworkOffset(),
timestamp: GetNetworkTime.now(),
secretKey: group.secretKey,
sodium,
}),
@ -652,6 +663,8 @@ async function handleNameChangeFromUIOrNot({
throw new PreConditionFailed('nameChange infoGet is empty');
}
await checkWeAreAdminOrThrow(groupPk, 'handleNameChangeFromUIOrNot');
// this throws if the name is the same, or empty
const { newName, convo, us } = validateNameChange({
newName: uncheckedName,
@ -767,6 +780,35 @@ const markUsAsAdmin = createAsyncThunk(
}
);
const inviteResponseReceived = createAsyncThunk(
'group/inviteResponseReceived',
async (
{
groupPk,
member,
}: {
groupPk: GroupPubkeyType;
member: PubkeyType;
},
payloadCreator
): Promise<GroupDetailsUpdate> => {
const state = payloadCreator.getState() as StateType;
if (!state.groups.infos[groupPk] || !state.groups.members[groupPk]) {
throw new PreConditionFailed('inviteResponseReceived group but not present in redux slice');
}
await checkWeAreAdminOrThrow(groupPk, 'inviteResponseReceived');
await MetaGroupWrapperActions.memberSetAccepted(groupPk, member);
await GroupSync.queueNewJobIfNeeded(groupPk);
return {
groupPk,
infos: await MetaGroupWrapperActions.infoGet(groupPk),
members: await MetaGroupWrapperActions.memberGetAll(groupPk),
};
}
);
const currentDeviceGroupNameChange = createAsyncThunk(
'group/currentDeviceGroupNameChange',
async (
@ -783,6 +825,7 @@ const currentDeviceGroupNameChange = createAsyncThunk(
if (!state.groups.infos[groupPk] || !state.groups.members[groupPk]) {
throw new PreConditionFailed('currentDeviceGroupNameChange group not present in redux slice');
}
await checkWeAreAdminOrThrow(groupPk, 'currentDeviceGroupNameChange');
await handleNameChangeFromUIOrNot({ groupPk, ...args, fromCurrentDevice: true });
@ -929,6 +972,18 @@ const groupSlice = createSlice({
builder.addCase(markUsAsAdmin.rejected, (_state, action) => {
window.log.error('a markUsAsAdmin was rejected', action.error);
});
builder.addCase(inviteResponseReceived.fulfilled, (state, action) => {
const { infos, members, groupPk } = action.payload;
state.infos[groupPk] = infos;
state.members[groupPk] = members;
window.log.debug(`groupInfo after inviteResponseReceived: ${stringify(infos)}`);
window.log.debug(`groupMembers after inviteResponseReceived: ${stringify(members)}`);
});
builder.addCase(inviteResponseReceived.rejected, (_state, action) => {
window.log.error('a inviteResponseReceived was rejected', action.error);
});
},
});
@ -940,6 +995,7 @@ export const groupInfoActions = {
handleUserGroupUpdate,
currentDeviceGroupMembersChange,
markUsAsAdmin,
inviteResponseReceived,
currentDeviceGroupNameChange,
...groupSlice.actions,
};

@ -50,7 +50,7 @@ describe('SnodeSignature', () => {
describe('getSnodeGroupAdminSignatureParams', () => {
beforeEach(() => {
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(hardcodedTimestamp);
Sinon.stub(GetNetworkTime, 'now').returns(hardcodedTimestamp);
});
describe('retrieve', () => {
@ -162,7 +162,7 @@ describe('SnodeSignature', () => {
// describe('getSnodeGroupSubAccountSignatureParams', () => {
// beforeEach(() => {
// Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(hardcodedTimestamp);
// Sinon.stub(GetNetworkTime, 'now').returns(hardcodedTimestamp);
// });
// describe('retrieve', () => {

@ -164,7 +164,7 @@ describe('LibSessionUtil pendingChangesForGroup', () => {
};
Sinon.stub(MetaGroupWrapperActions, 'needsPush').resolves(true);
Sinon.stub(MetaGroupWrapperActions, 'push').resolves(pushResults);
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(1234);
Sinon.stub(GetNetworkTime, 'now').returns(1234);
const result = await LibSessionUtil.pendingChangesForGroup(groupPk);
expect(result.allOldHashes.size).to.be.equal(4);
// check that all of the hashes are there
@ -245,7 +245,7 @@ describe('LibSessionUtil pendingChangesForUs', () => {
.withArgs('ConvoInfoVolatileConfig')
.resolves(pushResultsConvo);
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(1234);
Sinon.stub(GetNetworkTime, 'now').returns(1234);
const result = await LibSessionUtil.pendingChangesForUs();
expect(needsPush.callCount).to.be.eq(4);
expect(needsPush.getCalls().map(m => m.args)).to.be.deep.eq([
@ -313,7 +313,7 @@ describe('LibSessionUtil pendingChangesForUs', () => {
.withArgs('ConvoInfoVolatileConfig')
.resolves(pushConvo);
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(1234);
Sinon.stub(GetNetworkTime, 'now').returns(1234);
const result = await LibSessionUtil.pendingChangesForUs();
expect(needsPush.callCount).to.be.eq(4);
expect(needsPush.getCalls().map(m => m.args)).to.be.deep.eq([

@ -285,7 +285,7 @@ describe('GroupSyncJob pushChangesToGroupSwarmIfNeeded', () => {
const member = validMembers(sodium);
const networkTimestamp = 4444;
const ttl = TTL_DEFAULT.TTL_CONFIG;
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(networkTimestamp);
Sinon.stub(GetNetworkTime, 'now').returns(networkTimestamp);
pendingChangesForGroupStub.resolves({
messages: [info, member],
allOldHashes: new Set('123'),

@ -281,7 +281,7 @@ describe('UserSyncJob pushChangesToUserSwarmIfNeeded', () => {
const contact = userChange(sodium, SnodeNamespaces.UserContacts, 123);
const networkTimestamp = 4444;
const ttl = TTL_DEFAULT.TTL_CONFIG;
Sinon.stub(GetNetworkTime, 'getNowWithNetworkOffset').returns(networkTimestamp);
Sinon.stub(GetNetworkTime, 'now').returns(networkTimestamp);
pendingChangesForUsStub.resolves({
messages: [profile, contact],

@ -79,10 +79,7 @@ async function checkIsFeatureReleased(featureName: FeatureNameTracked): Promise<
const featureAlreadyReleased = await getIsFeatureReleased(featureName);
// Is it time to release the feature based on the network timestamp?
if (
!featureAlreadyReleased &&
GetNetworkTime.getNowWithNetworkOffset() >= getFeatureReleaseTimestamp(featureName)
) {
if (!featureAlreadyReleased && GetNetworkTime.now() >= getFeatureReleaseTimestamp(featureName)) {
window.log.info(`[releaseFeature]: It is time to release ${featureName}. Releasing it now`);
await Storage.put(featureStorageItemId(featureName), true);
setIsFeatureReleasedCached(featureName, true);

Loading…
Cancel
Save