From 5ec9722e002fd89b113a694e9e152a566dd2614c Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Mon, 8 Feb 2021 17:16:17 +1100
Subject: [PATCH] autobind typescript class methods with autobind

---
 AUDRICTOCLEAN.txt                   |  5 ---
 libtextsecure/account_manager.js    | 10 ------
 package.json                        |  1 +
 ts/models/conversation.ts           | 47 ++---------------------------
 ts/models/message.ts                |  9 ++++--
 ts/receiver/queuedJob.ts            |  3 +-
 ts/state/selectors/conversations.ts | 30 +++++++++++-------
 yarn.lock                           |  5 +++
 8 files changed, 35 insertions(+), 75 deletions(-)

diff --git a/AUDRICTOCLEAN.txt b/AUDRICTOCLEAN.txt
index 97cdd874c..b8b1465a9 100644
--- a/AUDRICTOCLEAN.txt
+++ b/AUDRICTOCLEAN.txt
@@ -25,8 +25,3 @@ ReadSyncs
 SyncMessage
 sendSyncMessage needs to be rewritten
 sendSyncMessageOnly to fix
-
-
-
-
-LONG_ATTAHCMENNT
diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js
index c6d699f4e..4c2f5da7e 100644
--- a/libtextsecure/account_manager.js
+++ b/libtextsecure/account_manager.js
@@ -169,16 +169,6 @@
 
       this.dispatchEvent(new Event('registration'));
     },
-    validatePubKeyHex(pubKey) {
-      const c = new window.models.Conversation({
-        id: pubKey,
-        type: 'private',
-      });
-      const validationError = c.validateNumber();
-      if (validationError) {
-        throw new Error(validationError);
-      }
-    },
   });
   textsecure.AccountManager = AccountManager;
 })();
diff --git a/package.json b/package.json
index 19a9a0477..8a597300e 100644
--- a/package.json
+++ b/package.json
@@ -66,6 +66,7 @@
     "@types/react-mic": "^12.4.1",
     "@types/styled-components": "^5.1.4",
     "abort-controller": "3.0.0",
+    "auto-bind": "^4.0.0",
     "backbone": "1.3.3",
     "blob-util": "1.3.0",
     "blueimp-canvas-to-blob": "3.14.0",
diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts
index 46bb00d23..2fa60363b 100644
--- a/ts/models/conversation.ts
+++ b/ts/models/conversation.ts
@@ -21,6 +21,7 @@ import { SignalService } from '../protobuf';
 import { MessageCollection, MessageModel } from './message';
 import * as Data from '../../js/modules/data';
 import { MessageAttributesOptionals } from './messageType';
