Skip to content

Instantly share code, notes, and snippets.

@nathan130200
Created January 16, 2019 22:42
Show Gist options
  • Save nathan130200/715243c6d4eb2d4894b6675c96527a71 to your computer and use it in GitHub Desktop.
Save nathan130200/715243c6d4eb2d4894b6675c96527a71 to your computer and use it in GitHub Desktop.
WarfaceBot in C# with UseProtect.
using agsXMPP;
using agsXMPP.protocol.tls;
using agsXMPP.Xml;
using agsXMPP.Xml.Dom;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using URI = agsXMPP.Uri;
namespace Warface
{
class Program
{
static void Main(string[] args)
{
var conn = new WarfaceConnection("game.warface.levelupgames.com.br");
conn.Open();
while (true)
{
}
}
}
public class WarfaceSession
{
public string Id { get; set; }
public bool IsAuthenticated { get; private set; }
public bool IsTlsStarted { get; private set; }
public bool IsBinded { get; private set; }
public Jid Jid { get; private set; }
public void Authenticate(string username, string server)
{
this.Jid = new Jid(username, server, "GameClient");
this.IsAuthenticated = true;
}
public void Bind(string resource)
{
this.Jid.Resource = resource;
this.IsBinded = true;
}
public void StartTls()
{
this.IsTlsStarted = true;
}
}
public class WarfaceConnection
{
public WarfaceSession Session { get; private set; }
internal TcpClient _client;
internal string _host;
internal int _port;
internal Stream _stream;
internal StreamParser _parser;
internal string _domain = "warface";
internal bool _use_protect = true;
internal volatile bool _are_write = false;
internal volatile bool _are_read = false;
internal volatile bool _should_read = true;
internal volatile bool _closed = false;
public WarfaceConnection(string host, int port = 5222)
{
_host = host;
_port = port;
_client = new TcpClient();
_parser = new StreamParser();
_parser.OnStreamStart += OnStreamStart;
_parser.OnStreamElement += OnStreamElement;
_parser.OnStreamEnd += OnStreamEnd;
_parser.OnStreamError += OnError;
_parser.OnError += OnError;
this.Session = new WarfaceSession();
}
public void Open()
{
_client.BeginConnect(Dns.GetHostAddresses(_host), _port, OnConnect, null);
}
void OnStreamStart(object sender, Node node)
{
Console.WriteLine("stream start.");
var st = ((agsXMPP.protocol.Stream)node);
Session.Id = st.Attribute("id");
}
void OnStreamEnd(object sender, Node node)
{
Console.WriteLine("stream end.");
Close();
}
bool _requested_tls;
void OnStreamElement(object sender, Node node)
{
Console.WriteLine("recv <<:\n{0:I}\n", node);
if(node is Element element)
{
if(element.TagName == "features" && element.Prefix == "stream")
{
var has_starttls = element.SelectSingleElement("starttls", URI.TLS) != null;
if (has_starttls)
{
Send(new StartTls());
_requested_tls = true;
}
}
if(element is Proceed _)
{
while (_are_write) ;
_should_read = false;
this.StartTls();
}
}
}
void OnError(object sender, Exception ex)
{
Console.WriteLine(ex);
}
public void Send(Element element)
=> Send(element.ToString());
public void Send(string raw)
=> Send(Encoding.UTF8.GetBytes(raw));
public void Send(byte[] data)
{
while (_are_write) ;
if (!_use_protect)
{
_stream.BeginWrite(data, 0, data.Length, OnWrite, null);
}
else
{
using (var ms = new MemoryStream())
using (var bw = new BinaryWriter(ms))
{
bw.Write(MAGIC);
bw.Write(data.LongLength);
bw.Write(data, 0, data.Length);
_stream.BeginWrite(data, 0, data.Length, OnWrite, null);
}
}
}
public void Close()
{
if (_closed)
return;
while (_are_write) ;
_are_write = false;
_should_read = false;
_closed = true;
_stream.Dispose();
_stream = null;
_client.Close();
_client.Dispose();
_client = null;
}
public void Reset()
{
_should_read = true;
_parser.Reset();
Console.WriteLine("reset.");
this.ReadAsync();
}
public void StartTls()
{
_should_read = false;
while (_are_write && _are_read) ;
_stream = new SslStream(_stream, true, (sender, cert, chain, policy) =>
{
Console.WriteLine("cert <<@<< {0}, {1} ({2}).", cert.Subject, cert.GetKeyAlgorithm(), policy);
return true;
});
((SslStream)_stream).AuthenticateAsClient(_host);
Session.StartTls();
Reset();
}
void OnConnect(IAsyncResult ar)
{
_stream = _client.GetStream();
this.SendStreamStart();
this.ReadAsync();
}
void SendStreamStart()
{
var stbl = new StringBuilder()
.Append("<?xml version='1.0'?>")
.AppendFormat("<stream:stream to='{0}' ", _domain)
.Append("version='1.0' ")
.Append("xml:lang='en' ")
.AppendFormat("xmlns='{0}' ", URI.CLIENT)
.AppendFormat("xmlns:stream='{0}'>", URI.STREAM);
Console.WriteLine("send >>:\n{0:I}\n", stbl);
Send(stbl.ToString());
}
void ReadAsync()
{
while (_are_read) ;
if (!_use_protect)
{
var buf = new byte[1024];
_stream.BeginRead(buf, 0, buf.Length, OnRead, buf);
}
else
{
var protect = new OnlineProtect();
_stream.BeginRead(protect.Header, 0, protect.Header.Length, OnRead, protect);
}
}
void OnWrite(IAsyncResult ar)
{
_stream.EndWrite(ar);
_are_write = false;
}
void OnRead(IAsyncResult ar)
{
var read = _stream.EndRead(ar);
_are_read = false;
if (read > 0)
{
if (!_use_protect)
{
var buf = (byte[])ar.AsyncState;
if (read > 0)
{
_parser.Push(buf, 0, read);
if (_should_read)
{
_stream.BeginRead(buf, 0, buf.Length, OnRead, buf);
_are_read = true;
}
else
return;
}
}
else
{
var protect = (OnlineProtect)ar.AsyncState;
if (protect.IsProtected)
{
using (var ms = new MemoryStream(protect.Header))
using (var br = new BinaryReader(ms))
{
var magic = br.ReadUInt32();
var size = br.ReadInt64();
if (magic != MAGIC)
throw new InvalidDataException($"Must be valid magic {MAGIC}");
protect.IsProtected = false;
protect.Buffer = new byte[size];
Console.WriteLine("header <<: {0} # {1}\n", magic, size);
if (_should_read)
{
_stream.BeginRead(protect.Buffer, 0, protect.Buffer.Length, OnRead, protect);
_are_read = true;
}
}
}
else
{
_parser.Push(protect.Buffer, 0, protect.Buffer.Length);
if (_should_read)
{
protect = new OnlineProtect();
_stream.BeginRead(protect.Header, 0, protect.Header.Length, OnRead, protect);
_are_read = true;
}
}
}
}
else
{
Close();
}
}
public const uint MAGIC = 4277001901;
}
public class OnlineProtect
{
public bool IsProtected { get; set; } = true;
public byte[] Header { get; set; } = new byte[12];
public byte[] Buffer { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment