forked from Philipp15b/go-steam
/
auth.go
105 lines (86 loc) · 3.06 KB
/
auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package steam
import (
"code.google.com/p/goprotobuf/proto"
"crypto/sha1"
. "github.com/macb/go-steam/internal"
"github.com/macb/go-steam/steamid"
"log"
"sync/atomic"
"time"
)
type Auth struct {
client *Client
details *LogOnDetails
}
func (a *Auth) HandlePacket(packet *PacketMsg) {
switch packet.EMsg {
case EMsg_ClientLogOnResponse:
a.handleClientLogOnResponse(packet)
case EMsg_ClientUpdateMachineAuth:
a.handleClientUpdateMachineAuth(packet)
}
}
type LogOnDetails struct {
Username string
Password string
AuthCode string
SentryFileHash []byte
}
// Log on with the given details. You must always specify username and
// password. For the first login, don't set an authcode or a hash and you'll receive an error
// and Steam will send you an authcode. Then you have to login again, this time with the authcode.
// Shortly after logging in, you'll receive a MachineAuthUpdateEvent with a hash which allows
// you to login without using an authcode in the future.
//
// If you don't use Steam Guard, username and password are enough.
func (a *Auth) LogOn(details *LogOnDetails) {
if len(details.Username) == 0 || len(details.Password) == 0 {
panic("Username and password must be set!")
}
logon := new(CMsgClientLogon)
logon.AccountName = &details.Username
logon.Password = &details.Password
if details.AuthCode != "" {
logon.AuthCode = proto.String(details.AuthCode)
}
logon.ShaSentryfile = details.SentryFileHash
logon.ProtocolVersion = proto.Uint32(MsgClientLogon_CurrentProtocol)
atomic.StoreUint64(&a.client.steamId, uint64(steamid.New(0, 1, int32(EUniverse_Public), EAccountType_Individual)))
a.client.Write(NewClientMsgProtobuf(EMsg_ClientLogon, logon))
}
type LoggedOnEvent struct{}
func (a *Auth) handleClientLogOnResponse(packet *PacketMsg) {
if !packet.IsProto {
a.client.Fatalf("Got non-proto logon response!")
return
}
body := new(CMsgClientLogonResponse)
msg := packet.ReadProtoMsg(body)
result := EResult(body.GetEresult())
log.Println(result)
if result == EResult_OK {
atomic.StoreInt32(&a.client.sessionId, msg.Header.Proto.GetClientSessionid())
atomic.StoreUint64(&a.client.steamId, msg.Header.Proto.GetSteamid())
go a.client.heartbeatLoop(time.Duration(body.GetOutOfGameHeartbeatSeconds()))
a.client.Emit(&LoggedOnEvent{})
} else if result == EResult_Fail || result == EResult_ServiceUnavailable || result == EResult_TryAnotherCM {
// some error on Steam's side, we'll get an EOF later
} else {
a.client.Fatalf("Login error: %v", result)
}
}
type MachineAuthUpdateEvent struct {
Hash []byte
}
func (a *Auth) handleClientUpdateMachineAuth(packet *PacketMsg) {
body := new(CMsgClientUpdateMachineAuth)
hash := sha1.New()
hash.Write(body.GetBytes())
sha := hash.Sum(nil)
msg := NewClientMsgProtobuf(EMsg_ClientUpdateMachineAuthResponse, &CMsgClientUpdateMachineAuthResponse{
ShaFile: sha,
})
msg.SetTargetJobId(packet.SourceJobId)
a.client.Write(msg)
a.client.Emit(&MachineAuthUpdateEvent{sha})
}