document.cookie doesn't see embedded expression in template literal - cookies

I'm implementing logic for cookie consent with Next.js and Google Analytics 4 (gtag.js). I've used this example as basis. The logic is simple: if user accepted cookies - load script, if not - check if cookies were already present (e.g. user changed their mind) - disable GA cookies and delete current ones, if weren't present (first time consent) - just disable GA cookies.
GA4 sets 3 cookies, one of which is -ga-(container-id). This ID should be stored as env var. To delete cookie I set Max-Age param to zero.
Code:
const router = useRouter()
useEffect(() => {
if (areCookiesAccepted) {
console.log(1)
const handleRouteChange = url => {
gtag.pageview(url)
}
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
} else {
if (
document.cookie.split(';').some(item => item.trim().startsWith('_ga=')) ||
document.cookie.split(';').some(item => item.trim().startsWith(`_ga_${process.env.NEXT_PUBLIC_GA_ID}=`)) ||
document.cookie.split(';').some(item => item.trim().startsWith('_gid='))
) {
console.log(2.1)
window.gtag('consent', 'update', {'ad_storage': 'denied', 'analytics_storage': 'denied'})
document.cookie = '_ga=; Max-Age=0;'
document.cookie = `_ga_${process.env.NEXT_PUBLIC_GA_ID}=; Max-Age=0;`
document.cookie = '_gid=; Max-Age=0;'
} else {
console.log(2.2)
window.gtag('consent', 'default', {'ad_storage': 'denied', 'analytics_storage': 'denied'})
}
}
}, [router.events, areCookiesAccepted])
The problem is that document.cookie can't see embedded env var in template literal and cookie is not being deleted, but when I expose bare ID without env var - everything works okay. I double checked - no typos in env.local file. Does anybody knows what's wrong here?

So far I ended up with hack. So this doesn't work:
document.cookie = `_ga_${process.env.NEXT_PUBLIC_GA_ID}=; Max-Age=0;`
But this works:
const cookiePair = document.cookie.split('; ').find(row => row.startsWith('_ga_'))
const cookieName = cookiePair.substring(0, cookiePair.indexOf('='))
document.cookie = `${cookieName}=; Max-Age=0;`
Cookie is being deleted successfully. Still, I'm not fully satisfied with this approach and would like to know why initial problem happens.

Related

Can't set cookie on server side Nuxt.js

