
Research
PyPI Package Disguised as Instagram Growth Tool Harvests User Credentials
A deceptive PyPI package posing as an Instagram growth tool collects user credentials and sends them to third-party bot services.
server-client
Advanced tools
Node.js client for agar.io with API.
npm install agario-client
(ignore python
errors)node ./node_modules/agario-client/examples/basic.js
(for testing purpose)There are two types of object that have API:
Ball
, you need to talk with Client
Client
creates. Everything in game is Balls
(viruses/food/players...). You can't control Balls
objects, only observe what they do.Both objects have same methods for events from events.EventEmitter:
.on('eventName', callback)
attach listener to event.once('eventName', callback)
attach listener to event but execute only once.removeListener('eventName', callback)
remove listener from event.removeAllListeners('eventName')
remove all listeners from event.emit('eventName', p1, p2...)
emit your own eventvar AgarioClient = require('agario-client');
var client = new AgarioClient(client_name);
client_name is string for client that will be used for logging (if you enable it). It's not your ball name.
Properties that you can change:
client.debug
debug level. 0-5. 0 is completely silent. 5 is super verbose. Default: 1client.server
address that was used in client.connect()
callclient.key
key that was used in client.connect()
callclient.auth_token
token to login. See how to get token in additional info.client.auth_provider
provider to login. 1 for facebook, 2 for google. Default: 1client.agent
agent to use for connection. Check additional info.client.local_address
local interface to bind to for network connections (IP address of interface)client.headers
object with headers for WebSocket connection. Default: {'Origin':'http://agar.io'}client.inactive_destroy
time in ms for how long ball will live in memory after his last known action (if player exit from game or ball eaten outside our field of view, we will not know it since server sends action only about field that you see. Original code destroy()
Ball
when he disappear
from field of view. You can do that in client.on('ballDisppear')
if you want it for some reason). Default: 5*60*1000 (5 minutes)client.inactive_check
time in ms for time interval that search and destroy inactive Balls
. Default: 10*1000 (10 seconds)client.spawn_attempts
how much we need try spawn before disconnect (made for unstable spawn on official servers). Default: 25client.spawn_interval
time in ms between spawn attempts. Default: 200Properties that better not to change or you can break something:
client.balls
object with all Balls
that client
knows about. Access Ball
like client.balls[ball_id]
client.my_balls
array of alive Ball
's IDs that client
owns and can control.client.score
personal score since spawnclient.leaders
array of leader's Balls
IDs in FFA mode. (player can have lots of Balls
, but sever sends only one ID of one Ball
)client.teams_scores
array of team's scores in teams modeclient.client_name
name that you have set for client
(not nickname)client.tick_counter
number of tick packets received (i call them ticks because they contains information about eating/movement/size/disappear... of Balls
)client.connect(server, key)
connect to agar.io server. Check Servers part in this readme to see how to get server IP and key. ProTip: each server have few rooms (if it is not party), so you may need connect few times before you will get in room that you want (but you need new key each time and agar.io can ban your IP for flooding with requests). You can look client.once('leaderBoardUpdate')
to know if you're connected to correct roomclient.disconnect()
disconnect from serverclient.spawn(name)
will spawn Ball
with nickname. client.on('myNewBall')
will be called when server sends our Ball
info. Will return false
if connection is not established.client.spectate()
will activate spectating mode. Look at client.on('spectateFieldUpdate')
for FOV updates. Will return false
if connection is not established.client.spectateModeToggle()
switching spectate mode in spectating mode (Q key in official client). Use client.moveTo()
to move your "camera" around. Look at client.on('spectateFieldUpdate')
for movement updates. Will return false
if connection is not established.client.moveTo(x,y)
send move command. x
and y
is numbers where you want to move. Coordinates (size) of map you can get in client.on('mapSizeLoad')
. Your Balls
will move to coordinates you specified until you send new coordinates to move. Original source code do this every 100ms (10 times in second) and before split and eject. Will return false
if connection is not established.client.split()
will split your Balls
in two. Ball
will be ejected in last direction that you sent with client.moveTo()
. client.on('myNewBall')
will be called when server sends our Balls
info. Will return false
if connection is not established.client.eject()
will eject some mass from your Balls
. Mass will be ejected in last direction that you sent with client.moveTo()
. Ejected mass is Ball
too (but we don't own them). So client.on('ballAppear')
will be called when server sends ejected mass Balls
info. Will return false
if connection is not established.In this list on.eventName(param1, param2)
means you need to do client.on('eventName', function(param1, param2) { ... })
on.connecting()
connecting to serveron.connected()
connected to server and ready to spawnon.connectionError(err)
connection erroron.disconnect()
disconnectedon.message(packet)
new packet received from server (check packet.js
)on.myNewBall(ball_id)
my new Ball
created (spawn/split/explode...)on.somebodyAteSomething(eater_id, eaten_id)
somebody ate somethingon.scoreUpdate(old_score, new_score)
personal score updatedon.leaderBoardUpdate(old_array, new_array)
leaders update in FFA mode. Array of leader's Ball
's IDs (one ID per leader)on.teamsScoresUpdate(old_scores, new_scores)
array of teams scores update in teams modeon.mapSizeLoad(min_x, min_y, max_x, max_y)
map size update (after connect)on.reset()
when we delete all Balls
and stop timers (connection lost?)on.winner(ball_id)
somebody won and server going for restarton.ballAction(ball_id, coordinate_x, coordinate_y, size, is_virus, nick)
some action about some Ball
on.ballAppear(ball_id)
Ball
appear on "screen" (field of view)on.ballDisppear(ball_id)
Ball
disappear from "screen" (field of view)on.ballDestroy(ball_id, reason)
Ball
deleted (check reasons at the bottom of this document)on.mineBallDestroy(ball_id, reason)
mine (your) Ball
deleted (check reasons at the bottom of this document)on.lostMyBalls()
all mine Balls
destroyed/eatenon.merge(destroyed_ball_id)
mine two Balls
connects into oneon.ballMove(ball_id, old_x, old_y, new_x, new_y)
Ball
moveon.ballResize(ball_id, old_size, new_size)
Ball
resizeon.ballRename(ball_id, old_name, new_name)
Ball
set name/change name/we discover nameon.ballUpdate(ball_id, old_update_time, new_update_time)
new data about ball receivedon.spectateFieldUpdate(cord_x, cord_y, zoom_level)
coordinates of field of view in client.spectate()
modeon.experienceUpdate(level, current_exp, need_exp)
experience information update (if logined with auth token)on.packetError(packet, err, preventCrash)
unable to parse packet. It can mean that agar changed protocol or issue #46. By default client will crash. But if you sure this is not protocol change and it don't need new issue then you need to call preventCrash()
before callback execution ends. I highly recommend to disconnect client
if this error happens.on.debugLine(line_x, line_y)
the server sometimes sends a line for the client to render from your ball to the point though don't expect to see it.var ball = client.balls[ball_id];
ball_id is number that you can get from events
Properties that you can change:
Properties that better not to change or you can break something:
ball.id
ID of Ball
(number)ball.name
nickname of player that own the Ball
ball.x
last known X coordinate of Ball
(if ball.visible
is true
then its current coordinate)ball.y
last known Y coordinate of Ball
(if ball.visible
is true
then its current coordinate)ball.size
last known size of Ball
(if ball.visible
is true
then its current size)ball.mass
mass of ball calculated from ball.size
ball.color
string with color of Ball
ball.virus
if true
then ball is a virus (green thing that explode big balls)ball.mine
if true
then we do own this Ball
ball.client
Client
that knows this Ball
(if not ball.destroyed
)ball.destroyed
if true
then this Ball
no more exists, forget about itball.visible
if true
then we see this Ball
on our "screen" (field of view)ball.last_update
timestamp when we last saw this Ball
ball.update_tick
last tick when we saw this Ball
ball.toString()
will return ball.id
and (ball.name)
if set. So you can log ball
directlyIn this list on.eventName(param1, param2)
means you need to do ball.on('eventName', function(param1, param2) { ... })
on.destroy(reason)
Ball
deleted (check reasons at the bottom of this document)on.move(old_x, old_y, new_x, new_y)
Ball
moveon.resize(old_size, new_size)
Ball
resizeon.update(old_time, new_time)
new data about Ball
receivedon.rename(old_name, new_name)
Ball
change/set name/we discover nameon.appear()
Ball
appear on "screen" (field of view)on.disappear()
Ball
disappear from "screen" (field of view)When you do var AgarioClient = require('agario-client');
you can access AgarioClient.servers
Functions need opt
as options object and cb
as callback function.
All functions can accept:
opt.agent
to use for connection. Check additional info
opt.local_address
local interface to bind to for network connections (IP address of interface)
opt.resolve
set to true
to resolve IP on client side (since SOCKS4 can't accept domain names)
opt.ip
if you resolved m.agar.ip
IP by other way (will cancel opt.resolve
).
servers.getFFAServer(opt, cb)
to request FFA server.opt.region
servers.getTeamsServer(opt, cb)
to request teams server.opt.region
servers.getExperimentalServer(opt, cb)
to request experimental server.opt.region
servers.getPartyServer(opt, cb)
to request party server.opt.party_key
servers.createParty(opt, cb)
to request party server.opt.region
Check region list below in this file.
Callback will be called with single object that can contain:
server
- server's IP:PORT (add ws://
before passing to connect())key
- server's keyerror
- error code (WRONG_HTTP_CODE
/WRONG_DATA_FORMAT
/REQUEST_ERROR
/LOOKUP_FAIL
)error_source
- error object passed from req.on.error
when available (for example when REQUEST_ERROR
happens)res
- response object when available (for example when WRONG_HTTP_CODE
happens)data
- response data string when available (for example when WRONG_DATA_FORMAT
happens)LOOKUP_FAIL
can happen only if opt.lookup
was set to true
and will have only error_source
You can check how examples/basic.js
uses this.
If you want record/repeat or watch in real time what your client doing through web browser, you might want to check agario-devtools
{'reason': 'reset'}
when client
destroys everything (connection lost?){'reason': 'inactive'}
when we didn't saw Ball
for client.inactive_destroy
ms{'reason': 'eaten', 'by': ball_id}
when Ball
got eaten{'reason': 'merge'}
when our Ball
merges with our other Ball
To login into your account you need to request token. You can check example in examples/auth_token.js
First create new AgarioClient.Account
var account = new AgarioClient.Account();
Then you need to login through facebook on http://agar.io then go to http://www.facebook.com/ and get cookies c_user,datr,xs.
Here is list of properties of account
:
requestFBToken()
will set it to 1(+new Date)>account.token_expire
then you need to request new token and use it in new connection to agar.Then you call
account.requestFBToken(function(token, info) {
//If you have `token` then you can set it to `client.auth_token`
// and `client.connect()` to agar server
});
If token
is null, then something went wrong. Check info
which can contain:
Error
of connection errorYou can change default agent for AgarioClient
and AgarioClient.servers
to use for connections. You can use libs to do it. For testing and example i used socks lib. Execute node ./node_modules/agario-client/examples/socks.js
to test it and read examples/socks.js
file to see how to use SOCKS. For proxy you will need to use some other lib.
You can add your own properties/events to clients/balls.
var AgarioClient = require('agario-client');
Client
is located at AgarioClient.prototype.
Ball
is located at AgarioClient.Ball.prototype.
For example:
AgarioClient.Ball.prototype.isMyFriend = function() { ... }; //to call ball.isMyFriend()
AgarioClient.prototype.addFriend = function(ball_id) { ... }; //to call client.addFriend(1234)
Events:
client.on('somebodyAteSomething', function(eater_id, eaten_id) { #eat event
if(client.balls[eaten_id].isMyFriend()) { //if this is my friend
client.emit('friendEaten', eater_id, eaten_id); //emit custom event
}
});
client.on('friendEaten', function(eater_id, friend_id) { //on friend eaten
client.log('My friend got eaten!');
});
Check full example in examples/basic.js
If something is broken, please email me or create issue. I will not know that something is broken until somebody will tell me that.
MIT
FAQs
a test application
The npm package server-client receives a total of 0 weekly downloads. As such, server-client popularity was classified as not popular.
We found that server-client demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
A deceptive PyPI package posing as an Instagram growth tool collects user credentials and sends them to third-party bot services.
Product
Socket now supports pylock.toml, enabling secure, reproducible Python builds with advanced scanning and full alignment with PEP 751's new standard.
Security News
Research
Socket uncovered two npm packages that register hidden HTTP endpoints to delete all files on command.