diff --git a/.travis.yml b/.travis.yml index 00aecc23..64287630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: python +cache: pip python: - "2.7" +os: + - linux + - osx install: - pip install -r requirements.txt script: diff --git a/README.md b/README.md index 23494899..dcc554d1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ZeroNet +# ZeroNet [![Build Status](https://travis-ci.org/HelloZeroNet/ZeroNet.svg?branch=master)](https://travis-ci.org/HelloZeroNet/ZeroNet) Decentralized websites using Bitcoin crypto and the BitTorrent network - http://zeronet.io diff --git a/src/Config.py b/src/Config.py index e3873ee9..1216089d 100644 --- a/src/Config.py +++ b/src/Config.py @@ -8,7 +8,7 @@ class Config(object): def __init__(self, argv): self.version = "0.3.2" - self.rev = 423 + self.rev = 426 self.argv = argv self.action = None self.createParser() diff --git a/src/Test/TestConfig.py b/src/Test/TestConfig.py index d33f0161..24084392 100644 --- a/src/Test/TestConfig.py +++ b/src/Test/TestConfig.py @@ -4,7 +4,7 @@ import Config @pytest.mark.usefixtures("resetSettings") -class TestUser: +class TestConfig: def testParse(self): # Defaults config_test = Config.Config("zeronet.py".split(" ")) diff --git a/src/Test/TestSite.py b/src/Test/TestSite.py index 06e482d2..ffa951e9 100644 --- a/src/Test/TestSite.py +++ b/src/Test/TestSite.py @@ -25,6 +25,8 @@ class TestSite: assert new_site.storage.isFile("index.html") assert new_site.storage.isFile("data/users/content.json") assert new_site.storage.isFile("data/zeroblog.db") + assert new_site.storage.verifyFiles() == [] # No bad files allowed + assert new_site.storage.query("SELECT * FROM keyvalue WHERE key = 'title'").fetchone()["value"] == "MyZeroBlog" # Test re-cloning (updating) @@ -41,6 +43,9 @@ class TestSite: changed_data["title"] = "UpdateTest" new_site.storage.writeJson("data/data.json", changed_data) + # The update should be reflected to database + assert new_site.storage.query("SELECT * FROM keyvalue WHERE key = 'title'").fetchone()["value"] == "UpdateTest" + # Re-clone the site site.clone("159EGD5srUsMP97UpcLy8AtKQbQLK2AbbL") @@ -49,6 +54,5 @@ class TestSite: assert new_site.storage.read("index.html") != "this will be overwritten" # Delete created files - if os.path.isdir("src/Test/testdata/159EGD5srUsMP97UpcLy8AtKQbQLK2AbbL"): - new_site.storage.closeDb() - shutil.rmtree("src/Test/testdata/159EGD5srUsMP97UpcLy8AtKQbQLK2AbbL") + new_site.storage.deleteFiles() + assert not os.path.isdir("src/Test/testdata/159EGD5srUsMP97UpcLy8AtKQbQLK2AbbL") diff --git a/src/Test/TestUser.py b/src/Test/TestUser.py index f3cfe3bf..1fcdd1b7 100644 --- a/src/Test/TestUser.py +++ b/src/Test/TestUser.py @@ -5,14 +5,14 @@ from Crypt import CryptBitcoin @pytest.mark.usefixtures("resetSettings") class TestUser: - def testNewsite(self, user): - user.sites = {} # Reset user data + def testAddress(self, user): assert user.master_address == "15E5rhcAUD69WbiYsYARh4YHJ4sLm2JEyc" address_index = 1458664252141532163166741013621928587528255888800826689784628722366466547364755811L assert user.getAddressAuthIndex("15E5rhcAUD69WbiYsYARh4YHJ4sLm2JEyc") == address_index - # Re-generate privatekey based on address_index - address, address_index, site_data = user.getNewSiteData() + # Re-generate privatekey based on address_index + def testNewSite(self, user): + address, address_index, site_data = user.getNewSiteData() # Create a new random site assert CryptBitcoin.hdPrivatekey(user.master_seed, address_index) == site_data["privatekey"] user.sites = {} # Reset user data @@ -21,3 +21,30 @@ class TestUser: assert user.getSiteData(address)["auth_address"] != address # Re-generate auth_privatekey for site assert user.getSiteData(address)["auth_privatekey"] == site_data["auth_privatekey"] + + def testAuthAddress(self, user): + # Auth address without Cert + auth_address = user.getAuthAddress("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") + assert auth_address == "1MyJgYQjeEkR9QD66nkfJc9zqi9uUy5Lr2" + auth_privatekey = user.getAuthPrivatekey("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") + assert CryptBitcoin.privatekeyToAddress(auth_privatekey) == auth_address + + def testCert(self, user): + cert_auth_address = user.getAuthAddress("1iD5ZQJMNXu43w1qLB8sfdHVKppVMduGz") # Add site to user's registry + # Add cert + user.addCert(cert_auth_address, "zeroid.bit", "faketype", "fakeuser", "fakesign") + user.setCert("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr", "zeroid.bit") + + # By using certificate the auth address should be same as the certificate provider + assert user.getAuthAddress("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") == cert_auth_address + auth_privatekey = user.getAuthPrivatekey("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") + assert CryptBitcoin.privatekeyToAddress(auth_privatekey) == cert_auth_address + + # Test delete site data + assert "1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr" in user.sites + user.deleteSiteData("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") + assert "1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr" not in user.sites + + # Re-create add site should generate normal, unique auth_address + assert not user.getAuthAddress("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") == cert_auth_address + assert user.getAuthAddress("1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr") == "1MyJgYQjeEkR9QD66nkfJc9zqi9uUy5Lr2" diff --git a/src/Test/TestWeb.py b/src/Test/TestWeb.py index 4960ca33..e637fde4 100644 --- a/src/Test/TestWeb.py +++ b/src/Test/TestWeb.py @@ -22,6 +22,7 @@ class WaitForPageLoad(object): @pytest.mark.usefixtures("resetSettings") +@pytest.mark.webtest class TestWeb: def testFileSecurity(self, site_url): assert "Forbidden" in urllib.urlopen("%s/media/./sites.json" % site_url).read() diff --git a/src/Test/conftest.py b/src/Test/conftest.py index 5c222fef..3e7f5b4a 100644 --- a/src/Test/conftest.py +++ b/src/Test/conftest.py @@ -50,6 +50,7 @@ def site(): @pytest.fixture(scope="session") def user(): user = UserManager.user_manager.get() + user.sites = {} # Reset user data return user @pytest.fixture(scope="session") diff --git a/src/Test/coverage.ini b/src/Test/coverage.ini index 5b69dc21..28732e91 100644 --- a/src/Test/coverage.ini +++ b/src/Test/coverage.ini @@ -3,4 +3,15 @@ branch = True omit = src/lib/* src/Test/* + [report] +exclude_lines = + pragma: no cover + + if __name__ == .__main__.: + + if config.debug: + + if config.debug_socket: + + if self.logging: \ No newline at end of file diff --git a/src/Test/pytest.ini b/src/Test/pytest.ini index 6e9e4712..081cf778 100644 --- a/src/Test/pytest.ini +++ b/src/Test/pytest.ini @@ -1,4 +1,5 @@ [pytest] python_files = Test*.py addopts = -rsxX -v - +markers = + webtest: mark a test as a webtest. \ No newline at end of file diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py index 54757cb1..decd05f5 100644 --- a/src/Ui/UiRequest.py +++ b/src/Ui/UiRequest.py @@ -152,7 +152,7 @@ class UiRequest(object): if status == 200 and cacheable_type: # Cache Css, Js, Image files for 10min headers.append(("Cache-Control", "public, max-age=600")) # Cache 10 min - else: # Images, Css, Js + else: headers.append(("Cache-Control", "no-cache, no-store, private, must-revalidate, max-age=0")) # No caching at all headers.append(("Content-Type", content_type)) for extra_header in extra_headers: @@ -327,16 +327,17 @@ class UiRequest(object): from Debug import DebugMedia DebugMedia.merge(file_path) if os.path.isfile(file_path): # File exits - # self.sendHeader(content_type=self.getContentType(file_path)) # ?? Get Exception without this return self.actionFile(file_path) else: # File not exits, try to download site = SiteManager.site_manager.need(address, all_file=False) result = site.needFile(match.group("inner_path"), priority=1) # Wait until file downloads if result: - # self.sendHeader(content_type=self.getContentType(file_path)) return self.actionFile(file_path) else: self.log.debug("File not found: %s" % match.group("inner_path")) + # Site larger than allowed, re-add wrapper nonce to allow reload + if site.settings.get("size", 0) > site.getSizeLimit()*1024*1024: + self.server.wrapper_nonces.append(self.get.get("wrapper_nonce")) return self.error404(match.group("inner_path")) else: # Bad url @@ -460,7 +461,7 @@ class UiRequest(object): # Send file not found error def error404(self, path=""): self.sendHeader(404) - return self.formatError("Not Found", path.encode("utf8")) + return self.formatError("Not Found", path.encode("utf8"), details=False) # Internal server error def error500(self, message=":("): @@ -471,24 +472,30 @@ class UiRequest(object): import sys import gevent - details = {key: val for key, val in self.env.items() if hasattr(val, "endswith") and "COOKIE" not in key} - details["version_zeronet"] = "%s r%s" % (config.version, config.rev) - details["version_python"] = sys.version - details["version_gevent"] = gevent.__version__ - details["plugins"] = PluginManager.plugin_manager.plugin_names - arguments = {key: val for key, val in vars(config.arguments).items() if "password" not in key} - details["arguments"] = arguments - return """ -

