Prevent cheating in Rails/html5 game App (Rails 3.2/html5/javascript) - javascript

I'd like to know if it's possible to prevent cheating in the following case
I have a Ruby on Rails app and a Active Record database
I have Users (model User), that play Games(model Game) and there are Prizes (model Prize).
What I want is to :
1- prevent a player from cheating/hacking on the winnings (prizes he has won)
2- prevent a player from cheating on the nb of shots he has
As a user can win multiple prizes and prizes can belong to multiple users, I have a many_to_many relations: i use for this a table/model Winnings that lists all stuff won in the games by each User (a user has many winnings and a prize has many winnings)
Players have a certain number of shots, let's say 3 per user.
For 1-, basically, i guess everytime a user wins a prize in a Game, i'll send the server a url like:
mygame/com/?winning_id=1234;game_id=3;user_id=6;prize_id=4, telling the server the user with id 6 has won a prize with id4 in the game with id 6
I don't want players to be able to cheat that. how can I do this. Can any player just use that url above and send this way a message/action to my server (post) telling him he won? that would make it freaking easy to cheat?
Should I encrypt stuff/the url and make the url/message only understandable by my server?
For 2- (shots), I think I should send actions to server side every time and calculate scores at server side but still can't he cheat the same way as 1-?

In addition to using post as mentioned in the answer from palainum above, if needed, you could add a string (instead of an ID) in any place in your game where the URL could be edited and is visible.
Background - I had a similar problem in one of my apps (where if a URL was changed people could deduce / edit the number and cheat). The way I overcame it was to generate a unique code for the item in the URL.
To do this, I would add a string attribute to Winning model called url_code, make it required and indexable:
add_column :winning, string :url_code, :null => false, :index => true
in your model add an after_initialize callback:
Class Winning
validates :url_code, :uniqueness => true
after_initialize :create_url_code
def create_url_code
self.url_code=SecureRandom.hex(4) if self.url_code.nil?
end
And use that as a parameter in the cases using an ID is a problem (similar to this in your controller)...
#winning = Winning.find_by_url_code(params[:id])
Also, you could do the same thing for your users URL (or if you need to display it every in URL) by using the user.name as a friendly_id.
edit - just fixed a typo where I had offer_code instead of url_code.

There are at least two things you can do now:
Send POST request - it will be still possible to cheat, but it will require more work
Create a model Win - and create object of this class after winning a game. Then after making request (point 1) you can check if this object exists.
EDIT:
Sorry, you already mentioned Winning class. Just create object of this class after winning a game, then check if a user won a game (if the table contains a record with the user and the game).
You should also store shots of a user in a game and use unique validation to disallow for example shooting twice in one game.

Related

Discord.js - Secretly getting user input

I am making a 2-player rock-paper-scissors game using Discord.js.
Sadly the Discord API is really slow and afaik doesn't provide any type of middleware. When someone chooses their shape, the other person sees the reaction (or chat message) for quite a while until the bot deletes it, therefore ruining the whole game.
The only way of secretly getting an input I could think of, was sending the user a message in private chat, to which he can react. But having to switch from the server to private chat and then back to the server just makes the game unplayable in my opinion. It's just too much work for the user, compared to simply clicking a reaction.
Another option would be sending a message in the chat, which only a specific user can see. It could say something like "1 = Scissors, 2 = Rock, 3 = Paper". (The mapping would be randomized for each player). The user then picks the corresponding reaction from the options 1, 2 and 3.
But it seems, Discord does not allow to send a message in chat, which only a specific user can see. Or is there a way?
And is there any way of secetly getting user-input without the user having to switch chats?
Does the API maybe provide any kind of middle-ware for messages or reactions which I have overlooked?
Discord does not allow to send a message in chat, which only a specific user can see. Or is there a way?
No, there isn't. Discord API doesn't allow you to specify users that can see a specific guild message.
And is there any way of secetly getting user-input without the user having to switch chats?
There definitely is!
You could use a fairly new feature, buttons. Below is an example code, you can use to base your game on. Things left to implement are:
Gamestate, e.g. who is on turn, who has how much points, etc.
Update gamestates (identify gamestate by id?) in the interactionCreate event's callback.
Showing the gamestate to the players, e.g. updating the original message.
Don't allow players to modify the gamestate of other playing pairs.
Let the user specify an opponent in !createGame command.
The actual game logic (determining who won, who gets a point, etc.)
That is all I can think of for now. Take those more of a suggestions than requirements. There is no boundary to ones creativity.
// ... Some object to store the gamestates in? ...
client.on("messageCreate", async (message) => {
// Don't reply to bots
if (message.author.bot) return;
// Basic command handler, just for showcasing the buttons
if (message.content.startsWith("!createGame")) {
// ... Probably some argument handling for the opponent (e.g. a mention) ...
// Create an action row component with buttons attached to it
const actionRow = new Discord.MessageActionRow()
.addComponents(
[["Rock", "🗿"], ["Paper", "🧻"], ["Scissors", "✂️"]].map((buttonProperties) => {
return new Discord.MessageButton()
.setStyle("PRIMARY")
.setLabel(buttonProperties[0])
.setEmoji(buttonProperties[1])
.setCustomId(`rpsgame_${buttonProperties[0].toLowerCase()}`);
})
);
// Send the game message/playground
message.channel.send({
content: "Rock, Paper and Scissors: The game!",
components: [actionRow]
});
}
});
To handle the button clicks, we use the interactionCreate event.
client.on("interactionCreate", (interaction) => {
// If the interaction is a button
if (interaction.isButton()) {
// If the button belongs to our game
if (interaction.customId.startsWith("rpsgame")) {
// Log what the user has selected to console, as a test
console.log(`A user '${interaction.member.user.tag}' selected ${interaction.component.emoji.name}.`);
// Don't forget to reply to an interaction,
// otherwise an error will be shown on discord.
interaction.update("Update GameState...");
}
}
});
No one will see what the other users have selected, unless you want them to.
Using discord.js ^13.0.1. If you are on v12, there is a nice package called discord-buttons.

