handle cross-origin cookies with a custom header X-Set-Cookie, fix #24
Cookies set from a different domain can not be read by JS executed in the current domain. As a workaround, Isso sends both a Set-Cookie and X-Set-Cookie header. The former is used by the browser to make the HTTP request to the API, the latter is read by `embed.min.js` to determine if a comment can be edited or deleted. When a comment is deleted, the server sends an expired cookies in Set-Cookie and X-Set-Cookie.
This commit is contained in:
parent
05c8b571e2
commit
6691810316
@ -76,6 +76,11 @@ define(["q"], function(Q) {
|
||||
function onload() {
|
||||
|
||||
var rule = url.replace(endpoint, "").split("?", 1)[0];
|
||||
var cookie = xhr.getResponseHeader("X-Set-Cookie");
|
||||
|
||||
if (cookie && cookie.match(/^isso-/)) {
|
||||
document.cookie = cookie;
|
||||
}
|
||||
|
||||
if (rule in rules && rules[rule].indexOf(xhr.status) === -1) {
|
||||
response.reject(xhr.responseText);
|
||||
|
@ -241,7 +241,7 @@ define(["app/text/html", "app/dom", "app/utils", "app/api", "app/markup", "app/i
|
||||
|
||||
// remove edit and delete buttons when cookie is gone
|
||||
var clear = function(button) {
|
||||
if (! utils.cookie(comment.id)) {
|
||||
if (! utils.cookie("isso-" + comment.id)) {
|
||||
$(button, footer).remove();
|
||||
} else {
|
||||
setTimeout(function() { clear(button); }, 15*1000);
|
||||
@ -253,14 +253,14 @@ define(["app/text/html", "app/dom", "app/utils", "app/api", "app/markup", "app/i
|
||||
|
||||
// show direct reply to own comment when cookie is max aged
|
||||
var show = function(el) {
|
||||
if (utils.cookie(comment.id)) {
|
||||
if (utils.cookie("isso-" + comment.id)) {
|
||||
setTimeout(function() { show(el); }, 15*1000);
|
||||
} else {
|
||||
footer.append(el);
|
||||
}
|
||||
};
|
||||
|
||||
if (utils.cookie(comment.id)) {
|
||||
if (utils.cookie("isso-" + comment.id)) {
|
||||
show($("a.reply", footer).detach());
|
||||
}
|
||||
};
|
||||
|
@ -5,10 +5,11 @@ import json
|
||||
import time
|
||||
import hashlib
|
||||
import logging
|
||||
import sqlite3
|
||||
import functools
|
||||
|
||||
from itsdangerous import SignatureExpired, BadSignature
|
||||
|
||||
from werkzeug.http import dump_cookie
|
||||
from werkzeug.wrappers import Response
|
||||
from werkzeug.exceptions import BadRequest, Forbidden, NotFound
|
||||
|
||||
@ -118,9 +119,13 @@ def new(app, environ, request, uri):
|
||||
# success!
|
||||
logger.info('comment created: %s', json.dumps(rv))
|
||||
|
||||
resp = Response(json.dumps(rv), 202 if rv["mode"] == 2 else 201,
|
||||
content_type='application/json')
|
||||
resp.set_cookie(str(rv["id"]), app.sign([rv["id"], checksum]), max_age=app.conf.getint('general', 'max-age'))
|
||||
cookie = functools.partial(dump_cookie,
|
||||
value=app.sign([rv["id"], checksum]),
|
||||
max_age=app.conf.getint('general', 'max-age'))
|
||||
|
||||
resp = Response(json.dumps(rv), 202 if rv["mode"] == 2 else 201, content_type='application/json')
|
||||
resp.headers.add("Set-Cookie", cookie(str(rv["id"])))
|
||||
resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"]))
|
||||
return resp
|
||||
|
||||
|
||||
@ -176,8 +181,13 @@ def single(app, environ, request, id):
|
||||
checksum = hashlib.md5(rv["text"].encode('utf-8')).hexdigest()
|
||||
rv["text"] = app.markdown(rv["text"])
|
||||
|
||||
cookie = functools.partial(dump_cookie,
|
||||
value=app.sign([rv["id"], checksum]),
|
||||
max_age=app.conf.getint('general', 'max-age'))
|
||||
|
||||
resp = Response(json.dumps(rv), 200, content_type='application/json')
|
||||
resp.set_cookie(str(rv["id"]), app.sign([rv["id"], checksum]), max_age=app.conf.getint('general', 'max-age'))
|
||||
resp.headers.add("Set-Cookie", cookie(str(rv["id"])))
|
||||
resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"]))
|
||||
return resp
|
||||
|
||||
if request.method == 'DELETE':
|
||||
@ -192,8 +202,11 @@ def single(app, environ, request, id):
|
||||
|
||||
logger.info('comment %i deleted', id)
|
||||
|
||||
cookie = functools.partial(dump_cookie, expires=0, max_age=0)
|
||||
|
||||
resp = Response(json.dumps(rv), 200, content_type='application/json')
|
||||
resp.delete_cookie(str(id), path='/')
|
||||
resp.headers.add("Set-Cookie", cookie(str(id)))
|
||||
resp.headers.add("X-Set-Cookie", cookie("isso-%i" % id))
|
||||
return resp
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ class CORSMiddleWare(object):
|
||||
headers.append(("Access-Control-Allow-Headers", "Origin, Content-Type"))
|
||||
headers.append(("Access-Control-Allow-Credentials", "true"))
|
||||
headers.append(("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"))
|
||||
headers.append(("Access-Control-Expose-Headers", "X-Set-Cookie"))
|
||||
return start_response(status, headers, exc_info)
|
||||
|
||||
if environ.get("REQUEST_METHOD") == "OPTIONS":
|
||||
|
Loading…
Reference in New Issue
Block a user