tomer8007 / whatsapp-web-incognito

A Chrome extension that disables read receipts and presence updates on WhatsApp Web
MIT License
312 stars 74 forks source link

A new "Edited" Whatsapp feature #126

Closed neo2701 closed 12 months ago

neo2701 commented 1 year ago

Hi, can u implement feature for saving message for edited message? I tried to create it but didn't find the edited message on received message. Thanks!

message : {
    "conversation": "",
    "senderKeyDistributionMessage": null,
    "imageMessage": null,
    "contactMessage": null,
    "locationMessage": null,
    "extendedTextMessage": null,
    "documentMessage": null,
    "audioMessage": null,
    "videoMessage": null,
    "call": null,
    "chat": null,
    "protocolMessage": null,
    "contactsArrayMessage": null,
    "highlyStructuredMessage": null,
    "fastRatchetKeySenderKeyDistributionMessage": null,
    "sendPaymentMessage": null,
    "liveLocationMessage": null,
    "requestPaymentMessage": null,
    "declinePaymentRequestMessage": null,
    "cancelPaymentRequestMessage": null,
    "templateMessage": null,
    "stickerMessage": null,
    "groupInviteMessage": null,
    "templateButtonReplyMessage": null,
    "productMessage": null,
    "deviceSentMessage": null,
    "messageContextInfo": {
        "deviceListMetadata": {
            "senderKeyHash": {
                "0": 237,
                "1": 186,
                "2": 199,
                "3": 218,
                "4": 222,
                "5": 167,
                "6": 198,
                "7": 233,
                "8": 147,
                "9": 170
            },
            "senderTimestamp": 1686155018,
            "senderKeyIndexes": [],
            "recipientKeyHash": {
                "0": 148,
                "1": 25,
                "2": 127,
                "3": 228,
                "4": 147,
                "5": 72,
                "6": 126,
                "7": 47,
                "8": 198,
                "9": 140
            },
            "recipientTimestamp": 1686832994,
            "recipientKeyIndexes": []
        },
        "deviceListMetadataVersion": 2
    },
    "listMessage": null,
    "viewOnceMessage": null,
    "orderMessage": null,
    "listResponseMessage": null,
    "ephemeralMessage": null,
    "invoiceMessage": null,
    "buttonsMessage": null,
    "buttonsResponseMessage": null,
    "paymentInviteMessage": null,
    "interactiveMessage": null,
    "reactionMessage": null,
    "stickerSyncRmrMessage": null
},
{
    "tag": "message",
    "attrs": {
        "from": "62851*****:51@c.us",
        "type": "text",
        "edit": "1",
        "id": "3EB08757F87369C13969F0",
        "sender_lid": "*****.1@c.us",
        "notify": "Neo",
        "t": "1686834494"
    },
    "content": [
        {
            "tag": "enc",
            "attrs": {
                "v": "2",
                "type": "msg",
                "decrypt-fail": "hide"
            },
            "content": {}
        }
    ]
}
tomer8007 commented 1 year ago

Do you mean saving the versions history of edited messages? Adding new features such as this is not so much of my priority right now, unless more people will show demand for them. Maybe in the future

neo2701 commented 1 year ago

Yes, Exactly. I want to implement it myself but i couldn't found the object of edited message..

tomer8007 commented 1 year ago

Perhaps they're sending a REVOKE message first just like they do for deleted messages. I assume you have WADebugMode on.

neo2701 commented 1 year ago

They just send this node with message tag

{
    "tag": "message",
    "attrs": {
        "from": "62****:51@c.us",
        "type": "text",
        "edit": "1",
        "id": "3EB07B07BB4AB8459ECF63",
        "sender_lid": "***.1@c.us",
        "notify": "Neo",
        "t": "1686930292"
    },
    "content": [
        {
            "tag": "enc",
            "attrs": {
                "v": "2",
                "type": "pkmsg",
                "decrypt-fail": "hide"
            },
            "content": {}
        },
        {
            "tag": "device-identity",
            "content": {}
        }
    ]
}
tomer8007 commented 1 year ago

Sure, but what does the encrypted protobuf contain?

neo2701 commented 1 year ago

Just found out that the WAProtois very outdated 😂 I tried to update it from Baileys repo but it seems to break some function.

I see new MESSAGE_EDIT protocol on Baileys WAProto

