Chrome Extension - Migration to Manifest v3 - chrome.permissions user gesture issue - api

I have built a chrome extension in manifest version 2 and am now looking at migrating to version 3. As part of this migration I have come across an issue when trying to toggle an optional permission to use the chrome notifications api.
Since you can't request a new permission from a content script as the api is not accessible from a content script, you have to send a message to the background script to perform the request and return the response to the content script. This worked as expected with version 2, now I am receiving this error:
Unchecked runtime.lastError: This function must be called during a user gesture
This means that the extension wants the permission request to be initiated on the back of an event initiated by a user action, such as a click. This indicates that the extension wishes the permission request to be completed from the content script but as stated above this is impossible.
Could anyone illuminate me if I'm missing something?
Content Script:
chrome.runtime.sendMessage(
{message: 'requestPermissions', permissions: ['notifications']},
(res) => console.log(res)
);
Background Script:
export function requestPermissions(request, sender, sendResponse) {
const {permissions} = request;
new Promise((resolve) => {
chrome.permissions.request(
{
permissions
},
(granted) => resolve(granted)
);
}).then((res) => sendResponse(res));
return true;
}

Related

Strapi doesn't authorize JWT

Good morning,
I've encountered a weird issue with my strapi-project.
I have a standard user model which I query for info on the user's profile page via the /users/me endpoint. This was all working fine last week but as I tried logging in this morning, the authorization appeared to not work anymore. I log my user in via this code:
....
async submitForm() {
axios.post('http://localhost:1337/auth/local', {
'identifier': this.email,
'password': this.password
})
.then((response) => {
const { jwt, user } = response.data;
window.localStorage.setItem('jwt', jwt);
window.localStorage.setItem('userData', JSON.stringify(user));
router.push('/dashboard');
})
.catch((e) => {
this.$store.commit('LOGIN_ERROR', e)
});
},
...
Which then redirects to my dashboard which queries the /users/me endpoint like so:
let token = localStorage.jwt;
axios.get(`http://localhost:1337/users/me`, {
headers: {
Authorization: `Bearer ${token}`
}
})
.then((response) => {
console.log(response.data);
})
A few days ago this was working fine, also the token variable used in the post contais the token returned from the backend after logging in. Now strapi gives me an error in the console:
[2021-10-16T07:16:52.568Z] debug GET /users/me (5 ms) 500
[2021-10-16T07:17:03.231Z] debug POST /auth/local (76 ms) 200
[2021-10-16T07:17:24.915Z] error TypeError: Cannot read property 'type' of null
at module.exports (/home/user/WebstormProjects/strapi-project/node_modules/strapi-plugin-users-permissions/config/policies/permissions.js:35:14)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi-utils/lib/policy.js:68:5
at async serve (/home/user/WebstormProjects/strapi-project/node_modules/koa-static/index.js:59:5)
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/parser/index.js:48:23
at async /home/user/WebstormProjects/strapi-project/node_modules/strapi/lib/middlewares/xss/index.js:26:9
My first guess was that maybe something with axios was wrong e.g. that the token wasn't sent correctly in the request so I tried the same thing with webstorm's http client:
POST http://localhost:1337/auth/local
Content-Type: application/json
{
"identifier": "test#test.com",
"password": "..."
}
Which returns the user and token:
"jwt": "<TOKEN>",
If I try using this token to authenticate the user, however a get a 401
GET http://localhost:1337/users/me
Authorization: "Bearer <token>"
Accept: application/json
returns
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid token."
}
So I tried figuring out what was going on there and after an hour I noticed that when looking at the user in the backend the user didn't have the authenticated role assigned. When I changed this manually in the backend, the request authorization works again.
So can anyone maybe tell me what is going on here? Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated, which was working some days back.
Is there something I'm missing?
Any help would be greatly appreciated,
greetings, derelektrischemoench
Okay, so let me reply to your first part:
"Because from my understanding, when POSTing valid credentials to /auth/local the user's role should change to Authenticated"
Answer is, not really. When you send valid credentials to the auth/local, Strapi just checks the database for matching username/email and password. If a user is found, then it fetches the role assigned that user and puts all the data in ctx.state.user.role. So you could have many other roles, like Viewer, Commenter etc with each having different set of access limits.
The different roles can be created here:
http://localhost:1337/admin/settings/users-permissions/roles
So depending on the roles assigned, Strapi will just fetch and store the values in ctx.state.user.role on each request via the strapi-plugin-users-permissions plugin for your convenience, so that you can easily check which user it is and which role it has in any controller or service file using the ctx from the request to provide any additional functionality.
You can check how it does it in the following file:
node_modules/strapi-plugin-users-permissions/config/policies/permissions.js
Now coming to what could have caused it:
Well it could have been you yourself. Possibly while saving the user or viewing user details you could have removed the role from the user and saved the record.
The other possibility could be a database switch.
It can also be a Strapi version upgrade that caused, but it's highly unlikely.
You could have a update query in the your code that updates the user model, where you might have missed the role parameter. So check your code once.
Nevertheless, it can simply be solved by re-assigning the user roles via the users module.