%s

-

%s

-

Please report it if you think this an error.

-

Details:

-
%s
- - """ % (title, message, json.dumps(details, indent=4, sort_keys=True)) + if details: + details = {key: val for key, val in self.env.items() if hasattr(val, "endswith") and "COOKIE" not in key} + details["version_zeronet"] = "%s r%s" % (config.version, config.rev) + details["version_python"] = sys.version + details["version_gevent"] = gevent.__version__ + details["plugins"] = PluginManager.plugin_manager.plugin_names + arguments = {key: val for key, val in vars(config.arguments).items() if "password" not in key} + details["arguments"] = arguments + return """ + +

%s

+

%s

+

Please report it if you think this an error.

+

Details:

+
%s
+ """ % (title, message, json.dumps(details, indent=4, sort_keys=True)) + else: + return """ +

%s

+

%s

+ """ % (title, message) # - Reload for eaiser developing - diff --git a/src/Ui/UiWebsocket.py b/src/Ui/UiWebsocket.py index f58bdb53..c419d1b3 100644 --- a/src/Ui/UiWebsocket.py +++ b/src/Ui/UiWebsocket.py @@ -58,7 +58,6 @@ class UiWebsocket(object): try: message = ws.receive() except Exception, err: - self.log.error("WebSocket receive error: %s" % err) return "Bye." # Close connection if message: