• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Build has been canceled!

prebid / Prebid.js / 20469899712

23 Dec 2025 07:35PM UTC coverage: 96.216%. Remained the same
20469899712

push

github

66a74d
web-flow
modify TopOnBidderAdapter's UserSyncsUrlPath (#14296)

Co-authored-by: 范天成 <tiancheng.fan@takuad.com>

41481 of 50996 branches covered (81.34%)

2 of 2 new or added lines in 2 files covered. (100.0%)

1 existing line in 1 file now uncovered.

207631 of 215796 relevant lines covered (96.22%)

128.69 hits per line

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

83.15
/modules/kinessoIdSystem.js
1
/**
2✔
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';
2✔
19
const ID_SVC = 'https://id.knsso.com/id';
2✔
20
// These values should NEVER change. If
21
// they do, we're no longer making ulids!
22
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
2✔
23
const ENCODING_LEN = ENCODING.length;
2✔
24
const TIME_MAX = Math.pow(2, 48) - 1;
2✔
25
const TIME_LEN = 10;
2✔
26
const RANDOM_LEN = 16;
2✔
27
const id = factory();
2✔
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) {
2✔
36
    currPrng = detectPrng();
2✔
37
  }
38
  return function ulid(seedTime) {
2✔
39
    if (isNaN(seedTime)) {
2✔
40
      seedTime = Date.now();
2✔
41
    }
42
    return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, currPrng);
2✔
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);
32✔
53
  if (rand === ENCODING_LEN) {
32!
UNCOV
54
    rand = ENCODING_LEN - 1;
×
55
  }
56
  return ENCODING.charAt(rand);
32✔
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 = '';
2✔
67
  for (; len > 0; len--) {
2✔
68
    str = randomChar(prng) + str;
32✔
69
  }
70
  return str;
2✔
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)) {
2!
81
    throw new Error(now + ' must be a number');
×
82
  }
83

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

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

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

102
  let mod;
103
  let str = '';
2✔
104
  for (; len > 0; len--) {
2✔
105
    mod = now % ENCODING_LEN;
20✔
106
    str = ENCODING.charAt(mod) + str;
20✔
107
    now = (now - mod) / ENCODING_LEN;
20✔
108
  }
109
  return str;
2✔
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) {
2✔
133
    root = typeof window !== 'undefined' ? window : null;
2!
134
  }
135
  const browserCrypto = root && (root.crypto || root.msCrypto);
2!
136
  if (browserCrypto) {
2✔
137
    return () => {
2✔
138
      const buffer = new Uint8Array(1);
32✔
139
      browserCrypto.getRandomValues(buffer);
32✔
140
      return buffer[0] / 0xff;
32✔
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 {
2✔
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 = {};
2✔
169
  const knssoId = (value && typeof value === 'string') ? value : undefined;
2!
170
  if (knssoId) {
2✔
171
    result.kpuid = knssoId;
2✔
172
    logInfo('KinessoId: Decoded value ' + JSON.stringify(result));
2✔
173
    return result;
2✔
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 ?? {};
2!
186
  let kinessoSyncUrl = `${ID_SVC}?accountid=${accountId}`;
2✔
187
  if (usPrivacyString) {
2✔
188
    kinessoSyncUrl = `${kinessoSyncUrl}&us_privacy=${usPrivacyString}`;
2✔
189
  }
190
  if (!gdpr || typeof gdpr.gdprApplies !== 'boolean' || !gdpr.gdprApplies) return kinessoSyncUrl;
2!
191

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

196
/** @type {Submodule} */
197
export const kinessoIdSubmodule = {
2✔
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;
4✔
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) || {};
6!
224
    if (!configParams || typeof configParams.accountid !== 'number') {
6✔
225
      logError('User ID - KinessoId submodule requires a valid accountid to be defined');
2✔
226
      return;
2✔
227
    }
228
    if (consentData?.coppa) {
4✔
229
      logInfo('KinessoId: IDs not provided for coppa requests, exiting KinessoId');
2✔
230
      return;
2✔
231
    }
232
    const accountId = configParams.accountid;
2✔
233
    const knnsoId = id();
2✔
234
    logInfo('KinessoId: generated id ' + knnsoId);
2✔
235
    const kinessoIdPayload = {};
2✔
236
    kinessoIdPayload.id = knnsoId;
2✔
237
    const payloadString = JSON.stringify(kinessoIdPayload);
2✔
238
    ajax(kinessoSyncUrl(accountId, consentData), syncId(knnsoId), payloadString, {method: 'POST', withCredentials: true});
2✔
239
    return {'id': knnsoId};
2✔
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);
2✔
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