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

prebid / Prebid.js / 20310805267

17 Dec 2025 05:00PM UTC coverage: 96.204% (-0.002%) from 96.206%
20310805267

push

github

e480e4
web-flow
Various modules: Ensure modules use connection utils (#14038)

* Ensure modules use connection utils

* Timeout RTD: remove unused helpers

41429 of 50962 branches covered (81.29%)

40 of 49 new or added lines in 11 files covered. (81.63%)

1 existing line in 1 file now uncovered.

207300 of 215480 relevant lines covered (96.2%)

71.32 hits per line

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

83.15
/modules/kinessoIdSystem.js
1
/**
1✔
2
 * This module adds KinessoId ID support to the User ID module
3
 * The {@link module:modules/userId} module is required.
4
 * @module modules/KinessoIdSystem
5
 * @requires module:modules/userId
6
 */
7

8
import { logError, logInfo } from '../src/utils.js';
9
import {ajax} from '../src/ajax.js';
10
import {submodule} from '../src/hook.js';
11

12
/**
13
 * @typedef {import('../modules/userId/index.js').Submodule} Submodule
14
 * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
15
 * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
16
 */
17

18
const MODULE_NAME = 'kpuid';
1✔
19
const ID_SVC = 'https://id.knsso.com/id';
1✔
20
// These values should NEVER change. If
21
// they do, we're no longer making ulids!
22
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
1✔
23
const ENCODING_LEN = ENCODING.length;
1✔
24
const TIME_MAX = Math.pow(2, 48) - 1;
1✔
25
const TIME_LEN = 10;
1✔
26
const RANDOM_LEN = 16;
1✔
27
const id = factory();
1✔
28

29
/**
30
 * the factory to generate unique identifier based on time and current pseudorandom number
31
 * @param {string} currPrng the current pseudorandom number generator
32
 * @returns {function(*=): *}
33
 */
34
function factory(currPrng) {
35
  if (!currPrng) {
1✔
36
    currPrng = detectPrng();
1✔
37
  }
38
  return function ulid(seedTime) {
1✔
39
    if (isNaN(seedTime)) {
1✔
40
      seedTime = Date.now();
1✔
41
    }
42
    return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, currPrng);
1✔
43
  };
44
}
45

46
/**
47
 * gets a a random charcter from generated pseudorandom number
48
 * @param {string} prng the generated pseudorandom number
49
 * @returns {string}
50
 */
51
function randomChar(prng) {
52
  let rand = Math.floor(prng() * ENCODING_LEN);
16✔
53
  if (rand === ENCODING_LEN) {
16!
UNCOV
54
    rand = ENCODING_LEN - 1;
×
55
  }
56
  return ENCODING.charAt(rand);
16✔
57
}
58

59
/**
60
 * encodes random character
61
 * @param {number} len
62
 * @param {function(): number} prng
63
 * @returns {string}
64
 */
65
function encodeRandom(len, prng) {
66
  let str = '';
1✔
67
  for (; len > 0; len--) {
1✔
68
    str = randomChar(prng) + str;
16✔
69
  }
70
  return str;
1✔
71
}
72

73
/**
74
 * encodes the time based on the length
75
 * @param {number} now
76
 * @param {number} len
77
 * @returns {string} encoded time.
78
 */
79
function encodeTime(now, len) {
80
  if (isNaN(now)) {
1!
81
    throw new Error(now + ' must be a number');
×
82
  }
83

84
  if (Number.isInteger(now) === false) {
1!
85
    throw createError('time must be an integer');
×
86
  }
87

88
  if (now > TIME_MAX) {
1!
89
    throw createError('cannot encode time greater than ' + TIME_MAX);
×
90
  }
91
  if (now < 0) {
1!
92
    throw createError('time must be positive');
×
93
  }
94

95
  if (Number.isInteger(len) === false) {
1!
96
    throw createError('length must be an integer');
×
97
  }
98
  if (len < 0) {
1!
99
    throw createError('length must be positive');
×
100
  }
101

102
  let mod;
103
  let str = '';
1✔
104
  for (; len > 0; len--) {
1✔
105
    mod = now % ENCODING_LEN;
10✔
106
    str = ENCODING.charAt(mod) + str;
10✔
107
    now = (now - mod) / ENCODING_LEN;
10✔
108
  }
109
  return str;
1✔
110
}
111

112
/**
113
 * creates and logs the error message
114
 * @function
115
 * @param {string} message error message
116
 * @returns {Error}
117
 */
118
function createError(message) {
119
  logError(message);
×
120
  const err = new Error(message);
×
121
  err.source = 'kinessoId';
×
122
  return err;
×
123
}
124

