From 1a2d1484823cc4170b3da85bf8d7a08f287dab3b Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 5 Mar 2021 16:55:25 +1100 Subject: [PATCH 1/4] add attachment padding --- ts/receiver/attachments.ts | 14 ++++++-- ts/session/utils/Attachments.ts | 57 +++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/ts/receiver/attachments.ts b/ts/receiver/attachments.ts index c67497594..598436dec 100644 --- a/ts/receiver/attachments.ts +++ b/ts/receiver/attachments.ts @@ -3,6 +3,7 @@ import _ from 'lodash'; import { MessageModel } from '../models/message'; import { saveMessage } from '../../ts/data/data'; import { fromBase64ToArrayBuffer } from '../session/utils/String'; +import { AttachmentUtils } from '../session/utils'; export async function downloadAttachment(attachment: any) { const serverUrl = new URL(attachment.url).origin; @@ -70,9 +71,16 @@ export async function downloadAttachment(attachment: any) { ); if (!size || size !== data.byteLength) { - throw new Error( - `downloadAttachment: Size ${size} did not match downloaded attachment size ${data.byteLength}` - ); + // we might have padding, check that all the remaining bytes are padding bytes + // otherwise we have an error. + if (AttachmentUtils.isLeftOfBufferPaddingOnly(data, size)) { + // we can safely remove the padding + data = data.slice(0, size); + } else { + throw new Error( + `downloadAttachment: Size ${size} did not match downloaded attachment size ${data.byteLength}` + ); + } } } diff --git a/ts/session/utils/Attachments.ts b/ts/session/utils/Attachments.ts index f81ec0625..97e99b4e5 100644 --- a/ts/session/utils/Attachments.ts +++ b/ts/session/utils/Attachments.ts @@ -14,6 +14,7 @@ interface UploadParams { openGroup?: OpenGroup; isAvatar?: boolean; isRaw?: boolean; + shouldPad?: boolean; } interface RawPreview { @@ -37,6 +38,8 @@ interface RawQuote { // tslint:disable-next-line: no-unnecessary-class export class AttachmentUtils { + public static readonly PADDING_BYTE = 0; + private constructor() {} public static getDefaultServer(): LokiAppDotNetServerInterface { @@ -44,7 +47,13 @@ export class AttachmentUtils { } public static async upload(params: UploadParams): Promise { - const { attachment, openGroup, isAvatar = false, isRaw = false } = params; + const { + attachment, + openGroup, + isAvatar = false, + isRaw = false, + shouldPad = false, + } = params; if (typeof attachment !== 'object' || attachment == null) { throw new Error('Invalid attachment passed.'); } @@ -83,8 +92,12 @@ export class AttachmentUtils { server = this.getDefaultServer(); pointer.key = new Uint8Array(crypto.randomBytes(64)); const iv = new Uint8Array(crypto.randomBytes(16)); + + const dataToEncrypt = !shouldPad + ? attachment.data + : AttachmentUtils.addAttachmentPadding(attachment.data); const data = await window.textsecure.crypto.encryptAttachment( - attachment.data, + dataToEncrypt, pointer.key.buffer, iv.buffer ); @@ -126,6 +139,7 @@ export class AttachmentUtils { this.upload({ attachment, openGroup, + shouldPad: true, }) ); @@ -181,4 +195,43 @@ export class AttachmentUtils { attachments, }; } + + public static isLeftOfBufferPaddingOnly( + data: ArrayBuffer, + unpaddedExpectedSize: number + ): boolean { + // to have a padding we must have a strictly longer length expected + if (data.byteLength <= unpaddedExpectedSize) { + return false; + } + const dataUint = new Uint8Array(data); + for (let i = unpaddedExpectedSize; i < data.byteLength; i++) { + if (dataUint[i] !== this.PADDING_BYTE) { + return false; + } + } + + return true; + } + + private static addAttachmentPadding(data: ArrayBuffer): ArrayBuffer { + const originalUInt = new Uint8Array(data); + + const paddedSize = Math.max( + 541, + Math.floor( + Math.pow( + 1.05, + Math.ceil(Math.log(originalUInt.length) / Math.log(1.05)) + ) + ) + ); + const paddedData = new ArrayBuffer(paddedSize); + const paddedUInt = new Uint8Array(paddedData); + + paddedUInt.fill(AttachmentUtils.PADDING_BYTE, originalUInt.length); + paddedUInt.set(originalUInt); + + return paddedUInt.buffer; + } } From d98700b17f95ccca11ae81bbf14187d4264cea52 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 14 Apr 2021 14:15:02 +1000 Subject: [PATCH 2/4] allow unpadding of attachments if needed currently, the padding of attachments is disabled behind a featureFlags --- preload.js | 1 + ts/components/UserDetailsDialog.tsx | 2 +- ts/session/utils/Attachments.ts | 7 ++++--- ts/session/utils/JobQueue.ts | 2 +- ts/window.d.ts | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/preload.js b/preload.js index 2f250136d..24757e0d0 100644 --- a/preload.js +++ b/preload.js @@ -62,6 +62,7 @@ window.lokiFeatureFlags = { useFileOnionRequestsV2: true, // more compact encoding of files in response onionRequestHops: 3, useRequestEncryptionKeyPair: false, + padOutgoingAttachments: false, }; if ( diff --git a/ts/components/UserDetailsDialog.tsx b/ts/components/UserDetailsDialog.tsx index 70e4e0301..70276c53d 100644 --- a/ts/components/UserDetailsDialog.tsx +++ b/ts/components/UserDetailsDialog.tsx @@ -64,7 +64,7 @@ export class UserDetailsDialog extends React.Component { private renderAvatar() { const { avatarPath, pubkey, profileName } = this.props; const size = this.state.isEnlargedImageShown ? 300 : 80; - const userName = name || profileName || pubkey; + const userName = profileName || pubkey; return ( = (() => PromiseLike) | (() => ResultType); // TODO: This needs to replace js/modules/job_queue.js export class JobQueue { - private pending: Promise = Promise.resolve(); + private pending?: Promise = Promise.resolve(); private readonly jobs: Map> = new Map(); public has(id: string): boolean { diff --git a/ts/window.d.ts b/ts/window.d.ts index ea0eb1920..e3a1f6e1f 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -62,6 +62,7 @@ declare global { useFileOnionRequestsV2: boolean; onionRequestHops: number; useRequestEncryptionKeyPair: boolean; + padOutgoingAttachments: boolean; }; lokiFileServerAPI: LokiFileServerInstance; lokiMessageAPI: LokiMessageInterface; From e035b9176c4fa19f6a50a42692dfb05a1deecfac Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 14 Apr 2021 14:17:11 +1000 Subject: [PATCH 3/4] bump to 1.5.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf335e7f1..fcd86d8f7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "session-desktop", "productName": "Session", "description": "Private messaging from your desktop", - "version": "1.5.3", + "version": "1.5.4", "license": "GPL-3.0", "author": { "name": "Loki Project", From 6a1d0e93a345fcf292be3d73b5a7ec4f4f0cff12 Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Wed, 14 Apr 2021 19:41:54 -0700 Subject: [PATCH 4/4] Make 502 retry --- ts/session/snode_api/onions.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ts/session/snode_api/onions.ts b/ts/session/snode_api/onions.ts index b10c70f7c..0f0c46d10 100644 --- a/ts/session/snode_api/onions.ts +++ b/ts/session/snode_api/onions.ts @@ -238,6 +238,13 @@ const processOnionResponse = async ( // FIXME: 401/500 handling? + // detect SNode is deregisted? + if (response.status === 502) { + log.warn(`(${reqIdx}) [path] Got 502: snode not found`); + + return RequestError.BAD_PATH; + } + // detect SNode is not ready (not in swarm; not done syncing) if (response.status === 503) { log.warn(`(${reqIdx}) [path] Got 503: snode not ready`);