Giter Site home page Giter Site logo

mems / bookmarklets-context-menu Goto Github PK

View Code? Open in Web Editor NEW
81.0 8.0 6.0 371 KB

WebExtension allow to execute bookmarklets as privileged scripts

License: MIT License

JavaScript 75.59% Makefile 1.24% HTML 23.17%
webextension bookmarklets csp contextmenu bookmarks

bookmarklets-context-menu's Introduction

Firefox capture of Bookmarklets context menu: Context menu opened with a folder and a bookmarklet "Copy page as Markdown link"

This extension is available for Firefox (via AMO)

Why use Bookmarklets context menu

Current browsers' implementations of bookmarklets are broken: bookmarklet are executed as author's script, but should be executed as user's scripts (with higher pivileges).

To circumvent this restrictions, the extension Bookmarklets context menu create a context menu with all bookmarklets available from user's bookmarks and executed it on demand as content script. This allow access to a secured isolated environement, with higher privileges than author's scripts (allow to copy to clipboard without require user intialized event, cross domain fetch).

If the page block the context menu, you can use the browser action of context menu:

Firefox capture of Bookmarklets context menu: Browser action highlighted

Why current browsers' implementations of bookmarklets are broken?

consider users over authors over implementors over specifiers over theoretical purity.

HTML Design Principles

With current implementation, bookmarklet usage is restricted because bookmarklets are not executed as privileged scripts, but as author's script. That means bookmarklet are subject to security measures like CSP and CORS which make it difficulte to use or impossible in some cases.

This no more the cas with Chrome and Firefox (see bug 1267027, Intent to implement, bug 1406278, bug 1478037), but CSP still applied on subressources

See also Wiki pages

Limitations of this extension

This doesn't fix broken implementations. It's just an alternative.

Permissions required by the extension

The following permissions are used by the extension:

  • bookmarks: read the bookmark tree to get all bookmarklets
  • contextMenus: create context menus based on bookmarklets founded in bookmarks
  • activeTab: execute bookmarklet script in the active tab
  • clipboardWrite and clipboardRead: allow to use document.execCommand('cut'/'copy'/'paste') in bookmarklets
  • storage: store some preferences like "flat context menu"
  • <all_urls>: allow bookmarklets to perform fetch() or XMLHttpRequest without crossdomain limitations

How to write a bookmarklet

It's not recommended to use external resources. External resources are affected by CSP.

If the result of the bookmarklet is other than undefined (void 0), it will be used as HTML source of a new document opened in the same tab: javascript:"<span style='text-decoration:underline'>Underlined text</span>"

An example of a bookmarklet that copy the document's title (document.title):

javascript:(s=>{let%20d=document,l=e=>{d.removeEventListener("copy",l);e.preventDefault();e.clipboardData.setData("text/plain",s);};if(d.activeElement.tagName=="IFRAME"){let%20s=d.createElement("span");s.tabIndex=-1;s.style.position="fixed";d.body.appendChild(s);s.focus();s.remove()}d.addEventListener("copy",l);d.execCommand("copy");a.focus()})(document.title)

An example of a bookmarklet that copy the page as Markdown link:

