func TestServerTestAccount(t *testing.T) { A := AccountInfo{ AccountName: "test account", AccessKey: core.DeepHmac(20000, append([]byte("test account"), []byte("*ACCESS*KEY*PAD*")...), core.Hash([]byte("password"))), Datasets: core.DatasetArray{}, } accountHandler.SetInfo(A) JA, _ := json.Marshal(A) B := accountHandler.GetInfo(core.Hash([]byte(A.AccountName))) JB, _ := json.Marshal(*B) if B == nil { t.Error("Account not found") } else if string(JA) != string(JB) { fmt.Println(string(JA)) fmt.Println(string(JB)) t.Error("Accounts not equal") } C := accountHandler.GetInfo(core.Hash([]byte(""))) if C != nil { t.Error("Account without name found") } }
func TestClientServerAuthentication(t *testing.T) { var err error conn, err := net.Dial("tcp", "127.0.0.1:1248") if err != nil { panic(err) } conn.SetDeadline(time.Now().Add(15 * time.Second)) client := core.NewClient(conn, "test account", core.DeepHmac(20000, append([]byte("test account"), []byte("*ACCESS*KEY*PAD*")...), core.Hash([]byte("password")))) defer client.Close(true) }
func TestClientServerHashboxBlocks(t *testing.T) { var err error conn, err := net.Dial("tcp", "127.0.0.1:1248") if err != nil { panic(err) } conn.SetDeadline(time.Now().Add(10 * time.Minute)) client := core.NewClient(conn, "test account", core.DeepHmac(20000, append([]byte("test account"), []byte("*ACCESS*KEY*PAD*")...), core.Hash([]byte("password")))) defer client.Close(true) { var data bytearray.ByteArray data.Write([]byte("HELLO!")) blockID := client.StoreData(core.BlockDataTypeRaw, data, nil) client.Commit() block := client.ReadBlock(blockID) if !reflect.DeepEqual(blockID, block.BlockID) { t.Error("Received block has wrong ID") } rdata, _ := block.Data.ReadSlice() if !bytes.Equal(rdata, []byte("HELLO!")) { t.Error("Block contains wrong data, expected \"HELLO!\" received \"" + string(rdata) + "\"") } } { var data bytearray.ByteArray data.Write([]byte("Bet it all on black?")) blockID := client.StoreData(core.BlockDataTypeRaw, data, nil) client.Commit() block := client.ReadBlock(blockID) if !reflect.DeepEqual(blockID, block.BlockID) { t.Error("Received block has wrong ID") } rdata, _ := block.Data.ReadSlice() if !bytes.Equal(rdata, []byte("Bet it all on black?")) { t.Error("Block contains wrong data, expected \"Bet it all on black?\" received \"" + string(rdata) + "\"") } } }
func GenerateBackupKey(account string, password string) core.Byte128 { return core.DeepHmac(20000, append([]byte(account), []byte("*ENCRYPTION*PAD*")...), core.Hash([]byte(password))) }
func GenerateAccessKey(account string, password string) core.Byte128 { return core.DeepHmac(20000, append([]byte(account), []byte("*ACCESS*KEY*PAD*")...), core.Hash([]byte(password))) }
func handleConnection(conn net.Conn) { remoteID := conn.RemoteAddr().String() core.Log(core.LogInfo, "%s - Connection established", remoteID) defer func() { if err := recover(); err != nil { core.Log(core.LogError, "%s - %v", remoteID, err) } core.Log(core.LogInfo, "%s - Connection closed", remoteID) conn.Close() }() var clientSession core.Session var sessionAuthenticated = false for keepAlive := true; keepAlive; { conn.SetReadDeadline(time.Now().Add(10 * time.Minute)) // max size 512kb over 10 minutes is slower than 9600bps so we should be safe // TODO: testing non-idle of 10s between commands unauthorized := false func() { incoming := core.ReadMessage(conn) defer incoming.Release() core.Log(core.LogInfo, "%s < %s %s", remoteID, incoming.String(), incoming.Details()) reply := &core.ProtocolMessage{Num: incoming.Num, Type: incoming.Type & core.MsgTypeServerMask} defer reply.Release() switch incoming.Type { case core.MsgTypeOldGreeting: reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Client uses an outdated protocol version"} case core.MsgTypeGreeting: c := incoming.Data.(*core.MsgClientGreeting) if c.Version < core.ProtocolVersion { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Client uses an outdated protocol version"} } else if c.Version > core.ProtocolVersion { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Server uses an outdated protocol version"} } else { // Create server nonce using 64-bit time and 64-bit random binary.BigEndian.PutUint64(clientSession.SessionNonce[0:], uint64(time.Now().UnixNano())) binary.BigEndian.PutUint32(clientSession.SessionNonce[8:], rand.Uint32()) binary.BigEndian.PutUint32(clientSession.SessionNonce[12:], rand.Uint32()) reply.Data = &core.MsgServerGreeting{clientSession.SessionNonce} } case core.MsgTypeAuthenticate: c := incoming.Data.(*core.MsgClientAuthenticate) clientSession.AccountNameH = c.AccountNameH account := accountHandler.GetInfo(clientSession.AccountNameH) if account != nil { clientSession.GenerateSessionKey(account.AccessKey) myAuthenticationH := core.DeepHmac(1, c.AccountNameH[:], clientSession.SessionKey) sessionAuthenticated = bytes.Equal(myAuthenticationH[:], c.AuthenticationH[:]) } unauthorized = !sessionAuthenticated case core.MsgTypeGoodbye: keepAlive = false default: unauthorized = !sessionAuthenticated if !unauthorized { switch incoming.Type { case core.MsgTypeAddDatasetState: c := incoming.Data.(*core.MsgClientAddDatasetState) unauthorized = c.AccountNameH != clientSession.AccountNameH // TODO: admin support for other accounts hashes? if !unauthorized { if !storageHandler.doesBlockExist(c.State.BlockID) { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Dataset pointing to a non existent block"} } else { accountHandler.AddDatasetState(c.AccountNameH, c.DatasetName, c.State) // No need to set any data in reply } } case core.MsgTypeRemoveDatasetState: c := incoming.Data.(*core.MsgClientRemoveDatasetState) unauthorized = c.AccountNameH != clientSession.AccountNameH // TODO: admin support for other accounts hashes? if !unauthorized { accountHandler.RemoveDatasetState(c.AccountNameH, c.DatasetName, c.StateID) // No need to set any data in reply } case core.MsgTypeListDataset: c := incoming.Data.(*core.MsgClientListDataset) unauthorized = c.AccountNameH != clientSession.AccountNameH // TODO: admin support for other accounts hashes? if !unauthorized { list := accountHandler.ListDataset(c.AccountNameH, c.DatasetName) if list == nil { list = new(dbStateCollection) } reply.Data = &core.MsgServerListDataset{States: list.States, ListH: list.ListH} // } else { // reply.Type = core.MsgTypeError & core.MsgTypeServerMask // reply.Data = &core.MsgServerError{"Cannot list dataset named " + c.DatasetName} } case core.MsgTypeAccountInfo: c := incoming.Data.(*core.MsgClientAccountInfo) unauthorized = c.AccountNameH != clientSession.AccountNameH // TODO: admin support for other accounts hashes? if !unauthorized { account := accountHandler.GetInfo(c.AccountNameH) if account != nil { reply.Data = &core.MsgServerAccountInfo{DatasetList: account.Datasets} } else { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Cannot find account information"} } } case core.MsgTypeAllocateBlock: c := incoming.Data.(*core.MsgClientAllocateBlock) if storageHandler.doesBlockExist(c.BlockID) { reply.Type = core.MsgTypeAcknowledgeBlock & core.MsgTypeServerMask reply.Data = &core.MsgServerAcknowledgeBlock{BlockID: c.BlockID} } else { reply.Type = core.MsgTypeReadBlock & core.MsgTypeServerMask reply.Data = &core.MsgServerReadBlock{BlockID: c.BlockID} } case core.MsgTypeReadBlock: c := incoming.Data.(*core.MsgClientReadBlock) block := storageHandler.readBlock(c.BlockID) if block == nil { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Invalid blockID"} keepAlive = false } else { reply.Type = core.MsgTypeWriteBlock & core.MsgTypeServerMask reply.Data = &core.MsgServerWriteBlock{Block: block} } case core.MsgTypeWriteBlock: c := incoming.Data.(*core.MsgClientWriteBlock) if c.Block.VerifyBlock() { for _, l := range c.Block.Links { if !storageHandler.doesBlockExist(l) { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Linked to non existant block"} break } } if !storageHandler.checkFree(int64(c.Block.Data.Len())) { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Write permission is denied because the server is out of space"} } if reply.Data == nil { storageHandler.writeBlock(c.Block) reply.Type = core.MsgTypeAcknowledgeBlock & core.MsgTypeServerMask reply.Data = &core.MsgServerAcknowledgeBlock{BlockID: c.Block.BlockID} } } else { reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Unable to verify blockID"} } default: panic(errors.New("ASSERT: Well if we reach this point, we have not implemented everything correctly (missing " + incoming.String() + ")")) } } } if unauthorized { // Invalid authentication // TODO: Add to server auth.log reply.Type = core.MsgTypeError & core.MsgTypeServerMask reply.Data = &core.MsgServerError{"Invalid authentication"} keepAlive = false } core.Log(core.LogInfo, "%s > %s %s", remoteID, reply.String(), reply.Details()) core.WriteMessage(conn, reply) }() } }
func TestClientServerDataset(t *testing.T) { var err error conn, err := net.Dial("tcp", "127.0.0.1:1248") if err != nil { panic(err) } conn.SetDeadline(time.Now().Add(10 * time.Minute)) client := core.NewClient(conn, "test account", core.DeepHmac(20000, append([]byte("test account"), []byte("*ACCESS*KEY*PAD*")...), core.Hash([]byte("password")))) defer client.Close(true) // First make sure there is some data to reference var data bytearray.ByteArray block := core.NewHashboxBlock(core.BlockDataTypeZlib, data, nil) var blockID core.Byte128 blockID = client.StoreBlock(block) client.Commit() var array core.DatasetStateArray var stateID core.Byte128 // randomByte128() copy(stateID[:], []byte("testC")) keepstate := core.DatasetState{StateID: stateID, BlockID: blockID, Size: 5, UniqueSize: 42} client.AddDatasetState("testset", keepstate) array = append(array, core.DatasetStateEntry{State: keepstate}) copy(stateID[:], []byte("testD")) keepstate = core.DatasetState{StateID: stateID, BlockID: blockID, Size: 125, UniqueSize: 33342} client.AddDatasetState("testset", keepstate) array = append(array, core.DatasetStateEntry{State: keepstate}) copy(stateID[:], []byte("testA")) client.AddDatasetState("testset", core.DatasetState{StateID: stateID, BlockID: blockID, Size: 5, UniqueSize: 42}) copy(stateID[:], []byte("testB")) client.AddDatasetState("testset", core.DatasetState{StateID: stateID, BlockID: blockID, Size: 5, UniqueSize: 42}) copy(stateID[:], []byte("testB")) client.RemoveDatasetState("testset", stateID) copy(stateID[:], []byte("testA")) client.RemoveDatasetState("testset", stateID) client.RemoveDatasetState("testset", stateID) hash := md5.New() array[0].Serialize(hash) array[1].Serialize(hash) var localHash core.Byte128 copy(localHash[:], hash.Sum(nil)[:16]) info := client.GetAccountInfo() if reflect.TypeOf(info).String() != "*core.MsgServerAccountInfo" { t.Error("Invalid response to client.GetAccountInfo") } if len(info.DatasetList) != 1 { t.Error("More than one dataset was found under test account") } else { if info.DatasetList[0].Name != "testset" { t.Error("First dataset is not named \"testset\"") } if fmt.Sprintf("%x", info.DatasetList[0].ListH) != fmt.Sprintf("%x", localHash) { t.Error(fmt.Sprintf("%x != %x", info.DatasetList[0].ListH, localHash)) t.Error("List hash could not be verified") } if info.DatasetList[0].Size != 33509 { t.Error(fmt.Sprintf("Wrong total size for the dataset %d != %d", info.DatasetList[0].Size, 33509)) } } list := client.ListDataset("testset") if list == nil { t.Error("Dataset \"testset\" was not found") } else if !reflect.DeepEqual(array, list.States) { fmt.Println(array) fmt.Println(list.States) t.Error("Local list and remote list not equal") } }