Pass an extra auth= arg to the data url if we have one.
If we do, it'll be in localStorage[['auth', urlhost]].
You can set it by calling the /setauth URL, which happens to work as a
GoogleAPI-oauth2-compatible callback (but can be used for any API you want
as long as it provides the right query parameters).
diff --git a/app.yaml b/app.yaml
index aeb616e..ef69491 100644
--- a/app.yaml
+++ b/app.yaml
@@ -11,6 +11,9 @@
- url: /edit
static_files: edit.html
upload: edit.html
+- url: /(setauth|oauth2callback)
+ static_files: setauth.html
+ upload: setauth.html
- url: /help
static_files: help.html
upload: help.html
diff --git a/render.js b/render.js
index b0e9fc5..0defc6d 100644
--- a/render.js
+++ b/render.js
@@ -2,7 +2,7 @@
var afterquery = (function() {
// To appease v8shell
- var console;
+ var console, localStorage;
try {
console = window.console;
}
@@ -11,6 +11,11 @@
debug: print
};
}
+ try {
+ localStorage = window.localStorage;
+ } catch (ReferenceError) {
+ localStorage = {}
+ }
// For konqueror compatibility
if (!console) {
@@ -1079,9 +1084,28 @@
}
+ var URL_RE = RegExp("^((\\w+:)?(//[^/]*)?)");
+
+
+ function urlMinusPath(url) {
+ var g = URL_RE.exec(url);
+ if (g && g[1]) {
+ return g[1];
+ } else {
+ return url;
+ }
+ }
+
+
function getUrlData(url, success_func, error_func) {
// some services expect callback=, some expect jsonp=, so supply both
var plus = 'callback=jsonp&jsonp=jsonp';
+ var hostpart = urlMinusPath(url);
+ var auth = localStorage[['auth', hostpart]];
+ if (auth) {
+ plus += '&auth=' + encodeURIComponent(auth);
+ }
+
var nurl;
if (url.indexOf('?') >= 0) {
nurl = url + '&' + plus;
@@ -1109,14 +1133,16 @@
error(null, message + ' url=' + xurl + ' line=' + lineno);
};
- iframe.contentWindow.loaded = function() {
- alert('loaded');
- };
-
- iframe.contentDocument.write(
- '<script async onerror="loaded" onload="loaded" src="' +
- encodeURI(nurl) +
- '"></script>');
+ //TODO(apenwarr): change the domain/origin attribute of the iframe.
+ // That way the script won't be able to affect us, no matter how badly
+ // behaved it might be. That's important so they can't access our
+ // localStorage, set cookies, etc. We can use the new html5 postMessage
+ // feature to safely send json data from the iframe back to us.
+ // ...but for the moment we have to trust the data provider.
+ var script = document.createElement('script');
+ script.async = 1;
+ script.src = nurl;
+ iframe.contentDocument.body.appendChild(script);
}
@@ -1147,6 +1173,7 @@
orderBy: orderBy,
extractRegexp: extractRegexp,
fillNullsWithZero: fillNullsWithZero,
+ urlMinusPath: urlMinusPath,
gridFromData: gridFromData
},
render: wrap(_run)
diff --git a/setauth.html b/setauth.html
new file mode 100644
index 0000000..e6d5737
--- /dev/null
+++ b/setauth.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html>
+<body>
+
+<script src="render.js"></script>
+<script>
+
+var args = afterquery.internal.parseArgs(
+ (window.location.search || '?') + '&' + window.location.hash.substr(1));
+
+var token = args.get('access_token') || args.get('auth');
+var url = args.get('state') || args.get('url');
+var hostpart = url ? afterquery.internal.urlMinusPath(url) : null;
+
+if (token && hostpart) {
+ localStorage[['auth', hostpart]] = token;
+}
+
+</script>
+
+</body>
+</html>
diff --git a/t/trender.js b/t/trender.js
index 40a8ead..f8cc05d 100644
--- a/t/trender.js
+++ b/t/trender.js
@@ -113,3 +113,17 @@
WVPASSEQ(guessTypes(data2.concat(datanull)),
['date', 'datetime', 'number', 'string', 'boolean', 'boolean']);
});
+
+
+wvtest('urlMinusPath', function() {
+ WVPASSEQ(afterquery.internal.urlMinusPath('http://x/y/z'),
+ 'http://x');
+ WVPASSEQ(afterquery.internal.urlMinusPath('https://u:p@host:port/y/z'),
+ 'https://u:p@host:port');
+ WVPASSEQ(afterquery.internal.urlMinusPath('http:foo/blah//whatever'),
+ 'http:');
+ WVPASSEQ(afterquery.internal.urlMinusPath('foo/blah//whatever'),
+ 'foo/blah//whatever');
+ WVPASSEQ(afterquery.internal.urlMinusPath('//foo/blah//whatever'),
+ '//foo');
+});