Mike 3 лет назад
Родитель
Сommit
9ebb30655c
5 измененных файлов с 107 добавлено и 38 удалено
  1. 23 16
      cmd/main.go
  2. 12 11
      oscar/bucp.go
  3. 5 4
      oscar/oservice.go
  4. 32 7
      oscar/protocol.go
  5. 35 0
      oscar/session.go

+ 23 - 16
cmd/main.go

@@ -13,7 +13,9 @@ import (
 
 func main() {
 
-	go listenBOS()
+	sm := oscar.NewSessionManager()
+
+	go listenBOS(sm)
 	go listenStats()
 	go listenAlert()
 	go listenOdir()
@@ -39,7 +41,7 @@ func main() {
 		}
 
 		// Handle connection in a separate goroutine
-		go handleAuthConnection(conn)
+		go handleAuthConnection(sm, conn)
 	}
 }
 
@@ -54,7 +56,7 @@ func webServer(ch chan string) {
 	}
 }
 
-func listenBOS() {
+func listenBOS(sm *oscar.SessionManager) {
 	// Listen on TCP port 5190
 	listener, err := net.Listen("tcp", ":5191")
 	if err != nil {
@@ -76,7 +78,7 @@ func listenBOS() {
 			continue
 		}
 		seq := uint32(100)
-		go handleBOSConnection(conn, &seq)
+		go handleBOSConnection(sm, conn, &seq)
 		go sendIM(conn, ch, &seq)
 	}
 }
@@ -116,7 +118,7 @@ func listenStats() {
 
 		fmt.Println("got a connection on listenStats")
 		seq := uint32(100)
-		if err := oscar.ReadBos(conn, &seq); err != nil {
+		if err := oscar.ReadBos(nil, conn, &seq); err != nil {
 			if err == io.EOF {
 				break
 			} else {
@@ -148,7 +150,7 @@ func listenAlert() {
 
 		fmt.Println("got a connection on listenAlert")
 		seq := uint32(100)
-		if err := oscar.ReadBos(conn, &seq); err != nil && err != io.EOF {
+		if err := oscar.ReadBos(nil, conn, &seq); err != nil && err != io.EOF {
 			if err == io.EOF {
 				break
 			} else {
@@ -180,7 +182,7 @@ func listenOdir() {
 
 		fmt.Println("got a connection on listenOdir")
 		seq := uint32(100)
-		if err := oscar.ReadBos(conn, &seq); err != nil {
+		if err := oscar.ReadBos(nil, conn, &seq); err != nil {
 			if err == io.EOF {
 				break
 			} else {
@@ -191,32 +193,37 @@ func listenOdir() {
 	}
 }
 
-func handleAuthConnection(conn net.Conn) {
+func handleAuthConnection(sm *oscar.SessionManager, conn net.Conn) {
 	defer conn.Close()
 	seq := uint32(100)
-	err := oscar.SendAndReceiveSignonFrame(conn, &seq)
+	_, err := oscar.SendAndReceiveSignonFrame(conn, &seq)
 	if err != nil {
 		log.Println(err)
 		return
 	}
 
-	err = oscar.ReceiveAndSendAuthChallenge(conn, conn, &seq)
+	sess, err := sm.NewSession()
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+
+	err = oscar.ReceiveAndSendAuthChallenge(sess, conn, conn, &seq)
 	if err != nil {
 		log.Println(err)
 		return
 	}
 
-	err = oscar.ReceiveAndSendBUCPLoginRequest(conn, conn, &seq)
+	err = oscar.ReceiveAndSendBUCPLoginRequest(sess, conn, conn, &seq)
 	if err != nil {
 		log.Println(err)
 		return
 	}
 }
 
-func handleBOSConnection(conn net.Conn, seq *uint32) {
-	//defer conn.Close()
-	fmt.Println("SendAndReceiveSignonFrame...")
-	if err := oscar.SendAndReceiveSignonFrame(conn, seq); err != nil {
+func handleBOSConnection(sm *oscar.SessionManager, conn net.Conn, seq *uint32) {
+	fmt.Println("VerifyLogin...")
+	sess, err := oscar.VerifyLogin(sm, conn, seq)
+	if err != nil {
 		log.Println(err)
 		return
 	}
@@ -229,7 +236,7 @@ func handleBOSConnection(conn net.Conn, seq *uint32) {
 		}
 	}
 
-	if err := oscar.ReadBos(conn, seq); err != nil && err != io.EOF {
+	if err := oscar.ReadBos(sess, conn, seq); err != nil && err != io.EOF {
 		if err != io.EOF {
 			fmt.Println(err.Error())
 			os.Exit(1)

+ 12 - 11
oscar/bucp.go

@@ -66,7 +66,7 @@ func (s *snacBUCPChallengeResponse) write(w io.Writer) error {
 	return nil
 }
 
-func ReceiveAndSendAuthChallenge(r io.Reader, w io.Writer, sequence *uint32) error {
+func ReceiveAndSendAuthChallenge(s *Session, r io.Reader, w io.Writer, sequence *uint32) error {
 	flap := &flapFrame{}
 	if err := flap.read(r); err != nil {
 		return err
@@ -95,7 +95,7 @@ func ReceiveAndSendAuthChallenge(r io.Reader, w io.Writer, sequence *uint32) err
 		subGroup:  0x07,
 	}
 	snacPayloadOut := &snacBUCPChallengeResponse{
-		authKey: "theauthkey",
+		authKey: s.ID,
 	}
 
 	return writeOutSNAC(snac, flap, snacFrameOut, snacPayloadOut, sequence, w)
@@ -124,7 +124,7 @@ func (s *snacBUCPLoginRequest) read(r io.Reader) error {
 	})
 }
 
-func ReceiveAndSendBUCPLoginRequest(r io.Reader, w io.Writer, sequence *uint32) error {
+func ReceiveAndSendBUCPLoginRequest(sess *Session, r io.Reader, w io.Writer, sequence *uint32) error {
 	flap := &flapFrame{}
 	if err := flap.read(r); err != nil {
 		return err
@@ -148,22 +148,23 @@ func ReceiveAndSendBUCPLoginRequest(r io.Reader, w io.Writer, sequence *uint32)
 
 	fmt.Printf("ReceiveAndSendBUCPLoginRequest read SNAC: %+v\n", snacPayload)
 
+	var found bool
+	sess.screenName, found = snacPayload.getString(TLV_SCREEN_NAME)
+	if !found {
+		return errors.New("unable to find screen name")
+	}
+
 	snacFrameOut := snacFrame{
 		foodGroup: 0x17,
 		subGroup:  0x03,
 	}
 
-	screenName, found := snacPayload.getString(0x01)
-	if !found {
-		return errors.New("unable to find screen name tlv")
-	}
-
 	snacPayloadOut := &snacBUCPLoginRequest{
 		TLVPayload: TLVPayload{
 			TLVs: []*TLV{
 				{
-					tType: 0x01,
-					val:   screenName,
+					tType: TLV_SCREEN_NAME,
+					val:   sess.screenName,
 				},
 				{
 					tType: 0x08,
@@ -179,7 +180,7 @@ func ReceiveAndSendBUCPLoginRequest(r io.Reader, w io.Writer, sequence *uint32)
 				},
 				{
 					tType: 0x06,
-					val:   []byte("thecookie"),
+					val:   []byte(sess.ID),
 				},
 				{
 					tType: 0x11,

+ 5 - 4
oscar/oservice.go

@@ -49,7 +49,7 @@ const (
 	OServiceBartReply2               = 0x0023
 )
 
-func routeOService(flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+func routeOService(sess *Session, flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
 	switch snac.subGroup {
 	case OServiceErr:
 		panic("not implemented")
@@ -74,7 +74,7 @@ func routeOService(flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, s
 	case OServiceResume:
 		panic("not implemented")
 	case OServiceUserInfoQuery:
-		return ReceiveAndSendServiceRequestSelfInfo(flap, snac, r, w, sequence)
+		return ReceiveAndSendServiceRequestSelfInfo(sess, flap, snac, r, w, sequence)
 	case OServiceUserInfoUpdate:
 		panic("not implemented")
 	case OServiceEvilNotification:
@@ -377,15 +377,16 @@ func (s *snacOServiceUserInfoUpdate) write(w io.Writer) error {
 	return s.TLVPayload.write(w)
 }
 
-func ReceiveAndSendServiceRequestSelfInfo(flap *flapFrame, snac *snacFrame, _ io.Reader, w io.Writer, sequence *uint32) error {
+func ReceiveAndSendServiceRequestSelfInfo(sess *Session, flap *flapFrame, snac *snacFrame, _ io.Reader, w io.Writer, sequence *uint32) error {
 	fmt.Printf("receiveAndSendServiceRequestSelfInfo read SNAC frame: %+v\n", snac)
 
 	snacFrameOut := snacFrame{
 		foodGroup: OSERVICE,
 		subGroup:  OServiceUserInfoUpdate,
 	}
+
 	snacPayloadOut := &snacOServiceUserInfoUpdate{
-		screenName:   "myscreenname",
+		screenName:   sess.screenName,
 		warningLevel: 0,
 		TLVPayload: TLVPayload{
 			TLVs: []*TLV{

+ 32 - 7
oscar/protocol.go

@@ -3,6 +3,7 @@ package oscar
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"reflect"
@@ -16,6 +17,10 @@ type flapFrame struct {
 	payloadLength uint16
 }
 
+const (
+	TLV_SCREEN_NAME = 0x01
+)
+
 func (f *flapFrame) write(w io.Writer) error {
 	if err := binary.Write(w, binary.BigEndian, f.startMarker); err != nil {
 		return err
@@ -235,7 +240,7 @@ func (t *TLV) read(r io.Reader, typeLookup map[uint16]reflect.Kind) error {
 type flapSignonFrame struct {
 	flapFrame
 	flapVersion uint32
-	TLVs        []*TLV
+	TLVPayload
 }
 
 func (f *flapSignonFrame) write(w io.Writer) error {
@@ -281,7 +286,7 @@ func (f *flapSignonFrame) read(r io.Reader) error {
 	return nil
 }
 
-func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) error {
+func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) (*flapSignonFrame, error) {
 	// send
 	flap := &flapSignonFrame{
 		flapFrame: flapFrame{
@@ -296,7 +301,7 @@ func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) error {
 	atomic.AddUint32(sequence, 1)
 
 	if err := flap.write(rw); err != nil {
-		return err
+		return nil, err
 	}
 
 	fmt.Printf("SendAndReceiveSignonFrame read FLAP: %+v\n", flap)
@@ -304,12 +309,32 @@ func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) error {
 	// receive
 	flap = &flapSignonFrame{}
 	if err := flap.read(rw); err != nil {
-		return err
+		return nil, err
 	}
 
 	fmt.Printf("SendAndReceiveSignonFrame write FLAP: %+v\n", flap)
 
-	return nil
+	return flap, nil
+}
+
+func VerifyLogin(sm *SessionManager, rw io.ReadWriter, sequence *uint32) (*Session, error) {
+	flap, err := SendAndReceiveSignonFrame(rw, sequence)
+	if err != nil {
+		return nil, err
+	}
+
+	var ok bool
+	ID, ok := flap.getString(OserviceTlvTagsLoginCookie)
+	if !ok {
+		return nil, errors.New("unable to get session ID from payload")
+	}
+
+	sess, ok := sm.Retrieve(ID)
+	if !ok {
+		return nil, errors.New("unable to find session by ID")
+	}
+
+	return sess, nil
 }
 
 const (
@@ -339,7 +364,7 @@ const (
 	ARS                  = 0x044A
 )
 
-func ReadBos(rw io.ReadWriter, sequence *uint32) error {
+func ReadBos(sess *Session, rw io.ReadWriter, sequence *uint32) error {
 	for {
 		// receive
 		flap := &flapFrame{}
@@ -361,7 +386,7 @@ func ReadBos(rw io.ReadWriter, sequence *uint32) error {
 
 		switch snac.foodGroup {
 		case OSERVICE:
-			if err := routeOService(flap, snac, buf, rw, sequence); err != nil {
+			if err := routeOService(sess, flap, snac, buf, rw, sequence); err != nil {
 				return err
 			}
 		case LOCATE:

+ 35 - 0
oscar/session.go

@@ -0,0 +1,35 @@
+package oscar
+
+import "github.com/google/uuid"
+
+type Session struct {
+	ID         string
+	screenName string
+}
+
+type SessionManager struct {
+	store map[string]*Session
+}
+
+func NewSessionManager() *SessionManager {
+	return &SessionManager{
+		store: make(map[string]*Session),
+	}
+}
+
+func (s *SessionManager) Retrieve(ID string) (*Session, bool) {
+	sess, found := s.store[ID]
+	return sess, found
+}
+
+func (s *SessionManager) NewSession() (*Session, error) {
+	id, err := uuid.NewUUID()
+	if err != nil {
+		return nil, err
+	}
+	sess := &Session{
+		ID: id.String(),
+	}
+	s.store[sess.ID] = sess
+	return sess, nil
+}