Closed Bug 1780714 Opened 2 years ago Closed 2 years ago

chrome.permissions.request fails after making network request

Categories

(WebExtensions :: Untriaged, defect)

Firefox 103
defect

Tracking

(firefox103 affected, firefox104 affected)

RESOLVED DUPLICATE of bug 1398833
Tracking Status
firefox103 --- affected
firefox104 --- affected

People

(Reporter: extensions, Unassigned)

Details

(Keywords: regressionwindow-wanted)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0

Steps to reproduce:

context:

  • webext v2
  • moz-extension page containing form with email field
  • optional_permissions: "<all_urls>"

flow:
user enters email address
on form submit (user click), the extension flow is as follows:

  1. lookup email domain
    1.1 domain is unknown to extension -> perform dns lookup (https, cloudflare)
  2. chrome.permissions.request({origins: [domain] })
  3. ...

the extension has a pre-configured list of domains that it does not need to lookup via dns. in that case, the flow works, chrome.permissions.request pops up the 'allow access...' popup and all works as expected.

however, if we have to perform the dns lookup - initiated on the moz-extension page - that call fails with "permissions.request may only be called from a user input handler" without showing the 'allow access...' popup.

remember, we're right in the form's onSubmit handler!

sidenote: running the same extension on chromium platforms works as expected

Actual results:

see above

Expected results:

assumption: network request should not invalidate permissions request in form submit handler

The Bugbug bot thinks this bug should belong to the 'WebExtensions::Untriaged' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Product: Firefox → WebExtensions

And this worked in 102?

Can you use mozregression to figure out what caused it?

https://mozilla.github.io/mozregression/