+import autoBind from 'auto-bind';
 
 export interface OurLokiProfile {
   displayName: string;
@@ -152,6 +153,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
     this.messageCollection = new MessageCollection([], {
       conversation: this,
     });
+    autoBind(this);
 
     this.throttledBumpTyping = _.throttle(this.bumpTyping, 300);
     this.updateLastMessage = _.throttle(
@@ -177,8 +179,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
     if (this.isPublic()) {
       this.set('profileSharing', true);
     }
-    this.unset('hasFetchedProfile');
-    this.unset('tokens');
 
     this.typingRefreshTimer = null;
     this.typingPauseTimer = null;
@@ -549,49 +549,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
     return window.Signal.Data.getUnreadCountByConversation(this.id);
   }
 
-  public validate(attributes: any) {
-    const required = ['id', 'type'];
-    const missing = _.filter(required, attr => !attributes[attr]);
-    if (missing.length) {
-      return `Conversation must have ${missing}`;
-    }
-
-    if (attributes.type !== 'private' && attributes.type !== 'group') {
-      return `Invalid conversation type: ${attributes.type}`;
-    }
-
-    const error = this.validateNumber();
-    if (error) {
-      return error;
-    }
-
-    return null;
-  }
-
-  public validateNumber() {
-    if (!this.id) {
-      return 'Invalid ID';
-    }
-    if (!this.isPrivate()) {
-      return null;
-    }
-
-    // Check if it's hex
-    const isHex = this.id.replace(/[\s]*/g, '').match(/^[0-9a-fA-F]+$/);
-    if (!isHex) {
-      return 'Invalid Hex ID';
-    }
-
-    // Check if the pubkey length is 33 and leading with 05 or of length 32
-    const len = this.id.length;
-    if ((len !== 33 * 2 || !/^05/.test(this.id)) && len !== 32 * 2) {
-      return 'Invalid Pubkey Format';
-    }
-
-    this.set({ id: this.id });
-    return null;
-  }
-
   public queueJob(callback: any) {
     // tslint:disable-next-line: no-promise-as-boolean
     const previous = this.pending || Promise.resolve();
diff --git a/ts/models/message.ts b/ts/models/message.ts
index 8a1bb1e27..6db4f4427 100644
--- a/ts/models/message.ts
+++ b/ts/models/message.ts
@@ -20,6 +20,7 @@ import {
   MessageAttributesOptionals,
 } from './messageType';
 
+import autoBind from 'auto-bind';
 export class MessageModel extends Backbone.Model<MessageAttributes> {
   public propsForTimerNotification: any;
   public propsForGroupNotification: any;
@@ -45,6 +46,8 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
     this.on('change:expireTimer', this.setToExpire);
     // this.on('expired', this.onExpired);
     void this.setToExpire();
+    autoBind(this);
+    this.markRead = this.markRead.bind(this);
     // Keep props ready
     const generateProps = (triggerEvent = true) => {
       if (this.isExpirationTimerUpdate()) {
@@ -95,7 +98,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
     return !!this.get('unread');
   }
 
-  // Important to allow for this.unset('unread'), save to db, then fetch()
+  // Important to allow for this.set({ unread}), save to db, then fetch()
   // to propagate. We don't want the unset key in the db so our unread index
   // stays small.
   public merge(model: any) {
@@ -103,7 +106,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
 
     const { unread } = attributes;
     if (unread === undefined) {
-      this.unset('unread');
+      this.set({ unread: false });
     }
 
     this.set(attributes);
@@ -1323,7 +1326,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
   }
 
   public async markRead(readAt: number) {
-    this.unset('unread');
+    this.set({ unread: false });
 
     if (this.get('expireTimer') && !this.get('expirationStartTimestamp')) {
       const expirationStartTimestamp = Math.min(
diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts
index 2e3e166d9..92ab4d9d6 100644
--- a/ts/receiver/queuedJob.ts
+++ b/ts/receiver/queuedJob.ts
@@ -294,7 +294,8 @@ function updateReadStatus(
     }
   }
   if (readSync || message.isExpirationTimerUpdate()) {
-    message.unset('unread');
+    message.set({ unread: false });
+
     // This is primarily to allow the conversation to mark all older
     // messages as read, as is done when we receive a read sync for
     // a message we already know about.
diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts
index 20f5d85da..aa0e5200a 100644
--- a/ts/state/selectors/conversations.ts
+++ b/ts/state/selectors/conversations.ts
@@ -1,6 +1,5 @@
 import { createSelector } from 'reselect';
 
-import { LocalizerType } from '../../types/Util';
 import { StateType } from '../reducer';
 import {
   ConversationLookupType,
@@ -11,6 +10,7 @@ import {
 
 import { getIntl, getOurNumber } from './user';
 import { BlockedNumberController } from '../../util';
+import { LocalizerType } from '../../types/Util';
 
 export const getConversations = (state: StateType): ConversationsStateType =>
   state.conversations;
@@ -49,13 +49,15 @@ export const getMessagesOfSelectedConversation = createSelector(
   (state: ConversationsStateType): Array<MessageTypeInConvo> => state.messages
 );
 
-function getConversationTitle(conversation: ConversationType): string {
+function getConversationTitle(
+  conversation: ConversationType,
+  i18n: LocalizerType
+): string {
   if (conversation.name) {
     return conversation.name;
   }
 
   if (conversation.type === 'group') {
-    const { i18n } = window;
     return i18n('unknown');
   }
   return conversation.id;
@@ -65,19 +67,25 @@ const collator = new Intl.Collator();
 
 export const _getConversationComparator = (i18n: LocalizerType) => {
   return (left: ConversationType, right: ConversationType): number => {
-    const leftTimestamp = left.timestamp;
-    const rightTimestamp = right.timestamp;
-    if (leftTimestamp && !rightTimestamp) {
+    const leftActiveAt = left.activeAt;
+    const rightActiveAt = right.activeAt;
+    if (leftActiveAt && !rightActiveAt) {
       return -1;
     }
-    if (rightTimestamp && !leftTimestamp) {
+    if (rightActiveAt && !leftActiveAt) {
       return 1;
     }
-    if (leftTimestamp && rightTimestamp && leftTimestamp !== rightTimestamp) {
-      return rightTimestamp - leftTimestamp;
+    if (leftActiveAt && rightActiveAt && leftActiveAt !== rightActiveAt) {
+      return rightActiveAt - leftActiveAt;
     }
-    const leftTitle = getConversationTitle(left).toLowerCase();
-    const rightTitle = getConversationTitle(right).toLowerCase();
+    const leftTitle = getConversationTitle(
+      left,
+      i18n || window?.i18n
+    ).toLowerCase();
+    const rightTitle = getConversationTitle(
+      right,
+      i18n || window?.i18n
+    ).toLowerCase();
 
     return collator.compare(leftTitle, rightTitle);
   };
diff --git a/yarn.lock b/yarn.lock
index f759664d2..4e3cb28b3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1308,6 +1308,11 @@ atob@^2.1.2:
   resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
   integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
 
+auto-bind@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
+  integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
+
 autoprefixer@^6.3.1:
   version "6.7.7"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"