kfahy / slack-disable-wysiwyg-bookmarklet

Disables the WYSIWYG editor in Slack.
MIT License
824 stars 23 forks source link

Add userscript #13

Open Exagone313 opened 4 years ago

Exagone313 commented 4 years ago

Hi,

I worked for an hour to try to make it work in a userscript, but I can't make it work (in GreaseMonkey on Firefox), the redux.dispatch function call doesn't return and I can't find an error anywhere.

Here is my code if someone finds how to make it work:

// ==UserScript==
// @name     disable WYSIWYG editor
// @version  1
// @grant    none
// @include  https://app.slack.com/client/*
// @run-at   document-idle
// ==/UserScript==

(() => {
  const interval = setInterval(() => {
    if (unsafeWindow.slackDebug !== undefined) {
      clearInterval(interval)
      const slackDebug = unsafeWindow.slackDebug
      const redux = slackDebug[slackDebug.activeTeamId].redux
      const {wysiwyg_composer, wysiwyg_composer_ios, wysiwyg_composer_webapp, ...payload} = redux.getState().experiments
      console.error({slackDebug, redux, payload})
      const result = redux.dispatch({type: '[19] Bulk add experiment assignments to redux', payload})
      console.error({result}) // not firing
    }
  }, 300)
})()

I'd be happy to make a PR in that case.

kfahy commented 4 years ago

Oh nice! I saw many comments suggesting that this would be more suitable as a GreaseMonkey script, so thanks for working on this!

Your code looks good to me, so I'm confused. One thought is that dispatch is throwing an exception, perhaps. It'll definitely throw if type isn't present on the action, but you have one here, so I'm not sure what's going on. If you wrap the dispatch call in a try-catch, can you log the error?

Exagone313 commented 4 years ago

I didn't think about that, in fact I saw the error message somewhere already, without thinking it was linked to. Error: "Permission denied to access property "isThunkCreator""

kfahy commented 4 years ago

Oh interesting. I'm thinking that isThunkCreator is a Slack construct - here's a reference of this name in their (minified) code:

if (n.isThunkCreator || n.isActionCreator) {
    if (d) {
        const e = n.isThunkCreator ? "thunk" : "action"
            , t = n.meta ? n.meta.name : `${e}Creator`;
        Object(i.c)(`\n\tIt looks like you dispatched a ${e} creator instead of the ${e} itself!\n\tThis is a common mistake, and the solution is to call dispatch(${t}(payload)) instead of just dispatch(${t}), note the extra parens at the end.\n\t\t\t\t`)
    }
    return null
}

However, I'm guessing that the "Permission denied" part is related to GreaseMonkey. I don't have any familiarity here, but is there any additional step necessary to enable some sort of privileges for GreaseMonkey scripts?

Exagone313 commented 4 years ago

That's my guess too, apparently with @grant none I should be working with the true window object with unsafeWindow.

Exagone313 commented 4 years ago

It seems weird though, because the type of unsafeWindow is Sandbox when logging it. I'm not sure why using bind(unsafeWindow) on a function would make this.slackDebug undefined, this would mean there is some protection over this.

Too bad unsafeWindow.eval() can't be used due to CSP.

I'm out of ideas.

devsnek commented 4 years ago

I don't know much about greasemonkey but in tampermonkey using window directly normally works, perhaps the same is true of greasemonkey?

Exagone313 commented 4 years ago

Unfortunately, it doesn't.

Exagone313 commented 4 years ago

I think this can't be solved due to the different security measures (sandboxing and CSP) - at least on my platform - to prevent privilege escalation of website code into webextensions. Not even sure webextensions could bypass these. If it works in Chromium with TamperMonkey (untested - note that TamperMonkey is proprietary), it could also break in the future since all browsers are getting these kind of protections.

brainiac744 commented 4 years ago

I haven't tested this for this case - but I have some other greasemonkey scripts that interact with javascript on the page - and I had to update them a while back when the security model changed. To fix the problem then, I just wrapped the code that I had before in a window.eval('') - that same tactic may work here?