musescore-downloader icon indicating copy to clipboard operation
musescore-downloader copied to clipboard

MuseScore's Response to @workedintheory's Comment

Open sealsrock12 opened this issue 3 years ago • 22 comments

After @workedintheory's threat to Xmader, an anonymous MuseScore user shared with me the following statement from David, the "Chief Product Officer at Musescore BVBA":

The user is responding is not a part of musescore.com team, but he is working in the company (I mean @workedintheory).

I saw some complaints about his behavior, but after reading all the thread, I don't see any unacceptable things (maybe I just didn't notice).

User called (Xmader) abused our API, create the pirate browser extension, and also stole some scores. We put a lot of effort to neutralize his code, and spent a lot of $ and time for this. His actions are total copyright infringement. So I suppose none of us should worry about his feelings.

sealsrock12 avatar Jul 20 '21 21:07 sealsrock12

We put a lot of effort to neutralize his code, and spent a lot of $ and time for this. His actions are total copyright infringement. So I suppose none of us should worry about his feelings.

If the statement is real, does it mean my project costs them a lot of money and effort, so it's ok to send a kind of death-threat to me?

Xmader avatar Jul 20 '21 21:07 Xmader

(edit: nevermind i misread the quoting lol)

jneen avatar Jul 20 '21 21:07 jneen

Aah yes, doubling down on stupid. They're all in I see.

SchizoDuckie avatar Jul 20 '21 22:07 SchizoDuckie

Confirms also that this is a company policy and not one rogue employee or two like some wish to portray the thing.

cadadr avatar Jul 20 '21 22:07 cadadr

Hey, Xmader, make sure to make a GoFundMe or something should something happen.

I'm sure plenty of people will lend you their support.

Honestly, the Audacity (heh) of these people....

TZer0 avatar Jul 21 '21 10:07 TZer0

Adding credential checking to the API (which should be there if it is not meant to be public) takes a day at most, so wouldn't call it lots of effort and money.

raynet avatar Jul 21 '21 19:07 raynet

:laughing: Streisand effect initiated

Poikilos avatar Jul 21 '21 20:07 Poikilos

Hey, Xmader, make sure to make a GoFundMe or something should something happen.

I'm sure plenty of people will lend you their support.

Thanks.

Rather than money, more importantly, I need good lawyers for copyright, immigration status / status of political refugee

Xmader avatar Jul 21 '21 22:07 Xmader

@Xmader It's not their area of expertise, but the EFF are a bunch of lawyers who do offer legal advice and assistance. It may be worth contacting them to see if there's anything they can do to help. It's probably unlikely that they'll be able to do much about immigration stuff but maybe they can connect you with somebody in that field. If I were you I'd send them an email :)

AntiSol avatar Jul 22 '21 07:07 AntiSol

The EFF does take an interest in the chilling effects of extreme legal enforcement on rights, so if approached from that perspective they might have some advice.

nccerhostmaster avatar Jul 22 '21 14:07 nccerhostmaster

It's amazing how every time they say something, people get even more upset at them.

Be-ing avatar Jul 23 '21 00:07 Be-ing

Hey, Xmader, make sure to make a GoFundMe or something should something happen. I'm sure plenty of people will lend you their support.

Thanks.

Rather than money, more importantly, I need good lawyers for copyright, immigration status / status of political refugee

Perhaps the Digital Freedom Fund (DFF) https://digitalfreedomfund.org - can help you to find somebody. They work in Europe but they are well connected.

nanocat-net avatar Jul 23 '21 06:07 nanocat-net

It seems like MuseGroup is just digging a bigger whole to bury themselves in, the multiple audacity debacles, librescore threats and now this, it's insane.

caughtquick avatar Jul 23 '21 08:07 caughtquick

It's amazing how every time they say something, people get even more upset at them.

Yeah, this must be some special kind of ability. Every time they open their mouths or write something down it's a shit show. I have never seen anything like that before, this company is going to be hated by a lot of people. Maybe one day they will be hated more than Comcast, EA and Activision if they keep continuing the stupid shit.

Remzi1993 avatar Jul 24 '21 03:07 Remzi1993

If you're located in the US, @Xmader (we don't recall if you are or not, nor is it in our notes anywhere) then the ACLU would likely be interested in your problem here and may be in a position to offer you counsel. This kind of situation is along the lines of what they frequently assist with.

