Added Idempotency-Key header and fixed an bug allowing xss in display name

This commit is contained in:
nipos 2018-05-06 16:08:50 +02:00
parent ab0bd55cbc
commit fff7a7d50c
5 changed files with 64 additions and 29 deletions

View File

@ -10,16 +10,17 @@ Follow or Mastodon account and never miss an important update: [@halcyon@social.
## Instances ## Instances
These instances are publicly accessible and usable by everyone, no matter which Mastodon instance you use. These instances are publicly accessible and usable by everyone, no matter which Mastodon instance you use.
- https://halcyon.toromino.de - 1.1.4 - https://halcyon.toromino.de - 1.1.5
- https://halcyon.bka.li - 1.1.4 - https://social.dev-wiki.de - 1.1.5
- https://halcyon.bka.li - 1.1.5
- https://itter.photog.social - 1.1.4
- https://halcyon.tilde.team - 1.1.3 - https://halcyon.tilde.team - 1.1.3
- https://itter.photog.social - 1.1.3
- https://social.dev-wiki.de - 1.1.1
- https://halcyon.cybre.space - Outdated - https://halcyon.cybre.space - Outdated
You have your own Halcyon instance and want it to be listed here? Create an issue with the link and we will add it to the list. You have your own Halcyon instance and want it to be listed here? Create an issue with the link and we will add it to the list.
## Blog ## Blog
- Release of Version 1.1.5 - Introduced the new Idempotency-Key Header and fixed an bug allowing XSS with the display name
- Release of Version 1.1.4 - Automatically reconnect on bad connection,now supports desktop notifications,added ... at the end of shortened links - Release of Version 1.1.4 - Automatically reconnect on bad connection,now supports desktop notifications,added ... at the end of shortened links
- Release of Version 1.1.3 - New function link previews introduced and bug when replying an toot which already has replies below it fixed (reply to undefined) - Release of Version 1.1.3 - New function link previews introduced and bug when replying an toot which already has replies below it fixed (reply to undefined)
- Release of Version 1.1.2 - Privacy modes are now correctly displayed and used for replies,use username if display name doesn't exist,bugs on search page fixed - Release of Version 1.1.2 - Privacy modes are now correctly displayed and used for replies,use username if display name doesn't exist,bugs on search page fixed

View File

@ -147,6 +147,24 @@ const datetime ="・" + calendar[posted_time_original.getMonth()] + " " + posted
return datetime; return datetime;
} }
} }
function htmlEscape(strings, ...values) {
var handleString = function(str) {
return str.replace(/&/g, '&')
.replace(/>/g, '>')
.replace(/</g, '&lt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
.replace(/`/g, '&#096;');
};
var res = '';
for(var i=0, l=strings.length; i<l; i+=1) {
res += handleString(strings[i]);
if(i < values.length) {
res += handleString(values[i]);
}
}
return res;
}
function resetApp() { function resetApp() {
current_id = Number(localStorage.getItem("current_id")); current_id = Number(localStorage.getItem("current_id"));
current_instance = localStorage.getItem("current_instance"); current_instance = localStorage.getItem("current_instance");
@ -285,3 +303,9 @@ icon: '/assets/images/halcyon_logo.png'
} }
} }
} }
function getRandom() {
var s4 = function() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

View File

@ -279,7 +279,7 @@ const html=(`
<div class="text_ellipsis"> <div class="text_ellipsis">
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.account.display_name} ${htmlEscape(status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.account.acct} @${status.account.acct}
@ -313,7 +313,7 @@ ${media_views}
</article> </article>
<footer class="toot_footer"${toot_footer_width}> <footer class="toot_footer"${toot_footer_width}>
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${status.account.display_name}" privacy="${status.visibility}"> <button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${htmlEscape(status.account.display_name)}" privacy="${status.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -384,7 +384,7 @@ const html = (`
<li sid="${status.id}" class="toot_entry"> <li sid="${status.id}" class="toot_entry">
<div class="boost_author_box"> <div class="boost_author_box">
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${status.account.display_name} Boosted</span> <span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${htmlEscape(status.account.display_name)} Boosted</span>
</a> </a>
</div> </div>
<div class="toot_entry_body"> <div class="toot_entry_body">
@ -398,7 +398,7 @@ const html = (`
<div class="text_ellipsis"> <div class="text_ellipsis">
<a href="${status_reblog_account_link}"> <a href="${status_reblog_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.reblog.account.display_name} ${htmlEscape(status.reblog.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.reblog.account.acct} @${status.reblog.account.acct}
@ -432,7 +432,7 @@ ${media_views}
</article> </article>
<footer class="toot_footer" style="width:320px"> <footer class="toot_footer" style="width:320px">
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.reblog.id}"acct="@${status.reblog.account.acct}" display_name="${status.reblog.account.display_name}" privacy="${status.reblog.visibility}"> <button class="reply_button" tid="${status.reblog.id}"acct="@${status.reblog.account.acct}" display_name="${htmlEscape(status.reblog.account.display_name)}" privacy="${status.reblog.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -484,7 +484,7 @@ const html = (`
</a> </a>
<i class="fa fa-fw fa-star font-icon favourite"></i> <i class="fa fa-fw fa-star font-icon favourite"></i>
<a class="notice_author" href="${notice_author_link}"> <a class="notice_author" href="${notice_author_link}">
<span class="emoji_poss" >${NotificationObj.account.display_name}</span> favourited Your Toot <span class="emoji_poss" >${htmlEscape(NotificationObj.account.display_name)}</span> favourited Your Toot
</a> </a>
</div> </div>
<div class="notice_entry_body"> <div class="notice_entry_body">
@ -493,7 +493,7 @@ const html = (`
<div class="text_ellipsis"> <div class="text_ellipsis">
<a href="${toot_author_link}"> <a href="${toot_author_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${NotificationObj.status.account.display_name} ${htmlEscape(NotificationObj.status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${NotificationObj.status.account.acct} @${NotificationObj.status.account.acct}
@ -524,7 +524,7 @@ html = (`
</a> </a>
<i class="fa fa-fw fa-retweet font-icon boost"></i> <i class="fa fa-fw fa-retweet font-icon boost"></i>
<a class="notice_author" href="${notice_author_link}"> <a class="notice_author" href="${notice_author_link}">
<span class="emoji_poss" >${NotificationObj.account.display_name}</span> boosted Your Toot <span class="emoji_poss" >${htmlEscape(NotificationObj.account.display_name)}</span> boosted Your Toot
</a> </a>
</div> </div>
<blockquote class="notice_entry_body"> <blockquote class="notice_entry_body">
@ -533,7 +533,7 @@ html = (`
<div class="text_ellipsis"> <div class="text_ellipsis">
<a href="${toot_author_link}"> <a href="${toot_author_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${NotificationObj.status.account.display_name} ${htmlEscape(NotificationObj.status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${NotificationObj.status.account.acct} @${NotificationObj.status.account.acct}
@ -610,7 +610,7 @@ const html=(`
<div class="text_ellipsis"> <div class="text_ellipsis">
<a href="${toot_author_link}"> <a href="${toot_author_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${NotificationObj.status.account.display_name} ${htmlEscape(NotificationObj.status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${NotificationObj.status.account.acct} @${NotificationObj.status.account.acct}
@ -644,7 +644,7 @@ ${media_views}
</article> </article>
<footer class="toot_footer"${toot_footer_width}> <footer class="toot_footer"${toot_footer_width}>
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${NotificationObj.status.id}" acct="@${NotificationObj.account.acct}" display_name="${NotificationObj.account.display_name}" privacy="${NotificationObj.status.visibility}"> <button class="reply_button" tid="${NotificationObj.status.id}" acct="@${NotificationObj.account.acct}" display_name="${htmlEscape(NotificationObj.account.display_name)}" privacy="${NotificationObj.status.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -677,7 +677,7 @@ const html=(`
</a> </a>
<i class="fa fa-fw fa-user font-icon follow"></i> <i class="fa fa-fw fa-user font-icon follow"></i>
<a class="notice_author" href="${notice_author_link}"> <a class="notice_author" href="${notice_author_link}">
<span class="emoji_poss">${NotificationObj.account.display_name}</span> followed you <span class="emoji_poss">${htmlEscape(NotificationObj.account.display_name)}</span> followed you
</a> </a>
</div> </div>
</li>`); </li>`);
@ -706,7 +706,7 @@ const html = (`
<div class="follows_profile_name_box emoji_poss"> <div class="follows_profile_name_box emoji_poss">
<a class="js_follows_profile_link" href="${profile_link}"> <a class="js_follows_profile_link" href="${profile_link}">
<h2 class="js_follows_profile_displayname"> <h2 class="js_follows_profile_displayname">
${AccountObj.display_name} ${htmlEscape(AccountObj.display_name)}
</h2> </h2>
<span class="js_follows_profile_username"> <span class="js_follows_profile_username">
@${AccountObj.acct} @${AccountObj.acct}
@ -781,7 +781,7 @@ const html=(`
</div> </div>
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.account.display_name} ${htmlEscape(status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.account.acct} @${status.account.acct}
@ -816,7 +816,7 @@ ${media_views}
</section> </section>
<footer class="toot_footer"${toot_footer_width}> <footer class="toot_footer"${toot_footer_width}>
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${status.account.display_name}" privacy="${status.visibility}"> <button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${htmlEscape(status.account.display_name)}" privacy="${status.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -955,7 +955,7 @@ const html=(`
</div> </div>
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.reblog.account.display_name} ${htmlEscape(status.reblog.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.reblog.account.acct} @${status.reblog.account.acct}
@ -990,7 +990,7 @@ ${media_views}
</section> </section>
<footer class="toot_footer" style="width:320px"> <footer class="toot_footer" style="width:320px">
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.reblog.id}" acct="@${status.reblog.account.acct}" display_name="${status.reblog.account.display_name}" privacy="${status.reblog.visibility}"> <button class="reply_button" tid="${status.reblog.id}" acct="@${status.reblog.account.acct}" display_name="${htmlEscape(status.reblog.account.display_name)}" privacy="${status.reblog.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -1171,7 +1171,7 @@ const html=(`
<header class="toot_header"> <header class="toot_header">
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.account.display_name} ${htmlEscape(status.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.account.acct} @${status.account.acct}
@ -1204,7 +1204,7 @@ ${media_views}
</article> </article>
<footer class="toot_footer"${toot_footer_width}> <footer class="toot_footer"${toot_footer_width}>
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${status.account.display_name}" privacy="${status.visibility}"> <button class="reply_button" tid="${status.id}" acct="@${status.account.acct}" display_name="${htmlEscape(status.account.display_name)}" privacy="${status.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>
@ -1266,7 +1266,7 @@ const html=(`
<div sid="${status.id}" class="toot_entry ${class_options}"> <div sid="${status.id}" class="toot_entry ${class_options}">
<div class="boost_author_box"> <div class="boost_author_box">
<a href="${status_account_link}"> <a href="${status_account_link}">
<span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${status.account.display_name} Boosted</span> <span class="emoji_poss"><i class="fa fa-fw fa-retweet"></i>${htmlEscape(status.account.display_name)} Boosted</span>
</a> </a>
</div> </div>
<div class="toot_entry_body"> <div class="toot_entry_body">
@ -1277,7 +1277,7 @@ const html=(`
<header class="toot_header"> <header class="toot_header">
<a href="${status_reblog_account_link}"> <a href="${status_reblog_account_link}">
<span class="displayname emoji_poss"> <span class="displayname emoji_poss">
${status.reblog.account.display_name} ${htmlEscape(status.reblog.account.display_name)}
</span> </span>
<span class="username"> <span class="username">
@${status.reblog.account.acct} @${status.reblog.account.acct}
@ -1310,7 +1310,7 @@ ${media_views}
</article> </article>
<footer class="toot_footer" style="width:320px"> <footer class="toot_footer" style="width:320px">
<div class="toot_reaction"> <div class="toot_reaction">
<button class="reply_button" tid="${status.reblog.id}" acct="@${status.reblog.account.acct}" display_name="${status.reblog.account.display_name}" privacy="${status.reblog.visibility}"> <button class="reply_button" tid="${status.reblog.id}" acct="@${status.reblog.account.acct}" display_name="${htmlEscape(status.reblog.account.display_name)}" privacy="${status.reblog.visibility}">
<i class="fa fa-fw fa-reply"></i> <i class="fa fa-fw fa-reply"></i>
<span class="reaction_count reply_count"></span> <span class="reaction_count reply_count"></span>
</button> </button>

View File

@ -150,11 +150,21 @@ callback = arguments[1];
postData = arguments[1]; postData = arguments[1];
callback = arguments[2]; callback = arguments[2];
} }
var requestHeaders = {"Authorization":"Bearer "+config.api_user_token};
if(endpoint == "statuses") {
if(arguments.length == 4) {
var idempotencykey = arguments[3];
}
else {
var idempotencykey = getRandom();
}
requestHeaders["Idempotency-Key"] = idempotencykey;
}
$.ajax({ $.ajax({
url: apiBase + endpoint, url: apiBase + endpoint,
type: "POST", type: "POST",
data: postData, data: postData,
headers: {"Authorization": "Bearer " + config.api_user_token}, headers: requestHeaders,
success: function(data, textStatus) { success: function(data, textStatus) {
if(endpoint == "statuses") { if(endpoint == "statuses") {
$(".js_current_toots_count").html(++localStorage.current_statuses_count); $(".js_current_toots_count").html(++localStorage.current_statuses_count);
@ -170,7 +180,7 @@ callback(data,textStatus)
}, },
error: function(xhr, textStatus, errorThrown) { error: function(xhr, textStatus, errorThrown) {
if(xhr.readyState == 0) { if(xhr.readyState == 0) {
api.post(endpoint,postData,callback); api.post(endpoint,postData,callback,idempotencykey);
} }
else { else {
putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`); putMessage(`[${xhr.status}] ${xhr.responseJSON['error']}`);

View File

@ -1 +1 @@
1.1.4 1.1.5