Skip to content

Commit

Permalink
[Feature] Add option to block the creation and usage of the cookies b…
Browse files Browse the repository at this point in the history
…y name #1901
  • Loading branch information
MSNev committed Sep 15, 2022
1 parent ac1d628 commit a648118
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 5 deletions.
99 changes: 97 additions & 2 deletions shared/AppInsightsCore/Tests/Unit/src/CookieManager.Tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Assert, AITestClass } from "@microsoft/ai-test-framework";
import { AppInsightsCore, CoreUtils, createCookieMgr, IAppInsightsCore, IConfiguration, ICookieMgrConfig, IPlugin, ITelemetryItem, newId, _legacyCookieMgr } from "../../../src/applicationinsights-core-js"
import { AppInsightsCore, CoreUtils, createCookieMgr, IAppInsightsCore, IConfiguration, ICookieMgrConfig, IPlugin, ITelemetryItem, newId, objExtend, _legacyCookieMgr } from "../../../src/applicationinsights-core-js"
import { _InternalMessageId, LoggingSeverity } from "../../../src/JavaScriptSDK.Enums/LoggingEnums";
import { _InternalLogMessage, DiagnosticLogger } from "../../../src/JavaScriptSDK/DiagnosticLogger";

Expand Down Expand Up @@ -396,7 +396,6 @@ export class CookieManagerTests extends AITestClass {
}
});


this.testCase({
name: "CookieManager: validate setting _canUseCookies correctly enables or blocks cookie usage",
test: () => {
Expand Down Expand Up @@ -427,6 +426,102 @@ export class CookieManagerTests extends AITestClass {
Assert.equal(true, manager.isEnabled());
}
});

this.testCase({
name: "CookieManager: validate ignore Cookies empty setting",
test: () => {

let cookieCfg: ICookieMgrConfig = objExtend(true, {}, this._cookieMgrCfg);
cookieCfg.ignoreCookies = [];

let core = new AppInsightsCore();
core.initialize({
instrumentationKey: "testiKey",
cookieDomain: "MyDomain.com",
cookieCfg: cookieCfg
}, [new ChannelPlugin()]);

let manager = core.getCookieMgr();

let newKey = "test." + newId();
let newValue = newId();
manager.set(newKey, newValue);
Assert.equal(newValue, manager.get(newKey));
Assert.equal(newValue + "; domain=MyDomain.com; path=/", this._testCookies[newKey]);

manager.del(newKey);
Assert.equal("", manager.get(newKey));
Assert.equal(undefined, this._testCookies[newKey]);
}
});

this.testCase({
name: "CookieManager: validate ignore Cookies with a single cookie",
test: () => {

let cookieCfg: ICookieMgrConfig = objExtend(true, {}, this._cookieMgrCfg);
cookieCfg.ignoreCookies = [ "testCookie" ];

let core = new AppInsightsCore();
core.initialize({
instrumentationKey: "testiKey",
cookieDomain: "MyDomain.com",
cookieCfg: cookieCfg
}, [new ChannelPlugin()]);

let manager = core.getCookieMgr();

this._testCookies["testCookie"] = "test value";
Assert.equal("", manager.get("testCookie"), "Check that it can't read the cookie value");

manager.set("testCookie", "new value");
Assert.equal("test value", this._testCookies["testCookie"], "The value was not overwritten");

let newKey = "test." + newId();
let newValue = newId();
manager.set(newKey, newValue);
Assert.equal(newValue, manager.get(newKey));
Assert.equal(newValue + "; domain=MyDomain.com; path=/", this._testCookies[newKey]);

manager.del(newKey);
Assert.equal("", manager.get(newKey));
Assert.equal(undefined, this._testCookies[newKey]);
}
});

this.testCase({
name: "CookieManager: validate blocked Cookies with a single cookie",
test: () => {

let cookieCfg: ICookieMgrConfig = objExtend(true, {}, this._cookieMgrCfg);
cookieCfg.blockedCookies = [ "testCookie" ];

let core = new AppInsightsCore();
core.initialize({
instrumentationKey: "testiKey",
cookieDomain: "MyDomain.com",
cookieCfg: cookieCfg
}, [new ChannelPlugin()]);

let manager = core.getCookieMgr();

this._testCookies["testCookie"] = "test value";
Assert.equal("test value", manager.get("testCookie"), "Check that it can't read the cookie value");

manager.set("testCookie", "new value");
Assert.equal("test value", this._testCookies["testCookie"], "The value was not overwritten");

let newKey = "test." + newId();
let newValue = newId();
manager.set(newKey, newValue);
Assert.equal(newValue, manager.get(newKey));
Assert.equal(newValue + "; domain=MyDomain.com; path=/", this._testCookies[newKey]);

manager.del(newKey);
Assert.equal("", manager.get(newKey));
Assert.equal(undefined, this._testCookies[newKey]);
}
});
}
}

