diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6f2a748e..9c6f6f3b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ name: tests -on: [push] +on: [push, pull_request] jobs: test: @@ -9,10 +9,10 @@ jobs: strategy: max-parallel: 16 matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 diff --git a/README.md b/README.md index 1b08c868..055aa92d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ZeroNet [![Build Status](https://travis-ci.org/HelloZeroNet/ZeroNet.svg?branch=py3)](https://travis-ci.org/HelloZeroNet/ZeroNet) [![Documentation](https://img.shields.io/badge/docs-faq-brightgreen.svg)](https://zeronet.io/docs/faq/) [![Help](https://img.shields.io/badge/keep_this_project_alive-donate-yellow.svg)](https://zeronet.io/docs/help_zeronet/donate/) ![tests](https://github.com/HelloZeroNet/ZeroNet/workflows/tests/badge.svg) [![Docker Pulls](https://img.shields.io/docker/pulls/nofish/zeronet)](https://hub.docker.com/r/nofish/zeronet) -Decentralized websites using Bitcoin crypto and the BitTorrent network - https://zeronet.io +Decentralized websites using Bitcoin crypto and the BitTorrent network - https://zeronet.io / [onion](http://zeronet34m3r5ngdu54uj57dcafpgdjhxsgq5kla5con4qvcmfzpvhad.onion) ## Why? @@ -83,13 +83,13 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network - https:/ __Tip:__ Start with `./ZeroNet.sh --ui_ip '*' --ui_restrict your.ip.address` to allow remote connections on the web interface. ### Android (arm, arm64, x86) - - minimum Android version supported 16 (JellyBean). - - Google Play Store Link https://play.google.com/store/apps/details?id=in.canews.zeronet - -[Download from Google Play](https://play.google.com/store/apps/details?id=in.canews.zeronet) - + height="80">](https://play.google.com/store/apps/details?id=in.canews.zeronetmobile) + - APK download: https://github.com/canewsin/zeronet_mobile/releases + - XDA Labs: https://labs.xda-developers.com/store/app/in.canews.zeronet + #### Docker There is an official image, built from source at: https://hub.docker.com/r/nofish/zeronet/ diff --git a/plugins/Benchmark/BenchmarkPlugin.py b/plugins/Benchmark/BenchmarkPlugin.py index b47da642..fd6cacf3 100644 --- a/plugins/Benchmark/BenchmarkPlugin.py +++ b/plugins/Benchmark/BenchmarkPlugin.py @@ -146,6 +146,7 @@ class ActionsPlugin: yield "\n" res = {} + res_time_taken = {} multiplers = [] for test in tests: s = time.time() @@ -182,11 +183,35 @@ class ActionsPlugin: yield self.formatResult(time_taken, time_standard) yield "\n" res[key] = "ok" + res_time_taken[key] = time_taken multiplers.append(time_standard / max(time_taken, 0.001)) except Exception as err: res[key] = err yield "Failed!\n! Error: %s\n\n" % Debug.formatException(err) + yield "\n== Result ==\n" + + # Check verification speed + if "testVerify {'lib_verify': 'sslcrypto'}" in res_time_taken: + speed_order = ["sslcrypto_fallback", "sslcrypto", "libsecp256k1"] + time_taken = {} + for lib_verify in speed_order: + time_taken[lib_verify] = res_time_taken["testVerify {'lib_verify': '%s'}" % lib_verify] + + time_taken["sslcrypto_fallback"] *= 10 # fallback benchmark only run 20 times instead of 200 + speedup_sslcrypto = time_taken["sslcrypto_fallback"] / time_taken["sslcrypto"] + speedup_libsecp256k1 = time_taken["sslcrypto_fallback"] / time_taken["libsecp256k1"] + + yield "\n* Verification speedup:\n" + yield " - OpenSSL: %.1fx (reference: 7.0x)\n" % speedup_sslcrypto + yield " - libsecp256k1: %.1fx (reference: 23.8x)\n" % speedup_libsecp256k1 + + if speedup_sslcrypto < 2: + res["Verification speed"] = "error: OpenSSL speedup low: %.1fx" % speedup_sslcrypto + + if speedup_libsecp256k1 < speedup_sslcrypto: + res["Verification speed"] = "error: libsecp256k1 speedup low: %.1fx" % speedup_libsecp256k1 + if not res: yield "! No tests found" if config.action == "test": @@ -194,17 +219,22 @@ class ActionsPlugin: else: num_failed = len([res_key for res_key, res_val in res.items() if res_val != "ok"]) num_success = len([res_key for res_key, res_val in res.items() if res_val == "ok"]) - yield "* Result:\n" + yield "\n* Tests:\n" yield " - Total: %s tests\n" % len(res) yield " - Success: %s tests\n" % num_success yield " - Failed: %s tests\n" % num_failed if any(multiplers): multipler_avg = sum(multiplers) / len(multiplers) multipler_title = self.getMultiplerTitle(multipler_avg) - yield " - Average speed factor: %.2fx (%s)" % (multipler_avg, multipler_title) - if num_failed == 0 and config.action == "test": - sys.exit(1) + yield " - Average speed factor: %.2fx (%s)\n" % (multipler_avg, multipler_title) + # Display errors + for res_key, res_val in res.items(): + if res_val != "ok": + yield " ! %s %s\n" % (res_key, res_val) + + if num_failed != 0 and config.action == "test": + sys.exit(1) def testHttps(self, num_run=1): """ @@ -323,13 +353,14 @@ class ActionsPlugin: valid = "G1GXaDauZ8vX/N9Jn+MRiGm9h+I94zUhDnNYFaqMGuOiBHB+kp4cRPZOL7l1yqK5BHa6J+W97bMjvTXtxzljp6w=" assert sign == valid, "%s != %s" % (sign, valid) - def testVerify(self, num_run=1, lib_verify="btctools"): + def testVerify(self, num_run=1, lib_verify="sslcrypto"): """ Test verification of generated signatures """ from Crypt import CryptBitcoin CryptBitcoin.loadLib(lib_verify, silent=True) + data = "Hello" * 1024 privatekey = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk" address = CryptBitcoin.privatekeyToAddress(privatekey) @@ -340,6 +371,9 @@ class ActionsPlugin: yield "." assert ok, "does not verify from %s" % address + if lib_verify == "sslcrypto": + yield("(%s)" % CryptBitcoin.sslcrypto.ecc.get_backend()) + def testPortCheckers(self): """ Test all active open port checker @@ -361,7 +395,6 @@ class ActionsPlugin: """ from Peer import PeerPortchecker peer_portchecker = PeerPortchecker.PeerPortchecker(None) - s = time.time() announce_func = getattr(peer_portchecker, func_name) res = announce_func(3894) yield res diff --git a/plugins/Benchmark/media/benchmark.html b/plugins/Benchmark/media/benchmark.html index f308d8ba..73571367 100644 --- a/plugins/Benchmark/media/benchmark.html +++ b/plugins/Benchmark/media/benchmark.html @@ -39,7 +39,7 @@ function setState(elem, text) { } } formatted = formatted.replace(/(\! Error:.*)/, "
$1
"); - formatted = formatted.replace(/(\* Result:[^]*)/, "
$1
"); + formatted = formatted.replace(/(\== Result ==[^]*)/, "
$1
"); var is_bottom = document.body.scrollTop + document.body.clientHeight >= document.body.scrollHeight - 5; elem.innerHTML = formatted.trim(); if (is_bottom) diff --git a/plugins/ContentFilter/languages/jp.json b/plugins/ContentFilter/languages/jp.json new file mode 100644 index 00000000..ef586a1a --- /dev/null +++ b/plugins/ContentFilter/languages/jp.json @@ -0,0 +1,6 @@ +{ + "Hide all content from %s?": "%s のコンテンツをすべて隠しますか?", + "Mute": "ミュート", + "Unmute %s?": "%s のミュートを解除しますか?", + "Unmute": "ミュート解除" +} diff --git a/plugins/MergerSite/languages/jp.json b/plugins/MergerSite/languages/jp.json new file mode 100644 index 00000000..7216f268 --- /dev/null +++ b/plugins/MergerSite/languages/jp.json @@ -0,0 +1,5 @@ +{ + "Add %s new site?": "サイト: %s を追加しますか?", + "Added %s new site": "サイト: %s を追加しました", + "Site deleted: %s": "サイト: %s を削除しました" +} diff --git a/plugins/OptionalManager/UiWebsocketPlugin.py b/plugins/OptionalManager/UiWebsocketPlugin.py index 103bbe84..0acc53cf 100644 --- a/plugins/OptionalManager/UiWebsocketPlugin.py +++ b/plugins/OptionalManager/UiWebsocketPlugin.py @@ -139,7 +139,7 @@ class UiWebsocketPlugin(object): wheres = {} wheres_raw = [] if "bigfile" in filter: - wheres["size >"] = 1024 * 1024 * 10 + wheres["size >"] = 1024 * 1024 * 1 if "downloaded" in filter: wheres_raw.append("(is_downloaded = 1 OR is_pinned = 1)") if "pinned" in filter: @@ -166,11 +166,14 @@ class UiWebsocketPlugin(object): row["address"] = address if row["size"] > 1024 * 1024: - has_info = self.addBigfileInfo(row) + has_bigfile_info = self.addBigfileInfo(row) else: - has_info = False + has_bigfile_info = False - if not has_info: + if not has_bigfile_info and "bigfile" in filter: + continue + + if not has_bigfile_info: if row["is_downloaded"]: row["bytes_downloaded"] = row["size"] row["downloaded_percent"] = 100 diff --git a/plugins/OptionalManager/languages/jp.json b/plugins/OptionalManager/languages/jp.json new file mode 100644 index 00000000..af6dc79e --- /dev/null +++ b/plugins/OptionalManager/languages/jp.json @@ -0,0 +1,7 @@ +{ + "Pinned %s files": "%s 件のファイルを固定", + "Removed pin from %s files": "%s 件のファイルの固定を解除", + "You started to help distribute %s.
Directory: %s": "あなたはサイト: %s の配布の援助を開始しました。
ディレクトリ: %s", + "Help distribute all new optional files on site %s": "サイト: %s のすべての新しいオプションファイルの配布を援助しますか?", + "Yes, I want to help!": "はい、やります!" +} diff --git a/plugins/Sidebar/languages/jp.json b/plugins/Sidebar/languages/jp.json index 99b34564..38bbd420 100644 --- a/plugins/Sidebar/languages/jp.json +++ b/plugins/Sidebar/languages/jp.json @@ -1,8 +1,11 @@ { + "Copy to clipboard": "クリップボードにコピー", "Peers": "ピア", "Connected": "接続済み", "Connectable": "利用可能", "Connectable peers": "ピアに接続可能", + "Onion": "Onion", + "Local": "ローカル", "Data transfer": "データ転送", "Received": "受信", @@ -11,6 +14,8 @@ "Sent bytes": "送信バイト数", "Files": "ファイル", + "Browse files": "ファイルを見る", + "Save as .zip": "ZIP形式で保存", "Total": "合計", "Image": "画像", "Other": "その他", @@ -23,18 +28,23 @@ "Optional files": "オプション ファイル", "Downloaded": "ダウンロード済み", + "Help distribute added optional files": "オプションファイルの配布を支援する", + "Auto download big file size limit": "大きなファイルの自動ダウンロードのサイズ制限", + "Download previous files": "以前のファイルのダウンロード", + "Optional files download started": "オプションファイルのダウンロードを開始", + "Optional files downloaded": "オプションファイルのダウンロードが完了しました", "Download and help distribute all files": "ダウンロードしてすべてのファイルの配布を支援する", "Total size": "合計サイズ", "Downloaded files": "ダウンロードされたファイル", "Database": "データベース", "search feeds": "フィードを検索する", - "{feeds} query": "{フィード} お問い合わせ", + "{feeds} query": "{feeds} お問い合わせ", "Reload": "再読込", "Rebuild": "再ビルド", "No database found": "データベースが見つかりません", - "Identity address": "Identity address", + "Identity address": "あなたの識別アドレス", "Change": "編集", "Site control": "サイト管理", @@ -52,15 +62,23 @@ "{} tries": "{} 試行", "+ {num_bad_files} more": "+ {num_bad_files} more", - "This is my site": "This is my site", + "This is my site": "これは私のサイトです", "Site title": "サイトタイトル", "Site description": "サイトの説明", "Save site settings": "サイトの設定を保存する", + "Open site directory": "サイトのディレクトリを開く", "Content publishing": "コンテンツを公開する", + "Add saved private key": "秘密鍵の追加と保存", + "Save": "保存", + "Private key saved.": "秘密鍵が保存されています", + "Private key saved for site signing": "サイトに署名するための秘密鍵を保存", + "Forgot": "わすれる", + "Saved private key removed": "保存された秘密鍵を削除しました", "Choose": "選択", - "Sign": "Sign", + "Sign": "署名", "Publish": "公開する", + "Sign and publish": "署名して公開", "This function is disabled on this proxy": "この機能はこのプロキシで無効になっています", "GeoLite2 City database download error: {}!
Please download manually and unpack to data dir:
{}": "GeoLite2 Cityデータベースのダウンロードエラー: {}!
手動でダウンロードして、フォルダに解凍してください。:
{}", @@ -74,9 +92,13 @@ "Database rebuilt!": "データベースが再構築されました!", "Site updated!": "サイトが更新されました!", "Delete this site": "このサイトを削除する", + "Blacklist": "NG", + "Blacklist this site": "NGリストに入れる", + "Reason": "理由", + "Delete and Blacklist": "削除してNG", "File write error: ": "ファイル書き込みエラー:", "Site settings saved!": "サイト設定が保存されました!", "Enter your private key:": "秘密鍵を入力してください:", - " Signed!": " Signed!", + " Signed!": " 署名しました!", "WebGL not supported": "WebGLはサポートされていません" } diff --git a/plugins/Sidebar/media/Sidebar.css b/plugins/Sidebar/media/Sidebar.css index 8ce16ec7..04ae1ba7 100644 --- a/plugins/Sidebar/media/Sidebar.css +++ b/plugins/Sidebar/media/Sidebar.css @@ -1,5 +1,5 @@ .menu { - font-family: Roboto, 'Segoe UI', 'Helvetica Neue'; + font-family: Roboto, 'Segoe UI', 'Helvetica Neue'; z-index: 999; } .drag-bg { width: 100%; height: 100%; position: fixed; } diff --git a/plugins/Sidebar/media/all.css b/plugins/Sidebar/media/all.css index 056d7e89..9411d32a 100644 --- a/plugins/Sidebar/media/all.css +++ b/plugins/Sidebar/media/all.css @@ -111,7 +111,7 @@ .menu { - font-family: Roboto, 'Segoe UI', 'Helvetica Neue'; + font-family: Roboto, 'Segoe UI', 'Helvetica Neue'; z-index: 999; } .drag-bg { width: 100%; height: 100%; position: fixed; } diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py index f164ce8f..32fd06c5 100644 --- a/plugins/Stats/StatsPlugin.py +++ b/plugins/Stats/StatsPlugin.py @@ -2,7 +2,8 @@ import time import html import os import json -from collections import OrderedDict +import sys +import itertools from Plugin import PluginManager from Config import config @@ -35,40 +36,9 @@ class UiRequestPlugin(object): else: return 0 - # /Stats entry point - @helper.encodeResponse - def actionStats(self): - import gc - import sys - from Ui import UiRequest - from Crypt import CryptConnection + def renderHead(self): import main - - - hpy = None - if self.get.get("size") == "1": # Calc obj size - try: - import guppy - hpy = guppy.hpy() - except: - pass - self.sendHeader() - - if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: - yield "This function is disabled on this proxy" - return - - s = time.time() - - # Style - yield """ - - """ + from Crypt import CryptConnection # Memory yield "rev%s | " % config.rev @@ -99,9 +69,13 @@ class UiRequestPlugin(object): pass yield "
" + def renderConnectionsTable(self): + import main + # Connections yield "Connections (%s, total made: %s, in: %s, out: %s):
" % ( - len(main.file_server.connections), main.file_server.last_connection_id, main.file_server.num_incoming, main.file_server.num_outgoing + len(main.file_server.connections), main.file_server.last_connection_id, + main.file_server.num_incoming, main.file_server.num_outgoing ) yield "" yield "" @@ -140,10 +114,11 @@ class UiRequestPlugin(object): ]) yield "
id type ip open crypt pingbuff bad idle open delay cpu out in last sent
" + def renderTrackers(self): # Trackers yield "

Trackers:
" yield "" - from Site import SiteAnnouncer # importing at the top of the file breaks plugins + from Site import SiteAnnouncer # importing at the top of the file breaks plugins for tracker_address, tracker_stat in sorted(SiteAnnouncer.global_stats.items()): yield self.formatTableRow([ ("%s", tracker_address), @@ -168,12 +143,13 @@ class UiRequestPlugin(object): ]) yield "
address request successive errors last_request
" - # Tor hidden services + def renderTor(self): + import main yield "

Tor hidden services (status: %s):
" % main.file_server.tor_manager.status for site_address, onion in list(main.file_server.tor_manager.site_onions.items()): yield "- %-34s: %s
" % (site_address, onion) - # Db + def renderDbStats(self): yield "

Db:
" for db in Db.opened_dbs: tables = [row["name"] for row in db.execute("SELECT name FROM sqlite_master WHERE type = 'table'").fetchall()] @@ -185,8 +161,7 @@ class UiRequestPlugin(object): time.time() - db.last_query_time, db.db_path, db_size, json.dumps(table_rows, sort_keys=True) ) - - # Sites + def renderSites(self): yield "

Sites:" yield "" yield "" @@ -226,7 +201,7 @@ class UiRequestPlugin(object): yield "
" yield "
address connected peers content.json out in
" - # Big files + def renderBigfiles(self): yield "

Big files:
" for site in list(self.server.sites.values()): if not site.settings.get("has_bigfile"): @@ -250,7 +225,8 @@ class UiRequestPlugin(object): yield "" yield "" - # Cmd stats + def renderRequests(self): + import main yield "
" yield "

Sent commands:
" yield "" @@ -268,9 +244,18 @@ class UiRequestPlugin(object): yield "" yield "
" - # No more if not in debug mode - if not config.debug: - return + def renderMemory(self): + import gc + from Ui import UiRequest + + hpy = None + if self.get.get("size") == "1": # Calc obj size + try: + import guppy + hpy = guppy.hpy() + except Exception: + pass + self.sendHeader() # Object types @@ -371,6 +356,48 @@ class UiRequestPlugin(object): for module_name, module in objs: yield " - %.3fkb: %s %s
" % (self.getObjSize(module, hpy), module_name, html.escape(repr(module))) + # /Stats entry point + @helper.encodeResponse + def actionStats(self): + import gc + + self.sendHeader() + + if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: + yield "This function is disabled on this proxy" + return + + s = time.time() + + # Style + yield """ + + """ + + renderers = [ + self.renderHead(), + self.renderConnectionsTable(), + self.renderTrackers(), + self.renderTor(), + self.renderDbStats(), + self.renderSites(), + self.renderBigfiles(), + self.renderRequests() + + ] + + for part in itertools.chain(*renderers): + yield part + + if config.debug: + for part in self.renderMemory(): + yield part + gc.collect() # Implicit grabage collection yield "Done in %.1f" % (time.time() - s) @@ -457,7 +484,7 @@ class UiRequestPlugin(object): yield "%.1fkb %s... " % ( float(sys.getsizeof(obj)) / 1024, html.escape(str(obj)), html.escape(str(obj)[0:100].ljust(100)) ) - except: + except Exception: continue for ref in refs: yield " [" @@ -485,3 +512,116 @@ class UiRequestPlugin(object): import gc self.sendHeader() yield str(gc.collect()) + + # /About entry point + @helper.encodeResponse + def actionEnv(self): + import main + + self.sendHeader() + + yield """ + + """ + + if "Multiuser" in PluginManager.plugin_manager.plugin_names and not config.multiuser_local: + yield "This function is disabled on this proxy" + return + + yield from main.actions.testEnv(format="html") + + +@PluginManager.registerTo("Actions") +class ActionsPlugin: + def formatTable(self, *rows, format="text"): + if format == "html": + return self.formatTableHtml(*rows) + else: + return self.formatTableText(*rows) + + def formatHead(self, title, format="text"): + if format == "html": + return "

%s

" % title + else: + return "\n* %s\n" % title + + def formatTableHtml(self, *rows): + yield "
" + for row in rows: + yield "" + for col in row: + yield "" % html.escape(str(col)) + yield "" + yield "
%s
" + + def formatTableText(self, *rows): + for row in rows: + yield " " + for col in row: + yield " " + str(col) + yield "\n" + + def testEnv(self, format="text"): + import gevent + import msgpack + import pkg_resources + import importlib + import coincurve + import sqlite3 + from Crypt import CryptBitcoin + + yield "\n" + + yield from self.formatTable( + ["ZeroNet version:", "%s rev%s" % (config.version, config.rev)], + ["Python:", "%s" % sys.version], + ["Platform:", "%s" % sys.platform], + ["Crypt verify lib:", "%s" % CryptBitcoin.lib_verify_best], + ["OpenSSL:", "%s" % CryptBitcoin.sslcrypto.ecc.get_backend()], + ["Libsecp256k1:", "%s" % type(coincurve._libsecp256k1.lib).__name__], + ["SQLite:", "%s, API: %s" % (sqlite3.sqlite_version, sqlite3.version)], + format=format + ) + + + yield self.formatHead("Libraries:") + rows = [] + for lib_name in ["gevent", "greenlet", "msgpack", "base58", "merkletools", "rsa", "socks", "pyasn1", "gevent_ws", "websocket", "maxminddb"]: + try: + module = importlib.import_module(lib_name) + if "__version__" in dir(module): + version = module.__version__ + elif "version" in dir(module): + version = module.version + else: + version = "unknown version" + + if type(version) is tuple: + version = ".".join(map(str, version)) + + rows.append(["- %s:" % lib_name, version, "at " + module.__file__]) + except Exception as err: + rows.append(["! Error importing %s:", repr(err)]) + + """ + try: + yield " - %s
" % html.escape(repr(pkg_resources.get_distribution(lib_name))) + except Exception as err: + yield " ! %s
" % html.escape(repr(err)) + """ + + yield from self.formatTable(*rows, format=format) + + yield self.formatHead("Library config:", format=format) + + yield from self.formatTable( + ["- gevent:", gevent.config.loop.__module__], + ["- msgpack unpacker:", msgpack.Unpacker.__module__], + format=format + ) diff --git a/plugins/Trayicon/languages/fr.json b/plugins/Trayicon/languages/fr.json index ec335318..a6fca769 100644 --- a/plugins/Trayicon/languages/fr.json +++ b/plugins/Trayicon/languages/fr.json @@ -2,7 +2,7 @@ "ZeroNet Twitter": "ZeroNet Twitter", "ZeroNet Reddit": "ZeroNet Reddit", "ZeroNet Github": "ZeroNet Github", - "Report bug/request feature": "Rapport d'erreur/Demanger une fonctionnalité", + "Report bug/request feature": "Rapport d'erreur/Demander une fonctionnalité", "!Open ZeroNet": "!Ouvrir ZeroNet", "Quit": "Quitter", "(active)": "(actif)", diff --git a/plugins/Trayicon/languages/jp.json b/plugins/Trayicon/languages/jp.json new file mode 100644 index 00000000..aa28457b --- /dev/null +++ b/plugins/Trayicon/languages/jp.json @@ -0,0 +1,14 @@ + { + "ZeroNet Twitter": "ZeroNet Twitter", + "ZeroNet Reddit": "ZeroNet Reddit", + "ZeroNet Github": "ZeroNet Github", + "Report bug/request feature": "バグ報告/要望", + "!Open ZeroNet": "!ZeroNetをブラウザで開く", + "Quit": "閉じる", + "(active)": "(アクティブ)", + "(passive)": "(パッシブ)", + "Connections: %s": "接続数: %s", + "Received: %.2f MB | Sent: %.2f MB": "受信: %.2f MB | 送信: %.2f MB", + "Show console window": "コンソールを表示", + "Start ZeroNet when Windows starts": "Windows起動時にZeroNetも起動する" +} diff --git a/plugins/UiConfig/languages/jp.json b/plugins/UiConfig/languages/jp.json new file mode 100644 index 00000000..08184b65 --- /dev/null +++ b/plugins/UiConfig/languages/jp.json @@ -0,0 +1,62 @@ +{ + "ZeroNet config": "ZeroNetの設定", + "Web Interface": "WEBインターフェース", + "Open web browser on ZeroNet startup": "ZeroNet起動時に自動でブラウザーを開く", + + "Network": "ネットワーク", + "Offline mode": "オフラインモード", + "Disable network communication.": "通信を無効化します", + "File server network": "ファイルサーバネットワーク", + "Accept incoming peers using IPv4 or IPv6 address. (default: dual)": "IPv4とIPv6からの受信を許可(既定: 両方)", + "Dual (IPv4 & IPv6)": "両方 (IPv4 & IPv6)", + "File server port": "ファイルサーバのポート", + "Other peers will use this port to reach your served sites. (default: randomize)": "他のピアはこのポートを使用してあなたが所持しているサイトにアクセスします (既定: ランダム)", + "File server external ip": "ファイルサーバの外部IP", + "Detect automatically": "自動検出", + "Your file server is accessible on these ips. (default: detect automatically)": "あなたのファイルサーバへはここで設定したIPでアクセスできます (既定: 自動検出)", + + "Disable: Don't connect to peers on Tor network": "無効: Torネットワーク上のピアに接続しない", + "Enable: Only use Tor for Tor network peers": "有効: Torネットワーク上のピアに対してのみTorを使って接続する", + "Always: Use Tor for every connections to hide your IP address (slower)": "常時: 全ての接続にTorを使いIPを秘匿する(低速)", + + "Disable": "無効", + "Enable": "有効", + "Always": "常時", + + "Use Tor bridges": "Torブリッジを使用", + "Use obfuscated bridge relays to avoid network level Tor block (even slower)": "難読化されたブリッジリレーを使用してネットワークレベルのTorブロックを避ける(超低速)", + + "Discover new peers using these adresses": "ここで設定したアドレスを用いてピアを発見します", + + "Trackers files": "トラッカーファイル", + "Load additional list of torrent trackers dynamically, from a file": "ファイルからトレントラッカーの追加リストを動的に読み込みます", + "Eg.: data/trackers.json": "例: data/trackers.json", + + "Proxy for tracker connections": "トラッカーへの接続に使うプロキシ", + "Custom": "カスタム", + "Custom socks proxy address for trackers": "トラッカーに接続するためのカスタムsocksプロキシのアドレス", + + "Performance": "性能", + "Level of logging to file": "ログレベル", + "Everything": "全て", + "Only important messages": "重要なメッセージのみ", + "Only errors": "エラーのみ", + "Threads for async file system reads": "非同期ファイルシステムの読み込みに使うスレッド", + "Threads for async file system writes": "非同期ファイルシステムの書き込みに使うスレッド", + "Threads for cryptographic functions": "暗号機能に使うスレッド", + "Threads for database operations": "データベースの操作に使うスレッド", + "Sync read": "同期読み取り", + "Sync write": "同期書き込み", + "Sync execution": "同期実行", + "1 thread": "1スレッド", + "2 threads": "2スレッド", + "3 threads": "3スレッド", + "4 threads": "4スレッド", + "5 threads": "5スレッド", + "10 threads": "10スレッド", + + " configuration item value changed": " の項目の値が変更されました", + "Save settings": "設定を保存", + "Some changed settings requires restart": "一部の変更の適用には再起動が必要です。", + "Restart ZeroNet client": "ZeroNetクライアントを再起動" +} diff --git a/plugins/UiFileManager/UiFileManagerPlugin.py b/plugins/UiFileManager/UiFileManagerPlugin.py index 0af5bea9..040e1d22 100644 --- a/plugins/UiFileManager/UiFileManagerPlugin.py +++ b/plugins/UiFileManager/UiFileManagerPlugin.py @@ -73,11 +73,17 @@ class UiFileManagerPlugin(object): return super().error404(path) path_parts = self.parsePath(path) + if not path_parts: + return super().error404(path) + site = self.server.site_manager.get(path_parts["request_address"]) if not site or not site.content_manager.contents.get("content.json"): return super().error404(path) + if path_parts["inner_path"] in site.content_manager.contents.get("content.json").get("files", {}): + return super().error404(path) + self.sendHeader(200) path_redirect = "/list" + re.sub("^/media/", "/", path) self.log.debug("Index.html not found: %s, redirecting to: %s" % (path, path_redirect)) diff --git a/plugins/UiFileManager/languages/jp.json b/plugins/UiFileManager/languages/jp.json new file mode 100644 index 00000000..6d874a61 --- /dev/null +++ b/plugins/UiFileManager/languages/jp.json @@ -0,0 +1,20 @@ +{ + "New file name:": "新しいファイルの名前:", + "Delete": "削除", + "Cancel": "キャンセル", + "Selected:": "選択済み: ", + "Delete and remove optional:": "オプションを削除", + " files": " ファイル", + " (modified)": " (編集済み)", + " (new)": " (新しい)", + " (optional)": " (オプション)", + " (ignored from content.json)": " (content.jsonから無視されます)", + "Total: ": "合計: ", + " dir, ": " のディレクトリ, ", + " file in ": " のファイル, ", + "+ New": "+ 新規作成", + "Edit": "編集", + "View": "閲覧", + "Save": "保存", + "Save: done!": "保存完了!" +} diff --git a/plugins/UiFileManager/media/js/Config.coffee b/plugins/UiFileManager/media/js/Config.coffee new file mode 100644 index 00000000..0e156bef --- /dev/null +++ b/plugins/UiFileManager/media/js/Config.coffee @@ -0,0 +1,15 @@ +window.BINARY_EXTENSIONS = [ + "3dm", "3ds", "3g2", "3gp", "7z", "a", "aac", "adp", "ai", "aif", "aiff", "alz", "ape", "apk", "appimage", "ar", "arj", "asc", "asf", "au", "avi", "bak", + "baml", "bh", "bin", "bk", "bmp", "btif", "bz2", "bzip2", "cab", "caf", "cgm", "class", "cmx", "cpio", "cr2", "cur", "dat", "dcm", "deb", "dex", "djvu", + "dll", "dmg", "dng", "doc", "docm", "docx", "dot", "dotm", "dra", "DS_Store", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ecelp4800", "ecelp7470", + "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "flatpak", "fli", "flv", "fpx", "fst", "fvt", "g3", "gh", "gif", + "gpg", "graffle", "gz", "gzip", "h261", "h263", "h264", "icns", "ico", "ief", "img", "ipa", "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "key", + "ktx", "lha", "lib", "lvp", "lz", "lzh", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mht", "mid", "midi", "mj2", "mka", "mkv", "mmr", "mng", + "mobi", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "msgpack", "mxu", "nef", "npx", "numbers", "nupkg", "o", "oga", "ogg", "ogv", + "otf", "pages", "pbm", "pcx", "pdb", "pdf", "pea", "pgm", "pic", "png", "pnm", "pot", "potm", "potx", "ppa", "ppam", "ppm", "pps", "ppsm", "ppsx", + "ppt", "pptm", "pptx", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "resources", "rgb", "rip", "rlc", "rmf", "rmvb", "rpm", "rtf", + "rz", "s3m", "s7z", "scpt", "sgi", "shar", "sig", "sil", "sketch", "slk", "smv", "snap", "snk", "so", "stl", "sub", "suo", "swf", "tar", "tbz2", "tbz", + "tga", "tgz", "thmx", "tif", "tiff", "tlz", "ttc", "ttf", "txz", "udf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", + "wbmp", "wdp", "weba", "webm", "webp", "whl", "wim", "wm", "wma", "wmv", "wmx", "woff2", "woff", "wrm", "wvx", "xbm", "xif", "xla", "xlam", "xls", + "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "xm", "xmind", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx" +] diff --git a/plugins/UiFileManager/media/js/FileList.coffee b/plugins/UiFileManager/media/js/FileList.coffee index 2e38c2ae..1b5089b0 100644 --- a/plugins/UiFileManager/media/js/FileList.coffee +++ b/plugins/UiFileManager/media/js/FileList.coffee @@ -1,5 +1,3 @@ -BINARY_EXTENSIONS = ["png", "gif", "jpg", "pdf", "doc", "msgpack", "zip", "rar", "gz", "tar", "exe"] - class FileList extends Class constructor: (@site, @inner_path, @is_owner=false) -> @need_update = true @@ -179,7 +177,7 @@ class FileList extends Class ext = item.name.split(".").pop() is_editing = inner_path == Page.file_editor?.inner_path - is_editable = not is_dir and item.size < 1024 * 1024 and ext not in BINARY_EXTENSIONS + is_editable = not is_dir and item.size < 1024 * 1024 and ext not in window.BINARY_EXTENSIONS is_modified = @item_list.isModified(inner_path) is_added = @item_list.isAdded(inner_path) optional_info = @item_list.getOptionalInfo(inner_path) @@ -267,4 +265,4 @@ class FileList extends Class @renderFoot() ]) -window.FileList = FileList \ No newline at end of file +window.FileList = FileList diff --git a/plugins/UiFileManager/media/js/all.js b/plugins/UiFileManager/media/js/all.js index e8f866ff..4f9b2cbd 100644 --- a/plugins/UiFileManager/media/js/all.js +++ b/plugins/UiFileManager/media/js/all.js @@ -1918,6 +1918,15 @@ })); +/* ---- Config.coffee ---- */ + + +(function() { + window.BINARY_EXTENSIONS = ["3dm", "3ds", "3g2", "3gp", "7z", "a", "aac", "adp", "ai", "aif", "aiff", "alz", "ape", "apk", "appimage", "ar", "arj", "asc", "asf", "au", "avi", "bak", "baml", "bh", "bin", "bk", "bmp", "btif", "bz2", "bzip2", "cab", "caf", "cgm", "class", "cmx", "cpio", "cr2", "cur", "dat", "dcm", "deb", "dex", "djvu", "dll", "dmg", "dng", "doc", "docm", "docx", "dot", "dotm", "dra", "DS_Store", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "flatpak", "fli", "flv", "fpx", "fst", "fvt", "g3", "gh", "gif", "gpg", "graffle", "gz", "gzip", "h261", "h263", "h264", "icns", "ico", "ief", "img", "ipa", "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "key", "ktx", "lha", "lib", "lvp", "lz", "lzh", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mht", "mid", "midi", "mj2", "mka", "mkv", "mmr", "mng", "mobi", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "msgpack", "mxu", "nef", "npx", "numbers", "nupkg", "o", "oga", "ogg", "ogv", "otf", "pages", "pbm", "pcx", "pdb", "pdf", "pea", "pgm", "pic", "png", "pnm", "pot", "potm", "potx", "ppa", "ppam", "ppm", "pps", "ppsm", "ppsx", "ppt", "pptm", "pptx", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "resources", "rgb", "rip", "rlc", "rmf", "rmvb", "rpm", "rtf", "rz", "s3m", "s7z", "scpt", "sgi", "shar", "sig", "sil", "sketch", "slk", "smv", "snap", "snk", "so", "stl", "sub", "suo", "swf", "tar", "tbz2", "tbz", "tga", "tgz", "thmx", "tif", "tiff", "tlz", "ttc", "ttf", "txz", "udf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", "webm", "webp", "whl", "wim", "wm", "wma", "wmv", "wmx", "woff2", "woff", "wrm", "wvx", "xbm", "xif", "xla", "xlam", "xls", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "xm", "xmind", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx"]; + +}).call(this); + + /* ---- FileEditor.coffee ---- */ @@ -2187,7 +2196,6 @@ }).call(this); - /* ---- FileItemList.coffee ---- */ @@ -2477,14 +2485,12 @@ (function() { - var BINARY_EXTENSIONS, FileList, + var FileList, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - BINARY_EXTENSIONS = ["png", "gif", "jpg", "pdf", "doc", "msgpack", "zip", "rar", "gz", "tar", "exe"]; - FileList = (function(superClass) { extend(FileList, superClass); @@ -2759,7 +2765,7 @@ is_dir = (ref = item.type) === "dir" || ref === "parent"; ext = item.name.split(".").pop(); is_editing = inner_path === ((ref1 = Page.file_editor) != null ? ref1.inner_path : void 0); - is_editable = !is_dir && item.size < 1024 * 1024 && indexOf.call(BINARY_EXTENSIONS, ext) < 0; + is_editable = !is_dir && item.size < 1024 * 1024 && indexOf.call(window.BINARY_EXTENSIONS, ext) < 0; is_modified = this.item_list.isModified(inner_path); is_added = this.item_list.isAdded(inner_path); optional_info = this.item_list.getOptionalInfo(inner_path); diff --git a/src/Config.py b/src/Config.py index a9e05a6f..f4a230dd 100644 --- a/src/Config.py +++ b/src/Config.py @@ -14,7 +14,7 @@ class Config(object): def __init__(self, argv): self.version = "0.7.2" - self.rev = 4538 + self.rev = 4555 self.argv = argv self.action = None self.test_parser = None diff --git a/src/Crypt/CryptBitcoin.py b/src/Crypt/CryptBitcoin.py index c81999dd..68b2caa2 100644 --- a/src/Crypt/CryptBitcoin.py +++ b/src/Crypt/CryptBitcoin.py @@ -7,6 +7,8 @@ import hashlib from util.Electrum import dbl_format from Config import config +import util.OpensslFindPatch + lib_verify_best = "sslcrypto" from lib import sslcrypto @@ -28,6 +30,8 @@ def loadLib(lib_name, silent=False): ) elif lib_name == "sslcrypto": sslcurve = sslcurve_native + if sslcurve_native == sslcurve_fallback: + logging.warning("SSLCurve fallback loaded instead of native") elif lib_name == "sslcrypto_fallback": sslcurve = sslcurve_fallback diff --git a/src/Debug/Debug.py b/src/Debug/Debug.py index 12f084bc..0ec42615 100644 --- a/src/Debug/Debug.py +++ b/src/Debug/Debug.py @@ -28,7 +28,11 @@ def formatExceptionMessage(err): return "%s: %s" % (err_type, err_message) -python_lib_dir = os.path.dirname(os.__file__) +python_lib_dirs = [path.replace("\\", "/") for path in sys.path if re.sub(r".*[\\/]", "", path) in ("site-packages", "dist-packages")] +python_lib_dirs.append(os.path.dirname(os.__file__).replace("\\", "/")) # TODO: check if returns the correct path for PyPy + +root_dir = os.path.realpath(os.path.dirname(__file__) + "/../../") +root_dir = root_dir.replace("\\", "/") def formatTraceback(items, limit=None, fold_builtin=True): @@ -40,30 +44,63 @@ def formatTraceback(items, limit=None, fold_builtin=True): for path, line in items: i += 1 is_last = i == len(items) - dir_name, file_name = os.path.split(path.replace("\\", "/")) + path = path.replace("\\", "/") - plugin_match = re.match(".*/plugins/(.+)$", dir_name) - if plugin_match: - file_title = "%s/%s" % (plugin_match.group(1), file_name) - is_prev_builtin = False - elif path.startswith(python_lib_dir): - if is_prev_builtin and not is_last and fold_builtin: - if back[-1] != "...": - back.append("...") - continue + if path.startswith("src/gevent/"): + file_title = "/" + path[len("src/gevent/"):] + is_builtin = True + is_skippable_builtin = False + elif path in ("", ""): + file_title = "(importlib)" + is_builtin = True + is_skippable_builtin = True + else: + is_skippable_builtin = False + for base in python_lib_dirs: + if path.startswith(base + "/"): + file_title = path[len(base + "/"):] + module_name, *tail = file_title.split("/") + if module_name.endswith(".py"): + module_name = module_name[:-3] + file_title = "/".join(["<%s>" % module_name] + tail) + is_builtin = True + break else: - file_title = path.replace(python_lib_dir, "").replace("\\", "/").strip("/").replace("site-packages/", "") - is_prev_builtin = True - else: - file_title = file_name - is_prev_builtin = False + is_builtin = False + for base in (root_dir + "/src", root_dir + "/plugins", root_dir): + if path.startswith(base + "/"): + file_title = path[len(base + "/"):] + break + else: + # For unknown paths, do our best to hide absolute path + file_title = path + for needle in ("/zeronet/", "/core/"): + if needle in file_title.lower(): + file_title = "?/" + file_title[file_title.lower().rindex(needle) + len(needle):] - if file_title == prev_file_title: - back.append("%s" % line) + # Path compression: A/AB/ABC/X/Y.py -> ABC/X/Y.py + # E.g.: in 'Db/DbCursor.py' the directory part is unnecessary + if not file_title.startswith("/"): + prev_part = "" + for i, part in enumerate(file_title.split("/") + [""]): + if not part.startswith(prev_part): + break + prev_part = part + file_title = "/".join(file_title.split("/")[i - 1:]) + + if is_skippable_builtin and fold_builtin: + pass + elif is_builtin and is_prev_builtin and not is_last and fold_builtin: + if back[-1] != "...": + back.append("...") else: - back.append("%s line %s" % (file_title, line)) + if file_title == prev_file_title: + back.append("%s" % line) + else: + back.append("%s line %s" % (file_title, line)) prev_file_title = file_title + is_prev_builtin = is_builtin if limit and i >= limit: back.append("...") diff --git a/src/File/FileServer.py b/src/File/FileServer.py index 66cefd39..7114849b 100644 --- a/src/File/FileServer.py +++ b/src/File/FileServer.py @@ -760,10 +760,6 @@ class FileServer(ConnectionServer): self.stream_server.start() except Exception as err: log.error("Error listening on: %s:%s: %s" % (self.ip, self.port, err)) - if "ui_server" in dir(sys.modules["main"]): - log.debug("Stopping UI Server.") - sys.modules["main"].ui_server.stop() - return False if config.debug: # Auto reload FileRequest on change diff --git a/src/Test/TestDebug.py b/src/Test/TestDebug.py new file mode 100644 index 00000000..e3eb20b3 --- /dev/null +++ b/src/Test/TestDebug.py @@ -0,0 +1,52 @@ +from Debug import Debug +import gevent +import os +import re + +import pytest + + +class TestDebug: + @pytest.mark.parametrize("items,expected", [ + (["@/src/A/B/C.py:17"], ["A/B/C.py line 17"]), # basic test + (["@/src/Db/Db.py:17"], ["Db.py line 17"]), # path compression + (["%s:1" % __file__], ["TestDebug.py line 1"]), + (["@/plugins/Chart/ChartDb.py:100"], ["ChartDb.py line 100"]), # plugins + (["@/main.py:17"], ["main.py line 17"]), # root + (["@\\src\\Db\\__init__.py:17"], ["Db/__init__.py line 17"]), # Windows paths + ([":1"], []), # importlib builtins + ([":1"], []), # importlib builtins + (["/home/ivanq/ZeroNet/src/main.py:13"], ["?/src/main.py line 13"]), # best-effort anonymization + (["C:\\ZeroNet\\core\\src\\main.py:13"], ["?/src/main.py line 13"]), + (["/root/main.py:17"], ["/root/main.py line 17"]), + (["{gevent}:13"], ["/__init__.py line 13"]), # modules + (["{os}:13"], [" line 13"]), # python builtin modules + (["src/gevent/event.py:17"], ["/event.py line 17"]), # gevent-overriden __file__ + (["@/src/Db/Db.py:17", "@/src/Db/DbQuery.py:1"], ["Db.py line 17", "DbQuery.py line 1"]), # mutliple args + (["@/src/Db/Db.py:17", "@/src/Db/Db.py:1"], ["Db.py line 17", "1"]), # same file + (["{os}:1", "@/src/Db/Db.py:17"], [" line 1", "Db.py line 17"]), # builtins + (["{gevent}:1"] + ["{os}:3"] * 4 + ["@/src/Db/Db.py:17"], ["/__init__.py line 1", "...", "Db.py line 17"]) + ]) + def testFormatTraceback(self, items, expected): + q_items = [] + for item in items: + file, line = item.rsplit(":", 1) + if file.startswith("@"): + file = Debug.root_dir + file[1:] + file = file.replace("{os}", os.__file__) + file = file.replace("{gevent}", gevent.__file__) + q_items.append((file, int(line))) + assert Debug.formatTraceback(q_items) == expected + + def testFormatException(self): + try: + raise ValueError("Test exception") + except Exception: + assert re.match(r"ValueError: Test exception in TestDebug.py line [0-9]+", Debug.formatException()) + try: + os.path.abspath(1) + except Exception: + assert re.search(r"in TestDebug.py line [0-9]+ > <(posixpath|ntpath)> line ", Debug.formatException()) + + def testFormatStack(self): + assert re.match(r"TestDebug.py line [0-9]+ > <_pytest>/python.py line [0-9]+", Debug.formatStack()) diff --git a/src/Translate/languages/jp.json b/src/Translate/languages/jp.json index 5f858dd6..ff10aee4 100644 --- a/src/Translate/languages/jp.json +++ b/src/Translate/languages/jp.json @@ -8,11 +8,13 @@ "or configure Tor to become a full member of the ZeroNet network.": "または、TorをZeroNetネットワークのメンバーになるように設定してください。", "Select account you want to use in this site:": "このサイトで使用するアカウントを選択:", + "No certificate": "証明書がありません", "currently selected": "現在選択中", "Unique to site": "サイト固有", "Content signing failed": "コンテンツの署名に失敗", "Content publish queued for {0:.0f} seconds.": "コンテンツの公開は{0:.0f}秒のキューに入れられました。", + "Content published to {0}/{1} peers.": "サイトの更新を通知済 {0}/{1} ピア", "Content published to {0} peers.": "{0}ピアに公開されたコンテンツ。", "No peers found, but your content is ready to access.": "ピアは見つかりませんでしたが、コンテンツにアクセスする準備ができました。", "Your network connection is restricted. Please, open {0} port": "ネットワーク接続が制限されています。ポート {0} を開いて、", @@ -43,6 +45,7 @@ "No peers found": "ピアが見つかりません", "Running out of size limit (": "サイズ制限を使い果たしました (", "Set limit to \" + site_info.next_size_limit + \"MB": "制限を \" + site_info.next_size_limit + \"MB に設定", + "Cloning site...": "サイトを複製中…", "Site size limit changed to {0}MB": "サイトのサイズ制限が {0}MB に変更されました", " New version of this page has just released.
Reload to see the modified content.": " このページの新しいバージョンが公開されました。
変更されたコンテンツを見るには再読み込みしてください。", "This site requests permission:": "このサイトは権限を要求しています:", @@ -52,6 +55,12 @@ "Trackers announcing": "トラッカーをお知らせ", "Error": "エラー", "Done": "完了", - "Tracker connection error detected.": "トラッカー接続エラーが検出されました。" + "Tracker connection error detected.": "トラッカー接続エラーが検出されました。", + "Update ZeroNet client to latest version?": "ZeroNetクライアントを最新版に更新しますか?", + "Update": "更新", + "Restart ZeroNet client?": "ZeroNetクライアントを再起動しますか?", + "Restart": "再起動", + "Shut down ZeroNet client?": "ZeroNetクライアントを終了しますか?", + "Shut down": "終了" } diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py index afbe3226..8f00efcb 100644 --- a/src/Ui/UiRequest.py +++ b/src/Ui/UiRequest.py @@ -33,6 +33,9 @@ content_types = { "html": "text/html", "js": "application/javascript", "json": "application/json", + "oga": "audio/ogg", + "ogg": "application/ogg", + "ogv": "video/ogg", "sig": "application/pgp-signature", "txt": "text/plain", "webmanifest": "application/manifest+json", diff --git a/src/Ui/media/Infopanel.coffee b/src/Ui/media/Infopanel.coffee index d728ccbe..3a490364 100644 --- a/src/Ui/media/Infopanel.coffee +++ b/src/Ui/media/Infopanel.coffee @@ -9,9 +9,16 @@ class Infopanel else @open() + unfold: => + @elem.toggleClass("unfolded") + return false + updateEvents: => @elem.off("click") @elem.find(".close").off("click") + @elem.find(".line").off("click") + + @elem.find(".line").on("click", @unfold) if @elem.hasClass("closed") @elem.on "click", => diff --git a/src/Ui/media/Wrapper.coffee b/src/Ui/media/Wrapper.coffee index 43cd033f..1b98855e 100644 --- a/src/Ui/media/Wrapper.coffee +++ b/src/Ui/media/Wrapper.coffee @@ -658,7 +658,7 @@ class Wrapper else @announcer_line = @loading.printLine(status_line) - if status_db.error.length > (status_db.announced.length + status_db.announcing.length) + if status_db.error.length > (status_db.announced.length + status_db.announcing.length) and status_db.announced.length < 3 @loading.showTrackerTorBridge(@server_info) updateProgress: (site_info) -> diff --git a/src/Ui/media/Wrapper.css b/src/Ui/media/Wrapper.css index 4ce0f61f..7c486081 100644 --- a/src/Ui/media/Wrapper.css +++ b/src/Ui/media/Wrapper.css @@ -131,6 +131,7 @@ a { color: black } padding: 4px; border-top-left-radius: 6px; border-bottom-left-radius: 6px; font-size: 10px; opacity: 0; margin-left: 0px; pointer-events: none; transition: all 0.6s; } +.infopanel.unfolded .message .line { overflow: visible; white-space: normal; } .body-sidebar .infopanel { right: 425px; } .body-sidebar .infopanel.closed { right: 0px; } diff --git a/src/Ui/media/all.css b/src/Ui/media/all.css index 8f4b459c..bd54cf34 100644 --- a/src/Ui/media/all.css +++ b/src/Ui/media/all.css @@ -144,6 +144,7 @@ a { color: black } padding: 4px; border-top-left-radius: 6px; border-bottom-left-radius: 6px; font-size: 10px; opacity: 0; margin-left: 0px; pointer-events: none; -webkit-transition: all 0.6s; -moz-transition: all 0.6s; -o-transition: all 0.6s; -ms-transition: all 0.6s; transition: all 0.6s ; } +.infopanel.unfolded .message .line { overflow: visible; white-space: normal; } .body-sidebar .infopanel { right: 425px; } .body-sidebar .infopanel.closed { right: 0px; } diff --git a/src/Ui/media/all.js b/src/Ui/media/all.js index de9ecd79..f5ad947c 100644 --- a/src/Ui/media/all.js +++ b/src/Ui/media/all.js @@ -548,6 +548,7 @@ $.extend( $.easing, this.close = bind(this.close, this); this.hide = bind(this.hide, this); this.updateEvents = bind(this.updateEvents, this); + this.unfold = bind(this.unfold, this); this.show = bind(this.show, this); this.visible = false; } @@ -564,9 +565,16 @@ $.extend( $.easing, } }; + Infopanel.prototype.unfold = function() { + this.elem.toggleClass("unfolded"); + return false; + }; + Infopanel.prototype.updateEvents = function() { this.elem.off("click"); this.elem.find(".close").off("click"); + this.elem.find(".line").off("click"); + this.elem.find(".line").on("click", this.unfold); if (this.elem.hasClass("closed")) { return this.elem.on("click", (function(_this) { return function() { @@ -779,7 +787,6 @@ $.extend( $.easing, }).call(this); - /* ---- Notifications.coffee ---- */ @@ -1910,7 +1917,7 @@ $.extend( $.easing, } else { this.announcer_line = this.loading.printLine(status_line); } - if (status_db.error.length > (status_db.announced.length + status_db.announcing.length)) { + if (status_db.error.length > (status_db.announced.length + status_db.announcing.length) && status_db.announced.length < 3) { return this.loading.showTrackerTorBridge(this.server_info); } }; @@ -2004,6 +2011,7 @@ $.extend( $.easing, }).call(this); + /* ---- WrapperZeroFrame.coffee ---- */ diff --git a/src/Ui/media/img/logo-white.png b/src/Ui/media/img/logo-white.png deleted file mode 100644 index 3f28fb75..00000000 Binary files a/src/Ui/media/img/logo-white.png and /dev/null differ diff --git a/src/Ui/media/img/logo-white.svg b/src/Ui/media/img/logo-white.svg new file mode 100644 index 00000000..a6d85c74 --- /dev/null +++ b/src/Ui/media/img/logo-white.svg @@ -0,0 +1 @@ + diff --git a/src/Ui/template/wrapper.html b/src/Ui/template/wrapper.html index 8e1c6fbc..fe5a3f9c 100644 --- a/src/Ui/template/wrapper.html +++ b/src/Ui/template/wrapper.html @@ -38,7 +38,7 @@ else if (window.opener && window.opener.location.toString()) {
-
+
diff --git a/src/main.py b/src/main.py index ec04c9e3..80ecab2b 100644 --- a/src/main.py +++ b/src/main.py @@ -579,7 +579,7 @@ class Actions(object): func_name = "test" + test_name[0].upper() + test_name[1:] if hasattr(self, func_name): func = getattr(self, func_name) - print("- Running %s" % test_name, end="") + print("- Running test: %s" % test_name, end="") s = time.time() ret = func(*args, **kwargs) if type(ret) is types.GeneratorType: diff --git a/src/util/OpensslFindPatch.py b/src/util/OpensslFindPatch.py index 80987876..0f5d2dc6 100644 --- a/src/util/OpensslFindPatch.py +++ b/src/util/OpensslFindPatch.py @@ -1,11 +1,12 @@ import logging import os import sys -from ctypes.util import find_library -from lib.sslcrypto.openssl import discovery +import ctypes.util from Config import config +find_library_original = ctypes.util.find_library + def getOpensslPath(): if config.openssl_lib_file: @@ -47,11 +48,22 @@ def getOpensslPath(): logging.debug("OpenSSL lib not found in: %s (%s)" % (path, err)) lib_path = ( - find_library('ssl.so') or find_library('ssl') or - find_library('crypto') or find_library('libcrypto') or 'libeay32' + find_library_original('ssl.so') or find_library_original('ssl') or + find_library_original('crypto') or find_library_original('libcrypto') or 'libeay32' ) return lib_path -discovery.discover = getOpensslPath +def patchCtypesOpensslFindLibrary(): + def findLibraryPatched(name): + if name in ("ssl", "crypto", "libeay32"): + lib_path = getOpensslPath() + return lib_path + else: + return find_library_original(name) + + ctypes.util.find_library = findLibraryPatched + + +patchCtypesOpensslFindLibrary() diff --git a/src/util/UpnpPunch.py b/src/util/UpnpPunch.py index 48b497b6..18f4aaee 100644 --- a/src/util/UpnpPunch.py +++ b/src/util/UpnpPunch.py @@ -339,7 +339,7 @@ def _communicate_with_igd(port=15441, success = True break - # Wait another 10sec for competition or any positibe result + # Wait another 10sec for competition or any positive result for _ in range(10): all_done = all([thread.value is not None for thread in threads]) any_succeed = any([thread.value for thread in threads])