From d2cffe6d69ceff8f1b36ac8db620fe0167d85331 Mon Sep 17 00:00:00 2001 From: Carter McBride Date: Thu, 22 Aug 2024 14:59:07 -0600 Subject: [PATCH 1/4] Implement a prototype of decoding the konductor identity protobuf to get the ECID from a cookie --- kndctr.proto | 39 +++ package-lock.json | 83 +++++ package.json | 1 + src/components/Identity/createComponent.js | 6 + .../Identity/createGetEcidFromCookie.js | 34 ++ src/components/Identity/index.js | 6 + src/utils/identityProtobuf.js | 293 ++++++++++++++++++ .../Identity/createGetEcidFromCookie.spec.js | 24 ++ 8 files changed, 486 insertions(+) create mode 100644 kndctr.proto create mode 100644 src/components/Identity/createGetEcidFromCookie.js create mode 100644 src/utils/identityProtobuf.js create mode 100644 test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js diff --git a/kndctr.proto b/kndctr.proto new file mode 100644 index 000000000..627d53f02 --- /dev/null +++ b/kndctr.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +// Device-level identity for Experience Edge +message Identity { + // The Experience Cloud ID value + string ecid = 1; + + IdentityMetadata metadata = 10; + + // Used only in the 3rd party domain context. + // It stores the UNIX timestamp and some metadata about the last identity sync triggered by Experience Edge. + int64 last_sync = 20; + int64 sync_hash = 21; + int32 id_sync_container_id = 22; + + // UNIX timestamp when the Identity was last returned in a `state:store` instruction. + // The Identity is written at most once every 24h with a large TTL, to ensure it does not expire. + int64 write_time = 30; +} + +message IdentityMetadata { + // UNIX timestamp when this identity was minted. + int64 created_at = 1; + + // Whether or not the identity is random (new) or based on an existing seed. + bool is_new = 2; + + // Type of device for which the identity was generated. + // 0 = UNKNOWN, 1 = BROWSER, 2 = MOBILE + int32 device_type = 3; + + // The Experience Edge region in which the identity was minted. + string region = 5; + + // More details on the source of the ECID identity. + // Invariant: when `is_new` = true, the source must be set to `RANDOM`. + // 0 = RANDOM, 1 = THIRD_PARTY_ID, 2 = FIRST_PARTY_ID, 3 = RECEIVED_IN_REQUEST + int32 source = 6; +} diff --git a/package-lock.json b/package-lock.json index 59ec90751..4eca52aee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "inquirer": "^10.1.8", "js-cookie": "3.0.5", "parse-uri": "^1.0.9", + "protobufjs": "^7.3.3", "rollup": "^4.21.0", "rollup-plugin-license": "^3.5.2", "uuid": "^10.0.0" @@ -3384,6 +3385,60 @@ "spacetrim": "0.11.36" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@puppeteer/browsers": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", @@ -13488,6 +13543,11 @@ "dev": true, "license": "MIT" }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/loupe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", @@ -15092,6 +15152,29 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.3.tgz", + "integrity": "sha512-HaYi2CVjiPoBR1d2zTVKVHXr9IUnpJizCjUu19vxdD3B8o4z+vfOHpIEB1358w8nv8dfUNEfDHFvMsH7QlLt/Q==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-agent": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", diff --git a/package.json b/package.json index fcb0ada18..b65d6c718 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "inquirer": "^10.1.8", "js-cookie": "3.0.5", "parse-uri": "^1.0.9", + "protobufjs": "^7.3.3", "rollup": "^4.21.0", "rollup-plugin-license": "^3.5.2", "uuid": "^10.0.0" diff --git a/src/components/Identity/createComponent.js b/src/components/Identity/createComponent.js index e97310244..a49226d7d 100644 --- a/src/components/Identity/createComponent.js +++ b/src/components/Identity/createComponent.js @@ -19,6 +19,7 @@ export default ({ setLegacyEcid, handleResponseForIdSyncs, getEcidFromResponse, + getEcidFromCookie, getIdentity, consent, appendIdentityToUrl, @@ -71,6 +72,11 @@ export default ({ }); }, }, + getEcidFromCookie: { + run() { + return getEcidFromCookie(); + }, + }, appendIdentityToUrl: { optionsValidator: appendIdentityToUrlOptionsValidator, run: (options) => { diff --git a/src/components/Identity/createGetEcidFromCookie.js b/src/components/Identity/createGetEcidFromCookie.js new file mode 100644 index 000000000..6bcda3ae9 --- /dev/null +++ b/src/components/Identity/createGetEcidFromCookie.js @@ -0,0 +1,34 @@ +import { Identity } from "../../utils/identityProtobuf.js"; +import { getNamespacedCookieName } from "../../utils/index.js"; + +const base64ToBytes = (base64) => { + const binString = atob(base64); + return Uint8Array.from(binString, (m) => m.codePointAt(0)); +} + +export default ({ config, cookieJar }) => { + const { orgId } = config; + const kndctrCookieName = getNamespacedCookieName(orgId, "kndctr"); + /** + * Returns the ECID from the kndctr cookie. + * @returns {string|null} + */ + return () => { + const cookie = cookieJar.get(kndctrCookieName); + // const cookie = + // "CiYxNDAxNTI0NjEzODM4MjI2ODk1MTgwNTkyMTYxNjkxNTc0MzEyOFISCIelhf%5FOMRABGAEqA09SMjAA8AHX%5F4DZlzI%3D"; + if (!cookie) { + return null; + } + const decodedCookie = decodeURIComponent(cookie) + .replace(/_/g, "/") + .replace(/-/g, "+"); + // cookie is a base64 encoded byte representation of a Identity protobuf message + // and we need to get it to a Uint8Array in order to decode it + + const cookieBytes = base64ToBytes(decodedCookie); + const message = Identity.decode(cookieBytes); + console.log("CARTER - message", message); + return message.ecid; + }; +}; diff --git a/src/components/Identity/index.js b/src/components/Identity/index.js index 47ca0df4e..940208769 100644 --- a/src/components/Identity/index.js +++ b/src/components/Identity/index.js @@ -36,6 +36,7 @@ import createGetIdentity from "./getIdentity/createGetIdentity.js"; import createIdentityRequest from "./getIdentity/createIdentityRequest.js"; import createIdentityRequestPayload from "./getIdentity/createIdentityRequestPayload.js"; import injectAppendIdentityToUrl from "./appendIdentityToUrl/injectAppendIdentityToUrl.js"; +import createGetEcidFromCookie from "./createGetEcidFromCookie.js"; const createIdentity = ({ config, @@ -65,6 +66,10 @@ const createIdentity = ({ cookieJar: loggingCookieJar, isPageSsl: window.location.protocol === "https:", }); + const getEcidFromCookie = createGetEcidFromCookie({ + config, + cookieJar, + }); const doesIdentityCookieExist = injectDoesIdentityCookieExist({ orgId }); const getIdentity = createGetIdentity({ sendEdgeNetworkRequest, @@ -118,6 +123,7 @@ const createIdentity = ({ return createComponent({ addEcidQueryToPayload, addQueryStringIdentityToPayload, + getEcidFromCookie, ensureSingleIdentity, setLegacyEcid: legacyIdentity.setEcid, handleResponseForIdSyncs, diff --git a/src/utils/identityProtobuf.js b/src/utils/identityProtobuf.js new file mode 100644 index 000000000..67c93df0d --- /dev/null +++ b/src/utils/identityProtobuf.js @@ -0,0 +1,293 @@ +/* + * Generated automatically by the command + * `npx --package "protobufjs-cli" --command "pbjs --target static-module --wrap es6 --es6 --no-create --no-encode --no-verify --no-convert --no-delimited --no-beautify --no-service ./kndctr.proto" + */ +/* eslint-disable no-bitwise, max-classes-per-file */ +import * as $protobuf from "protobufjs/minimal"; + +// Common aliases +const $Reader = $protobuf.Reader; +const $util = $protobuf.util; + +// Exported root namespace +const $root = $protobuf.roots.default || ($protobuf.roots.default = {}); +export default $root; + +/** + * Properties of an Identity. + * @exports IIdentity + * @interface IIdentity + * @property {string|null} [ecid] Identity ecid + * @property {IIdentityMetadata|null} [metadata] Identity metadata + * @property {number|Long|null} [lastSync] Identity lastSync + * @property {number|Long|null} [syncHash] Identity syncHash + * @property {number|null} [idSyncContainerId] Identity idSyncContainerId + * @property {number|Long|null} [writeTime] Identity writeTime + */ +export class Identity { + /** + * Constructs a new Identity. + * @exports Identity + * @classdesc Represents an Identity. + * @implements IIdentity + * @constructor + * @param {IIdentity=} [p] Properties to set + */ + constructor(p) { + if (p) { + for (let ks = Object.keys(p), i = 0; i < ks.length; ++i) { + if (p[ks[i]] != null) { + this[ks[i]] = p[ks[i]]; + } + } + } + } + + /** + * Identity ecid. + * @member {string} ecid + * @memberof Identity + * @instance + */ + ecid = ""; + + /** + * Identity metadata. + * @member {IIdentityMetadata|null|undefined} metadata + * @memberof Identity + * @instance + */ + metadata = null; + + /** + * Identity lastSync. + * @member {number|Long} lastSync + * @memberof Identity + * @instance + */ + lastSync = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; + + /** + * Identity syncHash. + * @member {number|Long} syncHash + * @memberof Identity + * @instance + */ + syncHash = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; + + /** + * Identity idSyncContainerId. + * @member {number} idSyncContainerId + * @memberof Identity + * @instance + */ + idSyncContainerId = 0; + + /** + * Identity writeTime. + * @member {number|Long} writeTime + * @memberof Identity + * @instance + */ + writeTime = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; + + /** + * Decodes an Identity message from the specified reader or buffer. + * @function decode + * @memberof Identity + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Identity} Identity + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + static decode(r, l) { + if (!(r instanceof $Reader)) r = $Reader.create(r); + const c = l === undefined ? r.len : r.pos + l; + const m = new $root.Identity(); + while (r.pos < c) { + const t = r.uint32(); + switch (t >>> 3) { + case 1: { + m.ecid = r.string(); + break; + } + case 10: { + m.metadata = $root.IdentityMetadata.decode(r, r.uint32()); + break; + } + case 20: { + m.lastSync = r.int64(); + break; + } + case 21: { + m.syncHash = r.int64(); + break; + } + case 22: { + m.idSyncContainerId = r.int32(); + break; + } + case 30: { + m.writeTime = r.int64(); + break; + } + default: + r.skipType(t & 7); + break; + } + } + return m; + } + + /** + * Gets the default type url for Identity + * @function getTypeUrl + * @memberof Identity + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + static getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return `${typeUrlPrefix}/Identity`; + } +} +$root.Identity = Identity; + +/** + * Properties of an IdentityMetadata. + * @exports IIdentityMetadata + * @interface IIdentityMetadata + * @property {number|Long|null} [createdAt] IdentityMetadata createdAt + * @property {boolean|null} [isNew] IdentityMetadata isNew + * @property {number|null} [deviceType] IdentityMetadata deviceType + * @property {string|null} [region] IdentityMetadata region + * @property {number|null} [source] IdentityMetadata source + */ +export class IdentityMetadata { + /** + * Constructs a new IdentityMetadata. + * @exports IdentityMetadata + * @classdesc Represents an IdentityMetadata. + * @implements IIdentityMetadata + * @constructor + * @param {IIdentityMetadata=} [p] Properties to set + */ + constructor(p) { + if (p) { + for (let ks = Object.keys(p), i = 0; i < ks.length; ++i) { + if (p[ks[i]] != null) { + this[ks[i]] = p[ks[i]]; + } + } + } + } + + /** + * IdentityMetadata createdAt. + * @member {number|Long} createdAt + * @memberof IdentityMetadata + * @instance + */ + createdAt = $util.Long ? $util.Long.fromBits(0, 0, false) : 0; + + /** + * IdentityMetadata isNew. + * @member {boolean} isNew + * @memberof IdentityMetadata + * @instance + */ + isNew = false; + + /** + * IdentityMetadata deviceType. + * @member {number} deviceType + * @memberof IdentityMetadata + * @instance + */ + deviceType = 0; + + /** + * IdentityMetadata region. + * @member {string} region + * @memberof IdentityMetadata + * @instance + */ + region = ""; + + /** + * IdentityMetadata source. + * @member {number} source + * @memberof IdentityMetadata + * @instance + */ + source = 0; + + /** + * Decodes an IdentityMetadata message from the specified reader or buffer. + * @function decode + * @memberof IdentityMetadata + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {IdentityMetadata} IdentityMetadata + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + static decode(r, l) { + if (!(r instanceof $Reader)) { + r = $Reader.create(r); + } + const c = l === undefined ? r.len : r.pos + l; + const m = new $root.IdentityMetadata(); + while (r.pos < c) { + const t = r.uint32(); + switch (t >>> 3) { + case 1: { + m.createdAt = r.int64(); + break; + } + case 2: { + m.isNew = r.bool(); + break; + } + case 3: { + m.deviceType = r.int32(); + break; + } + case 5: { + m.region = r.string(); + break; + } + case 6: { + m.source = r.int32(); + break; + } + default: + r.skipType(t & 7); + break; + } + } + return m; + } + + /** + * Gets the default type url for IdentityMetadata + * @function getTypeUrl + * @memberof IdentityMetadata + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + static getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return `${typeUrlPrefix}/IdentityMetadata`; + } +} +$root.IdentityMetadata = IdentityMetadata; diff --git a/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js b/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js new file mode 100644 index 000000000..14f203e86 --- /dev/null +++ b/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js @@ -0,0 +1,24 @@ +import createGetEcidFromCookiefrom "../../../../../src/components/Identity/createGetEcidFromCookie"; + +describe("Identity::createGetEcidFromCookie", () => { + let cookieValue; + let cookieJar; + let getEcidFromCookie; + beforeEach(() => { + cookieValue = "CiYxNDAxNTI0NjEzODM4MjI2ODk1MTgwNTkyMTYxNjkxNTc0MzEyOFISCIelhf%5FOMRABGAEqA09SMjAA8AHX%5F4DZlzI%3D"; + cookieJar = jasmine.createSpyObj("cookieJar", { + get: cookieValue + }); + getEcidFromCookie = createGetEcidFromCookie({ + config: { + orgId: "TEST_ORG" + }, + cookieJar + }); + }); + + it("should return the ecid from the cookie", () => { + const result = getEcidFromCookie(); + expect(result).toBe("14015246138382268951805921616915743128"); + }); +}); From 447817c76320da281067fb2436ae85016c488fe4 Mon Sep 17 00:00:00 2001 From: Carter McBride Date: Thu, 22 Aug 2024 16:43:53 -0600 Subject: [PATCH 2/4] Add link to source of protobuf definition file --- kndctr.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kndctr.proto b/kndctr.proto index 627d53f02..cc2233437 100644 --- a/kndctr.proto +++ b/kndctr.proto @@ -1,3 +1,5 @@ +// From https://git.corp.adobe.com/pages/experience-edge/konductor/#/api/identifying-visitors?id=device-identifiers + syntax = "proto3"; // Device-level identity for Experience Edge From f75da495d729bb36902c9149619e33fadb127cd2 Mon Sep 17 00:00:00 2001 From: Carter McBride Date: Thu, 22 Aug 2024 16:50:19 -0600 Subject: [PATCH 3/4] Remove temp code --- src/components/Identity/createGetEcidFromCookie.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/Identity/createGetEcidFromCookie.js b/src/components/Identity/createGetEcidFromCookie.js index 6bcda3ae9..a22278223 100644 --- a/src/components/Identity/createGetEcidFromCookie.js +++ b/src/components/Identity/createGetEcidFromCookie.js @@ -15,8 +15,6 @@ export default ({ config, cookieJar }) => { */ return () => { const cookie = cookieJar.get(kndctrCookieName); - // const cookie = - // "CiYxNDAxNTI0NjEzODM4MjI2ODk1MTgwNTkyMTYxNjkxNTc0MzEyOFISCIelhf%5FOMRABGAEqA09SMjAA8AHX%5F4DZlzI%3D"; if (!cookie) { return null; } @@ -28,7 +26,6 @@ export default ({ config, cookieJar }) => { const cookieBytes = base64ToBytes(decodedCookie); const message = Identity.decode(cookieBytes); - console.log("CARTER - message", message); return message.ecid; }; }; From 7053dc959fdf9ae7538b73e51e94347f79ee4285 Mon Sep 17 00:00:00 2001 From: Carter McBride Date: Thu, 22 Aug 2024 17:19:51 -0600 Subject: [PATCH 4/4] Add (weak) identity protobuy test --- .../Identity/createGetEcidFromCookie.js | 13 ++++++++++- src/utils/identityProtobuf.js | 12 ++++------ .../Identity/createGetEcidFromCookie.spec.js | 13 ++++++----- .../unit/specs/utils/identityProtobuf.spec.js | 23 +++++++++++++++++++ 4 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 test/unit/specs/utils/identityProtobuf.spec.js diff --git a/src/components/Identity/createGetEcidFromCookie.js b/src/components/Identity/createGetEcidFromCookie.js index a22278223..838892448 100644 --- a/src/components/Identity/createGetEcidFromCookie.js +++ b/src/components/Identity/createGetEcidFromCookie.js @@ -1,10 +1,21 @@ +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ import { Identity } from "../../utils/identityProtobuf.js"; import { getNamespacedCookieName } from "../../utils/index.js"; const base64ToBytes = (base64) => { const binString = atob(base64); return Uint8Array.from(binString, (m) => m.codePointAt(0)); -} +}; export default ({ config, cookieJar }) => { const { orgId } = config; diff --git a/src/utils/identityProtobuf.js b/src/utils/identityProtobuf.js index 67c93df0d..5197b1ee2 100644 --- a/src/utils/identityProtobuf.js +++ b/src/utils/identityProtobuf.js @@ -3,14 +3,10 @@ * `npx --package "protobufjs-cli" --command "pbjs --target static-module --wrap es6 --es6 --no-create --no-encode --no-verify --no-convert --no-delimited --no-beautify --no-service ./kndctr.proto" */ /* eslint-disable no-bitwise, max-classes-per-file */ -import * as $protobuf from "protobufjs/minimal"; - -// Common aliases -const $Reader = $protobuf.Reader; -const $util = $protobuf.util; +import { $Reader, $util, roots } from "protobufjs/minimal.js"; // Exported root namespace -const $root = $protobuf.roots.default || ($protobuf.roots.default = {}); +const $root = roots.default || (roots.default = {}); export default $root; /** @@ -35,7 +31,7 @@ export class Identity { */ constructor(p) { if (p) { - for (let ks = Object.keys(p), i = 0; i < ks.length; ++i) { + for (let ks = Object.keys(p), i = 0; i < ks.length; i += 1) { if (p[ks[i]] != null) { this[ks[i]] = p[ks[i]]; } @@ -179,7 +175,7 @@ export class IdentityMetadata { */ constructor(p) { if (p) { - for (let ks = Object.keys(p), i = 0; i < ks.length; ++i) { + for (let ks = Object.keys(p), i = 0; i < ks.length; i += 1) { if (p[ks[i]] != null) { this[ks[i]] = p[ks[i]]; } diff --git a/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js b/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js index 14f203e86..f35d94fb5 100644 --- a/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js +++ b/test/unit/specs/components/Identity/createGetEcidFromCookie.spec.js @@ -1,19 +1,20 @@ -import createGetEcidFromCookiefrom "../../../../../src/components/Identity/createGetEcidFromCookie"; +import createGetEcidFromCookie from "../../../../../src/components/Identity/createGetEcidFromCookie.js"; describe("Identity::createGetEcidFromCookie", () => { let cookieValue; let cookieJar; let getEcidFromCookie; beforeEach(() => { - cookieValue = "CiYxNDAxNTI0NjEzODM4MjI2ODk1MTgwNTkyMTYxNjkxNTc0MzEyOFISCIelhf%5FOMRABGAEqA09SMjAA8AHX%5F4DZlzI%3D"; + cookieValue = + "CiYxNDAxNTI0NjEzODM4MjI2ODk1MTgwNTkyMTYxNjkxNTc0MzEyOFISCIelhf%5FOMRABGAEqA09SMjAA8AHX%5F4DZlzI%3D"; cookieJar = jasmine.createSpyObj("cookieJar", { - get: cookieValue + get: cookieValue, }); getEcidFromCookie = createGetEcidFromCookie({ config: { - orgId: "TEST_ORG" + orgId: "TEST_ORG", }, - cookieJar + cookieJar, }); }); @@ -21,4 +22,4 @@ describe("Identity::createGetEcidFromCookie", () => { const result = getEcidFromCookie(); expect(result).toBe("14015246138382268951805921616915743128"); }); -}); +}); diff --git a/test/unit/specs/utils/identityProtobuf.spec.js b/test/unit/specs/utils/identityProtobuf.spec.js new file mode 100644 index 000000000..a81b2052d --- /dev/null +++ b/test/unit/specs/utils/identityProtobuf.spec.js @@ -0,0 +1,23 @@ +import { Identity } from "../../../../src/utils/identityProtobuf.js"; + +const base64ToBytes = (base64) => { + const binString = atob(base64); + return Uint8Array.from(binString, (m) => m.codePointAt(0)); +}; + +describe("Utils::identityProtobuf", () => { + let message; + beforeEach(() => { + const messageStr = + "CiYxNTkyMTM0MTU3ODg1MzkxOTM2MDExOTIxMzkxNzkyNTE5NzMyMlISCMjKluKXMhABGAEqA09SMjAAoAHrypbilzKwAbyzAfAByMqW4pcy"; + const decodedMessage = decodeURIComponent(messageStr) + .replace(/_/g, "/") + .replace(/-/g, "+"); + message = base64ToBytes(decodedMessage); + }); + + it("should decode the message", () => { + const result = Identity.decode(message); + expect(result.ecid).toBe("15921341578853919360119213917925197322"); + }); +});