Пример #1
0
// TestGetFilesJSON verifies that /api/files returns proper JSON output
func TestGetFilesJSON(t *testing.T) {
	log.Println("TestGetFilesJSON()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "deadbeef",
		Verified: true,
	}

	// Save mock file
	if !file.Save() {
		t.Fatalf("Failed to save mock file")
	}

	// Load mock file to fetch ID
	file = file.Load(file.InfoHash, "info_hash")
	if file == (data.FileRecord{}) {
		t.Fatalf("Failed to load mock file")
	}

	// Request output JSON from API for this file
	var file2 data.FileRecord
	err := json.Unmarshal(getFilesJSON(file.ID), &file2)
	if err != nil {
		t.Fatalf("Failed to unmarshal result JSON for single file")
	}

	// Verify objects are the same
	if file.ID != file2.ID {
		t.Fatalf("ID, expected %d, got %d", file.ID, file2.ID)
	}

	// Request output JSON from API for all files
	var allFiles []data.FileRecord
	err = json.Unmarshal(getFilesJSON(-1), &allFiles)
	if err != nil {
		t.Fatalf("Failed to unmarshal result JSON for all files")
	}

	// Verify known file is in result set
	found := false
	for _, f := range allFiles {
		if f.ID == file.ID {
			found = true
		}
	}

	if !found {
		t.Fatalf("Expected file not found in all files result set")
	}

	// Delete mock file
	if !file.Delete() {
		t.Fatalf("Failed to delete mock file")
	}
}
Пример #2
0
// TestWhitelistRecord verifies that WhitelistRecord creation, methods, save, load, and delete work properly
func TestWhitelistRecord(t *testing.T) {
	log.Println("TestWhitelistRecord()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock WhitelistRecord
	whitelist := WhitelistRecord{
		Client:   "goat_test",
		Approved: true,
	}

	// Save mock whitelist
	if err := whitelist.Save(); err != nil {
		t.Fatalf("Failed to save mock whitelist: %s", err.Error())
	}

	// Load mock whitelist to fetch ID
	whitelist, err = whitelist.Load(whitelist.Client, "client")
	if whitelist == (WhitelistRecord{}) || err != nil {
		t.Fatalf("Failed to load mock whitelist: %s", err.Error())
	}

	// Delete mock whitelist
	if err := whitelist.Delete(); err != nil {
		t.Fatalf("Failed to delete mock whitelist: %s", err.Error())
	}
}
Пример #3
0
// TestUDPAnnounce verifies that the UDP tracker announce output format is correct
func TestUDPAnnounce(t *testing.T) {
	log.Println("TestUDPAnnounce()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566",
		Verified: true,
	}

	// Save mock file
	if !file.Save() {
		t.Fatalf("Failed to save mock file")
	}

	// Generate fake announce query
	query := url.Values{}
	query.Set("info_hash", "deadbeef")
	query.Set("ip", "127.0.0.1")
	query.Set("port", "5000")
	query.Set("uploaded", "0")
	query.Set("downloaded", "0")
	query.Set("left", "0")
	query.Set("numwant", "50")

	// Create a UDP tracker, trigger an announce
	tracker := UDPTracker{TransID: uint32(1234)}
	res := tracker.Announce(query, file)

	// Decode response
	announce := new(udp.AnnounceResponse)
	err := announce.UnmarshalBinary(res)
	if err != nil {
		t.Fatalf("Failed to decode UDP announce response")
	}
	log.Println(announce)

	// Verify correct action
	if announce.Action != 1 {
		t.Fatalf("Incorrect UDP action, expected 1")
	}

	// Encode response, verify same as before
	announceBuf, err := announce.MarshalBinary()
	if err != nil {
		t.Fatalf("Failed to encode UDP announce response")
	}

	if !bytes.Equal(res, announceBuf) {
		t.Fatalf("Byte slices are not identical")
	}

	// Delete mock file
	if !file.Delete() {
		t.Fatalf("Failed to delete mock file")
	}
}
Пример #4
0
// TestAPIKey verifies that APIKey creation, save, load, and delete work properly
func TestAPIKey(t *testing.T) {
	log.Println("TestAPIKey()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate mock APIKey
	key := APIKey{
		UserID: 1,
		Key:    "deadbeef",
		Salt:   "test",
	}

	// Verify key can be saved
	if !key.Save() {
		t.Fatalf("Failed to save keyLog")
	}

	// Verify key can be loaded using matching key
	key2 := key.Load(key.Key, "key")
	if key2 == (APIKey{}) {
		t.Fatal("Failed to load APIKey")
	}

	// Verify key is the same as previous one
	if key.Salt != key2.Salt {
		t.Fatalf("key.Salt, expected %s, got %s", key.Salt, key2.Salt)
	}

	// Verify key can be deleted
	if !key2.Delete() {
		t.Fatalf("Failed to delete APIKey")
	}
}
Пример #5
0
// TestHTTPRouter verifies that the main HTTP router is working properly
func TestHTTPRouter(t *testing.T) {
	log.Println("TestHTTPRouter()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566303030303030303030303030",
		Verified: true,
	}

	// Save mock file
	if err := file.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Generate mock data.FileRecord
	file2 := data.FileRecord{
		InfoHash: "6265656664656164",
		Verified: true,
	}

	// Save mock file
	if err := file2.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Iterate all HTTP tests
	for _, test := range httpTests {
		// Generate mock HTTP request
		r, err := http.NewRequest("GET", "http://localhost:8080"+test.url, nil)
		r.Header.Set("User-Agent", "goat_test")
		if err != nil {
			t.Fatalf("Failed to create HTTP request")
		}

		// Capture HTTP writer response with recorder
		w := httptest.NewRecorder()

		// Invoke HTTP router
		parseHTTP(w, r)
		log.Println("TEST:", test.url)
		log.Println(w.Body.String())
	}

	// Delete mock file2
	err = file.Delete()
	err2 := file2.Delete()
	if err != nil || err2 != nil {
		t.Fatalf("Failed to delete mock file : %s %s", err.Error(), err2.Error())
	}
}
Пример #6
0
// TestScrapeLog verifies that scrape log creation, save, load, and delete work properly
func TestScrapeLog(t *testing.T) {
	log.Println("TestScrapeLog()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate fake scrape query
	query := url.Values{}
	query.Set("info_hash", "deadbeef000000000000")
	query.Set("ip", "127.0.0.1")

	// Generate struct from query
	scrape := new(ScrapeLog)
	err = scrape.FromValues(query)
	if err != nil {
		t.Fatalf("Failed to create scrape from values: %s", err.Error())
	}

	// Verify proper hex encode of info hash
	if scrape.InfoHash != "6465616462656566303030303030303030303030" {
		t.Fatalf("InfoHash, expected \"6465616462656566303030303030303030303030\", got %s", scrape.InfoHash)
	}

	// Verify same IP
	if scrape.IP != "127.0.0.1" {
		t.Fatalf("IP, expected \"127.0.0.1\", got %s", scrape.IP)
	}

	// Verify scrape can be saved
	if err := scrape.Save(); err != nil {
		t.Fatalf("Failed to save ScrapeLog: %s", err.Error())
	}

	// Verify scrape can be loaded using hex info hash
	scrape2, err := scrape.Load("6465616462656566303030303030303030303030", "info_hash")
	if scrape2 == (ScrapeLog{}) || err != nil {
		t.Fatal("Failed to load ScrapeLog: %s", err.Error())
	}

	// Verify scrape is the same as previous one
	if scrape.InfoHash != scrape2.InfoHash {
		t.Fatalf("scrape.InfoHash, expected %s, got %s", scrape.InfoHash, scrape2.InfoHash)
	}

	// Verify scrape can be deleted
	if err := scrape2.Delete(); err != nil {
		t.Fatalf("Failed to delete ScrapeLog: %s", err.Error())
	}
}
Пример #7
0
// TestPostLogin verifies that /api/login returns proper JSON output
func TestPostLogin(t *testing.T) {
	log.Println("TestPostLogin()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.UserRecord
	mockUser := new(data.UserRecord)
	if err := mockUser.Create("test", "test", 100); err != nil {
		t.Fatalf("Failed to create mock user: %s", err.Error())
	}

	// Save mock user
	if err := mockUser.Save(); err != nil {
		t.Fatalf("Failed to save mock user: %s", err.Error())
	}

	// Load mock user to fetch ID
	user, err := mockUser.Load(mockUser.Username, "username")
	if user == (data.UserRecord{}) || err != nil {
		t.Fatalf("Failed to load mock user: %s", err.Error())
	}

	// Perform login request for this user
	res, err := postLogin(user)
	if err != nil {
		t.Fatalf("Failed to retrieve login JSON: %s", err.Error())
	}
	log.Println(string(res))

	// Unmarshal output JSON
	var key data.JSONAPIKey
	err = json.Unmarshal(res, &key)
	if err != nil {
		t.Fatalf("Failed to unmarshal login JSON: %s", err.Error())
	}

	// Verify same user ID from API
	if user.ID != key.UserID {
		t.Fatalf("Mismatched user IDs, got %d, expected %d", key.UserID, user.ID)
	}

	// Delete mock user
	if err := user.Delete(); err != nil {
		t.Fatalf("Failed to delete mock user: %s", err.Error())
	}
}
Пример #8
0
// TestFileRecord verifies that FileRecord creation, methods, save, load, and delete work properly
func TestFileRecord(t *testing.T) {
	log.Println("TestFileRecord()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock FileRecord
	file := FileRecord{
		InfoHash: "deadbeef",
		Verified: true,
	}

	// Save mock file
	if err := file.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Load mock file to fetch ID
	file, err = file.Load(file.InfoHash, "info_hash")
	if file == (FileRecord{}) || err != nil {
		t.Fatalf("Failed to load mock file: %s", err.Error())
	}

	// Verify completed is functional
	if _, err := file.Completed(); err != nil {
		t.Fatalf("Failed to fetch file completed")
	}

	// Verify seeders is functional
	if _, err := file.Seeders(); err != nil {
		t.Fatalf("Failed to fetch file seeders")
	}

	// Verify leechers is functional
	if _, err := file.Leechers(); err != nil {
		t.Fatalf("Failed to fetch file leechers")
	}

	// Delete mock file
	if err := file.Delete(); err != nil {
		t.Fatalf("Failed to delete mock file: %s", err.Error())
	}
}
Пример #9
0
// TestHTTPAnnounce verifies that the HTTP tracker announce output format is correct
func TestHTTPAnnounce(t *testing.T) {
	log.Println("TestHTTPAnnounce()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566303030303030303030303030",
		Verified: true,
	}

	// Save mock file
	if err := file.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Generate fake announce query
	query := url.Values{}
	query.Set("info_hash", "deadbeef")
	query.Set("ip", "127.0.0.1")
	query.Set("port", "5000")
	query.Set("uploaded", "0")
	query.Set("downloaded", "0")
	query.Set("left", "0")

	// Create a HTTP tracker, trigger an announce
	tracker := HTTPTracker{}
	res := tracker.Announce(query, file)
	log.Println(string(res))

	// Unmarshal response
	announce := AnnounceResponse{}
	if err := bencode.Unmarshal(bytes.NewReader(res), &announce); err != nil {
		t.Fatalf("Failed to unmarshal bencode announce response")
	}

	// Delete mock file
	if err := file.Delete(); err != nil {
		t.Fatalf("Failed to delete mock file: %s", err.Error())
	}
}
Пример #10
0
// TestScrapeLog verifies that scrape log creation, save, load, and delete work properly
func TestScrapeLog(t *testing.T) {
	log.Println("TestScrapeLog()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate fake scrape query
	query := url.Values{}
	query.Set("info_hash", "deadbeef")
	query.Set("ip", "127.0.0.1")

	// Generate struct from query
	scrape := new(ScrapeLog).FromValues(query)

	// Verify proper hex encode of info hash
	if scrape.InfoHash != "6465616462656566" {
		t.Fatalf("InfoHash, expected \"6465616462656566\", got %s", scrape.InfoHash)
	}

	// Verify same IP
	if scrape.IP != "127.0.0.1" {
		t.Fatalf("IP, expected \"127.0.0.1\", got %s", scrape.IP)
	}

	// Verify scrape can be saved
	if !scrape.Save() {
		t.Fatalf("Failed to save ScrapeLog")
	}

	// Verify scrape can be loaded using hex info hash
	scrape2 := scrape.Load("6465616462656566", "info_hash")
	if scrape2 == (ScrapeLog{}) {
		t.Fatal("Failed to load ScrapeLog")
	}

	// Verify scrape is the same as previous one
	if scrape.InfoHash != scrape2.InfoHash {
		t.Fatalf("scrape.InfoHash, expected %s, got %s", scrape.InfoHash, scrape2.InfoHash)
	}

	// Verify scrape can be deleted
	if !scrape2.Delete() {
		t.Fatalf("Failed to delete ScrapeLog")
	}
}
Пример #11
0
// TestFileRecord verifies that FileRecord creation, methods, save, load, and delete work properly
func TestFileRecord(t *testing.T) {
	log.Println("TestFileRecord()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate mock FileRecord
	file := FileRecord{
		InfoHash: "deadbeef",
		Verified: true,
	}

	// Save mock file
	if !file.Save() {
		t.Fatalf("Failed to save mock file")
	}

	// Load mock file to fetch ID
	file = file.Load(file.InfoHash, "info_hash")
	if file == (FileRecord{}) {
		t.Fatalf("Failed to load mock file")
	}

	// Verify positive number of completed on file
	if file.Completed() < 0 {
		t.Fatalf("Failed to fetch file completed")
	}

	// Verify positive number of seeders on file
	if file.Seeders() < 0 {
		t.Fatalf("Failed to fetch file seeders")
	}

	// Verify positive number of leechers on file
	if file.Leechers() < 0 {
		t.Fatalf("Failed to fetch file leechers")
	}

	// Delete mock file
	if !file.Delete() {
		t.Fatalf("Failed to delete mock file")
	}
}
Пример #12
0
// TestUserRecord verifies that user creation, save, load, and delete work properly
func TestUserRecord(t *testing.T) {
	log.Println("TestUserRecord()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Create a user
	user := new(UserRecord)
	if err := user.Create("test", "test", 100); err != nil {
		t.Fatalf("Failed to create UserRecord")
	}

	// Verify proper passkey length
	if len(user.Passkey) != 40 {
		t.Fatalf("user.Passkey is %d characters, expected 40", len(user.Passkey))
	}

	// Verify user can be saved
	if err := user.Save(); err != nil {
		t.Fatalf("Failed to save UserRecord: %s", err.Error())
	}

	// Verify user can be loaded using username
	user2, err := user.Load("test", "username")
	if user2 == (UserRecord{}) || err != nil {
		t.Fatal("Failed to load UserRecord: %s", err.Error())
	}

	// Verify user is the same as previous one
	if user.Passkey != user2.Passkey {
		t.Fatalf("user.Passkey, expected %s, got %s", user.Passkey, user2.Passkey)
	}

	// Verify user can be deleted
	if err := user2.Delete(); err != nil {
		t.Fatalf("Failed to delete UserRecord: %s", err.Error())
	}
}
Пример #13
0
// TestFileUserRecord verifies that FileUserRecord creation, methods, save, load, and delete work properly
func TestFileUserRecord(t *testing.T) {
	log.Println("TestFileUserRecord()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock FileUserRecord
	fileUser := FileUserRecord{
		FileID:     1,
		UserID:     1,
		IP:         "127.0.0.1",
		Active:     true,
		Completed:  true,
		Announced:  10,
		Uploaded:   5000,
		Downloaded: 5000,
		Left:       0,
		Time:       time.Now().Unix(),
	}

	// Save mock fileUser
	if err := fileUser.Save(); err != nil {
		t.Fatalf("Failed to save mock fileUser: %s", err.Error())
	}

	// Load mock fileUser
	fileUser, err = fileUser.Load(fileUser.FileID, fileUser.UserID, fileUser.IP)
	if fileUser == (FileUserRecord{}) || err != nil {
		t.Fatalf("Failed to load mock fileUser: %s", err.Error())
	}

	// Delete mock fileUser
	if err := fileUser.Delete(); err != nil {
		t.Fatalf("Failed to delete mock fileUser: %s", err.Error())
	}
}
Пример #14
0
// TestAPIKey verifies that APIKey creation, save, load, and delete work properly
func TestAPIKey(t *testing.T) {
	log.Println("TestAPIKey()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock APIKey
	key := new(APIKey)
	if err := key.Create(1); err != nil {
		t.Fatalf("Failed to create mock APIKey: %s", err.Error())
	}

	// Verify key can be saved
	if err := key.Save(); err != nil {
		t.Fatalf("Failed to save APIKey: %s", err.Error())
	}

	// Verify key can be loaded using matching pubkey
	key2, err := key.Load(key.Pubkey, "pubkey")
	if err != nil || key2 == (APIKey{}) {
		t.Fatal("Failed to load APIKey: %s", err.Error())
	}

	// Verify key is the same as previous one
	if key.Pubkey != key2.Pubkey {
		t.Fatalf("key.Pubkey, expected %s, got %s", key.Pubkey, key2.Pubkey)
	}

	// Verify key can be deleted
	if err := key2.Delete(); err != nil {
		t.Fatalf("Failed to delete APIKey: %s", err.Error())
	}
}
Пример #15
0
// TestUDPRouter verifies that the main UDP router is working properly
func TestUDPRouter(t *testing.T) {
	log.Println("TestUDPRouter()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566303030303030303030303030",
		Verified: true,
	}

	// Save mock file
	if err := file.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Fake UDP address
	addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("Failed to create fake UDP address")
	}

	// Connect packet with handshake
	connect := udp.Packet{udpInitID, 0, 1234}
	connectBuf, err := connect.MarshalBinary()
	if err != nil {
		t.Fatalf("Failed to create UDP connect packet")
	}

	// Perform connection handshake
	res, err := parseUDP(connectBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Retrieve response, get new connection ID, which will be expected by router
	connRes := new(udp.ConnectResponse)
	err = connRes.UnmarshalBinary(res)
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Create announce request
	announce := udp.AnnounceRequest{
		ConnID:     connRes.ConnID,
		Action:     1,
		TransID:    connRes.TransID,
		InfoHash:   []byte("deadbeef000000000000"),
		PeerID:     []byte("00001111222233334444"),
		Downloaded: 0,
		Left:       0,
		Uploaded:   0,
		IP:         0,
		Key:        1234,
		Port:       5000,
	}

	// Get announce bytes
	announceBuf, err := announce.MarshalBinary()
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Send announce to UDP router
	res, err = parseUDP(announceBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Get UDP announce response
	announceRes := new(udp.AnnounceResponse)
	err = announceRes.UnmarshalBinary(res)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}
	log.Println(announceRes)

	// Create scrape request
	scrape := udp.ScrapeRequest{
		ConnID:     connRes.ConnID,
		Action:     2,
		TransID:    connRes.TransID,
		InfoHashes: [][]byte{[]byte("deadbeef000000000000")},
	}

	// Get scrape bytes
	scrapeBuf, err := scrape.MarshalBinary()
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Send scrape to UDP router
	res, err = parseUDP(scrapeBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Get UDP scrape response
	scrapeRes := new(udp.ScrapeResponse)
	err = scrapeRes.UnmarshalBinary(res)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}
	log.Println(scrapeRes)

	// Delete mock file
	if err := file.Delete(); err != nil {
		t.Fatalf("Failed to delete mock file: %s", err.Error())
	}
}
Пример #16
0
// TestAuthenticator verifies that the Basic and HMAC authenticators work properly
func TestAuthenticator(t *testing.T) {
	log.Println("TestBasicAuthenticator()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock user
	user := new(data.UserRecord)
	if err := user.Create("test", "test", 10); err != nil {
		t.Fatalf("Failed to create mock user: %s", err.Error())
	}

	// Save mock user
	if err := user.Save(); err != nil {
		t.Fatalf("Failed to save mock user: %s", err.Error())
	}

	// Load user to get ID
	user2, err := user.Load("test", "username")
	if err != nil || (user2 == data.UserRecord{}) {
		t.Fatalf("Failed to load mock user: %s", err.Error())
	}

	// Generate mock HTTP request
	r, err := http.NewRequest("POST", "http://localhost:8080/api/login", nil)
	if err != nil {
		t.Fatalf("Failed to generate HTTP request: %s", err.Error())
	}

	headers := map[string][]string{
		"Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte("test:test"))},
	}
	r.Header = headers

	// Capture HTTP response with recorder
	w := httptest.NewRecorder()

	// Perform HTTP Basic authentication
	var apiAuth APIAuthenticator
	apiAuth = new(BasicAuthenticator)

	// Attempt Basic authentication
	clientErr, serverErr := apiAuth.Auth(r)
	if clientErr != nil {
		t.Fatalf("Failed to authenticate: client: %s", clientErr.Error())
	}
	if serverErr != nil {
		t.Fatalf("Failed to authenticate: server: %s", serverErr.Error())
	}

	// Invoke API router
	Router(w, r, user2)

	// Read HTTP response body
	body, err := ioutil.ReadAll(w.Body)
	if err != nil {
		t.Fatalf("Failed to read HTTP response body: %s", err.Error())
	}

	// Unmarshal result JSON
	var login data.JSONAPIKey
	if err := json.Unmarshal(body, &login); err != nil {
		t.Fatalf("Failed to unmarshal login JSON: %s", err.Error())
	}

	// Generate API signature
	nonce := "abcdef"
	method := "GET"
	resource := "/api/status"

	signature, err := apiSignature(login.UserID, nonce, method, resource, login.Secret)
	if err != nil {
		t.Fatalf("Failed to generate API signature: %s", err.Error())
	}
	log.Println("signature:", signature)

	// Generate mock HTTP request
	r, err = http.NewRequest(method, "http://localhost:8080"+resource, nil)
	if err != nil {
		t.Fatalf("Failed to generate HTTP request: %s", err.Error())
	}

	headers = map[string][]string{
		"Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte(login.Pubkey+":"+nonce+"/"+signature))},
	}
	r.Header = headers

	// Capture HTTP response with recorder
	w = httptest.NewRecorder()

	// Attempt HMAC authentication
	apiAuth = new(HMACAuthenticator)
	clientErr, serverErr = apiAuth.Auth(r)
	if clientErr != nil {
		t.Fatalf("Failed to authenticate: client: %s", clientErr.Error())
	}
	if serverErr != nil {
		t.Fatalf("Failed to authenticate: server: %s", serverErr.Error())
	}

	// Invoke API router
	Router(w, r, user2)

	// Read HTTP response body
	body, err = ioutil.ReadAll(w.Body)
	if err != nil {
		t.Fatalf("Failed to read HTTP response body: %s", err.Error())
	}
	log.Println(string(body))

	// Delete mock user
	if err := user2.Delete(); err != nil {
		t.Fatalf("Failed to delete mock user: %s", err.Error())
	}
}
Пример #17
0
// TestAnnounceLog verifies that announce log creation, save, load, and delete work properly
func TestAnnounceLog(t *testing.T) {
	log.Println("TestAnnounceLog()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate fake announce query
	query := url.Values{}
	query.Set("info_hash", "deadbeef")
	query.Set("ip", "127.0.0.1")
	query.Set("port", "5000")
	query.Set("uploaded", "0")
	query.Set("downloaded", "0")
	query.Set("left", "0")

	// Generate struct from query
	announce := new(AnnounceLog).FromValues(query)

	// Verify proper hex encode of info hash
	if announce.InfoHash != "6465616462656566" {
		t.Fatalf("InfoHash, expected \"6465616462656566\", got %s", announce.InfoHash)
	}

	// Verify same IP
	if announce.IP != "127.0.0.1" {
		t.Fatalf("IP, expected \"127.0.0.1\", got %s", announce.IP)
	}

	// Verify proper port integer conversion
	if announce.Port != 5000 {
		t.Fatalf("Port, expected 5000, got %d", announce.Port)
	}

	// Verify proper uploaded integer conversion
	if announce.Uploaded != 0 {
		t.Fatalf("Uploaded, expected 0, got %d", announce.Uploaded)
	}

	// Verify proper downloaded integer conversion
	if announce.Downloaded != 0 {
		t.Fatalf("Downloaded, expected 0, got %d", announce.Downloaded)
	}

	// Verify proper left integer conversion
	if announce.Left != 0 {
		t.Fatalf("Left, expected 0, got %d", announce.Left)
	}

	// Verify announce can be saved
	if !announce.Save() {
		t.Fatalf("Failed to save AnnounceLog")
	}

	// Verify announce can be loaded using hex info hash
	announce2 := announce.Load("6465616462656566", "info_hash")
	if announce2 == (AnnounceLog{}) {
		t.Fatal("Failed to load AnnounceLog")
	}

	// Verify announce is the same as previous one
	if announce.InfoHash != announce2.InfoHash {
		t.Fatalf("announce.InfoHash, expected %s, got %s", announce.InfoHash, announce2.InfoHash)
	}

	// Verify announce can be deleted
	if !announce2.Delete() {
		t.Fatalf("Failed to delete AnnounceLog")
	}
}
Пример #18
0
// Manager is responsible for coordinating the application
func Manager(killChan chan bool, exitChan chan int) {
	// Capture startup time
	common.Static.StartTime = time.Now().Unix()

	// Set up logging flags
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	log.Println("Starting " + App + " " + Version)

	// Grab initial server status
	stat := common.GetServerStatus()
	if stat == (common.ServerStatus{}) {
		log.Println("Could not print get startup status")
	} else {
		log.Printf("%s - %s_%s (%d CPU) [pid: %d]", stat.Hostname, stat.Platform, stat.Architecture, stat.NumCPU, stat.PID)
	}

	// Load configuration
	config := common.LoadConfig()
	if config == (common.Conf{}) {
		panic("Cannot load configuration, panicking")
	}
	common.Static.Config = config

	// Check for sane announce interval (10 minutes or more)
	if common.Static.Config.Interval <= 600 {
		panic("Announce interval must be at least 600 seconds, panicking")
	}

	// Attempt database connection
	if !data.DBPing() {
		panic(fmt.Errorf("cannot connect to database %s; panicking", data.DBName()))
	}
	log.Println("Database", data.DBName(), ": OK")

	// If configured, attempt redis connection
	if common.Static.Config.Redis.Enabled {
		if !data.RedisPing() {
			panic("Cannot connect to Redis, panicking")
		}
		log.Println("Redis : OK")
	}

	// Start cron manager
	go cronManager()

	// Set up graceful shutdown channels
	httpSendChan := make(chan bool)
	httpRecvChan := make(chan bool)
	httpsSendChan := make(chan bool)
	httpsRecvChan := make(chan bool)
	udpSendChan := make(chan bool)
	udpRecvChan := make(chan bool)

	// Set up HTTP(S) route
	http.HandleFunc("/", parseHTTP)

	// Launch listeners as configured
	if common.Static.Config.HTTP {
		go listenHTTP(httpSendChan, httpRecvChan)
		log.Println("HTTP listener launched on port " + strconv.Itoa(common.Static.Config.Port))
	}
	if common.Static.Config.SSL.Enabled {
		go listenHTTPS(httpsSendChan, httpsRecvChan)
		log.Println("HTTPS listener launched on port " + strconv.Itoa(common.Static.Config.SSL.Port))
	}
	if common.Static.Config.UDP {
		go listenUDP(udpSendChan, udpRecvChan)
		log.Println("UDP listener launched on port " + strconv.Itoa(common.Static.Config.Port))
	}

	// Wait for shutdown signal
	for {
		select {
		case <-killChan:
			// Trigger a graceful shutdown
			log.Println("Triggering graceful shutdown, press Ctrl+C again to force halt")

			// If program hangs for more than 10 seconds, trigger a force halt
			go func() {
				<-time.After(10 * time.Second)
				log.Println("Timeout reached, triggering force halt")
				if err := syscall.Kill(os.Getpid(), syscall.SIGTERM); err != nil {
					log.Println(err.Error())
				}
			}()

			// Stop listeners
			if common.Static.Config.HTTP {
				log.Println("Stopping HTTP listener")
				httpSendChan <- true
				<-httpRecvChan
			}
			if common.Static.Config.SSL.Enabled {
				log.Println("Stopping HTTPS listener")
				httpsSendChan <- true
				<-httpsRecvChan
			}
			if common.Static.Config.UDP {
				log.Println("Stopping UDP listener")
				udpSendChan <- true
				<-udpRecvChan
			}

			log.Println("Closing database connection")
			data.DBCloseFunc()

			// Report that program should exit gracefully
			exitChan <- 0
		}
	}
}
Пример #19
0
// TestBasicAuthenticator verifies that BasicAuthenticator.Auth works properly
func TestBasicAuthenticator(t *testing.T) {
	log.Println("TestBasicAuthenticator()")

	// Load config
	config := common.LoadConfig()
	common.Static.Config = config

	// Generate mock user
	user := data.UserRecord{
		Username:     "******",
		Passkey:      "abcdef0123456789",
		TorrentLimit: 10,
	}

	// Save mock user
	if !user.Save() {
		t.Fatalf("Failed to save mock user")
	}

	// Load mock user to fetch ID
	user = user.Load(user.Username, "username")
	if user == (data.UserRecord{}) {
		t.Fatalf("Failed to load mock user")
	}

	// Generate an API key and salt
	pass := "******"
	salt := "test"

	sha := sha1.New()
	sha.Write([]byte(pass + salt))
	hash := fmt.Sprintf("%x", sha.Sum(nil))

	// Generate mock API key
	key := data.APIKey{
		UserID: user.ID,
		Key:    hash,
		Salt:   salt,
	}

	// Save mock API key
	if !key.Save() {
		t.Fatalf("Failed to save mock data.APIKey")
	}

	// Load mock data.APIKey to fetch ID
	key = key.Load(key.Key, "key")
	if key == (data.APIKey{}) {
		t.Fatalf("Failed to load mock data.APIKey")
	}

	// Generate mock HTTP request
	r := http.Request{}
	headers := map[string][]string{
		"Authorization": {"Basic " + base64.URLEncoding.EncodeToString([]byte(user.Username+":"+pass))},
	}
	r.Header = headers

	// Perform authentication request
	auth := new(BasicAuthenticator).Auth(&r)
	if !auth {
		t.Fatalf("Failed to authenticate using BasicAuthenticator")
	}

	// Delete mock user
	if !user.Delete() {
		t.Fatalf("Failed to delete mock user")
	}

	// Delete mock API key
	if !key.Delete() {
		t.Fatalf("Failed to delete mock data.APIKey")
	}
}
Пример #20
0
// TestAnnounceLog verifies that announce log creation, save, load, and delete work properly
func TestAnnounceLog(t *testing.T) {
	log.Println("TestAnnounceLog()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate fake announce query
	query := url.Values{}
	query.Set("info_hash", "deadbeef000000000000")
	query.Set("ip", "127.0.0.1")
	query.Set("port", "5000")
	query.Set("uploaded", "0")
	query.Set("downloaded", "0")
	query.Set("left", "0")

	// Generate struct from query
	announce := new(AnnounceLog)
	err = announce.FromValues(query)
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Verify proper hex encode of info hash
	if announce.InfoHash != "6465616462656566303030303030303030303030" {
		t.Fatalf("InfoHash, expected \"6465616462656566303030303030303030303030\", got %s", announce.InfoHash)
	}

	// Verify same IP
	if announce.IP != "127.0.0.1" {
		t.Fatalf("IP, expected \"127.0.0.1\", got %s", announce.IP)
	}

	// Verify proper port integer conversion
	if announce.Port != 5000 {
		t.Fatalf("Port, expected 5000, got %d", announce.Port)
	}

	// Verify proper uploaded integer conversion
	if announce.Uploaded != 0 {
		t.Fatalf("Uploaded, expected 0, got %d", announce.Uploaded)
	}

	// Verify proper downloaded integer conversion
	if announce.Downloaded != 0 {
		t.Fatalf("Downloaded, expected 0, got %d", announce.Downloaded)
	}

	// Verify proper left integer conversion
	if announce.Left != 0 {
		t.Fatalf("Left, expected 0, got %d", announce.Left)
	}

	// Verify announce can be saved
	if err := announce.Save(); err != nil {
		t.Fatalf("Failed to save AnnounceLog: %s", err.Error())
	}

	// Verify announce can be loaded using hex info hash
	announce2, err := new(AnnounceLog).Load("6465616462656566303030303030303030303030", "info_hash")
	if err != nil || announce2 == (AnnounceLog{}) {
		t.Fatal("Failed to load AnnounceLog: %s", err.Error())
	}

	// Verify announce can be deleted
	if err := announce2.Delete(); err != nil {
		t.Fatalf("Failed to delete AnnounceLog: %s", err.Error())
	}
}
Пример #21
0
// TestGetUsersJSON verifies that /api/users returns proper JSON output
func TestGetUsersJSON(t *testing.T) {
	log.Println("TestGetUsersJSON()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.UserRecord
	mockUser := new(data.UserRecord)
	if err := mockUser.Create("test", "test", 100); err != nil {
		t.Fatalf("Failed to create mock user: %s", err.Error())
	}

	// Save mock user
	if err := mockUser.Save(); err != nil {
		t.Fatalf("Failed to save mock user: %s", err.Error())
	}

	// Load mock user to fetch ID
	user, err := mockUser.Load(mockUser.Username, "username")
	if user == (data.UserRecord{}) || err != nil {
		t.Fatalf("Failed to load mock user: %s", err.Error())
	}

	// Request output JSON from API for this user
	res, err := getUsersJSON(user.ID)
	if err != nil {
		t.Fatalf("Failed to retrieve users JSON: %s", err.Error())
	}

	// Unmarshal output JSON
	var user2 data.UserRecord
	err = json.Unmarshal(res, &user2)
	if err != nil {
		t.Fatalf("Failed to unmarshal result JSON for single user: %s", err.Error())
	}

	// Verify objects are the same
	if user.ID != user2.ID {
		t.Fatalf("ID, expected %d, got %d", user.ID, user2.ID)
	}

	// Request output JSON from API for all users
	res, err = getUsersJSON(-1)
	if err != nil {
		t.Fatalf("Failed to retrieve all users JSON: %s", err.Error())
	}

	// Unmarshal all output JSON
	var allUsers []data.JSONUserRecord
	err = json.Unmarshal(res, &allUsers)
	if err != nil {
		t.Fatalf("Failed to unmarshal result JSON for all users: %s", err.Error())
	}

	// Verify known user is in result set
	found := false
	for _, f := range allUsers {
		if f.ID == user.ID {
			found = true
		}
	}

	if !found {
		t.Fatalf("Expected user not found in all users result set")
	}

	// Delete mock user
	if err := user.Delete(); err != nil {
		t.Fatalf("Failed to delete mock user: %s", err.Error())
	}
}