Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Barcode detection service unavailable #18

Open
louie0086 opened this issue Sep 15, 2023 · 33 comments
Open

Barcode detection service unavailable #18

louie0086 opened this issue Sep 15, 2023 · 33 comments
Labels
question Further information is requested

Comments

@louie0086
Copy link

throw new DOMException(
"Barcode detection service unavailable. Use 'setZXingModuleOverrides' in offline or strict CSP environments.",
"NotSupportedError",
);

i used vue-qrcode-reader at https website

<qrcode-stream @detect="onDetect"></qrcode-stream>

it shows "Barcode detection service unavailable. Use 'setZXingModuleOverrides' in offline or strict CSP environments.", "NotSupportedError"

the host already set Strict-Transport-Security: max-age=31536000; includeSubdomains; preload

but the static js file not set

i see the demo website https://vue-qrcode-reader.netlify.app. it's doc and static js both set Strict-Transport-Security

how can i solve the detect error?

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 15, 2023

Hey, louie

I don't think Strict-Transport-Security is relevant here. "CSP" is short for "Content Security Policy".

This package uses WebAssembly to provide the core function of detecting barcodes. And the browser must instantiate and execute the WebAssembly module to use it. However, per the spec, websites can control whether to block the WebAssembly execution by setting the script-src directive in CSP, specifically the wasm-unsafe-eval or unsafe-eval source value. If it is blocked, the error Barcode detection service unavailable will get thrown.

The directive connect-src can also affect this package. To prevent bloating the size, this package will load the .wasm file from the cdn.jsdelivr.net CDN at runtime (using fetch). connect-src or default-src can restrict the URLs which can be loaded with fetch. So if this connection is somewhat get blocked, the service unavailable error will also be thrown.

There're corresponding ways in which you can solve this problem:

  • If you have control on the website where you're using this package, you can modify the CSP of the site to allow wasm-unsafe-eval. and make sure connect-src or default-src includes https://cdn.jsdelivr.net. A detailed explanation can be found at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
  • If you don't want to load the .wasm file from a CDN. You can use setZXingModuleOverrides exported by vue-qrcode-reader to change the location where the .wasm file is hosted. For example, you can host the file on your website as an asset, etc.

If neither solves your problem, it would be great if you can provide the malfunctioning website so that I can dig into it and check whether there're some other bugs to fix.

@louie0086
Copy link
Author

import wasmFile from "../node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm?url";

I would like to ask what the syntax (?url)is?

in vue-cli project

import wasmFile from "@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm?url";

it's show error:

* a in ./node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm?url

To install it, you can run: npm install --save a

How do I import the wasm module correctly?

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 15, 2023

Ok you decide not to fetch the .wasm file from jsDelivr. There're some gotchas, so I'd like to explain more:


First, a question: I wonder if you want to inline the .wasm file inside your script output files or you want to host it as a binary file on your site, and fetch it from your site at runtime?

Inline

Inlining means encoding the .wasm file as a Base64 data url and hardcode this data url inside your script files. If you use a syntax like this:

import wasmFile from "...?url"

then you're inlining it. ?url is a syntax provided by build tools, like Vite, to transform assets into data urls. I'm not sure if vue-cli supports it. If it is supported, then the wasmFile will be a huge base64 encoded data url.

Afterwards, you use setZXingModuleOverrides + locateFile to relocate the fetching path to this data url:

setZXingModuleOverrides({
  locateFile: (path, prefix) => {
    if (path.endsWith(".wasm")) {
      return wasmFile; // <= a huge Base64 encoded data url
    }
    return prefix + path;
  },
});

A data url occupies a larger space than its binary form, and parsing a data url into binary data also consumes more CPU clocks. So, ideally, I suggest you to not use the inline form.

Binary

If you want to host it as a binary file on your site, then you need not to import it. You can just copy the .wasm file to your website's assets folder, e.g. public or assets, and use setZXingModuleOverrides + locateFile to relocate the fetching path like this:

setZXingModuleOverrides({
  locateFile: (path, prefix) => {
    if (path.endsWith(".wasm")) {
      return "https://<your website host>/public/zxing_reader.wasm"; // <= where the .wasm file is at
    }
    return prefix + path;
  },
});

Either way, CSP still applies. You have to make sure content-src and script-src are correctly configured to allow you fetching and executing it.


Second question: where is the .wasm file?

Normally, when you add vue-qrcode-reader as a dependency in your project, it will also download its dependencies inside node_modules folder, which includes barcode-detector. And barcode-detector in turn will download its dependency @sec-ant/zxing-wasm. This process is handled by the package manager automatically so you don't need to worry.

The .wasm file is published as an asset included in the package @sec-ant/zxing-wasm, therefore, the .wasm file can be found at this path:

<project root>/node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm

