barcode-detector icon indicating copy to clipboard operation
barcode-detector copied to clipboard

Barcode detection service unavailable

Open louie0086 opened this issue 2 years ago • 33 comments

https://github.com/Sec-ant/barcode-detector/blob/ab876a6a19b610ed3ce4b69f8216ed3c878421f4/src/BarcodeDetector.ts#L140-L143

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?

louie0086 avatar Sep 15 '23 03:09 louie0086

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.

Sec-ant avatar Sep 15 '23 03:09 Sec-ant

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?

louie0086 avatar Sep 15 '23 05:09 louie0086

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 [email protected], the matching version is @sec-ant/[email protected], so you can download the zxing_reader.wasm file from any of the following CDN paths:

  • UNPKG: https://unpkg.com/@sec-ant/[email protected]/dist/reader/zxing_reader.wasm
  • jsDelivr: https://cdn.jsdelivr.net/npm/@sec-ant/[email protected]/dist/reader/zxing_reader.wasm
  • Skypack: https://cdn.skypack.dev/@sec-ant/[email protected]/dist/reader/zxing_reader.wasm

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.

Sec-ant avatar Sep 15 '23 07:09 Sec-ant

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?

louie0086 avatar Sep 15 '23 07:09 louie0086

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.

Sec-ant avatar Sep 15 '23 08:09 Sec-ant

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

louie0086 avatar Sep 15 '23 08:09 louie0086

In that case, can you share a repro :)

Sec-ant avatar Sep 15 '23 08:09 Sec-ant

In that case, can you share a repro :)

Ok .i send email to you

louie0086 avatar Sep 15 '23 08:09 louie0086

Ok .i send email to you

Alright, here's my email address: [email protected]

Sec-ant avatar Sep 15 '23 09:09 Sec-ant

@louie0086 Can you try [email protected] (matches with @sec-ant/[email protected]) and see if this error still exists? If the error still exists, can you find more error information in the console?

Sec-ant avatar Sep 17 '23 09:09 Sec-ant

@louie0086 Can you try [email protected] (matches with @sec-ant/[email protected]) 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/[email protected] 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"

louie0086 avatar Sep 19 '23 01:09 louie0086

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

https://github.com/Sec-ant/barcode-detector/blob/bca5f666062e29a8a4d075f71e4695f9e7fc77c1/src/BarcodeDetector.ts#L156-L157

Sec-ant avatar Sep 19 '23 02:09 Sec-ant

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

https://github.com/Sec-ant/barcode-detector/blob/bca5f666062e29a8a4d075f71e4695f9e7fc77c1/src/BarcodeDetector.ts#L156-L157

image

louie0086 avatar Sep 19 '23 10:09 louie0086

screenshot

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

Sec-ant avatar Sep 19 '23 10:09 Sec-ant

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]

louie0086 avatar Sep 20 '23 08:09 louie0086

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 [email protected], this version problem is fixed :).

Sec-ant avatar Sep 20 '23 08:09 Sec-ant

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

louie0086 avatar Sep 21 '23 08:09 louie0086

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?

Sec-ant avatar Sep 21 '23 08:09 Sec-ant

RangeError stack here:

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

 $.HEAP8.set(O, L)

louie0086 avatar Sep 22 '23 02:09 louie0086

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?

Sec-ant avatar Sep 22 '23 03:09 Sec-ant

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

louie0086 avatar Sep 22 '23 03:09 louie0086

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?

Sec-ant avatar Sep 22 '23 04:09 Sec-ant

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

louie0086 avatar Sep 25 '23 01:09 louie0086

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

Sec-ant avatar Sep 25 '23 02:09 Sec-ant

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)

louie0086 avatar Sep 25 '23 02:09 louie0086

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);

Sec-ant avatar Sep 25 '23 02:09 Sec-ant

w.HEAP8.byteLength

the result: zxingInstance.HEAP8.byteLength:0

louie0086 avatar Sep 28 '23 07:09 louie0086

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?

Sec-ant avatar Sep 28 '23 07:09 Sec-ant

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

louie0086 avatar Sep 29 '23 02:09 louie0086

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

Sec-ant avatar Sep 29 '23 02:09 Sec-ant