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

Fix Visicut calling inkscape in an AppImage. #721

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

jnweiger
Copy link
Contributor

@jnweiger jnweiger commented Apr 8, 2024

In Ubuntu 20.04, this worked flawlessly. But only by chance. We use libraries from the host system, together with the binary inside the mounted appimage. in Ubintu 22.04, this crashes:

/tmp/.mount_inkscaYGPL8G/usr/bin/inkscape --version
/tmp/.mount_inkscaYGPL8G/usr/bin/inkscape: error while loading shared libraries: libboost_filesystem.so.1.71.0: cannot open shared object file: No such file or directory

The fix is to not call the binary directly, but the AppRun script, which nicely prepares the environment. But then, AppRun also prints a message for the user to stdout, (instead of stderr). We now need to filter this, when parsing output from e.g. --version:

/tmp/.mount_inkscaYGPL8G/AppRun --version 2>/dev/null
You should not use AppImage in production, but you can speedup the AppImage by following this guide: https://inkscape.org/learn/appimage/
Inkscape 1.3.2 (091e20e, 2023-11-25)

In Ubuntu 20.04, this worked flawlessly. But only by chance. We use libraries from the host system, together with the binary inside the mounted appimage.
in Ubintu 22.04, this crashes:

/tmp/.mount_inkscaYGPL8G/usr/bin/inkscape --version
 /tmp/.mount_inkscaYGPL8G/usr/bin/inkscape: error while loading shared libraries: libboost_filesystem.so.1.71.0: cannot open shared object file: No such file or directory

The fix is to not call the binary directly, but the AppRun scrit, which nicely prepares the environment. AppRun also prints a message for the user to stdout, (instead of stderr).
We now need to filter this, when parsing output from e.g. --version:

/tmp/.mount_inkscaYGPL8G/AppRun --version 2>/dev/null
 You should not use AppImage in production, but you can speedup the AppImage by following this guide: https://inkscape.org/learn/appimage/
 Inkscape 1.3.2 (091e20e, 2023-11-25)
@jnweiger
Copy link
Contributor Author

jnweiger commented Apr 8, 2024

tools/inkscape_extension/visicut_export.py Outdated Show resolved Hide resolved
tools/inkscape_extension/visicut_export.py Outdated Show resolved Hide resolved
dirname() should be fine to. It is more readable. Thanks!

(not sure if introducing a new apprun_path variable contributes to readability though ...) But I don't mind.

Co-authored-by: TheAssassin <[email protected]>
@TheAssassin
Copy link
Contributor

I'll open a separate PR to fix the issues in the linux-checkinstall CI.

@TheAssassin
Copy link
Contributor

Fix for the CI problems available in #722.

@mgmax
Copy link
Collaborator

mgmax commented Apr 8, 2024

Please also report the stdout pollution as an upstream issue with Inkscape. We are probably not the only one affected by that.

( Side topics, not really relevant to this PR: What about the other combinations and directions - does calling Visicut from the AppImage Inkscape work correctly, even with all the AppImage environment variables? What if VisiCut is also an AppImage? )

@TheAssassin
Copy link
Contributor

If someone opens an issue upstream, please ask them to just export INKSCAPE_VERSION=1234 for plugins.

@jnweiger jnweiger requested review from mgmax and TheAssassin April 8, 2024 20:46
@jnweiger
Copy link
Contributor Author

jnweiger commented Apr 8, 2024

@jnweiger
Copy link
Contributor Author

jnweiger commented Apr 8, 2024

( Side topics, not really relevant to this PR: What about the other combinations and directions - does calling Visicut from the AppImage Inkscape work correctly, ...

Yes, I believe most real-life combinations work. I have especially tested the case where both, Inkscape and VisiCut are AppImages.

tools/inkscape_extension/visicut_export.py Outdated Show resolved Hide resolved
@TheAssassin
Copy link
Contributor

does calling Visicut from the AppImage Inkscape work correctly, ...

This is broken currently and will be working once this has been merged.

@jnweiger jnweiger requested a review from mgmax April 9, 2024 23:31
INKSCAPEBIN = apprun_path
for parent in Path(INKSCAPEBIN).parents:
apprun = parent / "AppRun"
if apprun.is_file() and os.access(apprun, os.X_OK):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this os.access check, it's very compact. pathlib should have a shortcut for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe only checking is_file() alone is even more compact? An inkscape AppImage that has an 'AppRun' file which has no execute bits, or is mounted without exec, or suffering from a security policy, or whatever ... is out of scope here anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just failing silently is not the best idea. Your algorithm can still cross mountpoints (that's what the is_mount check was there for before) and I can imagine a bunch of false positive detections of AppRuns in that case. For instance, in some occasions, AppDirs can be integrated in each other (lazy approach but it works, I use that myself occasionally). In such a case, the execute bit on some AppRun in the chain might not be set. Also, AppImages can be extracted and copied to devices that do not have the executable bit set, etc.

The check is fine and it's good to have it. In fact, security wise, we should add the mountpoint check and abort once it's crossed. To do so, this should be appended to the for's body:

    if parent.is_mount():
        break

Security (i.e., preventing critical issues) and safety (i.e., keeping users from experiencing weird behavior) always add a bit of verbosity to the code, but in the end, it's always worth it. We'd have some good reasons to throw exceptions here even. But that'd bloat this PR. I think in its current form, it's a reasonably solid implementation and I don't see any attack vector (without thinking about it for more than 5 minutes).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an INKSCAPE_COMMAND environment variable that seems to point to the AppRun file. Can you check if we can use this instead? First guess:

INKSCAPEBIN = os.environ.get("INKSCAPE_COMMAND") or which("inkscape", [INKSCAPEDIR])

This would avoid the potential problems.

INKSCAPEBIN = apprun_path
for parent in Path(INKSCAPEBIN).parents:
apprun = parent / "AppRun"
if apprun.is_file() and os.access(apprun, os.X_OK):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an INKSCAPE_COMMAND environment variable that seems to point to the AppRun file. Can you check if we can use this instead? First guess:

INKSCAPEBIN = os.environ.get("INKSCAPE_COMMAND") or which("inkscape", [INKSCAPEDIR])

This would avoid the potential problems.

@TheAssassin
Copy link
Contributor

What does "found" mean? Is that an officially supported environment variable provided by the Inkscape code? Is it an AppImage-specific feature?

@mgmax
Copy link
Collaborator

mgmax commented Apr 22, 2024

For Inkscape 1.3.x and 1.4.x (current / upcoming release), the AppImage sets INKSCAPE_COMMAND.
https://gitlab.com/inkscape/inkscape/-/blob/1.4.x/packaging/appimage/AppRun?ref_type=heads#L40-44
This was added in 2022: https://gitlab.com/inkscape/inkscape/-/merge_requests/4751

For Inkscape 1.5.x (development branch) the AppImage is currently broken and fails to launch Python, so it is not possible to test. https://gitlab.com/inkscape/inkscape/-/issues/4851

Inkscape's inkex library for writing extensions has been using it since at least 1.0, so I guess that the normal Inkscape installation >= 1.0 also sets the variable.
https://gitlab.com/inkscape/extensions/-/blob/master/inkex/command.py?ref_type=heads#L46

Once we drop support for AppImage-Inkscape < 1.3 and normal Inkscape < 1.0 (used e.g. on Ubuntu 20.04) we could throw out half of our extension code and instead use inkex.command and friends. Until then, I suggest to do it as above: Use INKSCAPE_COMMAND if available, else fall back to what we did before.

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

Successfully merging this pull request may close these issues.

3 participants