neo2701 commented 1 year ago
{
    "stack": "Error: Failed to execute 'createElement' on 'Document': The tag name provided ('107') is not a valid name.\n    at document.createElement (https://web.whatsapp.com/app.ab3cb96ce8b0b5e2ac7c.js:93:816907)\n    at nodeToElement (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/utils.js:43:26)\n    at nodeToElement (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/utils.js:52:29)\n    at nodeToElement (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/utils.js:52:29)\n    at nodeToElement (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/utils.js:52:29)\n    at nodeToElement (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/utils.js:52:29)\n    at printNode (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/interception.js:439:38)\n    at Object.promise (chrome-extension://dgnhgkkblbdlgkebhopdhjfnliemgipp/core/interception.js:128:13)"
}

How to fix Error on this function?

function nodeToElement(node) {
  if (!node.tag) {
    var element = document.createElement("unknown");
    element.innerHTML = node.toString();
    return element;
  }
  console.log(node.tag);
  if (node.tag == "0") node.tag = "zero"; // prevent "The tag name provided ('0') is not a valid name."
  if (node.tag == "1") node.tag = "one"; // prevent "The tag name provided ('1') is not a valid name."

  var element = document.createElement(node.tag);

  for (var attribute in node.attrs) {
    element.setAttribute(attribute, node.attrs[attribute]);
  }

  if (node.content) {
    if (Array.isArray(node.content)) {
      for (var subNode of node.content) {
        element.appendChild(nodeToElement(subNode));
      }
    } else {
      element.appendChild(nodeToElement(node.content));
    }
  }

  return element;
}

file : /core/utils.js:43:26

tomer8007 commented 1 year ago

Oh, the if (node.tag == "0") node.tag = "zero" was just a dirtry hack I wrote to make exactly this error go away (numbers can't be tag names).

It'll be better to auto-detect all numbers, but for now you can add if (node.tag == "107") or whatever

I see new MESSAGE_EDIT protocol on Baileys WAProto

Makes perfect sense, I'll update it

neo2701 commented 1 year ago
function numberstowords(number) {
  var units = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
  number = number.toString();
  var result = "";
  for (var i = 0; i < number.length; i++) {
    result += units[number[i]];
  }
  return result;
}

function nodeToElement(node) {
  if (!node.tag) {
    var element = document.createElement("unknown");
    element.innerHTML = node.toString();
    return element;
  }
  if (node.tag == "0") node.tag = "zero"; // prevent "The tag name provided ('0') is not a valid name."
  if (node.tag == "1") node.tag = "one"; // prevent "The tag name provided ('1') is not a valid name."
  //   if (node.tag == "107") node.tag = "onezeroseven"; // prevent "The tag name provided ('107') is not a valid name."
  if (isNaN(node.tag) == false) node.tag = numberstowords(node.tag);
  var element = document.createElement(node.tag);

  for (var attribute in node.attrs) {
    element.setAttribute(attribute, node.attrs[attribute]);
  }

  if (node.content) {
    if (Array.isArray(node.content)) {
      for (var subNode of node.content) {
        element.appendChild(nodeToElement(subNode));
      }
    } else {
      element.appendChild(nodeToElement(node.content));
    }
  }

  return element;
}

Hahaha, it works after i did that

neo2701 commented 1 year ago
NodeHandler.checkForEditedMessageNode = function (message, messageId, remoteJid) {
  //
  // Check if this is a message edit node
  //
  var messageEditValue = ProtocolMessage.Type.MESSAGE_EDIT.value;

  if (message && message.editedMessage.message.protocolMessage.type == messageEditValue) {
    var editedMessageId = message.editedMessage.message.protocolMessage.key.id;
    if (saveEditedMsgsHookEnabled) {
      onEditedMessageBlocked(message, remoteJid, messageId, editedMessageId);
    }

    return true;
  }

  return false;
};

That function works too, but i can't do the UI.

tomer8007 commented 1 year ago

Nice :) I agree, the UI is the more creative part. We do already have a context-menu detection in the code, so maybe you could add "Show original message" option or so when you open the context menu of a message

tomer8007 commented 1 year ago

An alternative is to block the edited version entirely (which you seem to actually do), but this is probably not something everybody would want to happen. In this case, adding the UI option is easy

tomer8007 commented 12 months ago

@neo2701 You are more than welcome to open a PR (even without UI)