diff --git a/src/server/backend/plugins/others/poll/data/filterlist.txt b/src/server/backend/plugins/others/poll/data/filterlist.txt new file mode 100644 index 0000000..f9566bd --- /dev/null +++ b/src/server/backend/plugins/others/poll/data/filterlist.txt @@ -0,0 +1,298 @@ +nig +cum +pron +jap +xxx +cok +kkk +Africoon +akata +Beaner +Camel jockey +Chink +Coon +Coonass +Dune Coon +Gook +Jungle Bunny +Niglet +Nignog +Porch Monkey +Towel Head +Turk +Wetback +Wigger +Cock +Fag +Kock +Pecker +Tit +Wang +wank +Willy +Willies +Anal +Slut +Retard +Retarded +niga +Raped +Rape +Rapist +Semen +Cums +Cum +Fag +Fags +Tit +Porn +Slut +Smut +Teets +Tits +Jiz +doosh +Dick +Cunt +Boob +scat +slut +twat +pube +pubes +twat +retards +rimming +milf +nazi +orgy +porn +pussy +niggar +Nigga +Nigger +assfucker +assfucka +b00b +b00bs +ballsack +beastial +beastiality +bestial +bestiality +blow job +blowjob +blowjobs +boner +boobs +booobs +boooobs +booooobs +buttplug +c0ck +c0cksucker +chink +cl1t +clit +clitoris +clits +cock-sucker +cockface +cockhead +cockmunch +cockmuncher +cocks +cocksuck +cocksucked +cocksucker +cocksucking +cocksucks +cocksuka +cocksukka +cokmuncher +coksucka +cummer +cumshot +cunilingus +cunillingus +cunnilingus +cuntlick +cuntlicker +cuntlicking +cunts +cyalis +cyberfuc +cyberfuck +cyberfucked +cyberfucker +cyberfuckers +cyberfucking +d1ck +dickhead +dildo +dildos +dog-fucker +doggin +dogging +donkeyribber +doosh +duche +Douche +ejaculate +ejaculated +ejaculates +ejaculating +ejaculatings +ejaculation +ejakulate +F4nny +fagging +faggitt +faggot +faggs +fagot +fagots +fatass +felching +fellate +fellatio +fingerfuck +fingerfucked +fingerfucker +fingerfuckers +fingerfucking +fingerfucks +fistfuck +fistfucked +fistfucker +fistfuckers +fistfucking +fistfuckings +fistfucks +fuckhead +fuckheads +fuckingshitmotherfucker +fuckme +fuckwhit +fuckwit +fukwit +fukwhit +gangbang +gangbanged +gangbangs +gaysex +goatse +hardcoresex +horniest +horny +hotsex +jack-off +jackoff +jerk-off +jism +jizm +jizz +kawk +kondum +kondums +kummer +humming +kunilingus +l3i+ch +l3itch +labia +m0f0 +m0fo +m45terbate +ma5terb8 +ma5terbate +masochist +master-bate +masterb8 +masterbat* +masterbat3 +masterbate +masterbation +masterbations +masturbate +nig +n1g +n1gga +n1gger +nazi +nigg3r +nigg4h +nigga +niggah +niggas +niggaz +nigger +niggers +nutsack +orgasim +orgasims +orgasm +orgasms +p0rn +penis +phonesex +penisfucker +phuck +phuk +phuked +phuking +phukked +phukking +phuks +pigfucker +pissoff +porno +pornography +pornos +pusse +pussi +pussies +pussy +pussys +rectum +rimjaw +sadist +schlong +scrotum +shaggin +shagging +shitdick +shited +shitfuck +shithead +sluts +smegma +spunk +t1tt1e5 +t1tties +testical +testicle +titfuck +tittie5 +tittiefucker +titties +tittyfuck +tittywank +titwank +tw4t +twathead +twatty +twunt +twunter +v14gra +v1gra +vagina +viagra +vulva +w00se +wanker +wanky +whore +xrated +hitler +putin diff --git a/src/server/backend/plugins/others/poll/js/voting.js b/src/server/backend/plugins/others/poll/js/voting.js index 363877a..f6a97e3 100644 --- a/src/server/backend/plugins/others/poll/js/voting.js +++ b/src/server/backend/plugins/others/poll/js/voting.js @@ -11,6 +11,7 @@ createApp( { hasLoadedBasics: false, hasLoadedVotes: false, sorting: 'newest', + userIdentifier: '', }; }, computed: { @@ -44,12 +45,67 @@ createApp( { } } }, + computed: { + orderedVotes() { + if ( this.sorting === 'oldest' ) { + return Object.values( this.entries ); + } else if ( this.sorting === 'newest' ) { + const ent = Object.keys( this.entries ).reverse(); + let ret = []; + for ( let entry in ent ) { + ret.push( this.entries[ ent[ entry ] ] ); + } + return ret; + } else { + let ent = Object.keys( this.entries ).sort( ( a, b ) => { + if ( this.sorting === 'nameUp' ) { + return this.entries[ a ].title.localeCompare( this.entries[ b ].title ); + } else if ( this.sorting === 'nameDown' ) { + return this.entries[ b ].title.localeCompare( this.entries[ a ].title ); + } else if ( this.sorting === 'mostVoted' ) { + return this.entries[ b ].count - this.entries[ a ].count; + } else if ( this.sorting === 'leastVoted' ) { + return this.entries[ a ].count - this.entries[ b ].count; + } + } ); + let ret = []; + for ( let entry in ent ) { + ret.push( this.entries[ ent[ entry ] ] ); + } + return ret; + } + } + }, methods: { getData() { fetch( '/polls/get/' + location.pathname.substring( 7 ) ).then( response => { response.json().then( data => { this.entries = data; - this.hasLoadedVotes = true; + this.fingerprint(); + let fetchOptions = { + method: 'post', + body: JSON.stringify( { 'fingerprint': this.userIdentifier } ), + headers: { + 'Content-Type': 'application/json', + 'charset': 'utf-8' + }, + }; + fetch( '/voting/getVotedOn/' + location.pathname.substring( 8 ), fetchOptions ).then( res => { + if ( res.status === 200 ) { + res.json().then( json => { + this.votedOn = JSON.parse( localStorage.getItem( 'itemsVotedOn' ) ?? '{}' ); + for ( let el in json ) { + if ( json[ el ] === 1 ) { + this.votedOn[ json[ el ] ] = 'up'; + } else if ( json[ el ] === -1 ) { + this.votedOn[ json[ el ] ] = 'down'; + } + } + localStorage.setItem( 'itemsVotedOn', JSON.stringify( this.votedOn ) ); + this.hasLoadedVotes = true; + } ); + } + } ); } ); } ); fetch( '/polls/getDetails/' + location.pathname.substring( 7 ) ).then( response => { @@ -60,23 +116,29 @@ createApp( { } ); this.votedOn = JSON.parse( localStorage.getItem( 'itemsVotedOn' ) ?? '{}' ); }, + fingerprint() { + // I am forced to do this because there are idiots in this world + // https://stackoverflow.com/questions/27247806/generate-unique-id-for-each-device + if ( !this.userIdentifier ) { + const navigator_info = window.navigator; + const screen_info = window.screen; + let uid = navigator_info.mimeTypes.length; + uid += navigator_info.userAgent.replace( /\D+/g, '' ); + uid += navigator_info.plugins.length; + uid += screen_info.height || ''; + uid += screen_info.width || ''; + uid += screen_info.pixelDepth || ''; + this.userIdentifier = uid; + } + }, save() { if ( this.newSuggestion.comment && this.newSuggestion.title ) { let alreadyExists = false; for ( let el in this.entries ) { - if ( this.entries[ el ][ 'title' ] === this.newSuggestion.title ) { + if ( this.entries[ el ][ 'title' ].toLocaleLowerCase() === this.newSuggestion.title.toLocaleLowerCase() ) { alreadyExists = true; } } - if ( alreadyExists ) { - if ( confirm( 'An element with the same title exists already. Do you really want to add another one?' ) ) { - if ( confirm( 'Are you really sure?' ) ) { - alreadyExists = true; - } else { - alreadyExists = false; - } - } - } if ( !alreadyExists ) { let fetchOptions = { method: 'post', @@ -86,19 +148,25 @@ createApp( { 'charset': 'utf-8' }, }; - fetch( '/voting/add/' + location.pathname.substring( 8 ), fetchOptions ).then( response => { - if ( response.status !== 200 ) { + fetch( '/polls/add/' + location.pathname.substring( 8 ), fetchOptions ).then( response => { + if ( response.status === 418 ) { + alert( 'One or more of the words in either your description or title is on our blocklist. Please make sure that you are not using any words that are NSFW, racist or similar.' ); + } else if ( response.status !== 200 ) { alert( 'there was an error updating' ); + } else { + this.closePopup(); + this.getData(); } } ); - this.closePopup(); - this.getData(); + } else { + alert( 'An entry with this name exists already. Please vote on that entry.' ); } } else { alert( 'Not all required fields are filled out!' ); } }, vote( type, suggestionID ) { + this.fingerprint(); let voteType = type; let didDeactivate = false; if ( this.votedOn[ suggestionID ] === type ) { @@ -113,14 +181,16 @@ createApp( { } let fetchOptions = { method: 'post', - body: JSON.stringify( { 'voteType': voteType, 'id': suggestionID } ), + body: JSON.stringify( { 'voteType': voteType, 'id': suggestionID, 'fingerprint': this.userIdentifier } ), headers: { 'Content-Type': 'application/json', 'charset': 'utf-8' }, }; fetch( '/polls/vote/' + location.pathname.substring( 7 ), fetchOptions ).then( response => { - if ( response.status !== 200 ) { + if ( response.status === 409 ) { + alert( 'You have already voted on this!' ); + } else if ( response.status !== 200 ) { alert( 'there was an error updating' ); } else { this.votedOn[ suggestionID ] = didDeactivate ? undefined : voteType; diff --git a/src/server/backend/plugins/others/poll/pollRoutes.js b/src/server/backend/plugins/others/poll/pollRoutes.js index e6ae472..45f4268 100644 --- a/src/server/backend/plugins/others/poll/pollRoutes.js +++ b/src/server/backend/plugins/others/poll/pollRoutes.js @@ -40,6 +40,32 @@ const runSave = () => { } ); }; +// There are idiots in this world so we have to filter +// Filter list is from here: https://github.com/BurntRouter/filtered-word-lists plus some extra words +let uidCrossReference = JSON.parse( fs.readFileSync( path.join( __dirname + '/data/voteUIDReferencing.json' ) ) ); +const fl = '' + fs.readFileSync( path.join( __dirname + '/data/filterlist.txt' ) ); +let votingDirections = { '1': 'up', '-1': 'down' }; +let filterList = []; +let prevStart = 0; +for ( let e in fl ) { + if ( fl[ e ] === '\n' ) { + filterList.push( fl.slice( prevStart, e ).toLocaleLowerCase() ); + prevStart = parseInt( e ) + 1; + } +} + +const filtering = ( string ) => { + // using these filter lists: https://github.com/BurntRouter/filtered-word-lists plus some extra words + // returns true if text is ok + const str = string.toLocaleLowerCase(); + for ( let badWord in filterList ) { + if ( str.includes( filterList[ badWord ] ) ) { + return false; + } + } + return true; +}; + module.exports = ( app ) => { app.get( '/polls/:vote', ( req, res ) => { res.sendFile( path.join( __dirname + '/html/voting.html' ) ); @@ -58,6 +84,10 @@ module.exports = ( app ) => { res.send( JSON.parse( filedata )[ req.params.vote ] ?? {} ); } ); } ); + + app.post( '/polls/getVotedOn/:vote', ( req, res ) => { + res.send( uidCrossReference[ req.body.fingerprint ] ?? {} ); + } ); app.get( '/polls/get/:vote', ( req, res ) => { res.send( votingMemCache[ req.params.vote ] ); @@ -65,34 +95,64 @@ module.exports = ( app ) => { app.post( '/polls/vote/:vote/', bodyParser.json(), ( req, res ) => { // up / down-voting - if ( votingMemCache[ req.params.vote ] ) { - if ( votingMemCache[ req.params.vote ][ req.body.id ] ) { - if ( req.body.voteType === 'up' ) { - votingMemCache[ req.params.vote ][ req.body.id ].count += 1; - } else if ( req.body.voteType === 'down' ) { - votingMemCache[ req.params.vote ][ req.body.id ].count -= 1; + if ( req.body.fingerprint != '' ) { + if ( uidCrossReference[ req.body.fingerprint ] ) { + if ( uidCrossReference[ req.body.fingerprint ][ req.params.vote ] ) { + if ( uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ] !== 0 ) { + const vote = uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ]; + if ( votingDirections[ vote ] === req.body.voteType ) { + res.status( 409 ).send( 'alreadyVotedOn' ); + return; + } + } else { + uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ] = 0; + } + } else { + uidCrossReference[ req.body.fingerprint ][ req.params.vote ] = {}; } - saveVotingData(); - res.send( 'ok' ); } else { - res.status( 404 ).send( 'No Entry on this vote with' ); + uidCrossReference[ req.body.fingerprint ] = {}; + uidCrossReference[ req.body.fingerprint ][ req.params.vote ] = {}; + uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ] = 0; + } + if ( votingMemCache[ req.params.vote ] ) { + if ( votingMemCache[ req.params.vote ][ req.body.id ] ) { + if ( req.body.voteType === 'up' ) { + votingMemCache[ req.params.vote ][ req.body.id ].count += 1; + uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ] += 1; + } else if ( req.body.voteType === 'down' ) { + votingMemCache[ req.params.vote ][ req.body.id ].count -= 1; + uidCrossReference[ req.body.fingerprint ][ req.params.vote ][ req.body.id ] -= 1; + } + saveVotingData(); + res.send( 'ok' ); + } else { + res.status( 404 ).send( 'No Entry on this vote with' ); + } + } else { + res.status( 404 ).send( 'No Vote with this ID' ); } } else { - res.status( 404 ).send( 'No Vote with this ID' ); + res.status( 400 ).send( 'Wrong request' ); } } ); app.post( '/polls/add/:vote', bodyParser.json(), ( req, res ) => { let data = req.body; if ( data.title && data.comment ) { - if ( !votingMemCache[ req.params.vote ] ) { - votingMemCache[ req.params.vote ] = {}; + if ( filtering( data.title ) && filtering( data.comment ) ) { + if ( !votingMemCache[ req.params.vote ] ) { + votingMemCache[ req.params.vote ] = {}; + } + const id = parseInt( Object.keys( votingMemCache[ req.params.vote ] )[ Object.keys( votingMemCache[ req.params.vote ] ).length - 1 ] ?? 0 ) + 1; + votingMemCache[ req.params.vote ][ id ] = data; + votingMemCache[ req.params.vote ][ id ][ 'id' ] = id; + votingMemCache[ req.params.vote ][ id ][ 'count' ] = 1; + saveVotingData(); + res.send( 'ok' ); + } else { + res.status( 418 ).send( 'seriously?' ); } - const id = parseInt( Object.keys( votingMemCache[ req.params.vote ] )[ Object.keys( votingMemCache[ req.params.vote ] ).length - 1 ] ?? 0 ) + 1; - votingMemCache[ req.params.vote ][ id ] = data; - votingMemCache[ req.params.vote ][ id ][ 'id' ] = id; - votingMemCache[ req.params.vote ][ id ][ 'count' ] = 1; - res.send( 'ok' ); } else { res.status( 400 ).send( 'incomplete' ); }