I am using initial Nuxt function, that is invoked on reload, to set important data like userId and token. I can read data from cookie, but I can't save data to cookie.
initAuth(context, req) {
try {
const cookie = req.headers.cookie
if (req && cookie) {
let token = getCookieServerSide('token', cookie)
let userId = getCookieServerSide('userId', cookie)
let deviceId = getCookieServerSide('deviceId', cookie)
if (token) {
context.commit('SET_TOKEN', { token })
}
if (userId) {
userId = parseInt(userId)
context.commit('users/SET_USER_ID', userId, { root: true })
}
if (!deviceId) {
deviceId = generateUniqueId()
setCookie('deviceId', deviceId)
}
context.commit('SET_DEVICE_ID', deviceId)
}
} catch (error) {}
This is initial method, and setCookie looks like this:
export const setCookie = (name, value) => {
Cookie.set(name, value)
}
By reading different comments this should be valid solution, but cookie isn't saved
Your current cookie lib is only compatible with an execution on the front-end code.
To set cookie on both client and server sides, you have to use a lib that supports an universal usage, like universal-cookie.
With Nuxt, you can use cookie-universal-nuxt to set, get and remove cookies in both client and server side, based on the previous lib.

Trying to get a cookie value which I set on ARCGIS online but not getting any value back?

I am trying to set a cookie in ESRI Arcgis online using ESRI runtime SDK for .net v100.
var cookie = new CookieHeaderValue("customCookie", cred.Token);
var response = Request.CreateResponse(HttpStatusCode.OK, new {
token = cred.Token,
expires = cred.ExpirationDate
});
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return response;
Now when I try to retrieve that cookie later on in subsequent requests using below I get null.
CookieHeaderValue cookie = context.Request.Headers.GetCookies("customCookie").FirstOrDefault();
I am wondering if there is another way to get the cookie which I set back?
Are you using v100?
If yes, you can try the following code:
ArcGISHttpClientHandler.HttpRequestBegin += (sender, request) =>
{
var cookieContainer = ((System.Net.Http.HttpClientHandler)sender).CookieContainer;
var cookies = cookieContainer.GetCookies(request.RequestUri);
var customCookie = new Cookie("customCookie", "someValue") { Domain = request.RequestUri.Host };
bool foundCookie = false;
foreach (Cookie cookie in cookies)
{
if (cookie.Name == customCookie.Name)
{
foundCookie = true;
break;
}
}
if (!foundCookie)
cookieContainer.Add(customCookie);
};
ArcGISHttpClientHandler has an event HttpRequestBegin which is invoked on every request. You can use CookieContainer.GetCookies and Add to retrieve/add cookies.

How can I get and set cookies inside webview tag of nwjs?

So my app just open a new window of a local html file with a webview tag of some webpage. But when I tried to get the cookies, I cannot get anything.I think the reason is the cookie is bounded to the url of the webview tag but now my local file but when I can only get the window of the local file.How can I solve this problem?
it might be late but i will answer this for future visitors :P
I think the best and the direct way to set and get cookies without any workarounds is to use webview request interceptors and change the request and response headers this is more secure and reliable and will work in nodewebkit, electron and chromium extensions and apps:
So to set headers you can use onBeforeSendHeaders,
for example lets say you want to change a cookie called "connect.sid" that used as session id in expressjs you can do the following:
var new_sessionId = "s%randskbksbdfmnsdbf345k345h34k5";
var $webview = $("#my-webview");
$webview.get(0).request.onBeforeSendHeaders.addListener(
function (details) {
details.requestHeaders.forEach(function (header) {
if (header.name === "Cookie") {
var cookies = header.value.split("; ");
var valid_cookies = cookies.filter(function (cookie) {
return cookie && cookie.indexOf("connect.sid") < 0;
});
valid_cookies.push("connect.sid=" + new_sessionId);
header.value = valid_cookies.join("; ");
}
});
return {requestHeaders: details.requestHeaders};
},
{urls: ["<all_urls>"]},
["blocking", "requestHeaders"]
);
$webview.attr("src","http://example.com");
and to read headers you can use onHeadersReceived
var $webview = $("#my-webview");
$webview.get(0).request.onHeadersReceived.addListener(function (details) {
details.responseHeaders.forEach(function (header) {
if (header.name === "set-cookie") {
var cookies = header.value.split("; ");
var sessionCookie = cookies.find(function (cookie) {
return cookie && cookie.indexOf("connect.sid") === 0;
});
if (sessionCookie) {
var sessionId = sessionCookie.split("=")[1];
console.log(sessionId);
}
}
});
},
{urls: ["<all_urls>"]},
["blocking", "responseHeaders"]
);
$webview.attr("src","http://example.com");
Note: you can also set and get cookies for your main window using this method but instead of intercepting webview.request you can intercept chrome.webRequest or just use chrome.cookies.set and chrome.cookies.get, i found all these things in chromium source code ;)

Django rest framework - Authentication error with PUT requests

I have a very simple Resource like this for my model 'Presentacion'
class PresentacionResource(ModelResource):
model = Presentacion
fields = (some fields)
ignore_fields = (few to ignore)
and I need to implement authentication for this, so as I read, I created two wrappers
class AuthListOrCreateModelView(ListOrCreateModelView):
permissions = (IsAuthenticated, )
class AuthInstanceModelView(InstanceModelView):
permissions = (IsAuthenticated, )
And then in my in my urls.py
url(r'^presentaciones/$', AuthListOrCreateModelView.as_view(resource=PresentacionResource), name='presentacion-root'),
url(r'^presentaciones/(?P<id>[0-9]+)$', AuthInstanceModelView.as_view(resource=PresentacionResource), name='presentacion'),
This is working fine for the GET 'presentaciones/' requests but when I try to make a PUT request, I'm getting a 403 FORBIDDEN
What's strange to me is that GET is working fine: as long as I'm logged, it's responding correctly but if I logout it responds with 403 FORBIDDEN.
If the issue is the X-CSRF token header you can modify the Backbone.sync like this to send a token with each POST, PUT, DELETE request.
/* alias away the sync method */
Backbone._sync = Backbone.sync;
/* define a new sync method */
Backbone.sync = function(method, model, options) {
/* only need a token for non-get requests */
if (method == 'create' || method == 'update' || method == 'delete') {
// CSRF token value is in an embedded meta tag
var csrfToken = $("meta[name='csrf_token']").attr('content');
options.beforeSend = function(xhr){
xhr.setRequestHeader('X-CSRFToken', csrfToken);
};
}
/* proxy the call to the old sync method */
return Backbone._sync(method, model, options);
};
If you are using Django's session based authentication, then you may be tripping over the CSRF protection built into Django (see UserLoggedInAuthentication class[1]).
If this is the case, you will need to ensure that a CSRF cookie gets sent to the client and then you can adapt the jQuery instructions[2] to send the X-CSRFToken header with requests that may change data.
[1] http://django-rest-framework.org/_modules/authentication.html
[2] https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
I realize this is an older post, but I was dealing with this problem recently. Expanding on #orangewarp's answer and using django documentation (https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax), here's a solution:
This solution uses the csrftoken cookie. Another solution would be to create a csrf token endpoint in your API and grab the csrf from there.
Backbone._sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
//from django docs
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
/* only need a token for non-get requests */
if (method == 'create' || method == 'update' || method == 'delete') {
var csrfToken = getCookie('csrftoken');
options.beforeSend = function(xhr){
xhr.setRequestHeader('X-CSRFToken', csrfToken);
};
}
return Backbone._sync(method, model, options);
};