BUT, I made a mistake not pinning the version. So, the .wasm file you found in <project root>/node_modules/@sec-ant/zxing-wasm may not be what vue-qrcode-reader expects (Sorry for this mistake, I'm going to fix this in the next version). Therefore, for now, I recommend you manually download the .wasm file with the correct version, from the CDN.

If you're using vue-qrcode-reader@v5.3.4, the matching version is @sec-ant/zxing-wasm@2.1.3, so you can download the zxing_reader.wasm file from any of the following CDN paths:

Once you've downloaded the correct version of the .wasm file, you can inline or host it as you wish in your project.

Again, I'm really sorry for the inconvenience. Once the version problem is fixed and released in vue-qrcode-reader, you won't have to worry about downloading it with the matching version. You can just import or copy it from <project root>/node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm.

@louie0086
Copy link
Author

Thank @Sec-ant

i just put zxing_reader.wasm at assets public folder and then

  setZXingModuleOverrides({
    locateFile: (path, prefix) => {
      if (path.endsWith(".wasm")) {
        
        return '/zxing_reader.wasm';
      }
      return prefix + path;
    },
  });

my project site can request zxing_reader.wasm now.but it's still has error "Barcode detection service unavailable. Use 'setZXingModuleOverrides' in offline or strict CSP environments."

if the zxing_reader.wasm not from CDN and CSP not configured .Is this error still here?

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 15, 2023

Then this may be some other bug. To solve this problem I'll need more information.

  • If this issue is OS/browser related

    For example, is the demo page of vue-qrcode-reader works on the same device? If it doesn't, then it's probably device related, and then I need the versions of the device's OS and browser.

  • If the error only occurs in your project site

    Then it would be very helpful for you to share a repo to let me reproduce this problem, or share your site so that I can debug.

@louie0086
Copy link
Author

Then this may be some other bug. To solve this problem I'll need more information.

  • If this issue is OS/browser related
    For example, is the demo page of vue-qrcode-reader works on the same device? If it doesn't, then it's probably device related, and then I need the versions of the device's OS and browser.
  • If the error only occurs in your project site
    Then it would be very helpful for you to share a repo to let me reproduce this problem, or share your site so that I can debug.

yes.same device. vue-qrcode-reader demo page no exception

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 15, 2023

In that case, can you share a repro :)

@louie0086
Copy link
Author

In that case, can you share a repro :)

Ok .i send email to you

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 15, 2023

Ok .i send email to you

Alright, here's my email address: zzwu@zju.edu.cn

@Sec-ant Sec-ant changed the title detect error Barcode detection service unavailable Sep 16, 2023
@Sec-ant Sec-ant added the question Further information is requested label Sep 16, 2023
@Sec-ant
Copy link
Owner

Sec-ant commented Sep 17, 2023

@louie0086 Can you try vue-qrcode-reader@5.3.5 (matches with @sec-ant/zxing-wasm@2.1.5) and see if this error still exists? If the error still exists, can you find more error information in the console?

@louie0086
Copy link
Author

@louie0086 Can you try vue-qrcode-reader@5.3.5 (matches with @sec-ant/zxing-wasm@2.1.5) and see if this error still exists? If the error still exists, can you find more error information in the console?

i updated @sec-ant/zxing-wasm@2.1.5 and copy zxing_reader.wasm to zxing_reader1.wasm

still

  setZXingModuleOverrides({
    locateFile: (path, prefix) => {
      if (path.endsWith(".wasm")) {
        
        return '/zxing_reader1.wasm';
      }
      return prefix + path;
    },
  });

now it show

    "Barcode detection service unavailable.",
    "NotSupportedError"

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 19, 2023

I added this line of code to log a detailed error information, can you some how see this in the console?

// we need this information to debug
console.error(e);

@louie0086
Copy link
Author

I added this line of code to log a detailed error information, can you some how see this in the console?

// we need this information to debug
console.error(e);

image

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 19, 2023

screenshot

The RangeError is what we've been seeking. Is that just an empty object or does it hold more information?

@louie0086
Copy link
Author

louie0086 commented Sep 20, 2023

screenshot The RangeError is what we've been seeking. Is that just an empty object or does it hold more information?

message:Range consisting of offset and length are out of bounds.

stack:set@[native code]

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 20, 2023

Hmm, interesting.

If this is something about the WebAssembly instantiation, I wonder why vue-qrcode-reader demo page works.

Does this error message have a context so that I can check which line of code and file this error is thrown from? Or can you jump to the corresponding file and provide some information on its whereabouts? Screenshots would be great, and you can email me if you want.

PS: I previously said

Once the version problem is fixed and released in vue-qrcode-reader, you won't have to worry about downloading it with the matching version. You can just import or copy it from /node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm.

The good news is, starting from vue_qrcode_reader@5.3.5, this version problem is fixed :).

@louie0086
Copy link
Author

louie0086 commented Sep 21, 2023

I isolated a stripped down code from my project that is scannable. But the original project still has Range Error and NotSupportedError.

https://github.com/louie0086/test_Barcode

i used mkcert and http-server -S -C {PATH/TO/CERTIFICATE-FILENAME}.pem -K {PATH/TO/CERTIFICATE-KEY-FILENAME}.pem

https://web.dev/i18n/en/how-to-use-local-https/

with local IP test

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 21, 2023

