Merge branch 'HelloZeroNet-py3' into massive-rework

# Conflicts:
#	src/File/FileServer.py
This commit is contained in:
Vadim Ushakov 2021-11-06 22:39:47 +07:00
commit 545fe9442c
38 changed files with 588 additions and 120 deletions

View file

@ -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

View file

@ -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,12 +83,12 @@ 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
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
- minimum Android version supported 16 (JellyBean)
- [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Download from Google Play"
height="80">](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/

View file

@ -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

View file

@ -39,7 +39,7 @@ function setState(elem, text) {
}
}
formatted = formatted.replace(/(\! Error:.*)/, "<div class='test error'>$1</div>");
formatted = formatted.replace(/(\* Result:[^]*)/, "<div class='test summary'>$1</div>");
formatted = formatted.replace(/(\== Result ==[^]*)/, "<div class='test summary'>$1</div>");
var is_bottom = document.body.scrollTop + document.body.clientHeight >= document.body.scrollHeight - 5;
elem.innerHTML = formatted.trim();
if (is_bottom)

View file

@ -0,0 +1,6 @@
{
"Hide all content from <b>%s</b>?": "<b>%s</b> のコンテンツをすべて隠しますか?",
"Mute": "ミュート",
"Unmute <b>%s</b>?": "<b>%s</b> のミュートを解除しますか?",
"Unmute": "ミュート解除"
}

View file

@ -0,0 +1,5 @@
{
"Add <b>%s</b> new site?": "サイト: <b>%s</b> を追加しますか?",
"Added <b>%s</b> new site": "サイト: <b>%s</b> を追加しました",
"Site deleted: <b>%s</b>": "サイト: <b>%s</b> を削除しました"
}

View file

@ -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

View file

@ -0,0 +1,7 @@
{
"Pinned %s files": "%s 件のファイルを固定",
"Removed pin from %s files": "%s 件のファイルの固定を解除",
"You started to help distribute <b>%s</b>.<br><small>Directory: %s</small>": "あなたはサイト: <b>%s</b> の配布の援助を開始しました。<br><small>ディレクトリ: %s</small>",
"Help distribute all new optional files on site <b>%s</b>": "サイト: <b>%s</b> のすべての新しいオプションファイルの配布を援助しますか?",
"Yes, I want to help!": "はい、やります!"
}

View file

@ -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: {}!<br>Please download manually and unpack to data dir:<br>{}": "GeoLite2 Cityデータベースのダウンロードエラー: {}!<br>手動でダウンロードして、フォルダに解凍してください。:<br>{}",
@ -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はサポートされていません"
}

View file

@ -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; }

View file

@ -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; }

View file

