Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor[devtools]: forbid editing class instances in props #26522

Merged

Conversation

hoxyq
Copy link
Contributor

@hoxyq hoxyq commented Mar 30, 2023

Summary

Fixes #24781

Restricting from editing props, which are class instances, because their internals should be opaque.

Proposed changes:

  1. Adding new data type class_instance: based on prototype chain of an object we will check if its plain or not. If not, then will be marked as class_instance. This should not affect arrays, ..., because we do this in the end of an object case in getDataType function.

Important detail: this approach won't work for objects created with Object.create, because of the custom prototype. This can also be bypassed by manually deleting a prototype ¯\_(ツ)_/¯
I am not sure if there might be a better solution (which will cover all cases) to detect if object is a class instance. Initially I was trying to use Object.getPrototypeOf(object) === Object.prototype, but this won't work for cases when we are dealing with iframe.

  1. Objects with a type class_instance will be marked as unserializable and read-only.

Demo

person is a class instance, object is a plain object

demo.mov

@hoxyq hoxyq requested a review from mondaychen March 30, 2023 17:35
@hoxyq hoxyq force-pushed the refactor/forbid-editing-class-instances-in-props branch 3 times, most recently from 967fecf to ab8fa95 Compare March 30, 2023 17:58
@mondaychen mondaychen added the React Core Team Opened by a member of the React Core Team label Mar 30, 2023
Copy link
Contributor

@mondaychen mondaychen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good!

if (!objectPrototype) return true;

const objectParentPrototype = Object.getPrototypeOf(objectPrototype);
return objectParentPrototype == null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the only prototype with null as its parent prototype?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the only prototype with null as its parent prototype?

Sorry, didn't quite understand the question. I am using non-strict equals here, so essentially it will check just if objectParentPrototype is undefined or null

Might also just use !objectParentPrototype here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion. I was just curious whether the prototype of an object is the only one that has nothing up in the chain.
This check here is good.

packages/react-devtools-shared/src/utils.js Outdated Show resolved Hide resolved
@hoxyq hoxyq force-pushed the refactor/forbid-editing-class-instances-in-props branch from ab8fa95 to e50a8ba Compare March 31, 2023 11:04
@hoxyq hoxyq force-pushed the refactor/forbid-editing-class-instances-in-props branch from e50a8ba to 651a028 Compare March 31, 2023 13:55
@react-sizebot
Copy link

Comparing: ca01f35...651a028

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js = 162.81 kB 162.81 kB = 51.35 kB 51.35 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 164.35 kB 164.35 kB = 51.84 kB 51.84 kB
facebook-www/ReactDOM-prod.classic.js = 556.51 kB 556.51 kB = 98.16 kB 98.16 kB
facebook-www/ReactDOM-prod.modern.js = 540.21 kB 540.21 kB = 95.78 kB 95.78 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against 651a028