javascript:{let%20e=document,t=e.URL,a=[e.title].concat(Array.from(e.querySelectorAll("h1,h2")),t).reduce((e,t)=>e||t.textContent&&t.textContent.trim().replace(/\s+/g,"%20")||t.trim(),""),n=(e,t,a="&%23x",n=";")=>e.replace(t,e=>a+e.charCodeAt(0).toString(16).padStart(2,"0")+n),r=n(t,/[()"]/g,"%25",""),l=e.contentType.startsWith("image/"),[,i="Untitled"]=/\/([^/.]+$|[^/]+(?=\.[^.]*$))/g.exec(new%20URL(t).pathname)||[];i+="."+e.contentType.split("/")[1].split("+")[0];let%20c=o=>{let%20p=o.clipboardData,d=p.setData.bind(p);e.removeEventListener("copy",c),o.preventDefault(),p.clearData(),d("text/x-moz-url",t),d("text/uri-list",t),d("text/html",l?`<img%20src="${r}"%20alt="${n(i,/["&<>]/g)}">`:`<a%20href="${r}">${n(a,/[&<>]/g)}</a>`),d("text/plain",l||a!==t?(l?"!":"")+"["+(l?i:a).replace(/[\\<>\[\]]/g,"\\$&")+"]("+r+")":r)};if(["IFRAME","FRAME"].includes(e.activeElement.tagName)){let%20t=e.createElement("span");t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.position="fixed",e.documentElement.appendChild(t),t.focus(),t.remove()}e.addEventListener("copy",c),e.execCommand("copy")}void(0)

If you get the following error Bookmarklet error: SecurityError: The operation is insecure., that means you use document.write(potentiallyUnsafeHTML), when you should use wrappedJSObject.document.write(potentiallyUnsafeHTML) instead. It's related to content script (privilegied) context vs page context.

Note: It's impossible for the extension to catch asynchronous errors (in listener, setTimeout, etc.) even with a global error handler. You must use a try...catch block in your asynchronous functions. Alternatively you can use the add-ons debug mode about:debugging

If you need document.execCommand(), be sure there is no element in / iframe focused:

// execCommand will not been executed if a frame or an iframe is focused
if(["IFRAME","FRAME"].includes(document.activeElement.tagName)){
	let focusable = document.createElement("span");
	focusable.tabIndex = -1;// focusable
	focusable.setAttribute("aria-hidden", "true");// will not be announced by AT
	focusable.style.position = "fixed";
	document.documentElement.appendChild(focusable);// don't use doc.body because in case of frame the body is the frameset and execCommand will not work
	focusable.focus();// force focus, but will not scroll into view, because it have fixed position
	focusable.remove();// remove focus, without force to scroll into view to an other element
}
let listener = event => {
	document.removeEventListener("copy", listener);// one time listener
	// Do whaterver you want. Exemple: in copy event, use event.clipboardData
};
document.addEventListener("copy", listener);
document.execCommand("copy");// will dispatch copy event

See also:

bookmarklets-context-menu's People

Contributors

kafene avatar mems avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bookmarklets-context-menu's Issues

Still blocked by CSP on github

I have a very simple bookmarklet that calls a protocol:

javascript:location.href='org-protocol:/capture?template=l&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)+'&body='+encodeURIComponent(window.getSelection())

When I try to use it on github, I get this error:

Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src https://assets-cdn.github.com”).

If I try to use it with the context menu, I now get this error:

Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src https://assets-cdn.github.com”). Source: call to eval() or related function blocked by CSP.

Is this a bug?

#16 occurs again

Versions: Firefox 65.0.1, Bookmarklets context menu 1.1.5

The bookmarklet shown in #16 (quoted below) doesn't work just in the way shown in the issue.

javascript:location.href='https://web.archive.org/web/*/'+encodeURI(window.location)

The workaround with anomymous function shown in #16 works, too.

Palemoon support

Hello,
can this extension be made to work in Palemoon? I'm not sure what is status of WebExtension in Palemoon, but it would be really useful, especially if CSP get even more prevalent.

Some bookmarklets not shown in list

I am so happy I found this extension! Thank you so much!

It works very well, however, much to my surprise, my own (simple, I thought) bookmarklets are not shown in the list of bookmarklets. I can't see why. All other bookmarklets (it seems) are shown.

For example, the simplest of my bookmarklets opens a popup and offers the title + URL of the page to copy or edit in a textarea:

javascript:
Q=document.selection?document.selection.createRange().text:document.getSelection();
L=location.href;
T=document.title;
D=new%20Date();
W=open('','w'+D.getTime(),'width=600,height=300');
with(W.document){
  write('<html><body%20onLoad=%22document.forms[0].noteit.focus();document.forms[0].noteit.select();%22><center><form>');
  write('<textarea%20name=%22noteit%22%20style=%22width:100%;height:100%;%20overflow:visible%22%20wrap>'+T+'\n'+L+'\n'+'\n\n'+Q+'</textarea>');
  write('</form></center></body></html>');
  void(close());
}

I am on Firefox 57 on Ubuntu 16.04 x64 using Bookmarklets context menu 1.1.4.1.

Edit 2017-11-19 16:06: For reference + copy/paste, my bookmarklets are published at https://fam.tuwien.ac.at/~schamane/sysadmin/bookmarklets.php

How does it work?

How do I add a bookmarklet to the context menu? I can't find any "preferences" screen to add one – the context menu and toolbar items just say "No bookmarklets found," with no option to add any.

Does not work in calendar.google.com

I used to use a great bookmarklet that added events to Google Calendar from any page using the highlighted text.

It stopped working ever since Google enforced that security thing.

I tried this addon to see if it would work again, but it did not.

The script opened a Google Calendar popup but could not enter the highlighted text as the title of event.

here is the bookmarklet:
javascript:%20var%20s;/*Figure%20out%20the%20selected%20text*/if%20(%20window.getSelection%20)%20{s%20=%20window.getSelection();}%20else%20if%20(%20document.getSelection%20)%20{s%20=%20document.getSelection();}%20else%20{s%20=%20document.selection.createRange().text;}/*If%20there%20isn't%20any%20text%20selected,%20get%20user%20input*/if%20(%20s%20==%20''%20)%20{s%20=%20prompt('QuickAdd');}var%20re%20=%20RegExp(%20'[AaPp][Mm]'%20);if%20(%20encodeURIComponent(s).match(re)%20)%20{}%20else%20{var%20d%20=%20new%20Date();var%20hr%20=%20d.getHours();var%20min%20=%20d.getMinutes();if%20(min%20<%2010)%20{min%20=%20"0"%20+%20min;}s%20=%20s%20+%20"%20"%20+%20hr%20+%20":"%20+%20min;%20/*if%20there%20isn't%20an%20AM%20or%20PM%20in%20the%20text,%20add%20the%20default%20current%20time*/}void(/*open%20a%20new%20window%20with%20this%20information%20in%20the%20Google%20Calendar%20event%20creation%20page.*/window.open(encodeURI('http://www.google.com/calendar/event?ctext='+s+'&action=TEMPLATE&pprop=HowCreated:QUICKADD'),'addwindow','status=no,toolbar=no,width=520,height=470,resizable=yes'));

bookmarklet doesn't work correctly

I set up this bookmarklet to open the current page in the Internet Archive:

javascript:location.href='https://web.archive.org/web/*/'+encodeURI(window.location)

It works when clicking the bookmarklet from the bookmarks menu or running in the console, but running it through this addon doesn't. Instead of navigating to the new location, it just replaces the page content with the string https://web.archive.org/web/*/<window location>

EDIT: discovered that it works when wrapping the code in an anonymous function - the following works with the addon:

javascript:(function(){location.href='https://web.archive.org/web/*/'+encodeURI(window.location);})();

Should this be the case? It seems that maybe this addon is parsing the javascript incorrectly?

Allow accessing the bookmarklets with a browser action

Now that I have installed the addon I have a small request, could it be possible to access the bookmarklets with a toolbar button too ?

Maybe having an option to choose between the context menu and the toolbar or both.

For me it will be lot more convenient with my workflow cause usually I put all my bookmarklets in a folders with a shortcut just below my toolbar. 🖥

Regards :octocat:

Not really an issue

I've seen your post on bugzilla and many months ago I've tried to find some way to bypass CSP for userscripts but stopped to search since I had no more time.

But I remember having discussed with others Chrome dev and remember they told me it was possible with chrome, to bypass CSP.

Look here http://tinyurl.com/glgb3b9 at the first page of the search results, there is some interesting links and one Chrome addon that claim to work but I have no time to devote now to CSP but maybe in few weeks/months. 🐒

In meantime I will follow your progress ! :octocat:

Regards !

Icon hard to see in dark mode.

orange

This extension has kept me from going insane more times than I care to admit - thanks so much for making it available. It is the best and it should have the best icon to match.

Question about CSP and Mixed content for bookmarklets.

Could you tell me if Bookmarklet used through this addon are supposed to work if some JS ressource is on an HTTP (non secured) server ?

I don't remember if the addon is supposed to give this privilege ?

If not do you know of any other addon that can bypass the CSP and "Mixed content" only for my bookmarklet to stay secure ?

N.B.: In the past I used this addon https://addons.mozilla.org/en-US/firefox/addon/toggle-mixed-active-content/reviews/ but with Firefox 57 it will not work anymore sadly.

Regards :octocat:

Possible to work with this kind of bookmarklet code?

javascript:void((function(d){if(self!=top||d.getElementById('toolbar')&&d.getElementById('toolbar').getAttribute('data-resizer'))return%20false;d.write('<!DOCTYPE%20HTML><html%20style="opacity:0;"><head><meta%20charset="utf-8"/></head><body><a%20data-viewport="320x480"%20data-icon="mobile">Mobile%20(e.g.%20Apple%20iPhone)</a><a%20data-viewport="320x568"%20data-icon="mobile"%20data-version="5">Apple%20iPhone%205</a><a%20data-viewport="375%C3%97667"%20data-icon="mobile"%20data-version="7">Apple%20iPhone%207</a><a%20data-viewport="414%C3%97736"%20data-icon="mobile"%20data-version="7+">Apple%20iPhone%207%20Plus</a><a%20data-viewport="600x800"%20data-icon="small-tablet">Small%20Tablet</a><a%20data-viewport="768x1024"%20data-icon="tablet">Tablet%20(e.g.%20Apple%20iPad%202-3rd,%20mini)</a><a%20data-viewport="1280x800"%20data-icon="notebook">Widescreen</a><a%20data-viewport="1920%C3%971080"%20data-icon="tv">HDTV%201080p</a><script%20src="https://lab.maltewassermann.com/viewport-resizer/resizer.min.js"></script></body></html>')})(document));

This kind of code for the bookmarklet doesn't seem to run: it triggers a 'bookmarklet execution' promise has been rejected: Error: The operation is insecure.

Bookmarklet source: https://lab.maltewassermann.com/viewport-resizer/

Any way to get this kind of code to run?

Optional Cache?

I have 27k bookmarks!
'B-C-M' I assume reads them all at startup (Ff hogs cpu for a couple of minutes).
Would it be possible to provide a cache option to avoid re-scans (with a Refresh/Update button for new BMklets) ?
Or ... a way of accessing just BMklets ?

Big Bug !

Hi,

You uploaded the wrong package on AMO and when you try to install it it say " the add on could not be installed because it appears to be corrupt "

I found the cause, It's caused because a faulty structure of the XPI file: http://i.imgur.com/7YQr8tJ.png

Regards !

:octocat:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.