You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
import { AbortSignal } from 'abort-controller';
|
|
import { APPLICATION_JSON, APPLICATION_OCTET_STREAM } from '../../../../types/MIME';
|
|
import { OnionSending } from '../../../onions/onionSend';
|
|
import { UserUtils } from '../../../utils';
|
|
import { OpenGroupCapabilityRequest } from '../opengroupV2/ApiUtil';
|
|
import { OpenGroupMessageV2 } from '../opengroupV2/OpenGroupMessageV2';
|
|
import {
|
|
OpenGroupPollingUtils,
|
|
OpenGroupRequestHeaders,
|
|
} from '../opengroupV2/OpenGroupPollingUtils';
|
|
import { batchGlobalIsSuccess, parseBatchGlobalStatusCode } from './sogsV3BatchPoll';
|
|
|
|
export function addJsonContentTypeToHeaders(
|
|
headers: OpenGroupRequestHeaders
|
|
): OpenGroupRequestHeaders {
|
|
return { ...headers, 'Content-Type': APPLICATION_JSON };
|
|
}
|
|
export function addBinaryContentTypeToHeaders(
|
|
headers: OpenGroupRequestHeaders
|
|
): OpenGroupRequestHeaders {
|
|
return { ...headers, 'Content-Type': APPLICATION_OCTET_STREAM };
|
|
}
|
|
|
|
export type OpenGroupSendMessageRequest = OpenGroupCapabilityRequest & {
|
|
blinded: boolean;
|
|
};
|
|
|
|
export const sendSogsMessageOnionV4 = async (
|
|
serverUrl: string,
|
|
room: string,
|
|
abortSignal: AbortSignal,
|
|
message: OpenGroupMessageV2,
|
|
blinded: boolean
|
|
): Promise<OpenGroupMessageV2> => {
|
|
const allValidRoomInfos = OpenGroupPollingUtils.getAllValidRoomInfos(serverUrl, new Set([room]));
|
|
if (!allValidRoomInfos?.length) {
|
|
window?.log?.info('getSendMessageRequest: no valid roominfos got.');
|
|
throw new Error(`Could not find sogs pubkey of url:${serverUrl}`);
|
|
}
|
|
const endpoint = `/room/${room}/message`;
|
|
const method = 'POST';
|
|
const serverPubkey = allValidRoomInfos[0].serverPublicKey;
|
|
const ourKeyPair = await UserUtils.getIdentityKeyPair();
|
|
|
|
// if we are sending a blinded message, we have to sign it with the derived keypair
|
|
// otherwise, we just sign it with our real keypair
|
|
const signedMessage = blinded
|
|
? await message.signWithBlinding(serverPubkey)
|
|
: await message.sign(ourKeyPair);
|
|
const json = signedMessage.toJson();
|
|
|
|
const stringifiedBody = JSON.stringify(json);
|
|
|
|
const result = await OnionSending.sendJsonViaOnionV4ToSogs({
|
|
serverUrl,
|
|
endpoint,
|
|
serverPubkey,
|
|
method,
|
|
abortSignal,
|
|
blinded,
|
|
stringifiedBody,
|
|
headers: null,
|
|
throwErrors: true,
|
|
});
|
|
|
|
if (!batchGlobalIsSuccess(result)) {
|
|
window?.log?.warn('sendSogsMessageWithOnionV4 Got unknown status code; res:', result);
|
|
throw new Error(
|
|
`sendSogsMessageOnionV4: invalid status code: ${parseBatchGlobalStatusCode(result)}`
|
|
);
|
|
}
|
|
|
|
if (!result) {
|
|
throw new Error('Could not postMessage, res is invalid');
|
|
}
|
|
const rawMessage = result.body as Record<string, any>;
|
|
if (!rawMessage) {
|
|
throw new Error('postMessage parsing failed');
|
|
}
|
|
|
|
const toParse = {
|
|
data: rawMessage.data,
|
|
server_id: rawMessage.id,
|
|
public_key: rawMessage.session_id,
|
|
timestamp: Math.floor(rawMessage.posted * 1000),
|
|
signature: rawMessage.signature,
|
|
};
|
|
|
|
// this will throw if the json is not valid
|
|
const parsed = OpenGroupMessageV2.fromJson(toParse);
|
|
return parsed;
|
|
};
|
|
|
|
export const sendMessageOnionV4BlindedRequest = async (
|
|
serverUrl: string,
|
|
room: string,
|
|
abortSignal: AbortSignal,
|
|
message: OpenGroupMessageV2,
|
|
recipientBlindedId: string
|
|
): Promise<{ serverId: number; serverTimestamp: number }> => {
|
|
const allValidRoomInfos = OpenGroupPollingUtils.getAllValidRoomInfos(serverUrl, new Set([room]));
|
|
if (!allValidRoomInfos?.length) {
|
|
window?.log?.info('getSendMessageRequest: no valid roominfos got.');
|
|
throw new Error(`Could not find sogs pubkey of url:${serverUrl}`);
|
|
}
|
|
const endpoint = `/inbox/${recipientBlindedId}`;
|
|
const method = 'POST';
|
|
const serverPubkey = allValidRoomInfos[0].serverPublicKey;
|
|
|
|
// if we are sending a blinded message, we have to sign it with the derived keypair
|
|
// otherwise, we just sign it with our real keypair
|
|
const signedMessage = await message.signWithBlinding(serverPubkey);
|
|
const json = signedMessage.toBlindedMessageRequestJson();
|
|
const stringifiedBody = JSON.stringify(json);
|
|
|
|
const result = await OnionSending.sendJsonViaOnionV4ToSogs({
|
|
serverUrl,
|
|
endpoint,
|
|
serverPubkey,
|
|
method,
|
|
abortSignal,
|
|
blinded: true,
|
|
stringifiedBody,
|
|
headers: null,
|
|
throwErrors: true,
|
|
});
|
|
|
|
if (!batchGlobalIsSuccess(result)) {
|
|
window?.log?.warn('sendMessageOnionV4BlindedRequest Got unknown status code; res:', result);
|
|
throw new Error(
|
|
`sendMessageOnionV4BlindedRequest: invalid status code: ${parseBatchGlobalStatusCode(result)}`
|
|
);
|
|
}
|
|
|
|
if (!result) {
|
|
throw new Error('Could not postMessage, res is invalid');
|
|
}
|
|
const rawMessage = result.body as Record<string, any>;
|
|
if (!rawMessage) {
|
|
throw new Error('postMessage parsing failed');
|
|
}
|
|
|
|
const serverId = rawMessage.id as number | undefined;
|
|
const serverTimestamp = rawMessage.posted_at as number | undefined;
|
|
if (!serverTimestamp || serverId === undefined) {
|
|
window.log.warn('Could not blinded message request, server returned invalid data:', rawMessage);
|
|
throw new Error('Could not blinded message request, server returned invalid data');
|
|
}
|
|
|
|
return { serverId, serverTimestamp: Math.floor(serverTimestamp * 1000) }; //timestamp are now returned with a seconds.ms syntax
|
|
};
|