Why am I experiencing this error when publishing my application? - reactjs

I created an app with npm run build and tried testing on the github page. But I have an error with the way I call the js file. I already changed the files manually in the service worker but I still can't solve it. If anyone wants to take a look, this is the link:
My Service Worker
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read
/* eslint-disable */
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
self.addEventListener('fetch', function (e) {
console.log(e.request.url);
e.respondWith(
caches.match(e.request).then(function (response) {
return response || fetch(e.request);
})
);
});
My index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#000000">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Yeapps PWA">
<meta name="description" content="Yeapps PWA">
<!-- Add meta theme-color -->
<meta name="theme-color" content="#007bff" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.3/css/bulma.min.css">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/icons/192X192.png">
<link rel="apple-touch-icon" href="%PUBLIC_URL%//icons/icon-152x152.png"> -->
<link rel="manifest" href="./manifest.json">
<link rel="shortcut icon" href="./icons/192X192.png">
<link rel="apple-touch-icon" href="./icons/icon-152x152.png">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css" integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
<title>PWA</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<button class="add-button btn btn-danger">Instalar Yeapps</button>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('service-worker.js').then(function (registration) {
console.log('Worker registration successful', registration.scope);
}, function (err) {
console.log('Worker registration failed', err);
}).catch(function (err) {
console.log(err);
});
});
} else {
console.log('Service Worker is not supported by browser.');
}
let deferredPrompt;
const addBtn = document.querySelector('.add-button');
addBtn.style.display = 'none';
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI to notify the user they can add to home screen
addBtn.style.display = 'block';
addBtn.addEventListener('click', (e) => {
// hide our user interface that shows our A2HS button
addBtn.style.display = 'none';
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
deferredPrompt = null;
});
});
});
</script>
</body>
</html>

Related

CSP headers are missing in JS files (while CSS not) when served by service worker

I am using a brand new app generated by create-react-app 3.4.1. It uses the default service worker file:
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
type Config = {
onSuccess?: (registration: ServiceWorkerRegistration) => void;
onUpdate?: (registration: ServiceWorkerRegistration) => void;
};
export function register(config?: Config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(
process.env.PUBLIC_URL,
window.location.href
);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker.'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' }
})
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then(registration => {
registration.unregister();
})
.catch(error => {
console.error(error.message);
});
}
}
I turned on service worker by changing the code in index.ts to
serviceWorker.register();
I hosted the static files generated by yarn build through https by an Express.js server with strict Content Security Policy (CSP) turned on by helmet.
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: [
/* Content Security Policy Level 3 */
"'strict-dynamic'",
`'nonce-${cspNonce}'`,
/* Content Security Policy Level 2 (backward compatible) */
"'self'",
// Workbox
'https://storage.googleapis.com',
// ...
],
styleSrc: [
"'self'",
],
// ...
},
},
})
When I first time opening the page, the browser fetch files from server. Both JS and CSS have CSP headers. The page shows well.
When I second time opening the page, the files are loaded from service worker. Many got blocked by CSP, as my console shows:
When I further check, CSS files served by service worker still have CSP headers (and nonce inside also changed to new value, create-react-app did it for us?), which load well.
However, the CSP headers on JS files are missing, which got blocked.
Any guide will be helpful. Thanks!
UPDATE
One thing I notice in Chrome, it shows
CAUTION: provisional headers are shown
and I found more info at
"CAUTION: provisional headers are shown" in Chrome debugger
Another thing I found, the page won't load on second call on Chrome and Safari after service worker (create-react-app uses Workbox internally) registered.
For Firefox, although CSP headers are not shown neither in JS and CSS files when read from cache, Firefox still can show the page.
It is likely that the first time you load the page the nonce in your CSP and your script tags are in sync. On the second load they are no longer present or in sync in your script tags. Check the difference in nonce values in the CSP header and inline script tags.
CSP applies to pages being rendered in the browser (content-type: "text/html"), it doesn't have any effect when set on the other resources loaded. Missing CSP header on js files doesn't have any effect. Your CSS files are included because you include "style-src 'self'", you should add this to script-src as well. If it is not sufficient you could add localhost:5000 in development.
As noticed Halvor Sakshaug above, you do not need to serve JS/CSS with CSP headers, CSP work only for page/code having document property.
As seen from you Chrome console warnings, there is at least 2 issues:
an inline scripts blocked (you do use < script>...< /script> or < tag unClick='...'> somewhere). So you have to add 'unsafe-inline' to script-src (or add nonce='server_generated_value' attribute to < script>...< /script>), BUT:
'strict-dynamic' cancels host-based allowlisting (incliding 'self') in CSP3-browsers, so your https://localhost (and other hosts) will be disabled. Also 'strict-dynamic' cancels 'unsafe-inline' ('nonce-value' and 'hash-value' cancel it too). Probably you do not sign inline scripts with nonce='server_generated_nonce' attribute. Or you do use scripts calls incompatible with 'strict-dynamic' (parser-inserted scripts, inline event handlers etc)
You have to revise Content Security Policy rules, they are inconsistent.