How can I fix an Axios interceptor causing property 'status' of undefined error

I have a selection to set permissions for elements to global or private. I'm using the Axios interceptor request to handle looking for the permissions field to have data and, if it does, stringify it. The problem is, it causes me to get a "TypeError: Cannot read property 'status' of undefined" when I attempt to reload the program at all. The only "fix" right now is to log out, remove the interceptor, log in, read it, and then run the check again.
Because of this, I can't even get to the home dashboard of the software. If I clear my cookies, I can go back to the login screen, but no further than that after attempting to log in.
Is there something I'm missing for it? below is the interceptor code. If more information or context is needed, please let me know.
export default {
install: (Vue) => {
Vue.$eventBus = new Vue();
Vue.axios.interceptors.response.use(response => {
return response.data;
}, async error => {
if (error.response.status === 401 && error.config.url != '/api/authentication/login') {
var config = await Vue.$configService.find();
window.location = config.accountPortalUrl;
return
}
console.log(error);
Vue.$eventBus.$emit('notifyUser', 'Uh oh, something went wrong!');
return Promise.reject(error);
});
Vue.axios.interceptors.request.use(
config => {
// check request method -> use post if many params
if (config.data.permissions) {
config.data.permissions = JSON.stringify(config.data.permissions);
}
console.log(config);
return config;
}
);
}
};
Looks like your service API is not responding, this might happen if the user is not authenticated . Your error is at line where you check (error.response.status). Its only possible to get an undefined response when the request was interrupted before response. Most probably if you check your browser network pannel you will see that the preflight check for this request causes a 401 network error. Hence because the preflight failed your actual response comes as undefined. You should sanity check first if your server responded with a response or not and then access the response status.
Something like this might help
if (error.response) {
// Request was made and the server responded successfully
// You can now de-structure the response object to get the status
console.log(error.response.status);
} else if (error.request) {
// request was made but not responded by server
console.log(error.request);
}
So, the answer ultimately was something extremely simple.
if (config.data.permissions)
needed to be
if (config.data && config.data.permissions)

Handling errors if no network is available

