How does MIKROS know which users are cheaters or trolls? - mikros

I'm having trouble identifying how MIKROS tracks players who use exploits or are just a nuisance in general.
These are the code blocks I'm using to code user sign-in and sign-up:
For user sign-in:
SigninRequest.Builder()
.Username(username)
.Email(email)
.Password(password)
.Create(signinRequest =>
{
MikrosManager.Instance.AuthenticationController.Signin(signinRequest, delegate (MikrosUser mikrosUser)
{
// signed in successfully.
},
delegate (MikrosException mikrosException)
{
// handle authentication error
});
},
onFailure =>
{
// handle failure
});
For user sign-up:
SignupRequest.Builder()
.Username(username)
.Email(email)
.Password(password)
.Create(signupRequest =>
{
MikrosManager.Instance.AuthenticationController.Signup(signupRequest, delegate (MikrosUser mikrosUser)
{
// signed up successfully.
},
delegate (MikrosException mikrosException)
{
// handle authentication error
});
},
onFailure =>
{
// handle failure
});
Am I forgetting something?

If you are using MIKROS registration/authentication you will receive score information about the user.
For sign-in
SigninRequest.Builder()
.Username(username)
.Email(email)
.Password(password)
.Create(signinRequest =>
{
MikrosManager.Instance.AuthenticationController.Signin(signinRequest, delegate (MikrosUser mikrosUser)
{
// signed in successfully.
},
delegate (MikrosException mikrosException)
{
// handle authentication error
});
},
onFailure =>
{
// handle failure
});
For sign-up
SignupRequest.Builder()
.Username(username)
.Email(email)
.Password(password)
.Create(signupRequest =>
{
MikrosManager.Instance.AuthenticationController.Signup(signupRequest, delegate (MikrosUser mikrosUser)
{
// signed up successfully.
},
delegate (MikrosException mikrosException)
{
// handle authentication error
});
},
onFailure =>
{
// handle failure
});
Both will return a response body with a user{} object that will include scoring information for that particular user. Here is the short version of it.
Response Ex-
"user": {
....
"id": "172",
"email": "mikros3#test.com",
"username": "mikros3",
"spendingScore": "0",
"activityScore": "0",
"reputationScore": "0", <-- this is the score for hackers/trolls
}
Per the documentation, anyone with a score less than 7 you should be cautious about. It means that user has many negative offenses. The specifics of the offenses are not disclosed. But the only reasons you lose Reputation is from other users reporting you as a troll, hacker or other offensive behavior. To lower your score this has to happen pretty often and come from many different users.
Ref- https://developer.tatumgames.com/documentation/scores#reputation-score
Note: It has been mentioned by the MIKROS developers that they will be exposing a stand alone API for retrieving scores and more details about users outside of register/authentication. It's a feature on their roadmap.

Related

Trying to write a calendar event using Microsoft Graph API issue

I'm trying to use the Microsoft Graph API to write calendar events within my company.
First of all let me give you a little bit of context.
I'm building a node API that uses Microsoft Graph to write calendar events, so I configured my application inside the Azure Active Directory with the following application permission
I granted administrator consent as you can see from the picture.
I was also able to get the access token using msal-node
const graphToken = async () => {
const azureConfig = {
auth: {
clientId: process.env.CLIENT_ID,
authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
clientSecret: process.env.CLIENT_SECRET,
},
}
const tokenRequest = {
scopes: [process.env.GRAPH_ENDPOINT + '/.default'],
}
const cca = new msal.ConfidentialClientApplication(azureConfig)
const authRespose = await cca.acquireTokenByClientCredential(tokenRequest)
if (authRespose) {
return authRespose.accessToken
}
return null
}
The only thing that sounds me a little odd, is the scope set to [process.env.GRAPH_ENDPOINT + '/.default'] I tried to change it ex. [process.env.GRAPH_ENDPOINT + '/Calendar.ReadWrite'] but it fires an excepion.
The next thing I'm able to do is retrive all calendars a user have right to write to, using the following Graph endpoint:
https://graph.microsoft.com/v1.0/users/user#example.com/calendars
Now the issue, when I try to do a POST request to write a calendar event for example
POST https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events
{
"subject": "Test",
"body": {
"contentType": "HTML",
"content": "Test"
},
"start": {
"dateTime": "2022-11-09T16:00:00",
"timeZone": "Europe/Rome"
},
"end": {
"dateTime": "2022-11-09T17:00:00",
"timeZone": "Europe/Rome"
}
}
Note that calendarId is one of the id's from the previous call
(Not the default calendar of userId)
I got a 403 Forbidden with the following response
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again."
}
}
I also decoded my token to see if I get some info on the root cause of the 403 error, I found this:
...
"roles": [
"Calendars.Read",
"User.Read.All",
"Calendars.ReadWrite"
],
...
It seems correct to me.
I don't get if it is a scope issue, an authentication issue or something I'm missing, can someone pinpoint me in the right direction?
Thanks in advance
Basically it was my fault.
I messed up with calendar permissions and my test user had a reviewer permission instead of an author one on the calendar I had to write to
once I was able to identify this issue and change the permission the call response was what expected.
I leave this answer as a reference for anyone that encounter this issue
Thanks anyway