@ -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 """
<style>
* { font-family: monospace }
table td, table th { text-align: right; padding: 0px 10px }
.connections td { white-space: nowrap }
.serving-False { opacity: 0.3 }
</style>
"""
from Crypt import CryptConnection
# Memory
yield "rev%s | " % config.rev
@ -99,9 +69,13 @@ class UiRequestPlugin(object):
pass
yield "<br>"
def renderConnectionsTable(self):
import main
# Connections
yield "<b>Connections</b> (%s, total made: %s, in: %s, out: %s):<br>" % (
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 "<table class='connections'><tr> <th>id</th> <th>type</th> <th>ip</th> <th>open</th> <th>crypt</th> <th>ping</th>"
yield "<th>buff</th> <th>bad</th> <th>idle</th> <th>open</th> <th>delay</th> <th>cpu</th> <th>out</th> <th>in</th> <th>last sent</th>"
@ -140,6 +114,7 @@ class UiRequestPlugin(object):
])
yield "</table>"
def renderTrackers(self):
# Trackers
yield "<br><br><b>Trackers:</b><br>"
yield "<table class='trackers'><tr> <th>address</th> <th>request</th> <th>successive errors</th> <th>last_request</th></tr>"
@ -168,12 +143,13 @@ class UiRequestPlugin(object):
])
yield "</table>"
# Tor hidden services
def renderTor(self):
import main
yield "<br><br><b>Tor hidden services (status: %s):</b><br>" % main.file_server.tor_manager.status
for site_address, onion in list(main.file_server.tor_manager.site_onions.items()):
yield "- %-34s: %s<br>" % (site_address, onion)
# Db
def renderDbStats(self):
yield "<br><br><b>Db</b>:<br>"
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 "<br><br><b>Sites</b>:"
yield "<table>"
yield "<tr><th>address</th> <th>connected</th> <th title='connected/good/total'>peers</th> <th>content.json</th> <th>out</th> <th>in</th> </tr>"
@ -226,7 +201,7 @@ class UiRequestPlugin(object):
yield "<br></td></tr>"
yield "</table>"
# Big files
def renderBigfiles(self):
yield "<br><br><b>Big files</b>:<br>"
for site in list(self.server.sites.values()):
if not site.settings.get("has_bigfile"):
@ -250,7 +225,8 @@ class UiRequestPlugin(object):
yield "</table>"
yield "</div>"
# Cmd stats
def renderRequests(self):
import main
yield "<div style='float: left'>"
yield "<br><br><b>Sent commands</b>:<br>"
yield "<table>"
@ -268,9 +244,18 @@ class UiRequestPlugin(object):
yield "</div>"
yield "<div style='clear: both'></div>"
# 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<br>" % (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 """
<style>
* { font-family: monospace }
table td, table th { text-align: right; padding: 0px 10px }
.connections td { white-space: nowrap }
.serving-False { opacity: 0.3 }
</style>
"""
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 <span title=\"%s\">%s</span>... " % (
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 """
<style>
* { font-family: monospace; white-space: pre; }
h2 { font-size: 100%; margin-bottom: 0px; }
small { opacity: 0.5; }
table { border-collapse: collapse; }
td { padding-right: 10px; }
</style>
"""
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 "<h2>%s</h2>" % title
else:
return "\n* %s\n" % title
def formatTableHtml(self, *rows):
yield "<table>"
for row in rows:
yield "<tr>"
for col in row:
yield "<td>%s</td>" % html.escape(str(col))
yield "</tr>"
yield "</table>"
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<br>" % html.escape(repr(pkg_resources.get_distribution(lib_name)))
except Exception as err:
yield " ! %s<br>" % 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
)

View file

@ -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)",

View file

@ -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も起動する"
}

View file

@ -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クライアントを再起動"
}

View file

@ -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))

View file

@ -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!": "保存完了!"
}

View file

@ -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"
]

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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 path.startswith("src/gevent/"):
file_title = "<gevent>/" + path[len("src/gevent/"):]
is_builtin = True
is_skippable_builtin = False
elif path in ("<frozen importlib._bootstrap>", "<frozen importlib._bootstrap_external>"):
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:
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):]
# 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("...")
continue
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
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("...")

View file

@ -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

52
src/Test/TestDebug.py Normal file
View file

@ -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
(["<frozen importlib._bootstrap>:1"], []), # importlib builtins
(["<frozen importlib._bootstrap_external>: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"], ["<gevent>/__init__.py line 13"]), # modules
(["{os}:13"], ["<os> line 13"]), # python builtin modules
(["src/gevent/event.py:17"], ["<gevent>/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"], ["<os> line 1", "Db.py line 17"]), # builtins
(["{gevent}:1"] + ["{os}:3"] * 4 + ["@/src/Db/Db.py:17"], ["<gevent>/__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())

View file

@ -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 <b>{0}</b> port": "ネットワーク接続が制限されています。ポート <b>{0}</b> を開いて、",
@ -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.<br>Reload to see the modified content.": " このページの新しいバージョンが公開されました。<br>変更されたコンテンツを見るには再読み込みしてください。",
"This site requests permission:": "このサイトは権限を要求しています:",
@ -52,6 +55,12 @@
"Trackers announcing": "トラッカーをお知らせ",
"Error": "エラー",
"Done": "完了",
"Tracker connection error detected.": "トラッカー接続エラーが検出されました。"
"Tracker connection error detected.": "トラッカー接続エラーが検出されました。",
"Update <b>ZeroNet client</b> to latest version?": "<b>ZeroNetクライアント</b>を最新版に更新しますか?",
"Update": "更新",
"Restart <b>ZeroNet client</b>?": "ZeroNetクライアントを再起動しますか",
"Restart": "再起動",
"Shut down <b>ZeroNet client</b>?": "<b>ZeroNetクライアント</b>を終了しますか?",
"Shut down": "終了"
}

View file

@ -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",

View file

@ -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", =>

View file

@ -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) ->

View file

@ -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; }

View file

@ -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; }

View file

@ -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 ---- */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg version="1.1" viewBox="0 0 2050 2050" xmlns="http://www.w3.org/2000/svg"><g fill="white"><path d="m299 1211v-787.6l725.7-423.4 725.3 420-175.34 325.7-549.86-340.7-373.5 221v381.2z"/><path d="m1749.4 842.6v787.6l-725.4 423.3-724.5-419.5 219.38-278.79 505.12 293.39 373.2-221.2v-381z"/><path d="M299.5 1634L1750 786.4V420L299 1267.4z"/></g></svg>

After

Width:  |  Height:  |  Size: 350 B

View file

@ -38,7 +38,7 @@ else if (window.opener && window.opener.location.toString()) {
<!-- Fixed button -->
<div class='fixbutton'>
<div class='fixbutton-text'><img width=22 src='/uimedia/img/logo-white.png'/></div>
<div class='fixbutton-text'><img width=30 src='/uimedia/img/logo-white.svg'/></div>
<div class='fixbutton-burger'>&#x2261;</div>
<a class='fixbutton-bg' href="{homepage}/"></a>
</div>

View file

@ -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:

View file

@ -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()

View file

@ -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])