maxlath / wikibase-edit

a lib to edit Wikibase from NodeJS
67 stars 25 forks source link

Cross-Origin request blocked using multi-user setup #81

Open jmformenti opened 1 year ago

jmformenti commented 1 year ago

We are working on a VUE application (client side rendering) to manage our own Wikibase instance and we want users to login using our application with OAuth.

We have our OAuth authentication process against Wikibase implemented and got access tokens properly but when we try to execute our first action with wikibase-edit:

this.wbEdit.label.set({ id: 'Q35702', language: 'ca', value: 'Universitat de Salamanca' }, requestConfig)

we got this error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/w/api.php?action=query&meta=tokens&type=csrf&format=json. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/w/api.php?action=query&meta=tokens&type=csrf&format=json. (Reason: CORS request did not succeed). Status code: (null).

We are following this documentation: https://github.com/maxlath/wikibase-edit/blob/main/docs/how_to.md#multi-user-setup

What are we doing wrong? Can wikibase-edit be used from javascript running in the browser?

maxlath commented 1 year ago

Hi @jmformenti, it should be possible to use wikibase-edit in the browser since #47, but I don't use that possibility and we don't have tests to assert that unfortunately. Maybe @SirkoS knows more about the topic?

Reading mediawiki docs on CORS, it seems we might be missing the possibility to pass an origin parameter in the post request querystring. That origin parameter would need to match an origin set in $wgCrossSiteAJAXdomains in your mediawiki.

Could you try to set that $wgCrossSiteAJAXdomains, and then change your local version of wikibase-edit to hard-code query.origin = 'https://your.wikibase.instance' in lib/request/post.js actionPost function, and see if that works?

jmformenti commented 1 year ago

Thanks @maxlath, I've realized that the failing request is this one: https://github.com/maxlath/wikibase-edit/blob/main/lib/request/get_final_token.js#L10

I've added origin=* and I've already set $wgCrossSiteAJAXdomains = [ '*' ]; in my Wikibase but I'm getting the same error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://wikibase.svc/w/api.php?action=query&meta=tokens&type=csrf&format=json&origin=*. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://wikibase.svc/w/api.php?action=query&meta=tokens&type=csrf&format=json&origin=*. (Reason: CORS request did not succeed). Status code: (null).

My guess is that this is a special request precisely to get CSRF tokens and maybe origin parameter is ignored

AlexW00 commented 1 year ago

The issue is that wb-edit does not add the origin parameter when making requests to the Wikibase API. In a node.js environment this does not matter, but in the browser, the CORS header in the response must match (security). origin=* in $wgCrossSiteAJAXdomains does not work because credentials must not be sent over a wildcard origin (https://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin-when-credentials-flag-i). Therefore, for each request, there has to be an url parameter origin present, that matches one of the allowed origins configured in $wgCrossSiteAJAXdomains. I patched this by adding an origin to each request in fetch.js (https://github.com/AlexW00/wikibase-edit/blob/a0f456a9a1cd0aa2ba34e248bbfc52f1321b2bea/lib/request/fetch.js#L30) like so:

const addOrigin = (url, origin) => {
  const urlObj = new URL(url)
  urlObj.searchParams.set('origin', origin)
  return urlObj.toString()
}

There is also another issue when trying to make wb-edit work in the browser: cookie management. In the browser, it is not possible to manage cross-site cookies (security). I replaced cross-fetch with axios to use a cookie jar, which essentially handles all the cookies automatically. I'm sure there are better solutions, but for now, it works.

I created a fork, which runs fine in the browser now. However, I haven't tested it with Node.js yet. Furthermore, for node.js, the origin header is hard-coded (laziness) in fetch.js. For the browser, the origin is automatically pulled from window.location.origin.

Fork: https://github.com/AlexW00/wikibase-edit Npm (dev package for easy installation): https://www.npmjs.com/package/wikibase-edit-browser

jmformenti commented 1 year ago

Thanks a lot @AlexW00, I'm trying to use your fork but I'm getting the same error, not sure if I'm doing something wrong. This is the code that I'm testing:

    this.wbEditBrowser = require('wikibase-edit-browser')({
      instance: 'http://localhost',
      credentials: {
        username: 'admin',
        password: 'XXX'
      }
    })
    this.wbEditBrowser.label.set({ id: 'Q35702', language: 'ca', value: 'test' })

In order to make it work in my case (a VUE application with client side rendering) I needed to change this line: https://github.com/AlexW00/wikibase-edit/blob/main/lib/request/client.js#L1 for: const axios = require('axios').default. But after that, I'm getting the same error than before: Captura de pantalla de 2023-06-09 20-43-56 Any idea?

AlexW00 commented 1 year ago

Thanks a lot @AlexW00, I'm trying to use your fork but I'm getting the same error, not sure if I'm doing something wrong. This is the code that I'm testing:

    this.wbEditBrowser = require('wikibase-edit-browser')({
      instance: 'http://localhost',
      credentials: {
        username: 'admin',
        password: 'XXX'
      }
    })
    this.wbEditBrowser.label.set({ id: 'Q35702', language: 'ca', value: 'test' })

In order to make it work in my case (a VUE application with client side rendering) I needed to change this line: https://github.com/AlexW00/wikibase-edit/blob/main/lib/request/client.js#L1 for: const axios = require('axios').default. But after that, I'm getting the same error than before: Captura de pantalla de 2023-06-09 20-43-56 Any idea?

What does console.log(window.location.origin) print out? Is this value in your $wgCrossSiteAJAXdomains?

jmformenti commented 1 year ago

What does console.log(window.location.origin) print out? Is this value in your $wgCrossSiteAJAXdomains?

I've double-checked it, the window.location.origin=http://localhost:3000 and the final request is:

http://localhost/w/api.php?action=login&format=json&origin=http://localhost:3000

And this is my config in Wikibase:

$wgCrossSiteAJAXdomains = [ 'http://localhost:3000' ];

My Wikibase version is 1.36.4.

AlexW00 commented 1 year ago

What does console.log(window.location.origin) print out? Is this value in your $wgCrossSiteAJAXdomains?

I've double-checked it, the window.location.origin=http://localhost:3000 and the final request is:

http://localhost/w/api.php?action=login&format=json&origin=http://localhost:3000

And this is my config in Wikibase:

$wgCrossSiteAJAXdomains = [ 'http://localhost:3000' ];

My Wikibase version is 1.36.4.

In your wbEditConfig object, the port of your wikibase instance seems to be missing. On which port is wikibase running? If it is 8181 can you try it with the following config object? Btw I also published an update to the fork, which fixed another bug. I recommend you update wikibase-edit-browser first.

    this.wbEditBrowser = require('wikibase-edit-browser')({
      instance: 'http://localhost:8181',
      credentials: {
        username: 'admin',
        password: 'XXX'
      }
    })
    this.wbEditBrowser.label.set({ id: 'Q35702', language: 'ca', value: 'test' })
jmformenti commented 1 year ago

In your wbEditConfig object, the port of your wikibase instance seems to be missing. On which port is wikibase running? If it is 8181 can you try it with the following config object? Btw I also published an update to the fork, which fixed another bug. I recommend you update wikibase-edit-browser first.

It is running on port 80, I'll try to upgrade Wikibase to discard some problem with that version