(In reply to tom from comment #0)

however, if we have to perform the dns lookup - initiated on the moz-extension page - that call fails with "permissions.request may only be called from a user input handler" without showing the 'allow access...' popup.

remember, we're right in the form's onSubmit handler!

assumption: network request should not invalidate permissions request in form submit handler

Can you please provide (minimal) exact code you're using to trigger this behavior? If the "perform dns lookup" step involves awaiting a promise, then that's not a sync method anymore, and not counted as being initiated by the user (otherwise, an extension could "store" a user activation behind a promise it could choose to resolve at any point, and work around the intended limitation).

If this did work in 102, then it might be a change in what we consider "initiated by the user", and something to fix here.

Flags: needinfo?(extensions)
  • submit button hander from the moz-extionsion page:

    this._onSubmit = (evt) => {
    assert(typeof this._config.onSubmit === 'function', 'onSubmit must be a function');

    evt.preventDefault(); // prevent form action
    this._submitEl.disabled = true;
    
    const email = this._emailEl.value.trim().toLowerCase();
    const password = this._passwordEl.value;
    
    mp.lookupProviderByEmail(email)
    .then(provider => requestPermissions(provider))
    .then(provider => {
      const passwordRequired = this._adaptFormToProvider(provider);
      if (passwordRequired && !password)
        return;
    
      this._config.onSubmit(this, email, password);
    })
    .catch((e) => {
      this.showErrorMessage(chrome.i18n.getMessage(e.message));
    })
    .finally(_ => {
      this._submitEl.disabled = false;
    });
    

    }

  • lookup logic:

export async function lookupProviderByDomain(domain) {
let p = providersByEmailDomain[domain];
if (p) return p;

const exchange = await dns.lookup('MX', domain)
p = getProviderFromDNSAnswer(exchange);
if (!p) throw Error('error_domain');

updateProviderByEmailDomain(domain, p);
return p;
}

export async function lookupProviderByEmail(email) {
if (!sanitize.emailaddress(email, false))
throw Error('error_email');

const [, domain] = email.split("@");
return await lookupProviderByDomain(domain);
}

  • dns lookup:

import dnsPacket from 'dns-packet'
import https from 'https'

export function lookup(type, name) {
return new Promise((resolve, reject) => {
const buf = packet(type, name);
const request = https.request(options(buf), (response) => {
if (response.statusCode != 200) return reject(response.statusCode);

  response.on('data', (d) => {
    const p = dnsPacket.decode(d);
    // ddebug(p.answers);
    resolve(p.answers.map(a => a.data.exchange)); // TODO: map to exchange domain(s)
  });
});

request.on('error', (e) => reject(e));
request.write(buf)
request.end()

});
}

Flags: needinfo?(extensions)

the dns logic returns the correct result 100% of the time; as was said above, it just seems that the https call in the flow makes chrome.permissions.request fail

Hello,

I’m from Webextensions QA and I’m attempting to reproduce the issue in order to confirm it, but I’m having trouble building the test extension based on the code you provided in Comment 4.

Would it be much of a hassle to attach an already packed, working example extension to the report in order for me to test it out?

Thank you !

Flags: needinfo?(extensions)

hi alex, no hassle at all.

download it from here:
https://addons.mozilla.org/en-US/firefox/addon/webde-mailcheck/

positive case:
in the login panel, enter xyz@online.de (not a valid email address!) and watch the password field appear after you allowed the extension to access the domain.

negative case:
please contact me at tom+support@patugo.com and i provide you with an email address and domain - sorry for the inconvenience, keeping the customer's privacy here.

Flags: needinfo?(extensions)

Hello Tom and thank you for the additional info !

I reproduced the issue on the latest Nightly (104.0a1/20220724190402), Beta (103.0/20220718155818) and Release (102.0.120220705093820) under Windows 10 x64 and Ubuntu 16.04 LTS.

For the negative case example, using the provided info, once I enter and submit the email, there is no permission pop-up displayed to allow access to the domain and thus the password field is not displayed. An error is displayed in the console, stating “error_permission”.

For the positive case example, entering and submitting the email will generate a permission pop-up. Allowing access to the domain will then proceed to show the password field.

Status: UNCONFIRMED → NEW
Ever confirmed: true

thank you alex.
as a sidenote, customer confirmed that he had the problematic email address working with the extension for "3-4 years" now; only after he cleaned up his profile a few days ago, it stopped working.
this should lead to the conclusion that its indeed a regression, but unfortunately we're unable to trace it back to the release which caused the issue.

I believe the code you provided would have never worked in Firefox. If you're able to use mozregression[1] to confirm that it did, we can investigate fixing it, otherwise this is a known API limitation, and "working as designed".

https://mozilla.github.io/mozregression/

(In reply to Tomislav Jovanovic :zombie from comment #10)

I believe the code you provided would have never worked in Firefox. If you're able to use mozregression[1] to confirm that it did, we can investigate fixing it, otherwise this is a known API limitation, and "working as designed".

https://mozilla.github.io/mozregression/

tomislav, what do you suggest we do when we need to perform 1. a dns lookup to ensure we got a email address of a supported mail provider, 2. ask for permissions to access that email's mail provider?

Hello,

I tried finding the regressor by running several bisections initially spanning 01.01.2019 - 2022 present day and then 01.01.2020 - 2022 present day.

All tested builds presented the issue when using the negative case email. However, I was able to only go as far back as 01.28.2020 as further in the past, the extension no longer produces an onboarding page after install, the toolbar icon is not reacting to clicks (also it does not have the red cross on the toolbar icon as I’ve seen on the latest versions of Firefox) or the onboarding page is displayed but the “Login” button is inactive after inputting the email.

Now, I’ve also tried installing different versions of the extension to better correspond to the tested builds periods, but there were some issues there as well in the form of either not being able to install the extension due to a corrupted warning doorhanger being displayed or the flow for logging in was implemented differently – both Email and Password fields were available from the start of the onboarding flow and it did not match to the conditions in which the bug occurs.

hi alex, thank you for your efforts. yeah, product evolution probably got in the way here.
i think it all boils down to allow network requests before request-permission calls within the context of user interaction - which is a given in our scenario.

The severity field is not set for this bug.
:rpl, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(lgreco)

(In reply to tom from comment #11)

tomislav, what do you suggest we do when we need to perform 1. a dns lookup to ensure we got a email address of a supported mail provider, 2. ask for permissions to access that email's mail provider?

I'm not sure what I might suggest for this. If you had a previous version of the extension which worked in Firefox, then maybe reusing a similar approach could work.

The basic sure-fire approach would be to split the user flow into two steps 1) enter email address and determine the provider, 2) request permission for the provider domain. Obviously this would require one more click from the user, but there could be a few things to try to skip one of them:

  • you might try to start the DNS lookup when the email address is entered, before the user submits the form. In case it is complete in time, you can request the permission right away.
  • If the domain of the provider is very often the same as the email domain, then in case the previous item doesn't finish in time, you could maybe request the permission for the email domain, and if the lookup later returns a different domain, prompt the user to request that one as well.

In any case, if you're working with a small number of providers, you can safely (blindly) call permissions.request|() for a domain that the user has already granted access for, they will not be prompted again.

Hope that helps.

Flags: needinfo?(lgreco)

thank you, tomislav, that makes sense. adding an extra step to the ui flow is the only valid solution we came up with.
if nobody cares to get on par with chromium for the sake of ease of cross-webext development, we may close this ticket.

The severity field is not set for this bug.
:mixedpuppy, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(mixedpuppy)
Status: NEW → RESOLVED
Closed: 2 years ago
Flags: needinfo?(mixedpuppy)
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.