diff --git a/files/assets/js/changelog.js b/files/assets/js/changelog.js index a07e66592..b6dd7e798 100644 --- a/files/assets/js/changelog.js +++ b/files/assets/js/changelog.js @@ -2,6 +2,7 @@ function post_toast2(url, button1, button2) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); var form = new FormData() + form.append("formkey", formkey()); if(typeof data === 'object' && data !== null) { for(let k of Object.keys(data)) { diff --git a/files/assets/js/comments_v.js b/files/assets/js/comments_v.js index 20e679569..d841aca88 100644 --- a/files/assets/js/comments_v.js +++ b/files/assets/js/comments_v.js @@ -11,6 +11,7 @@ function post_toast3(url, button1, button2) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); var form = new FormData() + form.append("formkey", formkey()); if(typeof data === 'object' && data !== null) { for(let k of Object.keys(data)) { diff --git a/files/assets/js/default.js b/files/assets/js/default.js index 14fdbff2c..b87db87ea 100644 --- a/files/assets/js/default.js +++ b/files/assets/js/default.js @@ -91,6 +91,7 @@ function post_toast2(url, button1, button2) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); var form = new FormData() + form.append("formkey", formkey()); if(typeof data === 'object' && data !== null) { for(let k of Object.keys(data)) { diff --git a/files/assets/js/header.js b/files/assets/js/header.js index a16f273e7..af8a8d5be 100644 --- a/files/assets/js/header.js +++ b/files/assets/js/header.js @@ -24,6 +24,7 @@ function post_toast(url, reload, data) { var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); var form = new FormData() + form.append("formkey", formkey()); if(typeof data === 'object' && data !== null) { for(let k of Object.keys(data)) { diff --git a/files/assets/js/mirage.js b/files/assets/js/mirage.js new file mode 100644 index 000000000..bc98de22a --- /dev/null +++ b/files/assets/js/mirage.js @@ -0,0 +1 @@ +var mirage=function(t){"use strict";function e(){throw new Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}function r(t){return Object.prototype.toString.call(t)}function n(t){return[].slice.call(t)}function i(){return(new Date).getTime()}function o(t){return null!=t&&"object"==typeof t&&t.nodeType===Node.ELEMENT_NODE&&"object"==typeof t.style&&"object"==typeof t.ownerDocument}function s(t,e){for(var r=0;r=2e3&&e<=50?"slow-2g":t>=1400&&e<=70?"2g":t>=270&&e<=700?"3g":"4g"}function x(t,e,r){var n,i,o,s,a=t.byteLength;if(e=~~e,r=void 0===r?a:~~r,"function"==typeof t.slice)return t.slice(e,r);if(e<0?(e+=a)<0&&(e=0):e>a&&(e=a),r<0?(r+=a)<0&&(r=0):r>a&&(r=a),rx',t.firstChild.href}}(),_t=(Object.freeze||Object)({parseURL:pt,sameOrigin:dt,resolveFullURL:gt});S.prototype.add=function(t){var e;return this.tokens?(this.tokens.add(t),this):(e=this.array(),s(e,t)<0&&e.push(t),this.element.className=e.join(" "),this)},S.prototype.remove=function(t){var e,r;return this.tokens?(this.tokens.remove(t),this):(e=this.array(),(r=s(e,t))>=0?(e.splice(r,1),this.element.className=e.join(" "),this):void 0)},S.prototype.toggle=function(t){return this.tokens?(this.tokens.toggle(t),this):(this.has(t)?this.remove(t):this.add(t),this)},S.prototype.array=function(){var t,e;return t=this.element.className.replace(/^\s+|\s+$/g,""),""===(e=t.split(/\s+/))[0]&&e.shift(),e};var mt=T;S.prototype.has=S.prototype.contains=function(t){return this.tokens?this.tokens.contains(t):!!~s(this.array(),t)};var yt=(Object.freeze||Object)({add:function(t,e){return new S(t).add(e)},remove:E,toggle:function(t,e){new S(t).toggle(e)},has:T,contains:mt,Classes:S}),vt={};vt.log=function(t,e){var r={};r.message=t,r.category=e,vt.history.push(r)};var wt=function(t,e,r){if(it){try{console.log("[ CLOUDFLARE ] "+t)}catch(t){}!1!==r&&vt.log(t,1|e)}},bt=function(t,e,r){if(it){try{console.error("[ CLOUDFLARE ] "+t)}catch(r){wt(t,4|e,!1)}!1!==r&&vt.log(t,4|e)}},St={bandwidth:1/0},Et="mirage_network_connection",Tt="X-Mirage-Server-Time",Ot="X-Mirage-Transfer-Size",At="/cdn-cgi/mirage_speedtest/",It=1.25,Lt=(Object.freeze||Object)({isHighLatency:O,getFakeConnection:A,connectionFromStats:L,calculateEffectiveConnectionType:C}),Ct={};for(var xt in ht)Ct[xt]=ht[xt];var Nt=window.URL||window.webkitURL||window.mozURL,Pt=function(){var t;return window.location.origin?window.location.origin:(t=pt(window.location.toString())).protocol+"://"+t.host+":"+t.port}();return j.DEFAULT_TTL=1728e5,j.STORAGE_KEY="mirage_cache_manifest",j.DEBOUNCE_THRESHOLD=500,j.MAX_LENGTH=100,j.prototype.record=function(t){return this.whenReady_(function(){this.add_(t),this.persist_()})},j.prototype.has=function(t){return this.whenReady_(function(){return this.has_(t)})},j.prototype.indexOf=function(t){return this.whenReady_(function(){return this.indexOf_(this.map_[t])})},j.prototype.clear=function(){return this.whenReady_(function(){try{window.localStorage.removeItem(j.STORAGE_KEY)}catch(t){}this.reset_()})},j.prototype.whenReady_=function(t){return this.queue_=this.queue_.then(R(t,this)),this.queue_},j.prototype.has_=function(t){var e=this.map_[t],r=i();return e&&e+j.DEFAULT_TTLe.value?-1:t.valuet?this.indexOf_(t,i,r):i))},j.prototype.add_=function(t){var e,r=this.sizeMap_[t];r?(e=this.indexOf_(r.value),this.sizeQueue_.splice(e,1)):(r={key:t},this.sizeMap_[t]=r),this.map_[t]=r.value=i()+this.offset_++,this.sizeQueue_.unshift(r),this.sizeQueue_.length>j.MAX_LENGTH&&this.remove_(this.sizeQueue_[this.sizeQueue_.length-1].key)},j.prototype.remove_=function(t){var e=this.sizeMap_[t],r=this.indexOf_(e.value);delete this.map_[t],delete this.sizeMap_[t],-1!==r&&this.sizeQueue_.splice(r,1)},j.prototype.persist_=function(){return this.whenReady_(function(){try{window.localStorage.setItem(j.STORAGE_KEY,JSON.stringify(this.map_))}catch(t){}})},j.prototype.persist_=function(t,e){var r=null;return function(){var n=arguments,i=this;null!==r&&window.clearTimeout(r),r=window.setTimeout(function(){t.apply(i,n)},e)}}(j.prototype.persist_,j.DEBOUNCE_THRESHOLD),M.type={SIGNATURE:[137,80,78,71,13,10,26,10],IHDR:[73,72,68,82],IEND:[73,69,78,68]},M.FIELD_BYTE_LENGTH=12,M.prototype.initializeAsSignature_=function(t,e){this.byteLength=8,this.type_=new Uint8Array(t,e,this.byteLength)},M.prototype.initializeAsChunk_=function(t,e){for(var r=new Uint8Array(t,e,4),n=0,i=0;i<4;i++)n<<=8,n|=r[i];this.byteLength=n+M.FIELD_BYTE_LENGTH,this.type_=new Uint8Array(t,e+4,4)},M.prototype.isSignature=function(){return 8===this.byteLength},M.prototype.isHeader=function(){return this.matches(M.type.IHDR)},M.prototype.isEnd=function(){return this.matches(M.type.IEND)},M.prototype.matches=function(t){for(var e=0;ee.height?r.top-e.height:0,Math.abs(t)2032),t+(r299)return u.reject()}catch(t){}if(n.readyState>2&&void 0!==n.responseText){for(var t=n.responseText;t&&c299)return s.reject()}catch(t){}if(n.readyState>2){for(var t=n.response;t&&u=1&&(this.requireProxy_=this.accessorTest(t[0])),this.capture(),this.requireProxy_&&this.captureNativeMethods(),this.isHighLatency_().then(R(function(t){return t||this.forcePreload_?this.preload():this.backfill()},this))},this))},F.prototype.postProcess_=function(t,e,r){return new G(function(n){var i=document.createElement("canvas"),o=document.createElement("img"),s=i.getContext("2d");i.width=e,i.height=r,o.addEventListener("load",R(function(){s.drawImage(o,0,0,e,r),n(i.toDataURL())},this)),o.addEventListener("error",R(function(t){bt("Error loading image."),n("")},this)),o.src=t})},F.prototype.limitPreloadableImages_=function(t){var e=[],r=[];return y(b(t,function(t){return!!t}),function(t,n){var i=dt(t);nCt.maxexternalimages&&(r.splice(e.pop(),1),r.push(t))}),G.resolve(r)},F.prototype.reducePreloadableImages_=function(){var t=[];return y(this.getUniqueSrcs_(),function(e,r){t.push(G.resolve().then(R(function(){return this.manifest_.has(e).then(function(t){if(!t)return e})},this),function(){}))},this),G.all(t).then(R(function(t){return this.limitPreloadableImages_(t).then(R(function(t){var e,r={};y(t,function(t){r[t]=!0},{});var n=[];return e=b(this.imageCache_,function(t){var e=r[t.getSrc()];return e||this.push(t),e},n),n.length>0&&window.setTimeout(function(){y(n,function(t){t.restore()})},F.RESTORE_NON_DEGRADED_IMAGE_TIMEOUT),e},this))},this))},F.prototype.getUniqueSrcs_=function(){var t={},e=[],r=[],n=window.innerWidth,i=window.innerHeight;return y(this.imageCache_,function(o){var s=o.getTop(),a=o.getLeft(),u=o.getSrc();s= 200 && xhr.status < 300) { + var myToast = new bootstrap.Toast(document.getElementById('toast-post-error')); + myToast.hide(); + + var myToast = new bootstrap.Toast(document.getElementById('toast-post-success')); + myToast.show(); + + try { + if(typeof result == "string") { + document.getElementById('toast-post-success-text').innerText = result; + } else { + document.getElementById('toast-post-success-text').innerText = JSON.parse(xhr.response)["message"]; + } + } catch(e) { + document.getElementById('toast-post-success-text').innerText = "Action successful!"; + } + + return true; + } else { + var myToast = new bootstrap.Toast(document.getElementById('toast-post-success')); + myToast.hide(); + + var myToast = new bootstrap.Toast(document.getElementById('toast-post-error')); + myToast.show(); + + try { + if(typeof result == "string") { + document.getElementById('toast-post-error-text').innerText = result; + } else { + document.getElementById('toast-post-error-text').innerText = JSON.parse(xhr.response)["error"]; + } + return false + } catch(e) {} + + return false; + } + }; + + xhr.send(form); + +} + +function toggleElement(group, id) { + for(let el of document.getElementsByClassName(group)) { + if(el.id != id) { + el.classList.add('d-none'); + } + } + + document.getElementById(id).classList.toggle('d-none'); +} + +let TRANSFER_TAX = document.getElementById('tax').innerHTML + +function updateTax(mobile=false) { + let suf = mobile ? "-mobile" : ""; + let amount = parseInt(document.getElementById("coins-transfer-amount" + suf).value); + if(isNaN(amount) || amount < 0) { + amount = 0; + } + document.getElementById("coins-transfer-taxed" + suf).innerText = amount - Math.ceil(amount*TRANSFER_TAX); +} + +function transferCoins(mobile=false) { + let t = event.target; + t.disabled = true; + + let amount = parseInt(document.getElementById("coins-transfer-amount").value); + let transferred = amount - Math.ceil(amount*TRANSFER_TAX); + let username = document.getElementById('username').innerHTML + + post_toast_callback(`/@${username}/transfer_coins`, + {"amount": document.getElementById(mobile ? "coins-transfer-amount-mobile" : "coins-transfer-amount").value}, + (xhr) => { + if(xhr.status == 200) { + document.getElementById("user-coins-amount").innerText = parseInt(document.getElementById("user-coins-amount").innerText) - amount; + document.getElementById("profile-coins-amount-mobile").innerText = parseInt(document.getElementById("profile-coins-amount-mobile").innerText) + transferred; + document.getElementById("profile-coins-amount").innerText = parseInt(document.getElementById("profile-coins-amount").innerText) + transferred; + } + } + ); + + setTimeout(_ => t.disabled = false, 2000); +} \ No newline at end of file diff --git a/files/mail/__init__.py b/files/mail/__init__.py index 1bc255a4e..36d753da8 100644 --- a/files/mail/__init__.py +++ b/files/mail/__init__.py @@ -43,6 +43,7 @@ def send_verification_email(user, email=None): @app.post("/verify_email") @limiter.limit("1/second") @auth_required +@validate_formkey def api_verify_email(v): send_verification_email(v) diff --git a/files/routes/admin.py b/files/routes/admin.py index 10ec84ddb..653bc5c9c 100644 --- a/files/routes/admin.py +++ b/files/routes/admin.py @@ -36,6 +36,7 @@ def truescore(v): @app.post("/@/revert_actions") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def revert_actions(v, username): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): user = get_user(username) @@ -61,6 +62,7 @@ def revert_actions(v, username): @app.post("/@/club_allow") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def club_allow(v, username): u = get_user(username, v=v) @@ -84,6 +86,7 @@ def club_allow(v, username): @app.post("/@/club_ban") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def club_ban(v, username): u = get_user(username, v=v) @@ -107,6 +110,7 @@ def club_ban(v, username): @app.post("/@/make_admin") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def make_admin(v, username): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): user = get_user(username) @@ -120,6 +124,7 @@ def make_admin(v, username): @app.post("/@/remove_admin") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def remove_admin(v, username): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): user = get_user(username) @@ -133,6 +138,7 @@ def remove_admin(v, username): @app.post("/@/make_meme_admin") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def make_meme_admin(v, username): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): user = get_user(username) @@ -146,6 +152,7 @@ def make_meme_admin(v, username): @app.post("/@/remove_meme_admin") @limiter.limit("1/second") @admin_level_required(2) +@validate_formkey def remove_meme_admin(v, username): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): user = get_user(username) @@ -159,6 +166,7 @@ def remove_meme_admin(v, username): @app.post("/admin/monthly") @limiter.limit("1/day") @admin_level_required(2) +@validate_formkey def monthly(v): if 'pcm' in request.host or (SITE_NAME == 'Drama' and v.admin_level > 2) or ('rama' not in request.host and 'pcm' not in request.host): thing = g.db.query(AwardRelationship).order_by(AwardRelationship.id.desc()).first().id @@ -930,6 +938,7 @@ def api_distinguish_post(post_id, v): @app.post("/sticky/") @admin_level_required(2) +@validate_formkey def api_sticky_post(post_id, v): post = g.db.query(Submission).filter_by(id=post_id).first() @@ -965,6 +974,7 @@ def api_sticky_post(post_id, v): @app.post("/ban_comment/") @limiter.limit("1/second") @admin_level_required(1) +@validate_formkey def api_ban_comment(c_id, v): comment = g.db.query(Comment).filter_by(id=c_id).first() @@ -989,6 +999,7 @@ def api_ban_comment(c_id, v): @app.post("/unban_comment/") @limiter.limit("1/second") @admin_level_required(1) +@validate_formkey def api_unban_comment(c_id, v): comment = g.db.query(Comment).filter_by(id=c_id).first() @@ -1013,6 +1024,7 @@ def api_unban_comment(c_id, v): @app.post("/distinguish_comment/") @admin_level_required(1) +@validate_formkey def admin_distinguish_comment(c_id, v): diff --git a/files/routes/awards.py b/files/routes/awards.py index e70ba3d1a..71eab065f 100644 --- a/files/routes/awards.py +++ b/files/routes/awards.py @@ -270,6 +270,7 @@ def shop(v): @app.post("/buy/") @auth_required +@validate_formkey def buy(v, award): AWARDS = { "shit": { @@ -514,6 +515,7 @@ def buy(v, award): @app.post("/post//awards") @limiter.limit("1/second") @auth_required +@validate_formkey def award_post(pid, v): if v.shadowbanned: return render_template('errors/500.html', v=v), 500 @@ -671,6 +673,7 @@ def award_post(pid, v): @app.post("/comment//awards") @limiter.limit("1/second") @auth_required +@validate_formkey def award_comment(cid, v): if v.shadowbanned: return render_template('errors/500.html', v=v), 500 diff --git a/files/routes/front.py b/files/routes/front.py index 2bd50296e..25e0a812b 100644 --- a/files/routes/front.py +++ b/files/routes/front.py @@ -13,6 +13,7 @@ def slash_post(): @app.post("/clear") @auth_required +@validate_formkey def clear(v): for n in v.notifications.filter_by(read=False).all(): n.read = True @@ -210,7 +211,8 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words=' posts = posts.filter(Submission.created_utc >= cutoff) else: cutoff = 0 - posts = posts.filter_by(is_banned=False, stickied=None, private=False, deleted_utc = 0) + if sort == "new": posts = posts.filter_by(is_banned=False, private=False, deleted_utc = 0) + else: posts = posts.filter_by(is_banned=False, stickied=None, private=False, deleted_utc = 0) if v and v.admin_level == 0: blocking = [x[0] for x in g.db.query( @@ -263,13 +265,14 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words=' posts = posts[:size] - pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False) - if v and v.admin_level == 0: - blocking = [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=v.id).all()] - blocked = [x[0] for x in g.db.query(UserBlock.user_id).filter_by(target_id=v.id).all()] - pins = pins.filter(Submission.author_id.notin_(blocking), Submission.author_id.notin_(blocked)) + if sort != "new": + pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False) + if v and v.admin_level == 0: + blocking = [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=v.id).all()] + blocked = [x[0] for x in g.db.query(UserBlock.user_id).filter_by(target_id=v.id).all()] + pins = pins.filter(Submission.author_id.notin_(blocking), Submission.author_id.notin_(blocked)) - if page == 1 and not gt and not lt: posts = pins.all() + posts + if sort != "new" and page == 1 and not gt and not lt: posts = pins.all() + posts if ids_only: posts = [x.id for x in posts] diff --git a/files/routes/oauth.py b/files/routes/oauth.py index fae4ecb0a..ef7edb4d1 100644 --- a/files/routes/oauth.py +++ b/files/routes/oauth.py @@ -38,6 +38,7 @@ def authorize(v): @app.post("/api_keys") @limiter.limit("1/second") @is_not_banned +@validate_formkey def request_api_keys(v): new_app = OauthApp( @@ -253,6 +254,7 @@ def admin_apps_list(v): @app.post("/oauth/reroll/") @limiter.limit("1/second") @auth_required +@validate_formkey def reroll_oauth_tokens(aid, v): aid = aid diff --git a/files/routes/reporting.py b/files/routes/reporting.py index 2cc2b3763..37b39bb5a 100644 --- a/files/routes/reporting.py +++ b/files/routes/reporting.py @@ -8,6 +8,7 @@ from files.helpers.sanitize import filter_emojis_only @app.post("/report/post/") @limiter.limit("1/second") @auth_required +@validate_formkey def api_flag_post(pid, v): post = get_post(pid) @@ -38,6 +39,7 @@ def api_flag_post(pid, v): @app.post("/report/comment/") @limiter.limit("1/second") @auth_required +@validate_formkey def api_flag_comment(cid, v): comment = get_comment(cid) diff --git a/files/routes/settings.py b/files/routes/settings.py index 06c6a9ae9..0d01fbfe8 100644 --- a/files/routes/settings.py +++ b/files/routes/settings.py @@ -34,6 +34,7 @@ tiers={ @app.post("/settings/removebackground") @limiter.limit("1/second") @auth_required +@validate_formkey def removebackground(v): v.background = None g.db.add(v) @@ -439,6 +440,7 @@ def settings_profile_post(v): @app.post("/settings/filters") @auth_required +@validate_formkey def filters(v): filters=request.values.get("filters")[:1000].strip() @@ -810,6 +812,7 @@ def settings_css_get(v): @app.post("/settings/css") @limiter.limit("1/second") @auth_required +@validate_formkey def settings_css(v): css = request.values.get("css").strip().replace('\\', '').strip()[:4000] @@ -826,14 +829,15 @@ def settings_css(v): @auth_required def settings_profilecss_get(v): - if v.truecoins < 1000 and not v.patron and v.admin_level == 0 : return f"You must have +1000 {COINS_NAME} or be a patron to set profile css." + if v.truecoins < 1000 and not v.patron and v.admin_level == 0 : return f"You must have +1000 {COINS_NAME} or be a paypig to set profile css." return render_template("settings_profilecss.html", v=v) @app.post("/settings/profilecss") @limiter.limit("1/second") @auth_required +@validate_formkey def settings_profilecss(v): - if v.truecoins < 1000 and not v.patron: return f"You must have +1000 {COINS_NAME} or be a patron to set profile css." + if v.truecoins < 1000 and not v.patron: return f"You must have +1000 {COINS_NAME} or be a paypig to set profile css." profilecss = request.values.get("profilecss").strip().replace('\\', '').strip()[:4000] v.profilecss = profilecss g.db.add(v) diff --git a/files/routes/static.py b/files/routes/static.py index 6b5f2f4de..58b13a41f 100644 --- a/files/routes/static.py +++ b/files/routes/static.py @@ -230,6 +230,7 @@ def contact(v): @app.post("/contact") @limiter.limit("1/second") @auth_required +@validate_formkey def submit_contact(v): message = f'This message has been sent automatically to all admins via https://{site}/contact, user email is "{v.email}"\n\nMessage:\n\n' + request.values.get("message", "") send_admin(v.id, message) diff --git a/files/routes/users.py b/files/routes/users.py index 46e5e9a68..16be0d6d4 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -97,6 +97,7 @@ def downvoting(v, username): @app.post("/pay_rent") @limiter.limit("1/second") @auth_required +@validate_formkey def pay_rent(v): if v.coins < 500: return "You must have more than 500 coins." v.coins -= 500 @@ -113,6 +114,7 @@ def pay_rent(v): @app.post("/steal") @limiter.limit("1/second") @is_not_banned +@validate_formkey def steal(v): if int(time.time()) - v.created_utc < 604800: return "You must have an account older than 1 week in order to attempt stealing." @@ -167,6 +169,7 @@ def thiefs(v): @app.post("/@/suicide") @limiter.limit("1/second") @auth_required +@validate_formkey def suicide(v, username): t = int(time.time()) if v.admin_level == 0 and t - v.suicide_utc < 86400: return {"message": "You're on 1-day cooldown!"} @@ -312,6 +315,7 @@ def song(song): @app.post("/subscribe/") @limiter.limit("1/second") @auth_required +@validate_formkey def subscribe(v, post_id): new_sub = Subscription(user_id=v.id, submission_id=post_id) g.db.add(new_sub) @@ -321,6 +325,7 @@ def subscribe(v, post_id): @app.post("/unsubscribe/") @limiter.limit("1/second") @auth_required +@validate_formkey def unsubscribe(v, post_id): sub=g.db.query(Subscription).filter_by(user_id=v.id, submission_id=post_id).first() if sub: @@ -337,6 +342,7 @@ def reportbugs(v): @limiter.limit("1/second") @limiter.limit("10/hour") @auth_required +@validate_formkey def message2(v, username): user = get_user(username, v=v) @@ -400,6 +406,7 @@ def message2(v, username): @limiter.limit("1/second") @limiter.limit("6/minute") @auth_required +@validate_formkey def messagereply(v): message = request.values.get("body", "").strip()[:1000].strip() @@ -727,6 +734,7 @@ def u_username_info(username, v=None): @app.post("/follow/") @limiter.limit("1/second") @auth_required +@validate_formkey def follow_user(username, v): target = get_user(username) @@ -752,6 +760,7 @@ def follow_user(username, v): @app.post("/unfollow/") @limiter.limit("1/second") @auth_required +@validate_formkey def unfollow_user(username, v): target = get_user(username) @@ -778,6 +787,7 @@ def unfollow_user(username, v): @app.post("/remove_follow/") @limiter.limit("1/second") @auth_required +@validate_formkey def remove_follow(username, v): target = get_user(username) @@ -869,6 +879,7 @@ def saved_comments(v, username): @app.post("/fp/") @auth_required +@validate_formkey def fp(v, fp): if v.username != fp: v.fp = fp diff --git a/files/routes/votes.py b/files/routes/votes.py index a03e16ca0..32201e980 100644 --- a/files/routes/votes.py +++ b/files/routes/votes.py @@ -196,6 +196,7 @@ def api_vote_comment(comment_id, new, v): @app.post("/vote/poll/") @auth_required +@validate_formkey def api_vote_poll(comment_id, v): vote = request.values.get("vote") diff --git a/files/templates/changelog.html b/files/templates/changelog.html index 0e711b6db..6884eeb6d 100644 --- a/files/templates/changelog.html +++ b/files/templates/changelog.html @@ -102,6 +102,6 @@ {% endif %} - + {% endblock %} \ No newline at end of file diff --git a/files/templates/header.html b/files/templates/header.html index 912e2ed70..0fb96a491 100644 --- a/files/templates/header.html +++ b/files/templates/header.html @@ -213,7 +213,7 @@ - +