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

Should macOS .webloc files work? #34

Open
TomGem opened this issue May 29, 2020 · 17 comments
Open

Should macOS .webloc files work? #34

TomGem opened this issue May 29, 2020 · 17 comments

Comments

@TomGem
Copy link

TomGem commented May 29, 2020

Should macOS .webloc files work in the current version? Windows .url files work fine but with any .webloc files NC just says:
This link-file doesn't seem to be valid. – You can fix this by editing the file.

I've attached an example, it's a zipped 'apple binary property list' file.

te-online-files_linkeditor- A nextcloud app to edit .URL and .webloc files and visit links.zip

@te-online
Copy link
Owner

@TomGem Thanks for your bug report. I'll look into that as soon as possible. I'm working on a new version of the app on the next branch, though, where I've re-written the way .webloc files are parsed. There are some issue to be solved, before I can make a release from it, but maybe you'd like to check it out already?

@TomGem
Copy link
Author

TomGem commented Jun 2, 2020

Thanks for the fast reply! Testing, yes, gladly. How do get the next branch?

@te-online
Copy link
Owner

You can download it from this repository (https://github.com/te-online/files_linkeditor/tree/next), but you'll need a testing Nextcloud instance, e.g. on your local machine, because I wouldn't recommend putting the app for testing into your production Nextcloud.

On this testing Nextcloud instance you replace the contents of the folder apps/files_linkeditor with the content of the next branch (downloaded as .zip file, for example).

@te-online
Copy link
Owner

te-online commented Jun 6, 2020

@TomGem I've just release version 1.1.0 with the new .webloc file parser. Can you check if .webloc files work again?

@TomGem
Copy link
Author

TomGem commented Jun 8, 2020

You are fast, thanks!
Unfortunately linkeditor is still unable to open the macOS .webloc files.

webloc-links

@te-online
Copy link
Owner

@TomGem That's a shame... Any chance you can send me one of those broken files? Or upload it here? When I create the files in macOS I can open them fine, but I'm not using the latest macOS version, so maybe that's why.

@TomGem
Copy link
Author

TomGem commented Jun 8, 2020

Of course, I've attached a few to this message:
Webloc-Examples.zip
May I ask, how old is your version of macOS?

Anyway, current versions of macOS write .webloc files as Apple binary property list:
$ file link.webloc: Apple binary property list

Starting with Mac OS X 10.4, this is the default format for preference files.
https://en.wikipedia.org/wiki/Property_list
However, I don't know when they changed .webloc files, which are just .plist files with another file ending, to binary.

You might find some hints on how to parse these file here:
https://www.npmjs.com/search?q=binary%20plist

There is also a command linie utility to convert plist file formats, plutil.
It ships with macOS, there is also a similar tool for Linux:
https://packages.debian.org/buster/libplist-utils

@te-online
Copy link
Owner

Oh, that's unfortunate 😢 Thanks for your thorough research!

I can reproduce this issue now. The funny thing is, that Chrome still uses the XML format, while Safari saves shortcuts in the binary format. What a mess...

I'll look into if any of the npm modules will run in the browser, then I can try parsing as XML and if that fails, I'll try to parse the file as binary format.

te-online added a commit that referenced this issue Jun 13, 2020
@te-online
Copy link
Owner

The latest release, 1.1.1, addresses this issue by including a binary plist parser. – Two things to note. Firstly, this doubles the bundle size, unfortunately, so I might think about a server-side solution in the future. And, there's no writing of these binary files included. So keep in mind, if you edit a binary plist file it will be replaced by an XML-version of the file. From my experience that works just the same in terms of opening the link on macOS in the future.

@TomGem
Copy link
Author

TomGem commented Jun 15, 2020

Thank you, I just tested 1.1.1 with various .webloc files, everything works fine now. 👍😊

@kroko
Copy link

kroko commented Feb 8, 2023

Screenshot 2023-02-08 at 09 22 58

Reporting that the issue persists.
I've dealt with this in the past in different context, see this implementation in C that still works on reference files including safari.webloc which is the binary plist.
This plugin fails on safari.webloc, passes on chrome.webloc and firefox.webloc.

@te-online
Copy link
Owner

Generally, binary .webloc files cannot be read, because the parser is written purely in JavaScript and works only on strings. Maybe there could be an opportunity to use some webassembly for this 🤔 But I'm not actively looking into this right now. I know this is not perfect, but you can always create the link file using the Nextcloud GUI and then still double-click it on your Mac to open the link.

@kroko
Copy link

kroko commented Feb 8, 2023

// readbinarywebloc.js

async function fetchResponseValidateSimple (response) {
  if (!response.ok) {
    return Promise.reject(new Error(response.statusText));
  }
  return Promise.resolve(response);
}

async function loadDataFromUrlAsArrayBuffer (url) {
  return fetch(url)
    .then(response => fetchResponseValidateSimple(response) && response.arrayBuffer())
    .then(buffer => {return buffer;})
    .catch(error => console.error(error?.name, error));
}

// https://stackoverflow.com/a/70765338/1979530
function betweenMarkers (text, begin, end) {
  var firstChar = text.indexOf(begin) + begin.length;
  var lastChar = text.indexOf(end);
  var newText = text.substring(firstChar, lastChar);
  return newText;
}

(async () => {
  const urlToLoad = 'https://github.com/WARP-LAB/WindowsWeblocOpener/raw/master/testfiles/safari.webloc';
  // in Nextcloud app JS side urlToLoad is ->
  // const urlToLoad = this.source || this.davPath;
  // <- as it would both work in dav (authorized) and plain raw shared cases

  const buffer = await loadDataFromUrlAsArrayBuffer(urlToLoad);

  // convert to text because albeit plist is binary, the actual url is readable string (see the C impl ;))
  const blob = new Blob([buffer], {type: 'text/plain; charset=utf-8'});
  const delimStringStart = 'http';
  const delimStringEnd = '\b\v';
  blob.text().then(
    text => {
      const urlToOpen = delimStringStart + betweenMarkers(text, delimStringStart, delimStringEnd);
      // PROFIT ->
      console.log(urlToOpen);
    }
  );
})()
node readbinarywebloc.js

p.s. sure, this approach assumes HTTP(S) URI scheme, and ignores any other, but hey... ;)

