• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / #298

29 May 2025 11:21AM UTC coverage: 82.464% (-7.7%) from 90.144%
#298

push

travis-ci

prebidjs-release
Prebid 9.45.0 release

12606 of 17518 branches covered (71.96%)

18622 of 22582 relevant lines covered (82.46%)

157.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.46
/libraries/objectGuard/objectGuard.js
1
import {isData, objectTransformer, sessionedApplies} from '../../src/activities/redactor.js';
2
import {deepAccess, deepClone, deepEqual, deepSetValue} from '../../src/utils.js';
3

4
/**
5
 * @typedef {import('../src/activities/redactor.js').TransformationRuleDef} TransformationRuleDef
6
 * @typedef {import('../src/adapters/bidderFactory.js').TransformationRule} TransformationRule
7
 * @typedef {Object} ObjectGuard
8
 * @property {*} obj a view on the guarded object
9
 * @property {function(): void} verify a function that checks for and rolls back disallowed changes to the guarded object
10
 */
11

12
/**
13
 * Create a factory function for object guards using the given rules.
14
 *
15
 * An object guard is a pair {obj, verify} where:
16
 *  - `obj` is a view on the guarded object that applies "redact" rules (the same rules used in activites/redactor.js)
17
 *  - `verify` is a function that, when called, will check that the guarded object was not modified
18
 *   in a way that violates any "write protect" rules, and rolls back any offending changes.
19
 *
20
 * This is meant to provide sandboxed version of a privacy-sensitive object, where reads
21
 * are filtered through redaction rules and writes are checked against write protect rules.
22
 *
23
 * @param {Array[TransformationRule]} rules
24
 * @return {function(*, ...[*]): ObjectGuard}
25
 */
26
export function objectGuard(rules) {
27
  const root = {};
1✔
28
  const writeRules = [];
1✔
29

30
  rules.forEach(rule => {
1✔
31
    if (rule.wp) writeRules.push(rule);
8✔
32
    if (!rule.get) return;
8✔
33
    rule.paths.forEach(path => {
6✔
34
      let node = root;
19✔
35
      path.split('.').forEach(el => {
19✔
36
        node.children = node.children || {};
45✔
37
        node.children[el] = node.children[el] || {};
45✔
38
        node = node.children[el];
45✔
39
      })
40
      node.rule = rule;
19✔
41
    });
42
  });
43

44
  const wpTransformer = objectTransformer(writeRules);
1✔
45

46
  function mkGuard(obj, tree, applies) {
47
    return new Proxy(obj, {
×
48
      get(target, prop, receiver) {
49
        const val = Reflect.get(target, prop, receiver);
×
50
        if (tree.hasOwnProperty(prop)) {
×
51
          const {children, rule} = tree[prop];
×
52
          if (children && val != null && typeof val === 'object') {
×
53
            return mkGuard(val, children, applies);
×
54
          } else if (rule && isData(val) && applies(rule)) {
×
55
            return rule.get(val);
×
56
          }
57
        }
58
        return val;
×
59
      },
60
    });
61
  }
62

63
  function mkVerify(transformResult) {
64
    return function () {
×
65
      transformResult.forEach(fn => fn());
×
66
    }
67
  }
68

69
  return function guard(obj, ...args) {
1✔
70
    const session = {};
×
71
    return {
×
72
      obj: mkGuard(obj, root.children || {}, sessionedApplies(session, ...args)),
×
73
      verify: mkVerify(wpTransformer(session, obj, ...args))
74
    }
75
  };
76
}
77

78
/**
79
 * @param {TransformationRuleDef} ruleDef
80
 * @return {TransformationRule}
81
 */
82
export function writeProtectRule(ruleDef) {
83
  return Object.assign({
2✔
84
    wp: true,
85
    run(root, path, object, property, applies) {
86
      const origHasProp = object && object.hasOwnProperty(property);
×
87
      const original = origHasProp ? object[property] : undefined;
×
88
      const origCopy = origHasProp && original != null && typeof original === 'object' ? deepClone(original) : original;
×
89
      return function () {
×
90
        const object = path == null ? root : deepAccess(root, path);
×
91
        const finalHasProp = object && isData(object[property]);
×
92
        const finalValue = finalHasProp ? object[property] : undefined;
×
93
        if (!origHasProp && finalHasProp && applies()) {
×
94
          delete object[property];
×
95
        } else if ((origHasProp !== finalHasProp || finalValue !== original || !deepEqual(finalValue, origCopy)) && applies()) {
×
96
          deepSetValue(root, (path == null ? [] : [path]).concat(property).join('.'), origCopy);
×
97
        }
98
      }
99
    }
100
  }, ruleDef)
101
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc