From 62d71fa27107731ad7c1e5c02c1609143b6275a1 Mon Sep 17 00:00:00 2001 From: blurHY Date: Tue, 11 Dec 2018 18:20:42 +0800 Subject: [PATCH] index.md completed --- docs/zh/faq.md | 257 +++ docs/zh/help_zeronet/coding_conventions.md | 20 + docs/zh/help_zeronet/contributing.md | 64 + docs/zh/help_zeronet/donate.md | 127 ++ docs/zh/help_zeronet/network_protocol.md | 471 ++++++ docs/zh/index.md | 90 + docs/zh/site_development/cert_authority.md | 148 ++ docs/zh/site_development/content_json.md | 371 +++++ docs/zh/site_development/dbschema_json.md | 211 +++ docs/zh/site_development/getting_started.md | 62 + .../zeroframe_api_reference.md | 1460 +++++++++++++++++ docs/zh/translation.md | 3 + docs/zh/using_zeronet/create_new_site.md | 62 + docs/zh/using_zeronet/installing.md | 42 + docs/zh/using_zeronet/sample_sites.md | 129 ++ mkdocs-zh.yml | 54 + 16 files changed, 3571 insertions(+) create mode 100644 docs/zh/faq.md create mode 100644 docs/zh/help_zeronet/coding_conventions.md create mode 100644 docs/zh/help_zeronet/contributing.md create mode 100644 docs/zh/help_zeronet/donate.md create mode 100644 docs/zh/help_zeronet/network_protocol.md create mode 100644 docs/zh/index.md create mode 100644 docs/zh/site_development/cert_authority.md create mode 100644 docs/zh/site_development/content_json.md create mode 100644 docs/zh/site_development/dbschema_json.md create mode 100644 docs/zh/site_development/getting_started.md create mode 100644 docs/zh/site_development/zeroframe_api_reference.md create mode 100644 docs/zh/translation.md create mode 100644 docs/zh/using_zeronet/create_new_site.md create mode 100644 docs/zh/using_zeronet/installing.md create mode 100644 docs/zh/using_zeronet/sample_sites.md create mode 100644 mkdocs-zh.yml diff --git a/docs/zh/faq.md b/docs/zh/faq.md new file mode 100644 index 0000000..01f1d50 --- /dev/null +++ b/docs/zh/faq.md @@ -0,0 +1,257 @@ +# Frequently asked questions + + +#### Do I need to have a port opened? + +This is __optional__, you can browse and use ZeroNet sites without an open port. +If you want to create a new site it's highly recommended to have an open port. + +At startup ZeroNet tries to open a port for you on your router using +[UPnP](https://wikipedia.org/wiki/Universal_Plug_and_Play), if this fails you have to do it manually: + +- Try to access your router's web interface using [http://192.168.1.1](http://192.168.1.1) +or [http://192.168.0.1](http://192.168.0.1) +- Look for an "Enable UPnP support" or similar option then restart ZeroNet. + +If it still doesn't work then try to find a 'port forwarding' section of your router page. This is different for every router. [Here is a tutorial on YouTube.](https://www.youtube.com/watch?v=aQXJ7sLSz14) The port to forward is 15441. + + +--- + + +#### Is ZeroNet anonymous? + +It's no more anonymous than BitTorrent, but privacy (the possibility to find out who is the owner of the comment/site) will increase as the network and the sites gains more peers. + +ZeroNet is made to work with anonymity networks: you can easily hide your IP using the Tor network. + + +--- + + +#### How to use ZeroNet with the Tor browser? + +In Tor mode it is recommended to use ZeroNet from within the Tor Browser: + +- Start the Tor Browser +- Go to address `about:preferences#advanced` +- Click `Settings...` +- Enter `127.0.0.1` to field **No proxy for** +- Open http://127.0.0.1:43110 in the browser + +If you still see a blank page: + - Click on NoScript's button (first on the toolbar) + - Choose "Temporary allow all this page" + - Reload the page + +--- + + +#### How to use ZeroNet with Tor? + +If you want to hide your IP address, install the latest version of ZeroNet then click Tor > Enable Tor for every connection on ZeroHello. + +On Windows, Tor is bundled with ZeroNet. ZeroNet will attempt to download and unpack Tor on its first run. If this fails for any reason, you can install it manually following the instruction in `core\tools\tor\manual_install.txt`. + +For other OS's, follow the instructions in the "How to make ZeroNet work with Tor under Linux/MacOS" section. + +> __Tip:__ You can verify your IP address using ZeroNet's [Stats](http://127.0.0.1:43110/Stats) page. + +> __Tip:__ If you get connection errors, make sure you have the latest version of Tor installed. (0.2.7.5+ required) + + +--- + + +#### How to make ZeroNet work with Tor under Linux/MacOS? + + - Install Tor for your OS following Tor's official guidelines: [Linux](https://www.torproject.org/download/download-unix.html.en) [Mac](https://www.torproject.org/docs/tor-doc-osx.html.en). + - `sudo nano /etc/tor/torrc` + - Remove the `#` character from lines `ControlPort 9051` and `CookieAuthentication 1` (line ~57) + - Restart tor + - Add permission for yourself to read the auth cookie. With Debian Linux, the command is `sudo usermod -a -G debian-tor [yourlinuxuser]`
(if you are not on Debian check the file's user group by `ls -al /var/run/tor/control.authcookie`) + - Logout/Login with your user to apply group changes + +> __Tip:__ You can verify if your Tor setup is running correctly using `echo 'PROTOCOLINFO' | nc 127.0.0.1 9051` + +> __Tip:__ It's also possible to use Tor without modifying torrc (or to use older versions of Tor clients), by running `zeronet.py --tor disable --proxy 127.0.0.1:9050 --disable_udp`, but then you will lose ability to talk with other .onion addresses. + + +--- + +#### Is it possible to use a configuration file? + +Any command line configuration flag can also be used as a configuration option. Place these options line-by-line into a file called `zeronet.conf` in your top-level zeronet directory (the one with zeronet.py). Example: + +``` +[global] +data_dir = my-data-dir +log_dir = my-log-dir +ui_restrict = + 1.2.3.4 + 2.3.4.5 +``` + +To list possible options, use the `zeronet.py --help` command + +--- + + +#### How to make Tor work if my ISP or goverment blocks it? + +ZeroNet does not include [Tor pluggable transports](https://www.torproject.org/docs/pluggable-transports.html.en) yet. The easiest way to make Tor work in a censored network is to start the Tor browser, configure it to connect to the Tor network with working pluggable transports, and modify ZeroNet's config to use Tor browser's proxy and control port by starting ZeroNet with `--tor_controller 127.0.0.1:9151 --tor_proxy 127.0.0.1:9150` or by adding these parameters to `zeronet.conf`. + +``` +[global] +tor_controller = 127.0.0.1:9151 +tor_proxy = 127.0.0.1:9150 +``` + + +--- + + +#### Can I use the same username on multiple machines? + +Yes, simply copy the `data/users.json` file to your new machine. + + +--- + + +#### How to create a "fancy" (non .bit) site address? + +Use [vanitygen](https://bitcointalk.org/index.php?topic=25804.0) to generate one. Once you get your keys, create `data/1YourPublicKey...tCkBzAXTKvJk4uj8` directory. Put some files there. + +Then navigate to [http://127.0.0.1:43110/1YourPublicKey...tCkBzAXTKvJk4uj8/](http://127.0.0.1:43110/1YourPublicKey...tCkBzAXTKvJk4uj8/). Drag the `0` button to the left and use the sidebar to sign your site. + + +--- + + +#### How can I register a .bit domain? + +You can register .bit domains using [Namecoin](https://namecoin.info/). +Manage your domains using the client's GUI or by the [command line interface](https://github.com/namecoin/wiki/blob/master/How-to-register-and-configure-.bit-domains.md). + +After the registration is done you have to edit your domain's record by adding a zeronet section to it, e.g.: + +``` +{ +... + "zeronet": { + "": "1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr", + "blog": "1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8", + "talk": "1TaLk3zM7ZRskJvrh3ZNCDVGXvkJusPKQ" + }, +... +} +``` +An empty string (`""`) means the top domain, anything other than that is a sub-domain. + +> __Tip:__ You can buy Namecoin for Bitcoin or other cryptocurrencies using [shapeshift.io](https://shapeshift.io/). + +> __Tip:__ Other possibilities to register .bit domains: [domaincoin.net](https://domaincoin.net/), [peername.com](https://peername.com/), [dotbit.me](https://dotbit.me/) + +> __Tip:__ You can verify your domain on [namecha.in](http://namecha.in/), for example: [zeroid.bit](http://namecha.in/name/d/zeroid) + +> __Tip:__ You should use only [lower-cased letters, numbers and - in your domains](http://wiki.namecoin.info/?title=Domain_Name_Specification_2.0#Valid_Domains). + +> __Tip:__ To make ZeroHello display your domain name instead of your site's Bitcoin address, add a domain key to your content.json. ([Example](https://github.com/HelloZeroNet/ZeroBlog/blob/master/content.json#L6)) + + +--- + + +#### Can I use the generated site address/private key to accept Bitcoin payments? + +Yes, it's a standard Bitcoin address. The private key is WIF formatted, so you can import it in most clients. + +> __Tip:__ It's not recommended to keep a high amount of money on your site's address, because you have to enter your private key every time you modify your site. + + +--- + + +#### What happens when someone hosts malicious content? + +The ZeroNet sites are sandboxed, they have the same privileges as any other website you visit over the Internet. +You are in full control of what you are hosting. If you find suspicious content you can stop hosting the site at any time. + + +--- + + +#### Is it possible to install ZeroNet to a remote machine? + +Yes, you have to enable the UiPassword plugin by renaming the __plugins/disabled-UiPassword__ directory to __plugins/UiPassword__, +then start ZeroNet on the remote machine using
`zeronet.py --ui_ip "*" --ui_password anypassword`. +This will bind the ZeroNet UI webserver to all interfaces, but to keep it secure you can only access it by entering the given password. + +> __Tip:__ You can also restrict the interface based on ip address by using `--ui_restrict ip1 ip2`. + +> __Tip:__ You can specify the password in the config file by creating a `zeronet.conf` file and adding `[global]` and `ui_password = anypassword` lines to it. + + +--- + + +#### Is there any way to track the bandwidth ZeroNet is using? + +The sent/received bytes are displayed at ZeroNet's sidebar.
(open it by dragging the topright `0` button to left) + +> __Tip:__ Per connection statistics page: [http://127.0.0.1:43110/Stats](http://127.0.0.1:43110/Stats) + + +--- + + +#### What happens if two people use the same keys to modify a site? + +Every content.json file is timestamped, the clients always accept the newest one with a valid signature. + + +--- + + +#### Does ZeroNet use Bitcoin's blockchain? + +No, ZeroNet only uses the cryptography of Bitcoin for site addresses and content signing/verification. +User identification is based on Bitcoin's [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) format. + +Namecoin's blockchain is being used for domain registrations, however clients do not download the blockchain. Blockchain metadata is instead passed over the ZeroNet network. + + +--- + + +#### Does ZeroNet only support HTML, CSS websites? + +ZeroNet is built for dynamic, real-time updated websites, but you can serve any kind of files using it, such as (VCS repositories, your own thin-client, database, etc. + + +--- + + +#### How can I create a new ZeroNet site? + +[Follow these instructions.](../using_zeronet/create_new_site/) + +--- + + +#### What happens when I access a site? + +- When you want to open a new site it asks for visitor's IP addresses from BitTorrent trackers. +- Initially, a file named __content.json__ is downloaded, which holds all other filenames, + __hashes__ and the site owner's cryptographic signature. +- The downloaded content.json file is __verified__ using the site's __address__ and the site owner's __signature__ from the file. +- Other files (html, css, js...) are then __downloaded__ and verified using their size and SHA512 hash from content.json. +- Each visited site then becomes __also served by you__. +- If the site owner (who has the private key for the site address) __modifies__ the site, then he/she signs + the new content.json and __publishes it to peers__. After the peers have verified the file's + integrity (using the signature), they __download the modified files__ and serve the new content to other peers. + +More info: + [ZeroNet sample sites](../using_zeronet/sample_sites/), + [Slideshow about how ZeroNet works](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub) diff --git a/docs/zh/help_zeronet/coding_conventions.md b/docs/zh/help_zeronet/coding_conventions.md new file mode 100644 index 0000000..dfe5c10 --- /dev/null +++ b/docs/zh/help_zeronet/coding_conventions.md @@ -0,0 +1,20 @@ +# Coding standards if you want to collaborate to ZeroNet + - Follow [PEP8](https://www.python.org/dev/peps/pep-0008/) + - Simple is better than complex + - Premature optimization is the root of all evil + +### Naming + - ClassNames: Capitalized, CamelCased + - functionNames: starts with lowercase, camelCased + - variable_names: lowercased, under_scored + +### Variables + - file_path: File path realtive to working dir (data/17ib6teRqdVgjB698T4cD1zDXKgPqpkrMg/css/all.css) + - inner_path: File relative to site dir (css/all.css) + - file_name: all.css + - file: Python file object + - privatekey: Private key for the site (without _) + +### Source files directories and naming + - One class per file is preferred + - Source file name and directory comes from ClassName: WorkerManager class = Worker/WorkerManager.py diff --git a/docs/zh/help_zeronet/contributing.md b/docs/zh/help_zeronet/contributing.md new file mode 100644 index 0000000..b0ff239 --- /dev/null +++ b/docs/zh/help_zeronet/contributing.md @@ -0,0 +1,64 @@ +# Contributing to ZeroNet + +Thank you for using ZeroNet. ZeroNet is a collaborative effort of 67+ decentralization enthusiasts just like you. We appreciate all users that catch bugs, improve documentation and have good ideas of designing new protocols. Here are a few guidelines we ask you to follow to get started with making your contribution. + +### You don’t have to contribute source code + +In fact, a majority of contributors do not submit source code. Even if you like to write programs, other types of contribution are also welcomed. + +### Do you like to write? + +- Write about ZeroNet. +- Write tutorials to help people set things up. +- Help translate ZeroNet. +- Improve this documentation. This documentation is a written by many community members all over the world. + +### Do you like helping people? + +- Subscribe to our [issue tracker on GitHub](https://github.com/HelloZeroNet/ZeroNet/issues) and help people solve problems. +- Join us on [Gitter](https://gitter.im/HelloZeroNet/ZeroNet) and IRC channel [#zeronet @ freenode](https://kiwiirc.com/client/irc.freenode.net/zeronet) and help answer questions. +- Set up a seed box and help make the network faster. + +### Do you like to make websites? + +- Create new ZeroNet sites. Go ahead and make your own blog on ZeroNet. [It is easy and costs little.](../using_zeronet/create_new_site.md) +- “Content is king!” as NoFish puts. The network is worth nothing without content, so we need You to make it succeed. + +### Do you like to do research? + +- Help us investigate our [hard issues](https://github.com/HelloZeroNet/ZeroNet/labels/help%20wanted). +- Join our discussion of designing new features and protocols, such as [I2P support](https://github.com/HelloZeroNet/ZeroNet/issues/45) and [DHT support](https://github.com/HelloZeroNet/ZeroNet/issues/57). +- Do you own a [Raspberry Pi](https://github.com/HelloZeroNet/ZeroNet#linux-terminal), a [C.H.I.P.](http://127.0.0.1:43110/Blog.ZeroNetwork.bit/?Post:94:Running+ZeroNet+on+a+$9%C2%A0computer) or an [open router](https://github.com/HelloZeroNet/ZeroNet/issues/783)? Try running ZeroNet on it and tell us how well ZeroNet works on your device. + +### Do you like to write code? + +- If you know Python, you can pick a task from our [issue tracker on GitHub](https://github.com/HelloZeroNet/ZeroNet/issues). +- You are also welcomed develop your own ideas. Before you start, please [open a new discussion](https://github.com/HelloZeroNet/ZeroNet/issues/new) to let the community know, so you can make sure we can share our ideas to make the best out of it. +- Keep your coding style consistent. We ask you to follow our coding convention below. + +### Do you like to offer financial support? + +- You can [donate bitcoins](donate.md) to support ZeroNet. + + +## Coding convention + +- Follow [PEP8](https://www.python.org/dev/peps/pep-0008/) +- Simple is better than complex +- Premature optimization is the root of all evil + +### Naming +- ClassNames: Capitalized, CamelCased +- functionNames: starts with lowercase, camelCased +- variable_names: lowercased, under_scored + +### Variables +- file_path: File path relative to working dir (data/17ib6teRqdVgjB698T4cD1zDXKgPqpkrMg/css/all.css) +- inner_path: File relative to site dir (css/all.css) +- file_name: all.css +- file: Python file object +- privatekey: Private key for the site (without `_`) + +### Source files directories and naming +- One class per file is preferred +- Source file name and directory comes from ClassName: WorkerManager class = Worker/WorkerManager.py diff --git a/docs/zh/help_zeronet/donate.md b/docs/zh/help_zeronet/donate.md new file mode 100644 index 0000000..feb7a90 --- /dev/null +++ b/docs/zh/help_zeronet/donate.md @@ -0,0 +1,127 @@ + + + +# Help to keep ZeroNet development alive + + +## ZeroNet: 2018 first half + + +* General donation towards ZeroNet development + +
or using PayPal: + + + +
+ +--- + + +## Bitmessage support + + + + * Send and receive Bitmessage messages using local client's XMLRPC API interface + +Benefits: + + * Send your permission request to site owner via bitmessage + * Possible private messaging/commenting webui integration to sites + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/65) + + + +--- + + +## Namecoin domain support (done in version 0.2.8) + + * Use Namecoin domain names to access sites + +Benefits: + + * Easier to remember site addresses + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/31) + + +--- + + +## DHT support + + + + * Peer discovery using DHT + +Benefits: + + * Peer discovery no longer relies on torrent network + * Ipv6 and Tor peer discovery + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/57) + + +--- + + +## Private sites + + + + * Passworded or public key based peer auth to sites + +Benefits: + + * Secure control over peers who has access to your site + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/62) + + +--- + + +## Full Tor support (done in version 0.3.5) + + * Allow to seed sites and connect other peers using Tor network (Probably depends on DHT support) + +Benefits: + + * Hiding your IP when distributing new content or downloading site + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/60) + + + +--- + + +## Multiuser proxy support (done in version 0.2.7) + + * User login/logout using bip32 master seed + +Benefits: + + * Makes open ZeroNet proxies usable + * Use local ZeroNet more than one user + +[Github issue](https://github.com/HelloZeroNet/ZeroNet/issues/58) + + +--- + + +## Where does the donation go? + +The task's received donation goes directly to the developer(s) who successfully and properly integrates the feature (please add your plans and ideas to the issue before you start working on anything big). + + + +# Sponsors + +* Better OSX/Safari compatibility made possible by [BrowserStack.com](https://www.browserstack.com/) + + + diff --git a/docs/zh/help_zeronet/network_protocol.md b/docs/zh/help_zeronet/network_protocol.md new file mode 100644 index 0000000..6b9794e --- /dev/null +++ b/docs/zh/help_zeronet/network_protocol.md @@ -0,0 +1,471 @@ +# ZeroNet network protocol + + - Every message is encoded using [MessagePack](http://msgpack.org/) + - Every request has 3 parameter: + * `cmd`: The request command + * `req_id`: The request's unique id (simple, incremented nonce per-connection), the client has to include this when reply to the command. + * `params`: Parameters for the request + - Example request: `{"cmd": "getFile", "req_id": 1, "params:" {"site": "1EU...", "inner_path": "content.json", "location": 0}}` + - Example response: `{"cmd": "response", "to": 1, "body": "content.json content", "location": 1132, "size": 1132}` + - Example error response: `{"cmd": "response", "to": 1, "error": "Unknown site"}` + + +# Handshake +Every connection begins with a handshake by sending a request to the target network address: + +Parameter | Description + --- | --- +**crypt** | Null/None, only used in respones +**crypt_supported** | An array of connection encryption methods supported by the client +**fileserver_port** | The client's fileserver port +**onion** | (Only used on tor) The client's onion address +**protocol** | The protocol version the client uses (v1 or v2) +**port_opened** | The client's client port open status +**peer_id** | (Not used on tor) The client's peer_id +**rev** | The client's revision number +**version** | The client's version +**target_ip** | The server's network address + +The target initialize the encryption on the socket based on `crypt_supported`, then return: + +Return key | Description + --- | --- +**crypt** | The encryption to use +**crypt_supported** | An array of connection encryption methods supported by the server +**fileserver_port** | The server's fileserver port +**onion** | (Only used on tor) The server's onion address +**protocol** | The protocol version the server uses (v1 or v2) +**port_opened** | The server's client port open status +**peer_id** | (Not used on tor) The server's peer_id +**rev** | The server's revision number +**version** | The server's version +**target_ip** | The client's network address + +> **Note:** No encryption used on .onion connections, as the Tor network provides the transport security by default. +> **Note:** You can also implicitly initialize SSL before the handshake if you can assume it supported by remote client. + +**Example**: + +Sent handshake: + +```json +{ + "cmd": "handshake", + "req_id": 0, + "params": { + "crypt": None, + "crypt_supported": ["tls-rsa"], + "fileserver_port": 15441, + "onion": "zp2ynpztyxj2kw7x", + "protocol": "v2", + "port_opened": True, + "peer_id": "-ZN0056-DMK3XX30mOrw", + "rev": 2122, + "target_ip": "192.168.1.13", + "version": "0.5.6" + } +} +``` + +Return: + +``` +{ + "protocol": "v2", + "onion": "boot3rdez4rzn36x", + "to": 0, + "crypt": None, + "cmd": "response", + "rev": 2092, + "crypt_supported": [], + "target_ip": "zp2ynpztyxj2kw7x.onion", + "version": "0.5.5", + "fileserver_port": 15441, + "port_opened": False, + "peer_id": "" +} +``` + +# Peer requests + +#### getFile _site_, _inner_path_, _location_, _[file_size]_ +Request a file from the client + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**inner_path** | File path relative to site directory +**location** | Request file from this byte (max 512 bytes got sent in a request, so you need multiple requests for larger files) +**file_size** | Total size of the requested file (optional) + +**Return**: + +Return key | Description + --- | --- +**body** | The requested file content +**location** | The location of the last byte sent +**size** | Total size of the file + + +--- + +#### streamFile _site_, _inner_path_, _location_, _[file_size]_ +Stream a file from the client + +**Return**: + +Return key | Description + --- | --- +**stream_bytes** | The length of file data after the MessagePack payload + +To avoid having python-msgpack serialize large binary strings, the file body is appended directly after the MessagePack payload. For example, + +``` +> {"cmd": "streamFile", "id": 1, "inner_path": "content.json", "size": 1234} +< {"cmd": "response", "to": 1, "stream_bytes": 1234} +< content of the file +``` + +> ZeroNet implementation detail: For file segments larger than 256 kb, streaming is enabled by default. + +--- + + +#### ping +Checks if the client is still alive + +**Return**: + +Return key | Description + --- | --- +**body** | Pong + + +--- + + +#### pex _site_, _peers_, _need_ +Exchange peers with the client. +Peers packed to 6 bytes (4byte IP using inet_ntoa + 2byte for port) + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**peers** | List of peers that the requester has (packed) +**peers_onion** | List of Tor Onion peers that the requester has (packed) +**need** | Number of peers the requester want + +**Return**: + +Return key | Description + --- | --- +**peers** | List of IPv4 peers he has for the site (packed) +**peers_onion** | List of Tor Onion peers for this site (packed) + +Each element in the `peers` list is a packed IPv4 address. + +IP address | Port +---------- | ---- +`4 bytes` | `2 bytes` + +Each element in the `peers_onion` list is a packed Tor Onion Service address. + +B32-decoded onion address | Port +------------------------- | ---- +`binary_str[0:-2]` | `binary_str[-2:]` + +To restore the onion address, pass the first part through `base64.b32encode` and append `.onion` to the return value. + +--- + +#### update _site_, _inner_path_, _body_, _[diffs]_ +Update a site file. + + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**inner_path** | File path relative to site directory +**body** | Full content of the updated content.json +**diffs** (optional) | [Diff opcodes](#possible-diff-opcodes) for the modified files in the content.json + +**Return**: + +Return key | Description + --- | --- +**ok** | Thanks message on successful update :) + +##### Diffs format + +A dict that contains the modifications + + - Key: changed file's relative path to content.json (eg.: `data.json`) + - Value: The list of diff opcodes for the file (eg.: `[['=', 5], ['+', '\nhello new line'], ['-', 6]]`) + +##### Possible diff opcodes: + +Opcode | Description + --- | --- +**['=', number of same characters]** | Have not changed part of the file (eg.: `['=', 5]`) +**['+', new text]** | Added characters (eg.: `['+', '\nhello new line']`) +**['-', number of removed characters]** | Full content of the updated file (eg.: `['-', 6]`) + +After the update received, the client tries to patch the files using the diffs. +If it failes to match the sha hash provided by the content.json (had different version of the file) it automatically re-downloads the whole file from the sender of the update. + +> __Note:__ The patches are limited to 30KB per file and only used for .json files + +--- + +#### listModified _site_, _since_ +Lists the content.json files modified since the given parameter. It used to fetch the site's user submitted content. + + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**since** | List content.json files since this timestamp. + +**Return**: + +Return key | Description + --- | --- +**modified_files** | Key: content.json inner_path
Value: last modification date + +**Example**: + +```json +> zeronet.py --silent peerCmd 127.0.0.1 15441 listModified "{'site': '1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8', 'since': 1497507030}" +{ + "to": 1, + "cmd": "response", + "modified_files": { + "data/users/1NM9k7VJfrb1UWw5agAvyRfSn3ws1wTJ5U/content.json": 1497579272, + "data/users/1QEfmMwKVxgR4rkREbdJYjgUmF3Zy8pwHt/content.json": 1497565986, + "data/users/16NS3rBdW9zpLmLSQoD8nLTtNVsRFtVBhd/content.json": 1497575039, + "data/users/1CjXarXgvcNeCJ2nMQxUi4DRFWp3GEur2W/content.json": 1497513808, + "data/users/1L5rGDgTs4W2V7gekSvJNhKa7XaHkVwotD/content.json": 1497615798, + "data/users/1LWuc6JBhUGrKEAh1aPrPU85dEMcKmg3pS/content.json": 1497594716, + "data/users/1KdnTJVBGzEZrJppFZtzfG9chukuMv8xSb/content.json": 1497584640, + "data/users/1GMNmr2bDPbT4c8yVnyCoDHke52CNCdqAa/content.json": 1497614188, + "data/users/1GRm9rED83Tkfi3iWS9m3LWHiRpPZehWLd/content.json": 1497827772, + "data/users/12Ugp53jiMdvj1Kxa1w7c2LcXUBdGPs1oK/content.json": 1497692901, + "data/users/1F6BMqittjWUStzUbRXm2kG2GQ3RdBLqFQ/content.json": 1497571485, + "data/users/1GgNo3CmxPd7n2pMSF3uyqf1XHvgtTUqCe/content.json": 1497560829, + "data/users/16nArdxrSaNThNp83kL8E6NLL9WD98iUne/content.json": 1497627929, + "data/users/16CAJkbfNRxNJq4aKdrZ2MSYFfFGvQ8JPi/content.json": 1497664899, + "data/users/1DrBS2sTD3BX5BBxG8eqYsxXSvGt9kc5HE/content.json": 1497632000, + "data/users/19sggoAZ4hcorrrfWoFWP9rwfpVsL29cnZ/content.json": 1497928134, + "data/users/1NYpJupegoTXL4cFpkNdLNJ4XaAhTNhPe1/content.json": 1497535771, + "data/users/1R67TfYzNkCnh89EFfGmXn5LMb4hXaMRQ/content.json": 1497691787, + "data/users/1C9HXUYFSVafLxanwkaFPZRcRgCEGsj2Cn/content.json": 1497572833, + "data/users/1LgoHzNGWeijeZbJ8a1YgGjMCnjaM4BWG/content.json": 1497620232, + "content.json": 1497623639 + } +} +``` + +--- + + +#### getHashfield _site_ +Get the client's downloaded [optional file ids](#optional-file-id). + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) + +**Return**: + +Return key | Description + --- | --- +**hashfield_raw** | Optional file ids encoded using `array.array("H", [1000, 1001..]).tostring()` + +**Example**: +```json +> zeronet.py --silent peerCmd 192.168.1.13 15441 getHashfield "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h'} +{ + 'to': 1, + 'hashfield_raw': 'iG\xde\x02\xc6o\r;...', + 'cmd': 'response' +} +``` + +--- + + +#### setHashfield _site_, _hashfield_raw_ +Set the list of [optional file ids](#optional-file-id) that the requester client has. + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**hashfield_raw** | Optional file ids encoded using `array.array("H", [1000, 1001..]).tostring()` + +**Return**: + +Return key | Description + --- | --- +**ok** | Updated + + +--- + + +#### findHashIds _site_, _hash_ids_ +Queries if the client know any peer that has the requested hash_ids + +Parameter | Description + --- | --- +**site** | Site address (example: 1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr) +**hash_ids** | List of optional file ids the client currently looking for + +**Return**: + +Return key | Description + --- | --- +**peers** | Key: Optional file id
Value: List of ipv4 peers encoded using `socket.inet_aton(ip) + struct.pack("H", port)` +**peers_onion** | Key: Optional file id
Value: List of onion peers encoded using `base64.b32decode(onion.replace(".onion", "").upper()) + struct.pack("H", port)` + +**Example**: +```json +> zeronet.py --silent peerCmd 192.168.1.13 15441 findHashIds "{'site': '1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h', 'hash_ids': [59948, 29811]}" +{ + 'to': 1, + 'peers': { + 29811: [ + 'S&9\xd3Q<', + '>f\x94\x98N\xa4', + 'gIB\x90Q<', + '\xb4\xady\xf7Q<' + ], + 59948: [ + 'x\xcc>\xf6Q<', + 'S\xa1\xddkQ<', + '\x05\xac\xe8\x8dQ<', + '\x05\xc4\xe1\x93Q<', + 'Q\x02\xed\nQ<' + ] + }, + 'cmd': 'response', + 'peers_onion': { + 29811: ['\xc7;A\xce\xbc\xd9O\xe2w>> int("ea2c2acb30bd5e1249021976536574dd3f0fd83340e023bb4e78d0d818adf30a"[0:4], 16) +59948 +``` + +--- + +#### checkport _port_ +Check requested port of the other peer. + + +Parameter | Description + --- | --- +**port** | Port which will be checked. + +**Return**: + +Return key | Description + --- | --- +**status** | Status of the port ("open" or "closed") +**ip_external** | External IP of the requestor + +--- + +# Bigfile Plugin + +#### getPieceFields _site_ + +Returns all big file [piecefield](#bigfile-piecefield) that client has for that site in a dict. + +Parameter | Description + --- | --- +**site** | Requested site + + +**Return**: + +Return key | Description + --- | --- +**piecefields_packed** | Key: Bigfile's sha512/256 [merkle root hash](#bigfile-merkle-root)
Value: Packed [piecefield](#bigfile-piecefield) + +--- + +#### setPieceFields _site_, _piecefields_packed_ + +Set the client's [piecefields](#picefield) for that site. + +Parameter | Description + --- | --- +**site** | Requested site +**piecefields_packed** | Key: Bigfile's sha512/256 [merkle root hash](#bigfile-merkle-root)
Value: Packed [piecefield](#bigfile-piecefield) + + +**Return**: + +Return key | Description + --- | --- +**ok** | Updated + + +##### Bigfile piecefield + +Holds the the big files downloaded pieces information in a simple string with 1/0 values. (1 = Downloaded, 0 = Not downloaded) + +> __Example__: `1110000001` means the file is sized 9-10MB and the client downloaded the first 3MB and the last 1MB at 1MB piecesize. + +**Packed format**: + +Turns the string to an list of int by counting the repeating characters starting with `1`. + +> __Example__: `1110000001` to `[3, 6, 1]`, `0000000001` to `[0, 9, 1]`, `1111111111` to `[10]` + +After the conversion it turns it to more efficient [typed array](https://docs.python.org/2/library/array.html) using `array.array('H', piecefield)` + +##### Bigfile merkle root + +During the big file hashing procedure, in addition to storing the per-piece sha512/256 hash digests in the [piecemap](#bigfile-piecemap) file, the algorithm also calculates the SHA-512/256 merkle root of the file using the [merkle-tools](https://github.com/tierion/merkle-tools) implementation. +The merkle root is only used as an ID to identify the big file, not (yet) for verifying the pieces. + +> __Note__: The merkle root is chosen to identify the file, instead of the file's actual SHA-512/256 hash. Obviously, using the latter results in hashing the same file twice. (once for piecemap once for the whole file) + +> __Note__: The merkle root is not used to verify the integrity of the pieces or the big file, because doing so would take more bandwidth and space to transfer and store the merkle-proofs for partial verification, than the per-piece hash map file itself. + +##### Bigfile piecemap + +It holds the per-piece SHA-512/256 hashes. The piece size and the picemap filename is defined in `content.json`, eg.: + +``` +... + "files_optional": { + "bigfile.mp4": { + "piece_size": 1048576, + "piecemap": "bigfile.mp4.piecemap.msgpack", + "sha512": "d1f0d150e1e73bb1e684d370224315d7ba21e656189eb646ef7cc394d033bc2b", + "size": 42958831 + }, +... +``` + +Having the following data structure, the piecemap file is packed into the [msgpack](https://msgpack.org/) format: + +``` +{ + b'bigfile.mp4': {b'sha512_pieces': [ + b"e\xde\x0fx\xec\xc5LZ9\x0e\xe7\x85E\x1b\xd5\xe4C'\xe7req\xe3<\xff\\\xbb\xc8b\xc2\xc1\x8e", + b'\xef\xe8\xed\xfe\x16/\x96\xdb;;\x06n[8_\x06\x9ak|\xe1\x9f\xe1\xaf\x87\x96\xdd\xfd\x9bEf\xd9!', + b'\x1c\xd6-\x1f\xce\xde{\xcd\x01\x93un =D\x0brmB-\xd1\x8c\xbf\xfe\xca\x8a\x1c\xf60\xbb\xedD', + b'\x1aQdF\xd2\xbc\xdff{\xb7\x89\xf2\xd3\r\xa9\xe1\xefA-V\x18\xa4\xc8e\x13\x88v\x13\\&\xfbW', + ... + ]} +} +``` diff --git a/docs/zh/index.md b/docs/zh/index.md new file mode 100644 index 0000000..4bb5068 --- /dev/null +++ b/docs/zh/index.md @@ -0,0 +1,90 @@ +## 什么是ZeroNet? + +ZeroNet是使用比特币加密技术和BitTorrent构建的**抗审查分布式网络**. + +用户可以在ZeroNet发布静态或动态的网站,访客也可以选择去成为网站的服务器。只要有一个节点在,网站就会保持在线。 + +站长更新网站后,所有服务于这个网站(作为服务器)的节点(以前的访客)只会接收网站更新后增加的内容。 + +ZeroNet内置SQL数据库,便于开发规模大的网站。数据库会以增量更新的方式同步到有这个网站的节点。 + + +## 为什么要开发零网(ZeroNet)? + +* 我们信仰开放、自由、无审查的通讯。 +* 无审查:一旦内容发布,便不可删除。 +* 没有单点故障:即便只有一个节点,内容仍会保持在线。 +* 不可能被关闭:零网在何处无人知道,因为它无处不在。网站的内容都是由愿意为数据作服务器的用户来提供的。 +* 高速:零网使用BitTorrent技术传输数据,比中心化服务器还要快。 +* 离线可用:网络不可用时也可以访问网站。 +* 安全: 网站内容的所有权由Bitcoin钱包的同种加密技术所保护。 + +[comment]: <> (I'm unsure about the following bit. Thoughts?) +[comment]: <> (# What problem is ZeroNet solving?) + +[comment]: <> (When Tim Berners-Lee created the internet, he meant for it to be free. Not surveilled nor censored. And [he is still fighting for that](http://edition.cnn.com/2014/03/12/tech/web/tim-berners-lee-web-freedom/).) + +[comment]: <> (The internet is centralized mainly in two places: Content and Domain Names (URLs) are hosted and controlled by central servers. If you control the central servers (and if you are powerful enough you do) you control the network.) + +[comment]: <> (**Decentralized content storage**) + +[comment]: <> (ZeroNet tackles the content storage problem by giving everyone the ability to store content. Site visitors can choose to store a website on their computers, and when they do this they also help to serve the site to other users. The site is online even if only one user is hosting it.) + +[comment]: <> (**Shared DNS cache**) + +[comment]: <> (Site addresses on ZeroNet are cached by all network members. When you type a ZeroNet site URL on your browser this will query other peers connected to you about the site. If one of these peers happen to have the site they will send it to you, if not, they will forward your query along.) + +[comment]: <> (This architecture means that when a site URL is created, as long as one peer is serving it, there is no way to take the URL down.) + + +## 特性 + * 简单,零配置安装。 + * 无需密码,基于[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)的授权: 账号的所有权由Bitcoin钱包的同种加密技术所保护。 + * 站点实时更新,不需要刷新。 + * Namecoin .bit 域名支持。 + * SQL 数据库支持: 简化了站点开发,减少了页面加载时间。 + * 匿名性: 完整的Tor网络支持,使用.onion而非ipv4地址。 + * TLS加密连接。 + * 自动使用uPnP打开端口。 + * 多用户插件(openproxy)。 + * 可以在任何操作系统和浏览器上使用。 + + +## 零网是如何工作的? + +* 安装并启动零网后,访问类似于如下所示的地址打开网站。 + `http://127.0.0.1:43110/{零网站点地址}` + (例如 `http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D`). +* 零网用BitTorrent网络寻找为这个网站做种的节点并向节点索要网站数据(HTML, CSS, JS...)。 +* 客户端会为每个访问过的网站服务,站点也可以手动添加黑名单或移除。 +* 每个网站都有一个网站文件列表,包含站长用私钥生成的SHA512哈希和一个签名。 +* 站长修改网站后,签名新文件列表,并发布到其他节点。 + 节点验证完列表完整性后(用签名),下载已修改的文件再传送给其他节点。 + +##### [关于零网加密技术、内容更新和多用户站点的幻灯片 »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000) + + +## 截图 + +![截图](./img/zerohello.png) + +![ZeroTalk](./img/zerotalk.png) + +##### [更多截图 »](/using_zeronet/sample_sites/) + +## 当前局限 + +* 没有类似于torrent的文件分割、大文件的支持 (BigFile插件已实现) +* 文件传输未压缩 或加密 (TLS 加密已添加) +* 无法创建私有站点。 + +## 帮助这个项目存活 + +Bitcoin: 1QDhxQ6PraUZa21ET5fYUCPgdrwBomnFgX + +[Full donation page](help_zeronet/donate/) + +### 谢谢! + +* 更多信息、帮助、零网站点: [http://www.reddit.com/r/zeronet/](http://www.reddit.com/r/zeronet/) +* 交谈: [#zeronet @ FreeNode](https://kiwiirc.com/client/irc.freenode.net/zeronet) 或在 [gitter](https://gitter.im/HelloZeroNet/ZeroNet) diff --git a/docs/zh/site_development/cert_authority.md b/docs/zh/site_development/cert_authority.md new file mode 100644 index 0000000..8a82867 --- /dev/null +++ b/docs/zh/site_development/cert_authority.md @@ -0,0 +1,148 @@ +# Certificate Authority + +An account without password? A certificate for me? You realize the ID system of ZeroNet does not conform to convention. In this section, you are going to learn about how user certificate and certificate authority work in ZeroNet. + +## What does a certificate authority do? + +In ZeroNet, everything is signed by Bitcoin signing keys. A certificate provides a unique and memorizable name for a Bitcoin address. A certificate authority (or an ID provider) is responsible for proving the relationship between a unique friendly name and a Bitcoin address. + +## Certificate format + +### Body + +The body of a certificate contains a Bitcoin address, a portal type, and a memorizable user name. + +``` +[BitcoinAddress]#[PortalType]/[UserName] +``` + +**Example:** + +``` +1H28iygiKXe3GUMcD77HiifVqtf3858Aft#web/hellozeronet +``` + +- Bitcoin address: `1H28iygiKXe3GUMcD77HiifVqtf3858Aft` +- Portal type: `web` +- User name: `hellozeronet` + +**General rules:** + +The Bitcoin address, the portal type and the user name **must not** contain the character `#`, `@` or `/` + +Only 0-9 and a-z are allowed in a user name. All English letters in a user name **must** be in lower case. Characters not in the allowed set **must not** be used as parts of a user name. A user name **should not** be too long. A user name **should** be legible and **should not** interfere with user interface rendering. + +A user name **must** be unique in the pool of all registered user names. + +### Signature + +A certificate signing algorithm loads a secret signing key and generates a deterministic Bitcoin signature for the body. + +**From the source code:** + +```python +sign = os.popen("python zeronet.py --debug cryptSign %s#bitmsg/%s %s 2>&1" % (auth_address, user_name, config.site_privatekey)).readlines()[-1].strip() +``` + +### Certificate + +By looking at the source code of ZeroID, we know how a certificate is stored in its public database. + +```python +data["users"][user_name] = "bitmsg,%s,%s" % (auth_address, sign) +``` + +**Example:** + +``` +"hellozeronet": "web,1H28iygiKXe3GUMcD77HiifVqtf3858Aft,HA2A+iKekECD3hasrsN8IrR86BnXQ63kPH+9A85JLO9hLUpRJTBn62UfnuuF92B9CIc6+EewAIqzIn9UoVq2LPA=" +``` + +A certificate can be stored in various formats. However, all formats must include: + +- The Bitcoin address: `1H28iygiKXe3GUMcD77HiifVqtf3858Aft` +- The portal type: `web` +- The user name: `hellozeronet` +- The signature from authority: `HA2A+iKekECD3hasrsN8IrR86BnXQ63kPH+9A85JLO9hLUpRJTBn62UfnuuF92B9CIc6+EewAIqzIn9UoVq2LPA=` + +## Usage in `content.json` + +Site owners can choose which certificate authorities to trust. + +The Blue Hub, for example, accepts certificates signed by ZeroID. This rule is defined in its `data/users/content.json` + +- The ID provider has a friendly name: `zeroid.bit` +- The public key digest of the ID provider is: `1iD5ZQJMNXu43w1qLB8sfdHVKppVMduGz` + +```json +"user_contents": { + "cert_signers": { + "zeroid.bit": [ + "1iD5ZQJMNXu43w1qLB8sfdHVKppVMduGz" + ] + } +} +``` + +Every user presents his certificate in the manifest file in his Bitcoin folder. For example, `data/users/1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj/content.json` says: + +```json +{ + "address": "1BLueGvui1GdbtsjcKqCf4F67uKfritG49", + "cert_auth_type": "web", + "cert_sign": "HPiZsWEJ5eLnspUj8nQ75WXbSanLz0YhQf5KJDq+4bWe6wNW98Vv9PXNyPDNu2VX4bCEXhRC65pS3CM7cOrjjik=", + "cert_user_id": "nofish@zeroid.bit", + "files": { + "data.json": { + "sha512": "8e597412a2bc2726ac9a1ee85428fb3a94b09f4e7a3f5f589119973231417b15", + "size": 21422 + } + }, + "inner_path": "data/users/1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj/content.json", + "modified": 1492458379, + "signs": { + "1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj": "G8kaZIGAstsiWLVY20e2ogJQi4OO+QuwqJ9GTj3gz7YleST/jst7RQH7hDn0uf8BJMBjFs35H3LPhNHHj4jueh8=" + } +} +``` + +Site specific: + +- Expected site URL: `"address": "1BLueGvui1GdbtsjcKqCf4F67uKfritG49"` +- Expected file path: `"inner_path": "data/users/1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj/content.json"` + +Certificate information: + +- ID provider: `zeroid.bit` +- User name: `nofish` +- User Bitcoin address: `1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj` +- Portal type: `web` +- Signature from ID provider: `HPiZsWEJ5eLnspUj8nQ75WXbSanLz0YhQf5KJDq+4bWe6wNW98Vv9PXNyPDNu2VX4bCEXhRC65pS3CM7cOrjjik=` + +### The verifying process + +1. The verifying algorithm reads `data/users/content.json` to determine what is the expected site for the user content. + +2. The verifying algorithm reads `data/users/content.json` to look up the public key digest of the ID provider. + +3. Given a user Bitcoin address, a portal type and a user name, the verifying algorithm reconstructs the body of the certificate. + +4. The verifying algorithm checks the signature from the ID provider, with the public key defined in `data/users/content.json`, to ensure the authenticity of the certificate body. + +5. The verifying algorithm loads the user public key and checks the authenticity of the user content. + +## Features and limitations of certificate authorities + +- A certificate authority provides memorizable names for user public key digests. It also helps mitigate spam and unsolicited content. + +- A user does not have to give away secret information such as passwords. In addition, a user only has to authenticate once. + +- A certificate authority does not have to be approved by any ZeroNet developers. A site owner can choose which certificate authorities to trust for the sake of user content quality. + +- A certificate authority is responsible for maintaining its user name pool. + +- ZeroID does not revoke or renew certificates. + +## Can I live without certificate authorities? + +Generally, a certificate is required when you add things to someone else's site. You do not need a certificate when you are modifying your own site. diff --git a/docs/zh/site_development/content_json.md b/docs/zh/site_development/content_json.md new file mode 100644 index 0000000..0dbb06e --- /dev/null +++ b/docs/zh/site_development/content_json.md @@ -0,0 +1,371 @@ +# Structure of content.json + +Every ZeroNet site has a `content.json` file. ([Example content.json file](https://github.com/HelloZeroNet/ZeroTalk/blob/master/content.json)) + +This file will carry, among other things, a list of all files on your site and a signature created with your private key. This is used to ensure authenticity of site files and avoid tampering (ie: only you, or people you trust, can update your site's content). + +Here is a list of supported `content.json` keys: + + +--- + +## Generated automatically + +_These keys are added automatically when the site is created or cloned._ + +### address + +Your site address + +**Example**: 1TaLk3zM7ZRskJvrh3ZNCDVGXvkJusPKQ + + +--- + + +### address_index + +The site address's BIP32 sub-key index of your BIP32 seed. Auto-added when you clone a site. It allows recovery of the site's privatekey from your BIP32 seed. + +**Example**: 30926910 + +--- + + +### cloned_from + +Only for cloned sites. The site address where the site is cloned from. + +**Example**: 1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8 + +--- + + +### clone_root + +Only for cloned sites. The sub-directory on the site which this was cloned from. + +**Example**: template-new + + +--- + + +### files + +Size and sha512 hashes of automatically downloaded files contained in your site. Automatically added by the command `zeronet.py siteSign siteaddress privatekey`. + +**Example**: +```python + "css/all.css": { + "sha512": "869b09328f07bac538c313c4702baa5276544346418378199fa5cef644c139e8", + "size": 148208 + } +``` + + +--- + + +### files_optional + +Size and sha512 hashes of optional files contained in your site. Automatically added by the command `zeronet.py siteSign siteaddress privatekey`. + +**Example**: +```python + "data/myvideo.mp4": { + "sha512": "538c09328aa52765443464135cef644c144346418378199fa5cef61837819538", + "size": 832103 + } +``` + + + +--- + + +### modified + +Time when the content.json was generated. + +**Example**: 1425857522.076 + + +--- + + +### sign (deprecated) + +ECDSA sign of the content.json file content. (keys sorted, without whitespace and the `sign` and `signers_sign` nodes). For backward compatibility, will be removed soon. + +**Example**: +```python + "sign": [ + 43117356513690007125104018825100786623580298637039067305407092800990252156956, + 94139380599940414070721501960181245022427741524702752954181461080408625270000 + ], +``` + + +--- + + +### signers_sign + +Possible signer addresses for the root content.json signed using the site address private key. Multiple entries are allowed here, allowing for site Multisig functionality. + +**Format of the signed string**: [number_of_signers_required]:[signer address],[signer address] + +*Example*: +``` +signs_required: 1:1PcxwuHYxuJEmM4ydtB1vbiAY6WkNgsz9G,1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE +signers_sign: MEUCIQDuz+CzOVvFkv1P2ra9i5E1p1G0/1cOGecm7GpLpMLhuwIgBIbCL0YHXD1S2+x48QS5VO/rISrkdLiUR+o+x1X0y1A= +``` + +The above signed message is signed using the address "1PcxwuHYxuJEmM4ydtB1vbiAY6WkNgsz9G". + +--- + + +### signs + +ECDSA signature for the the content.json file content: + + - `sign`, `signs` JSON nodes removed + - JSON dumped with keys sorted alphabetically, without whitespace + - Signature generated on the dumped data, using Electrum Bitcoin message signature format: + * [Message encoding](https://github.com/vbuterin/pybitcointools/blob/87806f3c984e258a5f30814a089b5c29cbcf0952/bitcoin/main.py#L405): `sha256("\x18" || "Bitcoin Signed Message:\n" || num_to_var_int(len(message)) || message)` + * [Serialization format](https://github.com/MuxZeroNet/zerolib/blob/f13126e04bf99b1b416a7ea5b5cad7924cdc15a4/zerolib/integrity/bitcoin.py#L82-L93): `recovery_id || r || s`, where 27 ≤ recovery_id ≤ 30; signature length = 1 + 32 + 32 = 65 bytes. + * Double vertical bar `||` denotes byte concatenation. + +**Example**: +```python + "signs": { + "1TaLk3zM7ZRskJvrh3ZNCDVGXvkJusPKQ": "G6/QXFKvACPQ7LhoZG4fgqmeOSK99vGM2arVWkm9pV/WPCfc2ulv6iuQnuzw4v5z82qWswcRq907VPdBsdb9VRo=" + }, +``` + + +---- + + +### zeronet_version + +The ZeroNet version used to generate content.json file. + +**Example**: 0.2.5 + +--- + +## Optional Settings + +_These options can be added if the functionality is needed._ + + +### background-color + +Background color of the wrapper + +**Example**: #F5F5F5 + + +--- + + +### cloneable + +Allow to clone the site if **true**. + +To make your site properly cloneable you have to have a separate folder of data +files for a clean start (e.g. without any blog posts). To do this you have to +add the **-default** postfix to your data files and directories. During the +cloning process, only directories with the **-default** postfix are +copied. The postfix is removed from the new site. + + + +--- + + +### description + +Description of your site, displayed under the site title on ZeroHello. + +**Example**: Decentralized forum demo + + +--- + + +### domain + +Namecoin domain name of your site. ZeroHello will link to this if the user has Zeroname plugin enabled. + +**Example**: Blog.ZeroNetwork.bit + + + + +--- + + +### ignore + +Do not sign files matching this pattern. + +**Example**: `((js|css)/(?!all.(js|css))|data/users/.*)` (ignore all js and css files except all.js and all.css and don't add anything from the `data/users/` directory) + +Note: [Some restrictions](#regular-expression-limitations) apply to regular expressions. + +--- + + +### includes + +Include another content.json in the site. This is typically used for subsequent content.json files that are used to govern user data. + +**Example**: + +```python +"includes": { + "data/users/content.json": { + "signers": [ # Possible signers address for the file + "1LSxsKfC9S9TVXGGNSM3vPHjyW82jgCX5f" + ], + "signers_required": 1 # The *number* of Valid signs required to accept the file (Multisig possibility), + "files_allowed": "data.json", # Preg pattern for the allowed files in the include file + "includes_allowed": false, # Whether nested includes are allowed + "max_size": 10000, # Max allowed size of included content.json and files it signs (in bytes) + } +} +``` + + +--- + + +### merged_type + +The type of merger this site is a part of. + +**Example**: `ZeroMe` + + +--- + + +### optional + +Preg pattern of optional files. + +**Example**: `(data/mp4/.*|updater/.*)` (everything in data/mp4 and updater directory is optional) + +Note: [Some restrictions](#regular-expression-limitations) apply to regular expressions. + +--- + + +### signs_required + +The **number** of valid signs required to accept the file. Allows for Multisig functionality. + + +**Example**: 1 + + +--- + + +### title + +The site's title, visible in the browser title and on ZeroHello. + +**Example**: ZeroTalk + + +---- + + +### translate + +Files need be translated. (use language json files in the `languages` directory) + +**Example**: ["index.html", "js/all.js"] + + +---- + + +### favicon + +The site's favicon. Replaces the default ZeroNet logo with a site-specific icon. Can be a .ico, .png, .svg, etc. + +**Example**: favicon.ico + + +---- + + +### user_contents + +Rules of allowed user content within the current directory. + +Node | Description + --- | --- +**archived** | Delete the specified user content directory that is signed earler than the specified timestamp (key: directory name, value: timestamp) +**archived_before** | Delete all user content directory if that is signed earler than the specified timestamp +**cert_signers** | Accepted domains and valid signer addresses +**permission_rules** | Allowed file names and total directory size based on cert domain or authorization method +**permissions** | Per-user permissions. (false = banned user) + +**Example**: +```python + "user_contents": { + "archived": { + "1165u6pt5mQNFjyhMVwy6azB7bZuQGLA9b": 1523088096 + }, + "archived_before": 1523088096, + "cert_signers": { + "zeroid.bit": [ "1iD5ZQJMNXu43w1qLB8sfdHVKppVMduGz" ] + }, + "permission_rules": { + ".*": { + "files_allowed": "data.json", + "max_size": 10000 + }, + "bitid/.*@zeroid.bit": { "max_size": 40000 }, + "bitmsg/.*@zeroid.bit": { "max_size": 15000 } + }, + "permissions": { + "bad@zeroid.bit": false, + "nofish@zeroid.bit": { "max_size": 100000 } + } + } +``` + +Note: [Some restrictions](#regular-expression-limitations) apply to regular expressions. + +---- + + +### viewport + +Content for the viewport meta tag. (Used for mobile-friendly pages) + +**Example**: width=device-width, initial-scale=1.0 + + +---- + +## Regular expression limitations + +To avoid the [ReDoS](https://en.wikipedia.org/wiki/ReDoS) algorithmic complexity attack, the following restrictions are applied to each pattern: + + - `.` character is mandatory before repetition characters of `*,+,{` + - Maximum 9 repetitions are allowed in a single pattern + - The maximum length of a pattern is 255 characters + +### Examples: + + - `((?!json).)*$` not allowed, because of `)` before the `*` character. Possible fix: `.*(?!json)$` + - `(.*.epub|.*.jpg|.*.jpeg|.*.png|data/.*.gif|.*.avi|.*.ogg|.*.webm|.*.mp4|.*.mp3|.*.mkv|.*.eot)` not allowed, because it has 12 `.*` repetition patterns. Possible fix: `.*(epub|jpg|jpeg|png|data/gif|avi|ogg|webm|mp4|mp3|mkv|eot)` diff --git a/docs/zh/site_development/dbschema_json.md b/docs/zh/site_development/dbschema_json.md new file mode 100644 index 0000000..5f26ca3 --- /dev/null +++ b/docs/zh/site_development/dbschema_json.md @@ -0,0 +1,211 @@ +# Structure of dbschema.json + +[Example dbschema.json file](https://github.com/HelloZeroNet/ZeroTalk/blob/master/dbschema.json) + +The code below will do the following: + + - If an updated data/users/*/data.json file is received (eg.: a user posted something): + - Every row in `data["topics"]` is loaded to the `topic` table + - Every key in `data["comment_votes"]` is loaded to the `comment_vote` table as `comment_hash` col and the values stored in same line as `vote` + - If an updated data/users/content.json file is received (eg.: new user created): + - The `"user_id", "user_name", "max_size", "added"` key in value of `content["include"]` is loaded into the `user` table and the key is stored as `path` + +> Note: [Some restriction](content_json/#regular-expressions-limitations) apply to regular expressions to avoid possible ReDoS vulnerability. + +```json + +{ + "db_name": "ZeroTalk", # Database name (only used for debugging) + "db_file": "data/users/zerotalk.db", # Database file relative to site's directory + "version": 2, # 1 = Json table has path column that includes directory and filename + # 2 = Json table has separate directory and file_name column + # 3 = Same as version 2, but also has site column (for merger sites) + "maps": { # Json to database mappings + ".*/data.json": { # Regex pattern of file relative to db_file + "to_table": [ # Load values to table + { + "node": "topics", # Reading data.json[topics] key value + "table": "topic" # Feeding data to topic table + }, + { + "node": "comment_votes", # Reading data.json[comment_votes] key value + "table": "comment_vote", # Feeding data to comment_vote table + "key_col": "comment_hash", + # data.json[comment_votes] is a simple dict, the keys of the + # dict are loaded to comment_vote table comment_hash column + + "val_col": "vote" + # The data.json[comment_votes] dict values loaded to comment_vote table vote column + + } + ], + "to_keyvalue": ["next_message_id", "next_topic_id"] + # Load data.json[next_topic_id] to keyvalue table + # (key: next_message_id, value: data.json[next_message_id] value) + + }, + "content.json": { + "to_table": [ + { + "node": "includes", + "table": "user", + "key_col": "path", + "import_cols": ["user_id", "user_name", "max_size", "added"], + # Only import these columns to user table + "replaces": { + "path": {"content.json": "data.json"} + # Replace content.json to data.json in the + # value of path column (required for joining) + } + } + ], + "to_json_table": [ "cert_auth_type", "cert_user_id" ] # Save cert_auth_type and cert_user_id directly to json table (easier and faster data queries) + } + }, + "tables": { # Table definitions + "topic": { # Define topic table + "cols": [ # Cols of the table + ["topic_id", "INTEGER"], + ["title", "TEXT"], + ["body", "TEXT"], + ["type", "TEXT"], + ["parent_topic_hash", "TEXT"], + ["added", "DATETIME"], + ["json_id", "INTEGER REFERENCES json (json_id)"] + ], + "indexes": ["CREATE UNIQUE INDEX topic_key ON topic(topic_id, json_id)"], + # Indexes automatically created + + "schema_changed": 1426195822 + # Last time of the schema changed, if the client's version is different then + # automatically destroy the old, create the new table then reload the data into it + + }, + "comment_vote": { + "cols": [ + ["comment_hash", "TEXT"], + ["vote", "INTEGER"], + ["json_id", "INTEGER REFERENCES json (json_id)"] + ], + "indexes": ["CREATE UNIQUE INDEX comment_vote_key ON comment_vote(comment_hash, json_id)", "CREATE INDEX comment_vote_hash ON comment_vote(comment_hash)"], + "schema_changed": 1426195826 + }, + "user": { + "cols": [ + ["user_id", "INTEGER"], + ["user_name", "TEXT"], + ["max_size", "INTEGER"], + ["path", "TEXT"], + ["added", "INTEGER"], + ["json_id", "INTEGER REFERENCES json (json_id)"] + ], + "indexes": ["CREATE UNIQUE INDEX user_id ON user(user_id)", "CREATE UNIQUE INDEX user_path ON user(path)"], + "schema_changed": 1426195825 + }, + "json": { # Json table format only required if you have specified to_json_table pattern anywhere + "cols": [ + ["json_id", "INTEGER PRIMARY KEY AUTOINCREMENT"], + ["directory", "TEXT"], + ["file_name", "TEXT"], + ["cert_auth_type", "TEXT"], + ["cert_user_id", "TEXT"] + ], + "indexes": ["CREATE UNIQUE INDEX path ON json(directory, site, file_name)"], + "schema_changed": 4 + } + } +} +``` + +## Example for data.json file +```json +{ + "next_topic_id": 2, + "topics": [ + { + "topic_id": 1, + "title": "Newtopic", + "body": "Topic!", + "added": 1426628540, + "parent_topic_hash": "5@2" + } + ], + "next_message_id": 19, + "comments": { + "1@2": [ + { + "comment_id": 1, + "body": "New user test!", + "added": 1423442049 + } + ], + "1@13": [ + { + "comment_id": 2, + "body": "hello", + "added": 1424653288 + }, + { + "comment_id": 13, + "body": "test 123", + "added": 1426463715 + } + ] + }, + "topic_votes": { + "1@2": 1, + "4@2": 1, + "2@2": 1, + "1@5": 1, + "1@6": 1, + "3@2": 1, + "1@13": 1, + "4@5": 1 + }, + "comment_votes": { + "5@5": 1, + "2@12": 1, + "1@12": 1, + "33@2": 1, + "45@2": 1, + "12@5": 1, + "34@2": 1, + "46@2": 1 + } +} +``` + +## Example for content.json file + +```json +{ + "files": {}, + "ignore": ".*/.*", + "includes": { + "13v1FwKcq7dx2UPruFcRcqd8s7VBjvoWJW/content.json": { + "added": 1426683897, + "files_allowed": "data.json", + "includes_allowed": false, + "max_size": 10000, + "signers": [ + "13v1FwKcq7dx2UPruFcRcqd8s7VBjvoWJW" + ], + "signers_required": 1, + "user_id": 15, + "user_name": "meginthelloka" + }, + "15WGMVViswrF13sAKb7je6oX3UhXavBxxQ/content.json": { + "added": 1426687209, + "files_allowed": "data.json", + "includes_allowed": false, + "max_size": 10000, + "signers": [ + "15WGMVViswrF13sAKb7je6oX3UhXavBxxQ" + ], + "signers_required": 1, + "user_id": 18, + "user_name": "habla" + } + } +} +``` diff --git a/docs/zh/site_development/getting_started.md b/docs/zh/site_development/getting_started.md new file mode 100644 index 0000000..9cf39bf --- /dev/null +++ b/docs/zh/site_development/getting_started.md @@ -0,0 +1,62 @@ +# Getting Started + +ZeroNet allows you to publish static and dynamic websites on a distributed web platform. + +In ZeroNet there is no concept of servers. Thus, server-side languages like PHP or Ruby are not needed. Instead, one can create dynamic content using ZeroNet's API (called ZeroFrame), JavaScript (or CoffeeScript) and the SQL database provided to all websites. + +## Tutorials + +### ZeroChat tutorial + +In this tutorial we are going to build a P2P, decentralized, server-less chat site in less then 100 lines of code. + +* [Read on ZeroBlog](http://127.0.0.1:43110/Blog.ZeroNetwork.bit/?Post:99:ZeroChat+tutorial) +* [Read on Medium.com](https://decentralize.today/decentralized-p2p-chat-in-100-lines-of-code-d6e496034cd4) + +## Useful Information + +### ZeroNet Debug mode + +ZeroNet comes with a `--debug` flag that will make site development easier. + +To run ZeroNet in debug mode use: `python zeronet.py --debug` + +If you are using compiled/bundled version of ZeroNet: + +* On Windows: `lib\ZeroNet.cmd --debug` +* On Linux: `./ZeroNet.sh --debug` +* On Mac: `./ZeroNet.app/Contents/MacOS/ZeroNet --debug` + +#### Debug mode features: + +- Automatic CoffeeScript -> JavaScript conversion (All examples used in this documentation and sample sites are written in [CoffeeScript](http://coffeescript.org/)) +- Debug messages will appear in the console +- Auto reload of some source files (UiRequest, UiWebsocket, FileRequest) on modification to prevent restarting (Requires [PyFilesystem](http://pyfilesystem.org/) on GNU/Linux) +- `http://127.0.0.1:43110/Debug` Traceback and interactive Python console at the last error position (using the wonderful Werkzeug debugger - Requires [Werkzeug](http://werkzeug.pocoo.org/)) +- `http://127.0.0.1:43110/Console` Spawns an interactive Python console (Requires [Werkzeug](http://werkzeug.pocoo.org/)) + +### Disable HTTP Browser Caching + +In addition to Debug Mode, disabling HTTP Caching in the browser is an essential part of ZeroNet site development. Modern web browsers attempt to cache web content whenever they can. As all ZeroNet sites run in an iframe, web browsers cannot detect when a ZeroNet site's content changes, and thus site changes are often not reflected if HTTP Caching is enabled. + +To disable, open your browser's devtools, navigate to the devtools settings and check the option along the lines of 'Disable HTTP Cache (when toolbox is open)'. As the setting suggests, make sure to keep devtools open when testing new changes to your site! + +### Extra features (works only for sites that you own) + + - Merged CSS files: All CSS files inside the site folder will be merged into one file called `all.css`. You can choose to include only this file to your site. If you want to keep the other CSS files to make the development easier, you can add them to the ignore key of your `content.json`. This way, they won't be published with your site. (eg: add to your `content.json` `"ignore": "(js|css)/(?!all.(js|css))"` this will ignore all CSS and JS files except `all.js` and `all.css`) + - Merged JS files: All JS files inside the site folder will be merged into one file called `all.js`. If a CoffeeScript compiler is present (bundled for Windows) it will convert `.coffee` to `.js`. + - Order in which files are merged into all.css/all.js: Files inside subdirectories of the css/js folder comes first; Files in the css/js folder will be merged according to file name ordering (01_a.css, 02_a.css, etc) + +## Need Help? + +ZeroNet has a growing community of developers who hang out in various spaces. If you would like to ask for help, advice or just want to hang out, feel free to connect in to the following services: + +### Forums + +* [ZeroExchange](http://127.0.0.1:43110/zeroexchange.bit/), a p2p StackOverflow clone +* [ZeroTalk](http://127.0.0.1:43110/Talk.ZeroNetwork.bit/), a p2p Reddit-like forum + +### Chat + +* [#zeronet-dev:matrix.org](https://riot.im/app/#/room/#zeronet-dev:matrix.org) on Matrix +* IRC at #zeronet on Freenode diff --git a/docs/zh/site_development/zeroframe_api_reference.md b/docs/zh/site_development/zeroframe_api_reference.md new file mode 100644 index 0000000..af02669 --- /dev/null +++ b/docs/zh/site_development/zeroframe_api_reference.md @@ -0,0 +1,1460 @@ +# ZeroFrame API Reference + +## The ZeroFrame API + +ZeroFrame is an API that allows ZeroNet websites to interact with the ZeroNet daemon. It allows sites to save/retrieve files, publish changes and many other things. A copy of the library is included at `js/ZeroFrame.js` whenever a new site is created. + +The library can be imported like any other JavaScript file, or site developers also have the option of [importing through NPM](ZeroFrame API Page, ##Import?). Please see the [ZeroFrame API Reference]() for API details. + +## Wrapper + +_These commands are handled by the wrapper frame and are thus not sent to the UiServer using websocket._ + + +### wrapperConfirm +Display a notification with confirm button + +Parameter | Description + --- | --- +**message** | The message you want to display +**button_caption** (optional) | Caption of the confirmation button (default: OK) + +**Return**: True if clicked on button + +**Example:** +```coffeescript +# Delete site +siteDelete: (address) -> + site = @sites[address] + title = site.content.title + if title.length > 40 + title = title.substring(0, 15)+"..."+title.substring(title.length-10) + @cmd "wrapperConfirm", ["Are you sure you sure? #{title}", "Delete"], (confirmed) => + @log "Deleting #{site.address}...", confirmed + if confirmed + $(".site-#{site.address}").addClass("deleted") + @cmd "siteDelete", {"address": address} +``` + + +--- + + +### wrapperInnerLoaded + +Applies the windows.location.hash to page url. Call when you page is fully loaded to jump to the desired anchor point. + + +--- + + +### wrapperGetLocalStorage +**Return**: Browser's local store for the site + +**Example:** +```coffeescript +@cmd "wrapperGetLocalStorage", [], (res) => + res ?= {} + @log "Local storage value:", res +``` + + + +--- + +### wrapperGetState +**Return**: Browser's current history state object + +--- + +### wrapperGetAjaxKey +**Return**: The key you need to initilize ajax requests + +**Example:** +```javascript +ajax_key = await page.cmdp("wrapperGetAjaxKey") +req = new window.XMLHttpRequest() +req.open("GET", "content.json?ajax_key=" + ajax_key) +req.setRequestHeader("Range", "bytes=10-200") // Optional: only if you want request partial file +req.send() +console.log(req.response) +``` + +--- + +### wrapperNotification +Display a notification + +Parameter | Description + --- | --- +**type** | Possible values: info, error, done +**message** | The message you want to display +**timeout** (optional) | Hide display after this interval (milliseconds) + +**Return**: None + +**Example:** +```coffeescript +@cmd "wrapperNotification", ["done", "Your registration has been sent!", 10000] +``` + + +--- + +### wrapperOpenWindow + +Navigates or opens a new popup window. + +Parameter | Description + --- | --- +**url** | Url of the opened page +**target** (optional) | Target window name +**specs** (optional) | Special properties of the window (see: [window.open specs](http://www.w3schools.com/jsref/met_win_open.asp)) + +**Example:** +```coffeescript +@cmd "wrapperOpenWindow", ["https://zeronet.io", "_blank", "width=550,height=600,location=no,menubar=no"] +``` + +--- + + +### wrapperPermissionAdd + +Request new permission for site + + +Parameter | Description + --- | --- +**permission** | Name of permission (eg. Merger:ZeroMe) + + +--- + +### wrapperPrompt + +Prompt text input from user + +Parameter | Description + --- | --- +**message** | The message you want to display +**type** (optional) | Type of the input (default: text) + +**Return**: Text entered to input + +**Example:** +```coffeescript +# Prompt the private key +@cmd "wrapperPrompt", ["Enter your private key:", "password"], (privatekey) => + $(".publishbar .button").addClass("loading") + # Send sign content.json and publish request to server + @cmd "sitePublish", [privatekey], (res) => + $(".publishbar .button").removeClass("loading") + @log "Publish result:", res +``` + + +--- + +### wrapperPushState +Change the url and adds new entry to browser's history. See: [pushState JS method](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method) + +Parameter | Description + --- | --- +**state** | State javascript object +**title** | Title of the page +**url** | Url of the page + +**Return**: None + +**Example:** +```coffeescript +@cmd "wrapperPushState", [{"scrollY": 100}, "Profile page", "Profile"] +``` + + +--- + +### wrapperReplaceState +Change the url without adding new entry to browser's history. See: [replaceState JS method](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_replaceState()_method) + +Parameter | Description + --- | --- +**state** | State javascript object +**title** | Title of the page +**url** | Url of the page + +**Return**: None + +```coffeescript +@cmd "wrapperReplaceState", [{"scrollY": 100}, "Profile page", "Profile"] +``` + +--- + +### wrapperRequestFullscreen +Set the current page to fullscreen. (request permission for the site on first call) + +> **Note:** Starting from ZeroNet Rev3136 you can use the fullscreen javascript API directly, without fullscreen request + +**Example:** +```javascript +page.cmd("wrapperRequestFullscreen") +``` + + +--- + +### wrapperSetLocalStorage +Set browser's local store data stored for the site + +Parameter | Description + --- | --- +**data** | Any data structure you want to store for the site + +**Return**: None + +**Example:** +```coffeescript +Page.local_storage["topic.#{@topic_id}_#{@topic_user_id}.visited"] = Time.timestamp() +Page.cmd "wrapperSetLocalStorage", Page.local_storage +``` + + +--- + +### wrapperSetTitle +Set browser's title + +Parameter | Description + --- | --- +**title** | New browser tab title + +**Return**: None + +**Example:** +```coffeescript +Page.cmd "wrapperSetTitle", "newtitle" +``` + +--- + + +### wrapperSetViewport + +Set sites's viewport meta tag content (required for mobile sites) + + +Parameter | Description + --- | --- +**viewport** | The viewport meta tag content + +**Return**: None + +**Example:** +```coffeescript +# Prompt the private key +@cmd "wrapperSetViewport", "width=device-width, initial-scale=1.0" +``` + + +--- + + + +## UiServer + +The UiServer is for ZeroNet what the LAMP setup is for normal websites. + +The UiServer will do all the 'backend' work (eg: querying the DB, accessing files, etc). This are the API calls you will need to make your site dynamic. + + +### announcerInfo +Tracker statistics for current site + +**Return**: +```json +{ + "stats": { + "zero://45.77.23.92:15555": { + "status": "announced", + "num_success": 1, + "time_last_error": 0, + "time_status": 1541776998.782, + "num_request": 1, + "time_request": 1541776996.884, + "num_error": 0 + }, + ... + } +} +``` + + +### certAdd +Add a new certificate to current user. + +Parameter | Description + --- | --- +**domain** | Certificate issuer domain +**auth_type** | Auth type used on registration +**auth_user_name** | User name used on registration +**cert** | The cert itself: `auth_address#auth_type/auth_user_name` string signed by the cert site owner + +**Return**: "ok", "Not changed" or {"error": error_message} + +**Example:** +```coffeescript +@cmd "certAdd", ["zeroid.bit", auth_type, user_name, cert_sign], (res) => + $(".ui").removeClass("flipped") + if res.error + @cmd "wrapperNotification", ["error", "#{res.error}"] +``` + + +--- + + +### certSelect +Display certificate selector. + +Parameter | Description + --- | --- +**accepted_domains** | List of domains that accepted by site as authorization provider +**accept_any** | Does not limits the accepted certificate providers +**accepted_pattern** | Regexp pattern for accepted certificate providers address + +**Return**: None + +**Example:** +```coffeescript +@cmd "certSelect", {"accepted_domains": ["zeroid.bit"], "accepted_pattern": "1ZeroiD[0-9]"} +``` + + +--- + + +### channelJoin + +Request notifications about sites's events. + +Parameter | Description + --- | --- +**channel** | Channel to join + +**Return**: None + +**Channels**: + + - **siteChanged** (joined by default)
Events: peers_added, file_started, file_done, file_failed + +**Example**: +```coffeescript +# Wrapper websocket connection ready +onOpenWebsocket: (e) => + @cmd "channelJoinAllsite", {"channel": "siteChanged"} + +# Route incoming requests and messages +route: (cmd, data) -> + if cmd == "setSiteInfo" + @log "Site changed", data + else + @log "Unknown command", cmd, data +``` + +**Example event data** +```json +{ + "tasks":0, + "size_limit":10, + "address":"1RivERqttrjFqwp9YH1FviduBosQPtdBN", + "next_size_limit":10, + "event":[ "file_done", "index.html" ], + [...] # Same as siteInfo return dict +} + +``` + + +--- + + +### dbQuery +Run a query on the sql cache + +Parameter | Description + --- | --- +**query** | Sql query command +**params** | Parameter substitution to the sql query + +**Return**: Result of the query + + +**Example:** +```javascript +Page.cmd("dbQuery", [ + "SELECT * FROM json WHERE file_name = :file_name", + {file_name: "data.json"} +], (res) => { console.log(res.length) }) +``` + +```javascript +Page.cmd("dbQuery", [ + "SELECT * FROM json WHERE file_name IN :file_names", + {file_names: ["data.json", "content.json"]} +], (res) => { console.log(res.length) }) +``` + +```javascript +Page.cmd("dbQuery", [ + "SELECT * FROM json ?", + {file_name: ["data.json", "content.json"]} +], (res) => { console.log(res.length) }) +``` + + +```coffeescript +@log "Updating user info...", @my_address +Page.cmd "dbQuery", ["SELECT user.*, json.json_id AS data_json_id FROM user LEFT JOIN json USING(path) WHERE path='#{@my_address}/data.json'"], (res) => + if res.error or res.length == 0 # Db not ready yet or No user found + $(".head-user.visitor").css("display", "") + $(".user_name-my").text("Visitor") + if cb then cb() + return + + @my_row = res[0] + @my_id = @my_row["user_id"] + @my_name = @my_row["user_name"] + @my_max_size = @my_row["max_size"] +``` + + +--- + + +### dirList +List a content of a directory + +Parameter | Description + --- | --- +**inner_path** | Directory you want to list + +**Return**: List of file and directory names + + +--- + + +### fileDelete +Delete a file + +Parameter | Description + --- | --- +**inner_path** | The file you want to delete + +**Return**: "ok" on success else the error message + + +--- + + +### fileGet +Get file content + +Parameter | Description + --- | --- +**inner_path** | The file you want to get +**required** (optional) | Try and wait for the file if it's not exists. (default: True) +**format** (optional) | Encoding of returned data. (text or base64) (default: text) +**timeout** (optional) | Maximum wait time to data arrive (default: 300) + +**Return**: The content of the file + + +**Example:** +```coffeescript +# Upvote a topic on ZeroTalk +submitTopicVote: (e) => + if not Users.my_name # Not registered + Page.cmd "wrapperNotification", ["info", "Please, request access before posting."] + return false + + elem = $(e.currentTarget) + elem.toggleClass("active").addClass("loading") + inner_path = "data/users/#{Users.my_address}/data.json" + + Page.cmd "fileGet", [inner_path], (data) => + data = JSON.parse(data) + data.topic_votes ?= {} # Create if not exits + topic_address = elem.parents(".topic").data("topic_address") + + if elem.hasClass("active") # Add upvote to topic + data.topic_votes[topic_address] = 1 + else # Remove upvote from topic + delete data.topic_votes[topic_address] + + # Write file and publish to other peers + Page.writePublish inner_path, Page.jsonEncode(data), (res) => + elem.removeClass("loading") + if res == true + @log "File written" + else # Failed + elem.toggleClass("active") # Change back + + return false +``` + + +--- + + +### fileList +Recursively list of files in a directory + +Parameter | Description + --- | --- +**inner_path** | Directory you want to list + +**Return**: List of files in the directory (recursive) + + +--- + + +### fileNeed +Initialize download of a (optional) file. + +Parameter | Description + --- | --- +**inner_path** | The file you want to get +**timeout** (optional) | Maximum wait time to data arrive (default: 300) + +**Return**: "ok" on successfull download + + +--- + +### fileQuery +Simple json file query command + +Parameter | Description + --- | --- +**dir_inner_path** | Pattern of queried files +**query** | Query command (optional) + +**Return**: Matched content + +**Query examples:** + + - `["data/users/*/data.json", "topics"]`: Returns all topics node from all user files + - `["data/users/*/data.json", "comments.1@2"]`: Returns `user_data["comments"]["1@2"]` value from all user files + - `["data/users/*/data.json", ""]`: Returns all data from users files + - `["data/users/*/data.json"]`: Returns all data from users files (same as above) + +**Example:** +```coffeescript +@cmd "fileQuery", ["data/users/*/data.json", "topics"], (topics) => + topics.sort (a, b) -> # Sort by date + return a.added - b.added + for topic in topics + @log topic.topic_id, topic.inner_path, topic.title +``` + + +--- + + +### fileRules +Return the rules for the file. + +Parameter | Description + --- | --- +**inner_path** | File inner path + +**Return**: Matched content + +**Example result:** + +```json +{ + "current_size": 2485, + "cert_signers": {"zeroid.bit": ["1iD5ZQJMNXu43w1qLB8sfdHVKppVMduGz"]}, + "files_allowed": "data.json", + "signers": ["1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj"], + "user_address": "1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj", + "max_size": 100000 +} +``` + +**Example:** +```coffeescript +@cmd "fileRules", "data/users/1J3rJ8ecnwH2EPYa6MrgZttBNc61ACFiCj/content.json", (rules) => + @log rules +``` + + +--- + + +### fileWrite + +Write file content + + +Parameter | Description + --- | --- +**inner_path** | Inner path of the file you want to write +**content_base64** | Content you want to write to file (base64 encoded) + +**Return**: "ok" on success else the error message + +**Example:** +```coffeescript +writeData: (cb=null) -> + # Encode to json, encode utf8 + json_raw = unescape(encodeURIComponent(JSON.stringify({"hello": "ZeroNet"}, undefined, '\t'))) + # Convert to to base64 and send + @cmd "fileWrite", ["data.json", btoa(json_raw)], (res) => + if res == "ok" + if cb then cb(true) + else + @cmd "wrapperNotification", ["error", "File write error: #{res}"] + if cb then cb(false) +``` + +_Note:_ to write files that not in content.json yet, you must have `"own": true` in `data/sites.json` at the site you want to write + + +--- + + +### ping +Test UiServer websocket connection + +**Return:** pong + + +--- + + +### serverInfo + +**Return:** All information about the server + +**Example:** +```coffeescript +@cmd "serverInfo", {}, (server_info) => + @log "Server info:", server_info +``` + +**Example return value:** +```json +{ + "debug": true, # Running in debug mode + "fileserver_ip": "*", # Fileserver binded to + "fileserver_port": 15441, # FileServer port + "ip_external": true, # Active of passive mode + "platform": "win32", # Operating system + "ui_ip": "127.0.0.1", # UiServer binded to + "ui_port": 43110, # UiServer port (Web) + "version": "0.2.5" # Version +} +``` + + + + +--- + + +### siteInfo + +**Return**: All information about the site + +**Example:** +```coffeescript +@cmd "siteInfo", {}, (site_info) => + @log "Site info:", site_info +``` + +**Example return value:** +```json +{ + "tasks": 0, # Number of files currently under download + "size_limit": 10, # Current site size limit in MB + "address": "1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr", # Site address + "next_size_limit": 10, # Size limit required by sum of site's files + "auth_address": "2D6xXUmCVAXGrbVUGRRJdS4j1hif1EMfae", # Current user's bitcoin address + "auth_key_sha512": "269a0f4c1e0c697b9d56ccffd9a9748098e51acc5d2807adc15a587779be13cf", # Deprecated, dont use + "peers": 14, # Peers of site + "auth_key": "pOBdl00EJ29Ad8OmVIc763k4", # Deprecated, dont use + "settings": { + "peers": 13, # Saved peers num for sorting + "serving": true, # Site enabled + "modified": 1425344149.365, # Last modification time of all site's files + "own": true, # Own site + "permissions": ["ADMIN"], # Site's permission + "size": 342165 # Site total size in bytes + }, + "bad_files": 0, # Files that needs to be download + "workers": 0, # Current concurent downloads + "content": { # Root content.json + "files": 12, # Number of file, detailed file info removed to reduce data transfer and parse time + "description": "This site", + "title": "ZeroHello", + "signs_required": 1, + "modified": 1425344149.365, + "ignore": "(js|css)/(?!all.(js|css))", + "signers_sign": null, + "address": "1EU1tbG9oC1A8jz2ouVwGZyQ5asrNsE4Vr", + "zeronet_version": "0.2.5", + "includes": 0 + }, + "cert_user_id": "zeronetuser@zeroid.bit", # Currently selected certificate for the site + "started_task_num": 1, # Last number of files downloaded + "content_updated": 1426008289.71 # Content.json update time +} +``` + + +--- + + +### sitePublish +Publish a content.json of the site + +Parameter | Description + --- | --- +**privatekey** (optional) | Private key used for signing (default: current user's privatekey) +**inner_path** (optional) | Inner path of the content json you want to publish (default: content.json) +**sign** (optional) | If True then sign the content.json before publish (default: True) + +**Return**: "ok" on success else the error message + +**Example:** +```coffeescript +# Prompt the private key +@cmd "wrapperPrompt", ["Enter your private key:", "password"], (privatekey) => + $(".publishbar .button").addClass("loading") + # Send sign content.json and publish request to server + @cmd "sitePublish", [privatekey], (res) => + $(".publishbar .button").removeClass("loading") + @log "Publish result:", res +``` + + +--- + + +### siteReload +Reload content.json file content and scans for optional files + +**Return**: "ok" on success + + +--- + + +### siteSign +Sign a content.json of the site + +Parameter | Description + --- | --- +**privatekey** (optional) | Private key used for signing (default: current user's privatekey) +**inner_path** (optional) | Inner path of the content json you want to sign (default: content.json) +**remove_missing_optional** (optional) | Remove the optional files from content.json that no longer present in the directory (default: False) + +**Return**: "ok" on success else the error message + +> __Note:__ +> Use "stored" as privatekey if its definied in users.json (eg. cloned sites) + +**Example:** +```coffeescript +if @site_info["privatekey"] # Private key stored in users.json + @cmd "siteSign", ["stored", "content.json"], (res) => + @log "Sign result", res +``` + + +--- + + + +### siteUpdate + +Force check and download changed content from other peers (only necessary if user is in passive mode and using old version of Zeronet) + +Parameter | Description + --- | --- +**address** | Address of site want to update (only current site allowed without site ADMIN permission) + +**Return:** None + +**Example:** +```coffeescript +# Manual site update for passive connections +updateSite: => + $("#passive_error a").addClass("loading").removeClassLater("loading", 1000) + @log "Updating site..." + @cmd "siteUpdate", {"address": @site_info.address} +``` + + +--- + + +### userGetSettings + +Get user's saved settings. + +**Return:** The user specific site's settings saved using userSetSettings. + + +--- + + +### userSetSettings + +Set user's site specific settings. + +Parameter | Description + --- | --- +**settings** | The user's site specific settings you want to store. + +**Return:** ok on success + + +--- + + +## Plugin: Bigfile + + +### BigfileUploadInit + +Initialize a new upload endpoint for a bigfile. + +Parameter | Description + --- | --- +**inner_path** | Upload location +**size** | File size + + +**Return**: A dict with the information about the upload: + +Parameter | Description + --- | --- +**url** | Http upload endpoint +**piece_size** | Size of each separately hashed part of the file +**inner_path** | File path within the site +**file_relative_path** | File path relative to content.json + +> __Note:__ Not supported non-ascii characters will be automatically removed from `inner_path` and `file_relative_path` values + +**Example** + +```javascript +var input = document.createElement('input') +document.body.appendChild(input) +input.type = "file" +input.style.visibility = "hidden" + +input.onchange = () => { + var file = input.files[0] + page.cmd("bigfileUploadInit", ["optional/"+file.name, file.size], (init_res) => { + var formdata = new FormData() + formdata.append(file.name, file) + + var req = new XMLHttpRequest() + req.upload.addEventListener("progress", console.log) + req.upload.addEventListener("loadend", () => + page.cmd("wrapperConfirm", ["Upload finished!", "Open file"], + () => { window.top.location = init_res.inner_path } + ) + ) + req.withCredentials = true + req.open("POST", init_res.url) + req.send(formdata) + }) +} +input.click() +``` + + +--- + +## Plugin: Chart + +### chartDbQuery + +Run database query on chart database. + +Arguments and return value: Same as [dbQuery](#dbquery-query-param) + + +### chartGetPeerLocations + +Get list of unique peers in client + +**Return**: List of unique peers + +**Example**: +```javascript +Page.cmd("chartGetPeerLocations") +> [ +> {lat: 43.6655, city: "Toronto", ping: null, lon: -79.4204, country: "Canada"}, +> ... +> ] +``` + +--- + +## Plugin: Cors + +Allow cross-site file access under virtual directory **/cors-siteaddress/** and grant cross-site database query using the [as](#as-address-cmd-arguments) API command. + +### corsPermission + +Request Cross origin resource sharing permission with the given site. + +Parameter | Description + --- | --- +**address** | The site address you want get cors access + +**Return**: ok on success + +After the permission is granted the other site's files will be available under **/cors-siteaddress/** virtual directory via http request or by the fileGet API command. + +The site will be added to user's client if it's required. + + +--- + + +## Plugin: CryptMessage + + +### userPublickey + +Get user's site specific publickey + +Parameter | Description + --- | --- +**index** (optional) | Sub-publickey within site (default: 0) + + +**Return**: base64 encoded publickey + +--- + +### eciesEncrypt + +Encrypt a text using a publickey + +Parameter | Description + --- | --- +**text** | Text to encrypt +**publickey** (optional) | User's publickey index (int) or base64 encoded publickey (default: 0) +**return_aes_key** (optional) | Get the AES key used in encryption (default: False) + + +**Return**: Encrypted text in base64 format or [Encrypted text in base64 format, AES key in base64 format] + +--- + +### eciesDecrypt + +Try to decrypt list of texts + +Parameter | Description + --- | --- +**params** | A text or list of encrypted texts +**privatekey** (optional) | User's privatekey index (int) or base64 encoded privatekey (default: 0) + + +**Return**: Decrypted text or list of decrypted texts (null for failed decodings) + +--- + +### aesEncrypt + +Encrypt a text using the key and the iv + +Parameter | Description + --- | --- +**text** | A text encrypt using AES +**key** (optional) | Base64 encoded password (default: generate new) +**iv** (optional) | Base64 encoded iv (default: generate new) + + +**Return**: [base64 encoded key, base64 encoded iv, base64 encoded encrypted text] + + +--- + +### aesDecrypt + +Decrypt text using the IV and AES key + +Parameter | Description + --- | --- +**iv** | IV in Base64 format +**encrypted_text** | Encrypted text in Base64 format +**encrypted_texts** | List of [base64 encoded iv, base64 encoded encrypted text] pairs +**key** | Base64 encoded password for the text +**keys** | Keys for decoding (tries every one for every pairs) + + +**Return**: Decoded text or list of decoded texts + + +--- + + +## Plugin: Newsfeed + + +### feedFollow + +Set followed sql queries. + +The SQL query should result in rows with cols: + +Field | Description + --- | --- +**type** | Type: post, article, comment, mention +**date_added** | Event time +**title** | Event's first line to be displayed +**body** | Event's second and third line +**url** | Link to event's page + +Parameter | Description + --- | --- +**feeds** | Format: {"query name": [SQL query, [param1, param2, ...], ...}, parameters will be escaped, joined by `,` inserted in place of `:params` in the Sql query. + +**Return**: ok + +**Example:** +```coffeescript +# Follow ZeroBlog posts +query = " + SELECT + post_id AS event_uri, + 'post' AS type, + date_published AS date_added, + title AS title, + body AS body, + '?Post:' || post_id AS url + FROM post +" +params = [""] +Page.cmd feedFollow [{"Posts": [query, params]}] +``` + +--- + +### feedListFollow + +Return of current followed feeds + + +**Return**: The currently followed feeds in the same format as in the feedFollow commands + + +--- + +### feedQuery + +Execute all followed sql query + + +**Return**: The result of the followed Sql queries + +Parameter | Description + --- | --- +**limit** | Limit of results per followed site (default: 10) +**day_limit** | Return no older than number of this days (default: 3) + +--- + +## Plugin: MergerSite + + +### mergerSiteAdd + +Start downloading new merger site(s) + +Parameter | Description + --- | --- +**addresses** | Site address or list of site addresses + + +--- + +### mergerSiteDelete + +Stop seeding and delete a merged site + +Parameter | Description + --- | --- +**address** | Site address + + +--- + +### mergerSiteList + +Return merged sites. + +Parameter | Description + --- | --- +**query_site_info** | If True, then gives back detailed site info for merged sites + + +--- + + +## Plugin: Mute + + +### muteAdd + +Add new user to mute list. (Requires confirmation for non-ADMIN sites) + +Parameter | Description + --- | --- +**auth_address** | Directory name of the user's data. +**cert_user_id** | Cert user name of the user +**reason** | Reason of the muting + +**Return**: ok if confirmed + +**Example:** +```coffeescript +Page.cmd("muteAdd", ['1GJUaZMjTfeETdYUhchSkDijv6LVhjekHz','helloworld@kaffie.bit','Spammer']) +``` + +--- + +### muteRemove + +Remove a user from mute list. (Requires confirmation for non-ADMIN sites) + +Parameter | Description + --- | --- +**auth_address** | Directory name of the user's data. + +**Return**: ok if confirmed + +**Example:** +```coffeescript +Page.cmd("muteRemove", '1GJUaZMjTfeETdYUhchSkDijv6LVhjekHz') +``` + +--- + +### muteList + +List muted users. (Requires ADMIN permission on site) + +**Return**: List of muted users + + +--- + + +## Plugin: OptionalManager + + +### optionalFileList + +Return list of optional files + +Parameter | Description + --- | --- +**address** | The site address you want to list optional files (default: current site) +**orderby** | Order of returned optional files (default: time_downloaded DESC) +**limit** | Max number of returned optional files (default: 10) + +**Return**: Database row of optional files: file_id, site_id, inner_path, hash_id, size, peer, uploaded, is_downloaded, is_pinned, time_added, time_downlaoded, time_accessed + +--- + +### optionalFileInfo + +Query optional file info from database + +Parameter | Description + --- | --- +**inner_path** | The path of the file + +**Return**: Database row of optional file: file_id, site_id, inner_path, hash_id, size, peer, uploaded, is_downloaded, is_pinned, time_added, time_downlaoded, time_accessed + +--- + +### optionalFilePin + +Pin (exclude from automatized optional file cleanup) downloaded optional file + +Parameter | Description + --- | --- +**inner_path** | The path of the file +**address** | Address for the file (default: current site) + +--- + +### optionalFileUnpin + +Remove pinning (include from automatized optional file cleanup) of downloaded optional file + +Parameter | Description + --- | --- +**inner_path** | The path of the file +**address** | Address for the file (default: current site) + +--- + +### optionalFileDelete + +Query a downloaded optional file + +Parameter | Description + --- | --- +**inner_path** | The path of the file +**address** | Address for the file (default: current site) + +--- + +### optionalLimitStats + +Return currently used disk space by optional files + +**Return**: limit, used and free space statistics + +--- + + +### optionalLimitSet + +Set the optional file limit + +Parameter | Description + --- | --- +**limit** | Max space used by the optional files in gb or percent of used space + +--- + +### optionalHelpList + +List the auto-downloaded directories of optional files + +Parameter | Description + --- | --- +**address** | Address of site you want to list helped directories (default: current site) + +**Return**: Dict of auto-downloaded directories and descriptions + +--- + + +### optionalHelp + +Add directory to auto-download list + +Parameter | Description + --- | --- +**directory** | Directory you want to add to auto-download list +**title** | Title for the entry (displayed on ZeroHello) +**address** | Address of site you want to add the auto-download directory (default: current site) + +--- + +### optionalHelpRemove + +Remove an auto-download entry + +Parameter | Description + --- | --- +**directory** | Directory you want to remove from auto-download list +**address** | Address of affected site (default: current site) + +--- + +### optionalHelpAll + +Help download every new uploaded optional file to the site + +Parameter | Description + --- | --- +**value** | Enable or Disable the auto-download +**address** | Address of affected site (default: current site) + + +--- + + +## Admin commands +_(requires ADMIN permission in data/sites.json)_ + + +### as + +Execute command in other site's context + + +Parameter | Description + --- | --- +**address** | The context site's address +**cmd** | API command name +**arguments** | API command arguments + +**Return**: Command's return value + + +**Example** + +```javascript +Page.cmd("as", ["138R53t3ZW7KDfSfxVpWUsMXgwUnsDNXLP", "siteSetLimit", 20], console.log ) +``` + +```javascript +address = "138R53t3ZW7KDfSfxVpWUsMXgwUnsDNXLP" +query = "SELECT * FROM json WHERE file_name = :file_name" +params = {"file_name": "data.json"} +Page.cmd("as", [address, "dbQuery", [query, params]], function(res) { console.log(res.length) } ) +``` + +--- + + +**Return**: ok + +### configSet + +Create or update an entry in ZeroNet config file. (zeronet.conf by default) + + +Parameter | Description + --- | --- +**key** | Configuration entry name +**value** | Configuration entry new value + + +**Return**: ok + + +--- + + + +### certSet + +Set the used certificate for current site. + +Parameter | Description + --- | --- +**domain** | Domain of the certificate issuer + +**Return**: None + + +--- + + +### channelJoinAllsite + +Request notifications about every site's events. + +Parameter | Description + --- | --- +**channel** | Channel to join (see channelJoin) + +**Return**: None + + + + +--- + + +### serverPortcheck + +Start checking if port is opened + +**Return**: True (port opened) or False (port closed) + + +--- + + +### serverShutdown + +Stop running ZeroNet client. + +**Return**: None + + + +--- + + +### serverUpdate + +Re-download ZeroNet from github. + +**Return**: None + + +--- + + +### siteClone +Copy site files into a new one. + +Every file and directory will be skipped if it has a `-default` subfixed version and the subfixed version will be copied instead of it. + + +Eg. If you have a `data` and a `data-default` directory: The `data` directory will not be copied and the `data-default` directory will be renamed to data. + +Parameter | Description + --- | --- +**address** | Address of site want to clone +**root_inner_path** | The source directory of the new site + +**Return**: None, automatically redirects to new site on completion + + +--- + + +### siteList + +**Return**: SiteInfo list of all downloaded sites + + +--- + + +### sitePause +Pause site serving + +Parameter | Description + --- | --- +**address** | Address of site want to pause + +**Return**: None + + +--- + + +### siteResume +Resume site serving + +Parameter | Description + --- | --- +**address** | Address of site want to resume + +**Return**: None diff --git a/docs/zh/translation.md b/docs/zh/translation.md new file mode 100644 index 0000000..ec1787a --- /dev/null +++ b/docs/zh/translation.md @@ -0,0 +1,3 @@ +# 如何翻译 + +Instructions goes here. diff --git a/docs/zh/using_zeronet/create_new_site.md b/docs/zh/using_zeronet/create_new_site.md new file mode 100644 index 0000000..dc4e8b6 --- /dev/null +++ b/docs/zh/using_zeronet/create_new_site.md @@ -0,0 +1,62 @@ +# Create new ZeroNet site + +## Easy way: Using the web interface + + * Click on **⋮** > **"Create new, empty site"** menu item on the site [ZeroHello](http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D). + * You will be **redirected** to a completely new site that is only modifiable by you! + * You can find and modify your site's content in **data/[yoursiteaddress]** directory + * After the modifications open your site, drag the topright "0" button to left, then press **sign** and **publish** buttons on the bottom + +## Manual way: Using the command line + +### 1. Create site structure + +* Shut down ZeroNet if it is running +* Browse to the folder where ZeroNet is installed and run: + +```bash +$ zeronet.py siteCreate +... +- Site private key: 23DKQpzxhbVBrAtvLEc2uvk7DZweh4qL3fn3jpM3LgHDczMK2TtYUq +- Site address: 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2 +... +- Site created! +$ zeronet.py +... +``` + +- This will create the initial files for your site inside ```data/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2```. + +> __Note:__ +> Windows users using the bundle version must browse into the ZeroBundle/ZeroNet folder and run `"../Python/python.exe" zeronet.py siteCreate` + +### 2. Build/Modify site + +* Update the site files located in ```data/[your site address key]``` (eg: 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2). +* When your site is ready run: + +```bash +$ zeronet.py siteSign 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2 +- Signing site: 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2... +Private key (input hidden): +``` + +* Enter the private key you got when you created the site. This will sign all files so peers can verify that the site owner is who made the changes. + +### 3. Publish site changes + +* In order to inform peers about the changes you made you need to run: + +```bash +$ zeronet.py sitePublish 13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2 +... +Site:13DNDk..bhC2 Publishing to 3/10 peers... +Site:13DNDk..bhC2 Successfuly published to 3 peers +- Serving files.... +``` + +* That's it! You've successfully signed and published your modifications. +* Your site will be accessible from: ```http://localhost:43110/13DNDkMUExRf9Xa9ogwPKqp7zyHFEqbhC2``` + + +**Next steps:** [ZeroNet Developer Documentation](../../site_development/getting_started/) diff --git a/docs/zh/using_zeronet/installing.md b/docs/zh/using_zeronet/installing.md new file mode 100644 index 0000000..23c1177 --- /dev/null +++ b/docs/zh/using_zeronet/installing.md @@ -0,0 +1,42 @@ +# Installing ZeroNet + +* Download ZeroBundle package: [Microsoft Windows](https://github.com/HelloZeroNet/ZeroNet-win/archive/dist/ZeroNet-win.zip), [Apple macOS](https://github.com/HelloZeroNet/ZeroNet-mac/archive/dist/ZeroNet-mac.zip), [Linux 64bit](https://github.com/HelloZeroNet/ZeroBundle/raw/master/dist/ZeroBundle-linux64.tar.gz), [Linux 32bit](https://github.com/HelloZeroNet/ZeroBundle/raw/master/dist/ZeroBundle-linux32.tar.gz) +* Unpack anywhere +* Run `ZeroNet.exe` (win), `ZeroNet(.app)` (macOS), `ZeroNet.sh` (linux) + +### Manual install for Debian Linux + +* `sudo apt-get update` +* `sudo apt-get install msgpack-python python-gevent` +* `wget https://github.com/HelloZeroNet/ZeroNet/archive/master.tar.gz` +* `tar xvpfz master.tar.gz` +* `cd ZeroNet-master` +* Start with `python zeronet.py` +* Open http://127.0.0.1:43110/ in your browser + +### [Vagrant](https://www.vagrantup.com/) + +* `vagrant up` +* Access VM with `vagrant ssh` +* `cd /vagrant` +* Run `python zeronet.py --ui_ip 0.0.0.0` +* Open http://127.0.0.1:43110/ in your browser + +### [Docker](https://www.docker.com/) +* `docker run -d -v :/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 nofish/zeronet` +* This Docker image includes the Tor proxy, which is disabled by default. Beware that some +hosting providers may not allow you running Tor in their servers. If you want to enable it, +set `ENABLE_TOR` environment variable to `true` (Default: `false`). E.g.: + + `docker run -d -e "ENABLE_TOR=true" -v :/root/data -p 15441:15441 -p 127.0.0.1:43110:43110 nofish/zeronet` +* Open http://127.0.0.1:43110/ in your browser + +### [Virtualenv](https://virtualenv.readthedocs.org/en/latest/) + +* `virtualenv env` +* `source env/bin/activate` +* `pip install msgpack-python gevent` +* `python zeronet.py` +* Open http://127.0.0.1:43110/ in your browser + + diff --git a/docs/zh/using_zeronet/sample_sites.md b/docs/zh/using_zeronet/sample_sites.md new file mode 100644 index 0000000..0c68c1a --- /dev/null +++ b/docs/zh/using_zeronet/sample_sites.md @@ -0,0 +1,129 @@ +# Sample ZeroNet sites + +## ZeroHello + +The homepage of ZeroNet + + - Lists all added sites: Title, Peer number, Modification date, etc. + - Site actions: Update, Pause, Resume, Delete, Check Files and Save as .zip + - Clone sites to have your own blog / forum + - ZeroNet Statistics + - If an update is available, ZeroNet can be updated with one click + +![ZeroHello](../img/zerohello.png) + +Address: [1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D](http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D) + +[Source code](https://github.com/HelloZeroNet/ZeroHello) + +--- + +## ZeroBlog + +Self publishing blog demo + + - Inline content editor + - Markdown syntax + - Code syntax highlighting + - Site signing & publishing through the web interface + +How does it work? + + - `data.json` contained within site files contain blog posts and comments. Each user has their own. + - Upon pressing `Sign & Publish new content`, the blogger is asked for the site private key (displayed when [creating a new site using zeronet.py siteCreate command](create_new_site/)) + - Your ZeroNet client signs the new/modified files and publishes directly to other peers + - The site will then be accessible until to other peers to view + +![ZeroBlog](../img/zeroblog.png) + +Address: [1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8](http://127.0.0.1:43110/1BLogC9LN4oPDcruNz3qo1ysa133E9AGg8) or [blog.zeronetwork.bit](http://127.0.0.1:43110/blog.zeronetwork.bit) + +[Source code](https://github.com/HelloZeroNet/ZeroBlog) + + +--- + +## ZeroTalk + +Decentralized, P2P forum demo + + - Post and comment creation, modification, deletion and upvoting + - Commenting and content modifications pushed directly to other peers + - Only you can sign and modify your own files + - Real time display of new comments + +How does it work? + + - To post and comment you have to request a certificate of registration (a cryptographic sign) from a ZeroID provider + - After you have the certificate you can publish your content (messages, posts, upvotes) directly to other peers + +![ZeroTalk](../img/zerotalk.png) + +Address: [1TaLkFrMwvbNsooF4ioKAY9EuxTBTjipT](http://127.0.0.1:43110/1TaLkFrMwvbNsooF4ioKAY9EuxTBTjipT) or [talk.zeronetwork.bit](http://127.0.0.1:43110/talk.zeronetwork.bit) + +[Source code](https://github.com/HelloZeroNet/ZeroTalk) + +--- + +## ZeroMail + +End-to-end encrypted, distributed, P2P messaging site. To improve privacy it uses a BitMessage-like solution and will not expose the message recipient. + + - Using ECIES for secret exchange, AES256 for message encoding + - When you first visit the site, it adds your public key to your data file. At that point anyone is able to send a message to you + - Everyone tries to decrypt every message, this improves privacy by making it impossible to find the message recipient + - To reduce per message overhead and increase decryption speed, we re-use the AES key, but a new IV is generated every time + +![ZeroTalk](../img/zeromail.png) + +Address: [1MaiL5gfBM1cyb4a8e3iiL8L5gXmoAJu27](http://127.0.0.1:43110/1MaiL5gfBM1cyb4a8e3iiL8L5gXmoAJu27) or [mail.zeronetwork.bit](http://127.0.0.1:43110/mail.zeronetwork.bit) + +[Source code](https://github.com/HelloZeroNet/ZeroMail) + +--- + +## ZeroMe + +Decentralized, Twitter-like P2P social network. + + - Stores user information in ZeroMe user registry + - Stores posts and comments in MergerSites called Hubs + - Upload images as optional files + - Real time display of feed activity + +![ZeroMe](../img/zerome.png) + +Address: [1MeFqFfFFGQfa1J3gJyYYUvb5Lksczq7nH](http://127.0.0.1:43110/1MeFqFfFFGQfa1J3gJyYYUvb5Lksczq7nH) + +[Source code](https://github.com/HelloZeroNet/ZeroMe) + +--- + +## ReactionGIFs + +Demo for optional files, files which only download from other peers if your browser requests them. + +![ReactionGIFs](../img/reactiongifs.jpg) + +Address: [1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h](http://127.0.0.1:43110/1Gif7PqWTzVWDQ42Mo7np3zXmGAo3DXc7h) + +[Source code](https://github.com/HelloZeroNet/ReactionGIFs) + +--- + +## ZeroChat + +The finished site for the tutorial of creating a server-less, SQL backed, real-time updated P2P chat application using ZeroNet in less than 100 lines of code. + + - Uses ZeroID certificate for authentication + - Stores messages in a SQLite database + - Posts messages and distribute directly to other users in real-time + - Real-time update the messages as they arrive + +![ZeroChat](../img/zerochat.png) + +Address of finished site: [1AvF5TpcaamRNtqvN1cnDEWzNmUtD47Npg](http://127.0.0.1:43110/1AvF5TpcaamRNtqvN1cnDEWzNmUtD47Npg) + +Tutorial on ZeroBlog: + [Part1](http://127.0.0.1:43110/Blog.ZeroNetwork.bit/?Post:43:ZeroNet+site+development+tutorial+1), + [Part2](http://127.0.0.1:43110/Blog.ZeroNetwork.bit/?Post:46:ZeroNet+site+development+tutorial+2) diff --git a/mkdocs-zh.yml b/mkdocs-zh.yml new file mode 100644 index 0000000..857bdd0 --- /dev/null +++ b/mkdocs-zh.yml @@ -0,0 +1,54 @@ + +site_name: ZeroNet +site_url: https://zeronet.io +site_description: 使用比特币加密技术与BitTorrent的分布式网络 + +repo_url: https://github.com/HelloZeroNet/ZeroNet +edit_uri: ../Documentation/edit/master/docs/zh/ + +extra_css: [docs.css, stylesheets/menu.css] +extra_javascript: [ZeroFrame.js, jquery.min.js, docs.js, javascripts/menu.js] + +docs_dir: docs/zh +site_dir: site + +theme: + language: 'zh' + feature: + tabs: true + palette: + primary: "deep purple" + accent: "deep purple" + logo: "logo/zeronet_logo.svg" + name: "material" + favicon: "logo/favicon.ico" + custom_dir: "docs/resources" + font: false + +markdown_extensions: + - toc: + permalink: true + - codehilite + +plugins: + - search: + lang: ['en'] + +nav: +- 概述: "index.md" +- 常见问题: "faq.md" +- 开始使用ZeroNet: + - "using_zeronet/installing.md" + - "using_zeronet/sample_sites.md" + - "using_zeronet/create_new_site.md" +- 网站开发: + - "site_development/getting_started.md" + - "site_development/zeroframe_api_reference.md" + - "site_development/content_json.md" + - "site_development/dbschema_json.md" + - "site_development/cert_authority.md" +- 帮助开发ZeroNet: + - "help_zeronet/contributing.md" + - "help_zeronet/coding_conventions.md" + - "help_zeronet/network_protocol.md" + - "help_zeronet/donate.md"