2021-09-30 00:57:13 +00:00
package filesharing
import (
"crypto/rand"
app2 "cwtch.im/cwtch/app"
"cwtch.im/cwtch/app/utils"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/functionality/filesharing"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
2021-10-15 19:38:22 +00:00
"cwtch.im/cwtch/model/constants"
2021-09-30 00:57:13 +00:00
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/protocol/connections"
"cwtch.im/cwtch/protocol/files"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
2021-11-17 22:34:13 +00:00
// Import SQL Cipher
_ "github.com/mutecomm/go-sqlcipher/v4"
2021-09-30 00:57:13 +00:00
mrand "math/rand"
"os"
"os/user"
"path"
"runtime"
"runtime/pprof"
"testing"
"time"
)
func waitForPeerPeerConnection ( t * testing . T , peera peer . CwtchPeer , peerb peer . CwtchPeer ) {
for {
2021-11-17 22:34:13 +00:00
state := peera . GetPeerState ( peerb . GetOnion ( ) )
if state == connections . FAILED {
t . Fatalf ( "%v could not connect to %v" , peera . GetOnion ( ) , peerb . GetOnion ( ) )
}
if state != connections . AUTHENTICATED {
fmt . Printf ( "peer %v waiting connect to peer %v, currently: %v\n" , peera . GetOnion ( ) , peerb . GetOnion ( ) , connections . ConnectionStateName [ state ] )
time . Sleep ( time . Second * 5 )
continue
} else {
2021-12-08 01:02:02 +00:00
peerAName , _ := peera . GetScopedZonedAttribute ( attr . PublicScope , attr . ProfileZone , constants . Name )
peerBName , _ := peerb . GetScopedZonedAttribute ( attr . PublicScope , attr . ProfileZone , constants . Name )
2021-11-17 22:34:13 +00:00
fmt . Printf ( "%v CONNECTED and AUTHED to %v\n" , peerAName , peerBName )
break
2021-09-30 00:57:13 +00:00
}
}
}
func TestFileSharing ( t * testing . T ) {
os . RemoveAll ( "cwtch.out.png" )
os . RemoveAll ( "cwtch.out.png.manifest" )
log . SetLevel ( log . LevelDebug )
os . Mkdir ( "tordir" , 0700 )
dataDir := path . Join ( "tordir" , "tor" )
os . MkdirAll ( dataDir , 0700 )
// we don't need real randomness for the port, just to avoid a possible conflict...
mrand . Seed ( int64 ( time . Now ( ) . Nanosecond ( ) ) )
socksPort := mrand . Intn ( 1000 ) + 9051
controlPort := mrand . Intn ( 1000 ) + 9052
// generate a random password
key := make ( [ ] byte , 64 )
_ , err := rand . Read ( key )
if err != nil {
panic ( err )
}
tor . NewTorrc ( ) . WithSocksPort ( socksPort ) . WithOnionTrafficOnly ( ) . WithHashedPassword ( base64 . StdEncoding . EncodeToString ( key ) ) . WithControlPort ( controlPort ) . Build ( "tordir/tor/torrc" )
acn , err := tor . NewTorACNWithAuth ( "./tordir" , path . Join ( ".." , ".." , "tor" ) , controlPort , tor . HashedPasswordAuthenticator { Password : base64 . StdEncoding . EncodeToString ( key ) } )
if err != nil {
t . Fatalf ( "Could not start Tor: %v" , err )
}
2021-11-19 23:55:01 +00:00
acn . WaitTillBootstrapped ( )
defer acn . Close ( )
2021-09-30 00:57:13 +00:00
2021-11-19 23:55:01 +00:00
numGoRoutinesStart := runtime . NumGoroutine ( )
2021-09-30 00:57:13 +00:00
app := app2 . NewApp ( acn , "./storage" )
usr , _ := user . Current ( )
cwtchDir := path . Join ( usr . HomeDir , ".cwtch" )
os . Mkdir ( cwtchDir , 0700 )
os . RemoveAll ( path . Join ( cwtchDir , "testing" ) )
os . Mkdir ( path . Join ( cwtchDir , "testing" ) , 0700 )
fmt . Println ( "Creating Alice..." )
2021-11-10 22:28:52 +00:00
app . CreateTaggedPeer ( "alice" , "asdfasdf" , "testing" )
2021-09-30 00:57:13 +00:00
fmt . Println ( "Creating Bob..." )
2021-11-10 22:28:52 +00:00
app . CreateTaggedPeer ( "bob" , "asdfasdf" , "testing" )
2021-09-30 00:57:13 +00:00
2021-11-11 00:41:43 +00:00
t . Logf ( "** Waiting for Alice, Bob..." )
2021-09-30 00:57:13 +00:00
alice := utils . WaitGetPeer ( app , "alice" )
bob := utils . WaitGetPeer ( app , "bob" )
alice . AutoHandleEvents ( [ ] event . Type { event . PeerStateChange , event . NewRetValMessageFromPeer } )
bob . AutoHandleEvents ( [ ] event . Type { event . PeerStateChange , event . NewRetValMessageFromPeer , event . ManifestReceived } )
queueOracle := event . NewQueue ( )
app . GetEventBus ( bob . GetOnion ( ) ) . Subscribe ( event . FileDownloaded , queueOracle )
2021-11-11 00:41:43 +00:00
t . Logf ( "** Launching Peers..." )
2021-09-30 00:57:13 +00:00
app . LaunchPeers ( )
waitTime := time . Duration ( 30 ) * time . Second
t . Logf ( "** Waiting for Alice, Bob to connect with onion network... (%v)\n" , waitTime )
time . Sleep ( waitTime )
2021-11-11 00:41:43 +00:00
bob . NewContactConversation ( alice . GetOnion ( ) , model . DefaultP2PAccessControl ( ) , true )
alice . NewContactConversation ( bob . GetOnion ( ) , model . DefaultP2PAccessControl ( ) , true )
2021-09-30 00:57:13 +00:00
alice . PeerWithOnion ( bob . GetOnion ( ) )
fmt . Println ( "Waiting for alice and Bob to peer..." )
waitForPeerPeerConnection ( t , alice , bob )
fmt . Println ( "Alice and Bob are Connected!!" )
filesharingFunctionality , _ := filesharing . FunctionalityGate ( map [ string ] bool { "filesharing" : true } )
2021-11-11 00:41:43 +00:00
err = filesharingFunctionality . ShareFile ( "cwtch.png" , alice , 1 )
2021-09-30 00:57:13 +00:00
if err != nil {
t . Fatalf ( "Error!: %v" , err )
}
// Wait for the messages to arrive...
time . Sleep ( time . Second * 10 )
2021-11-11 00:41:43 +00:00
message , _ , err := bob . GetChannelMessage ( 1 , 0 , 1 )
if err != nil {
t . Fatalf ( "could not find file sharing message: %v" , err )
}
2021-09-30 00:57:13 +00:00
2021-11-10 22:28:52 +00:00
var messageWrapper model . MessageWrapper
json . Unmarshal ( [ ] byte ( message ) , & messageWrapper )
2021-09-30 00:57:13 +00:00
2021-11-10 22:28:52 +00:00
if messageWrapper . Overlay == model . OverlayFileSharing {
var fileMessageOverlay filesharing . OverlayMessage
err := json . Unmarshal ( [ ] byte ( messageWrapper . Data ) , & fileMessageOverlay )
2021-09-30 00:57:13 +00:00
2021-11-10 22:28:52 +00:00
if err == nil {
2021-11-17 22:34:13 +00:00
filesharingFunctionality . DownloadFile ( bob , 1 , "cwtch.out.png" , "cwtch.out.png.manifest" , fmt . Sprintf ( "%s.%s" , fileMessageOverlay . Hash , fileMessageOverlay . Nonce ) )
2021-09-30 00:57:13 +00:00
}
}
// Wait for the file downloaded event
ev := queueOracle . Next ( )
if ev . EventType != event . FileDownloaded {
t . Fatalf ( "Expected file download event" )
}
2021-11-17 23:59:52 +00:00
manifest , _ := files . CreateManifest ( "cwtch.out.png" )
2021-09-30 00:57:13 +00:00
if hex . EncodeToString ( manifest . RootHash ) != "8f0ed73bbb30db45b6a740b1251cae02945f48e4f991464d5f3607685c45dcd136a325dab2e5f6429ce2b715e602b20b5b16bf7438fb6235fefe912adcedb5fd" {
t . Fatalf ( "file hash does not match expected %x: " , manifest . RootHash )
}
queueOracle . Shutdown ( )
app . Shutdown ( )
2021-11-19 23:55:01 +00:00
time . Sleep ( 3 * time . Second )
2021-09-30 00:57:13 +00:00
numGoRoutinesPostACN := runtime . NumGoroutine ( )
// Printing out the current goroutines
// Very useful if we are leaking any.
pprof . Lookup ( "goroutine" ) . WriteTo ( os . Stdout , 1 )
if numGoRoutinesStart != numGoRoutinesPostACN {
t . Errorf ( "Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, leak detected!" , numGoRoutinesStart , numGoRoutinesPostACN )
}
}