I just implemented my first backend file where I fetch some user data, messages and so on.
Now I wanted to include error handling if there is no network available.
I don´t know if I did it right but this was my approach so far:
import axios from 'axios'
const host = process.env.VUE_APP_URL
export default {
person: async function (currentPerson) {
let params = {
currentPerson: localStorage.getItem("person"),
};
if (user) {
params['currentPerson'] = currentPerson;
}
return axios.get(`${host}/api/currentPerson`, {
params: params
})
//catching network errors
.catch (error => {
if (error.response) {
/*
* The request was made and the server responded with a
4xx/5xx error
*/
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
/*
* The request was made but no response was received
*/
console.log(error.request);
} else {
// Something happened in setting up the request and triggered an Error
console.log('Error', error.message);
}
console.log(error)
});
},
In my mounted() function of my main view I fetch the data from my backend file from above:
backend.matches().then(function (response) {
self.contacts = response.data.persons;
});
I tried to check in console if it is working but all I get is the following:
In the catch block I check for
response errors: like 4xx/5xx
request errors: if my network not responding in time
and any other errors
Would this be the right approach to check if a network is available or not? Or does it degrade the user experience when the user checks the error?
My backend file includes more methods.. do I have to write for each method these kind of requests?
In your backend file you don't react whether there is a network connection or not I think.
And only for reference: that is not the backend, but communicates with the backend - the backend is the part of your code what you communicate with, e.g. Laravel code, an API, ...
Try adding the following at the beginning of your catch part:
if (!error.response) {
//network error
console.log('No network connection');
} else if (error.response) {
//the rest of your code
This should print out No network connection in your console.
Run your application, turn off the internet connection and check the console.
These kind of code should always be located in your backend part.
My answer maybe different from your question.
When i create a .net core API with Angular i used three things to check is there network or not?
subscribe to windows's offline/online event
create signalR hub from layout component to API server
API request failed (it means lot of incident, but if 1. or 2. case is true i know what cause 3. case

Facebook login api still gives the error of https required even if app is in dev mode

I created a test app on facebook and set the domain and the site url to localhost and http://localhost:4200 respectively.
The app is in development mode, as the documentation says "You will still be able to use HTTP with “localhost” addresses, but only while your app is still in development mode", nevertheless I get the error "The method FB.login will soon stop working when called from http pages. Please update your site to use https for Facebook Login." when I invoke the FB.login() api.
Sometimes the facebook window to log the user is not displayed , other times the window opens with the error "Login Error: There is an error in logging you into this application. Please try again later." within.
Update
I'm over https in locale and the relative error is disappeared.
This is the function invoked by the "Login with Facebook" button
loginWithFacebook() {
this.btnLoaderFB = true;
this.auth.facebookInitializer()
.then(() => {
this.auth.facebookInitialized = true;
return this.auth.facebookLoginStatus();
})
.then((loginStatusResponse) => {
console.log(loginStatusResponse);
if (loginStatusResponse.status !== 'connected') {
return this.auth.facebookLogin();
} else {
return this.auth.getFacebookProfileInfo();
}
})
.then((profileInfo) => {
console.log(profileInfo);
this.auth.loginWithFacebookRemote(profileInfo)
.subscribe(
res => {
this.btnLoaderFB = false;
}
);
})
.catch(err => {
console.log(err);
this.translate.get('t.validation.error_fb_login').pipe(takeUntil(this.unsubscribe)).subscribe(
t => {
this.error = t;
this.btnLoaderFB = false;
});
});
The first time I call this function I receive the response from facebookLoginStatus() logged on the console
I enter the fb credential and I get this error
If I try to click again on the button I receive the same response from facebookLoginStatus() I showed in the first image and the facebook popup window shows the same error message in the previous image.
If I reload the page the facebookLoginStatus() response is what I expect for a logged user on facebook and the login process ends without error
I can recommend using https even on localhost, especially because you will have a system for testing that is more similar to the live environment. This solves the Facebook https issue once and for all.
For Node.js, it is very easy with this tool: https://github.com/davewasmer/devcert
For PHP, you may want to take a look at this thread: How do I allow HTTPS for Apache on localhost?
For Angular CLI: Get angular-cli to ng serve over HTTPS

FB.login returns Invalid OAuth access token

I've been developing an app for the past few weeks and up until now there have been no issues. Just a couple days ago a strange bug has started occurring:
My application uses the PHP SDK and implements the Javascript SDK for user authorization. The user is allowed to roam the application freely, but when they click on a video, FB.login is called to request permissions from the user and get an access token.
jQuery Code
FB.login(function(response) {
if (response.authResponse) {
//Set global vars
fb_uid = response.authResponse.userID;
fb_token = response.authResponse.accessToken;
//If user has already authorized the app
if (response.status === 'connected') {
//Create the user record
$.ajax(site_url + '/facebook/create_fb_user', {
type: 'POST',
dataType: 'json',
data: {fb_uid: fb_uid, token: fb_token},
success: function (data) {
user = data.resp.fb_user;
viewVideo(item);
}
});
};
};
}, {scope: "publish_stream"});
PHP Code
try {
$this->_fb->setAccessToken($this->request->post('token'));
$data = $this->_fb->api("/me");
$model = new Model_Fbuser;
$model->data = array(
'fb_uid' => $data['id'],
'fb_token' => $extended_token
);
$resp = $model->update();
return $this->render_json(array(
'success' => TRUE,
'resp' => $resp
));
} catch (Exception $e) {
return $this->render_json(array(
'success' => FALSE,
'error' => $e->getMessage(),
'token' => $this->request->post('token')
));
}
The first time the user does this, the FB.login call returns a valid access token, the PHP SDK is able to set the token, and everything works as expected.
However, should the user revoke the application's access in their App Settings, and then return to the application, they are presented with the FB.login once more, but this time, the call returns the same access token they were previously given, which has already had its access revoked. Trying to set the access token with the PHP SDK throws the exception: "Invalid OAuth access token."
Yet if I then check the token in the Facebook debugger, is says it is valid.
Edit:
Further investigation reveals that the user is issues the same access token every time in the same session. If the user logs out, then logs back in, then they will receive a new valid token. But if they try to get a new token without logging out first, Facebook reissues them the same invalid one. When trying to use this access token to query information about the user, this is the response:
{"error":{"type":"OAuthException","message":"Error validating access token: The session was invalidated explicitly using an API call."}}
If you get the "Invalid OAuth access token" error in this way, I usually call FB.logout() and then immediately call FB.login() in the callback.
FB.logout(function(response) {
// user is now logged out
FB.login(...)
});
Not ideal, but the best way to fix such a use-case.