How to add subscriber role and publisher role to deadletter for google cloud pubsub using nodeJS?

We've been following https://cloud.google.com/pubsub/docs/dead-letter-topics and nodeJS client to create, update our pubsub topics and subscriptions but after following:
async function createSubscriptionWithDeadLetterPolicy() {
// Creates a new subscription
await pubSubClient.topic(topicName).createSubscription(subscriptionName, {
deadLetterPolicy: {
deadLetterTopic: pubSubClient.topic(deadLetterTopicName).name,
maxDeliveryAttempts: 10,
},
});
console.log(
`Created subscription ${subscriptionName} with dead letter topic ${deadLetterTopicName}.`
);
console.log(
'To process dead letter messages, remember to add a subscription to your dead letter topic.'
);
}
We get this in the dead-letter
This Suggests running the command in CLI for each dead-letter but we don't want to do it manually for each subscription is there a way to do this in nodeJS client itself?
Or doing so for all the subscriptions once and for all even for the new subscriptions that will be created in given project later on.
According to this part of the documentation, you need to grant 2 roles to the PubSub service agent service account. And of course, you can do it by API calls. And, it's not so easy!
In fact, it's not difficult, just boring! Why? Because, you can't only "add" a policy, you set the whole policies. To achieve this:
Get all the existing policies
Add your policy in the existing list
Submit the new list of policies.
You need to do this:
Either globally by setting the policies at the project level. Easier but less secure (break the least privilege principle)
Or on each Dead Letter topic and on each subscription with Dead Letter set up.
You have code example in the Client library doc
EDIT1
If you script the grant access mechanism, you don't care to find it or not: it exists, that's all! Maybe you don't view it on the console, but it exists. Only the pattern is important:
service-<project-number>#gcp-sa-pubsub.iam.gserviceaccount.com
If you are looking for it on the console, it's tricky now! You have to go to Access -> IAM. And then click on the check box on the top rigth corner to display the Google technical accounts
In case anyone needs it, here are the functions that I made up from #guillaume blaquiere's answer:
private async bindPolicyToSubscriber(
subscriptionTopicName: string,
subscriptionName: string,
) {
if (process.env.PROJECT_NUMBER) {
try {
const pubSubTopic = this.getClient().topic(subscriptionTopicName);
const myPolicy = {
bindings: [
{
role: 'roles/pubsub.subscriber',
members: [
`serviceAccount:service-${process.env.PROJECT_NUMBER}#gcp-sa-pubsub.iam.gserviceaccount.com`,
],
},
],
};
await pubSubTopic
.subscription(subscriptionName)
.iam.setPolicy(myPolicy);
} catch (e) {
console.error('Error while binding policy.', e);
}
}
}
private async bindPolicyToDeadLetterTopic(deadLetterTopicName: string) {
if (process.env.PROJECT_NUMBER) {
try {
const pubSubTopic = this.getClient().topic(deadLetterTopicName);
const myPolicy = {
bindings: [
{
role: 'roles/pubsub.publisher',
members: [
`serviceAccount:service-${process.env.PROJECT_NUMBER}#gcp-sa-pubsub.iam.gserviceaccount.com`,
],
},
],
};
await pubSubTopic.iam.setPolicy(myPolicy);
} catch (e) {
console.error('Error while binding policy.', e);
}
}
}

Firebase Realtime Database Rules Denying Permission

