Skip to content

Commit

Permalink
Fix redirecting already-registered users from iframe dialog
Browse files Browse the repository at this point in the history
One thing missing from rauchg#126/rauchg#143, which intro'd the feature of
redirecting already-signed-up users to Slack, was support for the iframe
dialog that the "Realtime Badge" button thing pops up:
https://github.com/rauchg/slackin#realtime-badge

In simpler times this would've been a 4-character fix:

-        location.href = res.body.redirectUrl;
+        top.location.href = res.body.redirectUrl;

But nowadays people have futile "policies" trying to be "secure" about
their "content" and "sand" "box" "our" "i" "frames"---bottom line is,
top.location.href doesn't pass muster anymore for a library that's going
to run in arbitrary pages on arbitrary servers. Enter the postMessage()
RPC hack.
  • Loading branch information
laughinghan committed Feb 27, 2016
1 parent e3d3194 commit c775538
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
7 changes: 7 additions & 0 deletions lib/assets/badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@
// ensure it's shown (since first time hidden)
iframe.style.visibility = 'visible';
}

// redirect to URL
var redir = 'slackin-redirect:' + id + ':';
if (redir === e.data.substr(0, redir.length)) {
location.href = e.data.substr(redir.length);
}
});
}

Expand Down Expand Up @@ -115,6 +121,7 @@
ni.style.borderWidth = 0;
ni.src = iframe.src.replace(/\?.*/, '') + '/dialog';
ni.onload = function(){
setup(ni);
window.addEventListener('scroll', dposition);
window.addEventListener('resize', dposition);
position();
Expand Down
33 changes: 32 additions & 1 deletion lib/assets/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function invite(channel, coc, email, fn){
if (res.body.redirectUrl) {
var err = new Error(res.body.msg || 'Server error');
window.setTimeout(function() {
location.href = res.body.redirectUrl;
topLevelRedirect(res.body.redirectUrl);
}, 1500);
}
if (res.error) {
Expand Down Expand Up @@ -83,3 +83,34 @@ function anim(el, c){
el.anim = null;
}, 150);
}


// redirect, using "RPC" to parent if necessary
function topLevelRedirect(url) {
if (window === top) location.href = url;
else parent.postMessage('slackin-redirect:' + id + ':' + url, '*');
// Q: Why can't we just `top.location.href = url;`?
// A: Ah, the halcyon days, when scripts in iframes could just arbitrarily
// fuck with parent windows' globals. I'm afraid that in this day and
// age of [sandboxes][] and [Content Security Policies][CSP], it's all
// too common for meddling idiots to try to stop us from doing whatever
// we please with their globals---how dare they trample on our rights.
// I mean we're still allowed to do almost anything to their globals,
// the only global we're not allowed to change now is the location URL
// (seriously). I momentarily hoped that explicit permission from the
// parent of the iframe could ensure this privilege that we deserve of
// redirecting the parent, but [nope][].
//
// [sandboxing]: http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
// [CSP]: http://www.html5rocks.com/en/tutorials/security/content-security-policy/
// [nope]: http://output.jsbin.com/popawuk/16
};

// "RPC" channel to parent
var id;
window.addEventListener('message', function onmsg(e){
if (/^slackin:/.test(e.data)) {
id = e.data.replace(/^slackin:/, '');
window.removeEventListener('message', onmsg);
}
});

0 comments on commit c775538

Please sign in to comment.