File Sharing Integration Tests now Works with New Storage Code
continuous-integration/drone/push Build is pending Details

This commit is contained in:
Sarah Jamie Lewis 2021-11-10 14:28:52 -08:00
parent 8c80340a3d
commit 3d0ed3d4b0
6 changed files with 173 additions and 62 deletions

5
.gitignore vendored
View File

@ -24,4 +24,7 @@ testing/cwtch.out.png.manifest
testing/tordir/ testing/tordir/
tokens-bak.db tokens-bak.db
tokens.db tokens.db
tokens1.db tokens1.db
arch/
testing/encryptedstorage/encrypted_storage_profiles
testing/encryptedstorage/tordir

View File

@ -138,11 +138,11 @@ func (cp *cwtchPeer) SendMessage(handle string, message string) error {
ev = event.NewEvent(event.SendMessageToGroup, map[event.Field]string{event.GroupID: handle, event.GroupServer: group.GroupServer, event.Ciphertext: base64.StdEncoding.EncodeToString(ct), event.Signature: base64.StdEncoding.EncodeToString(sig)}) ev = event.NewEvent(event.SendMessageToGroup, map[event.Field]string{event.GroupID: handle, event.GroupServer: group.GroupServer, event.Ciphertext: base64.StdEncoding.EncodeToString(ct), event.Signature: base64.StdEncoding.EncodeToString(sig)})
} else if tor.IsValidHostname(handle) { } else if tor.IsValidHostname(handle) {
// We assume we are sending to a Contact. // We assume we are sending to a Contact.
contact, exists := cp.FetchConversationInfo(handle) contact, err := cp.FetchConversationInfo(handle)
ev = event.NewEvent(event.SendMessageToPeer, map[event.Field]string{event.RemotePeer: handle, event.Data: message}) ev = event.NewEvent(event.SendMessageToPeer, map[event.Field]string{event.RemotePeer: handle, event.Data: message})
// If the contact exists replace the event id wih the index of this message in the contacts timeline... // If the contact exists replace the event id wih the index of this message in the contacts timeline...
// Otherwise assume we don't log the message in the timeline... // Otherwise assume we don't log the message in the timeline...
if exists != nil { if contact != nil && err == nil {
//ev.EventID = strconv.Itoa(contact.Timeline.Len()) //ev.EventID = strconv.Itoa(contact.Timeline.Len())
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
@ -326,44 +326,50 @@ func (cp *cwtchPeer) NewContactConversation(handle string, acl model.AccessContr
// AcceptConversation looks up a conversation by `handle` and sets the Accepted status to `true` // AcceptConversation looks up a conversation by `handle` and sets the Accepted status to `true`
// This will cause Cwtch to auto connect to this conversation on start up // This will cause Cwtch to auto connect to this conversation on start up
func (cp *cwtchPeer) AcceptConversation(handle string) error { func (cp *cwtchPeer) AcceptConversation(id int) error {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
return cp.storage.AcceptConversation(handle) return cp.storage.AcceptConversation(id)
}
func (cp *cwtchPeer) FetchConversations() ([]*model.Conversation, error) {
cp.mutex.Lock()
defer cp.mutex.Unlock()
return cp.storage.FetchConversations()
} }
// FetchConversationInfo returns information about the given conversation referenced by the handle // FetchConversationInfo returns information about the given conversation referenced by the handle
func (cp *cwtchPeer) FetchConversationInfo(handle string) (*model.Conversation, error) { func (cp *cwtchPeer) FetchConversationInfo(handle string) (*model.Conversation, error) {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
return cp.storage.GetConversation(handle) return cp.storage.GetConversationByHandle(handle)
} }
// DeleteConversation purges all data about the conversation, including message timelines, referenced by the handle // DeleteConversation purges all data about the conversation, including message timelines, referenced by the handle
func (cp *cwtchPeer) DeleteConversation(handle string) error { func (cp *cwtchPeer) DeleteConversation(id int) error {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
return cp.storage.DeleteConversation(handle) return cp.storage.DeleteConversation(id)
} }
// SetConversationAttribute sets the conversation attribute at path to value // SetConversationAttribute sets the conversation attribute at path to value
func (cp *cwtchPeer) SetConversationAttribute(handle string, path attr.ScopedZonedPath, value string) error { func (cp *cwtchPeer) SetConversationAttribute(id int, path attr.ScopedZonedPath, value string) error {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
return cp.storage.SetConversationAttribute(handle, path, value) return cp.storage.SetConversationAttribute(id, path, value)
} }
// GetConversationAttribute is a shortcut method for retrieving the value of a given path // GetConversationAttribute is a shortcut method for retrieving the value of a given path
func (cp *cwtchPeer) GetConversationAttribute(handle string, path attr.ScopedZonedPath) (string, error) { func (cp *cwtchPeer) GetConversationAttribute(id int, path attr.ScopedZonedPath) (string, error) {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
ci, err := cp.storage.GetConversation(handle) ci, err := cp.storage.GetConversation(id)
if err != nil { if err != nil {
return "", err return "", err
} }
val, exists := ci.Attributes[path.ToString()] val, exists := ci.Attributes[path.ToString()]
if !exists { if !exists {
return "", fmt.Errorf("%v does not exist for conversation %v", path.ToString(), handle) return "", fmt.Errorf("%v does not exist for conversation %v", path.ToString(), id)
} }
return val, nil return val, nil
} }
@ -521,8 +527,8 @@ func (cp *cwtchPeer) GetOnion() string {
func (cp *cwtchPeer) GetPeerState(onion string) (connections.ConnectionState, bool) { func (cp *cwtchPeer) GetPeerState(onion string) (connections.ConnectionState, bool) {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
if peer, ok := cp.Profile.Contacts[onion]; ok { if state, ok := cp.state[onion]; ok {
return connections.ConnectionStateToType()[peer.State], true return state, ok
} }
return connections.DISCONNECTED, false return connections.DISCONNECTED, false
} }
@ -699,7 +705,7 @@ func (cp *cwtchPeer) eventHandler() {
// The security of cwtch groups are also not dependent on the servers inability to uniquely tag connections (as long as // The security of cwtch groups are also not dependent on the servers inability to uniquely tag connections (as long as
// it learns nothing else about each connection). // it learns nothing else about each connection).
// store the base64 encoded signature for later use // store the base64 encoded signature for later use
cp.SetConversationAttribute(ev.Data[event.GroupServer], lastKnownSignature, ev.Data[event.Signature]) //cp.SetConversationAttribute(ev.Data[event.GroupServer], lastKnownSignature, ev.Data[event.Signature])
cp.mutex.Lock() cp.mutex.Lock()
ok, groupID, message, index := cp.Profile.AttemptDecryption(ciphertext, signature) ok, groupID, message, index := cp.Profile.AttemptDecryption(ciphertext, signature)
@ -851,7 +857,10 @@ func (cp *cwtchPeer) eventHandler() {
// Allow public profile parameters to be added as peer specific attributes... // Allow public profile parameters to be added as peer specific attributes...
if attr.Scope(scope).IsPublic() && zone == attr.ProfileZone { if attr.Scope(scope).IsPublic() && zone == attr.ProfileZone {
cp.SetConversationAttribute(onion, attr.Scope(scope).ConstructScopedZonedPath(zone.ConstructZonedPath(path)), val) ci, err := cp.FetchConversationInfo(onion)
if ci != nil && err != nil {
cp.SetConversationAttribute(ci.ID, attr.Scope(scope).ConstructScopedZonedPath(zone.ConstructZonedPath(path)), val)
}
} }
} }
case event.PeerStateChange: case event.PeerStateChange:

View File

@ -34,11 +34,13 @@ type CwtchProfileStorage struct {
selectProfileKeyValueStmt *sql.Stmt selectProfileKeyValueStmt *sql.Stmt
// Conversation related statements // Conversation related statements
insertConversationStmt *sql.Stmt insertConversationStmt *sql.Stmt
selectConversationStmt *sql.Stmt fetchAllConversationsStmt *sql.Stmt
acceptConversationStmt *sql.Stmt selectConversationStmt *sql.Stmt
deleteConversationStmt *sql.Stmt selectConversationByHandleStmt *sql.Stmt
setConversationAttributesStmt *sql.Stmt acceptConversationStmt *sql.Stmt
deleteConversationStmt *sql.Stmt
setConversationAttributesStmt *sql.Stmt
channelInsertStmts map[ChannelID]*sql.Stmt channelInsertStmts map[ChannelID]*sql.Stmt
channelGetMessageStmts map[ChannelID]*sql.Stmt channelGetMessageStmts map[ChannelID]*sql.Stmt
@ -55,10 +57,12 @@ const insertProfileKeySQLStmt = `insert into profile_kv(KeyType, KeyName, KeyVal
const selectProfileKeySQLStmt = `select KeyValue from profile_kv where KeyType=(?) and KeyName=(?);` const selectProfileKeySQLStmt = `select KeyValue from profile_kv where KeyType=(?) and KeyName=(?);`
const insertConversationSQLStmt = `insert into conversations(Handle, Attributes, ACL, Accepted) values(?,?,?,?);` const insertConversationSQLStmt = `insert into conversations(Handle, Attributes, ACL, Accepted) values(?,?,?,?);`
const selectConversationSQLStmt = `select ID, Handle, Attributes, ACL, Accepted from conversations where Handle=(?);` const fetchAllConversationsSQLStmt = `select ID, Handle, Attributes, ACL, Accepted from conversations;`
const acceptedConversationSQLStmt = `update conversations set Accepted=true where Handle=(?);` const selectConversationSQLStmt = `select ID, Handle, Attributes, ACL, Accepted from conversations where ID=(?);`
const setConversationAttributesSQLStmt = `update conversations set Attributes=(?) where Handle=(?) ;` const selectConversationByHandleSQLStmt = `select ID, Handle, Attributes, ACL, Accepted from conversations where Handle=(?);`
const deleteConversationSQLStmt = `delete from conversations where Handle=(?);` const acceptedConversationSQLStmt = `update conversations set Accepted=true where ID=(?);`
const setConversationAttributesSQLStmt = `update conversations set Attributes=(?) where ID=(?) ;`
const deleteConversationSQLStmt = `delete from conversations where ID=(?);`
// createTableConversationMessagesSQLStmt is a template for creating conversation based tables... // createTableConversationMessagesSQLStmt is a template for creating conversation based tables...
const createTableConversationMessagesSQLStmt = `create table if not exists channel_%d_0_chat (ID integer unique primary key autoincrement, Body text, Attributes []byte, Expiry datetime);` const createTableConversationMessagesSQLStmt = `create table if not exists channel_%d_0_chat (ID integer unique primary key autoincrement, Body text, Attributes []byte, Expiry datetime);`
@ -95,12 +99,24 @@ func NewCwtchProfileStorage(db *sql.DB) (*CwtchProfileStorage, error) {
return nil, err return nil, err
} }
fetchAllConversationsStmt, err := db.Prepare(fetchAllConversationsSQLStmt)
if err != nil {
log.Errorf("error preparing query: %v %v", fetchAllConversationsSQLStmt, err)
return nil, err
}
selectConversationStmt, err := db.Prepare(selectConversationSQLStmt) selectConversationStmt, err := db.Prepare(selectConversationSQLStmt)
if err != nil { if err != nil {
log.Errorf("error preparing query: %v %v", selectConversationSQLStmt, err) log.Errorf("error preparing query: %v %v", selectConversationSQLStmt, err)
return nil, err return nil, err
} }
selectConversationByHandleStmt, err := db.Prepare(selectConversationByHandleSQLStmt)
if err != nil {
log.Errorf("error preparing query: %v %v", selectConversationByHandleSQLStmt, err)
return nil, err
}
acceptConversationStmt, err := db.Prepare(acceptedConversationSQLStmt) acceptConversationStmt, err := db.Prepare(acceptedConversationSQLStmt)
if err != nil { if err != nil {
log.Errorf("error preparing query: %v %v", acceptedConversationSQLStmt, err) log.Errorf("error preparing query: %v %v", acceptedConversationSQLStmt, err)
@ -119,7 +135,18 @@ func NewCwtchProfileStorage(db *sql.DB) (*CwtchProfileStorage, error) {
return nil, err return nil, err
} }
return &CwtchProfileStorage{db: db, insertProfileKeyValueStmt: insertProfileKeyValueStmt, selectProfileKeyValueStmt: selectProfileKeyStmt, insertConversationStmt: insertConversationStmt, selectConversationStmt: selectConversationStmt, acceptConversationStmt: acceptConversationStmt, deleteConversationStmt: deleteConversationStmt, setConversationAttributesStmt: setConversationAttributesStmt, channelInsertStmts: map[ChannelID]*sql.Stmt{}, channelGetMessageStmts: map[ChannelID]*sql.Stmt{}}, nil return &CwtchProfileStorage{db: db,
insertProfileKeyValueStmt: insertProfileKeyValueStmt,
selectProfileKeyValueStmt: selectProfileKeyStmt,
fetchAllConversationsStmt: fetchAllConversationsStmt,
insertConversationStmt: insertConversationStmt,
selectConversationStmt: selectConversationStmt,
selectConversationByHandleStmt: selectConversationByHandleStmt,
acceptConversationStmt: acceptConversationStmt,
deleteConversationStmt: deleteConversationStmt,
setConversationAttributesStmt: setConversationAttributesStmt,
channelInsertStmts: map[ChannelID]*sql.Stmt{},
channelGetMessageStmts: map[ChannelID]*sql.Stmt{}}, nil
} }
// StoreProfileKeyValue allows storing of typed Key/Value attribute in the Storage Engine // StoreProfileKeyValue allows storing of typed Key/Value attribute in the Storage Engine
@ -187,9 +214,8 @@ func (cps *CwtchProfileStorage) NewConversation(handle string, attributes model.
return tx.Commit() return tx.Commit()
} }
// GetConversation looks up a particular conversation by handle func (cps *CwtchProfileStorage) GetConversationByHandle(handle string) (*model.Conversation, error) {
func (cps *CwtchProfileStorage) GetConversation(handle string) (*model.Conversation, error) { rows, err := cps.selectConversationByHandleStmt.Query(handle)
rows, err := cps.selectConversationStmt.Query(handle)
if err != nil { if err != nil {
log.Errorf("error executing query: %v", err) log.Errorf("error executing query: %v", err)
return nil, err return nil, err
@ -202,11 +228,10 @@ func (cps *CwtchProfileStorage) GetConversation(handle string) (*model.Conversat
} }
var id int var id int
var rhandle string
var acl []byte var acl []byte
var attributes []byte var attributes []byte
var accepted bool var accepted bool
err = rows.Scan(&id, &rhandle, &attributes, &acl, &accepted) err = rows.Scan(&id, &handle, &attributes, &acl, &accepted)
if err != nil { if err != nil {
log.Errorf("error fetching rows: %v", err) log.Errorf("error fetching rows: %v", err)
rows.Close() rows.Close()
@ -214,12 +239,74 @@ func (cps *CwtchProfileStorage) GetConversation(handle string) (*model.Conversat
} }
rows.Close() rows.Close()
return &model.Conversation{ID: id, Handle: rhandle, ACL: model.DeserializeAccessControlList(acl), Attributes: model.DeserializeAttributes(attributes), Accepted: accepted}, nil return &model.Conversation{ID: id, Handle: handle, ACL: model.DeserializeAccessControlList(acl), Attributes: model.DeserializeAttributes(attributes), Accepted: accepted}, nil
}
func (cps *CwtchProfileStorage) FetchConversations() ([]*model.Conversation, error) {
rows, err := cps.fetchAllConversationsStmt.Query()
if err != nil {
log.Errorf("error executing query: %v", err)
return nil, err
}
var conversations []*model.Conversation
defer rows.Close()
for {
result := rows.Next()
if !result {
return conversations, nil
}
var id int
var handle string
var acl []byte
var attributes []byte
var accepted bool
err = rows.Scan(&id, &handle, &attributes, &acl, &accepted)
if err != nil {
log.Errorf("error fetching rows: %v", err)
rows.Close()
return nil, err
}
conversations = append(conversations, &model.Conversation{ID: id, Handle: handle, ACL: model.DeserializeAccessControlList(acl), Attributes: model.DeserializeAttributes(attributes), Accepted: accepted})
}
}
// GetConversation looks up a particular conversation by handle
func (cps *CwtchProfileStorage) GetConversation(id int) (*model.Conversation, error) {
rows, err := cps.selectConversationStmt.Query(id)
if err != nil {
log.Errorf("error executing query: %v", err)
return nil, err
}
result := rows.Next()
if !result {
return nil, errors.New("no result found")
}
var handle string
var acl []byte
var attributes []byte
var accepted bool
err = rows.Scan(&id, &handle, &attributes, &acl, &accepted)
if err != nil {
log.Errorf("error fetching rows: %v", err)
rows.Close()
return nil, err
}
rows.Close()
return &model.Conversation{ID: id, Handle: handle, ACL: model.DeserializeAccessControlList(acl), Attributes: model.DeserializeAttributes(attributes), Accepted: accepted}, nil
} }
// AcceptConversation sets the accepted status of a conversation to true in the backing datastore // AcceptConversation sets the accepted status of a conversation to true in the backing datastore
func (cps *CwtchProfileStorage) AcceptConversation(handle string) error { func (cps *CwtchProfileStorage) AcceptConversation(id int) error {
_, err := cps.acceptConversationStmt.Exec(handle) _, err := cps.acceptConversationStmt.Exec(id)
if err != nil { if err != nil {
log.Errorf("error executing query: %v", err) log.Errorf("error executing query: %v", err)
return err return err
@ -228,8 +315,8 @@ func (cps *CwtchProfileStorage) AcceptConversation(handle string) error {
} }
// DeleteConversation purges the conversation and any associated message history from the conversation store. // DeleteConversation purges the conversation and any associated message history from the conversation store.
func (cps *CwtchProfileStorage) DeleteConversation(handle string) error { func (cps *CwtchProfileStorage) DeleteConversation(id int) error {
_, err := cps.deleteConversationStmt.Exec(handle) _, err := cps.deleteConversationStmt.Exec(id)
if err != nil { if err != nil {
log.Errorf("error executing query: %v", err) log.Errorf("error executing query: %v", err)
return err return err
@ -237,13 +324,13 @@ func (cps *CwtchProfileStorage) DeleteConversation(handle string) error {
return nil return nil
} }
func (cps *CwtchProfileStorage) SetConversationAttribute(handle string, path attr.ScopedZonedPath, value string) error { func (cps *CwtchProfileStorage) SetConversationAttribute(id int, path attr.ScopedZonedPath, value string) error {
ci, err := cps.GetConversation(handle) ci, err := cps.GetConversation(id)
if err != nil { if err != nil {
return err return err
} }
ci.Attributes[path.ToString()] = value ci.Attributes[path.ToString()] = value
_, err = cps.setConversationAttributesStmt.Exec(ci.Attributes.Serialize(), handle) _, err = cps.setConversationAttributesStmt.Exec(ci.Attributes.Serialize(), id)
if err != nil { if err != nil {
log.Errorf("error executing query: %v", err) log.Errorf("error executing query: %v", err)
return err return err

View File

@ -116,13 +116,14 @@ type CwtchPeer interface {
// New Unified Conversation Interfaces // New Unified Conversation Interfaces
NewContactConversation(handle string, acl model.AccessControl, accepted bool) error NewContactConversation(handle string, acl model.AccessControl, accepted bool) error
FetchConversations() ([]*model.Conversation, error)
FetchConversationInfo(handle string) (*model.Conversation, error) FetchConversationInfo(handle string) (*model.Conversation, error)
AcceptConversation(handle string) error AcceptConversation(conversation int) error
SetConversationAttribute(handle string, path attr.ScopedZonedPath, value string) error SetConversationAttribute(conversation int, path attr.ScopedZonedPath, value string) error
GetConversationAttribute(handle string, path attr.ScopedZonedPath) (string, error) GetConversationAttribute(conversation int, path attr.ScopedZonedPath) (string, error)
DeleteConversation(handle string) error DeleteConversation(conversation int) error
GetChannelMessage(converstion int, channel int, id int) (string, model.Attributes, error) GetChannelMessage(conversation int, channel int, id int) (string, model.Attributes, error)
ShareFile(fileKey string, serializedManifest string) ShareFile(fileKey string, serializedManifest string)
} }

View File

@ -21,6 +21,8 @@ import (
func TestEncryptedStorage(t *testing.T) { func TestEncryptedStorage(t *testing.T) {
log.SetLevel(log.LevelDebug)
os.Mkdir("tordir", 0700) os.Mkdir("tordir", 0700)
dataDir := filepath.Join("tordir", "tor") dataDir := filepath.Join("tordir", "tor")
os.MkdirAll(dataDir, 0700) os.MkdirAll(dataDir, 0700)
@ -49,7 +51,7 @@ func TestEncryptedStorage(t *testing.T) {
fmt.Println("Creating Alice...") fmt.Println("Creating Alice...")
log.SetLevel(log.LevelDebug)
defer acn.Close() defer acn.Close()
acn.WaitTillBootstrapped() acn.WaitTillBootstrapped()
app := app2.NewApp(acn, cwtchDir) app := app2.NewApp(acn, cwtchDir)
@ -65,6 +67,11 @@ func TestEncryptedStorage(t *testing.T) {
// To keep this large test organized, we will break it down into sub tests... // To keep this large test organized, we will break it down into sub tests...
subTestAliceAddAndDeleteBob(t, alice, bob) subTestAliceAddAndDeleteBob(t, alice, bob)
conversations, err := alice.FetchConversations()
if err != nil || len(conversations) != 1 {
t.Fatalf("unexpected issue when fetching all of alices conversations. Expected 1 got : %v %v", conversations, err)
}
alice.PeerWithOnion(bob.GetOnion()) alice.PeerWithOnion(bob.GetOnion())
time.Sleep(time.Second * 30) time.Sleep(time.Second * 30)
@ -72,7 +79,9 @@ func TestEncryptedStorage(t *testing.T) {
alice.SendMessage(bob.GetOnion(), "Hello Bob") alice.SendMessage(bob.GetOnion(), "Hello Bob")
time.Sleep(time.Second * 30) time.Sleep(time.Second * 30)
ci,_ := bob.FetchConversationInfo(alice.GetOnion())
ci, _ := bob.FetchConversationInfo(alice.GetOnion())
body, _, err := bob.GetChannelMessage(ci.ID, 0, 1) body, _, err := bob.GetChannelMessage(ci.ID, 0, 1)
if body != "Hello Bob" || err != nil { if body != "Hello Bob" || err != nil {
t.Fatalf("unexpected message in conversation channel %v %v", body, err) t.Fatalf("unexpected message in conversation channel %v %v", body, err)
@ -100,7 +109,7 @@ func subTestAliceAddAndDeleteBob(t *testing.T, alice peer.CwtchPeer, bob peer.Cw
oldID := bobCI.ID oldID := bobCI.ID
alice.DeleteConversation(bob.GetOnion()) alice.DeleteConversation(oldID)
// Test Basic Fetching // Test Basic Fetching
bobCI, err = alice.FetchConversationInfo(bob.GetOnion()) bobCI, err = alice.FetchConversationInfo(bob.GetOnion())

View File

@ -91,10 +91,10 @@ func TestFileSharing(t *testing.T) {
os.Mkdir(path.Join(cwtchDir, "testing"), 0700) os.Mkdir(path.Join(cwtchDir, "testing"), 0700)
fmt.Println("Creating Alice...") fmt.Println("Creating Alice...")
app.CreatePeer("alice", "asdfasdf") app.CreateTaggedPeer("alice", "asdfasdf", "testing")
fmt.Println("Creating Bob...") fmt.Println("Creating Bob...")
app.CreatePeer("bob", "asdfasdf") app.CreateTaggedPeer("bob", "asdfasdf", "testing")
alice := utils.WaitGetPeer(app, "alice") alice := utils.WaitGetPeer(app, "alice")
bob := utils.WaitGetPeer(app, "bob") bob := utils.WaitGetPeer(app, "bob")
@ -111,7 +111,8 @@ func TestFileSharing(t *testing.T) {
t.Logf("** Waiting for Alice, Bob to connect with onion network... (%v)\n", waitTime) t.Logf("** Waiting for Alice, Bob to connect with onion network... (%v)\n", waitTime)
time.Sleep(waitTime) time.Sleep(waitTime)
bob.AddContact("alice?", alice.GetOnion(), model.AuthApproved) bob.NewContactConversation(alice.GetOnion(),model.DefaultP2PAccessControl(), true)
alice.NewContactConversation(bob.GetOnion(),model.DefaultP2PAccessControl(), true)
alice.PeerWithOnion(bob.GetOnion()) alice.PeerWithOnion(bob.GetOnion())
fmt.Println("Waiting for alice and Bob to peer...") fmt.Println("Waiting for alice and Bob to peer...")
@ -130,23 +131,24 @@ func TestFileSharing(t *testing.T) {
// Wait for the messages to arrive... // Wait for the messages to arrive...
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
for _, message := range bob.GetContact(alice.GetOnion()).Timeline.GetMessages() { message,_,err := bob.GetChannelMessage(1,0, 1)
if err != nil {
t.Fatalf("could not find file sharing message: %v", err)
}
var messageWrapper model.MessageWrapper var messageWrapper model.MessageWrapper
json.Unmarshal([]byte(message.Message), &messageWrapper) json.Unmarshal([]byte(message), &messageWrapper)
if messageWrapper.Overlay == model.OverlayFileSharing { if messageWrapper.Overlay == model.OverlayFileSharing {
var fileMessageOverlay filesharing.OverlayMessage var fileMessageOverlay filesharing.OverlayMessage
err := json.Unmarshal([]byte(messageWrapper.Data), &fileMessageOverlay) err := json.Unmarshal([]byte(messageWrapper.Data), &fileMessageOverlay)
if err == nil { if err == nil {
filesharingFunctionality.DownloadFile(bob, alice.GetOnion(), "cwtch.out.png", "cwtch.out.png.manifest", fmt.Sprintf("%s.%s", fileMessageOverlay.Hash, fileMessageOverlay.Nonce)) filesharingFunctionality.DownloadFile(bob, alice.GetOnion(), "cwtch.out.png", "cwtch.out.png.manifest", fmt.Sprintf("%s.%s", fileMessageOverlay.Hash, fileMessageOverlay.Nonce))
}
} }
fmt.Printf("Found message from Alice: %v", message.Message)
} }
// Wait for the file downloaded event // Wait for the file downloaded event
ev := queueOracle.Next() ev := queueOracle.Next()
if ev.EventType != event.FileDownloaded { if ev.EventType != event.FileDownloaded {