I have an application I am building in Kotlin, with a backend in Node.js.
I am allowing users to login/signup using Firebase Authentication on the client application.
Part of the functionality of the application, is to let users save data online through Firebase's real time database. What happens inside the application, is once a user is logged in, I am passing his/her uid to the backend, which makes a request to the database.
Everything was working fine when the rules for the database were to allow read/write to everyone.
Once I changed them to this:
{
"rules": {
"users": {
".read": "auth != null && auth.uid != null",
".write": "auth != null && auth.uid != null",
}
}
}
I keep getting Permission Denied.
I have tried different variations of the rules:
Without the users key
Only checking that auth is not null
but none seem to work.
Is there some step I am missing?
I have combed over many similar StackOverflow questions and Firebase's real time database documentation, but have not found an answer to my problem.
Some code for reference:
Backend:
app.get('/someRoute', function (req, res) {
var database = firebase.database()
var uid = req.query.uid
database.ref('/users/' + uid).once('value')
.then(function(snapshot) {
var data = snapshot.val() ? snapshot.val() : []
res.status(200).send({ response: data})
}).catch(function(error) {
console.log(error)
res.status(500).json({ error: error})
})
})
Client:
fun loginUser(view : View) {
FirebaseAuth.getInstance().signInWithEmailAndPassword(userEmail, userPassword)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
updateFirebaseUserDisplayName()
} else {
Toast.makeText(this, "An error has occurred during login. Please try again later.", Toast.LENGTH_SHORT).show()
}
}
}
fun updateFirebaseUserDisplayName() {
FirebaseAuth.getInstance().currentUser?.apply {
val profileUpdates : UserProfileChangeRequest = UserProfileChangeRequest.Builder().setDisplayName(userEmail).build()
updateProfile(profileUpdates)?.addOnCompleteListener(OnCompleteListener {
when(it.isSuccessful) {
true -> apply {
Intent(this#LoginActivity, MainActivity::class.java).apply {
startActivity(this)
finish()
}
}
false -> Toast.makeText(this#LoginActivity, "Login has failed", Toast.LENGTH_SHORT).show()
}
})
}
}
After some searching, I found the solution to my problem.
It appears that because I was authenticating users on the client and having a backend that communicated with Firebase's Realtime Database, I had to use Firebase's Admin SDK in the backend.
This is because it was required to pass a unique token generated each time a user logs in and authenticates in the client. This token is then required to be sent to the backend and used when trying to access the Realtime Database.
For anyone else that will stumble upon this question and want to know how it can be done, follow the links below:
Adding Firebase Admin SDK
Verifying ID Tokens
Medium Article Explaining Everything
Also, make sure to reference your database name correctly
It seems a problem with the permission you have given to your node i.e users and try below way
Only authenticated users can access/write data
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}

Slack bot fails to send message to restricted general channel via chat.postMessage

This is my first time trying to create a slack bot and I am following this template code to the word, I have not made any changes, and just remixed on glitch, copy-pasted the auth tokens correctly, things worked just fine.
That is until I made the #general channel restricted for Full Member users.
This is the error I see in the logs at glitch.
PostMessage Error: restricted_action
Is there an additional scope that I need to set, other than bot ?
Here is the workspace user permissions, I am the owner for this workspace.
Here is the code:
const postAnnouncementToChannel = (user, announcement) => {
const { title, details, channel } = announcement;
let announcementData = {
token: process.env.SLACK_ACCESS_TOKEN,
channel: channel,
text: `:loudspeaker: Announcement from: <#${user}>`,
attachments: JSON.stringify([
{
title: title,
text: details,
footer: 'DM me to make announcements.'
}
])
};
send(announcementData, user);
}
const send = async(data) => {
data.as_user = true; // send DM as a bot, not Slackbot
const result = await axios.post(`${apiUrl}/chat.postMessage`, qs.stringify(data))
try {
if(result.data.error) console.log(`PostMessage Error: ${result.data.error}`);
} catch(err) {
console.log(err);
}
}
Testing it via
https://api.slack.com/methods/chat.postMessage/test
using bot-token says
{
"ok": false,
"error": "restricted_action"
}
Testing this using xoxp-token gives this:-
{
"ok": false,
"error": "missing_scope",
"needed": "chat:write:user",
"provided": "identify,bot"
}
No. You are not missing any scopes. Its just that the user you used to auth your app can not post into the general channel. Apparently admins have restricted who can post messages in that channel, e.g. to admins only.
Either use a user that has posting rights for that channel to auth your app or switch to a different channel for your testing.
Bots are not full members so I had to use user token
xoxp-token
to post to chat.postmessage, with
as_user:false
and had to add a missing_scope that is
chat:write:user
And then I was able to make this work correctly.
Credit goes to #girliemac for helping out on this one.
https://github.com/slackapi/template-announcement-approvals/issues/6
Thanks