Is there any way to create a "Free-write" section for a Chatbot?

Quite new here and have been using Dialogflow and rasa to try making a chatbot for user reports, Stuck at a certain segment where I want the user to "report" to the bot what it has done for the day, regardless of the content the bot will reply with a "Thanks for your time" response and saves the user's response, I can't seem to figure this out, as the bot will try to analyze the layer of texts the user sends and then goes to default fallback intent....
You will need FormAction for free write action (given you don't want any intent for it).
In the actions.py, add following code
class FormFreeText(FormAction):
def name(self):
return "form_free_text"
#staticmethod
def required_slots(tracker):
return ["free_text"]
def slot_mappings(self):
return {
"free_text": self.from_text()
}
def submit(self, dispatcher, tracker, domain):
return []
In domain.yml, add following lines
slots:
free_text:
type: unfeaturized
responses:
utter_ask_free_text:
- text: "Please enter the text for your report"
actions:
- form_free_text
In stories.md, add the following lines where ever you want user input.
- form_free_text
- form{'name':'form_free_text'}
- form{'name':null}
There are some naming convenstions like using utter_ask to ask any question using FormAction.
I hope this helps.
In DialogFlow your option is to use a fulfilment which allows to drive the conversation logic using events, for example:
user answers what's wrong or good about the day
webhook receives the payload with the answer and the associated intent (or better define an action)
webhook triggers an event (EVENT_DONE)
the event (EVENT_DONE) belongs to an intent (THANK_YOU) which sends a response to the user
In Rasa the options are to either train an intent (inform) with training data (you can still capture/recognise what the user talks about) or use an FormAction where user input is captured in a slot (even if you don't really need to use/store it)

Mongo&Express - what are the practical ways to avoid client firing same req multiple times?

Introduction:
I am developing a liking system similar to normal facebook liking where each user can like each post only once. I need to develop this system and have a "totalLike" in mongoDB. Environment: Mongoose, Express on server-side, Nextjs(React) on client-side.
Problem:
When user spams clicking the LIKE button before the button re-render to UNLIKE, the express LIKE api could be fired multiple times causing the extra number to be put into "totalLike". For example, you clicked like 3 times very fast, there you get 3 totalLikes instead of 1. (noted: I choose to add totalLike to user to avoid too many nested populate when call in the future)
My Pseudo-code:
Simply +1 totalLikes when press like and -1 totalLikes when press unlike. And it should be just that !
router.patch(
'/like/:post',
(req, res, next) => {
// user_id = the_user_who_click_like_to:post
Post.updateOne(
// at this post, add the user_id LikedUser array, then ...
(res) => {
User.updateOne(
// at user_id, do { $inc: { totalLikes: 1 } }, <-- this is the problem
// because "totalLikes" could be plus more than once!
)})})
router.delete(
'/like/:post',
// Do the same but opposite, $pull user_id from Post and -1 totalLikes in User = face same problem as above
)
Now the questions:
What are the practical ways to avoid this from happening on
server-side?
Is blocking the client-side from firing normally done by only setting state to disabling React button ?
As a backend newbie, another improved approach for the shown Psuedo code would be eye candy.
There are of course different approaches you can use.
Usually people to like posts have to be logged in and thus have an account.
This enables you to store in the DB, attached to the user, the like.
When you get a request to like something you can just check if the user has liked that already or not and throw an error in case it's present.
Another way, of course not 100% safe (the first would be), is to use the browser's Memory Storage or send back a cookie.
You would again check if there is this cookie or not before processing the request.
Of course you would then add front-end code to show the like button as inactive if the user has liked it before or popup a login window if he is not logged in.
It's very hard to show a full functional code as it's a pretty big topic, but I hope these directives may help.

JSON vs multiple connections

i'm currently building a website which searches an external database and brings up records which match the given search string. The search is live, so results are brought up as the user types.
now the first (and current) approach i took, is that the page actually connects to the mySQL server and retrieves content via AJAX, with EVERY letter the user types in the search box.
now i am starting to look at JSON objects (i only very recently started building websites), and was wondering if it would be a good idea, to load the entire database into a JSON object in the beginning and then look through that when searching.
is this a good idea? would it be faster? thanks in advance
It totally depends on the size of the data and the complexity of the query. If you can reasonably send the data to the client in advance and then search it locally, then sure, that's useful because it's all local and you don't have the latency of querying the server. But if you have a large amount of data, or the query is complex, it may well make more sense to do the query on the server.
There's no one-size-fits-all solution, it's data-dependent.
...and retrieves content via AJAX, with EVERY letter the user types in the search box.
That's usually overkill. Normally, you want to wait until there's a pause in the user's typing before firing off the ajax call, so that if they type "james" in rapid succession, you search for "james" rather than searching for "j", then "ja", then "jam", then "jame", and then "james".
For instance, let's say your search trigger is a keypress event. This would be a fairly common approach:
var keypressTimer = 0;
function handleKeypress() {
if (keypressTimer) {
cancelTimeout(keypressTimer);
}
keypressTimer = setTimeout(doSearch, 100); // 100ms = 1/10th of a second
}
function doSearch() {
var searchValue;
keypressTimer = 0;
searchValue = /*...get the search value...*/;
doAjaxCallUsing(searchValue);
}
This is called "debouncing" the input (from hardware engineering, related to the mechanical and electrical "bouncing" of a key as it's pressed).

PHP retrieve new images from database

Apologies for the NOOB question but I’m still learning.
Firstly I’m not asking for someone to program the following problem for me or to give me the code. I’m merely looking for a bit of help with the logic and a bit of advice.
What I am trying to do
This is just an example, what I am trying to do is different but will use the same logic: I am trying to display a movie poster on my website, the user can than rate that movie between 0 - 5 stars, his/her rating will be recorded in a database, along with other users’ ratings. When he/she has finished his/her rating, a new movie poster needs to be displayed where he/she can again rate the poster and so it goes on until he/she is tired of rating movies.
The Logic
I AM ASSUMING I will need to use PHP here to store and retrieve the data
A Table will be created which contains different images and ratings corresponding to that movie’s rating, along with the number of users who rated the movie to calculate the average for the total rating
The Problem
How do I get the image to change once the user rated the image?
Is it possible to change an image src onclick with PHP like it is with Javascript?
If so how do I do it? Is it possible that I will need to use a combination of PHP and Javascript here?
Any help or advice will be greatly appreciated. Thank you in advance.
You definitely need to use both javascript and PHP to accomplish this.
I would approach it like this:
a) Use jQuery javascript library to make the javascript easier.
b) Write some javascript which responds to the user selecting a rating. You'd probably need to bind to the onClick event of your rating buttons.
c) When a rating button is clicked, the javascript functions should use jQuery.ajax to send the selected rating to the server via an HTTP POST. The data sent to the server would probably need to contain an ID to identify the movie, an ID to represent the user (so you can stop people voting more than once for the same movie), and the rating they chose.
d) On the server-side, you can write a PHP script to handle the vote submissions. It would check for the movie, and user ids, (stored in PHP's $_POST variable), and then save the rating to some database. It could then also send a response back to the client which would contain the next movie id, and the next poster. I would recommend you use json_encode to store this info in a way that's easy for the javascript to interpret.
e) Finally, back on the client side, your javascript code can react to the data sent back by PHP, by putting up a message like 'thank you for your vote', then changing the movie details on screen to replace them with the new one.
Your client-side code would look something a bit like this:
<img id="movie-poster" src="movie poster src" />
<ul>
<li class="rating-button">1</li>
<li class="rating-button">2</li>
<li class="rating-button">3</li>
<li class="rating-button">4</li>
<li class="rating-button">5</li>
</ul>
<script>
var currentUserId;
var currentMovieId;
$('.rating-button').on('click',function() {
$.ajax({
url: "URL of PHP script here",
type: 'post',
data: {'movieId':currentMovieId, 'userId':currentUserId, 'rating':$(this).text()},
dataType: 'json',
success: function(response) {
// this runs after your PHP script has responded
// update your page with the new movie here
alert('thanks for voting');
currentMovieId = response.newMovieId;
$('#movie-poster').attr('src',response.newMoviePosterSrc);
}
});
}
</script>
Your PHP script would look something a bit like this (you'll have to figure out all the database and user authentication bits yourself)
<?php
$user_id = $_POST['userId'];
$movie_id = $_POST['movieId'];
$rating = $_POST['rating'];
// check that the user is allowed to vote - possibly examine cookie for this
// check that rating is between 0 and 5
// check that the movie exists
// store results of vote in database
// load up another random movie from the database and send it back (in JSON format)
// assume details of new movie are in $new_movie =
header('Content-type: application/json');
echo json_encode(array('newMovieId'=> new movie id here, 'newMoviePosterSrc' => URL of new poster here));
exit;
You should also add some error handling to that code. EG, messages to display if there's a connection problem, or the movie ID isn't recognised or something.
This page has more info on how to select a random row from your database - IE to select at random the next poster to show:
How to randomly select rows in SQL?
Hopefully that should be enough to get you started.

Categories

Resources