integrate LinkedIn login in react

I am trying to integrate the script below in a React component (in componentDidMount) but I get an error at IN.Event.on(IN, "auth", getProfileData); IN is not recognizet. My main goal is to integrate this script in my React component.
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: YOUR_API_KEY_HERE
authorize: true
onLoad: onLinkedInLoad
</script>
<script type="text/javascript">
// Setup an event listener to make an API call once auth is complete
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
// Handle the successful return from the API call
function onSuccess(data) {
console.log(data);
}
// Handle an error response from the API call
function onError(error) {
console.log(error);
}
// Use the API call wrapper to request the member's basic profile data
function getProfileData() {
IN.API.Raw("/people/~").result(onSuccess).error(onError);
}
</script>

Facebook Login not working in PWA app if app is in stand alone state

I am building a PWA webiste. I am using Angular JS and I used javascript facebook login in my website. But if I view my app in browser, facebook login is working. But when I add shortcut to homescreen and launch the app from the homescreen, FB login is not working. Facebook page is loading. But after entering credentials it shows blank page. Can anyone help ?
Here is my FB login code
var doBrowserLogin = function(){
var deferred = $q.defer();
FB.login(
function(response){
if (response.authResponse) {
deferred.resolve(response);
}else{
deferred.reject(response);
}
},
{scope:'email,public_profile'}
);
return deferred.promise;
}
It is opening the facebook login screen and after entering the credentials, it is showing blank. Not coming back to app.
In my manifest.json file, the display property is set to standalone.
Please help.
Don't use facebook javascript plugin, write your own flow:
1) Create a static html that will receive fb login response (ex: /fb-login-receiver.html)
It will send back login result to the application with postMessage.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
Facebook login completed.
<script type="text/javascript">
window.opener.postMessage(window.location.toString(), window.location.href);
window.close();
</script>
</body>
</html>
2) In your application write a function that will open fb login page in a popup window
this typescript example returns a promise for the access token and check if the user has allowed email access:
async loginFacebook(): Promise<string> {
let popup = window.open("https://www.facebook.com/v3.1/dialog/oauth?client_id=**<YOUR_CLIENT_ID>**&display=popup&scope=email&response_type=token,granted_scopes&auth_type=rerequest&redirect_uri=" + window.location.origin + "/fb-login-receiver.html", 'Facebook Login', 'width=500,height=500');
var promise = new Promise<string>((resolve, reject) => {
let finished = false;
let listener = (e: MessageEvent) => {
finished = true;
let url = new URL(e.data);
let hash = url.hash.substring(1);
let splitted = hash.split('&');
let dct: { [key: string]: string } = {};
for (let s of splitted) {
var spltd = s.split('=');
dct[spltd[0]] = spltd[1];
}
if (dct['granted_scopes'].indexOf('email') < 0) {
reject("Email required");
return;
}
resolve(dct['access_token']);
};
addEventListener('message', listener);
let intervalChecker = setInterval(() => {
if (popup.closed) {
clearInterval(intervalChecker);
removeEventListener('message', listener);
if (!finished) {
reject('Login canceled');
}
}
}, 10);
});
return promise;
}
This is correct behaviour because Facebook API to login user open new tab with login form. Facebook implement OAuth2 solution and for authenticate user using their API activate OAuth2 Implicit Flow. For login in the same window you must use Authorization Code, but for client side applications isn't secure beacause you will need a secret code not available for users.
Instead of open new tab you can create iframe with facebook login form and when user logged in close it and redirect.

