auth_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package oscar
  2. import (
  3. "bytes"
  4. "context"
  5. "log/slog"
  6. "net"
  7. "testing"
  8. "time"
  9. "github.com/mk6i/retro-aim-server/wire"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/mock"
  12. "golang.org/x/time/rate"
  13. )
  14. type fakeConn struct {
  15. net.Conn // embed the real connection
  16. local net.Addr
  17. remote net.Addr
  18. }
  19. func (f fakeConn) RemoteAddr() net.Addr { return f.remote }
  20. func TestBUCPAuthService_handleNewConnection(t *testing.T) {
  21. serverConn, clientConn := net.Pipe()
  22. addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
  23. if err != nil {
  24. panic(err)
  25. }
  26. clientFake := fakeConn{
  27. Conn: clientConn,
  28. local: addr,
  29. remote: addr,
  30. }
  31. go func() {
  32. defer serverConn.Close()
  33. // < receive FLAPSignonFrame
  34. flap := wire.FLAPFrame{}
  35. assert.NoError(t, wire.UnmarshalBE(&flap, serverConn))
  36. flapSignonFrame := wire.FLAPSignonFrame{}
  37. assert.NoError(t, wire.UnmarshalBE(&flapSignonFrame, bytes.NewBuffer(flap.Payload)))
  38. // > send FLAPSignonFrame
  39. flapSignonFrame = wire.FLAPSignonFrame{
  40. FLAPVersion: 1,
  41. }
  42. buf := &bytes.Buffer{}
  43. assert.NoError(t, wire.MarshalBE(flapSignonFrame, buf))
  44. flap = wire.FLAPFrame{
  45. StartMarker: 42,
  46. FrameType: wire.FLAPFrameSignon,
  47. Payload: buf.Bytes(),
  48. }
  49. assert.NoError(t, wire.MarshalBE(flap, serverConn))
  50. // > send SNAC_0x17_0x06_BUCPChallengeRequest
  51. flapc := wire.NewFlapClient(0, serverConn, serverConn)
  52. frame := wire.SNACFrame{
  53. FoodGroup: wire.BUCP,
  54. SubGroup: wire.BUCPChallengeRequest,
  55. }
  56. bodyIn := wire.SNAC_0x17_0x06_BUCPChallengeRequest{}
  57. assert.NoError(t, flapc.SendSNAC(frame, bodyIn))
  58. // < receive SNAC_0x17_0x07_BUCPChallengeResponse
  59. frame = wire.SNACFrame{}
  60. assert.NoError(t, flapc.ReceiveSNAC(&frame, &wire.SNAC_0x17_0x07_BUCPChallengeResponse{}))
  61. assert.Equal(t, wire.SNACFrame{FoodGroup: wire.BUCP, SubGroup: wire.BUCPChallengeResponse}, frame)
  62. // > send keep alive frame (like BSFlite does mid-login)
  63. assert.NoError(t, flapc.SendKeepAliveFrame())
  64. // > send SNAC_0x17_0x02_BUCPLoginRequest
  65. frame = wire.SNACFrame{
  66. FoodGroup: wire.BUCP,
  67. SubGroup: wire.BUCPLoginRequest,
  68. }
  69. assert.NoError(t, flapc.SendSNAC(frame, wire.SNAC_0x17_0x02_BUCPLoginRequest{}))
  70. // < receive SNAC_0x17_0x03_BUCPLoginResponse
  71. frame = wire.SNACFrame{}
  72. assert.NoError(t, flapc.ReceiveSNAC(&frame, &wire.SNAC_0x17_0x03_BUCPLoginResponse{}))
  73. assert.Equal(t, wire.SNACFrame{FoodGroup: wire.BUCP, SubGroup: wire.BUCPLoginResponse}, frame)
  74. }()
  75. authService := newMockAuthService(t)
  76. authService.EXPECT().
  77. BUCPChallenge(matchContext(), mock.Anything, mock.Anything).
  78. Return(wire.SNACMessage{
  79. Frame: wire.SNACFrame{
  80. FoodGroup: wire.BUCP,
  81. SubGroup: wire.BUCPChallengeResponse,
  82. },
  83. Body: wire.SNAC_0x17_0x07_BUCPChallengeResponse{},
  84. }, nil)
  85. authService.EXPECT().
  86. BUCPLogin(matchContext(), mock.Anything, mock.Anything).
  87. Return(wire.SNACMessage{
  88. Frame: wire.SNACFrame{
  89. FoodGroup: wire.BUCP,
  90. SubGroup: wire.BUCPLoginResponse,
  91. },
  92. Body: wire.SNAC_0x17_0x03_BUCPLoginResponse{},
  93. }, nil)
  94. rt := AuthServer{
  95. AuthService: authService,
  96. Logger: slog.Default(),
  97. IPRateLimiter: NewIPRateLimiter(rate.Every(1*time.Minute), 10, 1*time.Minute),
  98. }
  99. assert.NoError(t, rt.handleNewConnection(context.Background(), clientFake))
  100. }