Compare commits
54 commits
py3-intern
...
py3-latest
Author | SHA1 | Date | |
---|---|---|---|
7edbda70f5 | |||
![]() |
290025958f | ||
![]() |
25c5658b72 | ||
![]() |
2970e3a205 | ||
![]() |
866179f6a3 | ||
![]() |
e8cf14bcf5 | ||
![]() |
fedcf9c1c6 | ||
![]() |
117bcf25d9 | ||
![]() |
a429349cd4 | ||
![]() |
d8e52eaabd | ||
![]() |
f2ef6e5d9c | ||
![]() |
dd2bb07cfb | ||
![]() |
06a9d1e0ff | ||
![]() |
c354f9e24d | ||
![]() |
77b4297224 | ||
![]() |
edc5310cd2 | ||
![]() |
99a8409513 | ||
![]() |
3550a64837 | ||
![]() |
85ef28e6fb | ||
![]() |
1500d9356b | ||
![]() |
f1a71770fa | ||
![]() |
f79a73cef4 | ||
![]() |
0731787518 | ||
![]() |
ad95eede10 | ||
![]() |
459b0a73ca | ||
![]() |
b7870edd2e | ||
![]() |
d5703541be | ||
![]() |
ba96654e1d | ||
![]() |
ac72d623f0 | ||
![]() |
fd857985f6 | ||
![]() |
966f671efe | ||
![]() |
86109ae4b2 | ||
![]() |
611fc774c8 | ||
![]() |
0ed0b746a4 | ||
![]() |
49e68c3a78 | ||
![]() |
3ac677c9a7 | ||
![]() |
016cfe9e16 | ||
![]() |
712ee18634 | ||
![]() |
5579c6b3cc | ||
![]() |
c3815c56ea | ||
![]() |
b257338b0a | ||
![]() |
ac70f83879 | ||
![]() |
2ad80afa10 | ||
![]() |
fe048cd08c | ||
![]() |
f9d7ccd83c | ||
![]() |
b29884db78 | ||
![]() |
a5190234ab | ||
![]() |
00db9c9f87 | ||
![]() |
02ceb70a4f | ||
![]() |
7ce118d645 | ||
![]() |
eb397cf4c7 | ||
![]() |
f8c9f2da4f | ||
![]() |
69d7eacfa4 | ||
![]() |
f498aedb96 |
26 changed files with 667 additions and 284 deletions
40
.forgejo/workflows/build-on-commit.yml
Normal file
40
.forgejo/workflows/build-on-commit.yml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
name: Build Docker Image on Commit
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- '!' # Exclude tags
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: docker-builder
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set REPO_VARS
|
||||||
|
id: repo-url
|
||||||
|
run: |
|
||||||
|
echo "REPO_HOST=$(echo "${{ github.server_url }}" | sed 's~http[s]*://~~g')" >> $GITHUB_ENV
|
||||||
|
echo "REPO_PATH=${{ github.repository }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Login to OCI registry
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.OCI_TOKEN }}" | docker login $REPO_HOST -u "${{ secrets.OCI_USER }}" --password-stdin
|
||||||
|
|
||||||
|
- name: Build and push Docker images
|
||||||
|
run: |
|
||||||
|
# Build Docker image with commit SHA
|
||||||
|
docker build -t $REPO_HOST/$REPO_PATH:${{ github.sha }} .
|
||||||
|
docker push $REPO_HOST/$REPO_PATH:${{ github.sha }}
|
||||||
|
|
||||||
|
# Build Docker image with nightly tag
|
||||||
|
docker tag $REPO_HOST/$REPO_PATH:${{ github.sha }} $REPO_HOST/$REPO_PATH:nightly
|
||||||
|
docker push $REPO_HOST/$REPO_PATH:nightly
|
||||||
|
|
||||||
|
# Remove local images to save storage
|
||||||
|
docker rmi $REPO_HOST/$REPO_PATH:${{ github.sha }}
|
||||||
|
docker rmi $REPO_HOST/$REPO_PATH:nightly
|
37
.forgejo/workflows/build-on-tag.yml
Normal file
37
.forgejo/workflows/build-on-tag.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: Build and Publish Docker Image on Tag
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: docker-builder
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set REPO_VARS
|
||||||
|
id: repo-url
|
||||||
|
run: |
|
||||||
|
echo "REPO_HOST=$(echo "${{ github.server_url }}" | sed 's~http[s]*://~~g')" >> $GITHUB_ENV
|
||||||
|
echo "REPO_PATH=${{ github.repository }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Login to OCI registry
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.OCI_TOKEN }}" | docker login $REPO_HOST -u "${{ secrets.OCI_USER }}" --password-stdin
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
run: |
|
||||||
|
TAG=${{ github.ref_name }} # Get the tag name from the context
|
||||||
|
# Build and push multi-platform Docker images
|
||||||
|
docker build -t $REPO_HOST/$REPO_PATH:$TAG --push .
|
||||||
|
# Tag and push latest
|
||||||
|
docker tag $REPO_HOST/$REPO_PATH:$TAG $REPO_HOST/$REPO_PATH:latest
|
||||||
|
docker push $REPO_HOST/$REPO_PATH:latest
|
||||||
|
|
||||||
|
# Remove the local image to save storage
|
||||||
|
docker rmi $REPO_HOST/$REPO_PATH:$TAG
|
||||||
|
docker rmi $REPO_HOST/$REPO_PATH:latest
|
11
.github/FUNDING.yml
vendored
11
.github/FUNDING.yml
vendored
|
@ -1 +1,10 @@
|
||||||
custom: https://zerolink.ml/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/
|
github: canewsin
|
||||||
|
patreon: # Replace with a single Patreon username e.g., user1
|
||||||
|
open_collective: # Replace with a single Open Collective username e.g., user1
|
||||||
|
ko_fi: canewsin
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: canewsin
|
||||||
|
issuehunt: # Replace with a single IssueHunt username e.g., user1
|
||||||
|
otechie: # Replace with a single Otechie username e.g., user1
|
||||||
|
custom: ['https://paypal.me/PramUkesh', 'https://zerolink.ml/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/']
|
||||||
|
|
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ py3-latest ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ py3-latest ]
|
||||||
|
schedule:
|
||||||
|
- cron: '32 19 * * 2'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'javascript', 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
7
.github/workflows/tests.yml
vendored
7
.github/workflows/tests.yml
vendored
|
@ -4,18 +4,17 @@ on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
strategy:
|
strategy:
|
||||||
max-parallel: 16
|
max-parallel: 16
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.6, 3.7, 3.8, 3.9]
|
python-version: ["3.7", "3.8", "3.9"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout ZeroNet
|
- name: Checkout ZeroNet
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: "true"
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v1
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@ __pycache__/
|
||||||
|
|
||||||
# Hidden files
|
# Hidden files
|
||||||
.*
|
.*
|
||||||
|
!/.forgejo
|
||||||
!/.github
|
!/.github
|
||||||
!/.gitignore
|
!/.gitignore
|
||||||
!/.travis.yml
|
!/.travis.yml
|
||||||
|
|
81
CHANGELOG.md
81
CHANGELOG.md
|
@ -1,6 +1,85 @@
|
||||||
### ZeroNet 0.7.2 (2020-09-?) Rev4206?
|
### ZeroNet 0.9.0 (2023-07-12) Rev4630
|
||||||
|
- Fix RDos Issue in Plugins https://github.com/ZeroNetX/ZeroNet-Plugins/pull/9
|
||||||
|
- Add trackers to Config.py for failsafety incase missing trackers.txt
|
||||||
|
- Added Proxy links
|
||||||
|
- Fix pysha3 dep installation issue
|
||||||
|
- FileRequest -> Remove Unnecessary check, Fix error wording
|
||||||
|
- Fix Response when site is missing for `actionAs`
|
||||||
|
|
||||||
|
|
||||||
|
### ZeroNet 0.8.5 (2023-02-12) Rev4625
|
||||||
|
- Fix(https://github.com/ZeroNetX/ZeroNet/pull/202) for SSL cert gen failed on Windows.
|
||||||
|
- default theme-class for missing value in `users.json`.
|
||||||
|
- Fetch Stats Plugin changes.
|
||||||
|
|
||||||
|
### ZeroNet 0.8.4 (2022-12-12) Rev4620
|
||||||
|
- Increase Minimum Site size to 25MB.
|
||||||
|
|
||||||
|
### ZeroNet 0.8.3 (2022-12-11) Rev4611
|
||||||
|
- main.py -> Fix accessing unassigned varible
|
||||||
|
- ContentManager -> Support for multiSig
|
||||||
|
- SiteStrorage.py -> Fix accessing unassigned varible
|
||||||
|
- ContentManager.py Improve Logging of Valid Signers
|
||||||
|
|
||||||
|
### ZeroNet 0.8.2 (2022-11-01) Rev4610
|
||||||
|
- Fix Startup Error when plugins dir missing
|
||||||
|
- Move trackers to seperate file & Add more trackers
|
||||||
|
- Config:: Skip loading missing tracker files
|
||||||
|
- Added documentation for getRandomPort fn
|
||||||
|
|
||||||
|
### ZeroNet 0.8.1 (2022-10-01) Rev4600
|
||||||
|
- fix readdress loop (cherry-pick previously added commit from conservancy)
|
||||||
|
- Remove Patreon badge
|
||||||
|
- Update README-ru.md (#177)
|
||||||
|
- Include inner_path of failed request for signing in error msg and response
|
||||||
|
- Don't Fail Silently When Cert is Not Selected
|
||||||
|
- Console Log Updates, Specify min supported ZeroNet version for Rust version Protocol Compatibility
|
||||||
|
- Update FUNDING.yml
|
||||||
|
|
||||||
|
### ZeroNet 0.8.0 (2022-05-27) Rev4591
|
||||||
|
- Revert File Open to catch File Access Errors.
|
||||||
|
|
||||||
|
### ZeroNet 0.7.9-patch (2022-05-26) Rev4586
|
||||||
|
- Use xescape(s) from zeronet-conservancy
|
||||||
|
- actionUpdate response Optimisation
|
||||||
|
- Fetch Plugins Repo Updates
|
||||||
|
- Fix Unhandled File Access Errors
|
||||||
|
- Create codeql-analysis.yml
|
||||||
|
|
||||||
|
### ZeroNet 0.7.9 (2022-05-26) Rev4585
|
||||||
|
- Rust Version Compatibility for update Protocol msg
|
||||||
|
- Removed Non Working Trakers.
|
||||||
|
- Dynamically Load Trackers from Dashboard Site.
|
||||||
|
- Tracker Supply Improvements.
|
||||||
|
- Fix Repo Url for Bug Report
|
||||||
|
- First Party Tracker Update Service using Dashboard Site.
|
||||||
|
- remove old v2 onion service [#158](https://github.com/ZeroNetX/ZeroNet/pull/158)
|
||||||
|
|
||||||
|
### ZeroNet 0.7.8 (2022-03-02) Rev4580
|
||||||
|
- Update Plugins with some bug fixes and Improvements
|
||||||
|
|
||||||
|
### ZeroNet 0.7.6 (2022-01-12) Rev4565
|
||||||
|
- Sync Plugin Updates
|
||||||
|
- Clean up tor v3 patch [#115](https://github.com/ZeroNetX/ZeroNet/pull/115)
|
||||||
|
- Add More Default Plugins to Repo
|
||||||
|
- Doubled Site Publish Limits
|
||||||
|
- Update ZeroNet Repo Urls [#103](https://github.com/ZeroNetX/ZeroNet/pull/103)
|
||||||
|
- UI/UX: Increases Size of Notifications Close Button [#106](https://github.com/ZeroNetX/ZeroNet/pull/106)
|
||||||
|
- Moved Plugins to Seperate Repo
|
||||||
|
- Added `access_key` variable in Config, this used to access restrited plugins when multiuser plugin is enabled. When MultiUserPlugin is enabled we cannot access some pages like /Stats, this key will remove such restriction with access key.
|
||||||
|
- Added `last_connection_id_current_version` to ConnectionServer, helpful to estimate no of connection from current client version.
|
||||||
|
- Added current version: connections to /Stats page. see the previous point.
|
||||||
|
|
||||||
|
### ZeroNet 0.7.5 (2021-11-28) Rev4560
|
||||||
|
- Add more default trackers
|
||||||
|
- Change default homepage address to `1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d`
|
||||||
|
- Change default update site address to `1Update8crprmciJHwp2WXqkx2c4iYp18`
|
||||||
|
|
||||||
|
### ZeroNet 0.7.3 (2021-11-28) Rev4555
|
||||||
|
- Fix xrange is undefined error
|
||||||
|
- Fix Incorrect viewport on mobile while loading
|
||||||
|
- Tor-V3 Patch by anonymoose
|
||||||
|
|
||||||
|
|
||||||
### ZeroNet 0.7.1 (2019-07-01) Rev4206
|
### ZeroNet 0.7.1 (2019-07-01) Rev4206
|
||||||
### Added
|
### Added
|
||||||
|
|
243
README-ru.md
243
README-ru.md
|
@ -3,206 +3,131 @@
|
||||||
[简体中文](./README-zh-cn.md)
|
[简体中文](./README-zh-cn.md)
|
||||||
[English](./README.md)
|
[English](./README.md)
|
||||||
|
|
||||||
Децентрализованные вебсайты использующие Bitcoin криптографию и BitTorrent сеть - https://zeronet.dev
|
Децентрализованные вебсайты, использующие криптографию Bitcoin и протокол BitTorrent — https://zeronet.dev ([Зеркало в ZeroNet](http://127.0.0.1:43110/1ZeroNetyV5mKY9JF1gsm82TuBXHpfdLX/)). В отличии от Bitcoin, ZeroNet'у не требуется блокчейн для работы, однако он использует ту же криптографию, чтобы обеспечить сохранность и проверку данных.
|
||||||
|
|
||||||
|
|
||||||
## Зачем?
|
## Зачем?
|
||||||
|
|
||||||
* Мы верим в открытую, свободную, и не отцензуренную сеть и коммуникацию.
|
- Мы верим в открытую, свободную, и неподдающуюся цензуре сеть и связь.
|
||||||
* Нет единой точки отказа: Сайт онлайн пока по крайней мере 1 пир обслуживает его.
|
- Нет единой точки отказа: Сайт остаётся онлайн, пока его обслуживает хотя бы 1 пир.
|
||||||
* Никаких затрат на хостинг: Сайты обслуживаются посетителями.
|
- Нет затрат на хостинг: Сайты обслуживаются посетителями.
|
||||||
* Невозможно отключить: Он нигде, потому что он везде.
|
- Невозможно отключить: Он нигде, потому что он везде.
|
||||||
* Быстр и работает оффлайн: Вы можете получить доступ к сайту, даже если Интернет недоступен.
|
- Скорость и возможность работать без Интернета: Вы сможете получить доступ к сайту, потому что его копия хранится на вашем компьютере и у ваших пиров.
|
||||||
|
|
||||||
|
|
||||||
## Особенности
|
## Особенности
|
||||||
* Обновляемые в реальном времени сайты
|
|
||||||
* Поддержка Namecoin .bit доменов
|
|
||||||
* Лёгок в установке: распаковал & запустил
|
|
||||||
* Клонирование вебсайтов в один клик
|
|
||||||
* Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
|
|
||||||
based authorization: Ваша учетная запись защищена той же криптографией, что и ваш Bitcoin-кошелек
|
|
||||||
* Встроенный SQL-сервер с синхронизацией данных P2P: Позволяет упростить разработку сайта и ускорить загрузку страницы
|
|
||||||
* Анонимность: Полная поддержка сети Tor с помощью скрытых служб .onion вместо адресов IPv4
|
|
||||||
* TLS зашифрованные связи
|
|
||||||
* Автоматическое открытие uPnP порта
|
|
||||||
* Плагин для поддержки многопользовательской (openproxy)
|
|
||||||
* Работает с любыми браузерами и операционными системами
|
|
||||||
|
|
||||||
|
- Обновление сайтов в реальном времени
|
||||||
|
- Поддержка доменов `.bit` ([Namecoin](https://www.namecoin.org))
|
||||||
|
- Легкая установка: просто распакуйте и запустите
|
||||||
|
- Клонирование сайтов "в один клик"
|
||||||
|
- Беспарольная [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
|
||||||
|
авторизация: Ваша учетная запись защищена той же криптографией, что и ваш Bitcoin-кошелек
|
||||||
|
- Встроенный SQL-сервер с синхронизацией данных P2P: Позволяет упростить разработку сайта и ускорить загрузку страницы
|
||||||
|
- Анонимность: Полная поддержка сети Tor, используя скрытые службы `.onion` вместо адресов IPv4
|
||||||
|
- Зашифрованное TLS подключение
|
||||||
|
- Автоматическое открытие UPnP–порта
|
||||||
|
- Плагин для поддержки нескольких пользователей (openproxy)
|
||||||
|
- Работа с любыми браузерами и операционными системами
|
||||||
|
|
||||||
|
## Текущие ограничения
|
||||||
|
|
||||||
|
- Файловые транзакции не сжаты
|
||||||
|
- Нет приватных сайтов
|
||||||
|
|
||||||
## Как это работает?
|
## Как это работает?
|
||||||
|
|
||||||
* После запуска `zeronet.py` вы сможете посетить зайты (zeronet сайты) используя адрес
|
- После запуска `zeronet.py` вы сможете посещать сайты в ZeroNet, используя адрес
|
||||||
`http://127.0.0.1:43110/{zeronet_address}`
|
`http://127.0.0.1:43110/{zeronet_адрес}`
|
||||||
(например. `http://127.0.0.1:43110/1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d`).
|
(Например: `http://127.0.0.1:43110/1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d`).
|
||||||
* Когда вы посещаете новый сайт zeronet, он пытается найти пиров с помощью BitTorrent
|
- Когда вы посещаете новый сайт в ZeroNet, он пытается найти пиров с помощью протокола BitTorrent,
|
||||||
чтобы загрузить файлы сайтов (html, css, js ...) из них.
|
чтобы скачать у них файлы сайта (HTML, CSS, JS и т.д.).
|
||||||
* Каждый посещенный зайт также обслуживается вами. (Т.е хранится у вас на компьютере)
|
- После посещения сайта вы тоже становитесь его пиром.
|
||||||
* Каждый сайт содержит файл `content.json`, который содержит все остальные файлы в хэше sha512
|
- Каждый сайт содержит файл `content.json`, который содержит SHA512 хеши всех остальные файлы
|
||||||
и подпись, созданную с использованием частного ключа сайта.
|
и подпись, созданную с помощью закрытого ключа сайта.
|
||||||
* Если владелец сайта (у которого есть закрытый ключ для адреса сайта) изменяет сайт, то он/она
|
- Если владелец сайта (тот, кто владеет закрытым ключом для адреса сайта) изменяет сайт, он
|
||||||
подписывает новый `content.json` и публикует его для пиров. После этого пиры проверяют целостность `content.json`
|
подписывает новый `content.json` и публикует его для пиров. После этого пиры проверяют целостность `content.json`
|
||||||
(используя подпись), они загружают измененные файлы и публикуют новый контент для других пиров.
|
(используя подпись), скачвают изменённые файлы и распространяют новый контент для других пиров.
|
||||||
|
|
||||||
#### [Слайд-шоу о криптографии ZeroNet, обновлениях сайтов, многопользовательских сайтах »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
|
|
||||||
#### [Часто задаваемые вопросы »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/faq/)
|
|
||||||
|
|
||||||
#### [Документация разработчика ZeroNet »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/site_development/getting_started/)
|
|
||||||
|
|
||||||
|
[Презентация о криптографии ZeroNet, обновлениях сайтов, многопользовательских сайтах »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
|
||||||
|
[Часто задаваемые вопросы »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/faq/)
|
||||||
|
[Документация разработчика ZeroNet »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/site_development/getting_started/)
|
||||||
|
|
||||||
## Скриншоты
|
## Скриншоты
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
[Больше скриншотов в документации ZeroNet »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/using_zeronet/sample_sites/)
|
||||||
|
|
||||||
#### [Больше скриншотов в ZeroNet документации »](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/using_zeronet/sample_sites/)
|
## Как присоединиться?
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
## Как вступить
|
- Скачайте и распакуйте архив [ZeroNet-win.zip](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-win.zip) (26МБ)
|
||||||
|
- Запустите `ZeroNet.exe`
|
||||||
|
|
||||||
* Скачайте ZeroBundle пакет:
|
### macOS
|
||||||
* [Microsoft Windows](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-win.zip)
|
|
||||||
* [Apple macOS](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-mac.zip)
|
|
||||||
* [Linux 64-bit](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-linux.zip)
|
|
||||||
* [Linux 32-bit](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-linux.zip)
|
|
||||||
* Распакуйте где угодно
|
|
||||||
* Запустите `ZeroNet.exe` (win), `ZeroNet(.app)` (osx), `ZeroNet.sh` (linux)
|
|
||||||
|
|
||||||
### Linux терминал
|
- Скачайте и распакуйте архив [ZeroNet-mac.zip](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-mac.zip) (14МБ)
|
||||||
|
- Запустите `ZeroNet.app`
|
||||||
|
|
||||||
* `wget https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-linux.zip`
|
### Linux (64 бит)
|
||||||
* `unzip ZeroNet-linux.zip`
|
|
||||||
* `cd ZeroNet-linux`
|
|
||||||
* Запустите с помощью `./ZeroNet.sh`
|
|
||||||
|
|
||||||
Он загружает последнюю версию ZeroNet, затем запускает её автоматически.
|
- Скачайте и распакуйте архив [ZeroNet-linux.zip](https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-linux.zip) (14МБ)
|
||||||
|
- Запустите `./ZeroNet.sh`
|
||||||
|
|
||||||
#### Ручная установка для Debian Linux
|
> **Note**
|
||||||
|
> Запустите таким образом: `./ZeroNet.sh --ui_ip '*' --ui_restrict ваш_ip_адрес`, чтобы разрешить удалённое подключение к веб–интерфейсу.
|
||||||
|
|
||||||
* `wget https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-src.zip`
|
### Docker
|
||||||
* `unzip ZeroNet-src.zip`
|
|
||||||
* `cd ZeroNet`
|
|
||||||
* `sudo apt-get update`
|
|
||||||
* `sudo apt-get install python3-pip`
|
|
||||||
* `sudo python3 -m pip install -r requirements.txt`
|
|
||||||
* Запустите с помощью `python3 zeronet.py`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
### [Arch Linux](https://www.archlinux.org)
|
Официальный образ находится здесь: https://hub.docker.com/r/canewsin/zeronet/
|
||||||
|
|
||||||
* `git clone https://aur.archlinux.org/zeronet.git`
|
### Android (arm, arm64, x86)
|
||||||
* `cd zeronet`
|
|
||||||
* `makepkg -srci`
|
|
||||||
* `systemctl start zeronet`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
Смотрите [ArchWiki](https://wiki.archlinux.org)'s [ZeroNet
|
- Для работы требуется Android как минимум версии 5.0 Lollipop
|
||||||
article](https://wiki.archlinux.org/index.php/ZeroNet) для дальнейшей помощи.
|
- [<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.zeronetmobile)
|
||||||
|
- Скачать APK: https://github.com/canewsin/zeronet_mobile/releases
|
||||||
|
|
||||||
### [Gentoo Linux](https://www.gentoo.org)
|
### Android (arm, arm64, x86) Облегчённый клиент только для просмотра (1МБ)
|
||||||
|
|
||||||
* [`layman -a raiagent`](https://github.com/leycec/raiagent)
|
- Для работы требуется Android как минимум версии 4.1 Jelly Bean
|
||||||
* `echo '>=net-vpn/zeronet-0.5.4' >> /etc/portage/package.accept_keywords`
|
- [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
* *(Опционально)* Включить поддержку Tor: `echo 'net-vpn/zeronet tor' >>
|
alt="Download from Google Play"
|
||||||
/etc/portage/package.use`
|
height="80">](https://play.google.com/store/apps/details?id=dev.zeronetx.app.lite)
|
||||||
* `emerge zeronet`
|
|
||||||
* `rc-service zeronet start`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
Смотрите `/usr/share/doc/zeronet-*/README.gentoo.bz2` для дальнейшей помощи.
|
### Установка из исходного кода
|
||||||
|
|
||||||
### [FreeBSD](https://www.freebsd.org/)
|
```sh
|
||||||
|
wget https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-src.zip
|
||||||
* `pkg install zeronet` or `cd /usr/ports/security/zeronet/ && make install clean`
|
unzip ZeroNet-src.zip
|
||||||
* `sysrc zeronet_enable="YES"`
|
cd ZeroNet
|
||||||
* `service zeronet start`
|
sudo apt-get update
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
sudo apt-get install python3-pip
|
||||||
|
sudo python3 -m pip install -r requirements.txt
|
||||||
### [Vagrant](https://www.vagrantup.com/)
|
|
||||||
|
|
||||||
* `vagrant up`
|
|
||||||
* Подключитесь к VM с помощью `vagrant ssh`
|
|
||||||
* `cd /vagrant`
|
|
||||||
* Запустите `python3 zeronet.py --ui_ip 0.0.0.0`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
### [Docker](https://www.docker.com/)
|
|
||||||
* `docker run -d -v <local_data_folder>:/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 canewsin/zeronet`
|
|
||||||
* Это изображение Docker включает в себя прокси-сервер Tor, который по умолчанию отключён.
|
|
||||||
Остерегайтесь что некоторые хостинг-провайдеры могут не позволить вам запускать Tor на своих серверах.
|
|
||||||
Если вы хотите включить его,установите переменную среды `ENABLE_TOR` в` true` (по умолчанию: `false`) Например:
|
|
||||||
|
|
||||||
`docker run -d -e "ENABLE_TOR=true" -v <local_data_folder>:/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 canewsin/zeronet`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
### [Virtualenv](https://virtualenv.readthedocs.org/en/latest/)
|
|
||||||
|
|
||||||
* `virtualenv env`
|
|
||||||
* `source env/bin/activate`
|
|
||||||
* `pip install msgpack gevent`
|
|
||||||
* `python3 zeronet.py`
|
|
||||||
* Откройте http://127.0.0.1:43110/ в вашем браузере.
|
|
||||||
|
|
||||||
## Текущие ограничения
|
|
||||||
|
|
||||||
* Файловые транзакции не сжаты
|
|
||||||
* Нет приватных сайтов
|
|
||||||
|
|
||||||
|
|
||||||
## Как я могу создать сайт в Zeronet?
|
|
||||||
|
|
||||||
Завершите работу zeronet, если он запущен
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ zeronet.py siteCreate
|
|
||||||
...
|
|
||||||
- Site private key (Приватный ключ сайта): 23DKQpzxhbVBrAtvLEc2uvk7DZweh4qL3fn3jpM3LgHDczMK2TtYUq
|
|
||||||
- Site address (Адрес сайта): 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
|
|
||||||
...
|
|
||||||
- Site created! (Сайт создан)
|
|
||||||
$ zeronet.py
|
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
- Запустите `python3 zeronet.py`
|
||||||
|
|
||||||
Поздравляем, вы закончили! Теперь каждый может получить доступ к вашему зайту используя
|
Откройте приветственную страницу ZeroHello в вашем браузере по ссылке http://127.0.0.1:43110/
|
||||||
`http://localhost:43110/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2`
|
|
||||||
|
|
||||||
Следующие шаги: [ZeroNet Developer Documentation](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/site_development/getting_started/)
|
## Как мне создать сайт в ZeroNet?
|
||||||
|
|
||||||
|
- Кликните на **⋮** > **"Create new, empty site"** в меню на сайте [ZeroHello](http://127.0.0.1:43110/1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d).
|
||||||
|
- Вы будете **перенаправлены** на совершенно новый сайт, который может быть изменён только вами!
|
||||||
|
- Вы можете найти и изменить контент вашего сайта в каталоге **data/[адрес_вашего_сайта]**
|
||||||
|
- После изменений откройте ваш сайт, переключите влево кнопку "0" в правом верхнем углу, затем нажмите кнопки **sign** и **publish** внизу
|
||||||
|
|
||||||
## Как я могу модифицировать Zeronet сайт?
|
Следующие шаги: [Документация разработчика ZeroNet](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/site_development/getting_started/)
|
||||||
|
|
||||||
* Измените файлы расположенные в data/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2 директории.
|
|
||||||
Когда закончите с изменением:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ zeronet.py siteSign 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
|
|
||||||
- Signing site (Подпись сайта): 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2...
|
|
||||||
Private key (Приватный ключ) (input hidden):
|
|
||||||
```
|
|
||||||
|
|
||||||
* Введите секретный ключ, который вы получили при создании сайта, потом:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ zeronet.py sitePublish 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2
|
|
||||||
...
|
|
||||||
Site:13DNDk..bhC2 Publishing to 3/10 peers...
|
|
||||||
Site:13DNDk..bhC2 Successfuly published to 3 peers
|
|
||||||
- Serving files....
|
|
||||||
```
|
|
||||||
|
|
||||||
* Вот и всё! Вы успешно подписали и опубликовали свои изменения.
|
|
||||||
|
|
||||||
|
|
||||||
## Поддержите проект
|
## Поддержите проект
|
||||||
- Bitcoin: 1ZeroNetyV5mKY9JF1gsm82TuBXHpfdLX (Preferred)
|
|
||||||
|
- Bitcoin: 1ZeroNetyV5mKY9JF1gsm82TuBXHpfdLX (Рекомендуем)
|
||||||
- LiberaPay: https://liberapay.com/PramUkesh
|
- LiberaPay: https://liberapay.com/PramUkesh
|
||||||
- Paypal: https://paypal.me/PramUkesh
|
- Paypal: https://paypal.me/PramUkesh
|
||||||
- Others: [Donate](!https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/#help-to-keep-zeronet-development-alive)
|
- Другие способы: [Donate](!https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/#help-to-keep-zeronet-development-alive)
|
||||||
|
|
||||||
|
|
||||||
#### Спасибо!
|
#### Спасибо!
|
||||||
|
|
||||||
* Больше информации, помощь, журнал изменений, zeronet сайты: https://www.reddit.com/r/zeronetx/
|
- Здесь вы можете получить больше информации, помощь, прочитать список изменений и исследовать ZeroNet сайты: https://www.reddit.com/r/zeronetx/
|
||||||
* Приходите, пообщайтесь с нами: [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) или на [gitter](https://gitter.im/canewsin/ZeroNet)
|
- Общение происходит на канале [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) или в [Gitter](https://gitter.im/canewsin/ZeroNet)
|
||||||
* Email: canews.in@gmail.com
|
- Электронная почта: canews.in@gmail.com
|
||||||
|
|
19
README.md
19
README.md
|
@ -1,5 +1,4 @@
|
||||||
# ZeroNet [](https://github.com/ZeroNetX/ZeroNet/actions/workflows/tests.yml) [](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/faq/) [](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/) [](https://hub.docker.com/r/canewsin/zeronet)
|
# ZeroNet [](https://github.com/ZeroNetX/ZeroNet/actions/workflows/tests.yml) [](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/faq/) [](https://docs.zeronet.dev/1DeveLopDZL1cHfKi8UXHh2UBEhzH6HhMp/help_zeronet/donate/) [](https://hub.docker.com/r/canewsin/zeronet)
|
||||||
|
|
||||||
<!--TODO: Update Onion Site -->
|
<!--TODO: Update Onion Site -->
|
||||||
Decentralized websites using Bitcoin crypto and the BitTorrent network - https://zeronet.dev / [ZeroNet Site](http://127.0.0.1:43110/1ZeroNetyV5mKY9JF1gsm82TuBXHpfdLX/), Unlike Bitcoin, ZeroNet Doesn't need a blockchain to run, But uses cryptography used by BTC, to ensure data integrity and validation.
|
Decentralized websites using Bitcoin crypto and the BitTorrent network - https://zeronet.dev / [ZeroNet Site](http://127.0.0.1:43110/1ZeroNetyV5mKY9JF1gsm82TuBXHpfdLX/), Unlike Bitcoin, ZeroNet Doesn't need a blockchain to run, But uses cryptography used by BTC, to ensure data integrity and validation.
|
||||||
|
|
||||||
|
@ -100,6 +99,24 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network - https:/
|
||||||
#### Docker
|
#### Docker
|
||||||
There is an official image, built from source at: https://hub.docker.com/r/canewsin/zeronet/
|
There is an official image, built from source at: https://hub.docker.com/r/canewsin/zeronet/
|
||||||
|
|
||||||
|
### Online Proxies
|
||||||
|
Proxies are like seed boxes for sites(i.e ZNX runs on a cloud vps), you can try zeronet experience from proxies. Add your proxy below if you have one.
|
||||||
|
|
||||||
|
#### Official ZNX Proxy :
|
||||||
|
|
||||||
|
https://proxy.zeronet.dev/
|
||||||
|
|
||||||
|
https://zeronet.dev/
|
||||||
|
|
||||||
|
#### From Community
|
||||||
|
|
||||||
|
https://0net-preview.com/
|
||||||
|
|
||||||
|
https://portal.ngnoid.tv/
|
||||||
|
|
||||||
|
https://zeronet.ipfsscan.io/
|
||||||
|
|
||||||
|
|
||||||
### Install from source
|
### Install from source
|
||||||
|
|
||||||
- `wget https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-src.zip`
|
- `wget https://github.com/ZeroNetX/ZeroNet/releases/latest/download/ZeroNet-src.zip`
|
||||||
|
|
2
plugins
2
plugins
|
@ -1 +1 @@
|
||||||
Subproject commit d3cbe172712951f43bb6589e92e9e9eeb86c3172
|
Subproject commit 689d9309f73371f4681191b125ec3f2e14075eeb
|
|
@ -3,7 +3,7 @@ greenlet==0.4.16; python_version <= "3.6"
|
||||||
gevent>=20.9.0; python_version >= "3.7"
|
gevent>=20.9.0; python_version >= "3.7"
|
||||||
msgpack>=0.4.4
|
msgpack>=0.4.4
|
||||||
base58
|
base58
|
||||||
merkletools
|
merkletools @ git+https://github.com/ZeroNetX/pymerkletools.git@dev
|
||||||
rsa
|
rsa
|
||||||
PySocks>=1.6.8
|
PySocks>=1.6.8
|
||||||
pyasn1
|
pyasn1
|
||||||
|
|
|
@ -13,8 +13,8 @@ import time
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
self.version = "0.7.6"
|
self.version = "0.9.0"
|
||||||
self.rev = 4565
|
self.rev = 4630
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
self.action = None
|
self.action = None
|
||||||
self.test_parser = None
|
self.test_parser = None
|
||||||
|
@ -82,34 +82,12 @@ class Config(object):
|
||||||
from Crypt import CryptHash
|
from Crypt import CryptHash
|
||||||
access_key_default = CryptHash.random(24, "base64") # Used to allow restrited plugins when multiuser plugin is enabled
|
access_key_default = CryptHash.random(24, "base64") # Used to allow restrited plugins when multiuser plugin is enabled
|
||||||
trackers = [
|
trackers = [
|
||||||
"zero://boot3rdez4rzn36x.onion:15441",
|
|
||||||
"http://open.acgnxtracker.com:80/announce", # DE
|
"http://open.acgnxtracker.com:80/announce", # DE
|
||||||
"http://tracker.bt4g.com:2095/announce", # Cloudflare
|
"http://tracker.bt4g.com:2095/announce", # Cloudflare
|
||||||
"zero://2602:ffc5::c5b2:5360:26312", # US/ATL
|
"http://tracker.files.fm:6969/announce",
|
||||||
"zero://145.239.95.38:15441",
|
"http://t.publictracker.xyz:6969/announce",
|
||||||
"zero://188.116.183.41:26552",
|
|
||||||
"zero://145.239.95.38:15441",
|
|
||||||
"zero://211.125.90.79:22234",
|
|
||||||
"zero://216.189.144.82:26312",
|
|
||||||
"zero://45.77.23.92:15555",
|
|
||||||
"zero://51.15.54.182:21041",
|
|
||||||
"https://tracker.lilithraws.cf:443/announce",
|
"https://tracker.lilithraws.cf:443/announce",
|
||||||
"udp://code2chicken.nl:6969/announce",
|
"https://tracker.babico.name.tr:443/announce",
|
||||||
"udp://abufinzio.monocul.us:6969/announce",
|
|
||||||
"udp://tracker.0x.tf:6969/announce",
|
|
||||||
"udp://tracker.zerobytes.xyz:1337/announce",
|
|
||||||
"udp://vibe.sleepyinternetfun.xyz:1738/announce",
|
|
||||||
"udp://www.torrent.eu.org:451/announce",
|
|
||||||
"zero://k5w77dozo3hy5zualyhni6vrh73iwfkaofa64abbilwyhhd3wgenbjqd.onion:15441",
|
|
||||||
"zero://2kcb2fqesyaevc4lntogupa4mkdssth2ypfwczd2ov5a3zo6ytwwbayd.onion:15441",
|
|
||||||
"zero://gugt43coc5tkyrhrc3esf6t6aeycvcqzw7qafxrjpqbwt4ssz5czgzyd.onion:15441",
|
|
||||||
"zero://hb6ozikfiaafeuqvgseiik4r46szbpjfu66l67wjinnyv6dtopuwhtqd.onion:15445",
|
|
||||||
"zero://75pmmcbp4vvo2zndmjnrkandvbg6jyptygvvpwsf2zguj7urq7t4jzyd.onion:7777",
|
|
||||||
"zero://dw4f4sckg2ultdj5qu7vtkf3jsfxsah3mz6pivwfd6nv3quji3vfvhyd.onion:6969",
|
|
||||||
"zero://5vczpwawviukvd7grfhsfxp7a6huz77hlis4fstjkym5kmf4pu7i7myd.onion:15441",
|
|
||||||
"zero://ow7in4ftwsix5klcbdfqvfqjvimqshbm2o75rhtpdnsderrcbx74wbad.onion:15441",
|
|
||||||
"zero://agufghdtniyfwty3wk55drxxwj2zxgzzo7dbrtje73gmvcpxy4ngs4ad.onion:15441",
|
|
||||||
"zero://qn65si4gtcwdiliq7vzrwu62qrweoxb6tx2cchwslaervj6szuje66qd.onion:26117",
|
|
||||||
]
|
]
|
||||||
# Platform specific
|
# Platform specific
|
||||||
if sys.platform.startswith("win"):
|
if sys.platform.startswith("win"):
|
||||||
|
@ -273,7 +251,7 @@ class Config(object):
|
||||||
self.parser.add_argument('--access_key', help='Plugin access key default: Random key generated at startup', default=access_key_default, metavar='key')
|
self.parser.add_argument('--access_key', help='Plugin access key default: Random key generated at startup', default=access_key_default, metavar='key')
|
||||||
self.parser.add_argument('--dist_type', help='Type of installed distribution', default='source')
|
self.parser.add_argument('--dist_type', help='Type of installed distribution', default='source')
|
||||||
|
|
||||||
self.parser.add_argument('--size_limit', help='Default site size limit in MB', default=10, type=int, metavar='limit')
|
self.parser.add_argument('--size_limit', help='Default site size limit in MB', default=25, type=int, metavar='limit')
|
||||||
self.parser.add_argument('--file_size_limit', help='Maximum per file size limit in MB', default=10, type=int, metavar='limit')
|
self.parser.add_argument('--file_size_limit', help='Maximum per file size limit in MB', default=10, type=int, metavar='limit')
|
||||||
self.parser.add_argument('--connected_limit', help='Max connected peer per site', default=8, type=int, metavar='connected_limit')
|
self.parser.add_argument('--connected_limit', help='Max connected peer per site', default=8, type=int, metavar='connected_limit')
|
||||||
self.parser.add_argument('--global_connected_limit', help='Max connections', default=512, type=int, metavar='global_connected_limit')
|
self.parser.add_argument('--global_connected_limit', help='Max connections', default=512, type=int, metavar='global_connected_limit')
|
||||||
|
@ -341,8 +319,7 @@ class Config(object):
|
||||||
|
|
||||||
def loadTrackersFile(self):
|
def loadTrackersFile(self):
|
||||||
if not self.trackers_file:
|
if not self.trackers_file:
|
||||||
return None
|
self.trackers_file = ["trackers.txt", "{data_dir}/1HELLoE3sFD9569CLCbHEAVqvqV7U2Ri9d/trackers.txt"]
|
||||||
|
|
||||||
self.trackers = self.arguments.trackers[:]
|
self.trackers = self.arguments.trackers[:]
|
||||||
|
|
||||||
for trackers_file in self.trackers_file:
|
for trackers_file in self.trackers_file:
|
||||||
|
@ -354,6 +331,9 @@ class Config(object):
|
||||||
else: # Relative to zeronet.py
|
else: # Relative to zeronet.py
|
||||||
trackers_file_path = self.start_dir + "/" + trackers_file
|
trackers_file_path = self.start_dir + "/" + trackers_file
|
||||||
|
|
||||||
|
if not os.path.exists(trackers_file_path):
|
||||||
|
continue
|
||||||
|
|
||||||
for line in open(trackers_file_path):
|
for line in open(trackers_file_path):
|
||||||
tracker = line.strip()
|
tracker = line.strip()
|
||||||
if "://" in tracker and tracker not in self.trackers:
|
if "://" in tracker and tracker not in self.trackers:
|
||||||
|
|
|
@ -32,6 +32,7 @@ class ConnectionServer(object):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.last_connection_id = 0 # Connection id incrementer
|
self.last_connection_id = 0 # Connection id incrementer
|
||||||
self.last_connection_id_current_version = 0 # Connection id incrementer for current client version
|
self.last_connection_id_current_version = 0 # Connection id incrementer for current client version
|
||||||
|
self.last_connection_id_supported_version = 0 # Connection id incrementer for last supported version
|
||||||
self.log = logging.getLogger("ConnServer")
|
self.log = logging.getLogger("ConnServer")
|
||||||
self.port_opened = {}
|
self.port_opened = {}
|
||||||
self.peer_blacklist = SiteManager.peer_blacklist
|
self.peer_blacklist = SiteManager.peer_blacklist
|
||||||
|
@ -157,7 +158,9 @@ class ConnectionServer(object):
|
||||||
connection = Connection(self, ip, port, sock)
|
connection = Connection(self, ip, port, sock)
|
||||||
self.connections.append(connection)
|
self.connections.append(connection)
|
||||||
rev = connection.handshake.get("rev", 0)
|
rev = connection.handshake.get("rev", 0)
|
||||||
if rev > 0 and rev == config.rev:
|
if rev >= 4560:
|
||||||
|
self.last_connection_id_supported_version += 1
|
||||||
|
if rev == config.rev:
|
||||||
self.last_connection_id_current_version += 1
|
self.last_connection_id_current_version += 1
|
||||||
if ip not in config.ip_local:
|
if ip not in config.ip_local:
|
||||||
self.ips[ip] = connection
|
self.ips[ip] = connection
|
||||||
|
@ -225,7 +228,9 @@ class ConnectionServer(object):
|
||||||
raise Exception("Connection event return error")
|
raise Exception("Connection event return error")
|
||||||
else:
|
else:
|
||||||
rev = connection.handshake.get("rev", 0)
|
rev = connection.handshake.get("rev", 0)
|
||||||
if rev > 0 and rev == config.rev:
|
if rev >= 4560:
|
||||||
|
self.last_connection_id_supported_version += 1
|
||||||
|
if rev == config.rev:
|
||||||
self.last_connection_id_current_version += 1
|
self.last_connection_id_current_version += 1
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
|
@ -727,7 +727,6 @@ class ContentManager(object):
|
||||||
elif "files_optional" in new_content:
|
elif "files_optional" in new_content:
|
||||||
del new_content["files_optional"]
|
del new_content["files_optional"]
|
||||||
|
|
||||||
new_content["modified"] = int(time.time()) # Add timestamp
|
|
||||||
if inner_path == "content.json":
|
if inner_path == "content.json":
|
||||||
new_content["zeronet_version"] = config.version
|
new_content["zeronet_version"] = config.version
|
||||||
new_content["signs_required"] = content.get("signs_required", 1)
|
new_content["signs_required"] = content.get("signs_required", 1)
|
||||||
|
@ -747,9 +746,11 @@ class ContentManager(object):
|
||||||
)
|
)
|
||||||
self.log.info("Correct %s in valid signers: %s" % (privatekey_address, valid_signers))
|
self.log.info("Correct %s in valid signers: %s" % (privatekey_address, valid_signers))
|
||||||
|
|
||||||
|
signs_required = 1
|
||||||
if inner_path == "content.json" and privatekey_address == self.site.address:
|
if inner_path == "content.json" and privatekey_address == self.site.address:
|
||||||
# If signing using the root key, then sign the valid signers
|
# If signing using the root key, then sign the valid signers
|
||||||
signers_data = "%s:%s" % (new_content["signs_required"], ",".join(valid_signers))
|
signs_required = new_content["signs_required"]
|
||||||
|
signers_data = "%s:%s" % (signs_required, ",".join(valid_signers))
|
||||||
new_content["signers_sign"] = CryptBitcoin.sign(str(signers_data), privatekey)
|
new_content["signers_sign"] = CryptBitcoin.sign(str(signers_data), privatekey)
|
||||||
if not new_content["signers_sign"]:
|
if not new_content["signers_sign"]:
|
||||||
self.log.info("Old style address, signers_sign is none")
|
self.log.info("Old style address, signers_sign is none")
|
||||||
|
@ -757,15 +758,32 @@ class ContentManager(object):
|
||||||
self.log.info("Signing %s..." % inner_path)
|
self.log.info("Signing %s..." % inner_path)
|
||||||
|
|
||||||
if "signs" in new_content:
|
if "signs" in new_content:
|
||||||
del(new_content["signs"]) # Delete old signs
|
# del(new_content["signs"]) # Delete old signs
|
||||||
|
old_signs_content = new_content["signs"]
|
||||||
|
del(new_content["signs"])
|
||||||
|
else:
|
||||||
|
old_signs_content = None
|
||||||
if "sign" in new_content:
|
if "sign" in new_content:
|
||||||
del(new_content["sign"]) # Delete old sign (backward compatibility)
|
del(new_content["sign"]) # Delete old sign (backward compatibility)
|
||||||
|
|
||||||
|
if signs_required > 1:
|
||||||
|
has_valid_sign = False
|
||||||
|
sign_content = json.dumps(new_content, sort_keys=True)
|
||||||
|
for signer in valid_signers:
|
||||||
|
res = CryptBitcoin.verify(sign_content,signer,old_signs_content[signer]);
|
||||||
|
print(res)
|
||||||
|
if res:
|
||||||
|
has_valid_sign = has_valid_sign or res
|
||||||
|
if has_valid_sign:
|
||||||
|
new_content["modified"] = content["modified"]
|
||||||
|
sign_content = json.dumps(new_content, sort_keys=True)
|
||||||
|
else:
|
||||||
|
new_content["modified"] = int(time.time()) # Add timestamp
|
||||||
sign_content = json.dumps(new_content, sort_keys=True)
|
sign_content = json.dumps(new_content, sort_keys=True)
|
||||||
sign = CryptBitcoin.sign(sign_content, privatekey)
|
sign = CryptBitcoin.sign(sign_content, privatekey)
|
||||||
# new_content["signs"] = content.get("signs", {}) # TODO: Multisig
|
# new_content["signs"] = content.get("signs", {}) # TODO: Multisig
|
||||||
if sign: # If signing is successful (not an old address)
|
if sign: # If signing is successful (not an old address)
|
||||||
new_content["signs"] = {}
|
new_content["signs"] = old_signs_content or {}
|
||||||
new_content["signs"][privatekey_address] = sign
|
new_content["signs"][privatekey_address] = sign
|
||||||
|
|
||||||
self.verifyContent(inner_path, new_content)
|
self.verifyContent(inner_path, new_content)
|
||||||
|
@ -800,7 +818,9 @@ class ContentManager(object):
|
||||||
|
|
||||||
# Return: The required number of valid signs for the content.json
|
# Return: The required number of valid signs for the content.json
|
||||||
def getSignsRequired(self, inner_path, content=None):
|
def getSignsRequired(self, inner_path, content=None):
|
||||||
return 1 # Todo: Multisig
|
if not content:
|
||||||
|
return 1
|
||||||
|
return content.get("signs_required", 1)
|
||||||
|
|
||||||
def verifyCertSign(self, user_address, user_auth_type, user_name, issuer_address, sign):
|
def verifyCertSign(self, user_address, user_auth_type, user_name, issuer_address, sign):
|
||||||
from Crypt import CryptBitcoin
|
from Crypt import CryptBitcoin
|
||||||
|
@ -988,14 +1008,16 @@ class ContentManager(object):
|
||||||
if inner_path != "content.json" and not self.verifyCert(inner_path, new_content): # Check if cert valid
|
if inner_path != "content.json" and not self.verifyCert(inner_path, new_content): # Check if cert valid
|
||||||
raise VerifyError("Invalid cert!")
|
raise VerifyError("Invalid cert!")
|
||||||
|
|
||||||
valid_signs = 0
|
valid_signs = []
|
||||||
for address in valid_signers:
|
for address in valid_signers:
|
||||||
if address in signs:
|
if address in signs:
|
||||||
valid_signs += CryptBitcoin.verify(sign_content, address, signs[address])
|
result = CryptBitcoin.verify(sign_content, address, signs[address])
|
||||||
if valid_signs >= signs_required:
|
if result:
|
||||||
|
valid_signs.append(address)
|
||||||
|
if len(valid_signs) >= signs_required:
|
||||||
break # Break if we has enough signs
|
break # Break if we has enough signs
|
||||||
if valid_signs < signs_required:
|
if len(valid_signs) < signs_required:
|
||||||
raise VerifyError("Valid signs: %s/%s" % (valid_signs, signs_required))
|
raise VerifyError("Valid signs: %s/%s, Valid Signers : %s" % (len(valid_signs), signs_required, valid_signs))
|
||||||
else:
|
else:
|
||||||
return self.verifyContent(inner_path, new_content)
|
return self.verifyContent(inner_path, new_content)
|
||||||
else: # Old style signing
|
else: # Old style signing
|
||||||
|
|
|
@ -127,6 +127,10 @@ class CryptConnectionManager:
|
||||||
"/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA"
|
"/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA"
|
||||||
]
|
]
|
||||||
self.openssl_env['CN'] = random.choice(self.fakedomains)
|
self.openssl_env['CN'] = random.choice(self.fakedomains)
|
||||||
|
environ = os.environ
|
||||||
|
environ['OPENSSL_CONF'] = self.openssl_env['OPENSSL_CONF']
|
||||||
|
environ['RANDFILE'] = self.openssl_env['RANDFILE']
|
||||||
|
environ['CN'] = self.openssl_env['CN']
|
||||||
|
|
||||||
if os.path.isfile(self.cert_pem) and os.path.isfile(self.key_pem):
|
if os.path.isfile(self.cert_pem) and os.path.isfile(self.key_pem):
|
||||||
self.createSslContexts()
|
self.createSslContexts()
|
||||||
|
@ -152,7 +156,7 @@ class CryptConnectionManager:
|
||||||
self.log.debug("Running: %s" % cmd)
|
self.log.debug("Running: %s" % cmd)
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
cmd, shell=True, stderr=subprocess.STDOUT,
|
cmd, shell=True, stderr=subprocess.STDOUT,
|
||||||
stdout=subprocess.PIPE, env=self.openssl_env
|
stdout=subprocess.PIPE, env=environ
|
||||||
)
|
)
|
||||||
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
||||||
proc.wait()
|
proc.wait()
|
||||||
|
@ -175,7 +179,7 @@ class CryptConnectionManager:
|
||||||
self.log.debug("Generating certificate key and signing request...")
|
self.log.debug("Generating certificate key and signing request...")
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
cmd, shell=True, stderr=subprocess.STDOUT,
|
cmd, shell=True, stderr=subprocess.STDOUT,
|
||||||
stdout=subprocess.PIPE, env=self.openssl_env
|
stdout=subprocess.PIPE, env=environ
|
||||||
)
|
)
|
||||||
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
||||||
proc.wait()
|
proc.wait()
|
||||||
|
@ -194,7 +198,7 @@ class CryptConnectionManager:
|
||||||
self.log.debug("Generating RSA cert...")
|
self.log.debug("Generating RSA cert...")
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
cmd, shell=True, stderr=subprocess.STDOUT,
|
cmd, shell=True, stderr=subprocess.STDOUT,
|
||||||
stdout=subprocess.PIPE, env=self.openssl_env
|
stdout=subprocess.PIPE, env=environ
|
||||||
)
|
)
|
||||||
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
back = proc.stdout.read().strip().decode(errors="replace").replace("\r", "")
|
||||||
proc.wait()
|
proc.wait()
|
||||||
|
|
|
@ -109,31 +109,35 @@ class FileRequest(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
inner_path = params.get("inner_path", "")
|
inner_path = params.get("inner_path", "")
|
||||||
current_content_modified = site.content_manager.contents.get(inner_path, {}).get("modified", 0)
|
|
||||||
body = params["body"]
|
|
||||||
|
|
||||||
if not inner_path.endswith("content.json"):
|
if not inner_path.endswith("content.json"):
|
||||||
self.response({"error": "Only content.json update allowed"})
|
self.response({"error": "Only content.json update allowed"})
|
||||||
self.connection.badAction(5)
|
self.connection.badAction(5)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
current_content_modified = site.content_manager.contents.get(inner_path, {}).get("modified", 0)
|
||||||
should_validate_content = True
|
should_validate_content = True
|
||||||
if "modified" in params and params["modified"] <= current_content_modified:
|
if "modified" in params and params["modified"] <= current_content_modified:
|
||||||
should_validate_content = False
|
should_validate_content = False
|
||||||
valid = None # Same or earlier content as we have
|
valid = None # Same or earlier content as we have
|
||||||
elif not body: # No body sent, we have to download it first
|
|
||||||
|
body = params["body"]
|
||||||
|
if not body: # No body sent, we have to download it first
|
||||||
site.log.debug("Missing body from update for file %s, downloading ..." % inner_path)
|
site.log.debug("Missing body from update for file %s, downloading ..." % inner_path)
|
||||||
peer = site.addPeer(self.connection.ip, self.connection.port, return_peer=True, source="update") # Add or get peer
|
peer = site.addPeer(self.connection.ip, self.connection.port, return_peer=True, source="update") # Add or get peer
|
||||||
try:
|
try:
|
||||||
body = peer.getFile(site.address, inner_path).read()
|
body = peer.getFile(site.address, inner_path).read()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
site.log.debug("Can't download updated file %s: %s" % (inner_path, err))
|
site.log.debug("Can't download updated file %s: %s" % (inner_path, err))
|
||||||
self.response({"error": "File invalid update: Can't download updaed file"})
|
self.response({"error": "Invalid File update: Failed to download updated file content"})
|
||||||
self.connection.badAction(5)
|
self.connection.badAction(5)
|
||||||
return
|
return
|
||||||
|
|
||||||
if should_validate_content:
|
if should_validate_content:
|
||||||
try:
|
try:
|
||||||
|
if type(body) is str:
|
||||||
|
body = body.encode()
|
||||||
|
# elif type(body) is list:
|
||||||
|
# content = json.loads(bytes(list).decode())
|
||||||
content = json.loads(body.decode())
|
content = json.loads(body.decode())
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
site.log.debug("Update for %s is invalid JSON: %s" % (inner_path, err))
|
site.log.debug("Update for %s is invalid JSON: %s" % (inner_path, err))
|
||||||
|
@ -161,7 +165,7 @@ class FileRequest(object):
|
||||||
|
|
||||||
site.onFileDone(inner_path) # Trigger filedone
|
site.onFileDone(inner_path) # Trigger filedone
|
||||||
|
|
||||||
if inner_path.endswith("content.json"): # Download every changed file from peer
|
# Download every changed file from peer
|
||||||
peer = site.addPeer(self.connection.ip, self.connection.port, return_peer=True, source="update") # Add or get peer
|
peer = site.addPeer(self.connection.ip, self.connection.port, return_peer=True, source="update") # Add or get peer
|
||||||
# On complete publish to other peers
|
# On complete publish to other peers
|
||||||
diffs = params.get("diffs", {})
|
diffs = params.get("diffs", {})
|
||||||
|
@ -173,8 +177,6 @@ class FileRequest(object):
|
||||||
del self.server.files_parsing[file_uri]
|
del self.server.files_parsing[file_uri]
|
||||||
|
|
||||||
gevent.spawn(downloader)
|
gevent.spawn(downloader)
|
||||||
else:
|
|
||||||
del self.server.files_parsing[file_uri]
|
|
||||||
|
|
||||||
self.response({"ok": "Thanks, file %s updated!" % inner_path})
|
self.response({"ok": "Thanks, file %s updated!" % inner_path})
|
||||||
self.connection.goodAction()
|
self.connection.goodAction()
|
||||||
|
|
|
@ -72,6 +72,12 @@ class FileServer(ConnectionServer):
|
||||||
self.ui_server = None
|
self.ui_server = None
|
||||||
|
|
||||||
def getRandomPort(self, ip, port_range_from, port_range_to):
|
def getRandomPort(self, ip, port_range_from, port_range_to):
|
||||||
|
"""Generates Random Port from given range
|
||||||
|
Args:
|
||||||
|
ip: IP Address
|
||||||
|
port_range_from: From Range
|
||||||
|
port_range_to: to Range
|
||||||
|
"""
|
||||||
self.log.info("Getting random port in range %s-%s..." % (port_range_from, port_range_to))
|
self.log.info("Getting random port in range %s-%s..." % (port_range_from, port_range_to))
|
||||||
tried = []
|
tried = []
|
||||||
for bind_retry in range(100):
|
for bind_retry in range(100):
|
||||||
|
|
|
@ -16,7 +16,9 @@ import plugins
|
||||||
class PluginManager:
|
class PluginManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.log = logging.getLogger("PluginManager")
|
self.log = logging.getLogger("PluginManager")
|
||||||
self.path_plugins = os.path.abspath(os.path.dirname(plugins.__file__))
|
self.path_plugins = None
|
||||||
|
if plugins.__file__:
|
||||||
|
self.path_plugins = os.path.dirname(os.path.abspath(plugins.__file__));
|
||||||
self.path_installed_plugins = config.data_dir + "/__plugins__"
|
self.path_installed_plugins = config.data_dir + "/__plugins__"
|
||||||
self.plugins = defaultdict(list) # Registered plugins (key: class name, value: list of plugins for class)
|
self.plugins = defaultdict(list) # Registered plugins (key: class name, value: list of plugins for class)
|
||||||
self.subclass_order = {} # Record the load order of the plugins, to keep it after reload
|
self.subclass_order = {} # Record the load order of the plugins, to keep it after reload
|
||||||
|
@ -32,6 +34,7 @@ class PluginManager:
|
||||||
|
|
||||||
self.config.setdefault("builtin", {})
|
self.config.setdefault("builtin", {})
|
||||||
|
|
||||||
|
if self.path_plugins:
|
||||||
sys.path.append(os.path.join(os.getcwd(), self.path_plugins))
|
sys.path.append(os.path.join(os.getcwd(), self.path_plugins))
|
||||||
self.migratePlugins()
|
self.migratePlugins()
|
||||||
|
|
||||||
|
@ -127,6 +130,8 @@ class PluginManager:
|
||||||
def loadPlugins(self):
|
def loadPlugins(self):
|
||||||
all_loaded = True
|
all_loaded = True
|
||||||
s = time.time()
|
s = time.time()
|
||||||
|
if self.path_plugins is None:
|
||||||
|
return
|
||||||
for plugin in self.listPlugins():
|
for plugin in self.listPlugins():
|
||||||
self.log.debug("Loading plugin: %s (%s)" % (plugin["name"], plugin["source"]))
|
self.log.debug("Loading plugin: %s (%s)" % (plugin["name"], plugin["source"]))
|
||||||
if plugin["source"] != "builtin":
|
if plugin["source"] != "builtin":
|
||||||
|
|
|
@ -143,7 +143,7 @@ class Site(object):
|
||||||
|
|
||||||
# Next size limit based on current size
|
# Next size limit based on current size
|
||||||
def getNextSizeLimit(self):
|
def getNextSizeLimit(self):
|
||||||
size_limits = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000]
|
size_limits = [25, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000]
|
||||||
size = self.settings.get("size", 0)
|
size = self.settings.get("size", 0)
|
||||||
for size_limit in size_limits:
|
for size_limit in size_limits:
|
||||||
if size * 1.2 < size_limit * 1024 * 1024:
|
if size * 1.2 < size_limit * 1024 * 1024:
|
||||||
|
|
|
@ -260,7 +260,7 @@ class SiteStorage(object):
|
||||||
# Open file object
|
# Open file object
|
||||||
@thread_pool_fs_read.wrap
|
@thread_pool_fs_read.wrap
|
||||||
def read(self, inner_path, mode="rb"):
|
def read(self, inner_path, mode="rb"):
|
||||||
return open(self.getPath(inner_path), mode).read()
|
return self.open(inner_path, mode).read()
|
||||||
|
|
||||||
@thread_pool_fs_write.wrap
|
@thread_pool_fs_write.wrap
|
||||||
def writeThread(self, inner_path, content):
|
def writeThread(self, inner_path, content):
|
||||||
|
@ -369,8 +369,12 @@ class SiteStorage(object):
|
||||||
# Load and parse json file
|
# Load and parse json file
|
||||||
@thread_pool_fs_read.wrap
|
@thread_pool_fs_read.wrap
|
||||||
def loadJson(self, inner_path):
|
def loadJson(self, inner_path):
|
||||||
|
try:
|
||||||
with self.open(inner_path, "r", encoding="utf8") as file:
|
with self.open(inner_path, "r", encoding="utf8") as file:
|
||||||
return json.load(file)
|
return json.load(file)
|
||||||
|
except Exception as err:
|
||||||
|
self.log.warning("Json load error: %s" % Debug.formatException(err))
|
||||||
|
return None
|
||||||
|
|
||||||
# Write formatted json file
|
# Write formatted json file
|
||||||
def writeJson(self, inner_path, data):
|
def writeJson(self, inner_path, data):
|
||||||
|
@ -459,7 +463,8 @@ class SiteStorage(object):
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ok = self.site.content_manager.verifyFile(file_inner_path, open(file_path, "rb"))
|
ok = self.site.content_manager.verifyFile(file_inner_path, open(file_path, "rb"))
|
||||||
except Exception as err:
|
except Exception as _err:
|
||||||
|
err = _err
|
||||||
ok = False
|
ok = False
|
||||||
|
|
||||||
if not ok:
|
if not ok:
|
||||||
|
|
|
@ -544,17 +544,36 @@ class UiRequest(object):
|
||||||
if show_loadingscreen:
|
if show_loadingscreen:
|
||||||
meta_tags += '<meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.8">';
|
meta_tags += '<meta name="viewport" id="viewport" content="width=device-width, initial-scale=0.8">';
|
||||||
|
|
||||||
|
def xescape(s):
|
||||||
|
'''combines parts from re.escape & html.escape'''
|
||||||
|
# https://github.com/python/cpython/blob/3.10/Lib/re.py#L267
|
||||||
|
# '&' is handled otherwise
|
||||||
|
re_chars = {i: '\\' + chr(i) for i in b'()[]{}*+-|^$\\.~# \t\n\r\v\f'}
|
||||||
|
# https://github.com/python/cpython/blob/3.10/Lib/html/__init__.py#L12
|
||||||
|
html_chars = {
|
||||||
|
'<' : '<',
|
||||||
|
'>' : '>',
|
||||||
|
'"' : '"',
|
||||||
|
"'" : ''',
|
||||||
|
}
|
||||||
|
# we can't replace '&' because it makes certain zites work incorrectly
|
||||||
|
# it should however in no way interfere with re.sub in render
|
||||||
|
repl = {}
|
||||||
|
repl.update(re_chars)
|
||||||
|
repl.update(html_chars)
|
||||||
|
return s.translate(repl)
|
||||||
|
|
||||||
return self.render(
|
return self.render(
|
||||||
"src/Ui/template/wrapper.html",
|
"src/Ui/template/wrapper.html",
|
||||||
server_url=server_url,
|
server_url=server_url,
|
||||||
inner_path=inner_path,
|
inner_path=inner_path,
|
||||||
file_url=re.escape(file_url),
|
file_url=xescape(file_url),
|
||||||
file_inner_path=re.escape(file_inner_path),
|
file_inner_path=xescape(file_inner_path),
|
||||||
address=site.address,
|
address=site.address,
|
||||||
title=html.escape(title),
|
title=xescape(title),
|
||||||
body_style=body_style,
|
body_style=body_style,
|
||||||
meta_tags=meta_tags,
|
meta_tags=meta_tags,
|
||||||
query_string=re.escape(inner_query_string),
|
query_string=xescape(inner_query_string),
|
||||||
wrapper_key=site.settings["wrapper_key"],
|
wrapper_key=site.settings["wrapper_key"],
|
||||||
ajax_key=site.settings["ajax_key"],
|
ajax_key=site.settings["ajax_key"],
|
||||||
wrapper_nonce=wrapper_nonce,
|
wrapper_nonce=wrapper_nonce,
|
||||||
|
@ -730,7 +749,10 @@ class UiRequest(object):
|
||||||
|
|
||||||
def replaceHtmlVariables(self, block, path_parts):
|
def replaceHtmlVariables(self, block, path_parts):
|
||||||
user = self.getCurrentUser()
|
user = self.getCurrentUser()
|
||||||
|
if user and user.settings:
|
||||||
themeclass = "theme-%-6s" % re.sub("[^a-z]", "", user.settings.get("theme", "light"))
|
themeclass = "theme-%-6s" % re.sub("[^a-z]", "", user.settings.get("theme", "light"))
|
||||||
|
else:
|
||||||
|
themeclass = "theme-light"
|
||||||
block = block.replace(b"{themeclass}", themeclass.encode("utf8"))
|
block = block.replace(b"{themeclass}", themeclass.encode("utf8"))
|
||||||
|
|
||||||
if path_parts:
|
if path_parts:
|
||||||
|
|
|
@ -327,7 +327,10 @@ class UiWebsocket(object):
|
||||||
|
|
||||||
def actionAs(self, to, address, cmd, params=[]):
|
def actionAs(self, to, address, cmd, params=[]):
|
||||||
if not self.hasSitePermission(address, cmd=cmd):
|
if not self.hasSitePermission(address, cmd=cmd):
|
||||||
|
#TODO! Return this as error ?
|
||||||
return self.response(to, "No permission for site %s" % address)
|
return self.response(to, "No permission for site %s" % address)
|
||||||
|
if not self.server.sites.get(address):
|
||||||
|
return self.response(to, {"error": "Site Does Not Exist: %s" % address})
|
||||||
req_self = copy.copy(self)
|
req_self = copy.copy(self)
|
||||||
req_self.site = self.server.sites.get(address)
|
req_self.site = self.server.sites.get(address)
|
||||||
req_self.hasCmdPermission = self.hasCmdPermission # Use the same permissions as current site
|
req_self.hasCmdPermission = self.hasCmdPermission # Use the same permissions as current site
|
||||||
|
@ -419,6 +422,11 @@ class UiWebsocket(object):
|
||||||
is_user_content = file_info and ("cert_signers" in file_info or "cert_signers_pattern" in file_info)
|
is_user_content = file_info and ("cert_signers" in file_info or "cert_signers_pattern" in file_info)
|
||||||
if is_user_content and privatekey is None:
|
if is_user_content and privatekey is None:
|
||||||
cert = self.user.getCert(self.site.address)
|
cert = self.user.getCert(self.site.address)
|
||||||
|
if not cert:
|
||||||
|
error = "Site sign failed: No certificate selected for Site: %s, Hence Signing inner_path: %s Failed, Try Adding/Selecting User Cert via Site Login" % (self.site.address, inner_path)
|
||||||
|
self.log.error(error)
|
||||||
|
return self.response(to, {"error": error})
|
||||||
|
else:
|
||||||
extend["cert_auth_type"] = cert["auth_type"]
|
extend["cert_auth_type"] = cert["auth_type"]
|
||||||
extend["cert_user_id"] = self.user.getCertUserId(site.address)
|
extend["cert_user_id"] = self.user.getCertUserId(site.address)
|
||||||
extend["cert_sign"] = cert["cert_sign"]
|
extend["cert_sign"] = cert["cert_sign"]
|
||||||
|
|
|
@ -254,8 +254,9 @@ class Actions(object):
|
||||||
file_correct = site.content_manager.verifyFile(
|
file_correct = site.content_manager.verifyFile(
|
||||||
content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False
|
content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as exp:
|
||||||
file_correct = False
|
file_correct = False
|
||||||
|
err = exp
|
||||||
|
|
||||||
if file_correct is True:
|
if file_correct is True:
|
||||||
logging.info("[OK] %s (Done in %.3fs)" % (content_inner_path, time.time() - s))
|
logging.info("[OK] %s (Done in %.3fs)" % (content_inner_path, time.time() - s))
|
||||||
|
|
|
@ -42,6 +42,8 @@ def patch(old_f, actions):
|
||||||
continue
|
continue
|
||||||
elif action == "+": # Add lines
|
elif action == "+": # Add lines
|
||||||
for add_line in param:
|
for add_line in param:
|
||||||
|
if type(add_line) is str:
|
||||||
|
add_line = add_line.encode()
|
||||||
new_f.write(add_line)
|
new_f.write(add_line)
|
||||||
else:
|
else:
|
||||||
raise "Unknown action: %s" % action
|
raise "Unknown action: %s" % action
|
||||||
|
|
142
trackers.txt
Normal file
142
trackers.txt
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
udp://tracker.opentrackr.org:1337/announce
|
||||||
|
udp://explodie.org:6969/announce
|
||||||
|
udp://open.stealth.si:80/announce
|
||||||
|
http://tracker.ipv6tracker.ru:80/announce
|
||||||
|
udp://tracker.birkenwald.de:6969/announce
|
||||||
|
udp://tracker.moeking.me:6969/announce
|
||||||
|
http://tracker.bt4g.com:2095/announce
|
||||||
|
https://tracker.nanoha.org:443/announce
|
||||||
|
http://tracker.files.fm:6969/announce
|
||||||
|
http://open.acgnxtracker.com:80/announce
|
||||||
|
udp://tracker.army:6969/announce
|
||||||
|
udp://fe.dealclub.de:6969/announce
|
||||||
|
udp://tracker.leech.ie:1337/announce
|
||||||
|
udp://tracker.altrosky.nl:6969/announce
|
||||||
|
https://tracker.cyber-hub.net:443/announce
|
||||||
|
https://tracker.lilithraws.cf:443/announce
|
||||||
|
http://bt.okmp3.ru:2710/announce
|
||||||
|
udp://vibe.sleepyinternetfun.xyz:1738/announce
|
||||||
|
udp://open.publictracker.xyz:6969/announce
|
||||||
|
udp://tracker.bitsearch.to:1337/announce
|
||||||
|
udp://tracker.pomf.se:80/announce
|
||||||
|
https://tr.burnabyhighstar.com:443/announce
|
||||||
|
https://tr.abiir.top:443/announce
|
||||||
|
udp://open.free-tracker.ga:6969/announce
|
||||||
|
http://i-p-v-6.tk:6969/announce
|
||||||
|
http://open-v6.demonoid.ch:6969/announce
|
||||||
|
udp://aarsen.me:6969/announce
|
||||||
|
udp://htz3.noho.st:6969/announce
|
||||||
|
udp://uploads.gamecoast.net:6969/announce
|
||||||
|
udp://mail.zasaonsk.ga:6969/announce
|
||||||
|
udp://tracker.joybomb.tw:6969/announce
|
||||||
|
udp://tracker.jonaslsa.com:6969/announce
|
||||||
|
udp://leefafa.tk:6969/announce
|
||||||
|
udp://carr.codes:6969/announce
|
||||||
|
https://tr.fuckbitcoin.xyz:443/announce
|
||||||
|
udp://tracker.cubonegro.xyz:6969/announce
|
||||||
|
udp://tracker.skynetcloud.site:6969/announce
|
||||||
|
http://tracker4.itzmx.com:2710/announce
|
||||||
|
https://tracker.lilithraws.org:443/announce
|
||||||
|
udp://tracker.novaopcj.eu.org:6969/announce
|
||||||
|
udp://exodus.desync.com:6969/announce
|
||||||
|
http://t.acg.rip:6699/announce
|
||||||
|
udp://tracker2.dler.com:80/announce
|
||||||
|
udp://6ahddutb1ucc3cp.ru:6969/announce
|
||||||
|
udp://tracker.blacksparrowmedia.net:6969/announce
|
||||||
|
http://fxtt.ru:80/announce
|
||||||
|
udp://tracker.auctor.tv:6969/announce
|
||||||
|
udp://torrentclub.space:6969/announce
|
||||||
|
udp://zecircle.xyz:6969/announce
|
||||||
|
udp://psyco.fr:6969/announce
|
||||||
|
udp://fh2.cmp-gaming.com:6969/announce
|
||||||
|
udp://new-line.net:6969/announce
|
||||||
|
udp://torrents.artixlinux.org:6969/announce
|
||||||
|
udp://bt.ktrackers.com:6666/announce
|
||||||
|
udp://static.54.161.216.95.clients.your-server.de:6969/announce
|
||||||
|
udp://cpe-104-34-3-152.socal.res.rr.com:6969/announce
|
||||||
|
http://t.overflow.biz:6969/announce
|
||||||
|
udp://tracker1.myporn.club:9337/announce
|
||||||
|
udp://moonburrow.club:6969/announce
|
||||||
|
udp://tracker.artixlinux.org:6969/announce
|
||||||
|
https://t1.hloli.org:443/announce
|
||||||
|
udp://bt1.archive.org:6969/announce
|
||||||
|
udp://tracker.theoks.net:6969/announce
|
||||||
|
udp://tracker.4.babico.name.tr:3131/announce
|
||||||
|
udp://buddyfly.top:6969/announce
|
||||||
|
udp://ipv6.tracker.harry.lu:80/announce
|
||||||
|
udp://public.publictracker.xyz:6969/announce
|
||||||
|
udp://mail.artixlinux.org:6969/announce
|
||||||
|
udp://v1046920.hosted-by-vdsina.ru:6969/announce
|
||||||
|
udp://tracker.cyberia.is:6969/announce
|
||||||
|
udp://tracker.beeimg.com:6969/announce
|
||||||
|
udp://creative.7o7.cx:6969/announce
|
||||||
|
udp://open.dstud.io:6969/announce
|
||||||
|
udp://laze.cc:6969/announce
|
||||||
|
udp://download.nerocloud.me:6969/announce
|
||||||
|
udp://cutscloud.duckdns.org:6969/announce
|
||||||
|
https://tracker.jiesen.life:8443/announce
|
||||||
|
udp://jutone.com:6969/announce
|
||||||
|
udp://wepzone.net:6969/announce
|
||||||
|
udp://ipv4.tracker.harry.lu:80/announce
|
||||||
|
udp://tracker.tcp.exchange:6969/announce
|
||||||
|
udp://f1sh.de:6969/announce
|
||||||
|
udp://movies.zsw.ca:6969/announce
|
||||||
|
https://tracker1.ctix.cn:443/announce
|
||||||
|
udp://sanincode.com:6969/announce
|
||||||
|
udp://www.torrent.eu.org:451/announce
|
||||||
|
udp://open.4ever.tk:6969/announce
|
||||||
|
https://tracker2.ctix.cn:443/announce
|
||||||
|
udp://bt2.archive.org:6969/announce
|
||||||
|
http://t.nyaatracker.com:80/announce
|
||||||
|
udp://yahor.ftp.sh:6969/announce
|
||||||
|
udp://tracker.openbtba.com:6969/announce
|
||||||
|
udp://tracker.dler.com:6969/announce
|
||||||
|
udp://tracker-udp.gbitt.info:80/announce
|
||||||
|
udp://tracker.srv00.com:6969/announce
|
||||||
|
udp://tracker.pimpmyworld.to:6969/announce
|
||||||
|
http://tracker.gbitt.info:80/announce
|
||||||
|
udp://tracker6.lelux.fi:6969/announce
|
||||||
|
http://tracker.vrpnet.org:6969/announce
|
||||||
|
http://00.xxtor.com:443/announce
|
||||||
|
http://vps02.net.orel.ru:80/announce
|
||||||
|
udp://tracker.yangxiaoguozi.cn:6969/announce
|
||||||
|
udp://rep-art.ynh.fr:6969/announce
|
||||||
|
https://tracker.imgoingto.icu:443/announce
|
||||||
|
udp://mirror.aptus.co.tz:6969/announce
|
||||||
|
udp://tracker.lelux.fi:6969/announce
|
||||||
|
udp://tracker.torrent.eu.org:451/announce
|
||||||
|
udp://admin.52ywp.com:6969/announce
|
||||||
|
udp://thouvenin.cloud:6969/announce
|
||||||
|
http://vps-dd0a0715.vps.ovh.net:6969/announce
|
||||||
|
udp://bubu.mapfactor.com:6969/announce
|
||||||
|
udp://94-227-232-84.access.telenet.be:6969/announce
|
||||||
|
udp://epider.me:6969/announce
|
||||||
|
udp://camera.lei001.com:6969/announce
|
||||||
|
udp://tamas3.ynh.fr:6969/announce
|
||||||
|
https://tracker.tamersunion.org:443/announce
|
||||||
|
udp://ftp.pet:2710/announce
|
||||||
|
udp://p4p.arenabg.com:1337/announce
|
||||||
|
http://tracker.mywaifu.best:6969/announce
|
||||||
|
udp://tracker.monitorit4.me:6969/announce
|
||||||
|
udp://ipv6.tracker.monitorit4.me:6969/announce
|
||||||
|
zero://k5w77dozo3hy5zualyhni6vrh73iwfkaofa64abbilwyhhd3wgenbjqd.onion:15441
|
||||||
|
zero://2kcb2fqesyaevc4lntogupa4mkdssth2ypfwczd2ov5a3zo6ytwwbayd.onion:15441
|
||||||
|
zero://5vczpwawviukvd7grfhsfxp7a6huz77hlis4fstjkym5kmf4pu7i7myd.onion:15441
|
||||||
|
zero://pn4q2zzt2pw4nk7yidxvsxmydko7dfibuzxdswi6gu6ninjpofvqs2id.onion:15441
|
||||||
|
zero://6i54dd5th73oelv636ivix6sjnwfgk2qsltnyvswagwphub375t3xcad.onion:15441
|
||||||
|
zero://tl74auz4tyqv4bieeclmyoe4uwtoc2dj7fdqv4nc4gl5j2bwg2r26bqd.onion:15441
|
||||||
|
zero://wlxav3szbrdhest4j7dib2vgbrd7uj7u7rnuzg22cxbih7yxyg2hsmid.onion:15441
|
||||||
|
zero://zy7wttvjtsijt5uwmlar4yguvjc2gppzbdj4v6bujng6xwjmkdg7uvqd.onion:15441
|
||||||
|
zero://rlcjomszyitxpwv7kzopmqgzk3bdpsxeull4c3s6goszkk6h2sotfoad.onion:15441
|
||||||
|
zero://gugt43coc5tkyrhrc3esf6t6aeycvcqzw7qafxrjpqbwt4ssz5czgzyd.onion:15441
|
||||||
|
zero://ow7in4ftwsix5klcbdfqvfqjvimqshbm2o75rhtpdnsderrcbx74wbad.onion:15441
|
||||||
|
zero://57hzgtu62yzxqgbvgxs7g3lfck3za4zrda7qkskar3tlak5recxcebyd.onion:15445
|
||||||
|
zero://hb6ozikfiaafeuqvgseiik4r46szbpjfu66l67wjinnyv6dtopuwhtqd.onion:15445
|
||||||
|
zero://qn65si4gtcwdiliq7vzrwu62qrweoxb6tx2cchwslaervj6szuje66qd.onion:26117
|
||||||
|
zero://s3j2s5pjdfesbsmaqx6alsumaxxdxibmhv4eukmqpv3vqj6f627qx5yd.onion:15441
|
||||||
|
zero://agufghdtniyfwty3wk55drxxwj2zxgzzo7dbrtje73gmvcpxy4ngs4ad.onion:15441
|
||||||
|
zero://kgsvasoakvj4gnjiy7zemu34l3hq46dn5eauqkn76jpowmilci5t2vqd.onion:15445
|
||||||
|
zero://dslesoe72bdfwfu4cfqa2wpd4hr3fhlu4zv6mfsjju5xlpmssouv36qd.onion:15441
|
||||||
|
zero://f2hnjbggc3c2u2apvxdugirnk6bral54ibdoul3hhvu7pd4fso5fq3yd.onion:15441
|
||||||
|
zero://skdeywpgm5xncpxbbr4cuiip6ey4dkambpanog6nruvmef4f3e7o47qd.onion:15441
|
||||||
|
zero://tqmo2nffqo4qc5jgmz3me5eri3zpgf3v2zciufzmhnvznjve5c3argad.onion:15441
|
|
@ -66,7 +66,7 @@ def displayErrorMessage(err, error_log_path):
|
||||||
res = ctypes.windll.user32.MessageBoxW(0, err_title, "ZeroNet error", MB_YESNOCANCEL | MB_ICONEXCLAIMATION)
|
res = ctypes.windll.user32.MessageBoxW(0, err_title, "ZeroNet error", MB_YESNOCANCEL | MB_ICONEXCLAIMATION)
|
||||||
if res == ID_YES:
|
if res == ID_YES:
|
||||||
import webbrowser
|
import webbrowser
|
||||||
report_url = "https://github.com/HelloZeroNet/ZeroNet/issues/new?assignees=&labels=&template=bug-report.md&title=%s"
|
report_url = "https://github.com/ZeroNetX/ZeroNet/issues/new?assignees=&labels=&template=bug-report.md&title=%s"
|
||||||
webbrowser.open(report_url % urllib.parse.quote("Unhandled exception: %s" % err_message))
|
webbrowser.open(report_url % urllib.parse.quote("Unhandled exception: %s" % err_message))
|
||||||
if res in [ID_YES, ID_NO]:
|
if res in [ID_YES, ID_NO]:
|
||||||
subprocess.Popen(['notepad.exe', error_log_path])
|
subprocess.Popen(['notepad.exe', error_log_path])
|
||||||
|
|
Loading…
Reference in a new issue