PWA offline service worker settings - django

I am building a simple Progressive Web Application with Python Django and django-pwa package. I have set up everything but offline functionality is not working. At this point, service workers (SW) are installed and dev tools recognize application as PWA. But when I check "offline" in devtools->Application and reload the web page there is a "No internet connection" error.
Here are my SW settings:
var staticCacheName = 'djangopwa-v1';
var filesToCache = [
'/',
'/x_offline/',
'/static/x_django_pwa/images/my_app_icon.jpg',
'/media/images/bfly1.2e16d0ba.fill-320x240.jpg',
];
// Cache on install
self.addEventListener("install", event => {
this.skipWaiting();
event.waitUntil(
caches.open(staticCacheName)
.then(cache => {
return cache.addAll(filesToCache);
})
)
});
// Clear cache on activate
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => (cacheName.startsWith("djangopwa-v1")))
.filter(cacheName => (cacheName !== staticCacheName))
.map(cacheName => caches.delete(cacheName))
);
})
);
});
// Serve from Cache
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(response => {
return response || fetch(event.request);
})
.catch(() => {
return caches.match('x_offline');
})
)
});
Listed settings are almost the same as default one from django-pwa repo
When I load the page for the first time I see that requests are also made for the urls listed in SW and all of them have status 200. In the cache storage I see cache with paths set in SW. So I don't understand what I do wrong.
Not sure if this additional info is useful, but: when I set SW to offline and reload the web page the cache storage is empty.

The issue is in the settings that django-pwa repo provided.
They accidentally added sign , at the end of the scope variable and so if you copy settings you copy with incorrect scope setting (PWA_APP_SCOPE = '/',) and it brakes offline mode. I am going to contact with repo admins so that to fix the issue for the next users.

Related

ASP.NET Core Antiforgery token problem with two applications on single domain

