]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Implement Scanner and Writer interface for FilePath
[rbdr/mobius] / hotline / transaction_handlers_test.go
1 package hotline
2
3 import (
4 "errors"
5 "fmt"
6 "github.com/stretchr/testify/assert"
7 "io/fs"
8 "math/rand"
9 "os"
10 "path/filepath"
11 "strings"
12 "testing"
13 "time"
14 )
15
16 func TestHandleSetChatSubject(t *testing.T) {
17 type args struct {
18 cc *ClientConn
19 t *Transaction
20 }
21 tests := []struct {
22 name string
23 args args
24 want []Transaction
25 wantErr bool
26 }{
27 {
28 name: "sends chat subject to private chat members",
29 args: args{
30 cc: &ClientConn{
31 UserName: []byte{0x00, 0x01},
32 Server: &Server{
33 PrivateChats: map[uint32]*PrivateChat{
34 uint32(1): {
35 Subject: "unset",
36 ClientConn: map[uint16]*ClientConn{
37 uint16(1): {
38 Account: &Account{
39 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
40 },
41 ID: &[]byte{0, 1},
42 },
43 uint16(2): {
44 Account: &Account{
45 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
46 },
47 ID: &[]byte{0, 2},
48 },
49 },
50 },
51 },
52 Clients: map[uint16]*ClientConn{
53 uint16(1): {
54 Account: &Account{
55 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
56 },
57 ID: &[]byte{0, 1},
58 },
59 uint16(2): {
60 Account: &Account{
61 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
62 },
63 ID: &[]byte{0, 2},
64 },
65 },
66 },
67 },
68 t: &Transaction{
69 Flags: 0x00,
70 IsReply: 0x00,
71 Type: []byte{0, 0x6a},
72 ID: []byte{0, 0, 0, 1},
73 ErrorCode: []byte{0, 0, 0, 0},
74 Fields: []Field{
75 NewField(fieldChatID, []byte{0, 0, 0, 1}),
76 NewField(fieldChatSubject, []byte("Test Subject")),
77 },
78 },
79 },
80 want: []Transaction{
81 {
82 clientID: &[]byte{0, 1},
83 Flags: 0x00,
84 IsReply: 0x00,
85 Type: []byte{0, 0x77},
86 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
87 ErrorCode: []byte{0, 0, 0, 0},
88 Fields: []Field{
89 NewField(fieldChatID, []byte{0, 0, 0, 1}),
90 NewField(fieldChatSubject, []byte("Test Subject")),
91 },
92 },
93 {
94 clientID: &[]byte{0, 2},
95 Flags: 0x00,
96 IsReply: 0x00,
97 Type: []byte{0, 0x77},
98 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
99 ErrorCode: []byte{0, 0, 0, 0},
100 Fields: []Field{
101 NewField(fieldChatID, []byte{0, 0, 0, 1}),
102 NewField(fieldChatSubject, []byte("Test Subject")),
103 },
104 },
105 },
106 wantErr: false,
107 },
108 }
109 for _, tt := range tests {
110 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
111
112 t.Run(tt.name, func(t *testing.T) {
113 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
114 if (err != nil) != tt.wantErr {
115 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
116 return
117 }
118 if !assert.Equal(t, tt.want, got) {
119 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
120 }
121 })
122 }
123 }
124
125 func TestHandleLeaveChat(t *testing.T) {
126 type args struct {
127 cc *ClientConn
128 t *Transaction
129 }
130 tests := []struct {
131 name string
132 args args
133 want []Transaction
134 wantErr bool
135 }{
136 {
137 name: "returns expected transactions",
138 args: args{
139 cc: &ClientConn{
140 ID: &[]byte{0, 2},
141 Server: &Server{
142 PrivateChats: map[uint32]*PrivateChat{
143 uint32(1): {
144 ClientConn: map[uint16]*ClientConn{
145 uint16(1): {
146 Account: &Account{
147 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
148 },
149 ID: &[]byte{0, 1},
150 },
151 uint16(2): {
152 Account: &Account{
153 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
154 },
155 ID: &[]byte{0, 2},
156 },
157 },
158 },
159 },
160 Clients: map[uint16]*ClientConn{
161 uint16(1): {
162 Account: &Account{
163 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
164 },
165 ID: &[]byte{0, 1},
166 },
167 uint16(2): {
168 Account: &Account{
169 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
170 },
171 ID: &[]byte{0, 2},
172 },
173 },
174 },
175 },
176 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
177 },
178 want: []Transaction{
179 {
180 clientID: &[]byte{0, 1},
181 Flags: 0x00,
182 IsReply: 0x00,
183 Type: []byte{0, 0x76},
184 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
185 ErrorCode: []byte{0, 0, 0, 0},
186 Fields: []Field{
187 NewField(fieldChatID, []byte{0, 0, 0, 1}),
188 NewField(fieldUserID, []byte{0, 2}),
189 },
190 },
191 },
192 wantErr: false,
193 },
194 }
195 for _, tt := range tests {
196 rand.Seed(1)
197 t.Run(tt.name, func(t *testing.T) {
198 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
199 if (err != nil) != tt.wantErr {
200 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
201 return
202 }
203 if !assert.Equal(t, tt.want, got) {
204 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
205 }
206 })
207 }
208 }
209
210 func TestHandleGetUserNameList(t *testing.T) {
211 type args struct {
212 cc *ClientConn
213 t *Transaction
214 }
215 tests := []struct {
216 name string
217 args args
218 want []Transaction
219 wantErr bool
220 }{
221 {
222 name: "replies with userlist transaction",
223 args: args{
224 cc: &ClientConn{
225
226 ID: &[]byte{1, 1},
227 Server: &Server{
228 Clients: map[uint16]*ClientConn{
229 uint16(1): {
230 ID: &[]byte{0, 1},
231 Icon: []byte{0, 2},
232 Flags: []byte{0, 3},
233 UserName: []byte{0, 4},
234 Agreed: true,
235 },
236 uint16(2): {
237 ID: &[]byte{0, 2},
238 Icon: []byte{0, 2},
239 Flags: []byte{0, 3},
240 UserName: []byte{0, 4},
241 Agreed: true,
242 },
243 uint16(3): {
244 ID: &[]byte{0, 3},
245 Icon: []byte{0, 2},
246 Flags: []byte{0, 3},
247 UserName: []byte{0, 4},
248 Agreed: false,
249 },
250 },
251 },
252 },
253 t: &Transaction{
254 ID: []byte{0, 0, 0, 1},
255 Type: []byte{0, 1},
256 },
257 },
258 want: []Transaction{
259 {
260 clientID: &[]byte{1, 1},
261 Flags: 0x00,
262 IsReply: 0x01,
263 Type: []byte{0, 1},
264 ID: []byte{0, 0, 0, 1},
265 ErrorCode: []byte{0, 0, 0, 0},
266 Fields: []Field{
267 NewField(
268 fieldUsernameWithInfo,
269 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
270 ),
271 NewField(
272 fieldUsernameWithInfo,
273 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
274 ),
275 },
276 },
277 },
278 wantErr: false,
279 },
280 }
281 for _, tt := range tests {
282 t.Run(tt.name, func(t *testing.T) {
283 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
284 if (err != nil) != tt.wantErr {
285 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
286 return
287 }
288 assert.Equal(t, tt.want, got)
289 })
290 }
291 }
292
293 func TestHandleChatSend(t *testing.T) {
294 type args struct {
295 cc *ClientConn
296 t *Transaction
297 }
298 tests := []struct {
299 name string
300 args args
301 want []Transaction
302 wantErr bool
303 }{
304 {
305 name: "sends chat msg transaction to all clients",
306 args: args{
307 cc: &ClientConn{
308 Account: &Account{
309 Access: func() accessBitmap {
310 var bits accessBitmap
311 bits.Set(accessSendChat)
312 return bits
313 }(),
314 },
315 UserName: []byte{0x00, 0x01},
316 Server: &Server{
317 Clients: map[uint16]*ClientConn{
318 uint16(1): {
319 Account: &Account{
320 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
321 },
322 ID: &[]byte{0, 1},
323 },
324 uint16(2): {
325 Account: &Account{
326 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
327 },
328 ID: &[]byte{0, 2},
329 },
330 },
331 },
332 },
333 t: &Transaction{
334 Fields: []Field{
335 NewField(fieldData, []byte("hai")),
336 },
337 },
338 },
339 want: []Transaction{
340 {
341 clientID: &[]byte{0, 1},
342 Flags: 0x00,
343 IsReply: 0x00,
344 Type: []byte{0, 0x6a},
345 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
346 ErrorCode: []byte{0, 0, 0, 0},
347 Fields: []Field{
348 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
349 },
350 },
351 {
352 clientID: &[]byte{0, 2},
353 Flags: 0x00,
354 IsReply: 0x00,
355 Type: []byte{0, 0x6a},
356 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
357 ErrorCode: []byte{0, 0, 0, 0},
358 Fields: []Field{
359 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
360 },
361 },
362 },
363 wantErr: false,
364 },
365 {
366 name: "when user does not have required permission",
367 args: args{
368 cc: &ClientConn{
369 Account: &Account{
370 Access: func() accessBitmap {
371 var bits accessBitmap
372 return bits
373 }(),
374 },
375 Server: &Server{
376 Accounts: map[string]*Account{},
377 },
378 },
379 t: NewTransaction(
380 tranChatSend, &[]byte{0, 1},
381 NewField(fieldData, []byte("hai")),
382 ),
383 },
384 want: []Transaction{
385 {
386 Flags: 0x00,
387 IsReply: 0x01,
388 Type: []byte{0, 0x00},
389 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
390 ErrorCode: []byte{0, 0, 0, 1},
391 Fields: []Field{
392 NewField(fieldError, []byte("You are not allowed to participate in chat.")),
393 },
394 },
395 },
396 wantErr: false,
397 },
398 {
399 name: "sends chat msg as emote if fieldChatOptions is set",
400 args: args{
401 cc: &ClientConn{
402 Account: &Account{
403 Access: func() accessBitmap {
404 var bits accessBitmap
405 bits.Set(accessSendChat)
406 return bits
407 }(),
408 },
409 UserName: []byte("Testy McTest"),
410 Server: &Server{
411 Clients: map[uint16]*ClientConn{
412 uint16(1): {
413 Account: &Account{
414 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
415 },
416 ID: &[]byte{0, 1},
417 },
418 uint16(2): {
419 Account: &Account{
420 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
421 },
422 ID: &[]byte{0, 2},
423 },
424 },
425 },
426 },
427 t: &Transaction{
428 Fields: []Field{
429 NewField(fieldData, []byte("performed action")),
430 NewField(fieldChatOptions, []byte{0x00, 0x01}),
431 },
432 },
433 },
434 want: []Transaction{
435 {
436 clientID: &[]byte{0, 1},
437 Flags: 0x00,
438 IsReply: 0x00,
439 Type: []byte{0, 0x6a},
440 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
441 ErrorCode: []byte{0, 0, 0, 0},
442 Fields: []Field{
443 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
444 },
445 },
446 {
447 clientID: &[]byte{0, 2},
448 Flags: 0x00,
449 IsReply: 0x00,
450 Type: []byte{0, 0x6a},
451 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
452 ErrorCode: []byte{0, 0, 0, 0},
453 Fields: []Field{
454 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
455 },
456 },
457 },
458 wantErr: false,
459 },
460 {
461 name: "only sends chat msg to clients with accessReadChat permission",
462 args: args{
463 cc: &ClientConn{
464 Account: &Account{
465 Access: func() accessBitmap {
466 var bits accessBitmap
467 bits.Set(accessSendChat)
468 return bits
469 }(),
470 },
471 UserName: []byte{0x00, 0x01},
472 Server: &Server{
473 Clients: map[uint16]*ClientConn{
474 uint16(1): {
475 Account: &Account{
476 Access: func() accessBitmap {
477 var bits accessBitmap
478 bits.Set(accessReadChat)
479 return bits
480 }()},
481 ID: &[]byte{0, 1},
482 },
483 uint16(2): {
484 Account: &Account{
485 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
486 },
487 ID: &[]byte{0, 2},
488 },
489 },
490 },
491 },
492 t: &Transaction{
493 Fields: []Field{
494 NewField(fieldData, []byte("hai")),
495 },
496 },
497 },
498 want: []Transaction{
499 {
500 clientID: &[]byte{0, 1},
501 Flags: 0x00,
502 IsReply: 0x00,
503 Type: []byte{0, 0x6a},
504 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
505 ErrorCode: []byte{0, 0, 0, 0},
506 Fields: []Field{
507 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
508 },
509 },
510 },
511 wantErr: false,
512 },
513 {
514 name: "only sends private chat msg to members of private chat",
515 args: args{
516 cc: &ClientConn{
517 Account: &Account{
518 Access: func() accessBitmap {
519 var bits accessBitmap
520 bits.Set(accessSendChat)
521 return bits
522 }(),
523 },
524 UserName: []byte{0x00, 0x01},
525 Server: &Server{
526 PrivateChats: map[uint32]*PrivateChat{
527 uint32(1): {
528 ClientConn: map[uint16]*ClientConn{
529 uint16(1): {
530 ID: &[]byte{0, 1},
531 },
532 uint16(2): {
533 ID: &[]byte{0, 2},
534 },
535 },
536 },
537 },
538 Clients: map[uint16]*ClientConn{
539 uint16(1): {
540 Account: &Account{
541 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
542 },
543 ID: &[]byte{0, 1},
544 },
545 uint16(2): {
546 Account: &Account{
547 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
548 },
549 ID: &[]byte{0, 2},
550 },
551 uint16(3): {
552 Account: &Account{
553 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
554 },
555 ID: &[]byte{0, 3},
556 },
557 },
558 },
559 },
560 t: &Transaction{
561 Fields: []Field{
562 NewField(fieldData, []byte("hai")),
563 NewField(fieldChatID, []byte{0, 0, 0, 1}),
564 },
565 },
566 },
567 want: []Transaction{
568 {
569 clientID: &[]byte{0, 1},
570 Flags: 0x00,
571 IsReply: 0x00,
572 Type: []byte{0, 0x6a},
573 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
574 ErrorCode: []byte{0, 0, 0, 0},
575 Fields: []Field{
576 NewField(fieldChatID, []byte{0, 0, 0, 1}),
577 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
578 },
579 },
580 {
581 clientID: &[]byte{0, 2},
582 Flags: 0x00,
583 IsReply: 0x00,
584 Type: []byte{0, 0x6a},
585 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
586 ErrorCode: []byte{0, 0, 0, 0},
587 Fields: []Field{
588 NewField(fieldChatID, []byte{0, 0, 0, 1}),
589 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
590 },
591 },
592 },
593 wantErr: false,
594 },
595 }
596 for _, tt := range tests {
597 t.Run(tt.name, func(t *testing.T) {
598 got, err := HandleChatSend(tt.args.cc, tt.args.t)
599
600 if (err != nil) != tt.wantErr {
601 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
602 return
603 }
604 tranAssertEqual(t, tt.want, got)
605 })
606 }
607 }
608
609 func TestHandleGetFileInfo(t *testing.T) {
610 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
611
612 type args struct {
613 cc *ClientConn
614 t *Transaction
615 }
616 tests := []struct {
617 name string
618 args args
619 wantRes []Transaction
620 wantErr bool
621 }{
622 {
623 name: "returns expected fields when a valid file is requested",
624 args: args{
625 cc: &ClientConn{
626 ID: &[]byte{0x00, 0x01},
627 Server: &Server{
628 FS: &OSFileStore{},
629 Config: &Config{
630 FileRoot: func() string {
631 path, _ := os.Getwd()
632 return filepath.Join(path, "/test/config/Files")
633 }(),
634 },
635 },
636 },
637 t: NewTransaction(
638 tranGetFileInfo, nil,
639 NewField(fieldFileName, []byte("testfile.txt")),
640 NewField(fieldFilePath, []byte{0x00, 0x00}),
641 ),
642 },
643 wantRes: []Transaction{
644 {
645 clientID: &[]byte{0, 1},
646 Flags: 0x00,
647 IsReply: 0x01,
648 Type: []byte{0, 0xce},
649 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
650 ErrorCode: []byte{0, 0, 0, 0},
651 Fields: []Field{
652 NewField(fieldFileName, []byte("testfile.txt")),
653 NewField(fieldFileTypeString, []byte("Text File")),
654 NewField(fieldFileCreatorString, []byte("ttxt")),
655 NewField(fieldFileComment, []byte{}),
656 NewField(fieldFileType, []byte("TEXT")),
657 NewField(fieldFileCreateDate, make([]byte, 8)),
658 NewField(fieldFileModifyDate, make([]byte, 8)),
659 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
660 },
661 },
662 },
663 wantErr: false,
664 },
665 }
666 for _, tt := range tests {
667 t.Run(tt.name, func(t *testing.T) {
668 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
669
670 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
671 if (err != nil) != tt.wantErr {
672 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
673 return
674 }
675
676 // Clear the fileWrapper timestamp fields to work around problems running the tests in multiple timezones
677 // TODO: revisit how to test this by mocking the stat calls
678 gotRes[0].Fields[5].Data = make([]byte, 8)
679 gotRes[0].Fields[6].Data = make([]byte, 8)
680 if !assert.Equal(t, tt.wantRes, gotRes) {
681 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
682 }
683 })
684 }
685 }
686
687 func TestHandleNewFolder(t *testing.T) {
688 type args struct {
689 cc *ClientConn
690 t *Transaction
691 }
692 tests := []struct {
693 name string
694 args args
695 wantRes []Transaction
696 wantErr bool
697 }{
698 {
699 name: "without required permission",
700 args: args{
701 cc: &ClientConn{
702 Account: &Account{
703 Access: func() accessBitmap {
704 var bits accessBitmap
705 return bits
706 }(),
707 },
708 },
709 t: NewTransaction(
710 accessCreateFolder,
711 &[]byte{0, 0},
712 ),
713 },
714 wantRes: []Transaction{
715 {
716 Flags: 0x00,
717 IsReply: 0x01,
718 Type: []byte{0, 0x00},
719 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
720 ErrorCode: []byte{0, 0, 0, 1},
721 Fields: []Field{
722 NewField(fieldError, []byte("You are not allowed to create folders.")),
723 },
724 },
725 },
726 wantErr: false,
727 },
728 {
729 name: "when path is nested",
730 args: args{
731 cc: &ClientConn{
732 Account: &Account{
733 Access: func() accessBitmap {
734 var bits accessBitmap
735 bits.Set(accessCreateFolder)
736 return bits
737 }(),
738 },
739 ID: &[]byte{0, 1},
740 Server: &Server{
741 Config: &Config{
742 FileRoot: "/Files/",
743 },
744 FS: func() *MockFileStore {
745 mfs := &MockFileStore{}
746 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
747 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
748 return mfs
749 }(),
750 },
751 },
752 t: NewTransaction(
753 tranNewFolder, &[]byte{0, 1},
754 NewField(fieldFileName, []byte("testFolder")),
755 NewField(fieldFilePath, []byte{
756 0x00, 0x01,
757 0x00, 0x00,
758 0x03,
759 0x61, 0x61, 0x61,
760 }),
761 ),
762 },
763 wantRes: []Transaction{
764 {
765 clientID: &[]byte{0, 1},
766 Flags: 0x00,
767 IsReply: 0x01,
768 Type: []byte{0, 0xcd},
769 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
770 ErrorCode: []byte{0, 0, 0, 0},
771 },
772 },
773 wantErr: false,
774 },
775 {
776 name: "when path is not nested",
777 args: args{
778 cc: &ClientConn{
779 Account: &Account{
780 Access: func() accessBitmap {
781 var bits accessBitmap
782 bits.Set(accessCreateFolder)
783 return bits
784 }(),
785 },
786 ID: &[]byte{0, 1},
787 Server: &Server{
788 Config: &Config{
789 FileRoot: "/Files",
790 },
791 FS: func() *MockFileStore {
792 mfs := &MockFileStore{}
793 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
794 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
795 return mfs
796 }(),
797 },
798 },
799 t: NewTransaction(
800 tranNewFolder, &[]byte{0, 1},
801 NewField(fieldFileName, []byte("testFolder")),
802 ),
803 },
804 wantRes: []Transaction{
805 {
806 clientID: &[]byte{0, 1},
807 Flags: 0x00,
808 IsReply: 0x01,
809 Type: []byte{0, 0xcd},
810 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
811 ErrorCode: []byte{0, 0, 0, 0},
812 },
813 },
814 wantErr: false,
815 },
816 {
817 name: "when Write returns an err",
818 args: args{
819 cc: &ClientConn{
820 Account: &Account{
821 Access: func() accessBitmap {
822 var bits accessBitmap
823 bits.Set(accessCreateFolder)
824 return bits
825 }(),
826 },
827 ID: &[]byte{0, 1},
828 Server: &Server{
829 Config: &Config{
830 FileRoot: "/Files/",
831 },
832 FS: func() *MockFileStore {
833 mfs := &MockFileStore{}
834 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
835 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
836 return mfs
837 }(),
838 },
839 },
840 t: NewTransaction(
841 tranNewFolder, &[]byte{0, 1},
842 NewField(fieldFileName, []byte("testFolder")),
843 NewField(fieldFilePath, []byte{
844 0x00,
845 }),
846 ),
847 },
848 wantRes: []Transaction{},
849 wantErr: true,
850 },
851 {
852 name: "fieldFileName does not allow directory traversal",
853 args: args{
854 cc: &ClientConn{
855 Account: &Account{
856 Access: func() accessBitmap {
857 var bits accessBitmap
858 bits.Set(accessCreateFolder)
859 return bits
860 }(),
861 },
862 ID: &[]byte{0, 1},
863 Server: &Server{
864 Config: &Config{
865 FileRoot: "/Files/",
866 },
867 FS: func() *MockFileStore {
868 mfs := &MockFileStore{}
869 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
870 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
871 return mfs
872 }(),
873 },
874 },
875 t: NewTransaction(
876 tranNewFolder, &[]byte{0, 1},
877 NewField(fieldFileName, []byte("../../testFolder")),
878 ),
879 },
880 wantRes: []Transaction{
881 {
882 clientID: &[]byte{0, 1},
883 Flags: 0x00,
884 IsReply: 0x01,
885 Type: []byte{0, 0xcd},
886 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
887 ErrorCode: []byte{0, 0, 0, 0},
888 },
889 }, wantErr: false,
890 },
891 {
892 name: "fieldFilePath does not allow directory traversal",
893 args: args{
894 cc: &ClientConn{
895 Account: &Account{
896 Access: func() accessBitmap {
897 var bits accessBitmap
898 bits.Set(accessCreateFolder)
899 return bits
900 }(),
901 },
902 ID: &[]byte{0, 1},
903 Server: &Server{
904 Config: &Config{
905 FileRoot: "/Files/",
906 },
907 FS: func() *MockFileStore {
908 mfs := &MockFileStore{}
909 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
910 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
911 return mfs
912 }(),
913 },
914 },
915 t: NewTransaction(
916 tranNewFolder, &[]byte{0, 1},
917 NewField(fieldFileName, []byte("testFolder")),
918 NewField(fieldFilePath, []byte{
919 0x00, 0x02,
920 0x00, 0x00,
921 0x03,
922 0x2e, 0x2e, 0x2f,
923 0x00, 0x00,
924 0x03,
925 0x66, 0x6f, 0x6f,
926 }),
927 ),
928 },
929 wantRes: []Transaction{
930 {
931 clientID: &[]byte{0, 1},
932 Flags: 0x00,
933 IsReply: 0x01,
934 Type: []byte{0, 0xcd},
935 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
936 ErrorCode: []byte{0, 0, 0, 0},
937 },
938 }, wantErr: false,
939 },
940 }
941 for _, tt := range tests {
942 t.Run(tt.name, func(t *testing.T) {
943
944 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
945 if (err != nil) != tt.wantErr {
946 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
947 return
948 }
949
950 if !tranAssertEqual(t, tt.wantRes, gotRes) {
951 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
952 }
953 })
954 }
955 }
956
957 func TestHandleUploadFile(t *testing.T) {
958 type args struct {
959 cc *ClientConn
960 t *Transaction
961 }
962 tests := []struct {
963 name string
964 args args
965 wantRes []Transaction
966 wantErr bool
967 }{
968 {
969 name: "when request is valid and user has Upload Anywhere permission",
970 args: args{
971 cc: &ClientConn{
972 Server: &Server{
973 FS: &OSFileStore{},
974 fileTransfers: map[[4]byte]*FileTransfer{},
975 Config: &Config{
976 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
977 }},
978 transfers: map[int]map[[4]byte]*FileTransfer{
979 FileUpload: {},
980 },
981 Account: &Account{
982 Access: func() accessBitmap {
983 var bits accessBitmap
984 bits.Set(accessUploadFile)
985 bits.Set(accessUploadAnywhere)
986 return bits
987 }(),
988 },
989 },
990 t: NewTransaction(
991 tranUploadFile, &[]byte{0, 1},
992 NewField(fieldFileName, []byte("testFile")),
993 NewField(fieldFilePath, []byte{
994 0x00, 0x01,
995 0x00, 0x00,
996 0x03,
997 0x2e, 0x2e, 0x2f,
998 }),
999 ),
1000 },
1001 wantRes: []Transaction{
1002 {
1003 Flags: 0x00,
1004 IsReply: 0x01,
1005 Type: []byte{0, 0xcb},
1006 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1007 ErrorCode: []byte{0, 0, 0, 0},
1008 Fields: []Field{
1009 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1010 },
1011 },
1012 },
1013 wantErr: false,
1014 },
1015 {
1016 name: "when user does not have required access",
1017 args: args{
1018 cc: &ClientConn{
1019 Account: &Account{
1020 Access: func() accessBitmap {
1021 var bits accessBitmap
1022 return bits
1023 }(),
1024 },
1025 },
1026 t: NewTransaction(
1027 tranUploadFile, &[]byte{0, 1},
1028 NewField(fieldFileName, []byte("testFile")),
1029 NewField(fieldFilePath, []byte{
1030 0x00, 0x01,
1031 0x00, 0x00,
1032 0x03,
1033 0x2e, 0x2e, 0x2f,
1034 }),
1035 ),
1036 },
1037 wantRes: []Transaction{
1038 {
1039 Flags: 0x00,
1040 IsReply: 0x01,
1041 Type: []byte{0, 0x00},
1042 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1043 ErrorCode: []byte{0, 0, 0, 1},
1044 Fields: []Field{
1045 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1046 },
1047 },
1048 },
1049 wantErr: false,
1050 },
1051 }
1052 for _, tt := range tests {
1053 t.Run(tt.name, func(t *testing.T) {
1054 rand.Seed(1)
1055 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
1056 if (err != nil) != tt.wantErr {
1057 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
1058 return
1059 }
1060
1061 tranAssertEqual(t, tt.wantRes, gotRes)
1062
1063 })
1064 }
1065 }
1066
1067 func TestHandleMakeAlias(t *testing.T) {
1068 type args struct {
1069 cc *ClientConn
1070 t *Transaction
1071 }
1072 tests := []struct {
1073 name string
1074 args args
1075 wantRes []Transaction
1076 wantErr bool
1077 }{
1078 {
1079 name: "with valid input and required permissions",
1080 args: args{
1081 cc: &ClientConn{
1082 logger: NewTestLogger(),
1083 Account: &Account{
1084 Access: func() accessBitmap {
1085 var bits accessBitmap
1086 bits.Set(accessMakeAlias)
1087 return bits
1088 }(),
1089 },
1090 Server: &Server{
1091 Config: &Config{
1092 FileRoot: func() string {
1093 path, _ := os.Getwd()
1094 return path + "/test/config/Files"
1095 }(),
1096 },
1097 Logger: NewTestLogger(),
1098 FS: func() *MockFileStore {
1099 mfs := &MockFileStore{}
1100 path, _ := os.Getwd()
1101 mfs.On(
1102 "Symlink",
1103 path+"/test/config/Files/foo/testFile",
1104 path+"/test/config/Files/bar/testFile",
1105 ).Return(nil)
1106 return mfs
1107 }(),
1108 },
1109 },
1110 t: NewTransaction(
1111 tranMakeFileAlias, &[]byte{0, 1},
1112 NewField(fieldFileName, []byte("testFile")),
1113 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1114 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1115 ),
1116 },
1117 wantRes: []Transaction{
1118 {
1119 Flags: 0x00,
1120 IsReply: 0x01,
1121 Type: []byte{0, 0xd1},
1122 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1123 ErrorCode: []byte{0, 0, 0, 0},
1124 Fields: []Field(nil),
1125 },
1126 },
1127 wantErr: false,
1128 },
1129 {
1130 name: "when symlink returns an error",
1131 args: args{
1132 cc: &ClientConn{
1133 logger: NewTestLogger(),
1134 Account: &Account{
1135 Access: func() accessBitmap {
1136 var bits accessBitmap
1137 bits.Set(accessMakeAlias)
1138 return bits
1139 }(),
1140 },
1141 Server: &Server{
1142 Config: &Config{
1143 FileRoot: func() string {
1144 path, _ := os.Getwd()
1145 return path + "/test/config/Files"
1146 }(),
1147 },
1148 Logger: NewTestLogger(),
1149 FS: func() *MockFileStore {
1150 mfs := &MockFileStore{}
1151 path, _ := os.Getwd()
1152 mfs.On(
1153 "Symlink",
1154 path+"/test/config/Files/foo/testFile",
1155 path+"/test/config/Files/bar/testFile",
1156 ).Return(errors.New("ohno"))
1157 return mfs
1158 }(),
1159 },
1160 },
1161 t: NewTransaction(
1162 tranMakeFileAlias, &[]byte{0, 1},
1163 NewField(fieldFileName, []byte("testFile")),
1164 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1165 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1166 ),
1167 },
1168 wantRes: []Transaction{
1169 {
1170 Flags: 0x00,
1171 IsReply: 0x01,
1172 Type: []byte{0, 0x00},
1173 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1174 ErrorCode: []byte{0, 0, 0, 1},
1175 Fields: []Field{
1176 NewField(fieldError, []byte("Error creating alias")),
1177 },
1178 },
1179 },
1180 wantErr: false,
1181 },
1182 {
1183 name: "when user does not have required permission",
1184 args: args{
1185 cc: &ClientConn{
1186 logger: NewTestLogger(),
1187 Account: &Account{
1188 Access: func() accessBitmap {
1189 var bits accessBitmap
1190 return bits
1191 }(),
1192 },
1193 Server: &Server{
1194 Config: &Config{
1195 FileRoot: func() string {
1196 path, _ := os.Getwd()
1197 return path + "/test/config/Files"
1198 }(),
1199 },
1200 },
1201 },
1202 t: NewTransaction(
1203 tranMakeFileAlias, &[]byte{0, 1},
1204 NewField(fieldFileName, []byte("testFile")),
1205 NewField(fieldFilePath, []byte{
1206 0x00, 0x01,
1207 0x00, 0x00,
1208 0x03,
1209 0x2e, 0x2e, 0x2e,
1210 }),
1211 NewField(fieldFileNewPath, []byte{
1212 0x00, 0x01,
1213 0x00, 0x00,
1214 0x03,
1215 0x2e, 0x2e, 0x2e,
1216 }),
1217 ),
1218 },
1219 wantRes: []Transaction{
1220 {
1221 Flags: 0x00,
1222 IsReply: 0x01,
1223 Type: []byte{0, 0x00},
1224 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1225 ErrorCode: []byte{0, 0, 0, 1},
1226 Fields: []Field{
1227 NewField(fieldError, []byte("You are not allowed to make aliases.")),
1228 },
1229 },
1230 },
1231 wantErr: false,
1232 },
1233 }
1234 for _, tt := range tests {
1235 t.Run(tt.name, func(t *testing.T) {
1236 gotRes, err := HandleMakeAlias(tt.args.cc, tt.args.t)
1237 if (err != nil) != tt.wantErr {
1238 t.Errorf("HandleMakeAlias(%v, %v)", tt.args.cc, tt.args.t)
1239 return
1240 }
1241
1242 tranAssertEqual(t, tt.wantRes, gotRes)
1243 })
1244 }
1245 }
1246
1247 func TestHandleGetUser(t *testing.T) {
1248 type args struct {
1249 cc *ClientConn
1250 t *Transaction
1251 }
1252 tests := []struct {
1253 name string
1254 args args
1255 wantRes []Transaction
1256 wantErr assert.ErrorAssertionFunc
1257 }{
1258 {
1259 name: "when account is valid",
1260 args: args{
1261 cc: &ClientConn{
1262 Account: &Account{
1263 Access: func() accessBitmap {
1264 var bits accessBitmap
1265 bits.Set(accessOpenUser)
1266 return bits
1267 }(),
1268 },
1269 Server: &Server{
1270 Accounts: map[string]*Account{
1271 "guest": {
1272 Login: "guest",
1273 Name: "Guest",
1274 Password: "password",
1275 Access: accessBitmap{},
1276 },
1277 },
1278 },
1279 },
1280 t: NewTransaction(
1281 tranGetUser, &[]byte{0, 1},
1282 NewField(fieldUserLogin, []byte("guest")),
1283 ),
1284 },
1285 wantRes: []Transaction{
1286 {
1287 Flags: 0x00,
1288 IsReply: 0x01,
1289 Type: []byte{0x01, 0x60},
1290 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1291 ErrorCode: []byte{0, 0, 0, 0},
1292 Fields: []Field{
1293 NewField(fieldUserName, []byte("Guest")),
1294 NewField(fieldUserLogin, negateString([]byte("guest"))),
1295 NewField(fieldUserPassword, []byte("password")),
1296 NewField(fieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
1297 },
1298 },
1299 },
1300 wantErr: assert.NoError,
1301 },
1302 {
1303 name: "when user does not have required permission",
1304 args: args{
1305 cc: &ClientConn{
1306 Account: &Account{
1307 Access: func() accessBitmap {
1308 var bits accessBitmap
1309 return bits
1310 }(),
1311 },
1312 Server: &Server{
1313 Accounts: map[string]*Account{},
1314 },
1315 },
1316 t: NewTransaction(
1317 tranGetUser, &[]byte{0, 1},
1318 NewField(fieldUserLogin, []byte("nonExistentUser")),
1319 ),
1320 },
1321 wantRes: []Transaction{
1322 {
1323 Flags: 0x00,
1324 IsReply: 0x01,
1325 Type: []byte{0, 0x00},
1326 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1327 ErrorCode: []byte{0, 0, 0, 1},
1328 Fields: []Field{
1329 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1330 },
1331 },
1332 },
1333 wantErr: assert.NoError,
1334 },
1335 {
1336 name: "when account does not exist",
1337 args: args{
1338 cc: &ClientConn{
1339 Account: &Account{
1340 Access: func() accessBitmap {
1341 var bits accessBitmap
1342 bits.Set(accessOpenUser)
1343 return bits
1344 }(),
1345 },
1346 Server: &Server{
1347 Accounts: map[string]*Account{},
1348 },
1349 },
1350 t: NewTransaction(
1351 tranGetUser, &[]byte{0, 1},
1352 NewField(fieldUserLogin, []byte("nonExistentUser")),
1353 ),
1354 },
1355 wantRes: []Transaction{
1356 {
1357 Flags: 0x00,
1358 IsReply: 0x01,
1359 Type: []byte{0, 0x00},
1360 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1361 ErrorCode: []byte{0, 0, 0, 1},
1362 Fields: []Field{
1363 NewField(fieldError, []byte("Account does not exist.")),
1364 },
1365 },
1366 },
1367 wantErr: assert.NoError,
1368 },
1369 }
1370 for _, tt := range tests {
1371 t.Run(tt.name, func(t *testing.T) {
1372 gotRes, err := HandleGetUser(tt.args.cc, tt.args.t)
1373 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetUser(%v, %v)", tt.args.cc, tt.args.t)) {
1374 return
1375 }
1376
1377 tranAssertEqual(t, tt.wantRes, gotRes)
1378 })
1379 }
1380 }
1381
1382 func TestHandleDeleteUser(t *testing.T) {
1383 type args struct {
1384 cc *ClientConn
1385 t *Transaction
1386 }
1387 tests := []struct {
1388 name string
1389 args args
1390 wantRes []Transaction
1391 wantErr assert.ErrorAssertionFunc
1392 }{
1393 {
1394 name: "when user dataFile",
1395 args: args{
1396 cc: &ClientConn{
1397 Account: &Account{
1398 Access: func() accessBitmap {
1399 var bits accessBitmap
1400 bits.Set(accessDeleteUser)
1401 return bits
1402 }(),
1403 },
1404 Server: &Server{
1405 Accounts: map[string]*Account{
1406 "testuser": {
1407 Login: "testuser",
1408 Name: "Testy McTest",
1409 Password: "password",
1410 Access: accessBitmap{},
1411 },
1412 },
1413 FS: func() *MockFileStore {
1414 mfs := &MockFileStore{}
1415 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1416 return mfs
1417 }(),
1418 },
1419 },
1420 t: NewTransaction(
1421 tranDeleteUser, &[]byte{0, 1},
1422 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1423 ),
1424 },
1425 wantRes: []Transaction{
1426 {
1427 Flags: 0x00,
1428 IsReply: 0x01,
1429 Type: []byte{0x1, 0x5f},
1430 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1431 ErrorCode: []byte{0, 0, 0, 0},
1432 Fields: []Field(nil),
1433 },
1434 },
1435 wantErr: assert.NoError,
1436 },
1437 {
1438 name: "when user does not have required permission",
1439 args: args{
1440 cc: &ClientConn{
1441 Account: &Account{
1442 Access: func() accessBitmap {
1443 var bits accessBitmap
1444 return bits
1445 }(),
1446 },
1447 Server: &Server{
1448 Accounts: map[string]*Account{},
1449 },
1450 },
1451 t: NewTransaction(
1452 tranDeleteUser, &[]byte{0, 1},
1453 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1454 ),
1455 },
1456 wantRes: []Transaction{
1457 {
1458 Flags: 0x00,
1459 IsReply: 0x01,
1460 Type: []byte{0, 0x00},
1461 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1462 ErrorCode: []byte{0, 0, 0, 1},
1463 Fields: []Field{
1464 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
1465 },
1466 },
1467 },
1468 wantErr: assert.NoError,
1469 },
1470 }
1471 for _, tt := range tests {
1472 t.Run(tt.name, func(t *testing.T) {
1473 gotRes, err := HandleDeleteUser(tt.args.cc, tt.args.t)
1474 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteUser(%v, %v)", tt.args.cc, tt.args.t)) {
1475 return
1476 }
1477
1478 tranAssertEqual(t, tt.wantRes, gotRes)
1479 })
1480 }
1481 }
1482
1483 func TestHandleGetMsgs(t *testing.T) {
1484 type args struct {
1485 cc *ClientConn
1486 t *Transaction
1487 }
1488 tests := []struct {
1489 name string
1490 args args
1491 wantRes []Transaction
1492 wantErr assert.ErrorAssertionFunc
1493 }{
1494 {
1495 name: "returns news data",
1496 args: args{
1497 cc: &ClientConn{
1498 Account: &Account{
1499 Access: func() accessBitmap {
1500 var bits accessBitmap
1501 bits.Set(accessNewsReadArt)
1502 return bits
1503 }(),
1504 },
1505 Server: &Server{
1506 FlatNews: []byte("TEST"),
1507 },
1508 },
1509 t: NewTransaction(
1510 tranGetMsgs, &[]byte{0, 1},
1511 ),
1512 },
1513 wantRes: []Transaction{
1514 {
1515 Flags: 0x00,
1516 IsReply: 0x01,
1517 Type: []byte{0, 0x65},
1518 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1519 ErrorCode: []byte{0, 0, 0, 0},
1520 Fields: []Field{
1521 NewField(fieldData, []byte("TEST")),
1522 },
1523 },
1524 },
1525 wantErr: assert.NoError,
1526 },
1527 {
1528 name: "when user does not have required permission",
1529 args: args{
1530 cc: &ClientConn{
1531 Account: &Account{
1532 Access: func() accessBitmap {
1533 var bits accessBitmap
1534 return bits
1535 }(),
1536 },
1537 Server: &Server{
1538 Accounts: map[string]*Account{},
1539 },
1540 },
1541 t: NewTransaction(
1542 tranGetMsgs, &[]byte{0, 1},
1543 ),
1544 },
1545 wantRes: []Transaction{
1546 {
1547 Flags: 0x00,
1548 IsReply: 0x01,
1549 Type: []byte{0, 0x00},
1550 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1551 ErrorCode: []byte{0, 0, 0, 1},
1552 Fields: []Field{
1553 NewField(fieldError, []byte("You are not allowed to read news.")),
1554 },
1555 },
1556 },
1557 wantErr: assert.NoError,
1558 },
1559 }
1560 for _, tt := range tests {
1561 t.Run(tt.name, func(t *testing.T) {
1562 gotRes, err := HandleGetMsgs(tt.args.cc, tt.args.t)
1563 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetMsgs(%v, %v)", tt.args.cc, tt.args.t)) {
1564 return
1565 }
1566
1567 tranAssertEqual(t, tt.wantRes, gotRes)
1568 })
1569 }
1570 }
1571
1572 func TestHandleNewUser(t *testing.T) {
1573 type args struct {
1574 cc *ClientConn
1575 t *Transaction
1576 }
1577 tests := []struct {
1578 name string
1579 args args
1580 wantRes []Transaction
1581 wantErr assert.ErrorAssertionFunc
1582 }{
1583 {
1584 name: "when user does not have required permission",
1585 args: args{
1586 cc: &ClientConn{
1587 Account: &Account{
1588 Access: func() accessBitmap {
1589 var bits accessBitmap
1590 return bits
1591 }(),
1592 },
1593 Server: &Server{
1594 Accounts: map[string]*Account{},
1595 },
1596 },
1597 t: NewTransaction(
1598 tranNewUser, &[]byte{0, 1},
1599 ),
1600 },
1601 wantRes: []Transaction{
1602 {
1603 Flags: 0x00,
1604 IsReply: 0x01,
1605 Type: []byte{0, 0x00},
1606 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1607 ErrorCode: []byte{0, 0, 0, 1},
1608 Fields: []Field{
1609 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1610 },
1611 },
1612 },
1613 wantErr: assert.NoError,
1614 },
1615 }
1616 for _, tt := range tests {
1617 t.Run(tt.name, func(t *testing.T) {
1618 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1619 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1620 return
1621 }
1622
1623 tranAssertEqual(t, tt.wantRes, gotRes)
1624 })
1625 }
1626 }
1627
1628 func TestHandleListUsers(t *testing.T) {
1629 type args struct {
1630 cc *ClientConn
1631 t *Transaction
1632 }
1633 tests := []struct {
1634 name string
1635 args args
1636 wantRes []Transaction
1637 wantErr assert.ErrorAssertionFunc
1638 }{
1639 {
1640 name: "when user does not have required permission",
1641 args: args{
1642 cc: &ClientConn{
1643 Account: &Account{
1644 Access: func() accessBitmap {
1645 var bits accessBitmap
1646 return bits
1647 }(),
1648 },
1649 Server: &Server{
1650 Accounts: map[string]*Account{},
1651 },
1652 },
1653 t: NewTransaction(
1654 tranNewUser, &[]byte{0, 1},
1655 ),
1656 },
1657 wantRes: []Transaction{
1658 {
1659 Flags: 0x00,
1660 IsReply: 0x01,
1661 Type: []byte{0, 0x00},
1662 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1663 ErrorCode: []byte{0, 0, 0, 1},
1664 Fields: []Field{
1665 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1666 },
1667 },
1668 },
1669 wantErr: assert.NoError,
1670 },
1671 {
1672 name: "when user has required permission",
1673 args: args{
1674 cc: &ClientConn{
1675 Account: &Account{
1676 Access: func() accessBitmap {
1677 var bits accessBitmap
1678 bits.Set(accessOpenUser)
1679 return bits
1680 }(),
1681 },
1682 Server: &Server{
1683 Accounts: map[string]*Account{
1684 "guest": {
1685 Name: "guest",
1686 Login: "guest",
1687 Password: "zz",
1688 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1689 },
1690 },
1691 },
1692 },
1693 t: NewTransaction(
1694 tranGetClientInfoText, &[]byte{0, 1},
1695 NewField(fieldUserID, []byte{0, 1}),
1696 ),
1697 },
1698 wantRes: []Transaction{
1699 {
1700 Flags: 0x00,
1701 IsReply: 0x01,
1702 Type: []byte{0x01, 0x2f},
1703 ID: []byte{0, 0, 0, 0},
1704 ErrorCode: []byte{0, 0, 0, 0},
1705 Fields: []Field{
1706 NewField(fieldData, []byte{
1707 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1708 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1709 0x00, 0x6a, 0x00, 0x01, 0x78,
1710 }),
1711 },
1712 },
1713 },
1714 wantErr: assert.NoError,
1715 },
1716 }
1717 for _, tt := range tests {
1718 t.Run(tt.name, func(t *testing.T) {
1719 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1720 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1721 return
1722 }
1723
1724 tranAssertEqual(t, tt.wantRes, gotRes)
1725 })
1726 }
1727 }
1728
1729 func TestHandleDownloadFile(t *testing.T) {
1730 type args struct {
1731 cc *ClientConn
1732 t *Transaction
1733 }
1734 tests := []struct {
1735 name string
1736 args args
1737 wantRes []Transaction
1738 wantErr assert.ErrorAssertionFunc
1739 }{
1740 {
1741 name: "when user does not have required permission",
1742 args: args{
1743 cc: &ClientConn{
1744 Account: &Account{
1745 Access: func() accessBitmap {
1746 var bits accessBitmap
1747 return bits
1748 }(),
1749 },
1750 Server: &Server{},
1751 },
1752 t: NewTransaction(tranDownloadFile, &[]byte{0, 1}),
1753 },
1754 wantRes: []Transaction{
1755 {
1756 Flags: 0x00,
1757 IsReply: 0x01,
1758 Type: []byte{0, 0x00},
1759 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1760 ErrorCode: []byte{0, 0, 0, 1},
1761 Fields: []Field{
1762 NewField(fieldError, []byte("You are not allowed to download files.")),
1763 },
1764 },
1765 },
1766 wantErr: assert.NoError,
1767 },
1768 {
1769 name: "with a valid file",
1770 args: args{
1771 cc: &ClientConn{
1772 transfers: map[int]map[[4]byte]*FileTransfer{
1773 FileDownload: {},
1774 },
1775 Account: &Account{
1776 Access: func() accessBitmap {
1777 var bits accessBitmap
1778 bits.Set(accessDownloadFile)
1779 return bits
1780 }(),
1781 },
1782 Server: &Server{
1783 FS: &OSFileStore{},
1784 fileTransfers: map[[4]byte]*FileTransfer{},
1785 Config: &Config{
1786 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1787 },
1788 Accounts: map[string]*Account{},
1789 },
1790 },
1791 t: NewTransaction(
1792 accessDownloadFile,
1793 &[]byte{0, 1},
1794 NewField(fieldFileName, []byte("testfile.txt")),
1795 NewField(fieldFilePath, []byte{0x0, 0x00}),
1796 ),
1797 },
1798 wantRes: []Transaction{
1799 {
1800 Flags: 0x00,
1801 IsReply: 0x01,
1802 Type: []byte{0, 0x2},
1803 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1804 ErrorCode: []byte{0, 0, 0, 0},
1805 Fields: []Field{
1806 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1807 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1808 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1809 NewField(fieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1810 },
1811 },
1812 },
1813 wantErr: assert.NoError,
1814 },
1815 {
1816 name: "when client requests to resume 1k test file at offset 256",
1817 args: args{
1818 cc: &ClientConn{
1819 transfers: map[int]map[[4]byte]*FileTransfer{
1820 FileDownload: {},
1821 }, Account: &Account{
1822 Access: func() accessBitmap {
1823 var bits accessBitmap
1824 bits.Set(accessDownloadFile)
1825 return bits
1826 }(),
1827 },
1828 Server: &Server{
1829 FS: &OSFileStore{},
1830
1831 // FS: func() *MockFileStore {
1832 // path, _ := os.Getwd()
1833 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1834 // if err != nil {
1835 // panic(err)
1836 // }
1837 //
1838 // mfi := &MockFileInfo{}
1839 // mfi.On("Mode").Return(fs.FileMode(0))
1840 // mfs := &MockFileStore{}
1841 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1842 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1843 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1844 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1845 //
1846 // return mfs
1847 // }(),
1848 fileTransfers: map[[4]byte]*FileTransfer{},
1849 Config: &Config{
1850 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1851 },
1852 Accounts: map[string]*Account{},
1853 },
1854 },
1855 t: NewTransaction(
1856 accessDownloadFile,
1857 &[]byte{0, 1},
1858 NewField(fieldFileName, []byte("testfile-1k")),
1859 NewField(fieldFilePath, []byte{0x00, 0x00}),
1860 NewField(
1861 fieldFileResumeData,
1862 func() []byte {
1863 frd := FileResumeData{
1864 Format: [4]byte{},
1865 Version: [2]byte{},
1866 RSVD: [34]byte{},
1867 ForkCount: [2]byte{0, 2},
1868 ForkInfoList: []ForkInfoList{
1869 {
1870 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1871 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1872 RSVDA: [4]byte{},
1873 RSVDB: [4]byte{},
1874 },
1875 {
1876 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1877 DataSize: [4]byte{0, 0, 0, 0},
1878 RSVDA: [4]byte{},
1879 RSVDB: [4]byte{},
1880 },
1881 },
1882 }
1883 b, _ := frd.BinaryMarshal()
1884 return b
1885 }(),
1886 ),
1887 ),
1888 },
1889 wantRes: []Transaction{
1890 {
1891 Flags: 0x00,
1892 IsReply: 0x01,
1893 Type: []byte{0, 0x2},
1894 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1895 ErrorCode: []byte{0, 0, 0, 0},
1896 Fields: []Field{
1897 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1898 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1899 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1900 NewField(fieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1901 },
1902 },
1903 },
1904 wantErr: assert.NoError,
1905 },
1906 }
1907 for _, tt := range tests {
1908 t.Run(tt.name, func(t *testing.T) {
1909 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
1910 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
1911 return
1912 }
1913
1914 tranAssertEqual(t, tt.wantRes, gotRes)
1915 })
1916 }
1917 }
1918
1919 func TestHandleUpdateUser(t *testing.T) {
1920 type args struct {
1921 cc *ClientConn
1922 t *Transaction
1923 }
1924 tests := []struct {
1925 name string
1926 args args
1927 wantRes []Transaction
1928 wantErr assert.ErrorAssertionFunc
1929 }{
1930 {
1931 name: "when action is create user without required permission",
1932 args: args{
1933 cc: &ClientConn{
1934 logger: NewTestLogger(),
1935 Server: &Server{
1936 Logger: NewTestLogger(),
1937 },
1938 Account: &Account{
1939 Access: func() accessBitmap {
1940 var bits accessBitmap
1941 return bits
1942 }(),
1943 },
1944 },
1945 t: NewTransaction(
1946 tranUpdateUser,
1947 &[]byte{0, 0},
1948 NewField(fieldData, []byte{
1949 0x00, 0x04, // field count
1950
1951 0x00, 0x69, // fieldUserLogin = 105
1952 0x00, 0x03,
1953 0x9d, 0x9d, 0x9d,
1954
1955 0x00, 0x6a, // fieldUserPassword = 106
1956 0x00, 0x03,
1957 0x9c, 0x9c, 0x9c,
1958
1959 0x00, 0x66, // fieldUserName = 102
1960 0x00, 0x03,
1961 0x61, 0x61, 0x61,
1962
1963 0x00, 0x6e, // fieldUserAccess = 110
1964 0x00, 0x08,
1965 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1966 }),
1967 ),
1968 },
1969 wantRes: []Transaction{
1970 {
1971 Flags: 0x00,
1972 IsReply: 0x01,
1973 Type: []byte{0, 0x00},
1974 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1975 ErrorCode: []byte{0, 0, 0, 1},
1976 Fields: []Field{
1977 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1978 },
1979 },
1980 },
1981 wantErr: assert.NoError,
1982 },
1983 {
1984 name: "when action is modify user without required permission",
1985 args: args{
1986 cc: &ClientConn{
1987 logger: NewTestLogger(),
1988 Server: &Server{
1989 Logger: NewTestLogger(),
1990 Accounts: map[string]*Account{
1991 "bbb": {},
1992 },
1993 },
1994 Account: &Account{
1995 Access: func() accessBitmap {
1996 var bits accessBitmap
1997 return bits
1998 }(),
1999 },
2000 },
2001 t: NewTransaction(
2002 tranUpdateUser,
2003 &[]byte{0, 0},
2004 NewField(fieldData, []byte{
2005 0x00, 0x04, // field count
2006
2007 0x00, 0x69, // fieldUserLogin = 105
2008 0x00, 0x03,
2009 0x9d, 0x9d, 0x9d,
2010
2011 0x00, 0x6a, // fieldUserPassword = 106
2012 0x00, 0x03,
2013 0x9c, 0x9c, 0x9c,
2014
2015 0x00, 0x66, // fieldUserName = 102
2016 0x00, 0x03,
2017 0x61, 0x61, 0x61,
2018
2019 0x00, 0x6e, // fieldUserAccess = 110
2020 0x00, 0x08,
2021 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2022 }),
2023 ),
2024 },
2025 wantRes: []Transaction{
2026 {
2027 Flags: 0x00,
2028 IsReply: 0x01,
2029 Type: []byte{0, 0x00},
2030 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2031 ErrorCode: []byte{0, 0, 0, 1},
2032 Fields: []Field{
2033 NewField(fieldError, []byte("You are not allowed to modify accounts.")),
2034 },
2035 },
2036 },
2037 wantErr: assert.NoError,
2038 },
2039 {
2040 name: "when action is delete user without required permission",
2041 args: args{
2042 cc: &ClientConn{
2043 logger: NewTestLogger(),
2044 Server: &Server{
2045 Accounts: map[string]*Account{
2046 "bbb": {},
2047 },
2048 },
2049 Account: &Account{
2050 Access: func() accessBitmap {
2051 var bits accessBitmap
2052 return bits
2053 }(),
2054 },
2055 },
2056 t: NewTransaction(
2057 tranUpdateUser,
2058 &[]byte{0, 0},
2059 NewField(fieldData, []byte{
2060 0x00, 0x01,
2061 0x00, 0x65,
2062 0x00, 0x03,
2063 0x88, 0x9e, 0x8b,
2064 }),
2065 ),
2066 },
2067 wantRes: []Transaction{
2068 {
2069 Flags: 0x00,
2070 IsReply: 0x01,
2071 Type: []byte{0, 0x00},
2072 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2073 ErrorCode: []byte{0, 0, 0, 1},
2074 Fields: []Field{
2075 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
2076 },
2077 },
2078 },
2079 wantErr: assert.NoError,
2080 },
2081 }
2082 for _, tt := range tests {
2083 t.Run(tt.name, func(t *testing.T) {
2084 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2085 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2086 return
2087 }
2088
2089 tranAssertEqual(t, tt.wantRes, gotRes)
2090 })
2091 }
2092 }
2093
2094 func TestHandleDelNewsArt(t *testing.T) {
2095 type args struct {
2096 cc *ClientConn
2097 t *Transaction
2098 }
2099 tests := []struct {
2100 name string
2101 args args
2102 wantRes []Transaction
2103 wantErr assert.ErrorAssertionFunc
2104 }{
2105 {
2106 name: "without required permission",
2107 args: args{
2108 cc: &ClientConn{
2109 Account: &Account{
2110 Access: func() accessBitmap {
2111 var bits accessBitmap
2112 return bits
2113 }(),
2114 },
2115 },
2116 t: NewTransaction(
2117 tranDelNewsArt,
2118 &[]byte{0, 0},
2119 ),
2120 },
2121 wantRes: []Transaction{
2122 {
2123 Flags: 0x00,
2124 IsReply: 0x01,
2125 Type: []byte{0, 0x00},
2126 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2127 ErrorCode: []byte{0, 0, 0, 1},
2128 Fields: []Field{
2129 NewField(fieldError, []byte("You are not allowed to delete news articles.")),
2130 },
2131 },
2132 },
2133 wantErr: assert.NoError,
2134 },
2135 }
2136 for _, tt := range tests {
2137 t.Run(tt.name, func(t *testing.T) {
2138 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2139 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2140 return
2141 }
2142 tranAssertEqual(t, tt.wantRes, gotRes)
2143 })
2144 }
2145 }
2146
2147 func TestHandleDisconnectUser(t *testing.T) {
2148 type args struct {
2149 cc *ClientConn
2150 t *Transaction
2151 }
2152 tests := []struct {
2153 name string
2154 args args
2155 wantRes []Transaction
2156 wantErr assert.ErrorAssertionFunc
2157 }{
2158 {
2159 name: "without required permission",
2160 args: args{
2161 cc: &ClientConn{
2162 Account: &Account{
2163 Access: func() accessBitmap {
2164 var bits accessBitmap
2165 return bits
2166 }(),
2167 },
2168 },
2169 t: NewTransaction(
2170 tranDelNewsArt,
2171 &[]byte{0, 0},
2172 ),
2173 },
2174 wantRes: []Transaction{
2175 {
2176 Flags: 0x00,
2177 IsReply: 0x01,
2178 Type: []byte{0, 0x00},
2179 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2180 ErrorCode: []byte{0, 0, 0, 1},
2181 Fields: []Field{
2182 NewField(fieldError, []byte("You are not allowed to disconnect users.")),
2183 },
2184 },
2185 },
2186 wantErr: assert.NoError,
2187 },
2188 {
2189 name: "when target user has 'cannot be disconnected' priv",
2190 args: args{
2191 cc: &ClientConn{
2192 Server: &Server{
2193 Clients: map[uint16]*ClientConn{
2194 uint16(1): {
2195 Account: &Account{
2196 Login: "unnamed",
2197 Access: func() accessBitmap {
2198 var bits accessBitmap
2199 bits.Set(accessCannotBeDiscon)
2200 return bits
2201 }(),
2202 },
2203 },
2204 },
2205 },
2206 Account: &Account{
2207 Access: func() accessBitmap {
2208 var bits accessBitmap
2209 bits.Set(accessDisconUser)
2210 return bits
2211 }(),
2212 },
2213 },
2214 t: NewTransaction(
2215 tranDelNewsArt,
2216 &[]byte{0, 0},
2217 NewField(fieldUserID, []byte{0, 1}),
2218 ),
2219 },
2220 wantRes: []Transaction{
2221 {
2222 Flags: 0x00,
2223 IsReply: 0x01,
2224 Type: []byte{0, 0x00},
2225 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2226 ErrorCode: []byte{0, 0, 0, 1},
2227 Fields: []Field{
2228 NewField(fieldError, []byte("unnamed is not allowed to be disconnected.")),
2229 },
2230 },
2231 },
2232 wantErr: assert.NoError,
2233 },
2234 }
2235 for _, tt := range tests {
2236 t.Run(tt.name, func(t *testing.T) {
2237 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2238 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2239 return
2240 }
2241 tranAssertEqual(t, tt.wantRes, gotRes)
2242 })
2243 }
2244 }
2245
2246 func TestHandleSendInstantMsg(t *testing.T) {
2247 type args struct {
2248 cc *ClientConn
2249 t *Transaction
2250 }
2251 tests := []struct {
2252 name string
2253 args args
2254 wantRes []Transaction
2255 wantErr assert.ErrorAssertionFunc
2256 }{
2257 {
2258 name: "without required permission",
2259 args: args{
2260 cc: &ClientConn{
2261 Account: &Account{
2262 Access: func() accessBitmap {
2263 var bits accessBitmap
2264 return bits
2265 }(),
2266 },
2267 },
2268 t: NewTransaction(
2269 tranDelNewsArt,
2270 &[]byte{0, 0},
2271 ),
2272 },
2273 wantRes: []Transaction{
2274 {
2275 Flags: 0x00,
2276 IsReply: 0x01,
2277 Type: []byte{0, 0x00},
2278 ID: []byte{0, 0, 0, 0},
2279 ErrorCode: []byte{0, 0, 0, 1},
2280 Fields: []Field{
2281 NewField(fieldError, []byte("You are not allowed to send private messages.")),
2282 },
2283 },
2284 },
2285 wantErr: assert.NoError,
2286 },
2287 {
2288 name: "when client 1 sends a message to client 2",
2289 args: args{
2290 cc: &ClientConn{
2291 Account: &Account{
2292 Access: func() accessBitmap {
2293 var bits accessBitmap
2294 bits.Set(accessSendPrivMsg)
2295 return bits
2296 }(),
2297 },
2298 ID: &[]byte{0, 1},
2299 UserName: []byte("User1"),
2300 Server: &Server{
2301 Clients: map[uint16]*ClientConn{
2302 uint16(2): {
2303 AutoReply: []byte(nil),
2304 },
2305 },
2306 },
2307 },
2308 t: NewTransaction(
2309 tranSendInstantMsg,
2310 &[]byte{0, 1},
2311 NewField(fieldData, []byte("hai")),
2312 NewField(fieldUserID, []byte{0, 2}),
2313 ),
2314 },
2315 wantRes: []Transaction{
2316 *NewTransaction(
2317 tranServerMsg,
2318 &[]byte{0, 2},
2319 NewField(fieldData, []byte("hai")),
2320 NewField(fieldUserName, []byte("User1")),
2321 NewField(fieldUserID, []byte{0, 1}),
2322 NewField(fieldOptions, []byte{0, 1}),
2323 ),
2324 {
2325 clientID: &[]byte{0, 1},
2326 Flags: 0x00,
2327 IsReply: 0x01,
2328 Type: []byte{0x0, 0x6c},
2329 ID: []byte{0, 0, 0, 0},
2330 ErrorCode: []byte{0, 0, 0, 0},
2331 Fields: []Field(nil),
2332 },
2333 },
2334 wantErr: assert.NoError,
2335 },
2336 {
2337 name: "when client 2 has autoreply enabled",
2338 args: args{
2339 cc: &ClientConn{
2340 Account: &Account{
2341 Access: func() accessBitmap {
2342 var bits accessBitmap
2343 bits.Set(accessSendPrivMsg)
2344 return bits
2345 }(),
2346 },
2347 ID: &[]byte{0, 1},
2348 UserName: []byte("User1"),
2349 Server: &Server{
2350 Clients: map[uint16]*ClientConn{
2351 uint16(2): {
2352 ID: &[]byte{0, 2},
2353 UserName: []byte("User2"),
2354 AutoReply: []byte("autohai"),
2355 },
2356 },
2357 },
2358 },
2359 t: NewTransaction(
2360 tranSendInstantMsg,
2361 &[]byte{0, 1},
2362 NewField(fieldData, []byte("hai")),
2363 NewField(fieldUserID, []byte{0, 2}),
2364 ),
2365 },
2366 wantRes: []Transaction{
2367 *NewTransaction(
2368 tranServerMsg,
2369 &[]byte{0, 2},
2370 NewField(fieldData, []byte("hai")),
2371 NewField(fieldUserName, []byte("User1")),
2372 NewField(fieldUserID, []byte{0, 1}),
2373 NewField(fieldOptions, []byte{0, 1}),
2374 ),
2375 *NewTransaction(
2376 tranServerMsg,
2377 &[]byte{0, 1},
2378 NewField(fieldData, []byte("autohai")),
2379 NewField(fieldUserName, []byte("User2")),
2380 NewField(fieldUserID, []byte{0, 2}),
2381 NewField(fieldOptions, []byte{0, 1}),
2382 ),
2383 {
2384 clientID: &[]byte{0, 1},
2385 Flags: 0x00,
2386 IsReply: 0x01,
2387 Type: []byte{0x0, 0x6c},
2388 ID: []byte{0, 0, 0, 0},
2389 ErrorCode: []byte{0, 0, 0, 0},
2390 Fields: []Field(nil),
2391 },
2392 },
2393 wantErr: assert.NoError,
2394 },
2395 }
2396 for _, tt := range tests {
2397 t.Run(tt.name, func(t *testing.T) {
2398 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2399 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2400 return
2401 }
2402
2403 tranAssertEqual(t, tt.wantRes, gotRes)
2404 })
2405 }
2406 }
2407
2408 func TestHandleDeleteFile(t *testing.T) {
2409 type args struct {
2410 cc *ClientConn
2411 t *Transaction
2412 }
2413 tests := []struct {
2414 name string
2415 args args
2416 wantRes []Transaction
2417 wantErr assert.ErrorAssertionFunc
2418 }{
2419 {
2420 name: "when user does not have required permission to delete a folder",
2421 args: args{
2422 cc: &ClientConn{
2423 Account: &Account{
2424 Access: func() accessBitmap {
2425 var bits accessBitmap
2426 return bits
2427 }(),
2428 },
2429 Server: &Server{
2430 Config: &Config{
2431 FileRoot: func() string {
2432 return "/fakeRoot/Files"
2433 }(),
2434 },
2435 FS: func() *MockFileStore {
2436 mfi := &MockFileInfo{}
2437 mfi.On("Mode").Return(fs.FileMode(0))
2438 mfi.On("Size").Return(int64(100))
2439 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2440 mfi.On("IsDir").Return(false)
2441 mfi.On("Name").Return("testfile")
2442
2443 mfs := &MockFileStore{}
2444 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2445 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2446 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2447
2448 return mfs
2449 }(),
2450 Accounts: map[string]*Account{},
2451 },
2452 },
2453 t: NewTransaction(
2454 tranDeleteFile, &[]byte{0, 1},
2455 NewField(fieldFileName, []byte("testfile")),
2456 NewField(fieldFilePath, []byte{
2457 0x00, 0x01,
2458 0x00, 0x00,
2459 0x03,
2460 0x61, 0x61, 0x61,
2461 }),
2462 ),
2463 },
2464 wantRes: []Transaction{
2465 {
2466 Flags: 0x00,
2467 IsReply: 0x01,
2468 Type: []byte{0, 0x00},
2469 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2470 ErrorCode: []byte{0, 0, 0, 1},
2471 Fields: []Field{
2472 NewField(fieldError, []byte("You are not allowed to delete files.")),
2473 },
2474 },
2475 },
2476 wantErr: assert.NoError,
2477 },
2478 {
2479 name: "deletes all associated metadata files",
2480 args: args{
2481 cc: &ClientConn{
2482 Account: &Account{
2483 Access: func() accessBitmap {
2484 var bits accessBitmap
2485 bits.Set(accessDeleteFile)
2486 return bits
2487 }(),
2488 },
2489 Server: &Server{
2490 Config: &Config{
2491 FileRoot: func() string {
2492 return "/fakeRoot/Files"
2493 }(),
2494 },
2495 FS: func() *MockFileStore {
2496 mfi := &MockFileInfo{}
2497 mfi.On("Mode").Return(fs.FileMode(0))
2498 mfi.On("Size").Return(int64(100))
2499 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2500 mfi.On("IsDir").Return(false)
2501 mfi.On("Name").Return("testfile")
2502
2503 mfs := &MockFileStore{}
2504 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2505 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2506 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2507
2508 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2509 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2510 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2511 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2512
2513 return mfs
2514 }(),
2515 Accounts: map[string]*Account{},
2516 },
2517 },
2518 t: NewTransaction(
2519 tranDeleteFile, &[]byte{0, 1},
2520 NewField(fieldFileName, []byte("testfile")),
2521 NewField(fieldFilePath, []byte{
2522 0x00, 0x01,
2523 0x00, 0x00,
2524 0x03,
2525 0x61, 0x61, 0x61,
2526 }),
2527 ),
2528 },
2529 wantRes: []Transaction{
2530 {
2531 Flags: 0x00,
2532 IsReply: 0x01,
2533 Type: []byte{0x0, 0xcc},
2534 ID: []byte{0x0, 0x0, 0x0, 0x0},
2535 ErrorCode: []byte{0, 0, 0, 0},
2536 Fields: []Field(nil),
2537 },
2538 },
2539 wantErr: assert.NoError,
2540 },
2541 }
2542 for _, tt := range tests {
2543 t.Run(tt.name, func(t *testing.T) {
2544 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2545 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2546 return
2547 }
2548
2549 tranAssertEqual(t, tt.wantRes, gotRes)
2550
2551 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2552 })
2553 }
2554 }
2555
2556 func TestHandleGetFileNameList(t *testing.T) {
2557 type args struct {
2558 cc *ClientConn
2559 t *Transaction
2560 }
2561 tests := []struct {
2562 name string
2563 args args
2564 wantRes []Transaction
2565 wantErr assert.ErrorAssertionFunc
2566 }{
2567 {
2568 name: "when fieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2569 args: args{
2570 cc: &ClientConn{
2571 Account: &Account{
2572 Access: func() accessBitmap {
2573 var bits accessBitmap
2574 return bits
2575 }(),
2576 },
2577 Server: &Server{
2578
2579 Config: &Config{
2580 FileRoot: func() string {
2581 path, _ := os.Getwd()
2582 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2583 }(),
2584 },
2585 },
2586 },
2587 t: NewTransaction(
2588 tranGetFileNameList, &[]byte{0, 1},
2589 NewField(fieldFilePath, []byte{
2590 0x00, 0x01,
2591 0x00, 0x00,
2592 0x08,
2593 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2594 }),
2595 ),
2596 },
2597 wantRes: []Transaction{
2598 {
2599 Flags: 0x00,
2600 IsReply: 0x01,
2601 Type: []byte{0, 0x00},
2602 ID: []byte{0, 0, 0, 0},
2603 ErrorCode: []byte{0, 0, 0, 1},
2604 Fields: []Field{
2605 NewField(fieldError, []byte("You are not allowed to view drop boxes.")),
2606 },
2607 },
2608 },
2609 wantErr: assert.NoError,
2610 },
2611 {
2612 name: "with file root",
2613 args: args{
2614 cc: &ClientConn{
2615 Server: &Server{
2616 Config: &Config{
2617 FileRoot: func() string {
2618 path, _ := os.Getwd()
2619 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2620 }(),
2621 },
2622 },
2623 },
2624 t: NewTransaction(
2625 tranGetFileNameList, &[]byte{0, 1},
2626 NewField(fieldFilePath, []byte{
2627 0x00, 0x00,
2628 0x00, 0x00,
2629 }),
2630 ),
2631 },
2632 wantRes: []Transaction{
2633 {
2634 Flags: 0x00,
2635 IsReply: 0x01,
2636 Type: []byte{0, 0xc8},
2637 ID: []byte{0, 0, 0, 0},
2638 ErrorCode: []byte{0, 0, 0, 0},
2639 Fields: []Field{
2640 NewField(
2641 fieldFileNameWithInfo,
2642 func() []byte {
2643 fnwi := FileNameWithInfo{
2644 fileNameWithInfoHeader: fileNameWithInfoHeader{
2645 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2646 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2647 FileSize: [4]byte{0, 0, 0x04, 0},
2648 RSVD: [4]byte{},
2649 NameScript: [2]byte{},
2650 NameSize: [2]byte{0, 0x0b},
2651 },
2652 name: []byte("testfile-1k"),
2653 }
2654 b, _ := fnwi.MarshalBinary()
2655 return b
2656 }(),
2657 ),
2658 },
2659 },
2660 },
2661 wantErr: assert.NoError,
2662 },
2663 }
2664 for _, tt := range tests {
2665 t.Run(tt.name, func(t *testing.T) {
2666 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2667 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2668 return
2669 }
2670
2671 tranAssertEqual(t, tt.wantRes, gotRes)
2672 })
2673 }
2674 }
2675
2676 func TestHandleGetClientInfoText(t *testing.T) {
2677 type args struct {
2678 cc *ClientConn
2679 t *Transaction
2680 }
2681 tests := []struct {
2682 name string
2683 args args
2684 wantRes []Transaction
2685 wantErr assert.ErrorAssertionFunc
2686 }{
2687 {
2688 name: "when user does not have required permission",
2689 args: args{
2690 cc: &ClientConn{
2691 Account: &Account{
2692 Access: func() accessBitmap {
2693 var bits accessBitmap
2694 return bits
2695 }(),
2696 },
2697 Server: &Server{
2698 Accounts: map[string]*Account{},
2699 },
2700 },
2701 t: NewTransaction(
2702 tranGetClientInfoText, &[]byte{0, 1},
2703 NewField(fieldUserID, []byte{0, 1}),
2704 ),
2705 },
2706 wantRes: []Transaction{
2707 {
2708 Flags: 0x00,
2709 IsReply: 0x01,
2710 Type: []byte{0, 0x00},
2711 ID: []byte{0, 0, 0, 0},
2712 ErrorCode: []byte{0, 0, 0, 1},
2713 Fields: []Field{
2714 NewField(fieldError, []byte("You are not allowed to get client info.")),
2715 },
2716 },
2717 },
2718 wantErr: assert.NoError,
2719 },
2720 {
2721 name: "with a valid user",
2722 args: args{
2723 cc: &ClientConn{
2724 UserName: []byte("Testy McTest"),
2725 RemoteAddr: "1.2.3.4:12345",
2726 Account: &Account{
2727 Access: func() accessBitmap {
2728 var bits accessBitmap
2729 bits.Set(accessGetClientInfo)
2730 return bits
2731 }(),
2732 Name: "test",
2733 Login: "test",
2734 },
2735 Server: &Server{
2736 Accounts: map[string]*Account{},
2737 Clients: map[uint16]*ClientConn{
2738 uint16(1): {
2739 UserName: []byte("Testy McTest"),
2740 RemoteAddr: "1.2.3.4:12345",
2741 Account: &Account{
2742 Access: func() accessBitmap {
2743 var bits accessBitmap
2744 bits.Set(accessGetClientInfo)
2745 return bits
2746 }(),
2747 Name: "test",
2748 Login: "test",
2749 },
2750 },
2751 },
2752 },
2753 transfers: map[int]map[[4]byte]*FileTransfer{
2754 FileDownload: {},
2755 FileUpload: {},
2756 FolderDownload: {},
2757 FolderUpload: {},
2758 },
2759 },
2760 t: NewTransaction(
2761 tranGetClientInfoText, &[]byte{0, 1},
2762 NewField(fieldUserID, []byte{0, 1}),
2763 ),
2764 },
2765 wantRes: []Transaction{
2766 {
2767 Flags: 0x00,
2768 IsReply: 0x01,
2769 Type: []byte{0x1, 0x2f},
2770 ID: []byte{0, 0, 0, 0},
2771 ErrorCode: []byte{0, 0, 0, 0},
2772 Fields: []Field{
2773 NewField(fieldData, []byte(
2774 strings.Replace(`Nickname: Testy McTest
2775 Name: test
2776 Account: test
2777 Address: 1.2.3.4:12345
2778
2779 -------- File Downloads ---------
2780
2781 None.
2782
2783 ------- Folder Downloads --------
2784
2785 None.
2786
2787 --------- File Uploads ----------
2788
2789 None.
2790
2791 -------- Folder Uploads ---------
2792
2793 None.
2794
2795 ------- Waiting Downloads -------
2796
2797 None.
2798
2799 `, "\n", "\r", -1)),
2800 ),
2801 NewField(fieldUserName, []byte("Testy McTest")),
2802 },
2803 },
2804 },
2805 wantErr: assert.NoError,
2806 },
2807 }
2808 for _, tt := range tests {
2809 t.Run(tt.name, func(t *testing.T) {
2810 gotRes, err := HandleGetClientInfoText(tt.args.cc, tt.args.t)
2811 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetClientInfoText(%v, %v)", tt.args.cc, tt.args.t)) {
2812 return
2813 }
2814 tranAssertEqual(t, tt.wantRes, gotRes)
2815 })
2816 }
2817 }
2818
2819 func TestHandleTranAgreed(t *testing.T) {
2820 type args struct {
2821 cc *ClientConn
2822 t *Transaction
2823 }
2824 tests := []struct {
2825 name string
2826 args args
2827 wantRes []Transaction
2828 wantErr assert.ErrorAssertionFunc
2829 }{
2830 {
2831 name: "normal request flow",
2832 args: args{
2833 cc: &ClientConn{
2834 Account: &Account{
2835 Access: func() accessBitmap {
2836 var bits accessBitmap
2837 bits.Set(accessDisconUser)
2838 bits.Set(accessAnyName)
2839 return bits
2840 }()},
2841 Icon: []byte{0, 1},
2842 Flags: []byte{0, 1},
2843 Version: []byte{0, 1},
2844 ID: &[]byte{0, 1},
2845 logger: NewTestLogger(),
2846 Server: &Server{
2847 Config: &Config{
2848 BannerFile: "banner.jpg",
2849 },
2850 },
2851 },
2852 t: NewTransaction(
2853 tranAgreed, nil,
2854 NewField(fieldUserName, []byte("username")),
2855 NewField(fieldUserIconID, []byte{0, 1}),
2856 NewField(fieldOptions, []byte{0, 0}),
2857 ),
2858 },
2859 wantRes: []Transaction{
2860 {
2861 clientID: &[]byte{0, 1},
2862 Flags: 0x00,
2863 IsReply: 0x00,
2864 Type: []byte{0, 0x7a},
2865 ID: []byte{0, 0, 0, 0},
2866 ErrorCode: []byte{0, 0, 0, 0},
2867 Fields: []Field{
2868 NewField(fieldBannerType, []byte("JPEG")),
2869 },
2870 },
2871 {
2872 clientID: &[]byte{0, 1},
2873 Flags: 0x00,
2874 IsReply: 0x01,
2875 Type: []byte{0, 0x79},
2876 ID: []byte{0, 0, 0, 0},
2877 ErrorCode: []byte{0, 0, 0, 0},
2878 Fields: []Field{},
2879 },
2880 },
2881 wantErr: assert.NoError,
2882 },
2883 }
2884 for _, tt := range tests {
2885 t.Run(tt.name, func(t *testing.T) {
2886 gotRes, err := HandleTranAgreed(tt.args.cc, tt.args.t)
2887 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranAgreed(%v, %v)", tt.args.cc, tt.args.t)) {
2888 return
2889 }
2890 tranAssertEqual(t, tt.wantRes, gotRes)
2891 })
2892 }
2893 }
2894
2895 func TestHandleSetClientUserInfo(t *testing.T) {
2896 type args struct {
2897 cc *ClientConn
2898 t *Transaction
2899 }
2900 tests := []struct {
2901 name string
2902 args args
2903 wantRes []Transaction
2904 wantErr assert.ErrorAssertionFunc
2905 }{
2906 {
2907 name: "when client does not have accessAnyName",
2908 args: args{
2909 cc: &ClientConn{
2910 Account: &Account{
2911 Access: func() accessBitmap {
2912 var bits accessBitmap
2913 return bits
2914 }(),
2915 },
2916 ID: &[]byte{0, 1},
2917 UserName: []byte("Guest"),
2918 Flags: []byte{0, 1},
2919 Server: &Server{
2920 Clients: map[uint16]*ClientConn{
2921 uint16(1): {
2922 ID: &[]byte{0, 1},
2923 },
2924 },
2925 },
2926 },
2927 t: NewTransaction(
2928 tranSetClientUserInfo, nil,
2929 NewField(fieldUserIconID, []byte{0, 1}),
2930 NewField(fieldUserName, []byte("NOPE")),
2931 ),
2932 },
2933 wantRes: []Transaction{
2934 {
2935 clientID: &[]byte{0, 1},
2936 Flags: 0x00,
2937 IsReply: 0x00,
2938 Type: []byte{0x01, 0x2d},
2939 ID: []byte{0, 0, 0, 0},
2940 ErrorCode: []byte{0, 0, 0, 0},
2941 Fields: []Field{
2942 NewField(fieldUserID, []byte{0, 1}),
2943 NewField(fieldUserIconID, []byte{0, 1}),
2944 NewField(fieldUserFlags, []byte{0, 1}),
2945 NewField(fieldUserName, []byte("Guest"))},
2946 },
2947 },
2948 wantErr: assert.NoError,
2949 },
2950 }
2951 for _, tt := range tests {
2952 t.Run(tt.name, func(t *testing.T) {
2953 gotRes, err := HandleSetClientUserInfo(tt.args.cc, tt.args.t)
2954 if !tt.wantErr(t, err, fmt.Sprintf("HandleSetClientUserInfo(%v, %v)", tt.args.cc, tt.args.t)) {
2955 return
2956 }
2957
2958 tranAssertEqual(t, tt.wantRes, gotRes)
2959 })
2960 }
2961 }