@hoxyq hoxyq marked this pull request as ready for review March 31, 2023 14:38
@hoxyq hoxyq merged commit b14f8da into facebook:main Apr 3, 2023
@hoxyq hoxyq deleted the refactor/forbid-editing-class-instances-in-props branch April 3, 2023 10:32
hoxyq added a commit that referenced this pull request Apr 17, 2023
Full list of changes (not everything included in changelog):
* refactor[devtools]: copy to clipboard only on frontend side
([hoxyq](https://github.com/hoxyq) in
[#26604](#26604))
* Provide icon to edge devtools.
([harrygz889](https://github.com/harrygz889) in
[#26543](#26543))
* [BE] move shared types & constants to consolidated locations
([mondaychen](https://github.com/mondaychen) in
[#26572](#26572))
* remove backend dependency from the global hook
([mondaychen](https://github.com/mondaychen) in
[#26563](#26563))
* Replace deprecated `new-window` with
`webContents.setWindowOpenHandler()`
([Willie-Boy](https://github.com/Willie-Boy) in
[#26559](#26559))
* DevTools: Inline references to fiber flags
([acdlite](https://github.com/acdlite) in
[#26542](#26542))
* refactor[devtools]: forbid editing class instances in props
([hoxyq](https://github.com/hoxyq) in
[#26522](#26522))
* Move update scheduling to microtask
([acdlite](https://github.com/acdlite) in
[#26512](#26512))
* Remove unnecessary CIRCLE_CI_API_TOKEN checks
([mondaychen](https://github.com/mondaychen) in
[#26499](#26499))
* browser extension: improve script injection logic
([mondaychen](https://github.com/mondaychen) in
[#26492](#26492))
* [flow] make Flow suppressions explicit on the error
([kassens](https://github.com/kassens) in
[#26487](#26487))
kassens pushed a commit to kassens/react that referenced this pull request Apr 17, 2023
…#26522)

## Summary
Fixes facebook#24781

Restricting from editing props, which are class instances, because their
internals should be opaque.

Proposed changes:
1. Adding new data type `class_instance`: based on prototype chain of an
object we will check if its plain or not. If not, then will be marked as
`class_instance`. This should not affect `arrays`, ..., because we do
this in the end of an `object` case in `getDataType` function.

Important detail: this approach won't work for objects created with
`Object.create`, because of the custom prototype. This can also be
bypassed by manually deleting a prototype ¯\\\_(ツ)_/¯
I am not sure if there might be a better solution (which will cover all
cases) to detect if object is a class instance. Initially I was trying
to use `Object.getPrototypeOf(object) === Object.prototype`, but this
won't work for cases when we are dealing with `iframe`.


2. Objects with a type `class_instance` will be marked as unserializable
and read-only.

## Demo
`person` is a class instance, `object` is a plain object


https://user-images.githubusercontent.com/28902667/228914791-ebdc8ab0-eb5c-426d-8163-66d56b5e8790.mov
kassens pushed a commit to kassens/react that referenced this pull request Apr 17, 2023
Full list of changes (not everything included in changelog):
* refactor[devtools]: copy to clipboard only on frontend side
([hoxyq](https://github.com/hoxyq) in
[facebook#26604](facebook#26604))
* Provide icon to edge devtools.
([harrygz889](https://github.com/harrygz889) in
[facebook#26543](facebook#26543))
* [BE] move shared types & constants to consolidated locations
([mondaychen](https://github.com/mondaychen) in
[facebook#26572](facebook#26572))
* remove backend dependency from the global hook
([mondaychen](https://github.com/mondaychen) in
[facebook#26563](facebook#26563))
* Replace deprecated `new-window` with
`webContents.setWindowOpenHandler()`
([Willie-Boy](https://github.com/Willie-Boy) in
[facebook#26559](facebook#26559))
* DevTools: Inline references to fiber flags
([acdlite](https://github.com/acdlite) in
[facebook#26542](facebook#26542))
* refactor[devtools]: forbid editing class instances in props
([hoxyq](https://github.com/hoxyq) in
[facebook#26522](facebook#26522))
* Move update scheduling to microtask
([acdlite](https://github.com/acdlite) in
[facebook#26512](facebook#26512))
* Remove unnecessary CIRCLE_CI_API_TOKEN checks
([mondaychen](https://github.com/mondaychen) in
[facebook#26499](facebook#26499))
* browser extension: improve script injection logic
([mondaychen](https://github.com/mondaychen) in
[facebook#26492](facebook#26492))
* [flow] make Flow suppressions explicit on the error
([kassens](https://github.com/kassens) in
[facebook#26487](facebook#26487))
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
…#26522)

## Summary
Fixes facebook#24781

Restricting from editing props, which are class instances, because their
internals should be opaque.

Proposed changes:
1. Adding new data type `class_instance`: based on prototype chain of an
object we will check if its plain or not. If not, then will be marked as
`class_instance`. This should not affect `arrays`, ..., because we do
this in the end of an `object` case in `getDataType` function.

Important detail: this approach won't work for objects created with
`Object.create`, because of the custom prototype. This can also be
bypassed by manually deleting a prototype ¯\\\_(ツ)_/¯
I am not sure if there might be a better solution (which will cover all
cases) to detect if object is a class instance. Initially I was trying
to use `Object.getPrototypeOf(object) === Object.prototype`, but this
won't work for cases when we are dealing with `iframe`.


2. Objects with a type `class_instance` will be marked as unserializable
and read-only.

## Demo
`person` is a class instance, `object` is a plain object


https://user-images.githubusercontent.com/28902667/228914791-ebdc8ab0-eb5c-426d-8163-66d56b5e8790.mov
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
Full list of changes (not everything included in changelog):
* refactor[devtools]: copy to clipboard only on frontend side
([hoxyq](https://github.com/hoxyq) in
[facebook#26604](facebook#26604))
* Provide icon to edge devtools.
([harrygz889](https://github.com/harrygz889) in
[facebook#26543](facebook#26543))
* [BE] move shared types & constants to consolidated locations
([mondaychen](https://github.com/mondaychen) in
[facebook#26572](facebook#26572))
* remove backend dependency from the global hook
([mondaychen](https://github.com/mondaychen) in
[facebook#26563](facebook#26563))
* Replace deprecated `new-window` with
`webContents.setWindowOpenHandler()`
([Willie-Boy](https://github.com/Willie-Boy) in
[facebook#26559](facebook#26559))
* DevTools: Inline references to fiber flags
([acdlite](https://github.com/acdlite) in
[facebook#26542](facebook#26542))
* refactor[devtools]: forbid editing class instances in props
([hoxyq](https://github.com/hoxyq) in
[facebook#26522](facebook#26522))
* Move update scheduling to microtask
([acdlite](https://github.com/acdlite) in
[facebook#26512](facebook#26512))
* Remove unnecessary CIRCLE_CI_API_TOKEN checks
([mondaychen](https://github.com/mondaychen) in
[facebook#26499](facebook#26499))
* browser extension: improve script injection logic
([mondaychen](https://github.com/mondaychen) in
[facebook#26492](facebook#26492))
* [flow] make Flow suppressions explicit on the error
([kassens](https://github.com/kassens) in
[facebook#26487](facebook#26487))
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
## Summary
Fixes #24781

Restricting from editing props, which are class instances, because their
internals should be opaque.

Proposed changes:
1. Adding new data type `class_instance`: based on prototype chain of an
object we will check if its plain or not. If not, then will be marked as
`class_instance`. This should not affect `arrays`, ..., because we do
this in the end of an `object` case in `getDataType` function.

Important detail: this approach won't work for objects created with
`Object.create`, because of the custom prototype. This can also be
bypassed by manually deleting a prototype ¯\\\_(ツ)_/¯
I am not sure if there might be a better solution (which will cover all
cases) to detect if object is a class instance. Initially I was trying
to use `Object.getPrototypeOf(object) === Object.prototype`, but this
won't work for cases when we are dealing with `iframe`.

2. Objects with a type `class_instance` will be marked as unserializable
and read-only.

## Demo
`person` is a class instance, `object` is a plain object

https://user-images.githubusercontent.com/28902667/228914791-ebdc8ab0-eb5c-426d-8163-66d56b5e8790.mov

DiffTrain build for commit b14f8da.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DevTools Bug]: Selecting/deselecting boolean from DevTools Component props causing loss of class functions
4 participants