(value: unknown, parent: object | undefined,
path: PropertyPath, owner: RpcPayload | null)
| 1485 | }; |
| 1486 | |
| 1487 | function followPath(value: unknown, parent: object | undefined, |
| 1488 | path: PropertyPath, owner: RpcPayload | null): FollowPathResult { |
| 1489 | for (let i = 0; i < path.length; i++) { |
| 1490 | parent = <object>value; |
| 1491 | |
| 1492 | let part = path[i]; |
| 1493 | if (part in Object.prototype) { |
| 1494 | // Don't allow messing with Object.prototype properties over RPC. We block these even if |
| 1495 | // the specific object has overridden them for consistency with the deserialization code, |
| 1496 | // which will refuse to deserialize an object containing such properties. Anyway, it's |
| 1497 | // impossible for a normal client to even request these because accessing Object prototype |
| 1498 | // properties on a stub will resolve to the local prototype property, not making an RPC at |
| 1499 | // all. |
| 1500 | value = undefined; |
| 1501 | continue; |
| 1502 | } |
| 1503 | |
| 1504 | let kind = typeForRpc(value); |
| 1505 | switch (kind) { |
| 1506 | case "object": |
| 1507 | case "function": |
| 1508 | // Must be own property, NOT inherited from a prototype. |
| 1509 | if (Object.hasOwn(<object>value, part)) { |
| 1510 | value = (<any>value)[part]; |
| 1511 | } else { |
| 1512 | value = undefined; |
| 1513 | } |
| 1514 | break; |
| 1515 | |
| 1516 | case "array": |
| 1517 | // For arrays, restrict specifically to numeric indexes, to be consistent with |
| 1518 | // serialization, which only sends a flat list. |
| 1519 | if (Number.isInteger(part) && <number>part >= 0) { |
| 1520 | value = (<any>value)[part]; |
| 1521 | } else { |
| 1522 | value = undefined; |
| 1523 | } |
| 1524 | break; |
| 1525 | |
| 1526 | case "rpc-target": |
| 1527 | case "rpc-thenable": { |
| 1528 | // Must be prototype property, and must NOT be inherited from `Object`. |
| 1529 | if (Object.hasOwn(<object>value, part)) { |
| 1530 | // We throw an error in this case, rather than return undefined, because otherwise |
| 1531 | // people tend to get confused about this. If you don't want it to be possible to |
| 1532 | // probe the existence of your instance properties, make them properly private (prefix |
| 1533 | // with #). |
| 1534 | throw new TypeError( |
| 1535 | `Attempted to access property '${part}', which is an instance property of the ` + |
| 1536 | `RpcTarget. To avoid leaking private internals, instance properties cannot be ` + |
| 1537 | `accessed over RPC. If you want to make this property available over RPC, define ` + |
| 1538 | `it as a method or getter on the class, instead of an instance property.`); |
| 1539 | } else { |
| 1540 | value = (<any>value)[part]; |
| 1541 | } |
| 1542 | |
| 1543 | // Since we're descending into the RpcTarget, the rest of the path is not "owned" by any |
| 1544 | // RpcPayload. |
no test coverage detected
searching dependent graphs…