I have an ASP.NET Core 3.1 SPA application that use Microsoft.AspDotNetCore.Antiforgery.
I add the Antiforgery service in ConfigureServices method like this:
_ = services.AddAntiforgery((o) =>
{
o.HeaderName = "X-XSRF-TOKEN";
});
In Configure method, the middleware is added to add antiforgery cookie to http response:
app.Use(async (context, next) =>
{
var tokens = antiForgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN",
tokens.RequestToken, new CookieOptions
{
HttpOnly = false,
Secure = false,
IsEssential = true
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict
}
);
await next();
});
I have single domain where runs two application (e.g. https://example.com/test and https://example.com/master). When I open both applications in browser I get randomly 400 BadRequest response. When I open only one application in browser, it works great.
I think both application affect single antiforgery cookie, but I don't know how and why.
Is there any solution to my problem? Thanks

Django, React-Native Connection Network Request Failed

I'm working on a react-native-based mobile application and doing some operations with python in the background. I wanted to do both these transactions and connect to the database via Django rest api. But I get connection error.
I have used other rest-api and tried it. I also tried the rest api on the postman and it worked smoothly.
I tried everything, but I couldn't find a solution.
local rest url: http://localhost:8000/api/venues/
and fetch code:
componentDidMount() {
return fetch('http://localhost:8000/api/venues/?format=json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
also my django setting:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:3030',
]
CORS_ORIGIN_REGEX_WHITELIST = [
'http://localhost:3030',
]
add these configurations after adding cors as middleware (change to your port number)
https://stackoverflow.com/a/69186898/12497001 provides a very good answer!
As mentioned in the Android Studio documentation, emulators use a special address network (https://developer.android.com/studio/run/emulator-networking.html).
To address requests to your own machine, you can use the address http://10.0.2.2

Axios GET request to server - not local host

I was wondering if someone could bring some light on how GET request paths work. I am not skilled in networking so am a bit lost here.
I have a Flask app running on PythonAnywhere... I built a small app with Vue and am using Axios for send GET request to my API on server. I however found out that when I run my app on PythonAnywhere server i will get response only when I also run the flask app on my local machine. I suspect it is due to me trying to send the request to http://localhost:5000/api/random2. Is that true? What do I have to replace it with to send the request to my PythonAnywhere app?
getResults () {
const path = `http://localhost:5000/api/random2`
axios.get(path, {
params: {
p_a: this.p_a,
R_eH: this.R_eH,
a: this.a,
b: this.b
}
})
.then(response => {this.result = response.data})
.catch(error => {
console.log(error)
})
}
},
Thank you,
Jakub

Preserve cookies / localStorage session across tests in Cypress

I want to save/persist/preserve a cookie or localStorage token that is set by a cy.request(), so that I don't have to use a custom command to login on every test. This should work for tokens like jwt (json web tokens) that are stored in the client's localStorage.
To update this thread, there is already a better solution available for preserving cookies (by #bkucera); but now there is a workaround available now to save and restore local storage between the tests (in case needed). I recently faced this issue; and found this solution working.
This solution is by using helper commands and consuming them inside the tests,
Inside - cypress/support/<some_command>.js
let LOCAL_STORAGE_MEMORY = {};
Cypress.Commands.add("saveLocalStorage", () => {
Object.keys(localStorage).forEach(key => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add("restoreLocalStorage", () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
Then in test,
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
Reference: https://github.com/cypress-io/cypress/issues/461#issuecomment-392070888
From the Cypress docs
For persisting cookies: By default, Cypress automatically clears all cookies before each test to prevent state from building up.
You can configure specific cookies to be preserved across tests using the Cypress.Cookies api:
// now any cookie with the name 'session_id' will
// not be cleared before each test runs
Cypress.Cookies.defaults({
preserve: "session_id"
})
NOTE: Before Cypress v5.0 the configuration key is "whitelist", not "preserve".
For persisting localStorage: It's not built in ATM, but you can achieve it manually right now because the method thats clear local storage is publicly exposed as Cypress.LocalStorage.clear.
You can backup this method and override it based on the keys sent in.
const clear = Cypress.LocalStorage.clear
Cypress.LocalStorage.clear = function (keys, ls, rs) {
// do something with the keys here
if (keys) {
return clear.apply(this, arguments)
}
}
You can add your own login command to Cypress, and use the cypress-localstorage-commands package to persist localStorage between tests.
In support/commands:
import "cypress-localstorage-commands";
Cypress.Commands.add('loginAs', (UserEmail, UserPwd) => {
cy.request({
method: 'POST',
url: "/loginWithToken",
body: {
user: {
email: UserEmail,
password: UserPwd,
}
}
})
.its('body')
.then((body) => {
cy.setLocalStorage("accessToken", body.accessToken);
cy.setLocalStorage("refreshToken", body.refreshToken);
});
});
Inside your tests:
describe("when user FOO is logged in", ()=> {
before(() => {
cy.loginAs("foo#foo.com", "fooPassword");
cy.saveLocalStorage();
});
beforeEach(() => {
cy.visit("/your-private-page");
cy.restoreLocalStorage();
});
it('should exist accessToken in localStorage', () => {
cy.getLocalStorage("accessToken").should("exist");
});
it('should exist refreshToken in localStorage', () => {
cy.getLocalStorage("refreshToken").should("exist");
});
});
Here is the solution that worked for me:
Cypress.LocalStorage.clear = function (keys, ls, rs) {
return;
before(() => {
LocalStorage.clear();
Login();
})
Control of cookie clearing is supported by Cypress: https://docs.cypress.io/api/cypress-api/cookies.html
I'm not sure about local storage, but for cookies, I ended up doing the following to store all cookies between tests once.
beforeEach(function () {
cy.getCookies().then(cookies => {
const namesOfCookies = cookies.map(c => c.name)
Cypress.Cookies.preserveOnce(...namesOfCookies)
})
})
According to the documentation, Cypress.Cookies.defaults will maintain the changes for every test run after that. In my opinion, this is not ideal as this increases test suite coupling.
I added a more robust response in this Cypress issue: https://github.com/cypress-io/cypress/issues/959#issuecomment-828077512
I know this is an old question but wanted to share my solution either way in case someone needs it.
For keeping a google token cookie, there is a library called
cypress-social-login. It seems to have other OAuth providers as a milestone.
It's recommended by the cypress team and can be found on the cypress plugin page.
https://github.com/lirantal/cypress-social-logins
This Cypress library makes it possible to perform third-party logins
(think oauth) for services such as GitHub, Google or Facebook.
It does so by delegating the login process to a puppeteer flow that
performs the login and returns the cookies for the application under
test so they can be set by the calling Cypress flow for the duration
of the test.
I can see suggestions to use whitelist. But it does not seem to work during cypress run.
Tried below methods in before() and beforeEach() respectively:
Cypress.Cookies.defaults({
whitelist: "token"
})
and
Cypress.Cookies.preserveOnce('token');
But none seemed to work. But either method working fine while cypress open i.e. GUI mode. Any ideas where I am coming short?
2023 Updated on Cypress v12 or more:
Since Cypress Version 12 you can use the new cy.session()
it cache and restore cookies, localStorage, and sessionStorage (i.e. session data) in order to recreate a consistent browser context between tests.
Here's how to use it
// Caching session when logging in via page visit
cy.session(name, () => {
cy.visit('/login')
cy.get('[data-test=name]').type(name)
cy.get('[data-test=password]').type('s3cr3t')
cy.get('form').contains('Log In').click()
cy.url().should('contain', '/login-successful')
})

Chrome extension get all tab cookies

Trying to get all cookies from the page, using chrome extension.
For example the page os https://ya.ru.
Here is my code:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var domain = getDomain(tabs[0].url);
chrome.cookies.getAll({
domain: domain
}, function(cookies) {
console.log(cookies);
});
});
This code will return all cookies (8) for domain ya.ru.
But the problem is when I'm opening the browser console I see cookies not only for ya.ru domain:
Same situation is on google and other sites. So I'm having multiple domain cookies on one page. How to get ALL cookies on the page?
Thank for your time.
Devtools shows cookies for all resource URLs requested by the page (source code) so we can do the same by accessing Performance API in the content script code that we'll execute in the page:
chrome.tabs.executeScript({
code: 'performance.getEntriesByType("resource").map(e => e.name)',
}, data => {
if (chrome.runtime.lastError || !data || !data[0]) return;
const urls = data[0].map(url => url.split(/[#?]/)[0]);
const uniqueUrls = [...new Set(urls).values()].filter(Boolean);
Promise.all(
uniqueUrls.map(url =>
new Promise(resolve => {
chrome.cookies.getAll({url}, resolve);
})
)
).then(results => {
// convert the array of arrays into a deduplicated flat array of cookies
const cookies = [
...new Map(
[].concat(...results)
.map(c => [JSON.stringify(c), c])
).values()
];
// do something with the cookies here
console.log(uniqueUrls, cookies);
});
});
Important notes:
Your manifest.json should have "<all_urls>" in "permissions" or an explicit list of URL match patterns that will allow the corresponding results in chrome.cookies.getAll.
Cookie deduplication code above may be slow when there are thousands of cookies.
We're reading cookies for an URL, not domain, because it's the only reliable way to get an encompassing cookie (imgur.com) for something like i.stack.imgur.com