Merge pull request #2822 from Bilb/feat/prepare-blinded25-receiving

Feat/prepare blinded25 receiving
This commit is contained in:
Audric Ackermann 2023-07-14 12:25:31 +02:00 committed by GitHub
commit 7148afa61d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 56 additions and 42 deletions

View file

@ -6,7 +6,7 @@ import { MessageRenderingProps } from '../../../../models/messageType';
import { findCachedBlindedMatchOrLookItUp } from '../../../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { getConversationController } from '../../../../session/conversations';
import { getSodiumRenderer } from '../../../../session/crypto';
import { PubKey } from '../../../../session/types';
import { KeyPrefixType, PubKey } from '../../../../session/types';
import { openConversationWithMessages } from '../../../../state/ducks/conversations';
import { updateUserDetailsModal } from '../../../../state/ducks/modalDialog';
import {
@ -61,7 +61,7 @@ export const MessageAvatar = (props: Props) => {
const userName = authorName || authorProfileName || sender;
const onMessageAvatarClick = useCallback(async () => {
if (isPublic && !PubKey.hasBlindedPrefix(sender)) {
if (isPublic && !PubKey.isBlinded(sender)) {
// public chat but session id not blinded. disable showing user details if we do not have an active convo with that user.
// an unactive convo with that user means that we never chatted with that id directyly, but only through a sogs
const convoWithSender = getConversationController().get(sender);
@ -84,6 +84,11 @@ export const MessageAvatar = (props: Props) => {
}
if (isPublic && selectedConvoKey) {
if (sender.startsWith(KeyPrefixType.blinded25)) {
window.log.info('onMessageAvatarClick: blinded25 convo click are disabled currently...');
return;
}
const convoOpen = getConversationController().get(selectedConvoKey);
const room = OpenGroupData.getV2OpenGroupRoom(convoOpen.id);
let privateConvoToOpen = sender;

View file

@ -357,7 +357,7 @@ export const CopyMenuItem = (): JSX.Element | null => {
export const MarkAllReadMenuItem = (): JSX.Element | null => {
const convoId = useConvoIdFromContext();
const isIncomingRequest = useIsIncomingRequest(convoId);
if (!isIncomingRequest && !PubKey.hasBlindedPrefix(convoId)) {
if (!isIncomingRequest && !PubKey.isBlinded(convoId)) {
return (
<Item onClick={() => markAllReadByConvoId(convoId)}>{window.i18n('markAllAsRead')}</Item>
);
@ -379,7 +379,7 @@ export const BlockMenuItem = (): JSX.Element | null => {
const isPrivate = useIsPrivate(convoId);
const isIncomingRequest = useIsIncomingRequest(convoId);
if (!isMe && isPrivate && !isIncomingRequest && !PubKey.hasBlindedPrefix(convoId)) {
if (!isMe && isPrivate && !isIncomingRequest && !PubKey.isBlinded(convoId)) {
const blockTitle = isBlocked ? window.i18n('unblock') : window.i18n('block');
const blockHandler = isBlocked
? () => unblockConvoById(convoId)

View file

@ -101,7 +101,7 @@ export function useIsBlinded(convoId?: string) {
if (!convoId) {
return false;
}
return Boolean(PubKey.hasBlindedPrefix(convoId));
return Boolean(PubKey.isBlinded(convoId));
}
export function useHasNickname(convoId?: string) {

View file

@ -532,8 +532,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
);
const hasIncomingMessages = incomingMessageCount > 0;
if (this.id.startsWith('15')) {
window.log.info('Sending a blinded message to this user: ', this.id);
if (PubKey.isBlinded(this.id)) {
window.log.info('Sending a blinded message react to this user: ', this.id);
await this.sendBlindedMessageRequest(chatMessageParams);
return;
}
@ -1674,7 +1674,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
);
const hasIncomingMessages = incomingMessageCount > 0;
if (this.id.startsWith('15')) {
if (PubKey.isBlinded(this.id)) {
window.log.info('Sending a blinded message to this user: ', this.id);
await this.sendBlindedMessageRequest(chatMessageParams);
return;
@ -1778,7 +1778,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const ourSignKeyBytes = await UserUtils.getUserED25519KeyPairBytes();
const groupUrl = this.getSogsOriginMessage();
if (!PubKey.hasBlindedPrefix(this.id)) {
if (!PubKey.isBlinded(this.id)) {
window?.log?.warn('sendBlindedMessageRequest - convo is not a blinded one');
return;
}
@ -1826,7 +1826,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
this.set({ active_at: Date.now(), isApproved: true });
// TODO we need to add support for sending blinded25 message request in addition to the legacy blinded15
await getMessageQueue().sendToOpenGroupV2BlindedRequest({
encryptedContent: encryptedMsg,
roomInfos: roomInfo,

View file

@ -1279,7 +1279,7 @@ export function findAndFormatContact(pubkey: string): FindAndFormatContactType {
if (
pubkey === UserUtils.getOurPubKeyStrFromCache() ||
(pubkey && pubkey.startsWith('15') && isUsAnySogsFromCache(pubkey))
(pubkey && PubKey.isBlinded(pubkey) && isUsAnySogsFromCache(pubkey))
) {
profileName = window.i18n('you');
isMe = true;

View file

@ -1676,7 +1676,7 @@ function updateToSessionSchemaVersion31(currentVersion: number, db: BetterSqlite
// this filter is based on the `isContactToStoreInWrapper` function. Note, blocked contacts won't be added to the wrapper at first, but will on the first start
const contactsToWriteInWrapper = db
.prepare(
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND active_at > 0 AND priority <> ${CONVERSATION_PRIORITIES.hidden} AND (didApproveMe OR isApproved) AND id <> '$us' AND id NOT LIKE '15%' ;`
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND active_at > 0 AND priority <> ${CONVERSATION_PRIORITIES.hidden} AND (didApproveMe OR isApproved) AND id <> '$us' AND id NOT LIKE '15%' AND id NOT LIKE '25%' ;`
)
.all({
us: publicKeyHex,

View file

@ -145,8 +145,8 @@ export function tryMatchBlindWithStandardKey(
throw new Error('standardKey must be a standard key (starting with 05)');
}
if (!blindedSessionId.startsWith(KeyPrefixType.blinded)) {
throw new Error('blindedKey must be a blinded key (starting with 15)');
if (!PubKey.isBlinded(blindedSessionId)) {
throw new Error('blindedKey must be a blinded key (starting with 15 or 25)');
}
// We don't want to stop iterating even if an error happens while looking for a blind/standard match.
@ -204,7 +204,7 @@ function findNotCachedBlindingMatch(
// we iterate only over the convos private, approved, and which have an unblinded id.
const foundConvoMatchingBlindedPubkey = getConversationController()
.getConversations()
.filter(m => m.isPrivate() && m.isApproved() && !PubKey.hasBlindedPrefix(m.id))
.filter(m => m.isPrivate() && m.isApproved() && !PubKey.isBlinded(m.id))
.find(m => {
return tryMatchBlindWithStandardKey(m.id, blindedId, serverPublicKey, sodium);
});
@ -214,13 +214,13 @@ function findNotCachedBlindingMatch(
/**
* This function returns true if the given blindedId matches our own blinded id on any pysogs.
* If the given pubkey is not blinded, it returns true if it is our naked SessionID.
* If the given pubkey is not blinded, it returns true if it is our naked SessionID.
* It can be used to replace mentions with the @You syntax and for the quotes too
*/
export function isUsAnySogsFromCache(blindedOrNakedId: string): boolean {
const usUnblinded = UserUtils.getOurPubKeyStrFromCache();
if (!PubKey.hasBlindedPrefix(blindedOrNakedId)) {
if (!PubKey.isBlinded(blindedOrNakedId)) {
return blindedOrNakedId === usUnblinded;
}
const found = assertLoaded().find(
@ -268,7 +268,7 @@ function findNotCachedBlindedConvoFromUnblindedKey(
serverPublicKey: string,
sodium: LibSodiumWrappers
): Array<ConversationModel> {
if (PubKey.hasBlindedPrefix(unblindedID)) {
if (PubKey.isBlinded(unblindedID)) {
throw new Error(
'findNotCachedBlindedConvoFromUnblindedKey unblindedID is supposed to be unblinded!'
);
@ -279,7 +279,7 @@ function findNotCachedBlindedConvoFromUnblindedKey(
const foundConvosForThisServerPk =
getConversationController()
.getConversations()
.filter(m => m.isPrivate() && PubKey.hasBlindedPrefix(m.id) && m.isActive())
.filter(m => m.isPrivate() && PubKey.isBlinded(m.id) && m.isActive())
.filter(m => {
return tryMatchBlindWithStandardKey(unblindedID, m.id, serverPublicKey, sodium);
}) || [];
@ -302,7 +302,7 @@ export async function findCachedBlindedMatchOrLookItUp(
serverPubKey: string,
sodium: LibSodiumWrappers
): Promise<string | undefined> {
if (!PubKey.hasBlindedPrefix(blindedId)) {
if (!PubKey.isBlinded(blindedId)) {
return blindedId;
}
const found = getCachedNakedKeyFromBlinded(blindedId, serverPubKey);
@ -333,7 +333,7 @@ export function findCachedBlindedIdFromUnblinded(
unblindedId: string,
serverPubKey: string
): string | undefined {
if (PubKey.hasBlindedPrefix(unblindedId)) {
if (PubKey.isBlinded(unblindedId)) {
throw new Error('findCachedBlindedIdFromUnblinded needs an unblindedID');
}
const found = assertLoaded().find(
@ -351,7 +351,7 @@ export async function findCachedOurBlindedPubkeyOrLookItUp(
): Promise<string> {
const ourNakedSessionID = UserUtils.getOurPubKeyStrFromCache();
if (PubKey.hasBlindedPrefix(ourNakedSessionID)) {
if (PubKey.isBlinded(ourNakedSessionID)) {
throw new Error('findCachedBlindedIdFromUnblindedOrLookItUp needs a unblindedID');
}
let found = findCachedBlindedIdFromUnblinded(ourNakedSessionID, serverPubKey);
@ -402,7 +402,7 @@ export function findCachedBlindedMatchOrLookupOnAllServers(
unblindedId: string,
sodium: LibSodiumWrappers
): Array<ConversationModel> {
if (PubKey.hasBlindedPrefix(unblindedId)) {
if (PubKey.isBlinded(unblindedId)) {
throw new Error('findCachedBlindedMatchOrLookupOnAllServers needs an unblindedId');
}

View file

@ -63,7 +63,8 @@ async function getOpenGroupHeaders(data: {
const blindingValues = getBlindingValues(serverPK, signingKeys, sodium);
ka = blindingValues.secretKey;
kA = blindingValues.publicKey;
pubkey = `${KeyPrefixType.blinded}${toHex(kA)}`;
// TODO we will need to add the support of blinded25 here
pubkey = `${KeyPrefixType.blinded15}${toHex(kA)}`;
} else {
pubkey = `${KeyPrefixType.unblinded}${toHex(signingKeys.pubKeyBytes)}`;
}
@ -151,7 +152,8 @@ const getBlindedPubKey = (
sodium: LibSodiumWrappers
): string => {
const blindedPubKeyBytes = getBlindingValues(serverPK, signingKeys, sodium);
return `${KeyPrefixType.blinded}${to_hex(blindedPubKeyBytes.publicKey)}`;
// TODO we will need to add the support of blinded25 here
return `${KeyPrefixType.blinded15}${to_hex(blindedPubKeyBytes.publicKey)}`;
};
const getBlindingValues = (

View file

@ -187,7 +187,7 @@ export class ConversationController {
'getConversationController().deleteBlindedContact() needs complete initial fetch'
);
}
if (!PubKey.hasBlindedPrefix(blindedId)) {
if (!PubKey.isBlinded(blindedId)) {
throw new Error('deleteBlindedContact allow accepts blinded id');
}
window.log.info(`deleteBlindedContact with ${blindedId}`);

View file

@ -139,7 +139,8 @@ export class MessageQueue {
recipientBlindedId: string;
}) {
try {
if (!PubKey.hasBlindedPrefix(recipientBlindedId)) {
// TODO we will need to add the support for blinded25 messages requests
if (!PubKey.isBlinded(recipientBlindedId)) {
throw new Error('sendToOpenGroupV2BlindedRequest needs a blindedId');
}
const { serverTimestamp, serverId } = await MessageSender.sendToOpenGroupV2BlindedRequest(

View file

@ -10,9 +10,15 @@ export enum KeyPrefixType {
*/
standard = '05',
/**
* used for participants in open groups
* used for participants in open groups (legacy blinding logic)
*/
blinded = '15',
blinded15 = '15',
/**
* used for participants in open groups (new blinding logic)
*/
blinded25 = '25',
/**
* used for participants in open groups
*/
@ -32,7 +38,7 @@ export class PubKey {
public static readonly PREFIX_GROUP_TEXTSECURE = '__textsecure_group__!';
// prettier-ignore
private static readonly regex: RegExp = new RegExp(
`^(${PubKey.PREFIX_GROUP_TEXTSECURE})?(${KeyPrefixType.standard}|${KeyPrefixType.blinded}|${KeyPrefixType.unblinded}|${KeyPrefixType.groupV3})?(${PubKey.HEX}{64}|${PubKey.HEX}{32})$`
`^(${PubKey.PREFIX_GROUP_TEXTSECURE})?(${KeyPrefixType.standard}|${KeyPrefixType.blinded15}|${KeyPrefixType.blinded25}|${KeyPrefixType.unblinded}|${KeyPrefixType.groupV3})?(${PubKey.HEX}{64}|${PubKey.HEX}{32})$`
);
/**
* If you want to update this regex. Be sure that those are matches ;
@ -146,18 +152,19 @@ export class PubKey {
/**
* @param keyWithOrWithoutPrefix Key with or without prefix
* @returns If key is the correct length and has a supported prefix 05 or 15
* @returns If key is the correct length and has a supported prefix 05, 15, 25
*/
public static isValidPrefixAndLength(keyWithOrWithoutPrefix: string): boolean {
return (
keyWithOrWithoutPrefix.length === 66 &&
(keyWithOrWithoutPrefix.startsWith(KeyPrefixType.blinded) ||
(keyWithOrWithoutPrefix.startsWith(KeyPrefixType.blinded15) ||
keyWithOrWithoutPrefix.startsWith(KeyPrefixType.blinded25) ||
keyWithOrWithoutPrefix.startsWith(KeyPrefixType.standard))
);
}
/**
* This removes the 05 or 15 prefix from a Pubkey which have it and have a length of 66
* This removes the 05, 15 or 25 prefix from a Pubkey which have it and have a length of 66
* @param keyWithOrWithoutPrefix the key with or without the prefix
*/
public static removePrefixIfNeeded(keyWithOrWithoutPrefix: string): string {
@ -230,8 +237,8 @@ export class PubKey {
return fromHexToArray(PubKey.removePrefixIfNeeded(this.key));
}
public static hasBlindedPrefix(key: string) {
return key.startsWith(KeyPrefixType.blinded);
public static isBlinded(key: string) {
return key.startsWith(KeyPrefixType.blinded15) || key.startsWith(KeyPrefixType.blinded25);
}
public static isClosedGroupV3(key: string) {

View file

@ -29,9 +29,7 @@ const mappedContactWrapperValues = new Map<string, ContactInfo>();
* We want to sync the message request status so we need to allow a contact even if it's not approved, did not approve us and is not blocked.
*/
function isContactToStoreInWrapper(convo: ConversationModel): boolean {
return (
!convo.isMe() && convo.isPrivate() && convo.isActive() && !PubKey.hasBlindedPrefix(convo.id)
);
return !convo.isMe() && convo.isPrivate() && convo.isActive() && !PubKey.isBlinded(convo.id);
}
/**

View file

@ -204,7 +204,7 @@ const getValidContacts = (convos: Array<ConversationModel>) => {
c.getRealSessionUsername() &&
c.isPrivate() &&
c.isApproved() &&
!PubKey.hasBlindedPrefix(c.get('id'))
!PubKey.isBlinded(c.get('id'))
);
const contacts = contactsModels.map(c => {

View file

@ -785,7 +785,7 @@ export const getMessageQuoteProps = createSelector(
const isFromMe = isUsAnySogsFromCache(author) || false;
// NOTE the quote lookup map always stores our messages using the unblinded pubkey
if (isFromMe && PubKey.hasBlindedPrefix(author)) {
if (isFromMe && PubKey.isBlinded(author)) {
author = UserUtils.getOurPubKeyStrFromCache();
}

View file

@ -418,7 +418,7 @@ describe('knownBlindedKeys', () => {
it('throws if blindedSessionId is not standard', () => {
expect(() => {
tryMatchBlindWithStandardKey(realSessionId, realSessionId, serverPublicKey, sodium);
}).to.throw('blindedKey must be a blinded key (starting with 15)');
}).to.throw('blindedKey must be a blinded key (starting with 15 or 25)');
});
it('returns true if those keys are not matching blind & naked', () => {

View file

@ -141,7 +141,8 @@ async function verifySignature(
}
const messageData = fromBase64ToUint8Array(messageBase64);
const signature = fromBase64ToUint8Array(signatureBase64);
const isBlindedSender = senderPubKey.startsWith('15');
// blinded15 or blinded25 are the same for the verifySignature logic
const isBlindedSender = senderPubKey.startsWith('15') || senderPubKey.startsWith('25');
const pubkeyWithoutPrefix = senderPubKey.slice(2);
const pubkeyBytes = fromHexToArray(pubkeyWithoutPrefix);