Best of luck in staying safe and continuing the good work!

kirwinia avatar Jul 24 '21 16:07 kirwinia

I don't think they really intervene directly in any copyright case. Their bread and butter is protecting free speech from government entities. The EFF would probably be a better resource imo

IkeKap avatar Jul 24 '21 20:07 IkeKap

Hey, Xmader, make sure to make a GoFundMe or something should something happen. I'm sure plenty of people will lend you their support.

Thanks.

Rather than money, more importantly, I need good lawyers for copyright, immigration status / status of political refugee

When Youtube-dl was taken down, EFF helped the team with legal advices which leads to Github restoring the repo. Maybe they can help you with this one too.

ghost avatar Jul 30 '21 19:07 ghost

We put a lot of effort to neutralize his code, and spent a lot of $ and time for this. His actions are total copyright infringement. So I suppose none of us should worry about his feelings.

If the statement is real, does it mean my project costs them a lot of money and effort, so it's ok to send a kind of death-threat to me?

The neutralization pretty much is just a 90 ish line inline script.

(function () {
        function executeIfLoaded(callback) {
            if (document.readyState === 'complete') {
                callback()
            } else {
                window.addEventListener('load', callback)
            }
        }
        function onReady(callback) {
            if (document.readyState !== "loading") {
                callback();
            } else {
                document.addEventListener("DOMContentLoaded", callback);
            }
        }
        function getIsUserScript(stack) {
            return stack.indexOf('userscript.html') > -1
        }
        var createElement = document.createElement;
        var open = window.open;
        var append = HTMLElement.prototype.append;
        var prepend = HTMLElement.prototype.prepend;
        var Img = window.Image;

        Object.defineProperty(HTMLElement.prototype, 'append', {
            writable: false,
            value: function () {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
                return append.apply(this, arguments)
            }
        })

        Object.defineProperty(HTMLElement.prototype, 'prepend', {
            writable: false,
            value: function () {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
                return prepend.apply(this, arguments)
            }
        })

        function disable() {
                        executeIfLoaded(function () {
                window["yaCounter46196364"].reachGoal('UNLEGAL_PAGE_SHOW', {
                    TrackingId: "0",
                    user_id: 0,
                    origin_url: window.location.href,
                })
            })
        }

        document.createElement = function() {
            var tag = arguments[0].toLowerCase()
            if (['img', 'iframe'].indexOf(tag) !== -1) {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
            }
            return createElement.apply(this, arguments);
        }
        window.open = function () {
            var stack = new Error().stack;
            if (getIsUserScript(stack)) return;
            return open.apply(this, arguments);
        }

        window.Image = function() {
            var stack = new Error().stack
            var stackChunks = stack.split('\n').slice(2);
            var lastLine = stackChunks.reverse()[0];
            var url = lastLine.split(' ').reverse()[0]
            var urlChunks = url.substr(1, url.length - 2).split(':')
            var resultUrl = urlChunks[0] + ':' + urlChunks[1]

            if (
                getIsUserScript(stack)
                || lastLine.split(' (eval').length >= 3
                || (lastLine.indexOf(' eval ') && resultUrl === location.href)                 || stackChunks.every(function (chunk) { return chunk.indexOf('a (https://c.amazon-adsystem.com/aax2/apstag.js:') > -1 })
            ) {
                disable()
                return null;
            }
            return new Img(arguments[0], arguments[1])
        }
    })();

All that code is doing is preventing a userscript from making Image objects, adding or creating any elements. It would probably take just a little work to bypass musescore can't do anything about the code running at document-start.

anartisticpanda avatar Oct 17 '21 17:10 anartisticpanda

Who cares what the stupid musescore developers have to say? Piracy will never die. It is not our problem that big companies want to make profit out of everything.

user7230724 avatar Dec 16 '21 13:12 user7230724

We put a lot of effort to neutralize his code, and spent a lot of $ and time for this. His actions are total copyright infringement. So I suppose none of us should worry about his feelings.

If the statement is real, does it mean my project costs them a lot of money and effort, so it's ok to send a kind of death-threat to me?

The neutralization pretty much is just a 90 ish line inline script.

