admin_test.go 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  1. package foodgroup
  2. import (
  3. "context"
  4. "io"
  5. "log/slog"
  6. "net/mail"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/mock"
  10. "github.com/mk6i/open-oscar-server/config"
  11. "github.com/mk6i/open-oscar-server/state"
  12. "github.com/mk6i/open-oscar-server/wire"
  13. )
  14. func TestAdminService_ConfirmRequest(t *testing.T) {
  15. cases := []struct {
  16. // name is the unit test name
  17. name string
  18. // cfg is the app configuration
  19. cfg config.Config
  20. // inputSNAC is the SNAC sent from the client to the server
  21. inputSNAC wire.SNACMessage
  22. // mockParams is the list of params sent to mocks that satisfy this
  23. // method's dependencies
  24. mockParams mockParams
  25. // instance is the session of the user
  26. instance *state.SessionInstance
  27. // expectOutput is the SNAC sent from the server to client
  28. expectOutput wire.SNACMessage
  29. // expectErr is the expected error returned
  30. expectErr error
  31. }{
  32. {
  33. name: "unconfirmed account sends confirmation request",
  34. instance: newTestInstance("chattingchuck"),
  35. inputSNAC: wire.SNACMessage{
  36. Frame: wire.SNACFrame{
  37. FoodGroup: wire.Admin,
  38. SubGroup: wire.AdminAcctConfirmRequest,
  39. RequestID: 1234,
  40. },
  41. Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
  42. },
  43. expectOutput: wire.SNACMessage{
  44. Frame: wire.SNACFrame{
  45. FoodGroup: wire.Admin,
  46. SubGroup: wire.AdminAcctConfirmReply,
  47. RequestID: 1234,
  48. },
  49. Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
  50. Status: wire.AdminAcctConfirmStatusEmailSent,
  51. },
  52. },
  53. mockParams: mockParams{
  54. accountManagerParams: accountManagerParams{
  55. accountManagerEmailAddressParams: accountManagerEmailAddressParams{
  56. {
  57. screenName: state.NewIdentScreenName("chattingchuck"),
  58. emailAddress: &mail.Address{
  59. Address: "chuck@aol.com",
  60. },
  61. err: nil,
  62. },
  63. },
  64. accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
  65. {
  66. screenName: state.NewIdentScreenName("chattingchuck"),
  67. confirmStatus: false,
  68. err: nil,
  69. },
  70. },
  71. accountManagerUpdateConfirmStatusParams: accountManagerUpdateConfirmStatusParams{
  72. {
  73. confirmStatus: true,
  74. screenName: state.NewIdentScreenName("chattingchuck"),
  75. err: nil,
  76. },
  77. },
  78. },
  79. buddyBroadcasterParams: buddyBroadcasterParams{
  80. broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
  81. {
  82. screenName: state.DisplayScreenName("Chatting Chuck"),
  83. },
  84. },
  85. },
  86. },
  87. },
  88. {
  89. name: "already confirmed account sends confirmation request",
  90. instance: newTestInstance("chattingchuck"),
  91. inputSNAC: wire.SNACMessage{
  92. Frame: wire.SNACFrame{
  93. FoodGroup: wire.Admin,
  94. SubGroup: wire.AdminAcctConfirmRequest,
  95. RequestID: 1234,
  96. },
  97. Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
  98. },
  99. expectOutput: wire.SNACMessage{
  100. Frame: wire.SNACFrame{
  101. FoodGroup: wire.Admin,
  102. SubGroup: wire.AdminAcctConfirmReply,
  103. RequestID: 1234,
  104. },
  105. Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
  106. Status: wire.AdminAcctConfirmStatusAlreadyConfirmed,
  107. },
  108. },
  109. mockParams: mockParams{
  110. accountManagerParams: accountManagerParams{
  111. accountManagerEmailAddressParams: accountManagerEmailAddressParams{
  112. {
  113. screenName: state.NewIdentScreenName("chattingchuck"),
  114. emailAddress: &mail.Address{
  115. Address: "chuck@aol.com",
  116. },
  117. err: nil,
  118. },
  119. },
  120. accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
  121. {
  122. screenName: state.NewIdentScreenName("chattingchuck"),
  123. confirmStatus: true,
  124. err: nil,
  125. },
  126. },
  127. },
  128. },
  129. },
  130. {
  131. name: "acccount with no email address sends confirmation request",
  132. instance: newTestInstance("chattingchuck"),
  133. inputSNAC: wire.SNACMessage{
  134. Frame: wire.SNACFrame{
  135. FoodGroup: wire.Admin,
  136. SubGroup: wire.AdminAcctConfirmRequest,
  137. RequestID: 1234,
  138. },
  139. Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
  140. },
  141. expectOutput: wire.SNACMessage{
  142. Frame: wire.SNACFrame{
  143. FoodGroup: wire.Admin,
  144. SubGroup: wire.AdminAcctConfirmReply,
  145. RequestID: 1234,
  146. },
  147. Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
  148. Status: wire.AdminAcctConfirmStatusServerError,
  149. },
  150. },
  151. mockParams: mockParams{
  152. accountManagerParams: accountManagerParams{
  153. accountManagerEmailAddressParams: accountManagerEmailAddressParams{
  154. {
  155. screenName: state.NewIdentScreenName("chattingchuck"),
  156. emailAddress: nil,
  157. err: state.ErrNoEmailAddress,
  158. },
  159. },
  160. },
  161. },
  162. },
  163. }
  164. for _, tc := range cases {
  165. t.Run(tc.name, func(t *testing.T) {
  166. messageRelayer := newMockMessageRelayer(t)
  167. accountManager := newMockAccountManager(t)
  168. buddyBroadcaster := newMockbuddyBroadcaster(t)
  169. for _, params := range tc.mockParams.accountManagerEmailAddressParams {
  170. accountManager.EXPECT().
  171. EmailAddress(matchContext(), params.screenName).
  172. Return(params.emailAddress, params.err)
  173. }
  174. for _, params := range tc.mockParams.accountManagerConfirmStatusParams {
  175. accountManager.EXPECT().
  176. ConfirmStatus(matchContext(), params.screenName).
  177. Return(params.confirmStatus, params.err)
  178. }
  179. for _, params := range tc.mockParams.accountManagerUpdateConfirmStatusParams {
  180. accountManager.EXPECT().
  181. UpdateConfirmStatus(matchContext(), params.screenName, params.confirmStatus).
  182. Return(params.err)
  183. }
  184. for _, params := range tc.mockParams.broadcastBuddyArrivedParams {
  185. buddyBroadcaster.EXPECT().
  186. BroadcastBuddyArrived(mock.Anything, tc.instance.IdentScreenName(), tc.instance.Session().TLVUserInfo()).
  187. Return(params.err)
  188. }
  189. svc := AdminService{
  190. messageRelayer: messageRelayer,
  191. accountManager: accountManager,
  192. buddyBroadcaster: buddyBroadcaster,
  193. }
  194. outputSNAC, err := svc.ConfirmRequest(context.Background(), tc.instance, tc.inputSNAC.Frame)
  195. assert.ErrorIs(t, err, tc.expectErr)
  196. if tc.expectErr != nil {
  197. return
  198. }
  199. assert.Equal(t, tc.expectOutput, outputSNAC)
  200. })
  201. }
  202. }
  203. func TestAdminService_InfoQuery(t *testing.T) {
  204. cases := []struct {
  205. // name is the unit test name
  206. name string
  207. // cfg is the app configuration
  208. cfg config.Config
  209. // inputSNAC is the SNAC sent from the client to the server
  210. inputSNAC wire.SNACMessage
  211. // mockParams is the list of params sent to mocks that satisfy this
  212. // method's dependencies
  213. mockParams mockParams
  214. // instance is the session of the user
  215. instance *state.SessionInstance
  216. // expectOutput is the SNAC sent from the server to client
  217. expectOutput wire.SNACMessage
  218. // expectErr is the expected error returned
  219. expectErr error
  220. }{
  221. {
  222. name: "user requests account registration status",
  223. instance: newTestInstance("chattingchuck"),
  224. inputSNAC: wire.SNACMessage{
  225. Frame: wire.SNACFrame{
  226. FoodGroup: wire.Admin,
  227. SubGroup: wire.AdminInfoQuery,
  228. RequestID: 1337,
  229. },
  230. Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
  231. TLVRestBlock: wire.TLVRestBlock{
  232. TLVList: wire.TLVList{
  233. wire.NewTLVBE(wire.AdminTLVRegistrationStatus, uint16(0x00))},
  234. },
  235. },
  236. },
  237. expectOutput: wire.SNACMessage{
  238. Frame: wire.SNACFrame{
  239. FoodGroup: wire.Admin,
  240. SubGroup: wire.AdminInfoReply,
  241. RequestID: 1337,
  242. },
  243. Body: wire.SNAC_0x07_0x03_AdminInfoReply{
  244. Permissions: wire.AdminInfoPermissionsReadWrite,
  245. TLVBlock: wire.TLVBlock{
  246. TLVList: wire.TLVList{
  247. wire.NewTLVBE(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusLimitDisclosure),
  248. },
  249. },
  250. },
  251. },
  252. mockParams: mockParams{
  253. accountManagerParams: accountManagerParams{
  254. accountManagerRegStatusParams: accountManagerRegStatusParams{
  255. {
  256. screenName: state.NewIdentScreenName("chattingchuck"),
  257. regStatus: wire.AdminInfoRegStatusLimitDisclosure,
  258. err: nil,
  259. },
  260. },
  261. },
  262. },
  263. },
  264. {
  265. name: "user requests account email address",
  266. instance: newTestInstance("chattingchuck"),
  267. inputSNAC: wire.SNACMessage{
  268. Frame: wire.SNACFrame{
  269. FoodGroup: wire.Admin,
  270. SubGroup: wire.AdminInfoQuery,
  271. RequestID: 1337,
  272. },
  273. Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
  274. TLVRestBlock: wire.TLVRestBlock{
  275. TLVList: wire.TLVList{
  276. wire.NewTLVBE(wire.AdminTLVEmailAddress, uint16(0x00))},
  277. },
  278. },
  279. },
  280. expectOutput: wire.SNACMessage{
  281. Frame: wire.SNACFrame{
  282. FoodGroup: wire.Admin,
  283. SubGroup: wire.AdminInfoReply,
  284. RequestID: 1337,
  285. },
  286. Body: wire.SNAC_0x07_0x03_AdminInfoReply{
  287. Permissions: wire.AdminInfoPermissionsReadWrite,
  288. TLVBlock: wire.TLVBlock{
  289. TLVList: wire.TLVList{
  290. wire.NewTLVBE(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
  291. },
  292. },
  293. },
  294. },
  295. mockParams: mockParams{
  296. accountManagerParams: accountManagerParams{
  297. accountManagerEmailAddressParams: accountManagerEmailAddressParams{
  298. {
  299. screenName: state.NewIdentScreenName("chattingchuck"),
  300. emailAddress: &mail.Address{
  301. Address: "chattingchuck@aol.com",
  302. },
  303. err: nil,
  304. },
  305. },
  306. },
  307. },
  308. },
  309. {
  310. name: "user requests account email address but not set",
  311. instance: newTestInstance("chattingchuck"),
  312. inputSNAC: wire.SNACMessage{
  313. Frame: wire.SNACFrame{
  314. FoodGroup: wire.Admin,
  315. SubGroup: wire.AdminInfoQuery,
  316. RequestID: 1337,
  317. },
  318. Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
  319. TLVRestBlock: wire.TLVRestBlock{
  320. TLVList: wire.TLVList{
  321. wire.NewTLVBE(wire.AdminTLVEmailAddress, uint16(0x00))},
  322. },
  323. },
  324. },
  325. expectOutput: wire.SNACMessage{
  326. Frame: wire.SNACFrame{
  327. FoodGroup: wire.Admin,
  328. SubGroup: wire.AdminInfoReply,
  329. RequestID: 1337,
  330. },
  331. Body: wire.SNAC_0x07_0x03_AdminInfoReply{
  332. Permissions: wire.AdminInfoPermissionsReadWrite,
  333. TLVBlock: wire.TLVBlock{
  334. TLVList: wire.TLVList{
  335. wire.NewTLVBE(wire.AdminTLVEmailAddress, ""),
  336. },
  337. },
  338. },
  339. },
  340. mockParams: mockParams{
  341. accountManagerParams: accountManagerParams{
  342. accountManagerEmailAddressParams: accountManagerEmailAddressParams{
  343. {
  344. screenName: state.NewIdentScreenName("chattingchuck"),
  345. emailAddress: nil,
  346. err: state.ErrNoEmailAddress,
  347. },
  348. },
  349. },
  350. },
  351. },
  352. {
  353. name: "user requests formatted screenname",
  354. instance: newTestInstance("ChattingChuck"),
  355. inputSNAC: wire.SNACMessage{
  356. Frame: wire.SNACFrame{
  357. FoodGroup: wire.Admin,
  358. SubGroup: wire.AdminInfoQuery,
  359. RequestID: 1337,
  360. },
  361. Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
  362. TLVRestBlock: wire.TLVRestBlock{
  363. TLVList: wire.TLVList{
  364. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, uint16(0x00))},
  365. },
  366. },
  367. },
  368. expectOutput: wire.SNACMessage{
  369. Frame: wire.SNACFrame{
  370. FoodGroup: wire.Admin,
  371. SubGroup: wire.AdminInfoReply,
  372. RequestID: 1337,
  373. },
  374. Body: wire.SNAC_0x07_0x03_AdminInfoReply{
  375. Permissions: wire.AdminInfoPermissionsReadWrite,
  376. TLVBlock: wire.TLVBlock{
  377. TLVList: wire.TLVList{
  378. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "ChattingChuck"),
  379. },
  380. },
  381. },
  382. },
  383. },
  384. {
  385. name: "user requests invalid TLV",
  386. instance: newTestInstance("ChattingChuck"),
  387. inputSNAC: wire.SNACMessage{
  388. Frame: wire.SNACFrame{
  389. FoodGroup: wire.Admin,
  390. SubGroup: wire.AdminInfoQuery,
  391. RequestID: 1337,
  392. },
  393. Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
  394. TLVRestBlock: wire.TLVRestBlock{
  395. TLVList: wire.TLVList{
  396. wire.NewTLVBE(uint16(0x99), uint16(0x00))},
  397. },
  398. },
  399. },
  400. expectOutput: wire.SNACMessage{
  401. Frame: wire.SNACFrame{
  402. FoodGroup: wire.Admin,
  403. SubGroup: wire.AdminErr,
  404. RequestID: 1337,
  405. },
  406. Body: wire.SNACError{
  407. Code: wire.ErrorCodeNotSupportedByHost,
  408. },
  409. },
  410. },
  411. }
  412. for _, tc := range cases {
  413. t.Run(tc.name, func(t *testing.T) {
  414. messageRelayer := newMockMessageRelayer(t)
  415. accountManager := newMockAccountManager(t)
  416. buddyBroadcaster := newMockbuddyBroadcaster(t)
  417. for _, params := range tc.mockParams.accountManagerRegStatusParams {
  418. accountManager.EXPECT().
  419. RegStatus(matchContext(), params.screenName).
  420. Return(params.regStatus, params.err)
  421. }
  422. for _, params := range tc.mockParams.accountManagerEmailAddressParams {
  423. accountManager.EXPECT().
  424. EmailAddress(matchContext(), params.screenName).
  425. Return(params.emailAddress, params.err)
  426. }
  427. svc := AdminService{
  428. messageRelayer: messageRelayer,
  429. accountManager: accountManager,
  430. buddyBroadcaster: buddyBroadcaster,
  431. }
  432. outputSNAC, err := svc.InfoQuery(context.Background(), tc.instance, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x02_AdminInfoQuery))
  433. assert.ErrorIs(t, err, tc.expectErr)
  434. if tc.expectErr != nil {
  435. return
  436. }
  437. assert.Equal(t, tc.expectOutput, outputSNAC)
  438. })
  439. }
  440. }
  441. func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
  442. cases := []struct {
  443. // name is the unit test name
  444. name string
  445. // cfg is the app configuration
  446. cfg config.Config
  447. // inputSNAC is the SNAC sent from the client to the server
  448. inputSNAC wire.SNACMessage
  449. // mockParams is the list of params sent to mocks that satisfy this
  450. // method's dependencies
  451. mockParams mockParams
  452. // instance is the session of the user
  453. instance *state.SessionInstance
  454. // expectOutput is the SNAC sent from the server to client
  455. expectOutput wire.SNACMessage
  456. // expectErr is the expected error returned
  457. expectErr error
  458. }{
  459. {
  460. name: "user changes screen name format successfully aim < 6",
  461. instance: newTestInstance("chattingchuck"),
  462. mockParams: mockParams{
  463. accountManagerParams: accountManagerParams{
  464. accountManagerUpdateDisplayScreenNameParams: accountManagerUpdateDisplayScreenNameParams{
  465. {
  466. displayScreenName: state.DisplayScreenName("Chatting Chuck"),
  467. },
  468. },
  469. },
  470. buddyBroadcasterParams: buddyBroadcasterParams{
  471. broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
  472. {
  473. screenName: state.DisplayScreenName("Chatting Chuck"),
  474. },
  475. },
  476. },
  477. messageRelayerParams: messageRelayerParams{
  478. relayToSelfParams: relayToSelfParams{
  479. {
  480. screenName: state.NewIdentScreenName("Chatting Chuck"),
  481. message: wire.SNACMessage{
  482. Frame: wire.SNACFrame{
  483. FoodGroup: wire.OService,
  484. SubGroup: wire.OServiceUserInfoUpdate,
  485. RequestID: wire.ReqIDFromServer,
  486. },
  487. },
  488. },
  489. },
  490. },
  491. },
  492. inputSNAC: wire.SNACMessage{
  493. Frame: wire.SNACFrame{
  494. FoodGroup: wire.Admin,
  495. SubGroup: wire.AdminInfoChangeRequest,
  496. RequestID: 1337,
  497. },
  498. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  499. TLVRestBlock: wire.TLVRestBlock{
  500. TLVList: wire.TLVList{
  501. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
  502. },
  503. },
  504. },
  505. },
  506. expectOutput: wire.SNACMessage{
  507. Frame: wire.SNACFrame{
  508. FoodGroup: wire.Admin,
  509. SubGroup: wire.AdminInfoChangeReply,
  510. RequestID: 1337,
  511. },
  512. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  513. Permissions: wire.AdminInfoPermissionsReadWrite,
  514. TLVBlock: wire.TLVBlock{
  515. TLVList: wire.TLVList{
  516. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
  517. },
  518. },
  519. },
  520. },
  521. },
  522. {
  523. name: "user changes screen name format successfully aim >= 6",
  524. instance: newTestInstance("chattingchuck", sessOptSetFoodGroupVersion(wire.OService, 4)),
  525. mockParams: mockParams{
  526. accountManagerParams: accountManagerParams{
  527. accountManagerUpdateDisplayScreenNameParams: accountManagerUpdateDisplayScreenNameParams{
  528. {
  529. displayScreenName: state.DisplayScreenName("Chatting Chuck"),
  530. },
  531. },
  532. },
  533. buddyBroadcasterParams: buddyBroadcasterParams{
  534. broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
  535. {
  536. screenName: state.DisplayScreenName("Chatting Chuck"),
  537. },
  538. },
  539. },
  540. messageRelayerParams: messageRelayerParams{
  541. relayToSelfParams: relayToSelfParams{
  542. {
  543. screenName: state.NewIdentScreenName("Chatting Chuck"),
  544. message: wire.SNACMessage{
  545. Frame: wire.SNACFrame{
  546. FoodGroup: wire.OService,
  547. SubGroup: wire.OServiceUserInfoUpdate,
  548. RequestID: wire.ReqIDFromServer,
  549. },
  550. },
  551. },
  552. },
  553. },
  554. },
  555. inputSNAC: wire.SNACMessage{
  556. Frame: wire.SNACFrame{
  557. FoodGroup: wire.Admin,
  558. SubGroup: wire.AdminInfoChangeRequest,
  559. RequestID: 1337,
  560. },
  561. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  562. TLVRestBlock: wire.TLVRestBlock{
  563. TLVList: wire.TLVList{
  564. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
  565. },
  566. },
  567. },
  568. },
  569. expectOutput: wire.SNACMessage{
  570. Frame: wire.SNACFrame{
  571. FoodGroup: wire.Admin,
  572. SubGroup: wire.AdminInfoChangeReply,
  573. RequestID: 1337,
  574. },
  575. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  576. Permissions: wire.AdminInfoPermissionsReadWrite,
  577. TLVBlock: wire.TLVBlock{
  578. TLVList: wire.TLVList{
  579. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "Chatting Chuck"),
  580. },
  581. },
  582. },
  583. },
  584. },
  585. {
  586. name: "proposed screen name is too long",
  587. instance: newTestInstance("chattingchuck"),
  588. inputSNAC: wire.SNACMessage{
  589. Frame: wire.SNACFrame{
  590. FoodGroup: wire.Admin,
  591. SubGroup: wire.AdminInfoChangeRequest,
  592. RequestID: 1337,
  593. },
  594. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  595. TLVRestBlock: wire.TLVRestBlock{
  596. TLVList: wire.TLVList{
  597. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "c h a t t i n g c h u c k")},
  598. },
  599. },
  600. },
  601. expectOutput: wire.SNACMessage{
  602. Frame: wire.SNACFrame{
  603. FoodGroup: wire.Admin,
  604. SubGroup: wire.AdminInfoChangeReply,
  605. RequestID: 1337,
  606. },
  607. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  608. Permissions: wire.AdminInfoPermissionsReadWrite,
  609. TLVBlock: wire.TLVBlock{
  610. TLVList: wire.TLVList{
  611. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidNickNameLength),
  612. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  613. },
  614. },
  615. },
  616. },
  617. },
  618. {
  619. name: "proposed screen name does not match session screen name",
  620. instance: newTestInstance("chattingchuck"),
  621. inputSNAC: wire.SNACMessage{
  622. Frame: wire.SNACFrame{
  623. FoodGroup: wire.Admin,
  624. SubGroup: wire.AdminInfoChangeRequest,
  625. RequestID: 1337,
  626. },
  627. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  628. TLVRestBlock: wire.TLVRestBlock{
  629. TLVList: wire.TLVList{
  630. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "QuietQuinton")},
  631. },
  632. },
  633. },
  634. expectOutput: wire.SNACMessage{
  635. Frame: wire.SNACFrame{
  636. FoodGroup: wire.Admin,
  637. SubGroup: wire.AdminInfoChangeReply,
  638. RequestID: 1337,
  639. },
  640. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  641. Permissions: wire.AdminInfoPermissionsReadWrite,
  642. TLVBlock: wire.TLVBlock{
  643. TLVList: wire.TLVList{
  644. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorValidateNickName),
  645. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  646. },
  647. },
  648. },
  649. },
  650. },
  651. {
  652. name: "proposed screen name ends in a space",
  653. instance: newTestInstance("chattingchuck"),
  654. inputSNAC: wire.SNACMessage{
  655. Frame: wire.SNACFrame{
  656. FoodGroup: wire.Admin,
  657. SubGroup: wire.AdminInfoChangeRequest,
  658. RequestID: 1337,
  659. },
  660. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  661. TLVRestBlock: wire.TLVRestBlock{
  662. TLVList: wire.TLVList{
  663. wire.NewTLVBE(wire.AdminTLVScreenNameFormatted, "ChattingChuck ")},
  664. },
  665. },
  666. },
  667. expectOutput: wire.SNACMessage{
  668. Frame: wire.SNACFrame{
  669. FoodGroup: wire.Admin,
  670. SubGroup: wire.AdminInfoChangeReply,
  671. RequestID: 1337,
  672. },
  673. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  674. Permissions: wire.AdminInfoPermissionsReadWrite,
  675. TLVBlock: wire.TLVBlock{
  676. TLVList: wire.TLVList{
  677. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidNickName),
  678. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  679. },
  680. },
  681. },
  682. },
  683. },
  684. }
  685. for _, tc := range cases {
  686. t.Run(tc.name, func(t *testing.T) {
  687. messageRelayer := newMockMessageRelayer(t)
  688. accountManager := newMockAccountManager(t)
  689. mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
  690. for _, params := range tc.mockParams.accountManagerUpdateDisplayScreenNameParams {
  691. accountManager.EXPECT().
  692. UpdateDisplayScreenName(matchContext(), params.displayScreenName).
  693. Return(params.err)
  694. }
  695. for _, params := range tc.mockParams.broadcastBuddyArrivedParams {
  696. mockBuddyBroadcaster.EXPECT().
  697. BroadcastBuddyArrived(mock.Anything, state.NewIdentScreenName(params.screenName.String()), mock.MatchedBy(func(userInfo wire.TLVUserInfo) bool {
  698. return userInfo.ScreenName == params.screenName.String()
  699. })).
  700. Return(params.err)
  701. }
  702. for _, params := range tc.mockParams.relayToScreenNameParams {
  703. p := params
  704. messageRelayer.EXPECT().
  705. RelayToScreenName(mock.Anything, p.screenName, p.message)
  706. }
  707. for _, params := range tc.mockParams.relayToSelfParams {
  708. p := params
  709. messageRelayer.EXPECT().
  710. RelayToSelf(mock.Anything, mock.Anything, mock.MatchedBy(func(msg wire.SNACMessage) bool {
  711. if msg.Frame != p.message.Frame {
  712. return false
  713. }
  714. body, ok := msg.Body.(wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate)
  715. return ok && len(body.UserInfo) == 1 &&
  716. state.NewIdentScreenName(body.UserInfo[0].ScreenName) == p.screenName
  717. })).
  718. Once()
  719. }
  720. svc := AdminService{
  721. accountManager: accountManager,
  722. buddyBroadcaster: mockBuddyBroadcaster,
  723. messageRelayer: messageRelayer,
  724. }
  725. outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.instance, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
  726. assert.ErrorIs(t, err, tc.expectErr)
  727. if tc.expectErr != nil {
  728. return
  729. }
  730. assert.Equal(t, tc.expectOutput, outputSNAC)
  731. })
  732. }
  733. }
  734. func TestAdminService_InfoChangeRequest_EmailAddress(t *testing.T) {
  735. // One case needs a 320 character long email address
  736. longEmailAddress := "longemailaddress@"
  737. for i := 0; i < 50; i++ {
  738. longEmailAddress += "domain"
  739. }
  740. longEmailAddress += ".com"
  741. cases := []struct {
  742. // name is the unit test name
  743. name string
  744. // cfg is the app configuration
  745. cfg config.Config
  746. // inputSNAC is the SNAC sent from the client to the server
  747. inputSNAC wire.SNACMessage
  748. // mockParams is the list of params sent to mocks that satisfy this
  749. // method's dependencies
  750. mockParams mockParams
  751. // instance is the session of the user
  752. instance *state.SessionInstance
  753. // expectOutput is the SNAC sent from the server to client
  754. expectOutput wire.SNACMessage
  755. // expectErr is the expected error returned
  756. expectErr error
  757. }{
  758. {
  759. name: "user changes email address successfully",
  760. instance: newTestInstance("chattingchuck"),
  761. mockParams: mockParams{
  762. accountManagerParams: accountManagerParams{
  763. accountManagerUpdateEmailAddressParams: accountManagerUpdateEmailAddressParams{
  764. {
  765. screenName: state.NewIdentScreenName("chattingchuck"),
  766. emailAddress: &mail.Address{
  767. Address: "chattingchuck@aol.com",
  768. },
  769. },
  770. },
  771. },
  772. },
  773. inputSNAC: wire.SNACMessage{
  774. Frame: wire.SNACFrame{
  775. FoodGroup: wire.Admin,
  776. SubGroup: wire.AdminInfoChangeRequest,
  777. RequestID: 1337,
  778. },
  779. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  780. TLVRestBlock: wire.TLVRestBlock{
  781. TLVList: wire.TLVList{
  782. wire.NewTLVBE(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
  783. },
  784. },
  785. },
  786. },
  787. expectOutput: wire.SNACMessage{
  788. Frame: wire.SNACFrame{
  789. FoodGroup: wire.Admin,
  790. SubGroup: wire.AdminInfoChangeReply,
  791. RequestID: 1337,
  792. },
  793. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  794. Permissions: wire.AdminInfoPermissionsReadWrite,
  795. TLVBlock: wire.TLVBlock{
  796. TLVList: wire.TLVList{
  797. wire.NewTLVBE(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
  798. },
  799. },
  800. },
  801. },
  802. },
  803. {
  804. name: "proposed email address invalid rfc 5322 format",
  805. instance: newTestInstance("chattingchuck"),
  806. inputSNAC: wire.SNACMessage{
  807. Frame: wire.SNACFrame{
  808. FoodGroup: wire.Admin,
  809. SubGroup: wire.AdminInfoChangeRequest,
  810. RequestID: 1337,
  811. },
  812. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  813. TLVRestBlock: wire.TLVRestBlock{
  814. TLVList: wire.TLVList{
  815. wire.NewTLVBE(wire.AdminTLVEmailAddress, "chattingchuck@@@@@@@aol.com"),
  816. },
  817. },
  818. },
  819. },
  820. expectOutput: wire.SNACMessage{
  821. Frame: wire.SNACFrame{
  822. FoodGroup: wire.Admin,
  823. SubGroup: wire.AdminInfoChangeReply,
  824. RequestID: 1337,
  825. },
  826. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  827. Permissions: wire.AdminInfoPermissionsReadWrite,
  828. TLVBlock: wire.TLVBlock{
  829. TLVList: wire.TLVList{
  830. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidEmail),
  831. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  832. },
  833. },
  834. },
  835. },
  836. },
  837. {
  838. name: "proposed email address too long",
  839. instance: newTestInstance("chattingchuck"),
  840. inputSNAC: wire.SNACMessage{
  841. Frame: wire.SNACFrame{
  842. FoodGroup: wire.Admin,
  843. SubGroup: wire.AdminInfoChangeRequest,
  844. RequestID: 1337,
  845. },
  846. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  847. TLVRestBlock: wire.TLVRestBlock{
  848. TLVList: wire.TLVList{
  849. wire.NewTLVBE(wire.AdminTLVEmailAddress, longEmailAddress),
  850. },
  851. },
  852. },
  853. },
  854. expectOutput: wire.SNACMessage{
  855. Frame: wire.SNACFrame{
  856. FoodGroup: wire.Admin,
  857. SubGroup: wire.AdminInfoChangeReply,
  858. RequestID: 1337,
  859. },
  860. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  861. Permissions: wire.AdminInfoPermissionsReadWrite,
  862. TLVBlock: wire.TLVBlock{
  863. TLVList: wire.TLVList{
  864. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidEmailLength),
  865. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  866. },
  867. },
  868. },
  869. },
  870. },
  871. }
  872. for _, tc := range cases {
  873. t.Run(tc.name, func(t *testing.T) {
  874. messageRelayer := newMockMessageRelayer(t)
  875. accountManager := newMockAccountManager(t)
  876. buddyBroadcaster := newMockbuddyBroadcaster(t)
  877. for _, params := range tc.mockParams.accountManagerUpdateEmailAddressParams {
  878. accountManager.EXPECT().
  879. UpdateEmailAddress(matchContext(), params.screenName, params.emailAddress).
  880. Return(params.err)
  881. }
  882. svc := AdminService{
  883. accountManager: accountManager,
  884. buddyBroadcaster: buddyBroadcaster,
  885. messageRelayer: messageRelayer,
  886. }
  887. outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.instance, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
  888. assert.ErrorIs(t, err, tc.expectErr)
  889. if tc.expectErr != nil {
  890. return
  891. }
  892. assert.Equal(t, tc.expectOutput, outputSNAC)
  893. })
  894. }
  895. }
  896. func TestAdminService_InfoChangeRequest_RegStatus(t *testing.T) {
  897. cases := []struct {
  898. // name is the unit test name
  899. name string
  900. // cfg is the app configuration
  901. cfg config.Config
  902. // inputSNAC is the SNAC sent from the client to the server
  903. inputSNAC wire.SNACMessage
  904. // mockParams is the list of params sent to mocks that satisfy this
  905. // method's dependencies
  906. mockParams mockParams
  907. // instance is the session of the user
  908. instance *state.SessionInstance
  909. // expectOutput is the SNAC sent from the server to client
  910. expectOutput wire.SNACMessage
  911. // expectErr is the expected error returned
  912. expectErr error
  913. }{
  914. {
  915. name: "user changes reg preference successfully",
  916. instance: newTestInstance("chattingchuck"),
  917. mockParams: mockParams{
  918. accountManagerParams: accountManagerParams{
  919. accountManagerUpdateRegStatusParams: accountManagerUpdateRegStatusParams{
  920. {
  921. screenName: state.NewIdentScreenName("chattingchuck"),
  922. regStatus: wire.AdminInfoRegStatusNoDisclosure,
  923. },
  924. },
  925. },
  926. },
  927. inputSNAC: wire.SNACMessage{
  928. Frame: wire.SNACFrame{
  929. FoodGroup: wire.Admin,
  930. SubGroup: wire.AdminInfoChangeRequest,
  931. RequestID: 1337,
  932. },
  933. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  934. TLVRestBlock: wire.TLVRestBlock{
  935. TLVList: wire.TLVList{
  936. wire.NewTLVBE(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusNoDisclosure),
  937. },
  938. },
  939. },
  940. },
  941. expectOutput: wire.SNACMessage{
  942. Frame: wire.SNACFrame{
  943. FoodGroup: wire.Admin,
  944. SubGroup: wire.AdminInfoChangeReply,
  945. RequestID: 1337,
  946. },
  947. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  948. Permissions: wire.AdminInfoPermissionsReadWrite,
  949. TLVBlock: wire.TLVBlock{
  950. TLVList: wire.TLVList{
  951. wire.NewTLVBE(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusNoDisclosure),
  952. },
  953. },
  954. },
  955. },
  956. },
  957. {
  958. name: "proposed reg preference invalid",
  959. instance: newTestInstance("chattingchuck"),
  960. inputSNAC: wire.SNACMessage{
  961. Frame: wire.SNACFrame{
  962. FoodGroup: wire.Admin,
  963. SubGroup: wire.AdminInfoChangeRequest,
  964. RequestID: 1337,
  965. },
  966. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  967. TLVRestBlock: wire.TLVRestBlock{
  968. TLVList: wire.TLVList{
  969. wire.NewTLVBE(wire.AdminTLVRegistrationStatus, uint16(0x1337)),
  970. },
  971. },
  972. },
  973. },
  974. expectOutput: wire.SNACMessage{
  975. Frame: wire.SNACFrame{
  976. FoodGroup: wire.Admin,
  977. SubGroup: wire.AdminInfoChangeReply,
  978. RequestID: 1337,
  979. },
  980. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  981. Permissions: wire.AdminInfoPermissionsReadWrite,
  982. TLVBlock: wire.TLVBlock{
  983. TLVList: wire.TLVList{
  984. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidRegistrationPreference),
  985. wire.NewTLVBE(wire.AdminTLVUrl, ""),
  986. },
  987. },
  988. },
  989. },
  990. },
  991. }
  992. for _, tc := range cases {
  993. t.Run(tc.name, func(t *testing.T) {
  994. messageRelayer := newMockMessageRelayer(t)
  995. accountManager := newMockAccountManager(t)
  996. buddyBroadcaster := newMockbuddyBroadcaster(t)
  997. for _, params := range tc.mockParams.accountManagerUpdateRegStatusParams {
  998. accountManager.EXPECT().
  999. UpdateRegStatus(context.Background(), params.screenName, params.regStatus).
  1000. Return(params.err)
  1001. }
  1002. svc := AdminService{
  1003. accountManager: accountManager,
  1004. buddyBroadcaster: buddyBroadcaster,
  1005. messageRelayer: messageRelayer,
  1006. }
  1007. outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.instance, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
  1008. assert.ErrorIs(t, err, tc.expectErr)
  1009. if tc.expectErr != nil {
  1010. return
  1011. }
  1012. assert.Equal(t, tc.expectOutput, outputSNAC)
  1013. })
  1014. }
  1015. }
  1016. func TestAdminService_InfoChangeRequest_Password(t *testing.T) {
  1017. cases := []struct {
  1018. // name is the unit test name
  1019. name string
  1020. // cfg is the app configuration
  1021. cfg config.Config
  1022. // inputSNAC is the SNAC sent from the client to the server
  1023. inputSNAC wire.SNACMessage
  1024. // mockParams is the list of params sent to mocks that satisfy this
  1025. // method's dependencies
  1026. mockParams mockParams
  1027. // instance is the session of the user
  1028. instance *state.SessionInstance
  1029. // expectOutput is the SNAC sent from the server to client
  1030. expectOutput wire.SNACMessage
  1031. // expectErr is the expected error returned
  1032. expectErr error
  1033. }{
  1034. {
  1035. name: "user changes password successfully",
  1036. instance: newTestInstance("me"),
  1037. mockParams: mockParams{
  1038. accountManagerParams: accountManagerParams{
  1039. accountManagerSetUserPasswordParams: accountManagerSetUserPasswordParams{
  1040. {
  1041. screenName: state.NewIdentScreenName("me"),
  1042. password: "newpass",
  1043. },
  1044. },
  1045. accountManagerUserParams: accountManagerUserParams{
  1046. {
  1047. screenName: state.NewIdentScreenName("me"),
  1048. result: func() *state.User {
  1049. user := &state.User{
  1050. AuthKey: "auth_key",
  1051. }
  1052. assert.NoError(t, user.HashPassword("oldpass"))
  1053. return user
  1054. }(),
  1055. },
  1056. },
  1057. },
  1058. },
  1059. inputSNAC: wire.SNACMessage{
  1060. Frame: wire.SNACFrame{
  1061. FoodGroup: wire.Admin,
  1062. SubGroup: wire.AdminInfoChangeRequest,
  1063. RequestID: 1337,
  1064. },
  1065. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1066. TLVRestBlock: wire.TLVRestBlock{
  1067. TLVList: wire.TLVList{
  1068. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  1069. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1070. },
  1071. },
  1072. },
  1073. },
  1074. expectOutput: wire.SNACMessage{
  1075. Frame: wire.SNACFrame{
  1076. FoodGroup: wire.Admin,
  1077. SubGroup: wire.AdminInfoChangeReply,
  1078. RequestID: 1337,
  1079. },
  1080. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1081. Permissions: wire.AdminInfoPermissionsReadWrite,
  1082. TLVBlock: wire.TLVBlock{
  1083. TLVList: wire.TLVList{
  1084. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1085. },
  1086. },
  1087. },
  1088. },
  1089. },
  1090. {
  1091. name: "user changes password, invalid new password length",
  1092. instance: newTestInstance("me"),
  1093. mockParams: mockParams{
  1094. accountManagerParams: accountManagerParams{
  1095. accountManagerSetUserPasswordParams: accountManagerSetUserPasswordParams{
  1096. {
  1097. screenName: state.NewIdentScreenName("me"),
  1098. password: "newpass",
  1099. err: state.ErrPasswordInvalid,
  1100. },
  1101. },
  1102. accountManagerUserParams: accountManagerUserParams{
  1103. {
  1104. screenName: state.NewIdentScreenName("me"),
  1105. result: func() *state.User {
  1106. user := &state.User{
  1107. AuthKey: "auth_key",
  1108. }
  1109. assert.NoError(t, user.HashPassword("oldpass"))
  1110. return user
  1111. }(),
  1112. },
  1113. },
  1114. },
  1115. },
  1116. inputSNAC: wire.SNACMessage{
  1117. Frame: wire.SNACFrame{
  1118. FoodGroup: wire.Admin,
  1119. SubGroup: wire.AdminInfoChangeRequest,
  1120. RequestID: 1337,
  1121. },
  1122. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1123. TLVRestBlock: wire.TLVRestBlock{
  1124. TLVList: wire.TLVList{
  1125. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  1126. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1127. },
  1128. },
  1129. },
  1130. },
  1131. expectOutput: wire.SNACMessage{
  1132. Frame: wire.SNACFrame{
  1133. FoodGroup: wire.Admin,
  1134. SubGroup: wire.AdminInfoChangeReply,
  1135. RequestID: 1337,
  1136. },
  1137. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1138. Permissions: wire.AdminInfoPermissionsReadWrite,
  1139. TLVBlock: wire.TLVBlock{
  1140. TLVList: wire.TLVList{
  1141. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1142. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidPasswordLength),
  1143. },
  1144. },
  1145. },
  1146. },
  1147. },
  1148. {
  1149. name: "user changes password, set user password runtime error",
  1150. instance: newTestInstance("me"),
  1151. mockParams: mockParams{
  1152. accountManagerParams: accountManagerParams{
  1153. accountManagerSetUserPasswordParams: accountManagerSetUserPasswordParams{
  1154. {
  1155. screenName: state.NewIdentScreenName("me"),
  1156. password: "newpass",
  1157. err: io.EOF,
  1158. },
  1159. },
  1160. accountManagerUserParams: accountManagerUserParams{
  1161. {
  1162. screenName: state.NewIdentScreenName("me"),
  1163. result: func() *state.User {
  1164. user := &state.User{
  1165. AuthKey: "auth_key",
  1166. }
  1167. assert.NoError(t, user.HashPassword("oldpass"))
  1168. return user
  1169. }(),
  1170. },
  1171. },
  1172. },
  1173. },
  1174. inputSNAC: wire.SNACMessage{
  1175. Frame: wire.SNACFrame{
  1176. FoodGroup: wire.Admin,
  1177. SubGroup: wire.AdminInfoChangeRequest,
  1178. RequestID: 1337,
  1179. },
  1180. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1181. TLVRestBlock: wire.TLVRestBlock{
  1182. TLVList: wire.TLVList{
  1183. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  1184. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1185. },
  1186. },
  1187. },
  1188. },
  1189. expectOutput: wire.SNACMessage{
  1190. Frame: wire.SNACFrame{
  1191. FoodGroup: wire.Admin,
  1192. SubGroup: wire.AdminInfoChangeReply,
  1193. RequestID: 1337,
  1194. },
  1195. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1196. Permissions: wire.AdminInfoPermissionsReadWrite,
  1197. TLVBlock: wire.TLVBlock{
  1198. TLVList: wire.TLVList{
  1199. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1200. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorAllOtherErrors),
  1201. },
  1202. },
  1203. },
  1204. },
  1205. },
  1206. {
  1207. name: "user changes password, old password is invalid",
  1208. instance: newTestInstance("me"),
  1209. mockParams: mockParams{
  1210. accountManagerParams: accountManagerParams{
  1211. accountManagerUserParams: accountManagerUserParams{
  1212. {
  1213. screenName: state.NewIdentScreenName("me"),
  1214. result: func() *state.User {
  1215. user := &state.User{
  1216. AuthKey: "auth_key",
  1217. }
  1218. assert.NoError(t, user.HashPassword("oldpass"))
  1219. return user
  1220. }(),
  1221. },
  1222. },
  1223. },
  1224. },
  1225. inputSNAC: wire.SNACMessage{
  1226. Frame: wire.SNACFrame{
  1227. FoodGroup: wire.Admin,
  1228. SubGroup: wire.AdminInfoChangeRequest,
  1229. RequestID: 1337,
  1230. },
  1231. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1232. TLVRestBlock: wire.TLVRestBlock{
  1233. TLVList: wire.TLVList{
  1234. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpassbad"),
  1235. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1236. },
  1237. },
  1238. },
  1239. },
  1240. expectOutput: wire.SNACMessage{
  1241. Frame: wire.SNACFrame{
  1242. FoodGroup: wire.Admin,
  1243. SubGroup: wire.AdminInfoChangeReply,
  1244. RequestID: 1337,
  1245. },
  1246. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1247. Permissions: wire.AdminInfoPermissionsReadWrite,
  1248. TLVBlock: wire.TLVBlock{
  1249. TLVList: wire.TLVList{
  1250. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1251. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorValidatePassword),
  1252. },
  1253. },
  1254. },
  1255. },
  1256. },
  1257. {
  1258. name: "user changes password, user not found",
  1259. instance: newTestInstance("me"),
  1260. mockParams: mockParams{
  1261. accountManagerParams: accountManagerParams{
  1262. accountManagerUserParams: accountManagerUserParams{
  1263. {
  1264. screenName: state.NewIdentScreenName("me"),
  1265. result: nil,
  1266. },
  1267. },
  1268. },
  1269. },
  1270. inputSNAC: wire.SNACMessage{
  1271. Frame: wire.SNACFrame{
  1272. FoodGroup: wire.Admin,
  1273. SubGroup: wire.AdminInfoChangeRequest,
  1274. RequestID: 1337,
  1275. },
  1276. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1277. TLVRestBlock: wire.TLVRestBlock{
  1278. TLVList: wire.TLVList{
  1279. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  1280. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1281. },
  1282. },
  1283. },
  1284. },
  1285. expectOutput: wire.SNACMessage{
  1286. Frame: wire.SNACFrame{
  1287. FoodGroup: wire.Admin,
  1288. SubGroup: wire.AdminInfoChangeReply,
  1289. RequestID: 1337,
  1290. },
  1291. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1292. Permissions: wire.AdminInfoPermissionsReadWrite,
  1293. TLVBlock: wire.TLVBlock{
  1294. TLVList: wire.TLVList{
  1295. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1296. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorAllOtherErrors),
  1297. },
  1298. },
  1299. },
  1300. },
  1301. },
  1302. {
  1303. name: "user changes password, user lookup runtime error",
  1304. instance: newTestInstance("me"),
  1305. mockParams: mockParams{
  1306. accountManagerParams: accountManagerParams{
  1307. accountManagerUserParams: accountManagerUserParams{
  1308. {
  1309. screenName: state.NewIdentScreenName("me"),
  1310. err: io.EOF,
  1311. },
  1312. },
  1313. },
  1314. },
  1315. inputSNAC: wire.SNACMessage{
  1316. Frame: wire.SNACFrame{
  1317. FoodGroup: wire.Admin,
  1318. SubGroup: wire.AdminInfoChangeRequest,
  1319. RequestID: 1337,
  1320. },
  1321. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1322. TLVRestBlock: wire.TLVRestBlock{
  1323. TLVList: wire.TLVList{
  1324. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  1325. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1326. },
  1327. },
  1328. },
  1329. },
  1330. expectOutput: wire.SNACMessage{
  1331. Frame: wire.SNACFrame{
  1332. FoodGroup: wire.Admin,
  1333. SubGroup: wire.AdminInfoChangeReply,
  1334. RequestID: 1337,
  1335. },
  1336. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1337. Permissions: wire.AdminInfoPermissionsReadWrite,
  1338. TLVBlock: wire.TLVBlock{
  1339. TLVList: wire.TLVList{
  1340. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1341. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorAllOtherErrors),
  1342. },
  1343. },
  1344. },
  1345. },
  1346. },
  1347. {
  1348. name: "user changes password, missing old password",
  1349. instance: newTestInstance("me"),
  1350. mockParams: mockParams{},
  1351. inputSNAC: wire.SNACMessage{
  1352. Frame: wire.SNACFrame{
  1353. FoodGroup: wire.Admin,
  1354. SubGroup: wire.AdminInfoChangeRequest,
  1355. RequestID: 1337,
  1356. },
  1357. Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  1358. TLVRestBlock: wire.TLVRestBlock{
  1359. TLVList: wire.TLVList{
  1360. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  1361. },
  1362. },
  1363. },
  1364. },
  1365. expectOutput: wire.SNACMessage{
  1366. Frame: wire.SNACFrame{
  1367. FoodGroup: wire.Admin,
  1368. SubGroup: wire.AdminInfoChangeReply,
  1369. RequestID: 1337,
  1370. },
  1371. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  1372. Permissions: wire.AdminInfoPermissionsReadWrite,
  1373. TLVBlock: wire.TLVBlock{
  1374. TLVList: wire.TLVList{
  1375. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  1376. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorNeedOldPassword),
  1377. },
  1378. },
  1379. },
  1380. },
  1381. },
  1382. }
  1383. for _, tc := range cases {
  1384. t.Run(tc.name, func(t *testing.T) {
  1385. accountManager := newMockAccountManager(t)
  1386. for _, params := range tc.mockParams.accountManagerUserParams {
  1387. accountManager.EXPECT().
  1388. User(matchContext(), params.screenName).
  1389. Return(params.result, params.err)
  1390. }
  1391. for _, params := range tc.mockParams.accountManagerSetUserPasswordParams {
  1392. accountManager.EXPECT().
  1393. SetUserPassword(matchContext(), params.screenName, params.password).
  1394. Return(params.err)
  1395. }
  1396. svc := AdminService{
  1397. accountManager: accountManager,
  1398. logger: slog.Default(),
  1399. }
  1400. outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.instance, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
  1401. assert.ErrorIs(t, err, tc.expectErr)
  1402. if tc.expectErr != nil {
  1403. return
  1404. }
  1405. assert.Equal(t, tc.expectOutput, outputSNAC)
  1406. })
  1407. }
  1408. }