tweaselORG / cyanoacrylate

Toolkit for large-scale automated traffic analysis of mobile apps on Android and iOS.
MIT License
5 stars 1 forks source link

`ERR_IMPORT_ASSERTION_TYPE_MISSING` when used without bundler #50

Closed baltpeter closed 2 months ago

baltpeter commented 4 months ago

I tried upgrading cli to the latest CA version. However, when trying to build, I get the following error:

    TypeError Plugin: tweasel-cli Plugin: tweasel-cli: Module "file:///home/benni/coding/JS/tweasel/cli/node_modules/appstraction/package.json"
     needs an import attribute of type "json"
    Code: ERR_IMPORT_ASSERTION_TYPE_MISSING
baltpeter commented 4 months ago

Here's the code that causes this problem. We're trying to find appstraction's version by importing its package.json:

https://github.com/tweaselORG/cyanoacrylate/blob/46b03731254ad800e6330a68c519e43aea6e3f58/src/index.ts#L10

I think that problem is that cli is using tsc instead of a "proper" bundler like Parcel.

And Node does not support importing JSON files without an import assertion (require() works fine, though).

I tried this example:

import abc from './abc.json';

console.log(abc);

And indeed:

❯ node index.mjs
node:internal/errors:496
    ErrorCaptureStackTrace(err);
    ^

TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///tmp/sdfsdfsd/abc.json" needs an import assertion of type "json"
    at new NodeError (node:internal/errors:405:5)
    at validateAssertions (node:internal/modules/esm/assert:94:15)
    at defaultLoad (node:internal/modules/esm/load:93:3)
    at DefaultModuleLoader.load (node:internal/modules/esm/loader:263:26)
    at DefaultModuleLoader.moduleProvider (node:internal/modules/esm/loader:179:22)
    at new ModuleJob (node:internal/modules/esm/module_job:63:26)
    at #createModuleJob (node:internal/modules/esm/loader:203:17)
    at DefaultModuleLoader.getJobFromResolveResult (node:internal/modules/esm/loader:156:34)
    at DefaultModuleLoader.getModuleJob (node:internal/modules/esm/loader:141:17)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:33) {
  code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING'
}

Node.js v20.5.1

Earlier versions (like Node 14) didn't support importing JSON files at all:

❯ nvm use 14
Now using node v14.21.2 (npm v6.14.17)
❯ node index.mjs
internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /tmp/sdfsdfsd/abc.json
    at new NodeError (internal/errors.js:322:7)
    at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)
    at Loader.getFormat (internal/modules/esm/loader.js:105:42)
    at Loader.getModuleJob (internal/modules/esm/loader.js:243:31)
    at async ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:78:21)
    at async Promise.all (index 0)
    at async link (internal/modules/esm/module_job.js:83:9) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
baltpeter commented 4 months ago

The problem is the interaction between tsc and Parcel.

If I bundle the example from above using tsc (npx typescript index.ts --resolveJsonModule --esModuleInterop), it produces:

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var abc_json_1 = __importDefault(require("./abc.json"));
console.log(abc_json_1.default);

Meanwhile, Parcel keeps this as a JSON import:

import {version as $kYxtx$version} from "appstraction/package.json";
baltpeter commented 4 months ago

I had a similar problem in ReportHAR.

Unfortunately, just adding the import assertion didn't help—Parcel "helpfully" strips those in the output.

In ReportHAR, I was able to work around the problem by using Parcel's bundle inlining feature to… well, inline the JSON into the bundled code.

But I don't think that that is a valid solution here. That would mean that we essentially hardcode the appstraction version at build time. But that may not be the version that actually runs on the enduser's PC.

baltpeter commented 4 months ago

The problem is the interaction between tsc and Parcel.

Actually, that description doesn't quite describe the problem correctly. The reason that tsc produced CJS code in this example is that I ran it with a blank tsconfig.json and only supplied the resolveJsonModule and esModuleInterop via the command line.

If we repeat a similar experiment with cli's tsconfig.json (which is configured to output ESM: "target": "es2019"), it will also just preserve JSON imports:

import test from './test.json';

Running the output with node produces the same ERR_IMPORT_ASSERTION_TYPE_MISSING error.

Whether it preserves import assertions depends on the module option, which gets a lot more complicated. But I won't get into that, because all of this is beside the point, I was just correcting what I had said earlier.

I think the actual issue here is that the JSON import is in dependency. And tsc will just never touch those at all. So, the tsconfig.json settings and whatever tsc produces, don't even matter at all.

baltpeter commented 4 months ago

This is turning out surprisingly hard.

baltpeter commented 4 months ago

Oh, looks like someone has very kindly reimplemented the whole module resolution algorithm in a module: https://github.com/wooorm/import-meta-resolve!

While it's utterly ridiculous that we need something like that, this seems like the best solution to me.

The only other alternative that I had in mind was shipping a single .cjs file with require('appstraction/package.json').version).

baltpeter commented 4 months ago

That seems to work.

But of course, it won't work for getting our own version. So I guess, we will still need bundle inlining. sigh

baltpeter commented 4 months ago

Urgh, now bundle inlining isn't working for some reason. -.-

baltpeter commented 4 months ago

Welp, import-meta-resolve doesn't work either if I install CA as a dependency:

    Error: Cannot find package 'appstraction' imported from /src/util.ts
    Code: ERR_MODULE_NOT_FOUND

I'm wasting way too much time on this. CJS shim it is.

baltpeter commented 4 months ago

CJS shim doesn't work (trivially, at least) because Parcel helpfully folds that into the ESM module as:

var $e16ea7c30f77cffa$exports = {};
$e16ea7c30f77cffa$exports = {
    /**
     * @param {string} dependency
     *
     * @returns {Promise<string>}
     */ getDependencyVersion: async (dependency)=>{
        if (dependency === "cyanoacrylate") dependency = "..";
        return require(`${dependency}/package.json`).version;
    }
};

And that obviously fails with require is not defined.

SheldorSheldonDZ commented 4 months ago

@baltpeter @zner0L Is there anything we con do about that issue or is somebody working on it? Right now i am getting the same issue with the newest version of tweasel-cli (see below). I am wondering if there is currently any working version of tweasel when trying to get an fresh version. If I use npm to install it I get an frida/meson build error (see my open thread at tweasel-cli-site) and when I install tweasel 1.0.1 via yarn I run into this error. I even tried some older Versions of tweasel but then I run into the problem, that the auto-configuration of Wireguard doesnt work. So any Ideas or help? Would be great! Thanks in Advance.

`

tweasel Command-line tool for the libraries of the tweasel project.

VERSION tweasel-cli/1.0.1 linux-x64 node-v18.20.4

USAGE $ tweasel [COMMAND]

TOPICS android-emulator Create, start, and delete Android emulators.

COMMANDS autocomplete display autocomplete installation instructions detect-tracking Detect tracking data transmissions from traffic in HAR format. help Display help for tweasel. record-traffic Record the traffic of an Android or iOS app in HAR format.

:~$ tweasel record-traffic '/home/apppruefung/Schreibtisch/com.lidl.eci.lidlplus_16.8.2-1470400597.apk' TypeError: Module "file:///home/apppruefung/.nvm/versions/node/v18.20.4/li b/node_modules/tweasel-cli/node_modules/appstraction/package.json" needs an import attribute of type "json" Code: ERR_IMPORT_ASSERTION_TYPE_MISSING

`

SheldorSheldonDZ commented 3 months ago

Found a workaround for now - but it should definitly be fixed in future. In the file /usr/local/share/.config/yarn/global/node_modules/cyanoacrylate/dist/index.js you can delete the line import {version as $kYxtx$version} from "appstraction/package.json"; and change the lines const versions = { appstraction: (0, $kYxtx$version), cyanoacrylate: (0, $d3eb50877c24837a$exports.version), to const versions = { appstraction: (0, "1.3.0"), cyanoacrylate: (0, "1.2.0"),