Expand Down
13 changes: 13 additions & 0 deletions shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/ICookieMgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@ export interface ICookieMgrConfig {
*/
path?: string;

/**
* Specify the cookies names to be ignored, this is a simple mechanism to cause any cookie with the provided names
* to never be read or written. They may still be explicitly purged or deleted.
*/
ignoreCookies?: string[];

/**
* Specify the cookies names to never be written, this is a simple mechanism to cause any cookie with the provided
* names to never be created or updated, they will still be read unless also included in the ignoreCookies and may
* still be explicitly purged or deleted. If not provided defaults to the same list provided in ignoreCookies.
*/
blockedCookies?: string[];

/**
* Hook function to fetch the named cookie value.
* @param name - The name of the cookie
Expand Down
24 changes: 21 additions & 3 deletions shared/AppInsightsCore/src/JavaScriptSDK/CookieMgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger
import { _throwInternal } from "./DiagnosticLogger";
import { dumpObj, getDocument, getLocation, getNavigator, isIE } from "./EnvUtils";
import {
arrForEach, dateNow, getExceptionName, isFunction, isNotNullOrUndefined, isNullOrUndefined, isString, isTruthy, isUndefined,
arrForEach, dateNow, getExceptionName, isArray, isFunction, isNotNullOrUndefined, isNullOrUndefined, isString, isTruthy, isUndefined,
objForEachKey, setValue, strContains, strEndsWith, strTrim
} from "./HelperFuncs";
import { STR_EMPTY } from "./InternalConstants";
Expand Down Expand Up @@ -81,6 +81,24 @@ function _createCookieMgrConfig(rootConfig: IConfiguration): ICookieMgrConfig {
return cookieMgrCfg;
}

function _isIgnoredCookie(cookieMgrCfg: ICookieMgrConfig, name: string) {
if (name && cookieMgrCfg && isArray(cookieMgrCfg.ignoreCookies)) {
return cookieMgrCfg.ignoreCookies.indexOf(name) !== -1;
}

return false;
}

function _isBlockedCookie(cookieMgrCfg: ICookieMgrConfig, name: string) {
if (name && cookieMgrCfg && isArray(cookieMgrCfg.blockedCookies)) {
if (cookieMgrCfg.blockedCookies.indexOf(name) !== -1) {
return true;
}
}

return _isIgnoredCookie(cookieMgrCfg, name);
}

/**
* Helper to return the ICookieMgr from the core (if not null/undefined) or a default implementation
* associated with the configuration or a legacy default.
Expand Down Expand Up @@ -138,7 +156,7 @@ export function createCookieMgr(rootConfig?: IConfiguration, logger?: IDiagnosti
},
set: (name: string, value: string, maxAgeSec?: number, domain?: string, path?: string) => {
let result = false;
if (_isMgrEnabled(cookieMgr)) {
if (_isMgrEnabled(cookieMgr) && !_isBlockedCookie(cookieMgrConfig, name)) {
let values: any = {};
let theValue = strTrim(value || STR_EMPTY);
let idx = theValue.indexOf(";");
Expand Down Expand Up @@ -198,7 +216,7 @@ export function createCookieMgr(rootConfig?: IConfiguration, logger?: IDiagnosti
},
get: (name: string): string => {
let value = STR_EMPTY
if (_isMgrEnabled(cookieMgr)) {
if (_isMgrEnabled(cookieMgr) && !_isIgnoredCookie(cookieMgrConfig, name)) {
value = (cookieMgrConfig.getCookie || _getCookieValue)(name);
}

Expand Down

0 comments on commit a648118

Please sign in to comment.