Is there a way to prevent users from editing the local storage session?

I am creating a relational blog where I make use of ember_simple_auth:session to store the session like
{"authenticated":{"authenticator":"authenticator:devise","token":"rh2f9iy7EjJXESAM5koQ","email":"user#example.com","userId":1}}
However, on the developer tools on Chrome (and possibly on other browsers), it is quite easy to edit the email and userId in order to impersonate another user upon page reload.
EDIT #1
From the conversation with Joachim and Nikolaj, I now realized that the best way to tackle this problem is to probe the localStorage authenticity every time I need it (which is only on page reload) instead of attempting to prevent edits.
In order to validate authenticity, I create a promise that must be solved before the AccountSession can be used. The promise serverValidation() requests to create a token model with the current localStorage info, and when the server gets it, it validates the info and responds 200 with a simple user serialization with type as token if the information is legit. You can check more info on the Source Code.
Session Account
import Ember from 'ember';
const { inject: { service }, RSVP } = Ember;
export default Ember.Service.extend ({
session: service('session'),
store: service(),
serverValidation: false,
// Create a Promise to handle a server request that validates the current LocalStorage
// If valid, then set SessionAccount User.
loadCurrentUser() {
if (!Ember.isEmpty(this.get('session.data.authenticated.userId'))) {
this.serverValidation().then(() => {
return new RSVP.Promise((resolve, reject) => {
const userId = this.get('session.data.authenticated.userId');
// Get User to Session-Account Block
if(this.get('serverValidation') === true) {
return this.get('store').find('user', userId).then((user) => {
this.set('user', user);
resolve();
}).catch((reason) => {
console.log(reason.errors);
var possible404 = reason.errors.filterBy('status','404');
var possible500 = reason.errors.filterBy('status','500');
if(possible404.length !== 0) {
alert('404 | Sign In Not Found Error');
this.get('session').invalidate();
}
else if(possible500.length !== 0) {
alert('500 | Sign In Server Error');
this.get('session').invalidate();
}
reject();
});
}
else{
alert('Session for Server Validation failed! Logging out!');
this.get('session').invalidate();
resolve();
}
});
});
} else {
// Session is empty...
}
},
serverValidation() {
return new RSVP.Promise((resolve) => {
var tokenAuthentication = this.get('store').createRecord('token', {
id: this.get('session.data.authenticated.userId'),
email: this.get('session.data.authenticated.email'),
authenticity_token: this.get('session.data.authenticated.token'),
});
tokenAuthentication.save().then(() => {
this.set('serverValidation',true);
console.log('Server Validation complete with 200');
resolve();
}).catch((reason) => {
this.set('serverValidation',false);
resolve();
});
});
}
});
Token Controller
# Users Controller: JSON response through Active Model Serializers
class Api::V1::TokensController < ApiController
respond_to :json
def create
if token_by_id == token_by_token
if token_by_email == token_by_id
render json: token_by_id, serializer: TokenSerializer, status: 200
else
render json: {}, status: 404
end
else
render json: {}, status: 404
end
end
private
def token_by_id
User.find(user_params[:id])
end
def token_by_email
User.find_by(email: user_params[:email])
end
def token_by_token
User.find_by(authentication_token: user_params[:authenticity_token])
end
def user_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(params.to_unsafe_h)
end
end
There is no way to prevent a user from editing the content of his local storage, session storage, or cookies.
But this should not worry you. The user is identified through the value of the token. The token is generated and sent to him by the authenticator when he logs in. To impersonate another user by editing the session data he would have to know that the other user is logged in, and know the token of that user.
Token is already signed on the server side, a standard JWT mechanism.
Having said that, there can be a couple of ways to check tempering in local storage:
Generate a token the way you already do.
Generate a random secret key to be kept on the server.
Generate a corresponding HMAC using this secret key.
Send the token + HMAC to the user.
When the user sends you this token, first check if HMAC is correct, if not then reject the token right away.
If HMAC is correct, validate the token the way you already do.
Another way:
Along with the token, a HMAC checksum too can be stored separately, and when sent back to the server by the client, check if checksum matches.

Resources