React Builder tool won't set public url correctly

I am trying to build my react app with react's build tool.
npm run build
But when I open the index.html file in the build folder, I can't see anything except a blank page. That's because react builder sets script and css paths wrong.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<title>React App</title>
<style>
</style>
<link href="/static/css/main.5fa823c3.css" rel="stylesheet">
</head>
<body><noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.09bdcb2b.js"></script>
</body>
</html>
As you can see, there is slash before every file path. If I fix this by hand, then the script works but the browser cannot find the "service-worker.js" file because value of the process.env.PUBLIC_URL is null. (service-worker.js exists in the right location)
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
window.addEventListener('load', () => {
console.log("URL: "+process.env.PUBLIC_URL) //THIS IS NULL
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
});
}
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
Basically, it cannot set the public url.
How can I fix this? There is almost no information about this problem anywhere.
You must set your 'homepage' on your package.json file. Assume that your project is in a folder named "project" on the root of your server's working directory.
{
"name": "app name",
"homepage": "/project",
}

Adding google plus login to ionic app

I am trying to add google plus login to my ionic app.
Following this link gives me an error.
https://ionicthemes.com/tutorials/about/google-plus-login-with-ionic-framework
Error is : cannot read property googleplus of undefined.
Here is my app.js:
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
Steps to Configure authentication in Device(android)
ionic start newApp
ionic platform add android
cordova plugin add cordova-plugin-inappbrowser
bower install ngCordova
bower install ng-cordova-oauth -S
include both script into index.html above cordova.js
<script src="lib/ngCordova/dist/ng-cordova.min.js"></script>
<script src="lib/ng-cordova-oauth/dist/ng-cordova-oauth.js"></script>
<script src="cordova.js"></script>
Dependency injection
include below code
$scope.googleLogin = function() {
console.log('In My Method');
$cordovaOauth.google("Client ID", ["https://www.googleapis.com/auth/urlshortener", "https://www.googleapis.com/auth/userinfo.email"]).then(function(result) {
console.log(JSON.stringify(result));
// results
}, function(error) {
// error
console.log('In Error');
console.log(error);
});
}
add button to view file and call the function
1 first add inappbrower in your app
2 create app id for google console
https://console.developers.google.com
a: create new project
b: click on Credentials
c: choose web application
d: set redirect path
if u have if not than set http://localhost/callback
e: click on create button
than a pop up appear save those id
after that add following code
NOTE:Please change your app id and secret id in code
$scope.loginGoogle = function() {
var requestToken = '';
var accessToken = '';
var clientId = '1018908884240-futc1bfc681kl2jegi3a7nn1m28aem1o.apps.googleusercontent.com';
var clientSecret = 'KRQGDwu_llvagUucKM9oLZ7I';
var deferred = $q.defer();
$cordovaOauth.google(clientId, ['email']).then(function(result) {
$localStorage.accessToken = result.access_token;
deferred.resolve(result.access_token);
$http.get('https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + $localStorage.accessToken, {
params: {
format: 'json'
}
}).then(function(result) {
console.log(JSON.stringify(result));
var id =result.data.id;
deferred.resolve(result.data);
}, function(error) {
deferred.reject({
message: 'here was a problem getting your profile',
response: error
});
});
}, function(error) {
deferred.reject({
message: 'There was a problem signing in',
response: error
});
});
}
Try to add <script src="cordova.js"></script> to your index.html file.
And Cordova plugins only runs on emulators or real devices. try Ripple Emulator if you want to test it in a browser.
Credit to Cordova plugins not working with ionic

Resources