2021-11-16 16:44:29 -05:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-12-16 18:02:48 -05:00
|
|
|
"bytes"
|
2021-12-16 17:41:17 -05:00
|
|
|
"context"
|
2021-12-16 18:02:48 -05:00
|
|
|
"crypto/md5"
|
2021-12-16 17:41:17 -05:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base32"
|
2021-12-17 19:01:22 -05:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-12-16 18:02:48 -05:00
|
|
|
"io"
|
2021-12-16 17:41:17 -05:00
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
"aim-oscar/models"
|
|
|
|
"aim-oscar/oscar"
|
2021-12-17 19:01:22 -05:00
|
|
|
"aim-oscar/util"
|
2021-12-16 19:45:32 -05:00
|
|
|
|
2021-12-16 17:41:17 -05:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/uptrace/bun"
|
2021-11-16 16:44:29 -05:00
|
|
|
)
|
|
|
|
|
2021-12-16 17:41:17 -05:00
|
|
|
const CIPHER_LENGTH = 64
|
2021-12-16 18:02:48 -05:00
|
|
|
const AIM_MD5_STRING = "AOL Instant Messenger (SM)"
|
2021-12-16 17:41:17 -05:00
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
type AuthorizationRegistrationService struct {
|
|
|
|
}
|
2021-11-16 16:44:29 -05:00
|
|
|
|
2021-12-16 17:41:17 -05:00
|
|
|
func (a *AuthorizationRegistrationService) GenerateCipher() string {
|
|
|
|
randomBytes := make([]byte, 64)
|
|
|
|
_, err := rand.Read(randomBytes)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return base32.StdEncoding.EncodeToString(randomBytes)[:CIPHER_LENGTH]
|
|
|
|
}
|
|
|
|
|
2021-12-17 19:01:22 -05:00
|
|
|
func (a *AuthorizationRegistrationService) HandleSNAC(db *bun.DB, session *oscar.Session, snac *oscar.SNAC) error {
|
2021-12-15 19:55:43 -05:00
|
|
|
switch snac.Header.Subtype {
|
2021-11-16 16:44:29 -05:00
|
|
|
// Request MD5 Auth Key
|
2021-12-15 19:55:43 -05:00
|
|
|
case 0x06:
|
2021-12-16 19:45:32 -05:00
|
|
|
tlvs, err := oscar.UnmarshalTLVs(snac.Data.Bytes())
|
2021-12-17 19:01:22 -05:00
|
|
|
util.PanicIfError(err)
|
2021-12-15 19:55:43 -05:00
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
usernameTLV := oscar.FindTLV(tlvs, 1)
|
2021-12-15 19:55:43 -05:00
|
|
|
if usernameTLV == nil {
|
|
|
|
return errors.New("missing username TLV")
|
|
|
|
}
|
2021-11-16 16:44:29 -05:00
|
|
|
|
2021-12-16 17:41:17 -05:00
|
|
|
// Fetch the user
|
|
|
|
ctx := context.Background()
|
2021-12-17 19:01:22 -05:00
|
|
|
user, err := models.UserByUsername(ctx, db, string(usernameTLV.Data))
|
2021-12-16 17:41:17 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if user == nil {
|
2021-12-16 19:45:32 -05:00
|
|
|
snac := oscar.NewSNAC(0x17, 0x03)
|
2021-12-16 17:41:17 -05:00
|
|
|
snac.Data.WriteBinary(usernameTLV)
|
2021-12-16 19:45:32 -05:00
|
|
|
snac.Data.WriteBinary(oscar.NewTLV(0x08, []byte{0, 4}))
|
|
|
|
resp := oscar.NewFLAP(2)
|
2021-12-16 17:41:17 -05:00
|
|
|
resp.Data.WriteBinary(snac)
|
|
|
|
return session.Send(resp)
|
|
|
|
}
|
|
|
|
|
2021-12-15 19:55:43 -05:00
|
|
|
// Create cipher for this user
|
2021-12-16 17:41:17 -05:00
|
|
|
user.Cipher = a.GenerateCipher()
|
2021-12-17 19:01:22 -05:00
|
|
|
if err = user.Update(ctx, db); err != nil {
|
2021-12-16 17:41:17 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
snac := oscar.NewSNAC(0x17, 0x07)
|
2021-12-16 17:41:17 -05:00
|
|
|
snac.Data.WriteUint16(uint16(len(user.Cipher)))
|
|
|
|
snac.Data.WriteString(user.Cipher)
|
2021-11-16 16:44:29 -05:00
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
resp := oscar.NewFLAP(2)
|
2021-12-16 17:41:17 -05:00
|
|
|
resp.Data.WriteBinary(snac)
|
|
|
|
return session.Send(resp)
|
|
|
|
|
|
|
|
// Client Authorization Request
|
|
|
|
case 0x02:
|
2021-12-16 19:45:32 -05:00
|
|
|
tlvs, err := oscar.UnmarshalTLVs(snac.Data.Bytes())
|
2021-12-17 19:01:22 -05:00
|
|
|
util.PanicIfError(err)
|
2021-12-15 19:55:43 -05:00
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
usernameTLV := oscar.FindTLV(tlvs, 1)
|
2021-12-16 17:41:17 -05:00
|
|
|
if usernameTLV == nil {
|
2021-12-16 18:02:48 -05:00
|
|
|
return errors.New("missing username TLV 0x1")
|
2021-12-16 17:41:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
username := string(usernameTLV.Data)
|
|
|
|
ctx := context.Background()
|
2021-12-17 19:01:22 -05:00
|
|
|
user, err := models.UserByUsername(ctx, db, username)
|
2021-12-16 17:41:17 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if user == nil {
|
2021-12-16 19:45:32 -05:00
|
|
|
snac := oscar.NewSNAC(0x17, 0x03)
|
2021-12-16 17:41:17 -05:00
|
|
|
snac.Data.WriteBinary(usernameTLV)
|
2021-12-16 19:45:32 -05:00
|
|
|
snac.Data.WriteBinary(oscar.NewTLV(0x08, []byte{0, 4}))
|
|
|
|
resp := oscar.NewFLAP(2)
|
2021-12-16 17:41:17 -05:00
|
|
|
resp.Data.WriteBinary(snac)
|
|
|
|
return session.Send(resp)
|
|
|
|
}
|
|
|
|
|
2021-12-16 19:45:32 -05:00
|
|
|
passwordHashTLV := oscar.FindTLV(tlvs, 0x25)
|
2021-12-16 18:02:48 -05:00
|
|
|
if passwordHashTLV == nil {
|
|
|
|
return errors.New("missing password hash TLV 0x25")
|
|
|
|
}
|
|
|
|
|
2021-12-17 19:01:22 -05:00
|
|
|
// Compute password has that we expect the client to send back if the password was right
|
2021-12-16 18:02:48 -05:00
|
|
|
h := md5.New()
|
|
|
|
io.WriteString(h, user.Cipher)
|
|
|
|
io.WriteString(h, user.Password)
|
|
|
|
io.WriteString(h, AIM_MD5_STRING)
|
|
|
|
expectedPasswordHash := h.Sum(nil)
|
|
|
|
|
|
|
|
if !bytes.Equal(expectedPasswordHash, passwordHashTLV.Data) {
|
|
|
|
// Tell the client this was a bad password
|
2021-12-16 19:45:32 -05:00
|
|
|
badPasswordSnac := oscar.NewSNAC(0x17, 0x03)
|
2021-12-16 18:02:48 -05:00
|
|
|
badPasswordSnac.Data.WriteBinary(usernameTLV)
|
2021-12-16 19:45:32 -05:00
|
|
|
badPasswordSnac.Data.WriteBinary(oscar.NewTLV(0x08, []byte{0, 4}))
|
|
|
|
badPasswordFlap := oscar.NewFLAP(2)
|
2021-12-16 18:02:48 -05:00
|
|
|
badPasswordFlap.Data.WriteBinary(badPasswordSnac)
|
|
|
|
session.Send(badPasswordFlap)
|
|
|
|
|
2021-12-17 19:01:22 -05:00
|
|
|
// Tell them to leave
|
2021-12-16 19:45:32 -05:00
|
|
|
discoFlap := oscar.NewFLAP(4)
|
2021-12-16 18:02:48 -05:00
|
|
|
return session.Send(discoFlap)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send BOS response + cookie
|
2021-12-16 19:45:32 -05:00
|
|
|
authSnac := oscar.NewSNAC(0x17, 0x3)
|
2021-12-16 18:02:48 -05:00
|
|
|
authSnac.Data.WriteBinary(usernameTLV)
|
2021-12-17 19:01:22 -05:00
|
|
|
authSnac.Data.WriteBinary(oscar.NewTLV(0x5, []byte(SRV_ADDRESS)))
|
|
|
|
|
|
|
|
cookie, err := json.Marshal(struct {
|
|
|
|
UIN int
|
|
|
|
X string
|
|
|
|
}{
|
|
|
|
UIN: user.UIN,
|
|
|
|
X: fmt.Sprintf("%x", expectedPasswordHash),
|
|
|
|
})
|
|
|
|
util.PanicIfError(err)
|
|
|
|
|
|
|
|
authSnac.Data.WriteBinary(oscar.NewTLV(0x6, cookie))
|
|
|
|
authSnac.Data.WriteBinary(oscar.NewTLV(0x11, []byte(user.Email)))
|
2021-12-16 19:45:32 -05:00
|
|
|
authFlap := oscar.NewFLAP(2)
|
2021-12-16 18:02:48 -05:00
|
|
|
authFlap.Data.WriteBinary(authSnac)
|
|
|
|
session.Send(authFlap)
|
|
|
|
|
2021-12-17 19:01:22 -05:00
|
|
|
// Tell them to leave
|
2021-12-16 19:45:32 -05:00
|
|
|
discoFlap := oscar.NewFLAP(4)
|
2021-12-16 18:02:48 -05:00
|
|
|
return session.Send(discoFlap)
|
2021-11-16 16:44:29 -05:00
|
|
|
}
|
2021-12-15 19:55:43 -05:00
|
|
|
|
|
|
|
return nil
|
2021-11-16 16:44:29 -05:00
|
|
|
}
|