summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go')
-rw-r--r--vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go210
1 files changed, 210 insertions, 0 deletions
diff --git a/vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go b/vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go
new file mode 100644
index 00000000..ddcd1af6
--- /dev/null
+++ b/vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go
@@ -0,0 +1,210 @@
+// The GsBot package contains some useful utilites for working with the
+// steam package. It implements authentication with sentries, server lists and
+// logging messages and events.
+//
+// Every module is optional and requires an instance of the GsBot struct.
+// Should a module have a `HandlePacket` method, you must register it with the
+// steam.Client with `RegisterPacketHandler`. Any module with a `HandleEvent`
+// method must be integrated into your event loop and should be called for each
+// event you receive.
+package gsbot
+
+import (
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "net"
+ "os"
+ "path"
+ "reflect"
+ "time"
+
+ "github.com/Philipp15b/go-steam"
+ "github.com/Philipp15b/go-steam/netutil"
+ "github.com/Philipp15b/go-steam/protocol"
+ "github.com/davecgh/go-spew/spew"
+)
+
+// Base structure holding common data among GsBot modules.
+type GsBot struct {
+ Client *steam.Client
+ Log *log.Logger
+}
+
+// Creates a new GsBot with a new steam.Client where logs are written to stdout.
+func Default() *GsBot {
+ return &GsBot{
+ steam.NewClient(),
+ log.New(os.Stdout, "", 0),
+ }
+}
+
+// This module handles authentication. It logs on automatically after a ConnectedEvent
+// and saves the sentry data to a file which is also used for logon if available.
+// If you're logging on for the first time Steam may require an authcode. You can then
+// connect again with the new logon details.
+type Auth struct {
+ bot *GsBot
+ details *LogOnDetails
+ sentryPath string
+ machineAuthHash []byte
+}
+
+func NewAuth(bot *GsBot, details *LogOnDetails, sentryPath string) *Auth {
+ return &Auth{
+ bot: bot,
+ details: details,
+ sentryPath: sentryPath,
+ }
+}
+
+type LogOnDetails struct {
+ Username string
+ Password string
+ AuthCode string
+ TwoFactorCode string
+}
+
+// This is called automatically after every ConnectedEvent, but must be called once again manually
+// with an authcode if Steam requires it when logging on for the first time.
+func (a *Auth) LogOn(details *LogOnDetails) {
+ a.details = details
+ sentry, err := ioutil.ReadFile(a.sentryPath)
+ if err != nil {
+ a.bot.Log.Printf("Error loading sentry file from path %v - This is normal if you're logging in for the first time.\n", a.sentryPath)
+ }
+ a.bot.Client.Auth.LogOn(&steam.LogOnDetails{
+ Username: details.Username,
+ Password: details.Password,
+ SentryFileHash: sentry,
+ AuthCode: details.AuthCode,
+ TwoFactorCode: details.TwoFactorCode,
+ })
+}
+
+func (a *Auth) HandleEvent(event interface{}) {
+ switch e := event.(type) {
+ case *steam.ConnectedEvent:
+ a.LogOn(a.details)
+ case *steam.LoggedOnEvent:
+ a.bot.Log.Printf("Logged on (%v) with SteamId %v and account flags %v", e.Result, e.ClientSteamId, e.AccountFlags)
+ case *steam.MachineAuthUpdateEvent:
+ a.machineAuthHash = e.Hash
+ err := ioutil.WriteFile(a.sentryPath, e.Hash, 0666)
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+// This module saves the server list from ClientCMListEvent and uses
+// it when you call `Connect()`.
+type ServerList struct {
+ bot *GsBot
+ listPath string
+}
+
+func NewServerList(bot *GsBot, listPath string) *ServerList {
+ return &ServerList{
+ bot,
+ listPath,
+ }
+}
+
+func (s *ServerList) HandleEvent(event interface{}) {
+ switch e := event.(type) {
+ case *steam.ClientCMListEvent:
+ d, err := json.Marshal(e.Addresses)
+ if err != nil {
+ panic(err)
+ }
+ err = ioutil.WriteFile(s.listPath, d, 0666)
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+func (s *ServerList) Connect() (bool, error) {
+ return s.ConnectBind(nil)
+}
+
+func (s *ServerList) ConnectBind(laddr *net.TCPAddr) (bool, error) {
+ d, err := ioutil.ReadFile(s.listPath)
+ if err != nil {
+ s.bot.Log.Println("Connecting to random server.")
+ s.bot.Client.Connect()
+ return false, nil
+ }
+ var addrs []*netutil.PortAddr
+ err = json.Unmarshal(d, &addrs)
+ if err != nil {
+ return false, err
+ }
+ raddr := addrs[rand.Intn(len(addrs))]
+ s.bot.Log.Printf("Connecting to %v from server list\n", raddr)
+ s.bot.Client.ConnectToBind(raddr, laddr)
+ return true, nil
+}
+
+// This module logs incoming packets and events to a directory.
+type Debug struct {
+ packetId, eventId uint64
+ bot *GsBot
+ base string
+}
+
+func NewDebug(bot *GsBot, base string) (*Debug, error) {
+ base = path.Join(base, fmt.Sprint(time.Now().Unix()))
+ err := os.MkdirAll(path.Join(base, "events"), 0700)
+ if err != nil {
+ return nil, err
+ }
+ err = os.MkdirAll(path.Join(base, "packets"), 0700)
+ if err != nil {
+ return nil, err
+ }
+ return &Debug{
+ 0, 0,
+ bot,
+ base,
+ }, nil
+}
+
+func (d *Debug) HandlePacket(packet *protocol.Packet) {
+ d.packetId++
+ name := path.Join(d.base, "packets", fmt.Sprintf("%d_%d_%s", time.Now().Unix(), d.packetId, packet.EMsg))
+
+ text := packet.String() + "\n\n" + hex.Dump(packet.Data)
+ err := ioutil.WriteFile(name+".txt", []byte(text), 0666)
+ if err != nil {
+ panic(err)
+ }
+
+ err = ioutil.WriteFile(name+".bin", packet.Data, 0666)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (d *Debug) HandleEvent(event interface{}) {
+ d.eventId++
+ name := fmt.Sprintf("%d_%d_%s.txt", time.Now().Unix(), d.eventId, name(event))
+ err := ioutil.WriteFile(path.Join(d.base, "events", name), []byte(spew.Sdump(event)), 0666)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func name(obj interface{}) string {
+ val := reflect.ValueOf(obj)
+ ind := reflect.Indirect(val)
+ if ind.IsValid() {
+ return ind.Type().Name()
+ } else {
+ return val.Type().Name()
+ }
+}