2021-09-30 00:57:13 +00:00
package filesharing
import (
"crypto/rand"
2022-07-05 22:31:44 +00:00
utils2 "cwtch.im/cwtch/utils"
2021-12-19 00:15:05 +00:00
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
2022-01-20 21:27:35 +00:00
"io/ioutil"
2021-12-19 00:15:05 +00:00
2021-09-30 00:57:13 +00:00
app2 "cwtch.im/cwtch/app"
"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"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
2021-12-19 00:15:05 +00:00
2021-11-17 22:34:13 +00:00
// Import SQL Cipher
2021-09-30 00:57:13 +00:00
mrand "math/rand"
"os"
"os/user"
"path"
"runtime"
"runtime/pprof"
"testing"
"time"
2021-12-19 00:15:05 +00:00
_ "github.com/mutecomm/go-sqlcipher/v4"
2021-09-30 00:57:13 +00:00
)
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 ) {
2022-04-20 20:10:07 +00:00
numGoRoutinesStart := runtime . NumGoroutine ( )
2021-09-30 00:57:13 +00:00
os . RemoveAll ( "cwtch.out.png" )
os . RemoveAll ( "cwtch.out.png.manifest" )
2022-07-05 22:31:44 +00:00
log . SetLevel ( log . LevelInfo )
2021-09-30 00:57:13 +00:00
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 )
}
2022-01-20 21:27:35 +00:00
torDataDir := ""
2022-01-20 21:38:46 +00:00
if torDataDir , err = ioutil . TempDir ( dataDir , "data-dir-" ) ; err != nil {
2022-01-20 21:27:35 +00:00
t . Fatalf ( "could not create data dir" )
}
2021-09-30 00:57:13 +00:00
tor . NewTorrc ( ) . WithSocksPort ( socksPort ) . WithOnionTrafficOnly ( ) . WithHashedPassword ( base64 . StdEncoding . EncodeToString ( key ) ) . WithControlPort ( controlPort ) . Build ( "tordir/tor/torrc" )
2022-01-20 21:27:35 +00:00
acn , err := tor . NewTorACNWithAuth ( "./tordir" , path . Join ( ".." , ".." , "tor" ) , torDataDir , controlPort , tor . HashedPasswordAuthenticator { Password : base64 . StdEncoding . EncodeToString ( key ) } )
2021-09-30 00:57:13 +00:00
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
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 )
2022-07-05 22:31:44 +00:00
t . Logf ( "Creating Alice..." )
2021-11-10 22:28:52 +00:00
app . CreateTaggedPeer ( "alice" , "asdfasdf" , "testing" )
2021-09-30 00:57:13 +00:00
2022-07-05 22:31:44 +00:00
t . Logf ( "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..." )
2022-07-05 22:31:44 +00:00
alice := app2 . WaitGetPeer ( app , "alice" )
bob := app2 . WaitGetPeer ( app , "bob" )
2021-09-30 00:57:13 +00:00
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 ( ) )
2022-07-05 22:31:44 +00:00
t . Logf ( "Waiting for alice and Bob to peer..." )
2021-09-30 00:57:13 +00:00
waitForPeerPeerConnection ( t , alice , bob )
2022-07-05 22:31:44 +00:00
t . Logf ( "Alice and Bob are Connected!!" )
2021-09-30 00:57:13 +00:00
2021-12-19 00:15:05 +00:00
filesharingFunctionality , _ := filesharing . FunctionalityGate ( map [ string ] bool { constants . FileSharingExperiment : true } )
2021-09-30 00:57:13 +00:00
2022-07-05 22:31:44 +00:00
filekey , fileSharingMessage , err := filesharingFunctionality . ShareFile ( "cwtch.png" , alice )
2022-02-04 00:07:49 +00:00
alice . SendMessage ( 1 , fileSharingMessage )
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 )
2022-07-05 22:31:44 +00:00
// test that bob can download and verify the file
testBobDownloadFile ( t , bob , filesharingFunctionality , queueOracle )
// Test stopping and restarting file shares
t . Logf ( "Stopping File Share" )
alice . StopFileShare ( filekey )
// Allow time for the stop request to filter through Engine
time . Sleep ( time . Second * 5 )
// Restart
t . Logf ( "Restarting File Share" )
filesharingFunctionality . ReShareFiles ( alice )
// run the same download test again...to check that we can actually download the file
testBobDownloadFile ( t , bob , filesharingFunctionality , queueOracle )
queueOracle . Shutdown ( )
app . Shutdown ( )
acn . Close ( )
time . Sleep ( 5 * time . Second )
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 )
}
}
func testBobDownloadFile ( t * testing . T , bob peer . CwtchPeer , filesharingFunctionality * filesharing . Functionality , queueOracle event . Queue ) {
os . RemoveAll ( "cwtch.out.png" )
os . RemoveAll ( "cwtch.out.png.manifest" )
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 {
2022-02-04 00:07:49 +00:00
filesharingFunctionality . DownloadFile ( bob , 1 , "cwtch.out.png" , "cwtch.out.png.manifest" , fmt . Sprintf ( "%s.%s" , fileMessageOverlay . Hash , fileMessageOverlay . Nonce ) , constants . ImagePreviewMaxSizeInBytes )
2021-09-30 00:57:13 +00:00
}
}
// Wait for the file downloaded event
2022-07-05 22:31:44 +00:00
ClientTimeout := utils2 . TimeoutPolicy ( time . Second * 60 )
err = ClientTimeout . ExecuteAction ( func ( ) error {
ev := queueOracle . Next ( )
if ev . EventType != event . FileDownloaded {
t . Fatalf ( "Expected file download event" )
}
2021-09-30 00:57:13 +00:00
2022-07-05 22:31:44 +00:00
manifest , _ := files . CreateManifest ( "cwtch.out.png" )
if hex . EncodeToString ( manifest . RootHash ) != "8f0ed73bbb30db45b6a740b1251cae02945f48e4f991464d5f3607685c45dcd136a325dab2e5f6429ce2b715e602b20b5b16bf7438fb6235fefe912adcedb5fd" {
t . Fatalf ( "file hash does not match expected %x: " , manifest . RootHash )
}
return nil
} )
2021-09-30 00:57:13 +00:00
2022-07-05 22:31:44 +00:00
if err != nil {
t . Fatalf ( "timeout when attempting to download a file" )
2021-09-30 00:57:13 +00:00
}
}