@te-online
Copy link
Owner

Thanks, I'll take a look as soon as I can. Looks promising!
The question remains, what can we do if you want to edit such file? Probably we could replace it with the text-only-version of the format...

@kroko
Copy link

kroko commented Feb 8, 2023

imho, flag it as not editable and simply do not present user with the option to edit.
this is the reason why I put in this issue not started to look at your code in order to do a PR, as I assume that involves some new logic to divide between editable and noneditable URLs, you know your way around better there 😄 plus my example just assumes binary webloc, the fetch logic should check (as the C example) is it XML, if not then do binary logic.
i've tinkered with writing NC plugins for internal use (none published) thus I know my way around a bit. in those plugins I use exactly fetch to load this.source || this.davPath as i need to pass them to File for my needs. and i have done quite a lot with binary streams in javascript (node/Electron though, but array buffers exist in browser too), which makes me think this would be easily achievable in pure browser javascript in an NC app.
thanks for your great app and hopefully you could look into this.

@kroko
Copy link

kroko commented Feb 8, 2023

oh, and currently i fall back to just converting binary plists to xml ones in directory trees in those cases where i know that some shared stuff will be accessed by users from web

#!/bin/zsh
for f in "$@"
do
  PATHT_TO_SEARCH="$f"
  echo $PATHT_TO_SEARCH
  find $PATHT_TO_SEARCH -name "*.webloc" -exec bash -c "echo '{}' && plutil -convert xml1 '{}'" \;
done
exit 0

@kroko
Copy link

kroko commented Feb 8, 2023

Probably we could replace it with the text-only-version of the format...

missed it. yeah, if the url is parsed out from binary, the file could be rewritten using the known scheme and just putting the URL in it

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>URL</key>
	<string>URL_RETREIVED_FROM_BINARY_WEBLOC_GOES_HERE</string>
</dict>
</plist>

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

No branches or pull requests

3 participants