125
/**
126
 * detects the pseudorandom number generator and generates the random number
127
 * @function
128
 * @param {string} root
129
 * @returns {string} a random number
130
 */
131
function detectPrng(root) {
132
  if (!root) {
1✔
133
    root = typeof window !== 'undefined' ? window : null;
1!
134
  }
135
  const browserCrypto = root && (root.crypto || root.msCrypto);
1!
136
  if (browserCrypto) {
1✔
137
    return () => {
1✔
138
      const buffer = new Uint8Array(1);
16✔
139
      browserCrypto.getRandomValues(buffer);
16✔
140
      return buffer[0] / 0xff;
16✔
141
    };
142
  }
143
  return () => Math.random();
×
144
}
145

146
/**
147
 * existing id generation call back
148
 * @param {string} storedId
149
 * @returns {{success: function(Object): void, error: function(): void}}
150
 */
151
function syncId(storedId) {
152
  return {
1✔
153
    success: function (responseBody) {
154
      logInfo('KinessoId: id to be synced: ' + storedId);
×
155
    },
156
    error: function () {
157
      logInfo('KinessoId: Sync error for id : ' + storedId);
×
158
    }
159
  }
160
}
161

162
/**
163
 * Encode the id
164
 * @param value
165
 * @returns {string|*}
166
 */
167
function encodeId(value) {
168
  const result = {};
1✔
169
  const knssoId = (value && typeof value === 'string') ? value : undefined;
1!
170
  if (knssoId) {
1✔
171
    result.kpuid = knssoId;
1✔
172
    logInfo('KinessoId: Decoded value ' + JSON.stringify(result));
1✔
173
    return result;
1✔
174
  }
175
  return knssoId;
×
176
}
177

178
/**
179
 * Builds and returns the shared Id URL with attached consent data if applicable
180
 * @param {number} accountId
181
 * @param {Object} consentData
182
 * @return {string}
183
 */
184
function kinessoSyncUrl(accountId, consentData) {
185
  const {gdpr, usp: usPrivacyString} = consentData ?? {};
1!
186
  let kinessoSyncUrl = `${ID_SVC}?accountid=${accountId}`;
1✔
187
  if (usPrivacyString) {
1✔
188
    kinessoSyncUrl = `${kinessoSyncUrl}&us_privacy=${usPrivacyString}`;
1✔
189
  }
190
  if (!gdpr || typeof gdpr.gdprApplies !== 'boolean' || !gdpr.gdprApplies) return kinessoSyncUrl;
1!
191

192
  kinessoSyncUrl = `${kinessoSyncUrl}&gdpr=1&gdpr_consent=${gdpr.consentString}`;
1✔
193
  return kinessoSyncUrl
1✔
194
}
195

196
/** @type {Submodule} */
197
export const kinessoIdSubmodule = {
1✔
198

199
  /**
200
   * used to link submodule with config
201
   * @type {string}
202
   */
203
  name: MODULE_NAME,
204

205
  /**
206
   * decode the stored id value for passing to bid requests
207
   * @function
208
   * @param {string} value
209
   * @returns {{kpuid:{id: string}}|undefined}
210
   */
211
  decode(value) {
212
    return (value) ? encodeId(value) : undefined;
2✔
213
  },
214

215
  /**
216
   * performs action to obtain id and return a value.
217
   * @function
218
   * @param {SubmoduleConfig} [config]
219
   * @param {ConsentData|undefined} consentData
220
   * @returns {string|undefined}
221
   */
222
  getId(config, consentData) {
223
    const configParams = (config && config.params) || {};
3!
224
    if (!configParams || typeof configParams.accountid !== 'number') {
3✔
225
      logError('User ID - KinessoId submodule requires a valid accountid to be defined');
1✔
226
      return;
1✔
227
    }
228
    if (consentData?.coppa) {
2✔
229
      logInfo('KinessoId: IDs not provided for coppa requests, exiting KinessoId');
1✔
230
      return;
1✔
231
    }
232
    const accountId = configParams.accountid;
1✔
233
    const knnsoId = id();
1✔
234
    logInfo('KinessoId: generated id ' + knnsoId);
1✔
235
    const kinessoIdPayload = {};
1✔
236
    kinessoIdPayload.id = knnsoId;
1✔
237
    const payloadString = JSON.stringify(kinessoIdPayload);
1✔
238
    ajax(kinessoSyncUrl(accountId, consentData), syncId(knnsoId), payloadString, {method: 'POST', withCredentials: true});
1✔
239
    return {'id': knnsoId};
1✔
240
  },
241
  eids: {
242
    'kpuid': {
243
      source: 'kpuid.com',
244
      atype: 3
245
    },
246
  },
247
};
248

249
// Register submodule for userId
250
submodule('userId', kinessoIdSubmodule);
1✔
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