(core) Fix issue with lodash's map interpreting objects with length as array-like

Summary:
Here's a series of badness that easily leads to a crash, in reverse order:
- Lodash's map() function interprets an object with a .length property as an array.
- Some very old code generated human-friendly descriptions of user actions,
  applying map() to parts of them. It so happens that this generated description
  isn't even used.
- If a user action is encountered with a sufficiently large length propery,
  map() would exhaust the server memory.

Fixed by removing old unneeded code, and replacing some other occurrences of
lodash's map() with native equivalents.

Test Plan: Tested manually on a local reproduction of the issue.

Reviewers: paulfitz

Reviewed By: paulfitz

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D3938
This commit is contained in:
Dmitry S
2023-07-01 14:31:21 -04:00
parent b0aa17c932
commit 2b581ab7dc
6 changed files with 16 additions and 119 deletions

View File

@@ -6,7 +6,6 @@ import * as dispose from 'app/client/lib/dispose';
import dom from 'app/client/lib/dom';
import {timeFormat} from 'app/common/timeFormat';
import * as ko from 'knockout';
import map = require('lodash/map');
import koArray from 'app/client/lib/koArray';
import {KoArray} from 'app/client/lib/koArray';
@@ -17,8 +16,8 @@ import {GristDoc} from 'app/client/components/GristDoc';
import {ActionGroup} from 'app/common/ActionGroup';
import {ActionSummary, asTabularDiffs, defunctTableName, getAffectedTables,
LabelDelta} from 'app/common/ActionSummary';
import {CellDelta} from 'app/common/TabularDiff';
import {IDomComponent} from 'grainjs';
import {CellDelta, TabularDiff} from 'app/common/TabularDiff';
import {DomContents, IDomComponent} from 'grainjs';
import {makeT} from 'app/client/lib/localization';
/**
@@ -141,12 +140,12 @@ export class ActionLog extends dispose.Disposable implements IDomComponent {
* @param {string} txt - a textual description of the action
* @param {ActionGroupWithState} ag - the full action information we have
*/
public renderTabularDiffs(sum: ActionSummary, txt: string, ag?: ActionGroupWithState) {
public renderTabularDiffs(sum: ActionSummary, txt: string, ag?: ActionGroupWithState): HTMLElement {
const act = asTabularDiffs(sum);
const editDom = dom('div',
this._renderTableSchemaChanges(sum, ag),
this._renderColumnSchemaChanges(sum, ag),
map(act, (tdiff, table) => {
Object.entries(act).map(([table, tdiff]: [string, TabularDiff]) => {
if (tdiff.cells.length === 0) { return dom('div'); }
return dom('table.action_log_table',
koDom.show(() => this._showForTable(table, ag)),
@@ -238,7 +237,7 @@ export class ActionLog extends dispose.Disposable implements IDomComponent {
'Loading...'),
koDom.foreach(this._displayStack, (ag: ActionGroupWithState) => {
const timestamp = ag.time ? timeFormat("D T", new Date(ag.time)) : "";
let desc = ag.desc || "";
let desc: DomContents = ag.desc || "";
if (ag.actionSummary) {
desc = this.renderTabularDiffs(ag.actionSummary, desc, ag);
}