Skip to content

Commit

Permalink
feat: add yandex id system
Browse files Browse the repository at this point in the history
  • Loading branch information
chernodub committed Mar 12, 2024
1 parent 0756379 commit b95702e
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 1 deletion.
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"gravitoIdSystem",
"freepassIdSystem",
"operaadsIdSystem",
"mygaruIdSystem"
"mygaruIdSystem",
"yandexIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
127 changes: 127 additions & 0 deletions modules/yandexIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* The {@link module:modules/userId} module is required
* @module modules/yandexIdSystem
* @requires module:modules/userId
*/

import { MODULE_TYPE_UID } from "../src/activities/modules.js";
import { submodule } from "../src/hook.js";
import { getStorageManager } from "../src/storageManager.js";
import { logInfo } from "../src/utils.js";

/**
* @typedef {import('../modules/userId/index.js').Submodule} Submodule
* @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
* @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
*/

const BIDDER_CODE = "yandex";

const USER_ID_KEY = "_ym_uid";
const USER_ID_COOKIE_EXP = 31536000000; // 365 days

export const cookieStorage = getStorageManager({
moduleType: MODULE_TYPE_UID,
moduleName: BIDDER_CODE,
});

/** @type {Submodule} */
export const yandexIdSubmodule = {
/**
* Used to link submodule with config.
* @type {string}
*/
name: BIDDER_CODE,
/**
* Decodes the stored id value for passing to bid requests.
* @param {string} value
*/
decode(value) {
logInfo("decoded value yandexId", value);

return { yandexId: value };
},
getId() {
const yandexUidStorage = new YandexUidStorage(cookieStorage);

if (!yandexUidStorage.checkIsAvailable()) {
return;
}

return {
id: yandexUidStorage.getUid(),
};
},
eids: {
yandexId: {
source: "yandex",
atype: 1,
},
},
};

class YandexUidStorage {
/**
* @param {typeof cookieStorage} cookieStorage
*/
constructor(cookieStorage) {
this._cookieStorage = cookieStorage;
}

_generateUid() {
return new YandexUidGenerator().generateUid();
}

_getUserIdFromStorage() {
const id = this._cookieStorage.getCookie(USER_ID_KEY);

return id;
}

_setUid(userId) {

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
if (this._cookieStorage.cookiesAreEnabled()) {
const expires = new Date(Date.now() + USER_ID_COOKIE_EXP).toString();

this._cookieStorage.setCookie(USER_ID_KEY, userId, expires);
}
}

checkIsAvailable() {
return this._cookieStorage.cookiesAreEnabled();
}

getUid() {
const id = this._getUserIdFromStorage() || this._generateUid();

this._setUid(id);

return id;
}
}

/**
* Yandex-specific generator for uid. Needs to be compatible with Yandex Metrica tag.
* @see https://github.com/yandex/metrica-tag/blob/main/src/utils/uid/uid.ts#L51
*/
class YandexUidGenerator {
/**
* @param {number} min
* @param {number} max
*/
_getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}

_getCurrentSecTimestamp() {
return Math.round(Date.now() / 1000);
}

generateUid() {
return [
this._getCurrentSecTimestamp(),
this._getRandomInteger(1000000, 999999999),
].join("");
}
}

submodule("userId", yandexIdSubmodule);

0 comments on commit b95702e

Please sign in to comment.