]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Sanitize file path input to prevent directory traversal
[rbdr/mobius] / hotline / transaction_handlers_test.go
1 package hotline
2
3 import (
4 "github.com/stretchr/testify/assert"
5 "io/fs"
6 "math/rand"
7 "os"
8 "reflect"
9 "testing"
10 )
11
12 func TestHandleSetChatSubject(t *testing.T) {
13 type args struct {
14 cc *ClientConn
15 t *Transaction
16 }
17 tests := []struct {
18 name string
19 args args
20 want []Transaction
21 wantErr bool
22 }{
23 {
24 name: "sends chat subject to private chat members",
25 args: args{
26 cc: &ClientConn{
27 UserName: []byte{0x00, 0x01},
28 Server: &Server{
29 PrivateChats: map[uint32]*PrivateChat{
30 uint32(1): {
31 Subject: "unset",
32 ClientConn: map[uint16]*ClientConn{
33 uint16(1): {
34 Account: &Account{
35 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
36 },
37 ID: &[]byte{0, 1},
38 },
39 uint16(2): {
40 Account: &Account{
41 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
42 },
43 ID: &[]byte{0, 2},
44 },
45 },
46 },
47 },
48 Clients: map[uint16]*ClientConn{
49 uint16(1): {
50 Account: &Account{
51 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
52 },
53 ID: &[]byte{0, 1},
54 },
55 uint16(2): {
56 Account: &Account{
57 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
58 },
59 ID: &[]byte{0, 2},
60 },
61 },
62 },
63 },
64 t: &Transaction{
65 Flags: 0x00,
66 IsReply: 0x00,
67 Type: []byte{0, 0x6a},
68 ID: []byte{0, 0, 0, 1},
69 ErrorCode: []byte{0, 0, 0, 0},
70 Fields: []Field{
71 NewField(fieldChatID, []byte{0, 0, 0, 1}),
72 NewField(fieldChatSubject, []byte("Test Subject")),
73 },
74 },
75 },
76 want: []Transaction{
77 {
78 clientID: &[]byte{0, 1},
79 Flags: 0x00,
80 IsReply: 0x00,
81 Type: []byte{0, 0x77},
82 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
83 ErrorCode: []byte{0, 0, 0, 0},
84 Fields: []Field{
85 NewField(fieldChatID, []byte{0, 0, 0, 1}),
86 NewField(fieldChatSubject, []byte("Test Subject")),
87 },
88 },
89 {
90 clientID: &[]byte{0, 2},
91 Flags: 0x00,
92 IsReply: 0x00,
93 Type: []byte{0, 0x77},
94 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
95 ErrorCode: []byte{0, 0, 0, 0},
96 Fields: []Field{
97 NewField(fieldChatID, []byte{0, 0, 0, 1}),
98 NewField(fieldChatSubject, []byte("Test Subject")),
99 },
100 },
101 },
102 wantErr: false,
103 },
104 }
105 for _, tt := range tests {
106 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
107
108 t.Run(tt.name, func(t *testing.T) {
109 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
110 if (err != nil) != tt.wantErr {
111 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
112 return
113 }
114 if !assert.Equal(t, tt.want, got) {
115 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
116 }
117 })
118 }
119 }
120
121 func TestHandleLeaveChat(t *testing.T) {
122 type args struct {
123 cc *ClientConn
124 t *Transaction
125 }
126 tests := []struct {
127 name string
128 args args
129 want []Transaction
130 wantErr bool
131 }{
132 {
133 name: "returns expected transactions",
134 args: args{
135 cc: &ClientConn{
136 ID: &[]byte{0, 2},
137 Server: &Server{
138 PrivateChats: map[uint32]*PrivateChat{
139 uint32(1): {
140 ClientConn: map[uint16]*ClientConn{
141 uint16(1): {
142 Account: &Account{
143 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
144 },
145 ID: &[]byte{0, 1},
146 },
147 uint16(2): {
148 Account: &Account{
149 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
150 },
151 ID: &[]byte{0, 2},
152 },
153 },
154 },
155 },
156 Clients: map[uint16]*ClientConn{
157 uint16(1): {
158 Account: &Account{
159 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
160 },
161 ID: &[]byte{0, 1},
162 },
163 uint16(2): {
164 Account: &Account{
165 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
166 },
167 ID: &[]byte{0, 2},
168 },
169 },
170 },
171 },
172 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
173 },
174 want: []Transaction{
175 {
176 clientID: &[]byte{0, 1},
177 Flags: 0x00,
178 IsReply: 0x00,
179 Type: []byte{0, 0x76},
180 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
181 ErrorCode: []byte{0, 0, 0, 0},
182 Fields: []Field{
183 NewField(fieldChatID, []byte{0, 0, 0, 1}),
184 NewField(fieldUserID, []byte{0, 2}),
185 },
186 },
187 },
188 wantErr: false,
189 },
190 }
191 for _, tt := range tests {
192 rand.Seed(1)
193 t.Run(tt.name, func(t *testing.T) {
194 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
195 if (err != nil) != tt.wantErr {
196 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
197 return
198 }
199 if !assert.Equal(t, tt.want, got) {
200 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
201 }
202 })
203 }
204 }
205
206 func TestHandleGetUserNameList(t *testing.T) {
207 type args struct {
208 cc *ClientConn
209 t *Transaction
210 }
211 tests := []struct {
212 name string
213 args args
214 want []Transaction
215 wantErr bool
216 }{
217 {
218 name: "replies with userlist transaction",
219 args: args{
220 cc: &ClientConn{
221
222 ID: &[]byte{1, 1},
223 Server: &Server{
224 Clients: map[uint16]*ClientConn{
225 uint16(1): {
226 ID: &[]byte{0, 1},
227 Icon: &[]byte{0, 2},
228 Flags: &[]byte{0, 3},
229 UserName: []byte{0, 4},
230 },
231 },
232 },
233 },
234 t: &Transaction{
235 ID: []byte{0, 0, 0, 1},
236 Type: []byte{0, 1},
237 },
238 },
239 want: []Transaction{
240 {
241 clientID: &[]byte{1, 1},
242 Flags: 0x00,
243 IsReply: 0x01,
244 Type: []byte{0, 1},
245 ID: []byte{0, 0, 0, 1},
246 ErrorCode: []byte{0, 0, 0, 0},
247 Fields: []Field{
248 NewField(
249 fieldUsernameWithInfo,
250 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
251 ),
252 },
253 },
254 },
255 wantErr: false,
256 },
257 }
258 for _, tt := range tests {
259 t.Run(tt.name, func(t *testing.T) {
260 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
261 if (err != nil) != tt.wantErr {
262 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
263 return
264 }
265 if !reflect.DeepEqual(got, tt.want) {
266 t.Errorf("HandleGetUserNameList() got = %v, want %v", got, tt.want)
267 }
268 })
269 }
270 }
271
272 func TestHandleChatSend(t *testing.T) {
273 type args struct {
274 cc *ClientConn
275 t *Transaction
276 }
277 tests := []struct {
278 name string
279 args args
280 want []Transaction
281 wantErr bool
282 }{
283 {
284 name: "sends chat msg transaction to all clients",
285 args: args{
286 cc: &ClientConn{
287 UserName: []byte{0x00, 0x01},
288 Server: &Server{
289 Clients: map[uint16]*ClientConn{
290 uint16(1): {
291 Account: &Account{
292 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
293 },
294 ID: &[]byte{0, 1},
295 },
296 uint16(2): {
297 Account: &Account{
298 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
299 },
300 ID: &[]byte{0, 2},
301 },
302 },
303 },
304 },
305 t: &Transaction{
306 Fields: []Field{
307 NewField(fieldData, []byte("hai")),
308 },
309 },
310 },
311 want: []Transaction{
312 {
313 clientID: &[]byte{0, 1},
314 Flags: 0x00,
315 IsReply: 0x00,
316 Type: []byte{0, 0x6a},
317 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
318 ErrorCode: []byte{0, 0, 0, 0},
319 Fields: []Field{
320 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
321 },
322 },
323 {
324 clientID: &[]byte{0, 2},
325 Flags: 0x00,
326 IsReply: 0x00,
327 Type: []byte{0, 0x6a},
328 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
329 ErrorCode: []byte{0, 0, 0, 0},
330 Fields: []Field{
331 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
332 },
333 },
334 },
335 wantErr: false,
336 },
337 {
338 name: "sends chat msg as emote if fieldChatOptions is set",
339 args: args{
340 cc: &ClientConn{
341 UserName: []byte("Testy McTest"),
342 Server: &Server{
343 Clients: map[uint16]*ClientConn{
344 uint16(1): {
345 Account: &Account{
346 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
347 },
348 ID: &[]byte{0, 1},
349 },
350 uint16(2): {
351 Account: &Account{
352 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
353 },
354 ID: &[]byte{0, 2},
355 },
356 },
357 },
358 },
359 t: &Transaction{
360 Fields: []Field{
361 NewField(fieldData, []byte("performed action")),
362 NewField(fieldChatOptions, []byte{0x00, 0x01}),
363 },
364 },
365 },
366 want: []Transaction{
367 {
368 clientID: &[]byte{0, 1},
369 Flags: 0x00,
370 IsReply: 0x00,
371 Type: []byte{0, 0x6a},
372 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
373 ErrorCode: []byte{0, 0, 0, 0},
374 Fields: []Field{
375 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
376 },
377 },
378 {
379 clientID: &[]byte{0, 2},
380 Flags: 0x00,
381 IsReply: 0x00,
382 Type: []byte{0, 0x6a},
383 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
384 ErrorCode: []byte{0, 0, 0, 0},
385 Fields: []Field{
386 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
387 },
388 },
389 },
390 wantErr: false,
391 },
392 {
393 name: "only sends chat msg to clients with accessReadChat permission",
394 args: args{
395 cc: &ClientConn{
396 UserName: []byte{0x00, 0x01},
397 Server: &Server{
398 Clients: map[uint16]*ClientConn{
399 uint16(1): {
400 Account: &Account{
401 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
402 },
403 ID: &[]byte{0, 1},
404 },
405 uint16(2): {
406 Account: &Account{
407 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
408 },
409 ID: &[]byte{0, 2},
410 },
411 },
412 },
413 },
414 t: &Transaction{
415 Fields: []Field{
416 NewField(fieldData, []byte("hai")),
417 },
418 },
419 },
420 want: []Transaction{
421 {
422 clientID: &[]byte{0, 1},
423 Flags: 0x00,
424 IsReply: 0x00,
425 Type: []byte{0, 0x6a},
426 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
427 ErrorCode: []byte{0, 0, 0, 0},
428 Fields: []Field{
429 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
430 },
431 },
432 },
433 wantErr: false,
434 },
435 }
436 for _, tt := range tests {
437 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
438 t.Run(tt.name, func(t *testing.T) {
439 got, err := HandleChatSend(tt.args.cc, tt.args.t)
440
441 if (err != nil) != tt.wantErr {
442 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
443 return
444 }
445 if !assert.Equal(t, tt.want, got) {
446 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
447 }
448 })
449 }
450 }
451
452 func TestHandleGetFileInfo(t *testing.T) {
453 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
454
455 type args struct {
456 cc *ClientConn
457 t *Transaction
458 }
459 tests := []struct {
460 name string
461 args args
462 wantRes []Transaction
463 wantErr bool
464 }{
465 {
466 name: "returns expected fields when a valid file is requested",
467 args: args{
468 cc: &ClientConn{
469 ID: &[]byte{0x00, 0x01},
470 Server: &Server{
471 Config: &Config{
472 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
473 },
474 },
475 },
476 t: NewTransaction(
477 tranGetFileInfo, nil,
478 NewField(fieldFileName, []byte("testfile.txt")),
479 NewField(fieldFilePath, []byte{0x00, 0x00}),
480 ),
481 },
482 wantRes: []Transaction{
483 {
484 clientID: &[]byte{0, 1},
485 Flags: 0x00,
486 IsReply: 0x01,
487 Type: []byte{0, 0xce},
488 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
489 ErrorCode: []byte{0, 0, 0, 0},
490 Fields: []Field{
491 NewField(fieldFileName, []byte("testfile.txt")),
492 NewField(fieldFileTypeString, []byte("TEXT")),
493 NewField(fieldFileCreatorString, []byte("TTXT")),
494 NewField(fieldFileComment, []byte("TODO")),
495 NewField(fieldFileType, []byte("TEXT")),
496 NewField(fieldFileCreateDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
497 NewField(fieldFileModifyDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
498 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
499 },
500 },
501 },
502 wantErr: false,
503 },
504 }
505 for _, tt := range tests {
506 t.Run(tt.name, func(t *testing.T) {
507 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
508
509 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
510 if (err != nil) != tt.wantErr {
511 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
512 return
513 }
514 if !assert.Equal(t, tt.wantRes, gotRes) {
515 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
516 }
517 })
518 }
519 }
520
521 func TestHandleNewFolder(t *testing.T) {
522 type args struct {
523 cc *ClientConn
524 t *Transaction
525 }
526 tests := []struct {
527 setup func()
528 name string
529 args args
530 wantRes []Transaction
531 wantErr bool
532 }{
533 {
534 name: "when path is nested",
535 args: args{
536 cc: &ClientConn{
537 ID: &[]byte{0, 1},
538 Server: &Server{
539 Config: &Config{
540 FileRoot: "/Files/",
541 },
542 },
543 },
544 t: NewTransaction(
545 tranNewFolder, &[]byte{0, 1},
546 NewField(fieldFileName, []byte("testFolder")),
547 NewField(fieldFilePath, []byte{
548 0x00, 0x01,
549 0x00, 0x00,
550 0x03,
551 0x61, 0x61, 0x61,
552 }),
553 ),
554 },
555 setup: func() {
556 mfs := MockFileStore{}
557 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
558 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
559 FS = mfs
560 },
561 wantRes: []Transaction{
562 {
563 clientID: &[]byte{0, 1},
564 Flags: 0x00,
565 IsReply: 0x01,
566 Type: []byte{0, 0xcd},
567 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
568 ErrorCode: []byte{0, 0, 0, 0},
569 },
570 },
571 wantErr: false,
572 },
573 {
574 name: "when path is not nested",
575 args: args{
576 cc: &ClientConn{
577 ID: &[]byte{0, 1},
578 Server: &Server{
579 Config: &Config{
580 FileRoot: "/Files",
581 },
582 },
583 },
584 t: NewTransaction(
585 tranNewFolder, &[]byte{0, 1},
586 NewField(fieldFileName, []byte("testFolder")),
587 ),
588 },
589 setup: func() {
590 mfs := MockFileStore{}
591 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
592 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
593 FS = mfs
594 },
595 wantRes: []Transaction{
596 {
597 clientID: &[]byte{0, 1},
598 Flags: 0x00,
599 IsReply: 0x01,
600 Type: []byte{0, 0xcd},
601 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
602 ErrorCode: []byte{0, 0, 0, 0},
603 },
604 },
605 wantErr: false,
606 },
607 {
608 name: "when UnmarshalBinary returns an err",
609 args: args{
610 cc: &ClientConn{
611 ID: &[]byte{0, 1},
612 Server: &Server{
613 Config: &Config{
614 FileRoot: "/Files/",
615 },
616 },
617 },
618 t: NewTransaction(
619 tranNewFolder, &[]byte{0, 1},
620 NewField(fieldFileName, []byte("testFolder")),
621 NewField(fieldFilePath, []byte{
622 0x00,
623 }),
624 ),
625 },
626 setup: func() {
627 mfs := MockFileStore{}
628 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
629 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
630 FS = mfs
631 },
632 wantRes: []Transaction{},
633 wantErr: true,
634 },
635 {
636 name: "fieldFileName does not allow directory traversal",
637 args: args{
638 cc: &ClientConn{
639 ID: &[]byte{0, 1},
640 Server: &Server{
641 Config: &Config{
642 FileRoot: "/Files/",
643 },
644 },
645 },
646 t: NewTransaction(
647 tranNewFolder, &[]byte{0, 1},
648 NewField(fieldFileName, []byte("../../testFolder")),
649 ),
650 },
651 setup: func() {
652 mfs := MockFileStore{}
653 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
654 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
655 FS = mfs
656 },
657 wantRes: []Transaction{
658 {
659 clientID: &[]byte{0, 1},
660 Flags: 0x00,
661 IsReply: 0x01,
662 Type: []byte{0, 0xcd},
663 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
664 ErrorCode: []byte{0, 0, 0, 0},
665 },
666 }, wantErr: false,
667 },
668 {
669 name: "fieldFilePath does not allow directory traversal",
670 args: args{
671 cc: &ClientConn{
672 ID: &[]byte{0, 1},
673 Server: &Server{
674 Config: &Config{
675 FileRoot: "/Files/",
676 },
677 },
678 },
679 t: NewTransaction(
680 tranNewFolder, &[]byte{0, 1},
681 NewField(fieldFileName, []byte("testFolder")),
682 NewField(fieldFilePath, []byte{
683 0x00, 0x02,
684 0x00, 0x00,
685 0x03,
686 0x2e, 0x2e, 0x2f,
687 0x00, 0x00,
688 0x03,
689 0x66, 0x6f, 0x6f,
690 }),
691 ),
692 },
693 setup: func() {
694 mfs := MockFileStore{}
695 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
696 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
697 FS = mfs
698 },
699 wantRes: []Transaction{
700 {
701 clientID: &[]byte{0, 1},
702 Flags: 0x00,
703 IsReply: 0x01,
704 Type: []byte{0, 0xcd},
705 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
706 ErrorCode: []byte{0, 0, 0, 0},
707 },
708 }, wantErr: false,
709 },
710 }
711 for _, tt := range tests {
712 t.Run(tt.name, func(t *testing.T) {
713 tt.setup()
714
715 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
716 if (err != nil) != tt.wantErr {
717 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
718 return
719 }
720 if !tranAssertEqual(t, tt.wantRes, gotRes) {
721 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
722 }
723 })
724 }
725 }
726
727 func TestHandleUploadFile(t *testing.T) {
728 type args struct {
729 cc *ClientConn
730 t *Transaction
731 }
732 tests := []struct {
733 name string
734 args args
735 wantRes []Transaction
736 wantErr bool
737 }{
738 {
739 name: "when request is valid",
740 args: args{
741 cc: &ClientConn{
742 Server: &Server{
743 FileTransfers: map[uint32]*FileTransfer{},
744 },
745 Account: &Account{
746 Access: func() *[]byte {
747 var bits accessBitmap
748 bits.Set(accessUploadFile)
749 access := bits[:]
750 return &access
751 }(),
752 },
753 },
754 t: NewTransaction(
755 tranUploadFile, &[]byte{0, 1},
756 NewField(fieldFileName, []byte("testFile")),
757 NewField(fieldFilePath, []byte{
758 0x00, 0x01,
759 0x00, 0x00,
760 0x03,
761 0x2e, 0x2e, 0x2f,
762 }),
763 ),
764 },
765 wantRes: []Transaction{
766 {
767 Flags: 0x00,
768 IsReply: 0x01,
769 Type: []byte{0, 0xcb},
770 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
771 ErrorCode: []byte{0, 0, 0, 0},
772 Fields: []Field{
773 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
774 },
775 },
776 },
777 wantErr: false,
778 },
779 {
780 name: "when user does not have required access",
781 args: args{
782 cc: &ClientConn{
783 Account: &Account{
784 Access: func() *[]byte {
785 var bits accessBitmap
786 access := bits[:]
787 return &access
788 }(),
789 },
790 Server: &Server{
791 FileTransfers: map[uint32]*FileTransfer{},
792 },
793 },
794 t: NewTransaction(
795 tranUploadFile, &[]byte{0, 1},
796 NewField(fieldFileName, []byte("testFile")),
797 NewField(fieldFilePath, []byte{
798 0x00, 0x01,
799 0x00, 0x00,
800 0x03,
801 0x2e, 0x2e, 0x2f,
802 }),
803 ),
804 },
805 wantRes: []Transaction{
806 {
807 Flags: 0x00,
808 IsReply: 0x01,
809 Type: []byte{0, 0x00},
810 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
811 ErrorCode: []byte{0, 0, 0, 1},
812 Fields: []Field{
813 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
814 },
815 },
816 },
817 wantErr: false,
818 },
819 }
820 for _, tt := range tests {
821 t.Run(tt.name, func(t *testing.T) {
822 rand.Seed(1)
823 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
824 if (err != nil) != tt.wantErr {
825 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
826 return
827 }
828 if !tranAssertEqual(t, tt.wantRes, gotRes) {
829 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)
830 }
831 })
832 }
833 }