Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions JavaScriptResource.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ fiftyoneDegreesManager = function() {
if(startsWith(nextKey, session51DataPrefix)){
let name =
nextKey.substring(session51DataPrefix.length);
// A name holding a quote was stored by an earlier
// version of this script, which took the text of
// a join for a fixed name. No snippet writes a
// result by that name, so it is not sent.
if(name.indexOf('"') !== -1){
continue;
}
if(!Object.prototype.hasOwnProperty.call(
fodValues, name)){
fodValues[name] = window.sessionStorage[nextKey];
Expand Down Expand Up @@ -796,7 +803,20 @@ fiftyoneDegreesManager = function() {
// then process them and perform any call-backs required.
if (jsProperties !== undefined && jsProperties.length > 0) {

let valueSetPrefix = new RegExp('document\\.cookie\\s*=\\s*(("([A-Za-z0-9_"\\s\\+]+)\\s*=\\s*"\\s*\\+\\s*([^\\s};]+))|(`([A-Za-z0-9_]+)\\s*=\\s*\\$\\{([^}]+)\\}`))', 'g');
// The stores a snippet makes, found in its text. Group 3 is the
// name of a quoted store and group 6 the name of a template
// literal store, and groups 4 and 7 start their values. A quoted
// name is a fixed start, optionally joined with + to further
// quoted text and to plain variable names, as in
// "51D_Pos_" + key + "=" and "51D_Bandwidth" + "=". Group 3 then
// holds the text between the outer quotes, so the rewrite below
// puts the same join inside the session storage key and the
// snippet builds the same name there as it would for a cookie.
// Any other form, such as a name joined to a member or a call,
// or a template literal with anything but a fixed name and one
// value, is not matched, and its store is left as it is rather
// than rewritten under a name the pattern did not understand.
let valueSetPrefix = new RegExp('document\\.cookie\\s*=\\s*(("([A-Za-z0-9_]+(?:"\\s*\\+\\s*(?:[A-Za-z_$][A-Za-z0-9_$]*\\s*\\+\\s*)*"[A-Za-z0-9_]*)*)\\s*=\\s*"\\s*\\+\\s*([^\\s};]+))|(`([A-Za-z0-9_]+)\\s*=\\s*\\$\\{([^}]+)\\}`))', 'g');
let session51DataPrefix = sessionKey + "_data_";
{{^_enableCookies}}
let sessionSetPatch = 'window.sessionStorage["' + session51DataPrefix + '$3$6"]=$4$7';
Expand All @@ -811,12 +831,23 @@ fiftyoneDegreesManager = function() {
// result goes to session storage whatever the cookie setting, so
// the script gains no cookie write of its own, and
// getFodSavedValues falls back to that result for a name the
// cookies do not carry.
// cookies do not carry. A quoted name joined only to further
// quoted text is one fixed name once the joins are removed. A
// quote left after that means a variable is joined in, so the
// name is only known as the snippet runs and nothing is stored
// for it here, because storing the text of the join would send
// the server a name no snippet writes.
let storeEmptyValues = function(snippet) {
let found;
valueSetPrefix.lastIndex = 0;
while ((found = valueSetPrefix.exec(snippet)) !== null) {
let valueName = found[3] || found[6];
let valueName = found[6];
if (found[3]) {
valueName = found[3].replace(/"\s*\+\s*"/g, '');
if (valueName.indexOf('"') !== -1) {
continue;
}
}
if (!valueName) {
continue;
}
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ The processJsProperties function in javascript template has a section that uses
- **Cookie Assignment**: The expression should start with `document.cookie = `
- **Spaces**: Spaces around the first `=` sign are optional
- **Cookie Name**: The name of the cookie should only contain alphanumeric characters, underscores, and must not have spaces
- **Joined Cookie Name**: In double quotes, the name can be a fixed start joined with `+` to further quoted text and to plain variable names, for example `"51D_Pos_" + key + "="` or `"51D_Bandwidth" + "="`. The session storage key is then joined the same way, so it holds the name the snippet builds as it runs
- **Assignment with Double Quotes**: The cookie value assignment can use double quotes, and the value should be set programmatically by concatenating a string with a variable or expression
- **Assignment with Backticks**: The cookie value assignment can use backticks for template literals, and the value can be set programmatically using expressions inside `${}`
- **Assignment with Backticks**: The cookie value assignment can use backticks for template literals, and the value can be set programmatically using expressions inside `${}`. The name in a template literal must be fixed
- **No Direct Value Assignment**: Directly setting a value within the string is not allowed; values must be set programmatically

A statement that does not follow these rules is not changed, so it still writes its cookie and nothing is kept in session storage for it.

Before a snippet runs, the script stores an empty value in session storage for each fixed name the snippet writes, which is how the server hears that the snippet ran and stored nothing. A name joined to a variable is only known as the snippet runs, so no empty value is stored for it.

#### Regular Expression:
```javascript
/document\.cookie\s*=\s*(("([A-Za-z0-9_"\s\+]+)\s*=\s*"\s*\+\s*([^\s};]+))|(`([A-Za-z0-9_]+)\s*=\s*\$\{([^}]+)\}`))/g
/document\.cookie\s*=\s*(("([A-Za-z0-9_]+(?:"\s*\+\s*(?:[A-Za-z_$][A-Za-z0-9_$]*\s*\+\s*)*"[A-Za-z0-9_]*)*)\s*=\s*"\s*\+\s*([^\s};]+))|(`([A-Za-z0-9_]+)\s*=\s*\$\{([^}]+)\}`))/g
```

#### Valid Examples:
Expand All @@ -36,6 +41,8 @@ document.cookie="51D_PropertyName="+screen.height; // No spaces, variable assign
document.cookie=`51D_PropertyName=${btoa(JSON.stringify(value))}` // Using a template literal with an expression
document.cookie="51D_PropertyName="+profileIds.join("|") // Assigning a value using a joined string of variables
document.cookie = `51D_PropertyName=${"True"}`; // Using backticks for programmatic value assignment
document.cookie = "51D_Pos_" + key + "=" + pos.coords[key]; // A name built from a variable as the snippet runs
document.cookie = "51D_Bandwidth" + "=" + value; // A fixed name joined from two strings
```

#### Invalid Examples:
Expand All @@ -45,6 +52,8 @@ document.cookie = "51D_PropertyName=" + profileIds.join(" ") // Spaces within th
document.cookie = " 51D_PropertyName = " + "True"; // Spaces inside the cookie name are not allowed
document.cookie = ` 51D_PropertyName =${"True"}`; // Spaces inside the template literal are not allowed
document.cookie = `51D_PropertyName=START${window.middle}END`; // Concatenating strings directly within template literals is not allowed
document.cookie = `51D_${key}=${value}`; // A name built inside a template literal is not allowed
document.cookie = "51D_" + item.key + "=" + value; // A name joined to anything but a plain variable name is not allowed
```
---

Expand Down
Loading
Loading