tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

messages.js (4507B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  createSelector,
      9 } = require("resource://devtools/client/shared/vendor/reselect.js");
     10 
     11 /**
     12 * Returns list of messages that are visible to the user.
     13 * Filtered messages by types and text are factored in.
     14 */
     15 const getDisplayedMessages = createSelector(
     16  state => state.messages,
     17  ({
     18    messages,
     19    messageFilterType,
     20    showControlFrames,
     21    messageFilterText,
     22    currentChannelId,
     23  }) => {
     24    if (!currentChannelId || !messages.get(currentChannelId)) {
     25      return [];
     26    }
     27 
     28    const messagesArray = messages.get(currentChannelId);
     29    if (messageFilterType === "all" && messageFilterText.length === 0) {
     30      return messagesArray.filter(message =>
     31        typeFilter(message, messageFilterType, showControlFrames)
     32      );
     33    }
     34 
     35    const filter = searchFilter(messageFilterText);
     36 
     37    // If message payload is > 10,000 characters long, we check the LongStringActor payload string
     38    return messagesArray.filter(
     39      message =>
     40        (message.payload.initial
     41          ? filter(message.payload.initial)
     42          : filter(message.payload)) &&
     43        typeFilter(message, messageFilterType, showControlFrames)
     44    );
     45  }
     46 );
     47 
     48 function typeFilter(message, messageFilterType, showControlFrames) {
     49  const controlFrames = [0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf];
     50  const isControlFrame = controlFrames.includes(message.opCode);
     51  if (messageFilterType === "all" || messageFilterType === message.type) {
     52    return showControlFrames || !isControlFrame;
     53  }
     54  return false;
     55 }
     56 
     57 function searchFilter(messageFilterText) {
     58  let regex;
     59  if (looksLikeRegex(messageFilterText)) {
     60    try {
     61      regex = regexFromText(messageFilterText);
     62    } catch (e) {}
     63  }
     64 
     65  return regex
     66    ? payload => regex.test(payload)
     67    : payload => payload.includes(messageFilterText);
     68 }
     69 
     70 function looksLikeRegex(text) {
     71  return text.startsWith("/") && text.endsWith("/") && text.length > 2;
     72 }
     73 
     74 function regexFromText(text) {
     75  return new RegExp(text.slice(1, -1), "im");
     76 }
     77 
     78 /**
     79 * Checks if the selected message is visible.
     80 * If the selected message is not visible, the SplitBox component
     81 * should not show the MessagePayload component.
     82 */
     83 const isSelectedMessageVisible = createSelector(
     84  state => state.messages,
     85  getDisplayedMessages,
     86  ({ selectedMessage }, displayedMessages) =>
     87    displayedMessages.some(message => message === selectedMessage)
     88 );
     89 
     90 /**
     91 * Returns the current selected message.
     92 */
     93 const getSelectedMessage = createSelector(
     94  state => state.messages,
     95  ({ selectedMessage }) => (selectedMessage ? selectedMessage : undefined)
     96 );
     97 
     98 /**
     99 * Returns summary data of the list of messages that are visible to the user.
    100 * Filtered messages by types and text are factored in.
    101 */
    102 const getDisplayedMessagesSummary = createSelector(
    103  getDisplayedMessages,
    104  displayedMessages => {
    105    let firstStartedMs = +Infinity;
    106    let lastEndedMs = -Infinity;
    107    let sentSize = 0;
    108    let receivedSize = 0;
    109    let totalSize = 0;
    110 
    111    displayedMessages.forEach(message => {
    112      if (message.type == "received") {
    113        receivedSize += message.payload.length;
    114      } else if (message.type == "sent") {
    115        sentSize += message.payload.length;
    116      }
    117      totalSize += message.payload.length;
    118      if (message.timeStamp < firstStartedMs) {
    119        firstStartedMs = message.timeStamp;
    120      }
    121      if (message.timeStamp > lastEndedMs) {
    122        lastEndedMs = message.timeStamp;
    123      }
    124    });
    125 
    126    return {
    127      count: displayedMessages.length,
    128      totalMs: (lastEndedMs - firstStartedMs) / 1000,
    129      sentSize,
    130      receivedSize,
    131      totalSize,
    132    };
    133  }
    134 );
    135 
    136 /**
    137 * Returns if the currentChannelId is closed
    138 */
    139 const isCurrentChannelClosed = createSelector(
    140  state => state.messages,
    141  ({ closedConnections, currentChannelId }) =>
    142    closedConnections.has(currentChannelId)
    143 );
    144 
    145 /**
    146 * Returns the closed connection details of the currentChannelId
    147 * Null, if the connection is still open
    148 */
    149 const getClosedConnectionDetails = createSelector(
    150  state => state.messages,
    151  ({ closedConnections, currentChannelId }) =>
    152    closedConnections.get(currentChannelId)
    153 );
    154 
    155 module.exports = {
    156  getSelectedMessage,
    157  isSelectedMessageVisible,
    158  getDisplayedMessages,
    159  getDisplayedMessagesSummary,
    160  isCurrentChannelClosed,
    161  getClosedConnectionDetails,
    162 };