(function () {
        function executeIfLoaded(callback) {
            if (document.readyState === 'complete') {
                callback()
            } else {
                window.addEventListener('load', callback)
            }
        }
        function onReady(callback) {
            if (document.readyState !== "loading") {
                callback();
            } else {
                document.addEventListener("DOMContentLoaded", callback);
            }
        }
        function getIsUserScript(stack) {
            return stack.indexOf('userscript.html') > -1
        }
        var createElement = document.createElement;
        var open = window.open;
        var append = HTMLElement.prototype.append;
        var prepend = HTMLElement.prototype.prepend;
        var Img = window.Image;

        Object.defineProperty(HTMLElement.prototype, 'append', {
            writable: false,
            value: function () {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
                return append.apply(this, arguments)
            }
        })

        Object.defineProperty(HTMLElement.prototype, 'prepend', {
            writable: false,
            value: function () {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
                return prepend.apply(this, arguments)
            }
        })

        function disable() {
                        executeIfLoaded(function () {
                window["yaCounter46196364"].reachGoal('UNLEGAL_PAGE_SHOW', {
                    TrackingId: "0",
                    user_id: 0,
                    origin_url: window.location.href,
                })
            })
        }

        document.createElement = function() {
            var tag = arguments[0].toLowerCase()
            if (['img', 'iframe'].indexOf(tag) !== -1) {
                var stack = new Error().stack;
                if (getIsUserScript(stack)) {
                    disable()
                    return null;
                }
            }
            return createElement.apply(this, arguments);
        }
        window.open = function () {
            var stack = new Error().stack;
            if (getIsUserScript(stack)) return;
            return open.apply(this, arguments);
        }

        window.Image = function() {
            var stack = new Error().stack
            var stackChunks = stack.split('\n').slice(2);
            var lastLine = stackChunks.reverse()[0];
            var url = lastLine.split(' ').reverse()[0]
            var urlChunks = url.substr(1, url.length - 2).split(':')
            var resultUrl = urlChunks[0] + ':' + urlChunks[1]

            if (
                getIsUserScript(stack)
                || lastLine.split(' (eval').length >= 3
                || (lastLine.indexOf(' eval ') && resultUrl === location.href)                 || stackChunks.every(function (chunk) { return chunk.indexOf('a (https://c.amazon-adsystem.com/aax2/apstag.js:') > -1 })
            ) {
                disable()
                return null;
            }
            return new Img(arguments[0], arguments[1])
        }
    })();

All that code is doing is preventing a userscript from making Image objects, adding or creating any elements. It would probably take just a little work to bypass musescore can't do anything about the code running at document-start.

Funny thing is that if they don't want abuse (of certain things) then they should take care of it on the server side not at the client side! Everything on the client side is abusable and/or changeable.

For example this is code on the client side is also easy to circumvent.

Remzi1993 avatar Dec 16 '21 21:12 Remzi1993

I don't have too much time too look into the code, but I was working on some advanced ad-blocking extensions in the past, so I have experience with circumventing things. Literally any client-side script can be abused by an extension. That's guaranteed by the very fundamental concepts of how EcmaScript works.

In general, what you have to do is to:

  • Make sure you run the script in the document_start handler in the manifest file
  • Disable CSP (content security policy) in the background page (you need extraHeaders options IIRC)
  • Dispatch an inline event from the content script to work in the webpage's realm window (and to be able to use eval)
  • In the inline event, proxify all relevant global constructors and their prototypes (via window.Proxy)
  • Make sure you also proxify toString and Symbol.toPrimitive of each proxified object's prototype, so that the webpage's script cannot detect any difference
  • Define non-configurable getter-only properties of the global object, so that you can override any webpage's global variables
  • Don't forget to proxify createElement of the Document.prototype, so that if the webpage creates an inline iframe, you can inject your script in the iframe too
  • Proxify ServiceWorker, Navigator.serviceWorker and ServiceWorkerRegistration, so that you can inject your script in the worker script too
  • Also, it is always good to proxify addEventListener of EventTarget.prototype, just in case
  • If the webpage is using an external script which executes an IIFE and you can't access the local scope of it, you can always use redircection in the background script to redirect the request to that script to some local extension script (use getUrl to obtain adhoc url for you local script)
  • Override attachShadow of Element.prototype, so that you can traverse the shadow subtree before it is appended to the document, if needed
  • Override XMLHttpRequest and fetch, of course

user7230724 avatar Dec 19 '21 07:12 user7230724

Please note that the new repo is hosted at: https://github.com/LibreScore/dl-librescore

PeterNjeim avatar May 12 '22 19:05 PeterNjeim