PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / wordads / js / wordads-ccpa.js
jetpack / modules / wordads / js Last commit date
adflow-loader.js 7 months ago cmp-loader.js 2 years ago wordads-ccpa.js 1 year ago
wordads-ccpa.js
356 lines
1 /**
2 * Outputs Javascript to handle California IP detection, consent modal, and setting of default cookies.
3 */
4 ( function () {
5 /* global ccpaSettings */
6
7 // Minimal Mozilla Cookie library.
8 // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework
9 var cookieLib = {
10 getItem: function ( e ) {
11 return (
12 ( e &&
13 decodeURIComponent(
14 document.cookie.replace(
15 new RegExp(
16 '(?:(?:^|.*;)\\s*' +
17 encodeURIComponent( e ).replace( /[-.+*]/g, '\\$&' ) +
18 '\\s*\\=\\s*([^;]*).*$)|^.*$'
19 ),
20 '$1'
21 )
22 ) ) ||
23 null
24 );
25 },
26 setItem: function ( e, o, n, t, r, i ) {
27 if ( ! e || /^(?:expires|max-age|path|domain|secure)$/i.test( e ) ) {
28 return ! 1;
29 }
30 var c = '';
31 if ( n ) {
32 switch ( n.constructor ) {
33 case Number:
34 c = n === 1 / 0 ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + n;
35 break;
36 case String:
37 c = '; expires=' + n;
38 break;
39 case Date:
40 c = '; expires=' + n.toUTCString();
41 }
42 }
43 return (
44 ( 'rootDomain' !== r && '.rootDomain' !== r ) ||
45 ( r =
46 ( '.rootDomain' === r ? '.' : '' ) +
47 document.location.hostname.split( '.' ).slice( -2 ).join( '.' ) ),
48 ( document.cookie =
49 encodeURIComponent( e ) +
50 '=' +
51 encodeURIComponent( o ) +
52 c +
53 ( r ? '; domain=' + r : '' ) +
54 ( t ? '; path=' + t : '' ) +
55 ( i ? '; secure' : '' ) ),
56 ! 0
57 );
58 },
59 };
60
61 // Implement IAB USP API.
62 window.__uspapi = function ( command, version, callback ) {
63 // Validate callback.
64 if ( typeof callback !== 'function' ) {
65 return;
66 }
67
68 // Validate the given command.
69 if ( command !== 'getUSPData' || version !== 1 ) {
70 callback( null, false );
71 return;
72 }
73
74 // Check for GPC. If set, override any stored cookie.
75 if ( navigator.globalPrivacyControl ) {
76 callback( { version: 1, uspString: '1YYN' }, true );
77 return;
78 }
79
80 // Check for cookie.
81 var consent = cookieLib.getItem( 'usprivacy' );
82
83 // Invalid cookie.
84 if ( null === consent ) {
85 callback( null, false );
86 return;
87 }
88
89 // Everything checks out. Fire the provided callback with the consent data.
90 callback( { version: 1, uspString: consent }, true );
91 };
92
93 var setDefaultOptInCookie = function () {
94 var value = ccpaSettings.defaultOptInCookieString;
95 var domain =
96 '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
97 cookieLib.setItem( 'usprivacy', value, 365 * 24 * 60 * 60, '/', domain );
98 };
99
100 var setDefaultOptOutCookie = function () {
101 var value = ccpaSettings.defaultOptOutCookieString;
102 var domain =
103 '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
104 cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
105 };
106
107 var setDefaultNotApplicableCookie = function () {
108 var value = '1---';
109 var domain =
110 '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
111 cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
112 };
113
114 var setCcpaAppliesCookie = function ( value ) {
115 var domain =
116 '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
117 cookieLib.setItem( 'ccpa_applies', value, 24 * 60 * 60, '/', domain );
118 };
119
120 var injectLoadingMessage = function () {
121 var wrapper = document.createElement( 'div' );
122 document.body.insertBefore( wrapper, document.body.firstElementChild );
123 wrapper.outerHTML =
124 '<div id="ccpa-loading" class="cleanslate ccpa__loading-wrapper">' +
125 '<div class="ccpa__loading-overlay">' +
126 '<span class="ccpa__loading-message">' +
127 ccpaSettings.strings.pleaseWait +
128 '...</span>' +
129 '</div>' +
130 '</div>';
131 };
132
133 var destroyModal = function () {
134 var node = document.querySelector( '#ccpa-modal' );
135
136 if ( node ) {
137 node.parentElement.removeChild( node );
138 }
139 };
140
141 var injectModal = function () {
142 destroyModal();
143
144 injectLoadingMessage();
145
146 var request = new XMLHttpRequest();
147 request.open(
148 'GET',
149 ccpaSettings.ajaxUrl + '?action=privacy_optout_markup&security=' + ccpaSettings.ajaxNonce,
150 true
151 );
152 request.onreadystatechange = function () {
153 if ( 4 === this.readyState ) {
154 if ( 200 === this.status ) {
155 document.getElementById( 'ccpa-loading' ).remove();
156 var wrapper = document.createElement( 'div' );
157 document.body.insertBefore( wrapper, document.body.firstElementChild );
158 wrapper.outerHTML = this.response;
159 document.getElementById( 'ccpa-opt-out' ).focus();
160
161 var optOut = document.querySelector( '#ccpa-modal .opt-out' );
162 optOut.addEventListener( 'click', function ( e ) {
163 var post = new XMLHttpRequest();
164 post.open( 'POST', ccpaSettings.ajaxUrl, true );
165 post.setRequestHeader(
166 'Content-Type',
167 'application/x-www-form-urlencoded; charset=UTF-8'
168 );
169 post.onreadystatechange = function () {
170 if ( 4 === this.readyState ) {
171 if ( 200 === this.status ) {
172 var result = JSON.parse( this.response );
173
174 if ( result && result.success ) {
175 // Note: Cooke is set in HTTP response from POST, so only need to update the toggle switch state.
176 if ( result.data ) {
177 e.target.parentNode.classList.add( 'is-checked' );
178 e.target.parentNode.parentNode.classList.add( 'is-checked' );
179 } else {
180 e.target.parentNode.classList.remove( 'is-checked' );
181 e.target.parentNode.parentNode.classList.remove( 'is-checked' );
182 }
183 }
184 }
185 }
186 };
187 post.send(
188 'action=privacy_optout&optout=' +
189 e.target.checked +
190 '&security=' +
191 ccpaSettings.ajaxNonce
192 );
193 } );
194
195 // Set initial toggle status based on cookie data.
196 var usprivacyCookie = cookieLib.getItem( 'usprivacy' );
197 var optout = usprivacyCookie && 'Y' === usprivacyCookie[ 2 ];
198 var toggle = document.querySelector( '#ccpa-modal .opt-out' );
199
200 toggle.checked = optout;
201
202 if ( optout ) {
203 toggle.parentNode.classList.add( 'is-checked' );
204 toggle.parentNode.parentNode.classList.add( 'is-checked' );
205 }
206
207 var buttons = document.querySelectorAll( '#ccpa-modal .components-button' );
208 Array.prototype.forEach.call( buttons, function ( el ) {
209 el.addEventListener( 'click', function () {
210 destroyModal();
211 } );
212 } );
213 }
214 }
215 };
216
217 request.send();
218 };
219
220 var dispatchInitializedEvent = function ( ccpaApplies ) {
221 // Dispatches a custom event with data indicating if the CCPA applies or not once it has been determined.
222 // Sites can listen for this event and do additional processing, e.g. showing or hiding additional elements.
223 var event = document.createEvent( 'CustomEvent' );
224 event.initCustomEvent( 'wordads-ccpa-initialized', true, false, { ccpaApplies: ccpaApplies } );
225 document.dispatchEvent( event );
226 };
227
228 var initialize = function ( ccpaApplies, usprivacyCookie ) {
229 // Get any Do Not Sell links on the page.
230 var dnsLinks = document.querySelectorAll( '.ccpa-do-not-sell' );
231
232 // No usprivacy cookie, so we need to set it.
233 if ( null === usprivacyCookie ) {
234 if ( ccpaApplies ) {
235 if ( 0 === dnsLinks.length ) {
236 // Could not find a Do Not Sell link as required, so default to opt-OUT just to be safe.
237 setDefaultOptOutCookie();
238 } else {
239 // Found a Do Not Sell link, so set default opt-in.
240 setDefaultOptInCookie();
241 }
242 } else {
243 // CCPA does not apply.
244 setDefaultNotApplicableCookie();
245 }
246 }
247
248 // If CCPA does not apply, and we are not overriding it for admins, then we can stop here.
249 if ( ! ccpaApplies && 'false' === ccpaSettings.forceApplies ) {
250 dispatchInitializedEvent( false );
251 return;
252 }
253
254 // Displays Do Not Sell links and adds handlers to display the modal when clicked.
255 Array.prototype.forEach.call( dnsLinks, function ( dnsLink ) {
256 dnsLink.addEventListener( 'click', function ( e ) {
257 e.preventDefault();
258
259 if ( ! ccpaSettings.stylesLoaded ) {
260 // Load wordads-ccpa.min.css.
261 var ccpaCss = document.createElement( 'link' );
262 ccpaCss.rel = 'stylesheet';
263 ccpaCss.type = 'text/css';
264 ccpaCss.href = ccpaSettings.ccpaCssUrl;
265 document.getElementsByTagName( 'HEAD' )[ 0 ].appendChild( ccpaCss );
266
267 ccpaSettings.stylesLoaded = true;
268 }
269
270 injectModal();
271 } );
272
273 // Make the link visible.
274 dnsLink.style.display = '';
275 } );
276
277 // CCPA applies (or we're forcing it to display for admins). Let any listeners know.
278 dispatchInitializedEvent( true );
279 };
280
281 // Setup CCPA on DOM loaded.
282 document.addEventListener( 'DOMContentLoaded', function () {
283 // Look for usprivacy cookies first.
284 var usprivacyCookie = cookieLib.getItem( 'usprivacy' );
285
286 // Found a usprivacy cookie.
287 if ( null !== usprivacyCookie ) {
288 // CCPA does not apply.
289 if ( '1---' === usprivacyCookie ) {
290 initialize( false, usprivacyCookie );
291 } else {
292 // CCPA applies.
293 initialize( true, usprivacyCookie );
294 }
295
296 // No more processing needed.
297 return;
298 }
299
300 // We don't have a usprivacy cookie, so check to see if we have a CCPA applies cookie.
301 var ccpaCookie = cookieLib.getItem( 'ccpa_applies' );
302
303 // No CCPA applies cookie found, so we'll need to geolocate if this visitor is from applicable US state.
304 // This needs to happen client side because we do not have region geo data in our $SERVER headers,
305 // only country data -- therefore we can't vary cache on the region.
306 if ( null === ccpaCookie ) {
307 var request = new XMLHttpRequest();
308 request.open( 'GET', 'https://public-api.wordpress.com/geo/', true );
309
310 request.onreadystatechange = function () {
311 if ( 4 === this.readyState ) {
312 if ( 200 === this.status ) {
313 // Got a geo response. Parse out the region data.
314 var data = JSON.parse( this.response );
315 var region = data.region ? data.region.toLowerCase() : '';
316 var ccpaApplies =
317 [
318 'california',
319 'colorado',
320 'connecticut',
321 'delaware',
322 'indiana',
323 'iowa',
324 'montana',
325 'new jersey',
326 'oregon',
327 'tennessee',
328 'texas',
329 'utah',
330 'virginia',
331 ].indexOf( region ) > -1;
332
333 // Set CCPA applies cookie. This keeps us from having to make a geo request too frequently.
334 setCcpaAppliesCookie( ccpaApplies );
335
336 // Perform the rest of the initialization.
337 initialize( ccpaApplies, null );
338 } else {
339 // Geolocation request failed, so default to CCPA applies just to be safe.
340 setCcpaAppliesCookie( true );
341
342 // Perform the rest of the initialization.
343 initialize( true, null );
344 }
345 }
346 };
347
348 // Send the geo request.
349 request.send();
350 } else {
351 // We found a CCPA applies cookie. Continue with initialization.
352 initialize( 'true' === ccpaCookie, null );
353 }
354 } );
355 } )();
356