logger.Fatalw("Configuration directory not found", "path", configDir)
}
- hotline.FS = hotline.OSFileStore{}
+ hotline.FS = &hotline.OSFileStore{}
srv, err := hotline.NewServer(*configDir, "", *basePort, logger)
if err != nil {
accessOpenUser = 16
accessModifyUser = 17
// accessChangeOwnPass = 18 // Documented but unused?
- //accessSendPrivMsg = 19 // This doesn't do what it seems like it should do. TODO: Investigate
+ // accessSendPrivMsg = 19 // This doesn't do what it seems like it should do. TODO: Investigate
accessNewsReadArt = 20
accessNewsPostArt = 21
accessDisconUser = 22 // Toggles red user name in user list
accessCannotBeDiscon = 23
accessGetClientInfo = 24
- //accessUploadAnywhere = 25
- //accessAnyName = 26
- //accessNoAgreement = 27
- //accessSetFileComment = 28
- //accessSetFolderComment = 29
- //accessViewDropBoxes = 30
+ // accessUploadAnywhere = 25
+ // accessAnyName = 26
+ // accessNoAgreement = 27
+ // accessSetFileComment = 28
+ // accessSetFolderComment = 29
+ // accessViewDropBoxes = 30
accessMakeAlias = 31
accessBroadcast = 32
accessNewsDeleteArt = 33
accessNewsCreateCat = 34
- //accessNewsDeleteCat = 35
+ // accessNewsDeleteCat = 35
accessNewsCreateFldr = 36
- //accessNewsDeleteFldr = 37
+ // accessNewsDeleteFldr = 37
)
type accessBitmap [8]byte
newsTextView.SetBorder(true).SetTitle("News")
c.UI.Pages.AddPage("news", newsTextView, true, true)
- //c.UI.Pages.SwitchToPage("news")
- //c.UI.App.SetFocus(newsTextView)
+ // c.UI.Pages.SwitchToPage("news")
+ // c.UI.App.SetFocus(newsTextView)
c.UI.App.Draw()
return res, err
}
func (c *Client) Handshake() error {
- //Protocol ID 4 ‘TRTP’ 0x54 52 54 50
- //Sub-protocol ID 4 User defined
- //Version 2 1 Currently 1
- //Sub-version 2 User defined
+ // Protocol ID 4 ‘TRTP’ 0x54 52 54 50
+ // Sub-protocol ID 4 User defined
+ // Version 2 1 Currently 1
+ // Sub-version 2 User defined
if _, err := c.Connection.Write(ClientHandshake); err != nil {
return fmt.Errorf("handshake write err: %s", err)
}
requestNum := binary.BigEndian.Uint16(t.Type)
tID := binary.BigEndian.Uint32(t.ID)
- //handler := TransactionHandlers[requestNum]
+ // handler := TransactionHandlers[requestNum]
// if transaction is NOT reply, add it to the list to transactions we're expecting a response for
if t.IsReply == 0 {
package hotline
import (
- "bytes"
"encoding/binary"
- "errors"
"golang.org/x/crypto/bcrypt"
"math/big"
"net"
Server *Server
Version *[]byte
Idle bool
- AutoReply *[]byte
+ AutoReply []byte
Transfers map[int][]*FileTransfer
Agreed bool
}
// Validate that required field is present
if field.ID == nil {
- cc.Server.Logger.Infow(
+ cc.Server.Logger.Errorw(
"Missing required field",
"Account", cc.Account.Login, "UserName", string(cc.UserName), "RequestType", handler.Name, "FieldID", reqField.ID,
)
}
}
-type handshake struct {
- Protocol [4]byte // Must be 0x54525450 TRTP
- SubProtocol [4]byte
- Version [2]byte // Always 1
- SubVersion [2]byte
-}
-
-// Handshake
-// After establishing TCP connection, both client and server start the handshake process
-// in order to confirm that each of them comply with requirements of the other.
-// The information provided in this initial data exchange identifies protocols,
-// and their versions, used in the communication. In the case where, after inspection,
-// the capabilities of one of the subjects do not comply with the requirements of the other,
-// the connection is dropped.
-//
-// The following information is sent to the server:
-// Description Size Data Note
-// Protocol ID 4 TRTP 0x54525450
-// Sub-protocol ID 4 HOTL User defined
-// VERSION 2 1 Currently 1
-// Sub-version 2 2 User defined
-//
-// The server replies with the following:
-// Description Size Data Note
-// Protocol ID 4 TRTP
-//Error code 4 Error code returned by the server (0 = no error)
-func Handshake(conn net.Conn, buf []byte) error {
- var h handshake
- r := bytes.NewReader(buf)
- if err := binary.Read(r, binary.BigEndian, &h); err != nil {
- return err
- }
-
- if h.Protocol != [4]byte{0x54, 0x52, 0x54, 0x50} {
- return errors.New("invalid handshake")
- }
-
- _, err := conn.Write([]byte{84, 82, 84, 80, 0, 0, 0, 0})
- return err
-}
-
// NewReply returns a reply Transaction with fields for the ClientConn
func (cc *ClientConn) NewReply(t *Transaction, fields ...Field) Transaction {
reply := Transaction{
Server *Server
Version *[]byte
Idle bool
- AutoReply *[]byte
+ AutoReply []byte
}
type args struct {
transaction *Transaction
const fieldTransferSize = 108
const fieldChatOptions = 109
const fieldUserAccess = 110
-//const fieldUserAlias = 111 TODO: implement
+
+// const fieldUserAlias = 111 TODO: implement
const fieldUserFlags = 112
const fieldOptions = 113
const fieldChatID = 114
Symlink(oldname, newname string) error
// TODO: implement these
- //Rename(oldpath string, newpath string) error
- //RemoveAll(path string) error
+ // Rename(oldpath string, newpath string) error
+ // RemoveAll(path string) error
}
type OSFileStore struct{}
-func (fs OSFileStore) Mkdir(name string, perm os.FileMode) error {
+func (fs *OSFileStore) Mkdir(name string, perm os.FileMode) error {
return os.Mkdir(name, perm)
}
-func (fs OSFileStore) Stat(name string) (os.FileInfo, error) {
+func (fs *OSFileStore) Stat(name string) (os.FileInfo, error) {
return os.Stat(name)
}
-func (fs OSFileStore) Open(name string) (*os.File, error) {
+func (fs *OSFileStore) Open(name string) (*os.File, error) {
return os.Open(name)
}
-func (fs OSFileStore) Symlink(oldname, newname string) error {
+func (fs *OSFileStore) Symlink(oldname, newname string) error {
return os.Symlink(oldname, newname)
}
mock.Mock
}
-func (mfs MockFileStore) Mkdir(name string, perm os.FileMode) error {
+func (mfs *MockFileStore) Mkdir(name string, perm os.FileMode) error {
args := mfs.Called(name, perm)
return args.Error(0)
}
-func (mfs MockFileStore) Stat(name string) (os.FileInfo, error) {
+func (mfs *MockFileStore) Stat(name string) (os.FileInfo, error) {
args := mfs.Called(name)
if args.Get(0) == nil {
return nil, args.Error(1)
return args.Get(0).(os.FileInfo), args.Error(1)
}
-func (mfs MockFileStore) Open(name string) (*os.File, error) {
+func (mfs *MockFileStore) Open(name string) (*os.File, error) {
args := mfs.Called(name)
return args.Get(0).(*os.File), args.Error(1)
}
-func (mfs MockFileStore) Symlink(oldname, newname string) error {
+func (mfs *MockFileStore) Symlink(oldname, newname string) error {
args := mfs.Called(oldname, newname)
return args.Error(0)
}
func (ffif FlatFileInformationFork) DataSize() []byte {
size := make([]byte, 4)
- //TODO: Can I do math directly on two byte slices?
+ // TODO: Can I do math directly on two byte slices?
dataSize := len(ffif.Name) + len(ffif.Comment) + 74
binary.BigEndian.PutUint32(size, uint32(dataSize))
comment := bytes[commentStartPos:commentEndPos]
- //dataSizeField := bytes[nameEnd+14+commentLen : nameEnd+18+commentLen]
- //dataSize := binary.BigEndian.Uint32(dataSizeField)
+ // dataSizeField := bytes[nameEnd+14+commentLen : nameEnd+18+commentLen]
+ // dataSize := binary.BigEndian.Uint32(dataSizeField)
ffo := flattenedFileObject{
FlatFileHeader: NewFlatFileHeader(),
--- /dev/null
+package hotline
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "net"
+)
+
+type handshake struct {
+ Protocol [4]byte // Must be 0x54525450 TRTP
+ SubProtocol [4]byte
+ Version [2]byte // Always 1
+ SubVersion [2]byte
+}
+
+// Handshake
+// After establishing TCP connection, both client and server start the handshake process
+// in order to confirm that each of them comply with requirements of the other.
+// The information provided in this initial data exchange identifies protocols,
+// and their versions, used in the communication. In the case where, after inspection,
+// the capabilities of one of the subjects do not comply with the requirements of the other,
+// the connection is dropped.
+//
+// The following information is sent to the server:
+// Description Size Data Note
+// Protocol ID 4 TRTP 0x54525450
+// Sub-protocol ID 4 HOTL User defined
+// VERSION 2 1 Currently 1
+// Sub-version 2 2 User defined
+//
+// The server replies with the following:
+// Description Size Data Note
+// Protocol ID 4 TRTP
+// Error code 4 Error code returned by the server (0 = no error)
+func Handshake(conn net.Conn, buf []byte) error {
+ var h handshake
+ r := bytes.NewReader(buf)
+ if err := binary.Read(r, binary.BigEndian, &h); err != nil {
+ return err
+ }
+
+ if h.Protocol != [4]byte{0x54, 0x52, 0x54, 0x50} {
+ return errors.New("invalid handshake")
+ }
+
+ _, err := conn.Write([]byte{84, 82, 84, 80, 0, 0, 0, 0})
+ return err
+}
}
type NewsCategoryListData15 struct {
- Type []byte `yaml:"Type"` //Size 2 ; Bundle (2) or category (3)
+ Type []byte `yaml:"Type"` // Size 2 ; Bundle (2) or category (3)
Count []byte // Article or SubCategory count Size 2
NameSize byte
Name string `yaml:"Name"` //
type NewsArtData struct {
Title string `yaml:"Title"`
Poster string `yaml:"Poster"`
- Date []byte `yaml:"Date"` //size 8
- PrevArt []byte `yaml:"PrevArt"` //size 4
- NextArt []byte `yaml:"NextArt"` //size 4
- ParentArt []byte `yaml:"ParentArt"` //size 4
- FirstChildArt []byte `yaml:"FirstChildArtArt"` //size 4
+ Date []byte `yaml:"Date"` // size 8
+ PrevArt []byte `yaml:"PrevArt"` // size 4
+ NextArt []byte `yaml:"NextArt"` // size 4
+ ParentArt []byte `yaml:"ParentArt"` // size 4
+ FirstChildArt []byte `yaml:"FirstChildArtArt"` // size 4
DataFlav []byte `yaml:"DataFlav"` // "text/plain"
Data string `yaml:"Data"`
}
return []byte{uint8(len(newscat.Name))}
}
-//type NewsPath struct {
-// Paths []string
-//}
-//
-//func (np *NewsPath) Payload() []byte {
-// var out []byte
-//
-// count := make([]byte, 2)
-// binary.BigEndian.PutUint16(count, uint16(len(np.Paths)))
-//
-// out = append(out, count...)
-// for _, p := range np.Paths {
-// pLen := byte(len(p))
-// out = append(out, []byte{0, 0}...) // what is this?
-// out = append(out, pLen)
-// out = append(out, []byte(p)...)
-// }
-//
-// return out
-//}
-
func ReadNewsPath(newsPath []byte) []string {
if len(newsPath) == 0 {
return []string{}
"go.uber.org/zap"
"io"
"io/ioutil"
- "log"
"math/big"
"math/rand"
"net"
"sync"
"time"
- "golang.org/x/crypto/bcrypt"
"gopkg.in/yaml.v2"
)
APIListener net.Listener
FileListener net.Listener
- newsReader io.Reader
- newsWriter io.WriteCloser
+ // newsReader io.Reader
+ // newsWriter io.WriteCloser
outbox chan Transaction
Connection: conn,
Server: s,
Version: &[]byte{},
- AutoReply: &[]byte{},
+ AutoReply: []byte{},
Transfers: make(map[int][]*FileTransfer),
Agreed: false,
}
var connectedUsers []Field
for _, c := range sortedClients(s.Clients) {
- if c.Agreed == false {
+ if !c.Agreed {
continue
}
user := User{
}
}
-func hashAndSalt(pwd []byte) string {
- // Use GenerateFromPassword to hash & salt pwd.
- // MinCost is just an integer constant provided by the bcrypt
- // package along with DefaultCost & MaxCost.
- // The cost can be any value you want provided it isn't lower
- // than the MinCost (4)
- hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
- if err != nil {
- log.Println(err)
- }
- // GenerateFromPassword returns a byte slice so we need to
- // convert the bytes to a string and return it
- return string(hash)
-}
-
// NewTransactionRef generates a random ID for the file transfer. The Hotline client includes this ID
// in the file transfer request payload, and the file transfer server will use it to map the request
// to a transfer
}
// Read the client's Next Action request
- //TODO: Remove hardcoded behavior and switch behaviors based on the next action send
+ // TODO: Remove hardcoded behavior and switch behaviors based on the next action send
if _, err := conn.Read(readBuffer); err != nil {
return err
}
bytesRead, err := file.Read(sendBuffer)
if err == io.EOF {
// Read the client's Next Action request
- //TODO: Remove hardcoded behavior and switch behaviors based on the next action send
+ // TODO: Remove hardcoded behavior and switch behaviors based on the next action send
if _, err := conn.Read(readBuffer); err != nil {
s.Logger.Errorf("error reading next action: %v", err)
return err
func StartTestServer() (*Server, context.Context, context.CancelFunc) {
ctx, cancelRoot := context.WithCancel(context.Background())
- FS = OSFileStore{}
+ FS = &OSFileStore{}
srv, err := NewServer("test/config/", "localhost", 0, NewTestLogger())
if err != nil {
}
func TestHandshake(t *testing.T) {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
fh, _ := os.Open("./test/config/Agreement.txt")
mfs.On("Open", "/test/config/Agreement.txt").Return(fh, nil)
fh, _ = os.Open("./test/config/config.yaml")
}
-//func TestLogin(t *testing.T) {
+// func TestLogin(t *testing.T) {
//
// tests := []struct {
// name string
//
// })
// }
-//}
+// }
func TestNewUser(t *testing.T) {
srv, _, _ := StartTestServer()
tests := []testCase{
- //{
+ // {
// name: "a valid new account",
// mockHandler: func() mockClientHandler {
// mh := mockClientHandler{}
// want: &Transaction{
// Fields: []Field{},
// },
- //},
- //{
+ // },
+ // {
// name: "a newUser request from a user without the required access",
// mockHandler: func() *mockClientHandler {
// mh := mockClientHandler{}
// NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
// NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
// ),
- //},
- //{
+ // },
+ // {
// name: "when user does not have required permission",
// mockHandler: func() map[int]*mockClientHandler {
// mockHandlers := make(map[int]*mockClientHandler)
// NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
// NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
// ),
- //},
+ // },
- //{
+ // {
// name: "a request to create a user that already exists",
// setup: func() {
//
// NewField(fieldError, []byte("Cannot create account guest because there is already an account with that login.")),
// },
// },
- //},
+ // },
}
for _, test := range tests {
// send test case request
_ = c.Send(*test.request)
- //time.Sleep(1 * time.Second)
+ // time.Sleep(1 * time.Second)
// ===
transactions, _ := readN(c.Connection, 1)
}
}
+// tranAssertEqual compares equality of transactions slices after stripping out the random ID
func tranAssertEqual(t *testing.T, tran1, tran2 []Transaction) bool {
var newT1 []Transaction
var newT2 []Transaction
package hotline
//
-//import (
+// import (
// "bytes"
// "fmt"
// "github.com/google/go-cmp/cmp"
// "strings"
// "sync"
// "testing"
-//)
+// )
//
-//type transactionTest struct {
+// type transactionTest struct {
// description string // Human understandable description
// account Account // Account struct for a user that will test transaction will execute under
// request Transaction // transaction that will be sent by the client to the server
// want Transaction // transaction that the client expects to receive in response
// setup func() // Optional setup required for the test scenario
// teardown func() // Optional teardown for test scenario
-//}
+// }
//
-//func (tt *transactionTest) Setup(srv *Server) error {
+// func (tt *transactionTest) Setup(srv *Server) error {
// if err := srv.NewUser(tt.account.Login, tt.account.Name, NegatedUserString([]byte(tt.account.Password)), tt.account.Access); err != nil {
// return err
// }
// }
//
// return nil
-//}
+// }
//
-//func (tt *transactionTest) Teardown(srv *Server) error {
+// func (tt *transactionTest) Teardown(srv *Server) error {
// if err := srv.DeleteUser(tt.account.Login); err != nil {
// return err
// }
// }
//
// return nil
-//}
+// }
//
-//// StartTestServer
-//func StartTestServer() (srv *Server, lnPort int) {
+// // StartTestServer
+// func StartTestServer() (srv *Server, lnPort int) {
// hotlineServer, _ := NewServer("test/config/")
// ln, err := net.Listen("tcp", ":0")
//
// }
// }()
// return hotlineServer, ln.Addr().(*net.TCPAddr).Port
-//}
+// }
//
-//func StartTestClient(serverPort int, login, passwd string) (*Client, error) {
+// func StartTestClient(serverPort int, login, passwd string) (*Client, error) {
// c := NewClient("")
//
// err := c.JoinServer(fmt.Sprintf(":%v", serverPort), login, passwd)
// }
//
// return c, nil
-//}
+// }
//
-//func StartTestServerWithClients(clientCount int) ([]*Client, int) {
+// func StartTestServerWithClients(clientCount int) ([]*Client, int) {
// _, serverPort := StartTestServer()
//
// var clients []*Client
// clients[0].ReadN(2)
//
// return clients, serverPort
-//}
+// }
//
-////func TestHandleTranAgreed(t *testing.T) {
-//// clients, _ := StartTestServerWithClients(2)
-////
-//// chatMsg := "Test Chat"
-////
-//// // Assert that both clients should receive the user join notification
-//// var wg sync.WaitGroup
-//// for _, client := range clients {
-//// wg.Add(1)
-//// go func(wg *sync.WaitGroup, c *Client) {
-//// defer wg.Done()
-////
-//// receivedMsg := c.ReadTransactions()[0].GetField(fieldData).Data
-////
-//// want := []byte(fmt.Sprintf("test: %s\r", chatMsg))
-//// if bytes.Compare(receivedMsg, want) != 0 {
-//// t.Errorf("%q, want %q", receivedMsg, want)
-//// }
-//// }(&wg, client)
-//// }
-////
-//// trans := clients[1].ReadTransactions()
-//// spew.Dump(trans)
-////
-//// // Send the agreement
-//// clients[1].Connection.Write(
-//// NewTransaction(
-//// tranAgreed, 0,
-//// []Field{
-//// NewField(fieldUserName, []byte("testUser")),
-//// NewField(fieldUserIconID, []byte{0x00,0x07}),
-//// },
-//// ).Payload(),
-//// )
-////
-//// wg.Wait()
-////}
-//
-//func TestChatSend(t *testing.T) {
+// //func TestHandleTranAgreed(t *testing.T) {
+// // clients, _ := StartTestServerWithClients(2)
+// //
+// // chatMsg := "Test Chat"
+// //
+// // // Assert that both clients should receive the user join notification
+// // var wg sync.WaitGroup
+// // for _, client := range clients {
+// // wg.Add(1)
+// // go func(wg *sync.WaitGroup, c *Client) {
+// // defer wg.Done()
+// //
+// // receivedMsg := c.ReadTransactions()[0].GetField(fieldData).Data
+// //
+// // want := []byte(fmt.Sprintf("test: %s\r", chatMsg))
+// // if bytes.Compare(receivedMsg, want) != 0 {
+// // t.Errorf("%q, want %q", receivedMsg, want)
+// // }
+// // }(&wg, client)
+// // }
+// //
+// // trans := clients[1].ReadTransactions()
+// // spew.Dump(trans)
+// //
+// // // Send the agreement
+// // clients[1].Connection.Write(
+// // NewTransaction(
+// // tranAgreed, 0,
+// // []Field{
+// // NewField(fieldUserName, []byte("testUser")),
+// // NewField(fieldUserIconID, []byte{0x00,0x07}),
+// // },
+// // ).Payload(),
+// // )
+// //
+// // wg.Wait()
+// //}
+//
+// func TestChatSend(t *testing.T) {
// //srvPort := StartTestServer()
// //
// //senderClient := NewClient("senderClient")
// )
//
// wg.Wait()
-//}
+// }
//
-//func TestSetClientUserInfo(t *testing.T) {
+// func TestSetClientUserInfo(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
//
// newIcon := []byte{0x00, 0x01}
// }
//
// wg.Wait()
-//}
+// }
//
-//// TestSendInstantMsg tests that client A can send an instant message to client B
-////
-//func TestSendInstantMsg(t *testing.T) {
+// // TestSendInstantMsg tests that client A can send an instant message to client B
+// //
+// func TestSendInstantMsg(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
//
// instantMsg := "Test IM"
// }
//
// wg.Wait()
-//}
+// }
//
-//func TestOldPostNews(t *testing.T) {
+// func TestOldPostNews(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
//
// newsPost := "Test News Post"
// )
//
// wg.Wait()
-//}
-//
-//// TODO: Fixme
-////func TestGetFileNameList(t *testing.T) {
-//// clients, _ := StartTestServerWithClients(2)
-////
-//// clients[0].Connection.Write(
-//// NewTransaction(
-//// tranGetFileNameList, 0,
-//// []Field{},
-//// ).Payload(),
-//// )
-////
-//// ts := clients[0].ReadTransactions()
-//// testfileSit := ReadFileNameWithInfo(ts[0].Fields[1].Data)
-////
-//// want := "testfile.sit"
-//// got := testfileSit.Name
-//// diff := cmp.Diff(want, got)
-//// if diff != "" {
-//// t.Fatalf(diff)
-//// }
-//// if testfileSit.Name != "testfile.sit" {
-//// t.Errorf("news post missing")
-//// t.Errorf("%q, want %q", testfileSit.Name, "testfile.sit")
-//// }
-////}
-//
-//func TestNewsCategoryList(t *testing.T) {
+// }
+//
+// // TODO: Fixme
+// //func TestGetFileNameList(t *testing.T) {
+// // clients, _ := StartTestServerWithClients(2)
+// //
+// // clients[0].Connection.Write(
+// // NewTransaction(
+// // tranGetFileNameList, 0,
+// // []Field{},
+// // ).Payload(),
+// // )
+// //
+// // ts := clients[0].ReadTransactions()
+// // testfileSit := ReadFileNameWithInfo(ts[0].Fields[1].Data)
+// //
+// // want := "testfile.sit"
+// // got := testfileSit.Name
+// // diff := cmp.Diff(want, got)
+// // if diff != "" {
+// // t.Fatalf(diff)
+// // }
+// // if testfileSit.Name != "testfile.sit" {
+// // t.Errorf("news post missing")
+// // t.Errorf("%q, want %q", testfileSit.Name, "testfile.sit")
+// // }
+// //}
+//
+// func TestNewsCategoryList(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
// client := clients[0]
//
// if diff != "" {
// t.Fatalf(diff)
// }
-//}
+// }
//
-//func TestNestedNewsCategoryList(t *testing.T) {
+// func TestNestedNewsCategoryList(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
// client := clients[0]
// newsPath := NewsPath{
// if diff != "" {
// t.Fatalf(diff)
// }
-//}
+// }
//
-//func TestFileDownload(t *testing.T) {
+// func TestFileDownload(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
// client := clients[0]
//
// t.Errorf("TestFileDownload: fieldTransferSize: %s: got %#v, want %#v", test.fileName, got, test.want.transferSize)
// }
// }
-//}
+// }
//
-//func TestFileUpload(t *testing.T) {
+// func TestFileUpload(t *testing.T) {
// clients, _ := StartTestServerWithClients(2)
// client := clients[0]
//
// }
// }
// }
-//}
+// }
//
-//// TODO: Make canonical
-//func TestNewUser(t *testing.T) {
+// // TODO: Make canonical
+// func TestNewUser(t *testing.T) {
// srv, port := StartTestServer()
//
// var tests = []struct {
// test.teardown()
// }
// }
-//}
+// }
//
-//func TestDeleteUser(t *testing.T) {
+// func TestDeleteUser(t *testing.T) {
// srv, port := StartTestServer()
//
// var tests = []transactionTest{
//
// test.Teardown(srv)
// }
-//}
+// }
//
-//func TestDeleteFile(t *testing.T) {
+// func TestDeleteFile(t *testing.T) {
// srv, port := StartTestServer()
//
// var tests = []transactionTest{
//
// test.Teardown(srv)
// }
-//}
+// }
//
-//func Test_authorize(t *testing.T) {
+// func Test_authorize(t *testing.T) {
// accessBitmap := big.NewInt(int64(0))
// accessBitmap.SetBit(accessBitmap, accessCreateFolder, 1)
// fmt.Printf("%v %b %x\n", accessBitmap, accessBitmap, accessBitmap)
// }
// })
// }
-//}
+// }
return nil
}
-type ServerListing struct {
-}
-
const trackerTimeout = 5 * time.Second
// All string values use 8-bit ASCII character set encoding.
Version [2]byte // Old protocol (1) or new (2)
}
-//Message type 2 1 Sending list of servers
-//Message data size 2 Remaining size of this request
-//Number of servers 2 Number of servers in the server list
-//Number of servers 2 Same as previous field
+// Message type 2 1 Sending list of servers
+// Message data size 2 Remaining size of this request
+// Number of servers 2 Number of servers in the server list
+// Number of servers 2 Same as previous field
type ServerInfoHeader struct {
MsgType [2]byte // always has value of 1
MsgDataSize [2]byte // Remaining size of request
return 12 + nameLen + int(s.DescriptionSize), nil
}
-//
-//func (s *ServerRecord) UnmarshalBinary(b []byte) (err error) {
-// r := bytes.NewReader(b[:10])
-// if err := binary.Read(r, binary.BigEndian, s); err != nil {
-// return err
-// }
-//
-// copy(s.IPAddr[:], b[0:4])
-// s.Port = b[4:6]
-// s.NumUsers = b[6:8]
-// s.NameSize = b[10]
-// nameLen := int(b[10])
-// s.Name = b[11 : 11+nameLen]
-// s.DescriptionSize = b[11+nameLen]
-// s.Description = b[12+nameLen : 12+nameLen+int(s.DescriptionSize)]
-//
-// return nil
-//}
-
func (s *ServerRecord) PortInt() int {
data := binary.BigEndian.Uint16(s.Port[:])
return int(data)
},
tranSendInstantMsg: {
Access: accessAlwaysAllow,
- //Access: accessSendPrivMsg,
- //DenyMsg: "You are not allowed to send private messages",
+ // Access: accessSendPrivMsg,
+ // DenyMsg: "You are not allowed to send private messages",
Name: "tranSendInstantMsg",
Handler: HandleSendInstantMsg,
RequiredFields: []requiredField{
// 101 Data Optional
// 214 Quoting message Optional
//
-//Fields used in the reply:
+// Fields used in the reply:
// None
func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
msg := t.GetField(fieldData)
ID := t.GetField(fieldUserID)
// TODO: Implement reply quoting
- //options := transaction.GetField(hotline.fieldOptions)
+ // options := transaction.GetField(hotline.fieldOptions)
res = append(res,
*NewTransaction(
)
id, _ := byteToInt(ID.Data)
- //keys := make([]uint16, 0, len(cc.Server.Clients))
- //for k := range cc.Server.Clients {
- // keys = append(keys, k)
- //}
-
otherClient := cc.Server.Clients[uint16(id)]
if otherClient == nil {
return res, errors.New("ohno")
}
// Respond with auto reply if other client has it enabled
- if len(*otherClient.AutoReply) > 0 {
+ if len(otherClient.AutoReply) > 0 {
res = append(res,
*NewTransaction(
tranServerMsg,
cc.ID,
- NewField(fieldData, *otherClient.AutoReply),
+ NewField(fieldData, otherClient.AutoReply),
NewField(fieldUserName, otherClient.UserName),
NewField(fieldUserID, *otherClient.ID),
NewField(fieldOptions, []byte{0, 1}),
return nil, err
}
- //fileComment := t.GetField(fieldFileComment).Data
+ // fileComment := t.GetField(fieldFileComment).Data
fileNewName := t.GetField(fieldFileNewName).Data
if fileNewName != nil {
}
func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
- userLogin := string(t.GetField(fieldUserLogin).Data)
- account := cc.Server.Accounts[userLogin]
+ // userLogin := string(t.GetField(fieldUserLogin).Data)
+ account := cc.Server.Accounts[string(t.GetField(fieldUserLogin).Data)]
if account == nil {
errorT := cc.NewErrReply(t, "Account does not exist.")
res = append(res, errorT)
// Check auto response
if optBitmap.Bit(autoResponse) == 1 {
- *cc.AutoReply = t.GetField(fieldAutomaticResponse).Data
+ cc.AutoReply = t.GetField(fieldAutomaticResponse).Data
} else {
- *cc.AutoReply = []byte{}
+ cc.AutoReply = []byte{}
}
_, _ = cc.notifyNewUserHasJoined()
}
fullFilePath, err := readPath(cc.Server.Config.FileRoot, t.GetField(fieldFilePath).Data, t.GetField(fieldFileName).Data)
+ if err != nil {
+ return res, err
+ }
transferSize, err := CalcTotalSize(fullFilePath)
if err != nil {
// Check auto response
if optBitmap.Bit(autoResponse) == 1 {
- *cc.AutoReply = t.GetField(fieldAutomaticResponse).Data
+ cc.AutoReply = t.GetField(fieldAutomaticResponse).Data
} else {
- *cc.AutoReply = []byte{}
+ cc.AutoReply = []byte{}
}
}
),
},
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
FS = mfs
),
},
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
FS = mfs
),
},
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
FS = mfs
),
},
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
FS = mfs
),
},
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
FS = mfs
t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
return
}
- if !tranAssertEqual(t, tt.wantRes, gotRes) {
- t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)
- }
+
+ tranAssertEqual(t, tt.wantRes, gotRes)
+
})
}
}
{
name: "with valid input and required permissions",
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
path, _ := os.Getwd()
mfs.On(
"Symlink",
{
name: "when symlink returns an error",
setup: func() {
- mfs := MockFileStore{}
+ mfs := &MockFileStore{}
path, _ := os.Getwd()
mfs.On(
"Symlink",
joinServerForm.
// AddInputField("Name", server, 0, func(textToCheck string, lastChar rune) bool {
// return false
- //}, nil).
+ // }, nil).
AddInputField("Server", server, 0, nil, nil).
AddInputField("Login", login, 0, nil, nil).
AddPasswordField("Password", password, 0, '*', nil).
newsPostForm := tview.NewForm().
SetButtonsAlign(tview.AlignRight).
- //AddButton("Cancel", nil). // TODO: implement cancel button behavior
+ // AddButton("Cancel", nil). // TODO: implement cancel button behavior
AddButton("Send", nil)
newsPostForm.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(newsFlex, 15, 1, true).
- //AddItem(newsPostForm, 3, 0, false).
+ // AddItem(newsPostForm, 3, 0, false).
AddItem(nil, 0, 1, false), 40, 1, false).
AddItem(nil, 0, 1, false)
import (
"encoding/binary"
+ "golang.org/x/crypto/bcrypt"
+ "log"
)
// User flags are stored as a 2 byte bitmap with the following values:
}
return obfuText
}
+
+func hashAndSalt(pwd []byte) string {
+ // Use GenerateFromPassword to hash & salt pwd.
+ // MinCost is just an integer constant provided by the bcrypt
+ // package along with DefaultCost & MaxCost.
+ // The cost can be any value you want provided it isn't lower
+ // than the MinCost (4)
+ hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
+ if err != nil {
+ log.Println(err)
+ }
+ // GenerateFromPassword returns a byte slice so we need to
+ // convert the bytes to a string and return it
+ return string(hash)
+}