bucp_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package server
  2. import (
  3. "bytes"
  4. "os"
  5. "testing"
  6. "github.com/google/uuid"
  7. "github.com/mkaminski/goaim/oscar"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestReceiveAndSendBUCPLoginRequest(t *testing.T) {
  11. userGoodPwd := User{
  12. ScreenName: "sn_user_a",
  13. AuthKey: "auth_key_user",
  14. }
  15. assert.NoError(t, userGoodPwd.HashPassword("good_pwd"))
  16. userBadPwd := userGoodPwd
  17. assert.NoError(t, userBadPwd.HashPassword("bad_pwd"))
  18. cases := []struct {
  19. name string
  20. cfg Config
  21. userInDB User
  22. sessionUUID uuid.UUID
  23. inputSNAC oscar.SNAC_0x17_0x02_BUCPLoginRequest
  24. expectSnacFrame oscar.SnacFrame
  25. expectSNACBody oscar.SNAC_0x17_0x03_BUCPLoginResponse
  26. }{
  27. {
  28. name: "login with valid password, expect OK login response",
  29. cfg: Config{
  30. OSCARHost: "127.0.0.1",
  31. BOSPort: 1234,
  32. },
  33. userInDB: userGoodPwd,
  34. sessionUUID: uuid.UUID{1, 2, 3},
  35. inputSNAC: oscar.SNAC_0x17_0x02_BUCPLoginRequest{
  36. TLVRestBlock: oscar.TLVRestBlock{
  37. TLVList: oscar.TLVList{
  38. oscar.NewTLV(oscar.TLVPasswordHash, userGoodPwd.PassHash),
  39. oscar.NewTLV(oscar.TLVScreenName, userGoodPwd.ScreenName),
  40. },
  41. },
  42. },
  43. expectSnacFrame: oscar.SnacFrame{
  44. FoodGroup: oscar.BUCP,
  45. SubGroup: BUCPLoginResponse,
  46. },
  47. expectSNACBody: oscar.SNAC_0x17_0x03_BUCPLoginResponse{
  48. TLVRestBlock: oscar.TLVRestBlock{
  49. TLVList: oscar.TLVList{
  50. oscar.NewTLV(oscar.TLVScreenName, userGoodPwd.ScreenName),
  51. oscar.NewTLV(oscar.TLVReconnectHere, "127.0.0.1:1234"),
  52. oscar.NewTLV(oscar.TLVAuthorizationCookie, uuid.UUID{1, 2, 3}.String()),
  53. },
  54. },
  55. },
  56. },
  57. {
  58. name: "login with bad password, expect OK login response (cfg.DisableAuth=true)",
  59. cfg: Config{
  60. OSCARHost: "127.0.0.1",
  61. BOSPort: 1234,
  62. DisableAuth: true,
  63. },
  64. userInDB: userGoodPwd,
  65. sessionUUID: uuid.UUID{1, 2, 3},
  66. inputSNAC: oscar.SNAC_0x17_0x02_BUCPLoginRequest{
  67. TLVRestBlock: oscar.TLVRestBlock{
  68. TLVList: oscar.TLVList{
  69. oscar.NewTLV(oscar.TLVPasswordHash, userBadPwd.PassHash),
  70. oscar.NewTLV(oscar.TLVScreenName, userBadPwd.ScreenName),
  71. },
  72. },
  73. },
  74. expectSnacFrame: oscar.SnacFrame{
  75. FoodGroup: oscar.BUCP,
  76. SubGroup: BUCPLoginResponse,
  77. },
  78. expectSNACBody: oscar.SNAC_0x17_0x03_BUCPLoginResponse{
  79. TLVRestBlock: oscar.TLVRestBlock{
  80. TLVList: oscar.TLVList{
  81. oscar.NewTLV(oscar.TLVScreenName, userBadPwd.ScreenName),
  82. oscar.NewTLV(oscar.TLVReconnectHere, "127.0.0.1:1234"),
  83. oscar.NewTLV(oscar.TLVAuthorizationCookie, uuid.UUID{1, 2, 3}.String()),
  84. },
  85. },
  86. },
  87. },
  88. {
  89. name: "login with bad password, expect failed login response (cfg.DisableAuth=false)",
  90. cfg: Config{
  91. OSCARHost: "127.0.0.1",
  92. BOSPort: 1234,
  93. },
  94. userInDB: userGoodPwd,
  95. sessionUUID: uuid.UUID{1, 2, 3},
  96. inputSNAC: oscar.SNAC_0x17_0x02_BUCPLoginRequest{
  97. TLVRestBlock: oscar.TLVRestBlock{
  98. TLVList: oscar.TLVList{
  99. oscar.NewTLV(oscar.TLVPasswordHash, userBadPwd.PassHash),
  100. oscar.NewTLV(oscar.TLVScreenName, userBadPwd.ScreenName),
  101. },
  102. },
  103. },
  104. expectSnacFrame: oscar.SnacFrame{
  105. FoodGroup: oscar.BUCP,
  106. SubGroup: BUCPLoginResponse,
  107. },
  108. expectSNACBody: oscar.SNAC_0x17_0x03_BUCPLoginResponse{
  109. TLVRestBlock: oscar.TLVRestBlock{
  110. TLVList: oscar.TLVList{
  111. oscar.NewTLV(oscar.TLVScreenName, userBadPwd.ScreenName),
  112. oscar.NewTLV(oscar.TLVErrorSubcode, uint16(0x01)),
  113. },
  114. },
  115. },
  116. },
  117. }
  118. for _, tc := range cases {
  119. t.Run(tc.name, func(t *testing.T) {
  120. //
  121. // initialize dependencies
  122. //
  123. const testFile string = "aim_test.db"
  124. defer func() {
  125. assert.NoError(t, os.Remove(testFile))
  126. }()
  127. fs, err := NewFeedbagStore(testFile)
  128. if err != nil {
  129. assert.NoError(t, err)
  130. }
  131. assert.NoError(t, fs.InsertUser(tc.userInDB))
  132. sm := NewSessionManager()
  133. //
  134. // send input SNAC
  135. //
  136. input := &bytes.Buffer{}
  137. var seq uint32
  138. assert.NoError(t, writeOutSNAC(oscar.SnacFrame{}, oscar.SnacFrame{}, tc.inputSNAC, &seq, input))
  139. //
  140. // receive response
  141. //
  142. output := &bytes.Buffer{}
  143. fnNewUUID := func() uuid.UUID {
  144. return tc.sessionUUID
  145. }
  146. assert.NoError(t, ReceiveAndSendBUCPLoginRequest(tc.cfg, sm, fs, input, output, &seq, fnNewUUID))
  147. flap := oscar.FlapFrame{}
  148. assert.NoError(t, oscar.Unmarshal(&flap, output))
  149. //
  150. // verify output SNAC frame
  151. //
  152. SnacFrame := oscar.SnacFrame{}
  153. assert.NoError(t, oscar.Unmarshal(&SnacFrame, output))
  154. assert.Equal(t, tc.expectSnacFrame, SnacFrame)
  155. //
  156. // verify output SNAC body
  157. //
  158. actual := oscar.SNAC_0x17_0x03_BUCPLoginResponse{}
  159. assert.NoError(t, oscar.Unmarshal(&actual, output))
  160. assert.Equal(t, tc.expectSNACBody, actual)
  161. assert.Equalf(t, 0, output.Len(), "the rest of the buffer is unread")
  162. })
  163. }
  164. }
  165. func TestReceiveAndSendAuthChallenge(t *testing.T) {
  166. cases := []struct {
  167. name string
  168. cfg Config
  169. userInDB User
  170. fnNewUUID uuid.UUID
  171. inputSNAC oscar.SNAC_0x17_0x06_BUCPChallengeRequest
  172. expectSnacFrame oscar.SnacFrame
  173. expectSNACBody any
  174. }{
  175. {
  176. name: "login with valid username, expect OK login response",
  177. cfg: Config{
  178. OSCARHost: "127.0.0.1",
  179. BOSPort: 1234,
  180. },
  181. userInDB: User{
  182. ScreenName: "sn_user_a",
  183. AuthKey: "auth_key_user_a",
  184. },
  185. fnNewUUID: uuid.UUID{1, 2, 3},
  186. inputSNAC: oscar.SNAC_0x17_0x06_BUCPChallengeRequest{
  187. TLVRestBlock: oscar.TLVRestBlock{
  188. TLVList: oscar.TLVList{
  189. oscar.NewTLV(oscar.TLVScreenName, "sn_user_a"),
  190. },
  191. },
  192. },
  193. expectSnacFrame: oscar.SnacFrame{
  194. FoodGroup: oscar.BUCP,
  195. SubGroup: BUCPChallengeResponse,
  196. },
  197. expectSNACBody: oscar.SNAC_0x17_0x07_BUCPChallengeResponse{
  198. AuthKey: "auth_key_user_a",
  199. },
  200. },
  201. {
  202. name: "login with invalid username, expect OK login response (cfg.DisableAuth=true)",
  203. cfg: Config{
  204. OSCARHost: "127.0.0.1",
  205. BOSPort: 1234,
  206. DisableAuth: true,
  207. },
  208. userInDB: User{
  209. ScreenName: "sn_user_a",
  210. AuthKey: "auth_key_user_a",
  211. },
  212. fnNewUUID: uuid.UUID{1, 2, 3},
  213. inputSNAC: oscar.SNAC_0x17_0x06_BUCPChallengeRequest{
  214. TLVRestBlock: oscar.TLVRestBlock{
  215. TLVList: oscar.TLVList{
  216. oscar.NewTLV(oscar.TLVScreenName, "sn_user_b"),
  217. },
  218. },
  219. },
  220. expectSnacFrame: oscar.SnacFrame{
  221. FoodGroup: oscar.BUCP,
  222. SubGroup: BUCPChallengeResponse,
  223. },
  224. expectSNACBody: oscar.SNAC_0x17_0x07_BUCPChallengeResponse{
  225. AuthKey: uuid.UUID{1, 2, 3}.String(),
  226. },
  227. },
  228. {
  229. name: "login with invalid username, expect failed login response (cfg.DisableAuth=false)",
  230. cfg: Config{
  231. OSCARHost: "127.0.0.1",
  232. BOSPort: 1234,
  233. },
  234. userInDB: User{
  235. ScreenName: "sn_user_a",
  236. AuthKey: "auth_key_user_a",
  237. },
  238. fnNewUUID: uuid.UUID{1, 2, 3},
  239. inputSNAC: oscar.SNAC_0x17_0x06_BUCPChallengeRequest{
  240. TLVRestBlock: oscar.TLVRestBlock{
  241. TLVList: oscar.TLVList{
  242. oscar.NewTLV(oscar.TLVScreenName, "sn_user_b"),
  243. },
  244. },
  245. },
  246. expectSnacFrame: oscar.SnacFrame{
  247. FoodGroup: oscar.BUCP,
  248. SubGroup: BUCPLoginResponse,
  249. },
  250. expectSNACBody: oscar.SNAC_0x17_0x03_BUCPLoginResponse{
  251. TLVRestBlock: oscar.TLVRestBlock{
  252. TLVList: oscar.TLVList{
  253. oscar.NewTLV(oscar.TLVErrorSubcode, uint16(0x01)),
  254. },
  255. },
  256. },
  257. },
  258. }
  259. for _, tc := range cases {
  260. t.Run(tc.name, func(t *testing.T) {
  261. //
  262. // initialize dependencies
  263. //
  264. const testFile string = "aim_test.db"
  265. defer func() {
  266. assert.NoError(t, os.Remove(testFile))
  267. }()
  268. fs, err := NewFeedbagStore(testFile)
  269. if err != nil {
  270. assert.NoError(t, err)
  271. }
  272. assert.NoError(t, fs.InsertUser(tc.userInDB))
  273. //
  274. // send input SNAC
  275. //
  276. input := &bytes.Buffer{}
  277. var seq uint32
  278. assert.NoError(t, writeOutSNAC(oscar.SnacFrame{}, oscar.SnacFrame{}, tc.inputSNAC, &seq, input))
  279. //
  280. // receive response
  281. //
  282. output := &bytes.Buffer{}
  283. fnNewUUID := func() uuid.UUID {
  284. return tc.fnNewUUID
  285. }
  286. assert.NoError(t, ReceiveAndSendAuthChallenge(tc.cfg, fs, input, output, &seq, fnNewUUID))
  287. flap := oscar.FlapFrame{}
  288. assert.NoError(t, oscar.Unmarshal(&flap, output))
  289. //
  290. // verify output SNAC frame
  291. //
  292. SnacFrame := oscar.SnacFrame{}
  293. assert.NoError(t, oscar.Unmarshal(&SnacFrame, output))
  294. assert.Equal(t, tc.expectSnacFrame, SnacFrame)
  295. //
  296. // verify output SNAC body
  297. //
  298. switch v := tc.expectSNACBody.(type) {
  299. case oscar.SNAC_0x17_0x07_BUCPChallengeResponse:
  300. actual := oscar.SNAC_0x17_0x07_BUCPChallengeResponse{}
  301. assert.NoError(t, oscar.Unmarshal(&actual, output))
  302. assert.Equal(t, v, actual)
  303. case oscar.SNAC_0x17_0x03_BUCPLoginResponse:
  304. actual := oscar.SNAC_0x17_0x03_BUCPLoginResponse{}
  305. assert.NoError(t, oscar.Unmarshal(&actual, output))
  306. assert.Equal(t, v, actual)
  307. default:
  308. t.Fatalf("unexpected output SNAC type")
  309. }
  310. assert.Equalf(t, 0, output.Len(), "the rest of the buffer is unread")
  311. })
  312. }
  313. }