Jquery Tool: Keep selected tab on refresh or save data

I am using jquery tool for tab Ui,
Now I want to keep tab selected on page reload. Is there any way to do that? below is my code
$(function() {
// setup ul.tabs to work as tabs for each div directly under div.panes
$("ul.tabs").tabs("div.panes > div");
});
Here is a simple implementation of storing the cookie and retrieving it:
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function setCookie(c_name, value, exdays) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
document.cookie = c_name + "=" + c_value;
}
Then, to save/retrieve cookie data with jQuery UI Tabs:
$(function() {
// retrieve cookie value on page load
var $tabs = $('ul.tabs').tabs();
$tabs.tabs('select', getCookie("selectedtab"));
// set cookie on tab select
$("ul.tabs").bind('tabsselect', function (event, ui) {
setCookie("selectedtab", ui.index + 1, 365);
});
});
Of course, you'll probably want to test if the cookie is set and return 0 or something so that getCookie doesn't return undefined.
On a side note, your selector of ul.tabs may be improved by specifying the tabs by id instead. If you truly have a collection of tabs on the page, you will need a better way of storing the cookie by name - something more specific for which tab collection has been selected/saved.
UPDATE
Ok, I fixed the ui.index usage, it now saves with a +1 increment to the tab index.
Here is a working example of this in action: http://jsbin.com/esukop/7/edit#preview
UPDATE for use with jQuery Tools
According the jQuery Tools API, it should work like this:
$(function() {
//instantiate tabs object
$("ul.tabs").tabs("div.panes > div");
// get handle to the api (must have been constructed before this call)
var api = $("ul.tabs").data("tabs");
// set cookie when tabs are clicked
api.onClick(function(e, index) {
setCookie("selectedtab", index + 1, 365);
});
// retrieve cookie value on page load
var selectedTab = getCookie("selectedtab");
if (selectedTab != "undefined") {
api.click( parseInt(selectedTab) ); // must parse string to int for api to work
}
});
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function setCookie(c_name, value, exdays) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value = escape(value) + ((exdays === null) ? "" : "; expires=" + exdate.toUTCString());
document.cookie = c_name + "=" + c_value;
}
Here is a working (unstyled) example: http://jsbin.com/ixamig/12/edit#preview
Here is what I see in Firefox when inspecting the cookie from the jsbin.com example:
This is what worked for me... at least I haven't run into any issues yet:
$('#tabs').tabs({
select: function (event, ui)
{
$.cookie('active_tab', ui.index, { path: '/' });
}
});
$('#tabs').tabs("option", "active", $.cookie('active_tab'));
I'm using: jQuery 1.8.2, jQuery UI 1.9.1, jQuery Cookie Plugin.
I set the "path" because in C# I set this value in a mvc controller which defaults to "/". If the path doesn't match, it wont overwrite the existing cookie. Here is my C# code to set the value of the same cookie used above:
Response.Cookies["active_tab"].Value = "myTabIndex";
Edit:
As of jQuery UI 1.10.2 (I just tried this version, not sure if it's broken in previous versions), my method doesnt work. This new code will set the cookie using jQuery UI 1.10.2
$('#tabs').tabs({
activate: function (event, ui) {
$.cookie('active_tab', ui.newTab.index(), { path: '/' });
}
});
The easiest way to survive between page refresh is to store the selected tab id in session or through any server-side script.
Only methods to store data on client side are: Cookies or localStorage.
Refer to thread: Store Javascript variable client side