2023-03-06 21:06:15 +00:00
package filesharing
import (
"crypto/rand"
app2 "cwtch.im/cwtch/app"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/functionality/filesharing"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/model/attr"
"cwtch.im/cwtch/model/constants"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/protocol/connections"
"encoding/base64"
"errors"
"fmt"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"git.openprivacy.ca/openprivacy/log"
"path/filepath"
// Import SQL Cipher
mrand "math/rand"
"os"
"os/user"
"path"
"runtime"
"runtime/pprof"
"testing"
"time"
_ "github.com/mutecomm/go-sqlcipher/v4"
)
func waitForPeerPeerConnection ( t * testing . T , peera peer . CwtchPeer , peerb peer . CwtchPeer ) {
for {
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 {
peerAName , _ := peera . GetScopedZonedAttribute ( attr . PublicScope , attr . ProfileZone , constants . Name )
peerBName , _ := peerb . GetScopedZonedAttribute ( attr . PublicScope , attr . ProfileZone , constants . Name )
fmt . Printf ( "%v CONNECTED and AUTHED to %v\n" , peerAName , peerBName )
break
}
}
}
func TestFileSharing ( t * testing . T ) {
numGoRoutinesStart := runtime . NumGoroutine ( )
os . RemoveAll ( "cwtch.out.png" )
os . RemoveAll ( "cwtch.out.png.manifest" )
os . RemoveAll ( "storage" )
os . RemoveAll ( "tordir" )
2023-03-06 21:27:45 +00:00
os . RemoveAll ( "./download_dir" )
2023-03-06 21:06:15 +00:00
2023-04-20 19:18:54 +00:00
log . SetLevel ( log . LevelInfo )
2023-03-06 21:06:15 +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...
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 )
}
useCache := os . Getenv ( "TORCACHE" ) == "true"
torDataDir := ""
if useCache {
log . Infof ( "using tor cache" )
torDataDir = filepath . Join ( dataDir , "data-dir-torcache" )
os . MkdirAll ( torDataDir , 0700 )
} else {
log . Infof ( "using clean tor data dir" )
if torDataDir , err = os . MkdirTemp ( dataDir , "data-dir-" ) ; err != nil {
t . Fatalf ( "could not create data dir" )
}
}
tor . NewTorrc ( ) . WithSocksPort ( socksPort ) . WithOnionTrafficOnly ( ) . WithHashedPassword ( base64 . StdEncoding . EncodeToString ( key ) ) . WithControlPort ( controlPort ) . Build ( "tordir/tor/torrc" )
acn , err := tor . NewTorACNWithAuth ( "./tordir" , path . Join ( ".." , "tor" ) , torDataDir , controlPort , tor . HashedPasswordAuthenticator { Password : base64 . StdEncoding . EncodeToString ( key ) } )
if err != nil {
t . Fatalf ( "Could not start Tor: %v" , err )
}
acn . WaitTillBootstrapped ( )
defer acn . Close ( )
2023-04-20 20:32:36 +00:00
app := app2 . NewApp ( acn , "./storage" , app2 . LoadAppSettings ( "./storage" ) )
2023-03-06 21:06:15 +00:00
2023-11-18 19:49:52 +00:00
usr , err := user . Current ( )
if err != nil {
t . Fatalf ( "current user is undefined" )
}
2023-03-06 21:06:15 +00:00
cwtchDir := path . Join ( usr . HomeDir , ".cwtch" )
os . Mkdir ( cwtchDir , 0700 )
os . RemoveAll ( path . Join ( cwtchDir , "testing" ) )
os . Mkdir ( path . Join ( cwtchDir , "testing" ) , 0700 )
t . Logf ( "Creating Alice..." )
app . CreateProfile ( "alice" , "asdfasdf" , true )
t . Logf ( "Creating Bob..." )
app . CreateProfile ( "bob" , "asdfasdf" , true )
t . Logf ( "** Waiting for Alice, Bob..." )
alice := app2 . WaitGetPeer ( app , "alice" )
app . ActivatePeerEngine ( alice . GetOnion ( ) )
2023-09-18 14:46:33 +00:00
app . ConfigureConnections ( alice . GetOnion ( ) , true , true , true )
2023-03-06 21:06:15 +00:00
bob := app2 . WaitGetPeer ( app , "bob" )
app . ActivatePeerEngine ( bob . GetOnion ( ) )
2023-09-18 14:46:33 +00:00
app . ConfigureConnections ( bob . GetOnion ( ) , true , true , true )
2023-03-06 21:06:15 +00:00
alice . AutoHandleEvents ( [ ] event . Type { event . PeerStateChange , event . NewRetValMessageFromPeer } )
bob . AutoHandleEvents ( [ ] event . Type { event . PeerStateChange , event . NewRetValMessageFromPeer } )
// Turn on File Sharing Experiment...
settings := app . ReadSettings ( )
settings . ExperimentsEnabled = true
settings . DownloadPath = "./download_dir"
os . RemoveAll ( path . Join ( settings . DownloadPath , "cwtch.png" ) )
os . RemoveAll ( path . Join ( settings . DownloadPath , "cwtch.png.manifest" ) )
2023-03-06 21:27:45 +00:00
os . MkdirAll ( settings . DownloadPath , 0700 )
2023-03-06 21:06:15 +00:00
settings . Experiments [ constants . FileSharingExperiment ] = true
// Turn Auto Downloading On... (Part of the Image Previews / Profile Images Experiment)
settings . Experiments [ constants . ImagePreviewsExperiment ] = true
app . UpdateSettings ( settings )
t . Logf ( "** Launching Peers..." )
waitTime := time . Duration ( 30 ) * time . Second
t . Logf ( "** Waiting for Alice, Bob to connect with onion network... (%v)\n" , waitTime )
time . Sleep ( waitTime )
bob . NewContactConversation ( alice . GetOnion ( ) , model . DefaultP2PAccessControl ( ) , true )
alice . NewContactConversation ( bob . GetOnion ( ) , model . DefaultP2PAccessControl ( ) , true )
alice . PeerWithOnion ( bob . GetOnion ( ) )
2024-01-02 21:08:59 +00:00
json , err := alice . EnhancedGetConversationAccessControlList ( 1 )
if err != nil {
t . Fatalf ( "Error!: %v" , err )
}
t . Logf ( "alice<->bob ACL: %s" , json )
2023-03-06 21:06:15 +00:00
t . Logf ( "Waiting for alice and Bob to peer..." )
waitForPeerPeerConnection ( t , alice , bob )
2024-01-02 21:08:59 +00:00
err = alice . AcceptConversation ( 1 )
if err != nil {
t . Fatalf ( "Error!: %v" , err )
}
err = bob . AcceptConversation ( 1 )
if err != nil {
t . Fatalf ( "Error!: %v" , err )
}
2023-03-06 21:06:15 +00:00
t . Logf ( "Alice and Bob are Connected!!" )
filesharingFunctionality := filesharing . FunctionalityGate ( )
_ , fileSharingMessage , err := filesharingFunctionality . ShareFile ( "cwtch.png" , alice )
alice . SendMessage ( 1 , fileSharingMessage )
if err != nil {
t . Fatalf ( "Error!: %v" , err )
}
// test that bob can download and verify the file
// The main difference here is that bob doesn't need to do anything...
// testBobDownloadFile(t, bob, filesharingFunctionality, queueOracle)
// Wait for say...
time . Sleep ( 10 * time . Second )
if _ , err := os . Stat ( path . Join ( settings . DownloadPath , "cwtch.png" ) ) ; errors . Is ( err , os . ErrNotExist ) {
// path/to/whatever does not exist
2023-09-19 19:21:53 +00:00
t . Fatalf ( "cwtch.png should have been automatically downloaded..." )
2023-03-06 21:06:15 +00:00
}
app . Shutdown ( )
acn . Close ( )
2023-03-06 21:44:12 +00:00
time . Sleep ( 20 * time . Second )
2023-03-06 21:06:15 +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 )
}
}