Thanks for the repo, but I'm afraid a scannable demo can't provide to too much information on why your original project doesn't work.

What about these questions I previously asked:

Does this error message have a context so that I can check which line of code and file this error is thrown from? Or can you jump to the corresponding file and provide some information on its whereabouts?

@louie0086
Copy link
Author

louie0086 commented Sep 22, 2023

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 22, 2023

RangeError stack here:

https://github.com/louie0086/test_Barcode/blob/5c7a69936a4649c5b860b405b6797ba5aef3456c/public/barcode-detector/dist/es/pure.js#L345-L354

 $.HEAP8.set(O, L)

Thanks, this is very helpful. So the error is thrown from this line from the source code:

https://github.com/Sec-ant/zxing-wasm/blob/8b8df68e781e7524ce96f12276c7a028b2c0c9d6/src/core.ts#L390

I'm not very clear about the root cause but I can try to do some debugging. So this error happens on an iPhone iOS 16.6 Safari Browser, right?

@louie0086
Copy link
Author

louie0086 commented Sep 22, 2023

RangeError stack here:
https://github.com/louie0086/test_Barcode/blob/5c7a69936a4649c5b860b405b6797ba5aef3456c/public/barcode-detector/dist/es/pure.js#L345-L354

 $.HEAP8.set(O, L)

Thanks, this is very helpful. So the error is thrown from this line from the source code:

https://github.com/Sec-ant/zxing-wasm/blob/8b8df68e781e7524ce96f12276c7a028b2c0c9d6/src/core.ts#L390

I'm not very clear about the root cause but I can try to do some debugging. So this error happens on an iPhone iOS 16.6 Safari Browser, right?

yes.iPhone 14 Pro Max.

But the demo repo is Okay

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 22, 2023

Can you log the data, byteLength, bufferPtr and HEAP8 if you can patch the source packages in your project?

image

You can also directly modify the dist file, like this:

image

And show me the result?

@louie0086
Copy link
Author

img_v2_b4a0580b-329e-45fc-a828-4353af1f5chu

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 25, 2023

What's the byteLength of the Int8Array, i.e. zxingInstance.HEAP8.byteLength?

@louie0086
Copy link
Author

byteLength

i just console at barcode-detector.pure.js

    const w = await Bt($, ot.getState().zxingModuleOverrides),
      {
        data: O,
        width: G,
        height: j,
        data: { byteLength: F },
      } = c,
      Y = w._malloc(F)
    console.log('data:',O)
    console.log('byteLength:',F)
    console.log('bufferPtr:',Y)
    console.log('zxingInstance.HEAP8:',w.HEAP8)
    w.HEAP8.set(O, Y)
    const N = w.readBarcodesFromPixmap(Y, G, j, m, pe(u), g)
    w._free(Y)

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 25, 2023

I mean, can you also log the byteLength of the HEAP8 object in the console? So I can know the total available memory it holds.

like this (add this line):

console.log('zxingInstance.HEAP8.byteLength:', w.HEAP8.byteLength);

@louie0086
Copy link
Author

w.HEAP8.byteLength

the result: zxingInstance.HEAP8.byteLength:0

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 28, 2023

That's some useful info and a good start. Apparently, for some reason, the memory is not successfully allocated, which brings us to this line of code:

https://github.com/louie0086/test_Barcode/blob/5c7a69936a4649c5b860b405b6797ba5aef3456c/public/barcode-detector/dist/es/pure.js#L415-L416

Can you help me check whether J.buffer.byteLength is also zero?

@louie0086
Copy link
Author

That's some useful info and a good start. Apparently, for some reason, the memory is not successfully allocated, which brings us to this line of code:

https://github.com/louie0086/test_Barcode/blob/5c7a69936a4649c5b860b405b6797ba5aef3456c/public/barcode-detector/dist/es/pure.js#L415-L416

Can you help me check whether J.buffer.byteLength is also zero?

https://github.com/louie0086/test_Barcode/blob/master/barcode-detector.pure_4.js#L443

K.buffer undefiend

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 29, 2023

Hmmm, that means wasmMemory is not initiated.

Can you log n, n.exports and n.exports.qa in this function before the return statement?

https://github.com/louie0086/test_Barcode/blob/2faebca6c2e0ed3626b7ebfa183937b76cc279fe/barcode-detector.pure_4.js#L564-L566

@louie0086
Copy link
Author

@Sec-ant
Copy link
Owner

Sec-ant commented Sep 30, 2023

In a normal case, the n.exports.qa should be an instance of WebAssembly.Memory, like this (in a chrome browser):

image

I cannot tell whether B$() in your snapshot is an instance of the WebAssembly.Memory or is just a plain function. Given that the code works in your demo repo but not in your project, can you also check the n.exports.qa in your demo repo and compare the working one with the error one to see if the difference indeed lies in the n.exports.qa?

@louie0086
Copy link
Author

https://github.com/louie0086/test_Barcode/blob/master/barcode-detector.pure_4.js#L564-L566

i add a alert

The demo tips [object WebAssembly.Memory]

but the project is function B$(){hC()}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants